@markuplint/ml-core 4.13.3 → 5.0.0-alpha.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.
Files changed (57) hide show
  1. package/ARCHITECTURE.ja.md +92 -35
  2. package/ARCHITECTURE.md +85 -28
  3. package/CHANGELOG.md +50 -0
  4. package/docs/linting-pipeline.ja.md +18 -14
  5. package/docs/linting-pipeline.md +18 -14
  6. package/docs/maintenance.ja.md +1 -1
  7. package/docs/maintenance.md +1 -1
  8. package/docs/ml-dom/attr.ja.md +8 -0
  9. package/docs/ml-dom/attr.md +8 -0
  10. package/docs/ml-dom/block.ja.md +33 -33
  11. package/docs/ml-dom/block.md +33 -33
  12. package/docs/ml-dom/element.ja.md +17 -17
  13. package/docs/ml-dom/element.md +17 -17
  14. package/docs/ml-dom/node.ja.md +4 -5
  15. package/docs/ml-dom/node.md +4 -5
  16. package/docs/ml-dom/others.ja.md +2 -1
  17. package/docs/ml-dom/others.md +5 -4
  18. package/docs/rule-system.ja.md +23 -6
  19. package/docs/rule-system.md +23 -6
  20. package/lib/index.d.ts +4 -3
  21. package/lib/index.js +1 -1
  22. package/lib/ml-core.d.ts +1 -1
  23. package/lib/ml-core.js +142 -82
  24. package/lib/ml-dom/helper/accname.d.ts +8 -0
  25. package/lib/ml-dom/helper/accname.js +71 -55
  26. package/lib/ml-dom/helper/create-node.js +1 -0
  27. package/lib/ml-dom/helper/get-indent.js +17 -29
  28. package/lib/ml-dom/node/attr.js +122 -73
  29. package/lib/ml-dom/node/block.d.ts +3 -3
  30. package/lib/ml-dom/node/block.js +10 -1
  31. package/lib/ml-dom/node/document-type.js +12 -0
  32. package/lib/ml-dom/node/document.d.ts +14 -3
  33. package/lib/ml-dom/node/document.js +75 -34
  34. package/lib/ml-dom/node/dom-token-list.js +17 -30
  35. package/lib/ml-dom/node/element-close-tag.js +1 -0
  36. package/lib/ml-dom/node/element.d.ts +19 -7
  37. package/lib/ml-dom/node/element.js +134 -55
  38. package/lib/ml-dom/node/node-store.js +6 -15
  39. package/lib/ml-dom/node/node.d.ts +3 -1
  40. package/lib/ml-dom/node/node.js +159 -166
  41. package/lib/ml-dom/node/parent-node.js +14 -30
  42. package/lib/ml-dom/node/rule-mapper.js +7 -20
  43. package/lib/ml-dom/node/text.d.ts +7 -0
  44. package/lib/ml-dom/node/text.js +9 -0
  45. package/lib/ml-dom/token/token.js +23 -39
  46. package/lib/ml-rule/create-rule.d.ts +8 -1
  47. package/lib/ml-rule/create-rule.js +0 -9
  48. package/lib/ml-rule/ml-rule-context.js +7 -11
  49. package/lib/ml-rule/ml-rule.d.ts +33 -1
  50. package/lib/ml-rule/ml-rule.js +65 -25
  51. package/lib/ruleset/index.js +6 -0
  52. package/lib/test/index.js +4 -1
  53. package/lib/types.d.ts +2 -1
  54. package/lib/violation-collector.js +15 -28
  55. package/lib/virtual-rule.d.ts +72 -0
  56. package/lib/virtual-rule.js +233 -0
  57. package/package.json +16 -13
@@ -3,11 +3,10 @@ import type { MLNamedNodeMap } from './named-node-map.js';
3
3
  import type { MLNode } from './node.js';
4
4
  import type { MLText } from './text.js';
5
5
  import type { ElementNodeType, PretenderContext } from './types.js';
