@markuplint/ml-core 4.13.2 → 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 (92) hide show
  1. package/ARCHITECTURE.ja.md +524 -0
  2. package/ARCHITECTURE.md +524 -0
  3. package/CHANGELOG.md +52 -2
  4. package/README.md +5 -0
  5. package/SKILL.md +61 -0
  6. package/docs/linting-pipeline.ja.md +307 -0
  7. package/docs/linting-pipeline.md +307 -0
  8. package/docs/maintenance.ja.md +210 -0
  9. package/docs/maintenance.md +210 -0
  10. package/docs/ml-dom/attr.ja.md +103 -0
  11. package/docs/ml-dom/attr.md +103 -0
  12. package/docs/ml-dom/block.ja.md +272 -0
  13. package/docs/ml-dom/block.md +272 -0
  14. package/docs/ml-dom/document.ja.md +141 -0
  15. package/docs/ml-dom/document.md +141 -0
  16. package/docs/ml-dom/element.ja.md +176 -0
  17. package/docs/ml-dom/element.md +176 -0
  18. package/docs/ml-dom/helpers.ja.md +203 -0
  19. package/docs/ml-dom/helpers.md +203 -0
  20. package/docs/ml-dom/node.ja.md +199 -0
  21. package/docs/ml-dom/node.md +199 -0
  22. package/docs/ml-dom/others.ja.md +120 -0
  23. package/docs/ml-dom/others.md +120 -0
  24. package/docs/ml-dom/overview.ja.md +102 -0
  25. package/docs/ml-dom/overview.md +102 -0
  26. package/docs/ml-dom/pretender.ja.md +269 -0
  27. package/docs/ml-dom/pretender.md +269 -0
  28. package/docs/ml-dom/rule-mapping.ja.md +371 -0
  29. package/docs/ml-dom/rule-mapping.md +371 -0
  30. package/docs/ml-dom.ja.md +18 -0
  31. package/docs/ml-dom.md +18 -0
  32. package/docs/rule-system.ja.md +287 -0
  33. package/docs/rule-system.md +287 -0
  34. package/lib/convert-ruleset.d.ts +7 -0
  35. package/lib/convert-ruleset.js +7 -0
  36. package/lib/debug.d.ts +4 -0
  37. package/lib/debug.js +4 -0
  38. package/lib/index.d.ts +4 -3
  39. package/lib/index.js +1 -1
  40. package/lib/ml-core.d.ts +37 -1
  41. package/lib/ml-core.js +171 -82
  42. package/lib/ml-dom/helper/accname.d.ts +8 -0
  43. package/lib/ml-dom/helper/accname.js +71 -55
  44. package/lib/ml-dom/helper/create-node.js +1 -0
  45. package/lib/ml-dom/helper/get-indent.d.ts +4 -1
  46. package/lib/ml-dom/helper/get-indent.js +21 -30
  47. package/lib/ml-dom/node/attr.d.ts +65 -4
  48. package/lib/ml-dom/node/attr.js +151 -53
  49. package/lib/ml-dom/node/block.d.ts +23 -2
  50. package/lib/ml-dom/node/block.js +24 -1
  51. package/lib/ml-dom/node/child-node.d.ts +9 -0
  52. package/lib/ml-dom/node/child-node.js +9 -0
  53. package/lib/ml-dom/node/comment.d.ts +7 -0
  54. package/lib/ml-dom/node/comment.js +7 -0
  55. package/lib/ml-dom/node/document-fragment.d.ts +8 -0
  56. package/lib/ml-dom/node/document-fragment.js +8 -0
  57. package/lib/ml-dom/node/document-type.d.ts +22 -0
  58. package/lib/ml-dom/node/document-type.js +25 -0
  59. package/lib/ml-dom/node/document.d.ts +88 -7
  60. package/lib/ml-dom/node/document.js +128 -32
  61. package/lib/ml-dom/node/dom-token-list.js +17 -30
  62. package/lib/ml-dom/node/element-close-tag.js +1 -0
  63. package/lib/ml-dom/node/element.d.ts +151 -5
  64. package/lib/ml-dom/node/element.js +242 -50
  65. package/lib/ml-dom/node/node-store.js +6 -15
  66. package/lib/ml-dom/node/node.d.ts +19 -1
  67. package/lib/ml-dom/node/node.js +175 -166
  68. package/lib/ml-dom/node/parent-node.js +14 -30
  69. package/lib/ml-dom/node/rule-mapper.js +7 -20
  70. package/lib/ml-dom/node/text.d.ts +19 -0
  71. package/lib/ml-dom/node/text.js +21 -0
  72. package/lib/ml-dom/node/types.d.ts +68 -0
  73. package/lib/ml-dom/token/token.d.ts +42 -0
  74. package/lib/ml-dom/token/token.js +59 -39
  75. package/lib/ml-rule/create-rule.d.ts +17 -1
  76. package/lib/ml-rule/ml-rule-context.js +7 -11
  77. package/lib/ml-rule/ml-rule.d.ts +66 -1
  78. package/lib/ml-rule/ml-rule.js +95 -25
  79. package/lib/ml-rule/types.d.ts +41 -0
  80. package/lib/plugin/plugin.d.ts +8 -0
  81. package/lib/plugin/plugin.js +8 -0
  82. package/lib/plugin/types.d.ts +21 -0
  83. package/lib/ruleset/index.d.ts +10 -0
  84. package/lib/ruleset/index.js +13 -0
  85. package/lib/test/index.d.ts +42 -1
  86. package/lib/test/index.js +39 -2
  87. package/lib/types.d.ts +10 -1
  88. package/lib/violation-collector.d.ts +33 -0
  89. package/lib/violation-collector.js +48 -28
  90. package/lib/virtual-rule.d.ts +72 -0
  91. package/lib/virtual-rule.js +233 -0
  92. package/package.json +16 -13
