@remote-dom/polyfill 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/README.md +51 -3
- package/build/cjs/Attr.cjs +33 -4
- package/build/cjs/CharacterData.cjs +10 -0
- package/build/cjs/ChildNode.cjs +79 -13
- package/build/cjs/Comment.cjs +1 -1
- package/build/cjs/CustomElementRegistry.cjs +27 -2
- package/build/cjs/CustomEvent.cjs +2 -2
- package/build/cjs/Document.cjs +56 -32
- package/build/cjs/DocumentFragment.cjs +6 -2
- package/build/cjs/Element.cjs +68 -8
- package/build/cjs/Event.cjs +29 -27
- package/build/cjs/EventTarget.cjs +128 -58
- package/build/cjs/HTMLTemplateElement.cjs +1 -0
- package/build/cjs/MutationObserver.cjs +167 -1
- package/build/cjs/NamedNodeMap.cjs +82 -45
- package/build/cjs/Node.cjs +47 -11
- package/build/cjs/NodeList.cjs +9 -1
- package/build/cjs/ParentNode.cjs +319 -77
- package/build/cjs/SVGElement.cjs +1 -1
- package/build/cjs/Text.cjs +1 -1
- package/build/cjs/Window.cjs +131 -38
- package/build/cjs/attribute-reactions.cjs +20 -0
- package/build/cjs/constants.cjs +48 -24
- package/build/cjs/custom-element-reactions.cjs +52 -0
- package/build/cjs/dom-exception.cjs +15 -0
- package/build/cjs/hook-effects.cjs +51 -0
- package/build/cjs/names.cjs +61 -0
- package/build/cjs/selectors.cjs +213 -122
- package/build/cjs/serialization.cjs +168 -65
- package/build/cjs/shared.cjs +177 -28
- package/build/esm/Attr.mjs +34 -5
- package/build/esm/CharacterData.mjs +10 -0
- package/build/esm/ChildNode.mjs +76 -15
- package/build/esm/Comment.mjs +2 -2
- package/build/esm/CustomElementRegistry.mjs +27 -2
- package/build/esm/CustomEvent.mjs +2 -2
- package/build/esm/Document.mjs +60 -35
- package/build/esm/DocumentFragment.mjs +7 -3
- package/build/esm/Element.mjs +69 -9
- package/build/esm/Event.mjs +27 -27
- package/build/esm/EventTarget.mjs +130 -60
- package/build/esm/HTMLTemplateElement.mjs +2 -1
- package/build/esm/MutationObserver.mjs +166 -2
- package/build/esm/NamedNodeMap.mjs +83 -46
- package/build/esm/Node.mjs +48 -12
- package/build/esm/NodeList.mjs +9 -1
- package/build/esm/ParentNode.mjs +322 -81
- package/build/esm/SVGElement.mjs +2 -2
- package/build/esm/Text.mjs +2 -2
- package/build/esm/Window.mjs +132 -39
- package/build/esm/attribute-reactions.mjs +16 -0
- package/build/esm/constants.mjs +28 -23
- package/build/esm/custom-element-reactions.mjs +47 -0
- package/build/esm/dom-exception.mjs +11 -0
- package/build/esm/hook-effects.mjs +46 -0
- package/build/esm/names.mjs +54 -0
- package/build/esm/selectors.mjs +202 -124
- package/build/esm/serialization.mjs +169 -66
- package/build/esm/shared.mjs +173 -30
- package/build/esnext/Attr.esnext +45 -5
- package/build/esnext/CharacterData.esnext +10 -0
- package/build/esnext/ChildNode.esnext +84 -15
- package/build/esnext/Comment.esnext +2 -2
- package/build/esnext/CustomElementRegistry.esnext +42 -0
- package/build/esnext/CustomEvent.esnext +2 -2
- package/build/esnext/Document.esnext +69 -32
- package/build/esnext/DocumentFragment.esnext +6 -2
- package/build/esnext/Element.esnext +78 -9
- package/build/esnext/Event.esnext +36 -37
- package/build/esnext/EventTarget.esnext +133 -61
- package/build/esnext/HTMLTemplateElement.esnext +3 -1
- package/build/esnext/MutationObserver.esnext +163 -2
- package/build/esnext/NamedNodeMap.esnext +110 -42
- package/build/esnext/Node.esnext +50 -12
- package/build/esnext/NodeList.esnext +1 -1
- package/build/esnext/ParentNode.esnext +352 -79
- package/build/esnext/SVGElement.esnext +2 -2
- package/build/esnext/Text.esnext +2 -2
- package/build/esnext/Window.esnext +120 -16
- package/build/esnext/attribute-reactions.esnext +21 -0
- package/build/esnext/constants.esnext +34 -21
- package/build/esnext/custom-element-reactions.esnext +49 -0
- package/build/esnext/dom-exception.esnext +11 -0
- package/build/esnext/hook-effects.esnext +46 -0
- package/build/esnext/names.esnext +61 -0
- package/build/esnext/selectors.esnext +202 -100
- package/build/esnext/serialization.esnext +171 -48
- package/build/esnext/shared.esnext +181 -34
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/typescript/Attr.d.ts +6 -4
- package/build/typescript/Attr.d.ts.map +1 -1
- package/build/typescript/CharacterData.d.ts.map +1 -1
- package/build/typescript/ChildNode.d.ts +5 -0
- package/build/typescript/ChildNode.d.ts.map +1 -1
- package/build/typescript/ClipboardEvent.d.ts.map +1 -1
- package/build/typescript/Comment.d.ts +2 -2
- package/build/typescript/Comment.d.ts.map +1 -1
- package/build/typescript/CustomElementRegistry.d.ts +1 -0
- package/build/typescript/CustomElementRegistry.d.ts.map +1 -1
- package/build/typescript/CustomEvent.d.ts.map +1 -1
- package/build/typescript/Document.d.ts +10 -5
- package/build/typescript/Document.d.ts.map +1 -1
- package/build/typescript/DocumentFragment.d.ts +2 -1
- package/build/typescript/DocumentFragment.d.ts.map +1 -1
- package/build/typescript/Element.d.ts +16 -7
- package/build/typescript/Element.d.ts.map +1 -1
- package/build/typescript/ErrorEvent.d.ts.map +1 -1
- package/build/typescript/Event.d.ts +9 -10
- package/build/typescript/Event.d.ts.map +1 -1
- package/build/typescript/EventTarget.d.ts +20 -3
- package/build/typescript/EventTarget.d.ts.map +1 -1
- package/build/typescript/FocusEvent.d.ts.map +1 -1
- package/build/typescript/HTMLTemplateElement.d.ts.map +1 -1
- package/build/typescript/MutationObserver.d.ts +42 -0
- package/build/typescript/MutationObserver.d.ts.map +1 -1
- package/build/typescript/NamedNodeMap.d.ts +5 -3
- package/build/typescript/NamedNodeMap.d.ts.map +1 -1
- package/build/typescript/Node.d.ts +4 -3
- package/build/typescript/Node.d.ts.map +1 -1
- package/build/typescript/NodeList.d.ts +3 -2
- package/build/typescript/NodeList.d.ts.map +1 -1
- package/build/typescript/ParentNode.d.ts +29 -10
- package/build/typescript/ParentNode.d.ts.map +1 -1
- package/build/typescript/PromiseRejectionEvent.d.ts.map +1 -1
- package/build/typescript/SVGElement.d.ts +1 -1
- package/build/typescript/SVGElement.d.ts.map +1 -1
- package/build/typescript/Text.d.ts +1 -1
- package/build/typescript/Text.d.ts.map +1 -1
- package/build/typescript/ToggleEvent.d.ts.map +1 -1
- package/build/typescript/Window.d.ts +5 -1
- package/build/typescript/Window.d.ts.map +1 -1
- package/build/typescript/attribute-reactions.d.ts +4 -0
- package/build/typescript/attribute-reactions.d.ts.map +1 -0
- package/build/typescript/constants.d.ts +27 -18
- package/build/typescript/constants.d.ts.map +1 -1
- package/build/typescript/custom-element-reactions.d.ts +6 -0
- package/build/typescript/custom-element-reactions.d.ts.map +1 -0
- package/build/typescript/dom-exception.d.ts +2 -0
- package/build/typescript/dom-exception.d.ts.map +1 -0
- package/build/typescript/extensions.d.ts +4 -0
- package/build/typescript/extensions.d.ts.map +1 -0
- package/build/typescript/hook-effects.d.ts +6 -0
- package/build/typescript/hook-effects.d.ts.map +1 -0
- package/build/typescript/hooks.d.ts +3 -3
- package/build/typescript/hooks.d.ts.map +1 -1
- package/build/typescript/index.d.ts +1 -0
- package/build/typescript/index.d.ts.map +1 -1
- package/build/typescript/names.d.ts +11 -0
- package/build/typescript/names.d.ts.map +1 -0
- package/build/typescript/selectors.d.ts +21 -22
- package/build/typescript/selectors.d.ts.map +1 -1
- package/build/typescript/serialization.d.ts.map +1 -1
- package/build/typescript/shared.d.ts +10 -0
- package/build/typescript/shared.d.ts.map +1 -1
- package/build/typescript/tests/ChildNode.test.d.ts +2 -0
- package/build/typescript/tests/ChildNode.test.d.ts.map +1 -0
- package/build/typescript/tests/MutationObserver.test.d.ts +2 -0
- package/build/typescript/tests/MutationObserver.test.d.ts.map +1 -0
- package/build/typescript/tests/adopt-inserted-subtrees.test.d.ts +2 -0
- package/build/typescript/tests/adopt-inserted-subtrees.test.d.ts.map +1 -0
- package/build/typescript/tests/attr-mutation.test.d.ts +2 -0
- package/build/typescript/tests/attr-mutation.test.d.ts.map +1 -0
- package/build/typescript/tests/child-node-before-after.test.d.ts +2 -0
- package/build/typescript/tests/child-node-before-after.test.d.ts.map +1 -0
- package/build/typescript/tests/child-node-replace-with.test.d.ts +2 -0
- package/build/typescript/tests/child-node-replace-with.test.d.ts.map +1 -0
- package/build/typescript/tests/clone-import-namespaces.test.d.ts +2 -0
- package/build/typescript/tests/clone-import-namespaces.test.d.ts.map +1 -0
- package/build/typescript/tests/constants.test.d.ts +2 -0
- package/build/typescript/tests/constants.test.d.ts.map +1 -0
- package/build/typescript/tests/create-element-namespaces.test.d.ts +2 -0
- package/build/typescript/tests/create-element-namespaces.test.d.ts.map +1 -0
- package/build/typescript/tests/create-text-node.test.d.ts +2 -0
- package/build/typescript/tests/create-text-node.test.d.ts.map +1 -0
- package/build/typescript/tests/custom-element-reactions.test.d.ts +2 -0
- package/build/typescript/tests/custom-element-reactions.test.d.ts.map +1 -0
- package/build/typescript/tests/custom-element-registry.test.d.ts +2 -0
- package/build/typescript/tests/custom-element-registry.test.d.ts.map +1 -0
- package/build/typescript/tests/custom-event.test.d.ts +2 -0
- package/build/typescript/tests/custom-event.test.d.ts.map +1 -0
- package/build/typescript/tests/document-clone-import-contract.test.d.ts +2 -0
- package/build/typescript/tests/document-clone-import-contract.test.d.ts.map +1 -0
- package/build/typescript/tests/document.test.d.ts +2 -0
- package/build/typescript/tests/document.test.d.ts.map +1 -0
- package/build/typescript/tests/dom-mutation-selector-errors.test.d.ts +2 -0
- package/build/typescript/tests/dom-mutation-selector-errors.test.d.ts.map +1 -0
- package/build/typescript/tests/event-dispatch.test.d.ts +2 -0
- package/build/typescript/tests/event-dispatch.test.d.ts.map +1 -0
- package/build/typescript/tests/event-target.test.d.ts +2 -0
- package/build/typescript/tests/event-target.test.d.ts.map +1 -0
- package/build/typescript/tests/event.test.d.ts +2 -0
- package/build/typescript/tests/event.test.d.ts.map +1 -0
- package/build/typescript/tests/extensions.test.d.ts +2 -0
- package/build/typescript/tests/extensions.test.d.ts.map +1 -0
- package/build/typescript/tests/get-elements-by-tag-name.test.d.ts +2 -0
- package/build/typescript/tests/get-elements-by-tag-name.test.d.ts.map +1 -0
- package/build/typescript/tests/getElementsByClassName.test.d.ts +2 -0
- package/build/typescript/tests/getElementsByClassName.test.d.ts.map +1 -0
- package/build/typescript/tests/hooks.test.d.ts +2 -0
- package/build/typescript/tests/hooks.test.d.ts.map +1 -0
- package/build/typescript/tests/inner-html-parsing.test.d.ts +2 -0
- package/build/typescript/tests/inner-html-parsing.test.d.ts.map +1 -0
- package/build/typescript/tests/is-default-namespace.test.d.ts +2 -0
- package/build/typescript/tests/is-default-namespace.test.d.ts.map +1 -0
- package/build/typescript/tests/name-and-namespace-normalization.test.d.ts +2 -0
- package/build/typescript/tests/name-and-namespace-normalization.test.d.ts.map +1 -0
- package/build/typescript/tests/named-node-map.test.d.ts +2 -0
- package/build/typescript/tests/named-node-map.test.d.ts.map +1 -0
- package/build/typescript/tests/namespaced-attribute-reactions.test.d.ts +2 -0
- package/build/typescript/tests/namespaced-attribute-reactions.test.d.ts.map +1 -0
- package/build/typescript/tests/node.test.d.ts +2 -0
- package/build/typescript/tests/node.test.d.ts.map +1 -0
- package/build/typescript/tests/parent-node-mutation-return-values.test.d.ts +2 -0
- package/build/typescript/tests/parent-node-mutation-return-values.test.d.ts.map +1 -0
- package/build/typescript/tests/parent-node-mutation-validation.test.d.ts +2 -0
- package/build/typescript/tests/parent-node-mutation-validation.test.d.ts.map +1 -0
- package/build/typescript/tests/parent-node.test.d.ts +2 -0
- package/build/typescript/tests/parent-node.test.d.ts.map +1 -0
- package/build/typescript/tests/serialization-template.test.d.ts +2 -0
- package/build/typescript/tests/serialization-template.test.d.ts.map +1 -0
- package/build/typescript/tests/slot-attribute.test.d.ts +2 -0
- package/build/typescript/tests/slot-attribute.test.d.ts.map +1 -0
- package/build/typescript/tests/text-content.test.d.ts +2 -0
- package/build/typescript/tests/text-content.test.d.ts.map +1 -0
- package/build/typescript/tests/toggle-attribute.test.d.ts +2 -0
- package/build/typescript/tests/toggle-attribute.test.d.ts.map +1 -0
- package/build/typescript/tests/wide-tree-traversal.test.d.ts +2 -0
- package/build/typescript/tests/wide-tree-traversal.test.d.ts.map +1 -0
- package/build/typescript/tests/window-set-global.test.d.ts +2 -0
- package/build/typescript/tests/window-set-global.test.d.ts.map +1 -0
- package/package.json +1 -1
- package/source/Attr.ts +60 -8
- package/source/CharacterData.ts +13 -0
- package/source/ChildNode.ts +107 -14
- package/source/Comment.ts +2 -2
- package/source/CustomElementRegistry.ts +56 -0
- package/source/CustomEvent.ts +2 -2
- package/source/Document.ts +104 -38
- package/source/DocumentFragment.ts +12 -2
- package/source/Element.ts +129 -14
- package/source/Event.ts +34 -32
- package/source/EventTarget.ts +203 -79
- package/source/HTMLTemplateElement.ts +2 -1
- package/source/MutationObserver.ts +279 -1
- package/source/NamedNodeMap.ts +141 -60
- package/source/Node.ts +70 -14
- package/source/NodeList.ts +13 -3
- package/source/ParentNode.ts +500 -88
- package/source/SVGElement.ts +2 -2
- package/source/Text.ts +2 -2
- package/source/Window.ts +156 -17
- package/source/attribute-reactions.ts +32 -0
- package/source/constants.ts +40 -17
- package/source/custom-element-reactions.ts +64 -0
- package/source/dom-exception.ts +14 -0
- package/source/extensions.ts +4 -0
- package/source/hook-effects.ts +56 -0
- package/source/hooks.ts +11 -3
- package/source/index.ts +1 -0
- package/source/names.ts +94 -0
- package/source/selectors.ts +301 -138
- package/source/serialization.ts +224 -66
- package/source/shared.ts +269 -40
- package/source/tests/ChildNode.test.ts +178 -0
- package/source/tests/MutationObserver.test.ts +303 -0
- package/source/tests/adopt-inserted-subtrees.test.ts +584 -0
- package/source/tests/attr-mutation.test.ts +112 -0
- package/source/tests/child-node-before-after.test.ts +421 -0
- package/source/tests/child-node-replace-with.test.ts +251 -0
- package/source/tests/clone-import-namespaces.test.ts +365 -0
- package/source/tests/constants.test.ts +46 -0
- package/source/tests/create-element-namespaces.test.ts +142 -0
- package/source/tests/create-text-node.test.ts +38 -0
- package/source/tests/custom-element-reactions.test.ts +600 -0
- package/source/tests/custom-element-registry.test.ts +137 -0
- package/source/tests/custom-event.test.ts +26 -0
- package/source/tests/document-clone-import-contract.test.ts +77 -0
- package/source/tests/document.test.ts +122 -0
- package/source/tests/dom-mutation-selector-errors.test.ts +484 -0
- package/source/tests/event-dispatch.test.ts +270 -0
- package/source/tests/event-target.test.ts +208 -0
- package/source/tests/event.test.ts +98 -0
- package/source/tests/extensions.test.ts +159 -0
- package/source/tests/get-elements-by-tag-name.test.ts +79 -0
- package/source/tests/getElementsByClassName.test.ts +109 -0
- package/source/tests/hooks.test.ts +43 -0
- package/source/tests/inner-html-parsing.test.ts +461 -0
- package/source/tests/is-default-namespace.test.ts +111 -0
- package/source/tests/name-and-namespace-normalization.test.ts +319 -0
- package/source/tests/named-node-map.test.ts +122 -0
- package/source/tests/namespaced-attribute-reactions.test.ts +141 -0
- package/source/tests/node.test.ts +56 -0
- package/source/tests/parent-node-mutation-return-values.test.ts +63 -0
- package/source/tests/parent-node-mutation-validation.test.ts +362 -0
- package/source/tests/parent-node.test.ts +169 -0
- package/source/tests/selectors.test.ts +533 -22
- package/source/tests/serialization-template.test.ts +232 -0
- package/source/tests/slot-attribute.test.ts +133 -0
- package/source/tests/text-content.test.ts +440 -0
- package/source/tests/toggle-attribute.test.ts +113 -0
- package/source/tests/wide-tree-traversal.test.ts +699 -0
- package/source/tests/window-set-global.test.ts +321 -0
- package/tsconfig.json +1 -1
|
@@ -1,9 +1,53 @@
|
|
|
1
|
-
import { CHILD, NEXT, PARENT, PREV } from './constants.esnext';
|
|
1
|
+
import { CHILD, asciiLowercase, NEXT, splitOnASCIIWhitespace, HTML_NAMESPACE, PARENT, PREV } from './constants.esnext';
|
|
2
2
|
import { isElementNode } from './shared.esnext';
|
|
3
|
+
import { NodeList } from './NodeList.esnext';
|
|
4
|
+
import { createDOMException } from './dom-exception.esnext';
|
|
3
5
|
|
|
4
|
-
const
|
|
6
|
+
const COMBINATOR_DESCENDANT = 0;
|
|
7
|
+
const COMBINATOR_CHILD = 1;
|
|
8
|
+
const COMBINATOR_SIBLING = 2;
|
|
9
|
+
const COMBINATOR_ADJACENT = 3;
|
|
10
|
+
const COMBINATOR_INNER = 4;
|
|
11
|
+
const MATCHER_UNKNOWN = 0;
|
|
12
|
+
const MATCHER_ELEMENT = 1;
|
|
13
|
+
const MATCHER_ID = 2;
|
|
14
|
+
const MATCHER_CLASS = 3;
|
|
15
|
+
const MATCHER_ATTRIBUTE = 4;
|
|
16
|
+
const MATCHER_PSEUDO = 5;
|
|
17
|
+
const MATCHER_FUNCTION = 6;
|
|
18
|
+
const MATCHER_SCOPE = 7;
|
|
19
|
+
const SUPPORTED_IDENTIFIER_TEST = /^(?:--|-?[A-Za-z_\u0080-\u{10FFFF}])[A-Za-z0-9_\u0080-\u{10FFFF}-]*$/u;
|
|
20
|
+
function readFunctionArgument(selector, start) {
|
|
21
|
+
let depth = 1;
|
|
22
|
+
let quote = null;
|
|
23
|
+
for (let index = start; index < selector.length; index++) {
|
|
24
|
+
const character = selector[index];
|
|
25
|
+
if (quote) {
|
|
26
|
+
if (character === "\\") {
|
|
27
|
+
index++;
|
|
28
|
+
} else if (character === quote) {
|
|
29
|
+
quote = null;
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (character === '"' || character === "'") {
|
|
34
|
+
quote = character;
|
|
35
|
+
} else if (character === "(") {
|
|
36
|
+
depth++;
|
|
37
|
+
} else if (character === ")" && --depth === 0) {
|
|
38
|
+
return [selector.slice(start, index), index + 1];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return [selector.slice(start), selector.length];
|
|
42
|
+
}
|
|
43
|
+
function throwSelectorSyntaxError(selector) {
|
|
44
|
+
throw createDOMException(
|
|
45
|
+
`Invalid or unsupported selector: "${selector}"`,
|
|
46
|
+
"SyntaxError"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
5
49
|
function querySelector(within, selector) {
|
|
6
|
-
const parts = parseSelector(selector);
|
|
50
|
+
const parts = typeof selector === "string" ? parseSelector(selector) : [{ combinator: COMBINATOR_INNER, matchers: selector }];
|
|
7
51
|
let result = null;
|
|
8
52
|
const child = within[CHILD];
|
|
9
53
|
if (child && parts[0].matchers.length) {
|
|
@@ -15,8 +59,8 @@ function querySelector(within, selector) {
|
|
|
15
59
|
return result;
|
|
16
60
|
}
|
|
17
61
|
function querySelectorAll(within, selector) {
|
|
18
|
-
const parts = parseSelector(selector);
|
|
19
|
-
const results =
|
|
62
|
+
const parts = typeof selector === "string" ? parseSelector(selector) : [{ combinator: COMBINATOR_INNER, matchers: selector }];
|
|
63
|
+
const results = new NodeList();
|
|
20
64
|
const child = within[CHILD];
|
|
21
65
|
if (child && parts[0].matchers.length) {
|
|
22
66
|
walkNodesForSelector(child, parts, (node) => {
|
|
@@ -25,163 +69,221 @@ function querySelectorAll(within, selector) {
|
|
|
25
69
|
}
|
|
26
70
|
return results;
|
|
27
71
|
}
|
|
28
|
-
function parseSelector(selector) {
|
|
29
|
-
let part = { combinator:
|
|
72
|
+
function parseSelector(selector, insideHas = false, allowLeadingCombinator = false) {
|
|
73
|
+
let part = { combinator: COMBINATOR_INNER, matchers: [] };
|
|
30
74
|
const parts = [part];
|
|
31
|
-
const tokenizer =
|
|
75
|
+
const tokenizer = /[\t\n\f\r ]*?([>\t\n\f\r +~]?)[\t\n\f\r ]*?(?:(?:\[[\t\n\f\r ]*([^\]=\t\n\f\r ]+)[\t\n\f\r ]*(?:=[\t\n\f\r ]*(?:(['"])(.*?)\3|([^\]\t\n\f\r ]+)))?[\t\n\f\r ]*(?:\]|$))|([#.]?)([^\t\n\f\r #.[>:+~()]+)|:(\w+)(\()?)/gi;
|
|
76
|
+
const normalizedSelector = selector.replace(
|
|
77
|
+
/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g,
|
|
78
|
+
""
|
|
79
|
+
);
|
|
80
|
+
if (normalizedSelector === "") throwSelectorSyntaxError(selector);
|
|
81
|
+
let consumed = 0;
|
|
32
82
|
let token;
|
|
33
|
-
while (token = tokenizer.exec(
|
|
83
|
+
while (token = tokenizer.exec(normalizedSelector)) {
|
|
84
|
+
if (token.index !== consumed) throwSelectorSyntaxError(selector);
|
|
34
85
|
if (token[1]) {
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
86
|
+
if (part.matchers.length === 0 && !(allowLeadingCombinator && parts.length === 1)) {
|
|
87
|
+
throwSelectorSyntaxError(selector);
|
|
88
|
+
}
|
|
89
|
+
if (token[1] === ">") part.combinator = COMBINATOR_CHILD;
|
|
90
|
+
else if (token[1] === "+") part.combinator = COMBINATOR_ADJACENT;
|
|
91
|
+
else if (token[1] === "~") part.combinator = COMBINATOR_SIBLING;
|
|
92
|
+
else part.combinator = COMBINATOR_DESCENDANT;
|
|
93
|
+
part = { combinator: COMBINATOR_INNER, matchers: [] };
|
|
40
94
|
parts.push(part);
|
|
41
95
|
}
|
|
42
|
-
|
|
96
|
+
const name = token[8] ? asciiLowercase(token[8]) : token[2] || token[7];
|
|
97
|
+
const isTypeSelector = token[7] != null && !token[6];
|
|
98
|
+
if (isTypeSelector && part.matchers.length > 0) {
|
|
99
|
+
throwSelectorSyntaxError(selector);
|
|
100
|
+
}
|
|
101
|
+
let type;
|
|
102
|
+
let value = token[4] ?? token[5] ?? token[7];
|
|
43
103
|
if (token[2]) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
104
|
+
if (!SUPPORTED_IDENTIFIER_TEST.test(name)) {
|
|
105
|
+
throwSelectorSyntaxError(selector);
|
|
106
|
+
}
|
|
107
|
+
const unquotedValue = token[5];
|
|
108
|
+
const openingQuote = unquotedValue?.[0];
|
|
109
|
+
if (token[3] == null && (openingQuote === '"' || openingQuote === "'")) {
|
|
110
|
+
const valueOffset = token[0].lastIndexOf(unquotedValue);
|
|
111
|
+
value = normalizedSelector.slice(token.index + valueOffset + 1);
|
|
112
|
+
tokenizer.lastIndex = normalizedSelector.length;
|
|
113
|
+
} else if (unquotedValue != null && !SUPPORTED_IDENTIFIER_TEST.test(unquotedValue)) {
|
|
114
|
+
throwSelectorSyntaxError(selector);
|
|
115
|
+
}
|
|
116
|
+
type = MATCHER_ATTRIBUTE;
|
|
49
117
|
} else if (token[6]) {
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
} else if (ELEMENT_SELECTOR_TEST.test(token[6])) {
|
|
53
|
-
type = 1 /* Element */;
|
|
118
|
+
if (!SUPPORTED_IDENTIFIER_TEST.test(name)) {
|
|
119
|
+
throwSelectorSyntaxError(selector);
|
|
54
120
|
}
|
|
121
|
+
type = token[6] === "#" ? MATCHER_ID : MATCHER_CLASS;
|
|
122
|
+
} else if (token[8]) {
|
|
123
|
+
type = token[9] == null ? MATCHER_PSEUDO : MATCHER_FUNCTION;
|
|
124
|
+
} else if (token[7] === "*") {
|
|
125
|
+
type = MATCHER_UNKNOWN;
|
|
126
|
+
} else if (token[7] && SUPPORTED_IDENTIFIER_TEST.test(token[7])) {
|
|
127
|
+
type = MATCHER_ELEMENT;
|
|
128
|
+
} else {
|
|
129
|
+
throwSelectorSyntaxError(selector);
|
|
55
130
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
131
|
+
if (token[9]) {
|
|
132
|
+
[value, tokenizer.lastIndex] = readFunctionArgument(
|
|
133
|
+
normalizedSelector,
|
|
134
|
+
tokenizer.lastIndex
|
|
135
|
+
);
|
|
136
|
+
if (name !== "has" && name !== "not") {
|
|
137
|
+
throwSelectorSyntaxError(selector);
|
|
138
|
+
}
|
|
139
|
+
if (name === "has" && insideHas) throwSelectorSyntaxError(selector);
|
|
140
|
+
parseSelector(value, insideHas || name === "has", name === "has");
|
|
141
|
+
} else if (type === MATCHER_PSEUDO) {
|
|
142
|
+
throwSelectorSyntaxError(selector);
|
|
143
|
+
}
|
|
144
|
+
part.matchers.push({ type, name, value });
|
|
145
|
+
consumed = tokenizer.lastIndex;
|
|
146
|
+
}
|
|
147
|
+
if (consumed !== normalizedSelector.length || part.matchers.length === 0) {
|
|
148
|
+
throwSelectorSyntaxError(selector);
|
|
61
149
|
}
|
|
62
150
|
return parts;
|
|
63
151
|
}
|
|
64
152
|
function matchesSelector(element, selector) {
|
|
65
153
|
const parsed = parseSelector(selector);
|
|
66
|
-
|
|
67
|
-
while (part = parsed.pop()) {
|
|
68
|
-
if (!matchesSelectorPart(element, part)) return false;
|
|
69
|
-
}
|
|
70
|
-
return true;
|
|
154
|
+
return parsed[0]?.matchers.length ? matchesSelectorRecursive(element, parsed) : false;
|
|
71
155
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
156
|
+
function matchesRelativeSelector(scope, selector) {
|
|
157
|
+
const parts = parseSelector(selector, true, true);
|
|
158
|
+
const first = parts[0];
|
|
159
|
+
if (parts.length === 1 && first.matchers.length === 0) return false;
|
|
160
|
+
let leadingCombinator = COMBINATOR_DESCENDANT;
|
|
161
|
+
const scopeMatcher = { type: MATCHER_SCOPE, name: ":scope" };
|
|
162
|
+
if (first.matchers.length === 0) {
|
|
163
|
+
leadingCombinator = first.combinator;
|
|
164
|
+
first.matchers.push(scopeMatcher);
|
|
165
|
+
} else {
|
|
166
|
+
parts.unshift({
|
|
167
|
+
combinator: COMBINATOR_DESCENDANT,
|
|
168
|
+
matchers: [scopeMatcher]
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (parts.some(({ matchers }) => matchers.length === 0)) return false;
|
|
172
|
+
const root = leadingCombinator === COMBINATOR_ADJACENT || leadingCombinator === COMBINATOR_SIBLING ? scope[NEXT] : scope[CHILD];
|
|
173
|
+
if (!root) return false;
|
|
174
|
+
let matched = false;
|
|
175
|
+
walkNodesForSelector(
|
|
176
|
+
root,
|
|
177
|
+
parts,
|
|
178
|
+
() => {
|
|
179
|
+
matched = true;
|
|
79
180
|
return false;
|
|
181
|
+
},
|
|
182
|
+
scope
|
|
183
|
+
);
|
|
184
|
+
return matched;
|
|
185
|
+
}
|
|
186
|
+
function walkNodesForSelector(node, parts, callback, scope) {
|
|
187
|
+
const pendingSiblings = [];
|
|
188
|
+
let current = node;
|
|
189
|
+
while (current) {
|
|
190
|
+
if (isElementNode(current)) {
|
|
191
|
+
if (matchesSelectorRecursive(current, parts, scope)) {
|
|
192
|
+
if (callback(current) === false) return false;
|
|
193
|
+
}
|
|
194
|
+
const child = current[CHILD];
|
|
195
|
+
if (child) {
|
|
196
|
+
const sibling = current[NEXT];
|
|
197
|
+
if (sibling) pendingSiblings.push(sibling);
|
|
198
|
+
current = child;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
80
201
|
}
|
|
81
|
-
|
|
82
|
-
const next = node[NEXT];
|
|
83
|
-
if (next && walkNodesForSelector(next, parts, callback) === false) {
|
|
84
|
-
return false;
|
|
202
|
+
current = current[NEXT] ?? pendingSiblings.pop() ?? null;
|
|
85
203
|
}
|
|
86
204
|
return true;
|
|
87
205
|
}
|
|
88
|
-
function matchesSelectorRecursive(element, parts) {
|
|
206
|
+
function matchesSelectorRecursive(element, parts, scope) {
|
|
89
207
|
const { combinator, matchers } = parts[parts.length - 1];
|
|
90
|
-
if (combinator ===
|
|
91
|
-
if (!matchesSelectorMatcher(element, matchers)) return false;
|
|
208
|
+
if (combinator === COMBINATOR_INNER) {
|
|
209
|
+
if (!matchesSelectorMatcher(element, matchers, scope)) return false;
|
|
92
210
|
const pp = parts.slice(0, -1);
|
|
93
|
-
return pp.length === 0 || matchesSelectorRecursive(element, pp);
|
|
211
|
+
return pp.length === 0 || matchesSelectorRecursive(element, pp, scope);
|
|
94
212
|
}
|
|
95
|
-
const link = combinator ===
|
|
213
|
+
const link = combinator === COMBINATOR_CHILD || combinator === COMBINATOR_DESCENDANT ? PARENT : PREV;
|
|
96
214
|
let ref = element[link];
|
|
97
215
|
if (!ref) return false;
|
|
98
|
-
if (combinator ===
|
|
216
|
+
if (combinator === COMBINATOR_DESCENDANT || combinator === COMBINATOR_SIBLING) {
|
|
99
217
|
while (ref) {
|
|
100
|
-
if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers)) {
|
|
218
|
+
if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers, scope)) {
|
|
101
219
|
const pp = parts.slice(0, -1);
|
|
102
220
|
if (pp.length === 0) return true;
|
|
103
|
-
if (matchesSelectorRecursive(
|
|
221
|
+
if (matchesSelectorRecursive(ref, pp, scope)) return true;
|
|
104
222
|
}
|
|
105
223
|
ref = ref[link];
|
|
106
224
|
}
|
|
107
225
|
return false;
|
|
108
226
|
} else {
|
|
109
|
-
if (combinator ===
|
|
227
|
+
if (combinator === COMBINATOR_ADJACENT && !isElementNode(ref)) {
|
|
110
228
|
while (ref && !isElementNode(ref)) {
|
|
111
229
|
ref = ref[link];
|
|
112
230
|
}
|
|
113
231
|
if (!ref) return false;
|
|
114
232
|
}
|
|
115
|
-
if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
|
|
233
|
+
if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers, scope)) {
|
|
116
234
|
return false;
|
|
117
235
|
}
|
|
118
236
|
const pp = parts.slice(0, -1);
|
|
119
|
-
return pp.length === 0 || matchesSelectorRecursive(
|
|
237
|
+
return pp.length === 0 || matchesSelectorRecursive(ref, pp, scope);
|
|
120
238
|
}
|
|
121
239
|
}
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
let ref = element[link];
|
|
128
|
-
if (!ref) return false;
|
|
129
|
-
if (combinator === 3 /* Adjacent */ && !isElementNode(ref)) {
|
|
130
|
-
while (ref && !isElementNode(ref)) {
|
|
131
|
-
ref = ref[link];
|
|
132
|
-
}
|
|
133
|
-
if (!ref) return false;
|
|
134
|
-
}
|
|
135
|
-
if (!isElementNode(ref) || !matchesSelectorMatcher(ref, matchers)) {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
if (combinator === 0 /* Descendant */ || combinator === 2 /* Sibling */) {
|
|
139
|
-
while (ref = ref[link]) {
|
|
140
|
-
if (isElementNode(ref) && matchesSelectorMatcher(ref, matchers))
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return true;
|
|
240
|
+
function getSelectorAttribute(element, name) {
|
|
241
|
+
return element.getAttributeNS(
|
|
242
|
+
null,
|
|
243
|
+
element.namespaceURI === HTML_NAMESPACE ? asciiLowercase(name) : name
|
|
244
|
+
);
|
|
145
245
|
}
|
|
146
|
-
function matchesSelectorMatcher(element, matcher) {
|
|
246
|
+
function matchesSelectorMatcher(element, matcher, scope) {
|
|
147
247
|
if (!element) return false;
|
|
148
248
|
if (Array.isArray(matcher)) {
|
|
149
249
|
for (const single of matcher) {
|
|
150
|
-
if (matchesSelectorMatcher(element, single) === false)
|
|
250
|
+
if (matchesSelectorMatcher(element, single, scope) === false) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
151
253
|
}
|
|
152
254
|
return true;
|
|
153
255
|
}
|
|
154
256
|
const { type, name, value } = matcher;
|
|
155
257
|
switch (type) {
|
|
156
|
-
case
|
|
258
|
+
case MATCHER_UNKNOWN:
|
|
157
259
|
return name === "*";
|
|
158
260
|
// Universal selector
|
|
159
|
-
case
|
|
160
|
-
return element.localName === name;
|
|
161
|
-
case
|
|
162
|
-
return element
|
|
163
|
-
case
|
|
164
|
-
const classAttr = element
|
|
261
|
+
case MATCHER_ELEMENT:
|
|
262
|
+
return element.namespaceURI === HTML_NAMESPACE ? element.localName === asciiLowercase(name) : element.localName === name;
|
|
263
|
+
case MATCHER_ID:
|
|
264
|
+
return getSelectorAttribute(element, "id") === name;
|
|
265
|
+
case MATCHER_CLASS:
|
|
266
|
+
const classAttr = getSelectorAttribute(element, "class");
|
|
165
267
|
if (!classAttr) return false;
|
|
166
|
-
return classAttr
|
|
167
|
-
case
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
case
|
|
268
|
+
return splitOnASCIIWhitespace(classAttr).includes(name);
|
|
269
|
+
case MATCHER_ATTRIBUTE:
|
|
270
|
+
const attribute = getSelectorAttribute(element, name);
|
|
271
|
+
return value == null ? attribute != null : attribute === value;
|
|
272
|
+
case MATCHER_SCOPE:
|
|
273
|
+
return element === scope;
|
|
274
|
+
case MATCHER_PSEUDO:
|
|
275
|
+
throwSelectorSyntaxError(`:${name}`);
|
|
276
|
+
case MATCHER_FUNCTION:
|
|
175
277
|
switch (name) {
|
|
176
278
|
case "has":
|
|
177
|
-
return
|
|
279
|
+
return matchesRelativeSelector(element, value || "");
|
|
178
280
|
case "not":
|
|
179
281
|
return !matchesSelector(element, value || "");
|
|
180
282
|
default:
|
|
181
|
-
|
|
283
|
+
throwSelectorSyntaxError(`:${name}(${value})`);
|
|
182
284
|
}
|
|
183
285
|
}
|
|
184
286
|
return false;
|
|
185
287
|
}
|
|
186
288
|
|
|
187
|
-
export { parseSelector, querySelector, querySelectorAll };
|
|
289
|
+
export { COMBINATOR_ADJACENT, COMBINATOR_CHILD, COMBINATOR_DESCENDANT, COMBINATOR_INNER, COMBINATOR_SIBLING, MATCHER_ATTRIBUTE, MATCHER_CLASS, MATCHER_ELEMENT, MATCHER_FUNCTION, MATCHER_ID, MATCHER_PSEUDO, MATCHER_SCOPE, MATCHER_UNKNOWN, parseSelector, querySelector, querySelectorAll };
|
|
@@ -1,76 +1,199 @@
|
|
|
1
|
-
import { CHILD, NEXT,
|
|
1
|
+
import { CHILD, asciiLowercase, NS, SVG_NAMESPACE, HTML_NAMESPACE, CREATE_ELEMENT, NAME, NEXT, NODE_TYPE_COMMENT, DATA, NODE_TYPE_TEXT, NODE_TYPE_ELEMENT, ATTRIBUTES, VALUE, CONTENT } from './constants.esnext';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const CHARACTER_REFERENCES = {
|
|
4
|
+
amp: "&",
|
|
5
|
+
AMP: "&",
|
|
6
|
+
apos: "'",
|
|
7
|
+
gt: ">",
|
|
8
|
+
GT: ">",
|
|
9
|
+
lt: "<",
|
|
10
|
+
LT: "<",
|
|
11
|
+
quot: '"',
|
|
12
|
+
QUOT: '"'
|
|
13
|
+
};
|
|
14
|
+
const VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
15
|
+
"area",
|
|
16
|
+
"base",
|
|
17
|
+
"br",
|
|
18
|
+
"col",
|
|
19
|
+
"embed",
|
|
20
|
+
"hr",
|
|
21
|
+
"img",
|
|
22
|
+
"input",
|
|
23
|
+
"link",
|
|
24
|
+
"meta",
|
|
25
|
+
"param",
|
|
26
|
+
"source",
|
|
27
|
+
"track",
|
|
28
|
+
"wbr"
|
|
29
|
+
]);
|
|
30
|
+
const ELEMENT_TOKENIZER = /(?:<([a-z][a-z0-9-:]*)((?:[\s]+[^<>'"=/\s]+(?:=(['"])[^]*?\3|=[^>'"\s]*|))*)[\s]*(\/?)\s*>|<\/([a-z][a-z0-9-:]*)>|<!--(.*?)-->|([^<>]+))/gi;
|
|
31
|
+
const ATTRIBUTE_TOKENIZER = /\s([^<>'"=/\n\s]+)(?:=(["'])([\s\S]*?)\2|=([^>'"\n\s]*)|)/g;
|
|
32
|
+
const SVG_HTML_BREAKOUTS = "|b|big|blockquote|body|br|center|code|dd|div|dl|dt|em|embed|h1|h2|h3|h4|h5|h6|head|hr|i|img|li|listing|menu|meta|nobr|ol|p|pre|ruby|s|small|span|strong|strike|sub|sup|table|tt|u|ul|var|";
|
|
33
|
+
const SVG_HTML_FONT_ATTRIBUTE = /^(?:color|face|size)$/i;
|
|
34
|
+
function decodeCharacterReferences(value) {
|
|
35
|
+
return value.replace(
|
|
36
|
+
/&(?:(amp|AMP|apos|gt|GT|lt|LT|quot|QUOT)|#(\d+)|#[xX]([\da-fA-F]+));/g,
|
|
37
|
+
(reference, name, decimal, hexadecimal) => {
|
|
38
|
+
if (name) return CHARACTER_REFERENCES[name];
|
|
39
|
+
const codePoint = Number.parseInt(
|
|
40
|
+
decimal ?? hexadecimal,
|
|
41
|
+
decimal ? 10 : 16
|
|
42
|
+
);
|
|
43
|
+
try {
|
|
44
|
+
return String.fromCodePoint(codePoint);
|
|
45
|
+
} catch {
|
|
46
|
+
return reference;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
function isVoidElement(element) {
|
|
52
|
+
return element.namespaceURI === HTML_NAMESPACE && VOID_ELEMENTS.has(element.localName);
|
|
53
|
+
}
|
|
54
|
+
function isHtmlIntegrationPoint(element) {
|
|
55
|
+
const name = element.localName;
|
|
56
|
+
return element[NS] === SVG_NAMESPACE && (name === "foreignObject" || name === "desc" || name === "title");
|
|
57
|
+
}
|
|
58
|
+
function isSvgHtmlBreakout(tag, attributes) {
|
|
59
|
+
if (SVG_HTML_BREAKOUTS.includes(`|${tag}|`)) return true;
|
|
60
|
+
if (tag !== "font") return false;
|
|
61
|
+
for (const attribute of attributes.matchAll(ATTRIBUTE_TOKENIZER)) {
|
|
62
|
+
if (SVG_HTML_FONT_ATTRIBUTE.test(attribute[1])) return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
5
66
|
function parseHtml(html, contextNode) {
|
|
6
67
|
const document = contextNode.ownerDocument;
|
|
7
68
|
const root = document.createDocumentFragment();
|
|
8
|
-
const stack = [
|
|
69
|
+
const stack = [];
|
|
9
70
|
let parent = root;
|
|
10
|
-
|
|
11
|
-
elementTokenizer.lastIndex = 0;
|
|
12
|
-
while (token = elementTokenizer.exec(html)) {
|
|
71
|
+
for (const token of html.matchAll(ELEMENT_TOKENIZER)) {
|
|
13
72
|
const tag = token[1];
|
|
14
73
|
if (tag) {
|
|
15
|
-
const node = document.createElement(tag);
|
|
16
74
|
const attrs = token[2];
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
75
|
+
const normalizedTag = asciiLowercase(tag);
|
|
76
|
+
const openElement = stack[stack.length - 1]?.element ?? contextNode;
|
|
77
|
+
let namespace = openElement[NS] === SVG_NAMESPACE ? SVG_NAMESPACE : HTML_NAMESPACE;
|
|
78
|
+
if (normalizedTag === "svg") {
|
|
79
|
+
namespace = SVG_NAMESPACE;
|
|
80
|
+
} else if (namespace === SVG_NAMESPACE) {
|
|
81
|
+
if (isHtmlIntegrationPoint(openElement)) {
|
|
82
|
+
namespace = HTML_NAMESPACE;
|
|
83
|
+
} else if (isSvgHtmlBreakout(normalizedTag, attrs)) {
|
|
84
|
+
while (stack.length > 0) {
|
|
85
|
+
const frame = stack[stack.length - 1];
|
|
86
|
+
if (frame.element[NS] !== SVG_NAMESPACE || isHtmlIntegrationPoint(frame.element)) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
stack.pop();
|
|
90
|
+
parent = frame.target;
|
|
91
|
+
}
|
|
92
|
+
namespace = HTML_NAMESPACE;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const name = namespace === HTML_NAMESPACE ? normalizedTag : tag;
|
|
96
|
+
const node = document[CREATE_ELEMENT](name, namespace, null, name);
|
|
97
|
+
for (const attribute of attrs.matchAll(ATTRIBUTE_TOKENIZER)) {
|
|
98
|
+
node.setAttribute(
|
|
99
|
+
attribute[1],
|
|
100
|
+
decodeCharacterReferences(attribute[3] || attribute[4] || "")
|
|
101
|
+
);
|
|
21
102
|
}
|
|
22
103
|
parent.append(node);
|
|
23
|
-
|
|
24
|
-
|
|
104
|
+
if (isVoidElement(node) || namespace !== HTML_NAMESPACE && token[4]) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
stack.push({ element: node, target: parent });
|
|
108
|
+
parent = namespace === HTML_NAMESPACE && normalizedTag === "template" ? node.content : node;
|
|
25
109
|
} else if (token[5]) {
|
|
26
|
-
|
|
110
|
+
const closingTag = asciiLowercase(token[5]);
|
|
111
|
+
for (let index = stack.length - 1; index >= 0; index--) {
|
|
112
|
+
const frame = stack[index];
|
|
113
|
+
const frameName = asciiLowercase(frame.element[NAME]);
|
|
114
|
+
if (frameName === closingTag) {
|
|
115
|
+
parent = frame.target;
|
|
116
|
+
stack.length = index;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
if (frame.element[NS] === HTML_NAMESPACE && frameName === "template") {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
27
123
|
} else if (token[6]) {
|
|
28
124
|
parent.append(document.createComment(token[6]));
|
|
29
125
|
} else {
|
|
30
|
-
parent.append(token[7]);
|
|
126
|
+
parent.append(decodeCharacterReferences(token[7]));
|
|
31
127
|
}
|
|
32
128
|
}
|
|
33
129
|
return root;
|
|
34
130
|
}
|
|
35
131
|
function serializeChildren(parentNode) {
|
|
36
|
-
|
|
37
|
-
let child = parentNode[CHILD];
|
|
38
|
-
while (child) {
|
|
39
|
-
out += serializeNode(child);
|
|
40
|
-
child = child[NEXT];
|
|
41
|
-
}
|
|
42
|
-
return out;
|
|
132
|
+
return serialize([{ type: "content", child: parentNode[CHILD] }]);
|
|
43
133
|
}
|
|
44
134
|
function serializeNode(node) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
135
|
+
return serialize([{ type: "opening", node }]);
|
|
136
|
+
}
|
|
137
|
+
function serialize(workItems) {
|
|
138
|
+
const chunks = [];
|
|
139
|
+
let workItem;
|
|
140
|
+
while (workItem = workItems.pop()) {
|
|
141
|
+
switch (workItem.type) {
|
|
142
|
+
case "opening": {
|
|
143
|
+
const node = workItem.node;
|
|
144
|
+
switch (node.nodeType) {
|
|
145
|
+
case NODE_TYPE_ELEMENT: {
|
|
146
|
+
const el = node;
|
|
147
|
+
chunks.push(`<${el[NAME]}`);
|
|
148
|
+
let attr = el[ATTRIBUTES]?.[CHILD];
|
|
149
|
+
while (attr) {
|
|
150
|
+
chunks.push(` ${attr[NAME]}`);
|
|
151
|
+
let value = attr[VALUE];
|
|
152
|
+
if (value !== "") {
|
|
153
|
+
value = String(value).replace(/&/g, "&").replace(/"/g, """);
|
|
154
|
+
chunks.push(`="${value}"`);
|
|
155
|
+
}
|
|
156
|
+
attr = attr[NEXT];
|
|
157
|
+
}
|
|
158
|
+
chunks.push(">");
|
|
159
|
+
if (isVoidElement(el)) break;
|
|
160
|
+
const content = el.namespaceURI === HTML_NAMESPACE && el.localName === "template" ? el[CONTENT] : el;
|
|
161
|
+
workItems.push({ type: "closing", name: el[NAME] });
|
|
162
|
+
workItems.push({
|
|
163
|
+
type: "content",
|
|
164
|
+
child: content?.[CHILD] ?? null
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case NODE_TYPE_TEXT: {
|
|
169
|
+
const text = node;
|
|
170
|
+
chunks.push(
|
|
171
|
+
text[DATA].replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")
|
|
172
|
+
);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case NODE_TYPE_COMMENT: {
|
|
176
|
+
const text = node;
|
|
177
|
+
chunks.push(`<!--${text[DATA]}-->`);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
56
180
|
}
|
|
57
|
-
|
|
181
|
+
break;
|
|
58
182
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return `<!--${text[DATA]}-->`;
|
|
183
|
+
case "content": {
|
|
184
|
+
const child = workItem.child;
|
|
185
|
+
if (child) {
|
|
186
|
+
workItems.push({ type: "content", child: child[NEXT] });
|
|
187
|
+
workItems.push({ type: "opening", node: child });
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case "closing":
|
|
192
|
+
chunks.push(`</${workItem.name}>`);
|
|
193
|
+
break;
|
|
71
194
|
}
|
|
72
195
|
}
|
|
73
|
-
return "";
|
|
196
|
+
return chunks.join("");
|
|
74
197
|
}
|
|
75
198
|
|
|
76
199
|
export { parseHtml, serializeChildren, serializeNode };
|