6
- import type { ElementType, MLASTElement, NamespaceURI } from '@markuplint/ml-ast';
6
+ import type { ElementType, MLASTBlockBehavior, MLASTElement, NamespaceURI } from '@markuplint/ml-ast';
7
7
  import type { PlainData, Pretender, RegexSelector, RuleConfigValue, RuleInfo } from '@markuplint/ml-config';
8
8
  import type { ARIAVersion } from '@markuplint/ml-spec';
9
9
  import type { SelectorMatches } from '@markuplint/selector';
10
- import { MLToken } from '../token/token.js';
11
10
  import { MLAttr } from './attr.js';
12
11
  import { MLDomTokenList } from './dom-token-list.js';
13
12
  import { MLElementCloseTag } from './element-close-tag.js';
@@ -57,9 +56,9 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
57
56
  */
58
57
  pretenderContext: PretenderContext<MLElement<T, O>, T, O> | null;
59
58
  /**
60
- * The self-closing solidus token (`/`), or null if the element is not self-closing.
59
+ * Block behavior associated with this element, if any.
61
60
  */
62
- readonly selfClosingSolidus: MLToken | null;
61
+ readonly blockBehavior: MLASTBlockBehavior | null;
63
62
  /**
64
63
  * The tag close character string (e.g., `>` or `/>` or `%>`).
65
64
  */
@@ -1836,12 +1835,25 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
1836
1835
  */
1837
1836
  focus(options?: FocusOptions): void;
1838
1837
  /**
1839
- * Computes the accessible name of this element according to the
1840
- * Accessible Name and Description Computation algorithm.
1838
+ * Returns the accessible name of this element, with per-element memoization.
1839
+ *
1840
+ * On the first call for a given ARIA version the full AccName Computation
1841
+ * algorithm runs (tree walk, `aria-labelledby` resolution, `<label>` lookup,
1842
+ * etc.) and the result is stored in {@link #accessibleNameCache}.
1843
+ * Subsequent calls for the same version return the cached value in O(1).
1844
+ *
1845
+ * **All callers that need the accessible name of an MLElement should use
1846
+ * this method** rather than importing `getAccname()` directly, so that
1847
+ * every consumer benefits from the shared cache. This includes the
1848
+ * `:aria(has name)` selector in `@markuplint/selector`, which uses
1849
+ * duck-typing to detect and call this method.
1850
+ *
1851
+ * Added as part of the fix for {@link https://github.com/markuplint/markuplint/issues/2179 | #2179}
1852
+ * to eliminate redundant AccName computation across rules.
1841
1853
  *
1842
1854
  * @implements `@markuplint/ml-core` API: `MLElement`
1843
1855
  * @param version - The ARIA specification version to use for computation
1844
- * @returns The computed accessible name string
1856
+ * @returns The computed accessible name string (may be empty)
1845
1857
  */
1846
1858
  getAccessibleName(version: ARIAVersion): string;
1847
1859
  /**
@@ -1,21 +1,8 @@
1
1
  /* global StylePropertyMap, StylePropertyMapReadOnly */
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _MLElement_attributes, _MLElement_fixedNodeName, _MLElement_getChildElementsAndTextNodeWithoutWhitespacesCache, _MLElement_localName, _MLElement_normalizedAttrs, _MLElement_normalizedString;
14
2
  import { resolveNamespace } from '@markuplint/ml-spec';
15
3
  import { matchSelector } from '@markuplint/selector';
16
4
  import { getAccname } from '../helper/accname.js';
17
5
  import { after, before, nextElementSibling, previousElementSibling, remove, replaceWith, } from '../manipulations/child-node-methods.js';
18
- import { MLToken } from '../token/token.js';
19
6
  import { MLAttr } from './attr.js';
20
7
  import { MLDomTokenList } from './dom-token-list.js';
21
8
  import { MLElementCloseTag } from './element-close-tag.js';
@@ -34,6 +21,91 @@ const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
34
21
  * @template O - The rule options type
35
22
  */