@@ -1,19 +1,10 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- 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");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- 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");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _MLDOMIndentation_fixed, _MLDOMIndentation_node, _MLDOMIndentation_parent;
13
1
  /**
2
+ * Computes the indentation preceding the given node by analyzing
3
+ * the whitespace in adjacent text nodes.
14
4
  *
15
5
  * @deprecated
16
- * @param node
6
+ * @param node - The node whose indentation to determine
7
+ * @returns An indentation object describing the whitespace, or null if no indentation is found
17
8
  */
18
9
  export function getIndent(
19
10
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -59,52 +50,52 @@ node) {
59
50
  return null;
60
51
  }
61
52
  class MLDOMIndentation {
53
+ #fixed;
54
+ line;
55
+ #node;
56
+ #parent;
62
57
  constructor(
63
58
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
64
59
  originTextNode, raw, line,
65
60
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
66
61
  parentNode) {
67
- _MLDOMIndentation_fixed.set(this, void 0);
68
- _MLDOMIndentation_node.set(this, void 0);
69
- _MLDOMIndentation_parent.set(this, void 0);
70
62
  this.line = line;
71
- __classPrivateFieldSet(this, _MLDOMIndentation_node, originTextNode, "f");
72
- __classPrivateFieldSet(this, _MLDOMIndentation_parent, parentNode, "f");
73
- __classPrivateFieldSet(this, _MLDOMIndentation_fixed, raw, "f");
63
+ this.#node = originTextNode;
64
+ this.#parent = parentNode;
65
+ this.#fixed = raw;
74
66
  }
75
67
  get raw() {
76
- if (!__classPrivateFieldGet(this, _MLDOMIndentation_parent, "f").is(__classPrivateFieldGet(this, _MLDOMIndentation_parent, "f").TEXT_NODE) && this.line !== __classPrivateFieldGet(this, _MLDOMIndentation_node, "f").endLine) {
68
+ if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
77
69
  return '';
78
70
  }
79
- return __classPrivateFieldGet(this, _MLDOMIndentation_fixed, "f");
71
+ return this.#fixed;
80
72
  }
81
73
  get type() {
82
- if (!__classPrivateFieldGet(this, _MLDOMIndentation_parent, "f").is(__classPrivateFieldGet(this, _MLDOMIndentation_parent, "f").TEXT_NODE) && this.line !== __classPrivateFieldGet(this, _MLDOMIndentation_node, "f").endLine) {
74
+ if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
83
75
  return 'none';
84
76
  }
85
- const raw = __classPrivateFieldGet(this, _MLDOMIndentation_fixed, "f");
77
+ const raw = this.#fixed;
86
78
  return raw === '' ? 'none' : /^\t+$/.test(raw) ? 'tab' : /^[^\t]+$/.test(raw) ? 'space' : 'mixed';
87
79
  }
88
80
  get width() {
89
- if (!__classPrivateFieldGet(this, _MLDOMIndentation_parent, "f").is(__classPrivateFieldGet(this, _MLDOMIndentation_parent, "f").TEXT_NODE) && this.line !== __classPrivateFieldGet(this, _MLDOMIndentation_node, "f").endLine) {
81
+ if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
90
82
  return 0;
91
83
  }
92
- return __classPrivateFieldGet(this, _MLDOMIndentation_fixed, "f").length;
84
+ return this.#fixed.length;
93
85
  }
94
86
  fix(raw) {
95
- const current = __classPrivateFieldGet(this, _MLDOMIndentation_fixed, "f");
96
- __classPrivateFieldSet(this, _MLDOMIndentation_fixed, raw, "f");
97
- const node = __classPrivateFieldGet(this, _MLDOMIndentation_node, "f");
87
+ const current = this.#fixed;
88
+ this.#fixed = raw;
89
+ const node = this.#node;
98
90
  const line = node.startLine;
99
91
  const lines = node.raw.split(/\r?\n/);
100
92
  const index = this.line - line;
101
93
  if (lines[index] != null) {
102
- lines[index] = lines[index].replace(current, __classPrivateFieldGet(this, _MLDOMIndentation_fixed, "f"));
94
+ lines[index] = lines[index].replace(current, this.#fixed);
103
95
  }
104
96
  node.fix(lines.join('\n'));
105
97
  }
106
98
  }
107
- _MLDOMIndentation_fixed = new WeakMap(), _MLDOMIndentation_node = new WeakMap(), _MLDOMIndentation_parent = new WeakMap();
108
99
  function isFirstToken(
109
100
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
110
101
  node) {
@@ -5,24 +5,69 @@ import type { PlainData, RuleConfigValue } from '@markuplint/ml-config';
5
5
  import { MLToken } from '../token/token.js';
6
6
  import { MLDomTokenList } from './dom-token-list.js';
7
7
  import { MLNode } from './node.js';
8
+ /**
9
+ * Represents a DOM Attr (attribute) node wrapper in the markuplint DOM tree.
10
+ * Wraps an AST attribute token and provides access to the attribute's name, value,
11
+ * tokens (name, equal sign, quotes, value), and metadata such as whether
12
+ * the attribute is a directive or has a dynamic value.
13
+ *
14
+ * @template T - The rule configuration value type
15
+ * @template O - The rule options type
16
+ */
8
17
  export declare class MLAttr<T extends RuleConfigValue, O extends PlainData = undefined> extends MLNode<T, O, MLASTAttr> implements Attr {
9
18
  #private;
19
+ /**
20
+ * A candidate attribute name suggested by the parser, if available.
21
+ */
10
22
  readonly candidate?: string;
23
+ /**
24
+ * The end quote token of the attribute value, or null if the attribute has no value or quotes.
25
+ */
11
26
  readonly endQuote: MLToken | null;
27
+ /**
28
+ * The equal sign token between the attribute name and value, or null if absent.
29
+ */
12
30
  readonly equal: MLToken | null;
31
+ /**
32
+ * Whether this attribute is a directive (e.g., framework-specific attributes like `v-if` or `@click`).
33
+ */
13
34
  readonly isDirective?: true;
35
+ /**
36
+ * Whether this attribute can be duplicated on the same element.
37
+ */
14
38
  readonly isDuplicatable: boolean;
39
+ /**
40
+ * Whether this attribute has a dynamic value (e.g., a template expression rather than a static string).
41
+ */
15
42
  readonly isDynamicValue?: true;
43
+ /**
44
+ * The token representing the attribute name, or null for spread attributes.
45
+ */
16
46
  readonly nameNode: MLToken | null;
17
47
  /**
18
48
  * @implements DOM API: `Attr`
19
49
  * @see https://dom.spec.whatwg.org/#ref-for-dom-node-previoussibling%E2%91%A0
20
50
  */
21
51
  readonly ownerElement: MLElement<T, O>;
52
+ /**
53
+ * The whitespace token after the equal sign, or null if absent.
54
+ */
22
55
  readonly spacesAfterEqual: MLToken | null;
56
+ /**
57
+ * The whitespace token before the equal sign, or null if absent.
58
+ */
23
59
  readonly spacesBeforeEqual: MLToken | null;
60
+ /**
61
+ * The whitespace token before the attribute name, or null if absent.
62
+ */
24
63
  readonly spacesBeforeName: MLToken | null;
64
+ /**
65
+ * The start quote token of the attribute value, or null if the attribute has no value or quotes.
66
+ */
25
67
  readonly startQuote: MLToken | null;
68
+ /**
69
+ * The token representing the attribute value, or null if the attribute has no value.
70
+ */
26
71
  readonly valueNode: MLToken | null;
27
72
  /**
28
73
  * Returns the "string" if HTML syntax. Otherwise, returns a type in its syntax.
@@ -31,25 +76,30 @@ export declare class MLAttr<T extends RuleConfigValue, O extends PlainData = und
31
76
  * @implements `@markuplint/ml-core` API: `MLAttr`
32
77
  */
33
78
  readonly valueType: 'string' | 'number' | 'boolean' | 'code';
79
+ /**
80
+ * Creates a new MLAttr instance from an AST attribute token.
81
+ *
82
+ * @param astToken - The AST attribute token to wrap
83
+ * @param ownElement - The element that owns this attribute
84
+ */
34
85
  constructor(astToken: MLASTAttr, ownElement: MLElement<T, O>);
35
86
  /**
36
- * **IT THROWS AN ERROR WHEN CALLING THIS.**
87
+ * Returns the local name portion of the attribute (without namespace prefix).
37
88
  *
38
- * @unsupported
39
89
  * @implements DOM API: `Attr`
40
90
  * @see https://dom.spec.whatwg.org/#ref-for-dom-attr-localname
41
91
  */
42
92
  get localName(): string;
43
93
  /**
94
+ * Returns the qualified attribute name (the potential name resolved by the parser).
44
95
  *
45
96
  * @implements DOM API: `Attr`
46
97
  * @see https://dom.spec.whatwg.org/#dom-attr-name
47
98
  */
48
99
  get name(): string;
49
100
  /**
50
- * **IT THROWS AN ERROR WHEN CALLING THIS.**
101
+ * Returns the namespace URI of this attribute, resolved from the attribute name.
51
102
  *
52
- * @unsupported
53
103
  * @implements DOM API: `Attr`
54
104
  * @see https://dom.spec.whatwg.org/#ref-for-dom-attr-namespaceuri
55
105
  */
@@ -64,6 +114,12 @@ export declare class MLAttr<T extends RuleConfigValue, O extends PlainData = und
64
114
  * Returns a number appropriate for the type of `Attr`
65
115
  */
66
116
  get nodeType(): AttributeNodeType;
117
+ /**
118
+ * Returns the attribute value, equivalent to the `value` property.
119
+ *
120
+ * @implements DOM API: `Attr`
121
+ * @see https://dom.spec.whatwg.org/#dom-node-nodevalue
122
+ */
67
123
  get nodeValue(): string;
68
124
  /**
69
125
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
@@ -106,7 +162,12 @@ export declare class MLAttr<T extends RuleConfigValue, O extends PlainData = und
106
162
  */
107
163
  fix(raw: string): void;
108
164
  /**
165
+ * Returns a normalized string representation of the attribute,
166
+ * stripping extraneous whitespace around the name, equal sign, and value tokens.
167
+ * Falls back to the raw string if any token is missing.
168
+ *
109
169
  * @implements `@markuplint/ml-core` API: `MLAttr`
170
+ * @returns The normalized attribute string
110
171
  */
111
172
  toNormalizeString(): string;
112
173
  /**
@@ -1,51 +1,100 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- 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");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- 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");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _MLAttr_localName, _MLAttr_namespaceURI, _MLAttr_potentialName, _MLAttr_potentialValue;
13
- import { resolveNamespace } from '@markuplint/ml-spec';
1
+ import { resolveNamespace, compileDirectivePatterns, resolveDirective } from '@markuplint/ml-spec';
2
+ import { searchIDLAttribute } from '@markuplint/parser-utils';
14
3
  import { MLToken } from '../token/token.js';
15
4
  import { MLDomTokenList } from './dom-token-list.js';
16
5
  import { MLNode } from './node.js';
17
6
  import { UnexpectedCallError } from './unexpected-call-error.js';
7
+ /**
8
+ * Represents a DOM Attr (attribute) node wrapper in the markuplint DOM tree.
9
+ * Wraps an AST attribute token and provides access to the attribute's name, value,
10
+ * tokens (name, equal sign, quotes, value), and metadata such as whether
11
+ * the attribute is a directive or has a dynamic value.
12
+ *
13
+ * @template T - The rule configuration value type
14
+ * @template O - The rule options type
15
+ */
18
16
  export class MLAttr extends MLNode {
17
+ /**
18
+ * A candidate attribute name suggested by the parser, if available.
19
+ */
20
+ candidate;
21
+ /**
22
+ * The end quote token of the attribute value, or null if the attribute has no value or quotes.
23
+ */
24
+ endQuote = null;
25
+ /**
26
+ * The equal sign token between the attribute name and value, or null if absent.
27
+ */
28
+ equal = null;
29
+ /**
30
+ * Whether this attribute is a directive (e.g., framework-specific attributes like `v-if` or `@click`).
31
+ */
32
+ isDirective;
33
+ /**
34
+ * Whether this attribute can be duplicated on the same element.
35
+ */
36
+ isDuplicatable;
37
+ /**
38
+ * Whether this attribute has a dynamic value (e.g., a template expression rather than a static string).
39
+ */
40
+ isDynamicValue;
41
+ #localName;
42
+ /**
43
+ * The token representing the attribute name, or null for spread attributes.
44
+ */
45
+ nameNode = null;
46
+ #namespaceURI;
47
+ /**
48
+ * @implements DOM API: `Attr`
49
+ * @see https://dom.spec.whatwg.org/#ref-for-dom-node-previoussibling%E2%91%A0
50
+ */
51
+ ownerElement;
52
+ #potentialName;
53
+ #potentialValue;
54
+ /**
55
+ * The whitespace token after the equal sign, or null if absent.
56
+ */
57
+ spacesAfterEqual = null;
58
+ /**
59
+ * The whitespace token before the equal sign, or null if absent.
60
+ */
61
+ spacesBeforeEqual = null;
62
+ /**
63
+ * The whitespace token before the attribute name, or null if absent.
64
+ */
65
+ spacesBeforeName = null;
66
+ /**
67
+ * The start quote token of the attribute value, or null if the attribute has no value or quotes.
68
+ */
69
+ startQuote = null;
70
+ /**
71
+ * The token representing the attribute value, or null if the attribute has no value.
72
+ */
73
+ valueNode = null;
74
+ /**
75
+ * Returns the "string" if HTML syntax. Otherwise, returns a type in its syntax.
76
+ *
77
+ * @default "string"
78
+ * @implements `@markuplint/ml-core` API: `MLAttr`
79
+ */
80
+ valueType = 'string';
81
+ /**
82
+ * Creates a new MLAttr instance from an AST attribute token.
83
+ *
84
+ * @param astToken - The AST attribute token to wrap
85
+ * @param ownElement - The element that owns this attribute
86
+ */
19
87
  constructor(astToken,
20
88
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
21
89
  ownElement) {
22
90
  super(astToken, ownElement.ownerMLDocument);
23
- this.endQuote = null;
24
- this.equal = null;
25
- _MLAttr_localName.set(this, void 0);
26
- this.nameNode = null;
27
- _MLAttr_namespaceURI.set(this, void 0);
28
- _MLAttr_potentialName.set(this, void 0);
29
- _MLAttr_potentialValue.set(this, void 0);
30
- this.spacesAfterEqual = null;
31
- this.spacesBeforeEqual = null;
32
- this.spacesBeforeName = null;
33
- this.startQuote = null;
34
- this.valueNode = null;
35
- /**
36
- * Returns the "string" if HTML syntax. Otherwise, returns a type in its syntax.
37
- *
38
- * @default "string"
39
- * @implements `@markuplint/ml-core` API: `MLAttr`
40
- */
41
- this.valueType = 'string';
42
91
  this.ownerElement = ownElement;
43
92
  if (this._astToken.type === 'spread') {
44
- __classPrivateFieldSet(this, _MLAttr_namespaceURI, ownElement.namespaceURI, "f");
93
+ this.#namespaceURI = ownElement.namespaceURI;
45
94
  this.valueType = 'code';
46
- __classPrivateFieldSet(this, _MLAttr_localName, '#spread', "f");
47
- __classPrivateFieldSet(this, _MLAttr_potentialName, '#spread', "f");
48
- __classPrivateFieldSet(this, _MLAttr_potentialValue, this._astToken.raw, "f");
95
+ this.#localName = '#spread';
96
+ this.#potentialName = '#spread';
97
+ this.#potentialValue = this._astToken.raw;
49
98
  this.isDirective = true;
50
99
  this.isDynamicValue = true;
51
100
  this.isDuplicatable = true;
@@ -59,43 +108,82 @@ export class MLAttr extends MLNode {
59
108
  this.startQuote = new MLToken(this._astToken.startQuote);
60
109
  this.valueNode = new MLToken(this._astToken.value);
61
110
  this.endQuote = new MLToken(this._astToken.endQuote);
62
- this.isDynamicValue = this._astToken.isDynamicValue;
63
- this.isDirective = this._astToken.isDirective;
64
111
  this.candidate = this._astToken.candidate;
65
- __classPrivateFieldSet(this, _MLAttr_potentialName, this._astToken.potentialName ?? this.nameNode?.raw ?? '', "f");
66
- __classPrivateFieldSet(this, _MLAttr_potentialValue, this._astToken.potentialValue ?? this.valueNode?.raw ?? '', "f");
67
- this.isDuplicatable = this._astToken.isDuplicatable;
68
- const ns = resolveNamespace(__classPrivateFieldGet(this, _MLAttr_potentialName, "f"), ownElement.namespaceURI);
69
- __classPrivateFieldSet(this, _MLAttr_localName, ns.localName, "f");
70
- __classPrivateFieldSet(this, _MLAttr_namespaceURI, ns.namespaceURI, "f");
112
+ this.#potentialValue = this._astToken.potentialValue ?? this.valueNode?.raw ?? '';
113
+ if (this._astToken.potentialName == null) {
114
+ // Try declarative directive pattern resolution from spec
115
+ const patterns = ownElement.ownerMLDocument.specs.directivePatterns ?? [];
116
+ const resolution = patterns.length > 0
117
+ ? resolveDirective(this.nameNode?.raw ?? '', compileDirectivePatterns(patterns))
118
+ : null;
119
+ if (resolution) {
120
+ this.#potentialName = resolution.potentialName ?? this.nameNode?.raw ?? '';
121
+ this.isDynamicValue = resolution.isDynamicValue;
122
+ this.isDirective = resolution.isDirective;
123
+ this.isDuplicatable = resolution.isDuplicatable ?? this._astToken.isDuplicatable;
124
+ if (resolution.valueType) {
125
+ this.valueType = resolution.valueType;
126
+ }
127
+ }
128
+ else {
129
+ this.#potentialName = this.nameNode?.raw ?? '';
130
+ this.isDynamicValue = this._astToken.isDynamicValue;
131
+ this.isDirective = this._astToken.isDirective;
132
+ this.isDuplicatable = this._astToken.isDuplicatable;
133
+ }
134
+ // IDL attribute resolution (after directivePatterns)
135
+ if (ownElement.ownerMLDocument.specs.useIDLAttributeNames && !this.isDirective) {
136
+ const { contentAttrName, idlPropName } = searchIDLAttribute(this.#potentialName);
137
+ if (contentAttrName && contentAttrName !== this.#potentialName) {
138
+ this.#potentialName = contentAttrName;
139
+ }
140
+ // Set candidate for IDL naming suggestions (e.g., tabindex → tabIndex in JSX).
141
+ // Only when no directive pattern transformed the name.
142
+ if (!resolution && idlPropName) {
143
+ const rawName = this.nameNode?.raw ?? '';
144
+ if (rawName !== idlPropName) {
145
+ this.candidate = idlPropName;
146
+ }
147
+ }
148
+ }
149
+ }
150
+ else {
151
+ // Parser-set potentialName takes precedence
152
+ this.#potentialName = this._astToken.potentialName;
153
+ this.isDynamicValue = this._astToken.isDynamicValue;
154
+ this.isDirective = this._astToken.isDirective;
155
+ this.isDuplicatable = this._astToken.isDuplicatable;
156
+ }
157
+ const ns = resolveNamespace(this.#potentialName, ownElement.namespaceURI);
158
+ this.#localName = ns.localName;
159
+ this.#namespaceURI = ns.namespaceURI;
71
160
  }
72
161
  /**
73
- * **IT THROWS AN ERROR WHEN CALLING THIS.**
162
+ * Returns the local name portion of the attribute (without namespace prefix).
74
163
  *
75
- * @unsupported
76
164
  * @implements DOM API: `Attr`
77
165
  * @see https://dom.spec.whatwg.org/#ref-for-dom-attr-localname
78
166
  */
79
167
  get localName() {
80
- return __classPrivateFieldGet(this, _MLAttr_localName, "f");
168
+ return this.#localName;
81
169
  }
82
170
  /**
171
+ * Returns the qualified attribute name (the potential name resolved by the parser).
83
172
  *
84
173
  * @implements DOM API: `Attr`
85
174
  * @see https://dom.spec.whatwg.org/#dom-attr-name
86
175
  */
87
176
  get name() {
88
- return __classPrivateFieldGet(this, _MLAttr_potentialName, "f");
177
+ return this.#potentialName;
89
178
  }
90
179
  /**
91
- * **IT THROWS AN ERROR WHEN CALLING THIS.**
180
+ * Returns the namespace URI of this attribute, resolved from the attribute name.
92
181
  *
93
- * @unsupported
94
182
  * @implements DOM API: `Attr`
95
183
  * @see https://dom.spec.whatwg.org/#ref-for-dom-attr-namespaceuri
96
184
  */
97
185
  get namespaceURI() {
98
- return __classPrivateFieldGet(this, _MLAttr_namespaceURI, "f");
186
+ return this.#namespaceURI;
99
187
  }
100
188
  /**
101
189
  * Returns a string appropriate for the type of node as `Attr`
@@ -111,6 +199,12 @@ export class MLAttr extends MLNode {
111
199
  get nodeType() {
112
200
  return this.ATTRIBUTE_NODE;
113
201
  }
202
+ /**
203
+ * Returns the attribute value, equivalent to the `value` property.
204
+ *
205
+ * @implements DOM API: `Attr`
206
+ * @see https://dom.spec.whatwg.org/#dom-node-nodevalue
207
+ */
114
208
  get nodeValue() {
115
209
  return this.value;
116
210
  }
@@ -155,7 +249,7 @@ export class MLAttr extends MLNode {
155
249
  * @see https://dom.spec.whatwg.org/#dom-attr-value
156
250
  */
157
251
  get value() {
158
- return __classPrivateFieldGet(this, _MLAttr_potentialValue, "f");
252
+ return this.#potentialValue;
159
253
  }
160
254
  /**
161
255
  * Fixes the attribute value.
@@ -173,7 +267,12 @@ export class MLAttr extends MLNode {
173
267
  this.valueNode?.fix(raw);
174
268
  }
175
269
  /**
270
+ * Returns a normalized string representation of the attribute,
271
+ * stripping extraneous whitespace around the name, equal sign, and value tokens.
272
+ * Falls back to the raw string if any token is missing.
273
+ *
176
274
  * @implements `@markuplint/ml-core` API: `MLAttr`
275
+ * @returns The normalized attribute string
177
276
  */
178
277
  toNormalizeString() {
179
278
  if (this.nameNode && this.equal && this.startQuote && this.valueNode && this.endQuote) {
@@ -208,4 +307,3 @@ export class MLAttr extends MLNode {
208
307
  return tokens.join('');
209
308
  }
210
309
  }
211
- _MLAttr_localName = new WeakMap(), _MLAttr_namespaceURI = new WeakMap(), _MLAttr_potentialName = new WeakMap(), _MLAttr_potentialValue = new WeakMap();
@@ -1,12 +1,33 @@
1
1
  import type { MLDocument } from './document.js';
2
2
  import type { MLElement } from './element.js';
3
3
  import type { MarkuplintPreprocessorBlockType } from './types.js';
4
- import type { MLASTPreprocessorSpecificBlock, MLASTPreprocessorSpecificBlockConditionalType } from '@markuplint/ml-ast';
4
+ import type { MLASTPreprocessorSpecificBlock, MLASTBlockBehavior } from '@markuplint/ml-ast';
5
5
  import type { PlainData, RuleConfigValue } from '@markuplint/ml-config';
6
6
  import { MLNode } from './node.js';
7
+ /**
8
+ * Represents a preprocessor-specific block node in the markuplint DOM tree.
9
+ * These nodes correspond to template engine constructs such as conditionals (`if`/`else`),
10
+ * loops (`each`), and other preprocessor directives that are not part of standard HTML.
11
+ *
12
+ * @template T - The rule configuration value type
13
+ * @template O - The rule options type
14
+ */
7
15
  export declare class MLBlock<T extends RuleConfigValue, O extends PlainData = undefined> extends MLNode<T, O, MLASTPreprocessorSpecificBlock> {
8
- readonly conditionalType: MLASTPreprocessorSpecificBlockConditionalType;
16
+ /**
17
+ * Block behavior associated with this block, if any.
18
+ */
19
+ readonly blockBehavior: MLASTBlockBehavior | null;
20
+ /**
21
+ * Whether this block is transparent, meaning its children are treated
22
+ * as belonging to the parent node for tree traversal purposes.
23
+ */
9
24
  readonly isTransparent: boolean;
25
+ /**
26
+ * Creates a new MLBlock instance.
27
+ *
28
+ * @param astNode - The AST preprocessor block node to wrap
29
+ * @param document - The owning document
30
+ */
10
31
  constructor(astNode: MLASTPreprocessorSpecificBlock, document: MLDocument<T, O>);
11
32
  /**
12
33
  * Returns a string appropriate for the type of node as `MLBlock`
@@ -1,13 +1,36 @@
1
1
  import { after, before, remove, replaceWith } from '../manipulations/child-node-methods.js';
2
2
  import { MLNode } from './node.js';
3
+ /**
4
+ * Represents a preprocessor-specific block node in the markuplint DOM tree.
5
+ * These nodes correspond to template engine constructs such as conditionals (`if`/`else`),
6
+ * loops (`each`), and other preprocessor directives that are not part of standard HTML.
7
+ *
8
+ * @template T - The rule configuration value type
9
+ * @template O - The rule options type
10
+ */
3
11
  export class MLBlock extends MLNode {
12
+ /**
13
+ * Block behavior associated with this block, if any.
14
+ */
15
+ blockBehavior;
16
+ /**
17
+ * Whether this block is transparent, meaning its children are treated
18
+ * as belonging to the parent node for tree traversal purposes.
19
+ */
20
+ isTransparent;
21
+ /**
22
+ * Creates a new MLBlock instance.
23
+ *
24
+ * @param astNode - The AST preprocessor block node to wrap
25
+ * @param document - The owning document
26
+ */
4
27
  constructor(astNode,
5
28
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
6
29
  document) {
7
30
  super(astNode, document, astNode.isFragment);
8
31
  // TODO:
9
32
  this.isTransparent = true;
10
- this.conditionalType = astNode.conditionalType;
33
+ this.blockBehavior = astNode.blockBehavior;
11
34
  }
12
35
  /**
13
36
  * Returns a string appropriate for the type of node as `MLBlock`
@@ -15,4 +15,13 @@ import type { PlainData, RuleConfigValue } from '@markuplint/ml-config';
15
15
  * @see https://dom.spec.whatwg.org/#idl-index
16
16
  */
17
17
  export type MLChildNode<T extends RuleConfigValue, O extends PlainData = undefined> = MLDocumentType<T, O> | MLCharacterData<T, O> | MLElement<T, O> | MLBlock<T, O>;
18
+ /**
19
+ * Determines whether the given node is a child node type
20
+ * (DocumentType, CDATA, Comment, Text, Element, or preprocessor block).
21
+ *
22
+ * @template T - The rule configuration value type
23
+ * @template O - The rule options type
24
+ * @param node - The node to check
25
+ * @returns True if the node is one of the child node types
26
+ */
18
27
  export declare function isChildNode<T extends RuleConfigValue, O extends PlainData = undefined>(node: MLNode<T, O>): node is MLChildNode<T, O>;
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Determines whether the given node is a child node type
3
+ * (DocumentType, CDATA, Comment, Text, Element, or preprocessor block).
4
+ *
5
+ * @template T - The rule configuration value type
6
+ * @template O - The rule options type
7
+ * @param node - The node to check
8
+ * @returns True if the node is one of the child node types
9
+ */
1
10
  export function isChildNode(
2
11
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
3
12
  node) {
@@ -2,6 +2,13 @@ import type { CommentNodeType } from './types.js';
2
2
  import type { MLASTComment } from '@markuplint/ml-ast';
3
3
  import type { PlainData, RuleConfigValue } from '@markuplint/ml-config';
4
4
  import { MLCharacterData } from './character-data.js';
5
+ /**
6
+ * Represents a DOM Comment node wrapper in the markuplint DOM tree.
7
+ * Wraps an AST comment token and implements the standard DOM `Comment` interface.
8
+ *
9
+ * @template T - The rule configuration value type
10
+ * @template O - The rule options type
11
+ */
5
12
  export declare class MLComment<T extends RuleConfigValue, O extends PlainData = undefined> extends MLCharacterData<T, O, MLASTComment> implements Comment {
6
13
  /**
7
14
  * Returns a string appropriate for the type of node as `Attr`
@@ -1,4 +1,11 @@
1
1
  import { MLCharacterData } from './character-data.js';
2
+ /**
3
+ * Represents a DOM Comment node wrapper in the markuplint DOM tree.
4
+ * Wraps an AST comment token and implements the standard DOM `Comment` interface.
5
+ *
6
+ * @template T - The rule configuration value type
7
+ * @template O - The rule options type
8
+ */
2
9
  export class MLComment extends MLCharacterData {
3
10
  /**
4
11
  * Returns a string appropriate for the type of node as `Attr`
@@ -2,6 +2,14 @@ import type { DocumentFragmentNodeType } from './types.js';
2
2
  import type { MLASTNode } from '@markuplint/ml-ast';
3
3
  import type { PlainData, RuleConfigValue } from '@markuplint/ml-config';
4
4
  import { MLParentNode } from './parent-node.js';
5
+ /**
6
+ * Represents a DOM DocumentFragment node wrapper in the markuplint DOM tree.
7
+ * Used for JSX fragments and similar constructs where a set of nodes
8
+ * is grouped without a wrapping element.
9
+ *
10
+ * @template T - The rule configuration value type
11
+ * @template O - The rule options type
12
+ */
5
13
  export declare class MLDocumentFragment<T extends RuleConfigValue, O extends PlainData = undefined> extends MLParentNode<T, O, MLASTNode> implements DocumentFragment {
6
14
  /**
7
15
  * Returns a string appropriate for the type of node as `DocumentFragment`
@@ -1,5 +1,13 @@
1
1
  import { MLParentNode } from './parent-node.js';
2
2
  import { UnexpectedCallError } from './unexpected-call-error.js';
3
+ /**
4
+ * Represents a DOM DocumentFragment node wrapper in the markuplint DOM tree.
5
+ * Used for JSX fragments and similar constructs where a set of nodes
6
+ * is grouped without a wrapping element.
7
+ *
8
+ * @template T - The rule configuration value type
9
+ * @template O - The rule options type
10
+ */
3
11
  export class MLDocumentFragment extends MLParentNode {
4
12
  /**
5
13
  * Returns a string appropriate for the type of node as `DocumentFragment`