mirror of
https://github.com/google/blockly.git
synced 2026-01-06 16:40:07 +01:00
* fix(build): Restore erroneously-deleted filter function This was deleted in PR #7406 as it was mainly being used to filter core/ vs. test/mocha/ deps into separate deps files - but it turns out also to be used for filtering error messages too. Oops. * refactor(tests): Migrate advanced compilation test to ES Modules * refactor(build): Migrate main.js to TypeScript This turns out to be pretty straight forward, even if it would cause crashing if one actually tried to import this module instead of just feeding it to Closure Compiler. * chore(build): Remove goog.declareModuleId calls Replace goog.declareModuleId calls with a comment recording the former module ID for posterity (or at least until we decide how to reformat the renamings file. * chore(tests): Delete closure/goog/* For the moment we still need something to serve as base.js for the benefit of closure-make-deps, so we keep a vestigial base.js around, containing only the @provideGoog declaration. * refactor(build): Remove vestigial base.js By changing slightly the command line arguments to closure-make-deps and closure-calculate-chunks the need to have any base.js is eliminated. * chore: Typo fix for PR #7415
166 lines
4.8 KiB
TypeScript
166 lines
4.8 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2018 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
// Former goog.module ID: Blockly.utils.xml
|
|
|
|
let domParser: DOMParser = {
|
|
parseFromString: function () {
|
|
throw new Error(
|
|
'DOMParser was not found in the global scope and was not properly ' +
|
|
'injected using injectDependencies',
|
|
);
|
|
},
|
|
};
|
|
|
|
let xmlSerializer: XMLSerializer = {
|
|
serializeToString: function () {
|
|
throw new Error(
|
|
'XMLSerializer was not foundin the global scope and was not properly ' +
|
|
'injected using injectDependencies',
|
|
);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Injected dependencies. By default these are just (and have the
|
|
* same types as) the corresponding DOM Window properties, but the
|
|
* Node.js wrapper for Blockly (see scripts/package/node/core.js)
|
|
* calls injectDependencies to supply implementations from the jsdom
|
|
* package instead.
|
|
*/
|
|
let {document, DOMParser, XMLSerializer} = globalThis;
|
|
if (DOMParser) domParser = new DOMParser();
|
|
if (XMLSerializer) xmlSerializer = new XMLSerializer();
|
|
|
|
/**
|
|
* Inject implementations of document, DOMParser and/or XMLSerializer
|
|
* to use instead of the default ones.
|
|
*
|
|
* Used by the Node.js wrapper for Blockly (see
|
|
* scripts/package/node/core.js) to supply implementations from the
|
|
* jsdom package instead.
|
|
*
|
|
* While they may be set individually, it is normally the case that
|
|
* all three will be sourced from the same JSDOM instance. They MUST
|
|
* at least come from the same copy of the jsdom package. (Typically
|
|
* this is hard to avoid satsifying this requirement, but it can be
|
|
* inadvertently violated by using webpack to build multiple bundles
|
|
* containing Blockly and jsdom, and then loading more than one into
|
|
* the same JavaScript runtime. See
|
|
* https://github.com/google/blockly-samples/pull/1452#issuecomment-1364442135
|
|
* for an example of how this happened.)
|
|
*
|
|
* @param dependencies Options object containing dependencies to set.
|
|
*/
|
|
export function injectDependencies(dependencies: {
|
|
document?: Document;
|
|
DOMParser?: typeof DOMParser;
|
|
XMLSerializer?: typeof XMLSerializer;
|
|
}) {
|
|
({
|
|
// Default to existing value if option not supplied.
|
|
document = document,
|
|
DOMParser = DOMParser,
|
|
XMLSerializer = XMLSerializer,
|
|
} = dependencies);
|
|
|
|
domParser = new DOMParser();
|
|
xmlSerializer = new XMLSerializer();
|
|
}
|
|
|
|
/**
|
|
* Namespace for Blockly's XML.
|
|
*/
|
|
export const NAME_SPACE = 'https://developers.google.com/blockly/xml';
|
|
|
|
// eslint-disable-next-line no-control-regex
|
|
const INVALID_CONTROL_CHARS = /[\x00-\x09\x0B\x0C\x0E-\x1F]/g;
|
|
|
|
/**
|
|
* Create DOM element for XML.
|
|
*
|
|
* @param tagName Name of DOM element.
|
|
* @returns New DOM element.
|
|
*/
|
|
export function createElement(tagName: string): Element {
|
|
return document.createElementNS(NAME_SPACE, tagName);
|
|
}
|
|
|
|
/**
|
|
* Create text element for XML.
|
|
*
|
|
* @param text Text content.
|
|
* @returns New DOM text node.
|
|
*/
|
|
export function createTextNode(text: string): Text {
|
|
return document.createTextNode(text);
|
|
}
|
|
|
|
/**
|
|
* Converts an XML string into a DOM structure.
|
|
*
|
|
* Control characters should be escaped. (But we will try to best-effort parse
|
|
* unescaped characters.)
|
|
*
|
|
* Note that even when escaped, U+0000 will be parsed as U+FFFD (the
|
|
* "replacement character") because U+0000 is never a valid XML character
|
|
* (even in XML 1.1).
|
|
* https://www.w3.org/TR/xml11/#charsets
|
|
*
|
|
* @param text An XML string.
|
|
* @returns A DOM object representing the singular child of the document
|
|
* element.
|
|
* @throws if the text doesn't parse.
|
|
*/
|
|
export function textToDom(text: string): Element {
|
|
let doc = domParser.parseFromString(text, 'text/xml');
|
|
if (
|
|
doc &&
|
|
doc.documentElement &&
|
|
!doc.getElementsByTagName('parsererror').length
|
|
) {
|
|
return doc.documentElement;
|
|
}
|
|
|
|
// Attempt to parse as HTML to deserialize control characters that were
|
|
// serialized before the serializer did proper escaping.
|
|
doc = domParser.parseFromString(text, 'text/html');
|
|
if (
|
|
doc &&
|
|
doc.body.firstChild &&
|
|
doc.body.firstChild.nodeName.toLowerCase() === 'xml'
|
|
) {
|
|
return doc.body.firstChild as Element;
|
|
}
|
|
|
|
throw new Error(`DOMParser was unable to parse: ${text}`);
|
|
}
|
|
|
|
/**
|
|
* Converts a DOM structure into plain text.
|
|
* Currently the text format is fairly ugly: all one line with no whitespace.
|
|
*
|
|
* Control characters are escaped using their decimal encodings. This includes
|
|
* U+0000 even though it is technically never a valid XML character (even in
|
|
* XML 1.1).
|
|
* https://www.w3.org/TR/xml11/#charsets
|
|
*
|
|
* When decoded U+0000 will be parsed as U+FFFD (the "replacement character").
|
|
*
|
|
* @param dom A tree of XML nodes.
|
|
* @returns Text representation.
|
|
*/
|
|
export function domToText(dom: Node): string {
|
|
return sanitizeText(xmlSerializer.serializeToString(dom));
|
|
}
|
|
|
|
function sanitizeText(text: string) {
|
|
return text.replace(
|
|
INVALID_CONTROL_CHARS,
|
|
(match) => `&#${match.charCodeAt(0)};`,
|
|
);
|
|
}
|