36
23
  export class MLElement extends MLParentNode {
24
+ #attributes;
25
+ /**
26
+ * The closing tag for this element, or null if the element is self-closing or void.
27
+ */
28
+ closeTag;
29
+ /**
30
+ * Element type
31
+ *
32
+ * - `html`: From native HTML Standard
33
+ * - `web-component`: As the Web Component according to HTML Standard
34
+ * - `authored`: Authored element (JSX Element etc.) through the view framework or the template engine.
35
+ */
36
+ elementType;
37
+ #fixedNodeName;
38
+ #getChildElementsAndTextNodeWithoutWhitespacesCache = null;
39
+ /**
40
+ * Whether this element belongs to a non-HTML namespace (e.g., SVG or MathML).
41
+ */
42
+ isForeignElement;
43
+ /**
44
+ * Whether this element was implicitly created (e.g., an omitted `<body>` tag in HTML).
45
+ */
46
+ isOmitted;
47
+ #localName;
48
+ /**
49
+ * The namespace URI of this element (e.g., `http://www.w3.org/1999/xhtml` for HTML elements).
50
+ */
51
+ namespaceURI;
52
+ /**
53
+ * Memoization cache for the accessible name computation, keyed by ARIA version.
54
+ *
55
+ * ## Why this cache exists
56
+ *
57
+ * Multiple rules and the `:aria(has name)` selector evaluate the accessible name
58
+ * of every element during a single lint pass. Without caching, the same
59
+ * expensive tree-walking algorithm (AccName Computation 1.2) runs repeatedly
60
+ * for the same element — once per consumer. Benchmarks on a 500-element page
61
+ * show **14,626 total calls** of which **11,573 (79%) are cache hits**,
62
+ * eliminating redundant computation.
63
+ *
64
+ * ## Why memoization is safe
65
+ *
66
+ * The MLDOM is **immutable** once constructed — no attributes or child nodes
67
+ * change during a lint pass. Therefore the accessible name for a given ARIA
68
+ * version is deterministic and will never become stale. No invalidation
69
+ * logic is needed. The cache is garbage-collected together with the
70
+ * MLElement instance when the document is released.
71
+ *
72
+ * ## Consumers that benefit
73
+ *
74
+ * - `require-accessible-name` rule (direct call)
75
+ * - `wai-aria` rule via `:aria(has name)` selector
76
+ * - `neighbor-popovers` rule
77
+ * - `landmark-roles` rule
78
+ * - `MLDocument.getAccessibilityProp()` (accessibility tree builder)
79
+ *
80
+ * Introduced to resolve {@link https://github.com/markuplint/markuplint/issues/2179 | #2179}
81
+ * (AccName performance bottleneck).
82
+ *
83
+ * @see {@link getAccessibleName} — the public method that reads/writes this cache
84
+ */
85
+ #accessibleNameCache = new Map();
86
+ #normalizedAttrs = new Map();
87
+ #normalizedString = null;
88
+ ontouchcancel;
89
+ ontouchend;
90
+ ontouchmove;
91
+ ontouchstart;
92
+ /**
93
+ * The pretender context if this element is participating in pretender behavior,
94
+ * or null if it is not a pretender or pretended element.
95
+ */
96
+ pretenderContext = null;
97
+ /**
98
+ * Block behavior associated with this element, if any.
99
+ */
100
+ blockBehavior;
101
+ /**
102
+ * The tag close character string (e.g., `>` or `/>` or `%>`).
103
+ */
104
+ tagCloseChar;
105
+ /**
106
+ * The tag open character string (e.g., `<` or `<%`).
107
+ */
108
+ tagOpenChar;
37
109
  /**
38
110
  * Creates a new MLElement instance from an AST element node.
39
111
  *
@@ -44,29 +116,18 @@ export class MLElement extends MLParentNode {
44
116
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
45
117
  document) {
46
118
  super(astNode, document, astNode.isFragment);
47
- _MLElement_attributes.set(this, void 0);
48
- _MLElement_fixedNodeName.set(this, void 0);
49
- _MLElement_getChildElementsAndTextNodeWithoutWhitespacesCache.set(this, null);
50
- _MLElement_localName.set(this, void 0);
51
- _MLElement_normalizedAttrs.set(this, new Map());
52
- _MLElement_normalizedString.set(this, null);
53
- /**
54
- * The pretender context if this element is participating in pretender behavior,
55
- * or null if it is not a pretender or pretended element.
56
- */
57
- this.pretenderContext = null;
58
- __classPrivateFieldSet(this, _MLElement_attributes, astNode.attributes.map(attr => new MLAttr(attr, this)), "f");
59
- this.selfClosingSolidus = astNode.selfClosingSolidus ? new MLToken(astNode.selfClosingSolidus) : null;
119
+ this.#attributes = astNode.attributes.map(attr => new MLAttr(attr, this));
60
120
  this.closeTag = astNode.pairNode ? new MLElementCloseTag(astNode.pairNode, document, this) : null;
61
121
  const ns = resolveNamespace(astNode.nodeName, astNode.namespace);
62
- this.namespaceURI = ns.namespaceURI;
122
+ this.namespaceURI = astNode.namespace;
63
123
  this.elementType = astNode.elementType;
64
- __classPrivateFieldSet(this, _MLElement_localName, ns.localName, "f");
124
+ this.#localName = ns.localName;
65
125
  this.isForeignElement = this.namespaceURI !== HTML_NAMESPACE;
66
- __classPrivateFieldSet(this, _MLElement_fixedNodeName, astNode.nodeName, "f");
126
+ this.#fixedNodeName = astNode.nodeName;
67
127
  this.isOmitted = astNode.isGhost;
68
128
  this.tagOpenChar = astNode.tagOpenChar;
69
129
  this.tagCloseChar = astNode.tagCloseChar;
130
+ this.blockBehavior = astNode.blockBehavior;
70
131
  }
71
132
  /**
72
133
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
@@ -622,9 +683,9 @@ export class MLElement extends MLParentNode {
622
683
  * @see https://dom.spec.whatwg.org/#dom-element-attributes
623
684
  */
624
685
  get attributes() {
625
- const origin = this.pretenderContext?.type === 'pretender' ? __classPrivateFieldGet(this.pretenderContext.as, _MLElement_attributes, "f") : __classPrivateFieldGet(this, _MLElement_attributes, "f");
626
- if (__classPrivateFieldGet(this, _MLElement_normalizedAttrs, "f").has(origin)) {
627
- return __classPrivateFieldGet(this, _MLElement_normalizedAttrs, "f").get(origin);
686
+ const origin = this.pretenderContext?.type === 'pretender' ? this.pretenderContext.as.#attributes : this.#attributes;
687
+ if (this.#normalizedAttrs.has(origin)) {
688
+ return this.#normalizedAttrs.get(origin);
628
689
  }
629
690
  const names = new Set();
630
691
  const attrs = [];
@@ -640,7 +701,7 @@ export class MLElement extends MLParentNode {
640
701
  attrs.push(attr);
641
702
  }
642
703
  const map = toNamedNodeMap(attrs);
643
- __classPrivateFieldGet(this, _MLElement_normalizedAttrs, "f").set(origin, map);
704
+ this.#normalizedAttrs.set(origin, map);
644
705
  return map;
645
706
  }
646
707
  /**
@@ -796,13 +857,13 @@ export class MLElement extends MLParentNode {
796
857
  * @implements `@markuplint/ml-core` API: `MLElement`
797
858
  */
798
859
  get fixedNodeName() {
799
- return __classPrivateFieldGet(this, _MLElement_fixedNodeName, "f");
860
+ return this.#fixedNodeName;
800
861
  }
801
862
  /**
802
863
  * Whether this element has any spread attributes (e.g., `{...props}` in JSX).
803
864
  */
804
865
  get hasSpreadAttr() {
805
- return __classPrivateFieldGet(this, _MLElement_attributes, "f").some(attr => attr.localName === '#spread');
866
+ return this.#attributes.some(attr => attr.localName === '#spread');
806
867
  }
807
868
  /**
808
869
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
@@ -902,12 +963,12 @@ export class MLElement extends MLParentNode {
902
963
  return this.pretenderContext.as.localName;
903
964
  }
904
965
  if (this.isForeignElement || this.elementType !== 'html') {
905
- return __classPrivateFieldGet(this, _MLElement_localName, "f");
966
+ return this.#localName;
906
967
  }
907
968
  if (this.ownerMLDocument.tagNameCaseSensitive) {
908
- return __classPrivateFieldGet(this, _MLElement_localName, "f");
969
+ return this.#localName;
909
970
  }
910
- return __classPrivateFieldGet(this, _MLElement_localName, "f").toLowerCase();
971
+ return this.#localName.toLowerCase();
911
972
  }
912
973
  /**
913
974
  * The element immediately following the specified one in its parent's children list.
@@ -2331,7 +2392,7 @@ export class MLElement extends MLParentNode {
2331
2392
  * @param name - The new node name to set
2332
2393
  */
2333
2394
  fixNodeName(name) {
2334
- __classPrivateFieldSet(this, _MLElement_fixedNodeName, name, "f");
2395
+ this.#fixedNodeName = name;
2335
2396
  }
2336
2397
  /**
2337
2398
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
@@ -2346,15 +2407,34 @@ export class MLElement extends MLParentNode {
2346
2407
  throw new UnexpectedCallError('Not supported "focus" method');
2347
2408
  }
2348
2409
  /**
2349
- * Computes the accessible name of this element according to the
2350
- * Accessible Name and Description Computation algorithm.
2410
+ * Returns the accessible name of this element, with per-element memoization.
2411
+ *
2412
+ * On the first call for a given ARIA version the full AccName Computation
2413
+ * algorithm runs (tree walk, `aria-labelledby` resolution, `<label>` lookup,
2414
+ * etc.) and the result is stored in {@link #accessibleNameCache}.
2415
+ * Subsequent calls for the same version return the cached value in O(1).
2416
+ *
2417
+ * **All callers that need the accessible name of an MLElement should use
2418
+ * this method** rather than importing `getAccname()` directly, so that
2419
+ * every consumer benefits from the shared cache. This includes the
2420
+ * `:aria(has name)` selector in `@markuplint/selector`, which uses
2421
+ * duck-typing to detect and call this method.
2422
+ *
2423
+ * Added as part of the fix for {@link https://github.com/markuplint/markuplint/issues/2179 | #2179}
2424
+ * to eliminate redundant AccName computation across rules.
2351
2425
  *
2352
2426
  * @implements `@markuplint/ml-core` API: `MLElement`
2353
2427
  * @param version - The ARIA specification version to use for computation
2354
- * @returns The computed accessible name string
2428
+ * @returns The computed accessible name string (may be empty)
2355
2429
  */
2356
2430
  getAccessibleName(version) {
2357
- return getAccname(this, version);
2431
+ const cached = this.#accessibleNameCache.get(version);
2432
+ if (cached != null) {
2433
+ return cached;
2434
+ }
2435
+ const name = getAccname(this, version);
2436
+ this.#accessibleNameCache.set(version, name);
2437
+ return name;
2358
2438
  }
2359
2439
  /**
2360
2440
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
@@ -2423,7 +2503,7 @@ export class MLElement extends MLParentNode {
2423
2503
  * @returns The attribute value, or null if the attribute is not found
2424
2504
  */
2425
2505
  getAttributePretended(attrName) {
2426
- for (const attr of __classPrivateFieldGet(this, _MLElement_attributes, "f")) {
2506
+ for (const attr of this.#attributes) {
2427
2507
  if (attr.name.toLowerCase() === attrName.toLowerCase()) {
2428
2508
  return attr.value;
2429
2509
  }
@@ -2456,7 +2536,7 @@ export class MLElement extends MLParentNode {
2456
2536
  * @returns A frozen array of all attribute tokens
2457
2537
  */
2458
2538
  getAttributeTokens() {
2459
- return Object.freeze(this.pretenderContext?.type === 'pretender' ? __classPrivateFieldGet(this.pretenderContext.as, _MLElement_attributes, "f") : __classPrivateFieldGet(this, _MLElement_attributes, "f"));
2539
+ return Object.freeze(this.pretenderContext?.type === 'pretender' ? this.pretenderContext.as.#attributes : this.#attributes);
2460
2540
  }
2461
2541
  /**
2462
2542
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
@@ -2476,8 +2556,8 @@ export class MLElement extends MLParentNode {
2476
2556
  * @returns An array of child elements and non-whitespace text nodes
2477
2557
  */
2478
2558
  getChildElementsAndTextNodeWithoutWhitespaces() {
2479
- if (__classPrivateFieldGet(this, _MLElement_getChildElementsAndTextNodeWithoutWhitespacesCache, "f")) {
2480
- return __classPrivateFieldGet(this, _MLElement_getChildElementsAndTextNodeWithoutWhitespacesCache, "f");
2559
+ if (this.#getChildElementsAndTextNodeWithoutWhitespacesCache) {
2560
+ return this.#getChildElementsAndTextNodeWithoutWhitespacesCache;
2481
2561
  }
2482
2562
  const filteredNodes = [];
2483
2563
  for (const node of this.childNodes) {
@@ -2494,7 +2574,7 @@ export class MLElement extends MLParentNode {
2494
2574
  filteredNodes.push(node);
2495
2575
  }
2496
2576
  }
2497
- __classPrivateFieldSet(this, _MLElement_getChildElementsAndTextNodeWithoutWhitespacesCache, filteredNodes, "f");
2577
+ this.#getChildElementsAndTextNodeWithoutWhitespacesCache = filteredNodes;
2498
2578
  return filteredNodes;
2499
2579
  }
2500
2580
  /**
@@ -2616,7 +2696,7 @@ export class MLElement extends MLParentNode {
2616
2696
  hasMutableChildren(attr = false) {
2617
2697
  for (const child of this.getPureChildNodes()) {
2618
2698
  if (child.is(child.MARKUPLINT_PREPROCESSOR_BLOCK)) {
2619
- if (child.conditionalType) {
2699
+ if (child.blockBehavior) {
2620
2700
  continue;
2621
2701
  }
2622
2702
  return true;
@@ -2787,7 +2867,7 @@ export class MLElement extends MLParentNode {
2787
2867
  return;
2788
2868
  }
2789
2869
  let nodeName;
2790
- let namespace = 'html';
2870
+ let namespace = 'http://www.w3.org/1999/xhtml';
2791
2871
  const attributes = [];
2792
2872
  let aria;
2793
2873
  if (typeof pretenderElement === 'string') {
@@ -2795,7 +2875,7 @@ export class MLElement extends MLParentNode {
2795
2875
  }
2796
2876
  else {
2797
2877
  nodeName = pretenderElement.element;
2798
- namespace = pretenderElement.namespace ?? namespace;
2878
+ namespace = pretenderElement.namespace === 'svg' ? 'http://www.w3.org/2000/svg' : namespace;
2799
2879
  if (pretenderElement.inheritAttrs) {
2800
2880
  attributes.push(...this._astToken.attributes);
2801
2881
  }
@@ -3077,8 +3157,8 @@ export class MLElement extends MLParentNode {
3077
3157
  * @returns The normalized HTML string of this element
3078
3158
  */
3079
3159
  toNormalizeString() {
3080
- if (__classPrivateFieldGet(this, _MLElement_normalizedString, "f")) {
3081
- return __classPrivateFieldGet(this, _MLElement_normalizedString, "f");
3160
+ if (this.#normalizedString) {
3161
+ return this.#normalizedString;
3082
3162
  }
3083
3163
  const children = this.getChildElementsAndTextNodeWithoutWhitespaces();
3084
3164
  const attrs = this.attributes.map(attr => attr.toNormalizeString());
@@ -3092,7 +3172,7 @@ export class MLElement extends MLParentNode {
3092
3172
  });
3093
3173
  const endTag = `</${this.nodeName}>`;
3094
3174
  const normalizedString = `${startTag}${childNodes.join('')}${endTag}`;
3095
- __classPrivateFieldSet(this, _MLElement_normalizedString, normalizedString, "f");
3175
+ this.#normalizedString = normalizedString;
3096
3176
  return normalizedString;
3097
3177
  }
3098
3178
  /**
@@ -3174,4 +3254,3 @@ export class MLElement extends MLParentNode {
3174
3254
  throw new UnexpectedCallError('Not supported "webkitMatchesSelector" method');
3175
3255
  }
3176
3256
  }
3177
- _MLElement_attributes = new WeakMap(), _MLElement_fixedNodeName = new WeakMap(), _MLElement_getChildElementsAndTextNodeWithoutWhitespacesCache = new WeakMap(), _MLElement_localName = new WeakMap(), _MLElement_normalizedAttrs = new WeakMap(), _MLElement_normalizedString = new WeakMap();
@@ -1,29 +1,21 @@
1
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
- };
6
- var _NodeStore_store;
7
1
  import { TargetParserError } from '@markuplint/parser-utils';
8
2
  import { log } from '../../debug.js';
9
3
  const nodeStoreLog = log.extend('node-store');
10
4
  const nodeStoreError = nodeStoreLog.extend('error');
11
5
  class NodeStore {
12
- constructor() {
13
- _NodeStore_store.set(this, new Map());
14
- }
6
+ #store = new Map();
15
7
  getNode(astNode) {
16
8
  // console.log(`Get: ${astNode.uuid} -> ${astNode.raw.trim()}(${astNode.type})`);
17
- const node = __classPrivateFieldGet(this, _NodeStore_store, "f").get(astNode.uuid);
9
+ const node = this.#store.get(astNode.uuid);
18
10
  if (!node) {
19
11
  nodeStoreError('Ref ID: %s (%s: "%s")', astNode.uuid, astNode.nodeName, astNode.raw);
20
- nodeStoreError('Map: %O', [...__classPrivateFieldGet(this, _NodeStore_store, "f").entries()].map(([id, node]) => ({
12
+ nodeStoreError('Map: %O', [...this.#store.entries()].map(([id, node]) => ({
21
13
  id,
22
14
  name: node.nodeName,
23
15
  })));
24
16
  throw new TargetParserError('Broke mapping nodes.', {
25
- line: astNode.startLine,
26
- col: astNode.startCol,
17
+ line: astNode.line,
18
+ col: astNode.col,
27
19
  raw: astNode.raw,
28
20
  nodeName: astNode.nodeName,
29
21
  });
@@ -41,10 +33,9 @@ class NodeStore {
41
33
  nodeStoreError('Invalid node: %O', node);
42
34
  }
43
35
  nodeStoreLog('Mapped: %s (%s: "%s")', astNode.uuid, astNode.nodeName, astNode.raw.replaceAll('\n', '⏎').replaceAll('\t', '→'));
44
- __classPrivateFieldGet(this, _NodeStore_store, "f").set(astNode.uuid, node);
36
+ this.#store.set(astNode.uuid, node);
45
37
  }
46
38
  }
47
- _NodeStore_store = new WeakMap();
48
39
  /**
49
40
  * `NodeStore` Singleton
50
41
  */
@@ -136,6 +136,8 @@ export declare abstract class MLNode<T extends RuleConfigValue, O extends PlainD
136
136
  get baseURI(): string;
137
137
  /**
138
138
  * The list of child nodes that contains `Element`, `Text`, and `Comment`.
139
+ * Fragment nodes and preprocessor blocks with `each` or `end` block behavior
140
+ * are transparent — their child nodes are flattened into this list.
139
141
  *
140
142
  * @readonly
141
143
  * @implements DOM API: `Node`
@@ -376,7 +378,7 @@ export declare abstract class MLNode<T extends RuleConfigValue, O extends PlainD
376
378
  /**
377
379
  * Returns an array of NodeLists representing the conditional child nodes of the current node.
378
380
  * Conditional child nodes are nodes that are nested within
379
- * **preprocessor blocks** such as `if`, `each`, or `switch`.
381
+ * **preprocessor blocks** such as `if` or `switch`.
380
382
  * Each NodeList represents a branch of conditional child nodes.
381
383
  *
382
384
  * Note: NodeList doesn't include whitespace nodes.