@markuplint/rules 4.11.1 → 4.12.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 (231) hide show
  1. package/CHANGELOG.md +9 -3
  2. package/SKILL.md +76 -0
  3. package/lib/attr-check.d.ts +41 -5
  4. package/lib/attr-check.js +29 -5
  5. package/lib/attr-duplication/index.d.ts +7 -0
  6. package/lib/attr-duplication/index.js +7 -0
  7. package/lib/attr-duplication/meta.d.ts +1 -0
  8. package/lib/attr-duplication/meta.js +1 -0
  9. package/lib/attr-value-quotes/index.d.ts +10 -0
  10. package/lib/attr-value-quotes/index.js +10 -0
  11. package/lib/attr-value-quotes/meta.d.ts +1 -0
  12. package/lib/attr-value-quotes/meta.js +1 -0
  13. package/lib/case-sensitive-attr-name/index.d.ts +9 -0
  14. package/lib/case-sensitive-attr-name/index.js +8 -0
  15. package/lib/case-sensitive-attr-name/meta.d.ts +1 -0
  16. package/lib/case-sensitive-attr-name/meta.js +1 -0
  17. package/lib/case-sensitive-tag-name/index.d.ts +9 -0
  18. package/lib/case-sensitive-tag-name/index.js +8 -0
  19. package/lib/case-sensitive-tag-name/meta.d.ts +1 -0
  20. package/lib/case-sensitive-tag-name/meta.js +1 -0
  21. package/lib/character-reference/index.d.ts +8 -0
  22. package/lib/character-reference/index.js +16 -0
  23. package/lib/character-reference/meta.d.ts +1 -0
  24. package/lib/character-reference/meta.js +1 -0
  25. package/lib/class-naming/index.d.ts +9 -0
  26. package/lib/class-naming/index.js +8 -0
  27. package/lib/class-naming/meta.d.ts +1 -0
  28. package/lib/class-naming/meta.js +1 -0
  29. package/lib/create-message.d.ts +27 -0
  30. package/lib/create-message.js +56 -1
  31. package/lib/debug.d.ts +9 -0
  32. package/lib/debug.js +5 -0
  33. package/lib/deprecated-attr/index.d.ts +6 -0
  34. package/lib/deprecated-attr/index.js +6 -0
  35. package/lib/deprecated-attr/meta.d.ts +1 -0
  36. package/lib/deprecated-attr/meta.js +1 -0
  37. package/lib/deprecated-element/index.d.ts +8 -0
  38. package/lib/deprecated-element/index.js +8 -0
  39. package/lib/deprecated-element/meta.d.ts +1 -0
  40. package/lib/deprecated-element/meta.js +1 -0
  41. package/lib/disallowed-element/index.d.ts +7 -0
  42. package/lib/disallowed-element/index.js +7 -0
  43. package/lib/disallowed-element/meta.d.ts +1 -0
  44. package/lib/disallowed-element/meta.js +1 -0
  45. package/lib/doctype/index.d.ts +10 -0
  46. package/lib/doctype/index.js +8 -0
  47. package/lib/doctype/meta.d.ts +1 -0
  48. package/lib/doctype/meta.js +1 -0
  49. package/lib/end-tag/index.d.ts +7 -0
  50. package/lib/end-tag/index.js +7 -0
  51. package/lib/end-tag/meta.d.ts +1 -0
  52. package/lib/end-tag/meta.js +1 -0
  53. package/lib/heading-levels/index.d.ts +6 -0
  54. package/lib/heading-levels/index.js +6 -0
  55. package/lib/heading-levels/meta.d.ts +1 -0
  56. package/lib/heading-levels/meta.js +1 -0
  57. package/lib/helpers.d.ts +104 -0
  58. package/lib/helpers.js +105 -2
  59. package/lib/id-duplication/index.d.ts +7 -0
  60. package/lib/id-duplication/index.js +7 -0
  61. package/lib/id-duplication/meta.d.ts +1 -0
  62. package/lib/id-duplication/meta.js +1 -0
  63. package/lib/index.d.ts +14 -1
  64. package/lib/index.js +12 -0
  65. package/lib/ineffective-attr/index.d.ts +7 -0
  66. package/lib/ineffective-attr/index.js +7 -0
  67. package/lib/ineffective-attr/meta.d.ts +1 -0
  68. package/lib/ineffective-attr/meta.js +1 -0
  69. package/lib/invalid-attr/index.d.ts +24 -0
  70. package/lib/invalid-attr/index.js +17 -0
  71. package/lib/invalid-attr/meta.d.ts +1 -0
  72. package/lib/invalid-attr/meta.js +1 -0
  73. package/lib/label-has-control/index.d.ts +7 -0
  74. package/lib/label-has-control/index.js +11 -0
  75. package/lib/label-has-control/meta.d.ts +1 -0
  76. package/lib/label-has-control/meta.js +1 -0
  77. package/lib/landmark-roles/index.d.ts +14 -0
  78. package/lib/landmark-roles/index.js +21 -0
  79. package/lib/landmark-roles/meta.d.ts +1 -0
  80. package/lib/landmark-roles/meta.js +1 -0
  81. package/lib/neighbor-popovers/index.d.ts +8 -0
  82. package/lib/neighbor-popovers/index.js +26 -2
  83. package/lib/neighbor-popovers/meta.d.ts +1 -0
  84. package/lib/neighbor-popovers/meta.js +1 -0
  85. package/lib/no-ambiguous-navigable-target-names/index.d.ts +8 -0
  86. package/lib/no-ambiguous-navigable-target-names/index.js +8 -0
  87. package/lib/no-ambiguous-navigable-target-names/meta.d.ts +1 -0
  88. package/lib/no-ambiguous-navigable-target-names/meta.js +1 -0
  89. package/lib/no-boolean-attr-value/index.d.ts +7 -0
  90. package/lib/no-boolean-attr-value/index.js +7 -0
  91. package/lib/no-boolean-attr-value/meta.d.ts +1 -0
  92. package/lib/no-boolean-attr-value/meta.js +1 -0
  93. package/lib/no-consecutive-br/index.d.ts +8 -0
  94. package/lib/no-consecutive-br/index.js +8 -0
  95. package/lib/no-consecutive-br/meta.d.ts +1 -0
  96. package/lib/no-consecutive-br/meta.js +1 -0
  97. package/lib/no-default-value/index.d.ts +7 -0
  98. package/lib/no-default-value/index.js +7 -0
  99. package/lib/no-default-value/meta.d.ts +1 -0
  100. package/lib/no-default-value/meta.js +1 -0
  101. package/lib/no-duplicate-dt/index.d.ts +6 -0
  102. package/lib/no-duplicate-dt/index.js +6 -0
  103. package/lib/no-duplicate-dt/meta.d.ts +1 -0
  104. package/lib/no-duplicate-dt/meta.js +1 -0
  105. package/lib/no-empty-palpable-content/index.d.ts +13 -0
  106. package/lib/no-empty-palpable-content/index.js +12 -0
  107. package/lib/no-empty-palpable-content/meta.d.ts +1 -0
  108. package/lib/no-empty-palpable-content/meta.js +1 -0
  109. package/lib/no-hard-code-id/index.d.ts +8 -0
  110. package/lib/no-hard-code-id/index.js +8 -0
  111. package/lib/no-hard-code-id/meta.d.ts +1 -0
  112. package/lib/no-hard-code-id/meta.js +1 -0
  113. package/lib/no-orphaned-end-tag/index.d.ts +7 -0
  114. package/lib/no-orphaned-end-tag/index.js +7 -0
  115. package/lib/no-orphaned-end-tag/meta.d.ts +1 -0
  116. package/lib/no-orphaned-end-tag/meta.js +1 -0
  117. package/lib/no-refer-to-non-existent-id/index.d.ts +8 -0
  118. package/lib/no-refer-to-non-existent-id/index.js +9 -0
  119. package/lib/no-refer-to-non-existent-id/meta.d.ts +1 -0
  120. package/lib/no-refer-to-non-existent-id/meta.js +1 -0
  121. package/lib/no-use-event-handler-attr/index.d.ts +10 -0
  122. package/lib/no-use-event-handler-attr/index.js +8 -0
  123. package/lib/no-use-event-handler-attr/meta.d.ts +1 -0
  124. package/lib/no-use-event-handler-attr/meta.js +1 -0
  125. package/lib/permitted-contents/choice.d.ts +17 -0
  126. package/lib/permitted-contents/choice.js +30 -0
  127. package/lib/permitted-contents/complex-branch.d.ts +11 -7
  128. package/lib/permitted-contents/complex-branch.js +11 -7
  129. package/lib/permitted-contents/content-model.d.ts +11 -0
  130. package/lib/permitted-contents/content-model.js +32 -0
  131. package/lib/permitted-contents/count-pattern.d.ts +13 -7
  132. package/lib/permitted-contents/count-pattern.js +23 -7
  133. package/lib/permitted-contents/debug.browser.d.ts +12 -0
  134. package/lib/permitted-contents/debug.browser.js +12 -0
  135. package/lib/permitted-contents/debug.d.ts +12 -0
  136. package/lib/permitted-contents/debug.js +12 -0
  137. package/lib/permitted-contents/index.d.ts +12 -0
  138. package/lib/permitted-contents/index.js +21 -0
  139. package/lib/permitted-contents/matches-selector.d.ts +19 -0
  140. package/lib/permitted-contents/matches-selector.js +33 -0
  141. package/lib/permitted-contents/meta.d.ts +1 -0
  142. package/lib/permitted-contents/meta.js +1 -0
  143. package/lib/permitted-contents/order.d.ts +14 -7
  144. package/lib/permitted-contents/order.js +14 -7
  145. package/lib/permitted-contents/recursive-branch.d.ts +17 -0
  146. package/lib/permitted-contents/recursive-branch.js +17 -0
  147. package/lib/permitted-contents/represent-transparent-nodes.d.ts +29 -0
  148. package/lib/permitted-contents/represent-transparent-nodes.js +24 -0
  149. package/lib/permitted-contents/start.d.ts +12 -6
  150. package/lib/permitted-contents/start.js +12 -6
  151. package/lib/permitted-contents/transparent.d.ts +12 -0
  152. package/lib/permitted-contents/transparent.js +12 -0
  153. package/lib/permitted-contents/types.d.ts +67 -0
  154. package/lib/permitted-contents/utils.d.ts +161 -1
  155. package/lib/permitted-contents/utils.js +194 -0
  156. package/lib/placeholder-label-option/index.d.ts +7 -0
  157. package/lib/placeholder-label-option/index.js +19 -15
  158. package/lib/placeholder-label-option/meta.d.ts +1 -0
  159. package/lib/placeholder-label-option/meta.js +1 -0
  160. package/lib/require-accessible-name/index.d.ts +11 -0
  161. package/lib/require-accessible-name/index.js +7 -0
  162. package/lib/require-accessible-name/meta.d.ts +1 -0
  163. package/lib/require-accessible-name/meta.js +1 -0
  164. package/lib/require-datetime/index.d.ts +12 -0
  165. package/lib/require-datetime/index.js +8 -0
  166. package/lib/require-datetime/meta.d.ts +1 -0
  167. package/lib/require-datetime/meta.js +1 -0
  168. package/lib/require-datetime/types.d.ts +7 -0
  169. package/lib/require-datetime/utils.d.ts +18 -5
  170. package/lib/require-datetime/utils.js +53 -9
  171. package/lib/required-attr/index.d.ts +13 -0
  172. package/lib/required-attr/index.js +7 -0
  173. package/lib/required-attr/meta.d.ts +1 -0
  174. package/lib/required-attr/meta.js +1 -0
  175. package/lib/required-element/index.d.ts +14 -0
  176. package/lib/required-element/index.js +14 -2
  177. package/lib/required-element/meta.d.ts +1 -0
  178. package/lib/required-element/meta.js +1 -0
  179. package/lib/required-h1/index.d.ts +12 -0
  180. package/lib/required-h1/index.js +7 -0
  181. package/lib/required-h1/meta.d.ts +1 -0
  182. package/lib/required-h1/meta.js +1 -0
  183. package/lib/table-row-column-alignment/find-children.d.ts +10 -0
  184. package/lib/table-row-column-alignment/find-children.js +11 -0
  185. package/lib/table-row-column-alignment/grid.d.ts +60 -0
  186. package/lib/table-row-column-alignment/grid.js +85 -0
  187. package/lib/table-row-column-alignment/index.d.ts +8 -0
  188. package/lib/table-row-column-alignment/index.js +8 -0
  189. package/lib/table-row-column-alignment/meta.d.ts +1 -0
  190. package/lib/table-row-column-alignment/meta.js +1 -0
  191. package/lib/table-row-column-alignment/types.d.ts +10 -0
  192. package/lib/use-list/index.d.ts +16 -0
  193. package/lib/use-list/index.js +20 -0
  194. package/lib/use-list/meta.d.ts +1 -0
  195. package/lib/use-list/meta.js +1 -0
  196. package/lib/wai-aria/checkings/abstract-role.d.ts +9 -0
  197. package/lib/wai-aria/checkings/abstract-role.js +9 -0
  198. package/lib/wai-aria/checkings/default-value.d.ts +11 -0
  199. package/lib/wai-aria/checkings/default-value.js +11 -0
  200. package/lib/wai-aria/checkings/deprecated-props.d.ts +11 -0
  201. package/lib/wai-aria/checkings/deprecated-props.js +11 -0
  202. package/lib/wai-aria/checkings/deprecated-role.d.ts +10 -0
  203. package/lib/wai-aria/checkings/deprecated-role.js +10 -0
  204. package/lib/wai-aria/checkings/disallowed-prop.d.ts +14 -0
  205. package/lib/wai-aria/checkings/disallowed-prop.js +14 -0
  206. package/lib/wai-aria/checkings/implicit-props.d.ts +13 -0
  207. package/lib/wai-aria/checkings/implicit-props.js +13 -0
  208. package/lib/wai-aria/checkings/implicit-role.d.ts +9 -0
  209. package/lib/wai-aria/checkings/implicit-role.js +9 -0
  210. package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +9 -0
  211. package/lib/wai-aria/checkings/interaction-in-hidden.js +15 -4
  212. package/lib/wai-aria/checkings/no-global-prop.d.ts +10 -0
  213. package/lib/wai-aria/checkings/no-global-prop.js +10 -0
  214. package/lib/wai-aria/checkings/non-existent-role.d.ts +10 -0
  215. package/lib/wai-aria/checkings/non-existent-role.js +10 -0
  216. package/lib/wai-aria/checkings/permitted-roles.d.ts +10 -0
  217. package/lib/wai-aria/checkings/permitted-roles.js +10 -0
  218. package/lib/wai-aria/checkings/presentational-children.d.ts +7 -1
  219. package/lib/wai-aria/checkings/presentational-children.js +14 -1
  220. package/lib/wai-aria/checkings/required-owned-elements.d.ts +9 -1
  221. package/lib/wai-aria/checkings/required-owned-elements.js +16 -1
  222. package/lib/wai-aria/checkings/required-prop.d.ts +13 -0
  223. package/lib/wai-aria/checkings/required-prop.js +13 -0
  224. package/lib/wai-aria/checkings/value.d.ts +23 -0
  225. package/lib/wai-aria/checkings/value.js +32 -0
  226. package/lib/wai-aria/index.d.ts +10 -0
  227. package/lib/wai-aria/index.js +10 -0
  228. package/lib/wai-aria/meta.d.ts +1 -0
  229. package/lib/wai-aria/meta.js +1 -0
  230. package/lib/wai-aria/types.d.ts +17 -0
  231. package/package.json +10 -10
@@ -13,6 +13,15 @@ var _Collection_locked, _Collection_matched, _Collection_nodes, _Collection_orig
13
13
  import { createSelector } from '@markuplint/selector';
14
14
  import { bgGreen, green, bgRed, bgBlue, blue, bgMagenta, cyan } from './debug.js';
15
15
  import { transparentMode } from './represent-transparent-nodes.js';
16
+ /**
17
+ * Determines whether a given value is a terminal model (a selector string or an array
18
+ * of selector strings) rather than a nested array of content model patterns.
19
+ * Distinguishes between `Model` (leaf-level selectors) and `PermittedContentPattern[]`
20
+ * (structural pattern arrays that require further recursive evaluation).
21
+ *
22
+ * @param model - The value to check, either a terminal model or a nested pattern array.
23
+ * @returns True if the value is a terminal model (string or string array), false if it is a pattern array.
24
+ */
16
25
  export function isModel(model) {
17
26
  if (typeof model === 'string') {
18
27
  return true;
@@ -29,6 +38,16 @@ export function isModel(model) {
29
38
  }
30
39
  return modelMode;
31
40
  }
41
+ /**
42
+ * Tests whether a child node matches a CSS selector string using the markuplint
43
+ * selector engine. Returns whether the node matched and, if not, the deepest
44
+ * unmatched descendant node for diagnostic purposes.
45
+ *
46
+ * @param selector - The CSS selector string to test against.
47
+ * @param node - The child node to test.
48
+ * @param specs - The spec data passed to the selector engine for attribute resolution.
49
+ * @returns An object with `matched: true` if the node matches, or `matched: false` with an optional `not` node.
50
+ */
32
51
  export function matches(selector,
33
52
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
34
53
  node, specs) {
@@ -48,6 +67,14 @@ node, specs) {
48
67
  not,
49
68
  };
50
69
  }
70
+ /**
71
+ * Traverses a chain of nested `:has()` selector results to find the deepest
72
+ * descendant nodes that caused a selector mismatch. Used to provide precise
73
+ * error reporting by identifying the actual offending node in nested selectors.
74
+ *
75
+ * @param selectorResult - A matched selector result that may contain nested `:has()` results.
76
+ * @returns The deepest descendant child nodes from the nested selector chain.
77
+ */
51
78
  function descendants(
52
79
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
53
80
  selectorResult) {
@@ -58,6 +85,7 @@ selectorResult) {
58
85
  nodes = dep.nodes;
59
86
  continue;
60
87
  }
88
+ // eslint-disable-next-line no-useless-assignment
61
89
  selectorResult = dep;
62
90
  continue;
63
91
  }
@@ -65,24 +93,74 @@ selectorResult) {
65
93
  }
66
94
  return nodes;
67
95
  }
96
+ /**
97
+ * Type guard that checks whether a content model pattern is a "require" pattern,
98
+ * indicating one or more required occurrences of a specific element or model.
99
+ *
100
+ * @param content - The content model pattern to check.
101
+ * @returns True if the pattern has a `require` property.
102
+ */
68
103
  export function isRequire(content) {
69
104
  return 'require' in content;
70
105
  }
106
+ /**
107
+ * Type guard that checks whether a content model pattern is an "optional" pattern,
108
+ * indicating zero or one occurrences of a specific element or model.
109
+ *
110
+ * @param content - The content model pattern to check.
111
+ * @returns True if the pattern has an `optional` property.
112
+ */
71
113
  export function isOptional(content) {
72
114
  return 'optional' in content;
73
115
  }
116
+ /**
117
+ * Type guard that checks whether a content model pattern is a "oneOrMore" pattern,
118
+ * indicating one or more occurrences of a specific element or model.
119
+ *
120
+ * @param content - The content model pattern to check.
121
+ * @returns True if the pattern has a `oneOrMore` property.
122
+ */
74
123
  export function isOneOrMore(content) {
75
124
  return 'oneOrMore' in content;
76
125
  }
126
+ /**
127
+ * Type guard that checks whether a content model pattern is a "zeroOrMore" pattern,
128
+ * indicating zero or more occurrences of a specific element or model.
129
+ *
130
+ * @param content - The content model pattern to check.
131
+ * @returns True if the pattern has a `zeroOrMore` property.
132
+ */
77
133
  export function isZeroOrMore(content) {
78
134
  return 'zeroOrMore' in content;
79
135
  }
136
+ /**
137
+ * Type guard that checks whether a content model pattern is a "choice" pattern,
138
+ * representing an alternation between multiple possible content model branches.
139
+ *
140
+ * @param content - The content model pattern to check.
141
+ * @returns True if the pattern has a `choice` property.
142
+ */
80
143
  export function isChoice(content) {
81
144
  return 'choice' in content;
82
145
  }
146
+ /**
147
+ * Type guard that checks whether a content model pattern is a "transparent" pattern,
148
+ * indicating the element inherits its parent's content model.
149
+ *
150
+ * @param content - The content model pattern to check.
151
+ * @returns True if the pattern has a `transparent` property.
152
+ */
83
153
  export function isTransparent(content) {
84
154
  return 'transparent' in content;
85
155
  }
156
+ /**
157
+ * Normalizes a quantified content model pattern (require, optional, oneOrMore, or zeroOrMore)
158
+ * into a uniform representation with the inner model, minimum count, maximum count,
159
+ * a regex-like repeat sign for debug display, and the appropriate missing-node error type.
160
+ *
161
+ * @param pattern - A quantified content model pattern to normalize.
162
+ * @returns An object with `model`, `min`, `max`, `repeat` sign, and optional `missingType`.
163
+ */
86
164
  export function normalizeModel(pattern) {
87
165
  let model;
88
166
  let min;
@@ -137,6 +215,15 @@ export function normalizeModel(pattern) {
137
215
  missingType,
138
216
  };
139
217
  }
218
+ /**
219
+ * Merges two Hints objects, combining their properties and selecting the
220
+ * `missing` hint with the higher `barelyMatchedElements` count (i.e., the
221
+ * one closest to a successful match) for the most useful error diagnostics.
222
+ *
223
+ * @param a - The first hints object.
224
+ * @param b - The second hints object.
225
+ * @returns A merged hints object with undefined properties removed.
226
+ */
140
227
  export function mergeHints(
141
228
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
142
229
  a,
@@ -149,6 +236,15 @@ b) {
149
236
  missing: missing && cleanObject(missing),
150
237
  });
151
238
  }
239
+ /**
240
+ * Creates a shallow copy of an object with all `undefined` values removed.
241
+ * Used to produce clean hint objects for result reporting without
242
+ * extraneous undefined properties.
243
+ *
244
+ * @template T - The object type.
245
+ * @param object - The source object to clean.
246
+ * @returns A new object containing only the defined properties of the input.
247
+ */
152
248
  export function cleanObject(object) {
153
249
  const newObject = {};
154
250
  for (const [key, value] of Object.entries(object)) {
@@ -158,7 +254,20 @@ export function cleanObject(object) {
158
254
  }
159
255
  return newObject;
160
256
  }
257
+ /**
258
+ * Tracks matched and unmatched child nodes during content model validation.
259
+ * Provides operations for adding matched nodes, backtracking to a locked state,
260
+ * capping matches at a maximum count, and generating colored debug output.
261
+ *
262
+ * The collection maintains an ordered set of original nodes and partitions them
263
+ * into matched and unmatched sets as the validation algorithm progresses.
264
+ */
161
265
  export class Collection {
266
+ /**
267
+ * Creates a new Collection from the given child nodes.
268
+ *
269
+ * @param origin - The initial list of child nodes to track.
270
+ */
162
271
  constructor(
163
272
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
164
273
  origin) {
@@ -169,18 +278,37 @@ export class Collection {
169
278
  __classPrivateFieldSet(this, _Collection_origin, [...origin], "f");
170
279
  __classPrivateFieldSet(this, _Collection_nodes, new Set(__classPrivateFieldGet(this, _Collection_origin, "f")), "f");
171
280
  }
281
+ /**
282
+ * Returns a copy of the currently matched nodes in insertion order.
283
+ */
172
284
  get matched() {
173
285
  return [...__classPrivateFieldGet(this, _Collection_matched, "f")];
174
286
  }
287
+ /**
288
+ * Returns the number of currently matched nodes.
289
+ */
175
290
  get matchedCount() {
176
291
  return __classPrivateFieldGet(this, _Collection_matched, "f").size;
177
292
  }
293
+ /**
294
+ * Returns a copy of all original nodes in their original order.
295
+ */
178
296
  get nodes() {
179
297
  return [...__classPrivateFieldGet(this, _Collection_origin, "f")];
180
298
  }
299
+ /**
300
+ * Returns the nodes that have not yet been matched, preserving original order.
301
+ */
181
302
  get unmatched() {
182
303
  return [...__classPrivateFieldGet(this, _Collection_nodes, "f")].filter(n => !__classPrivateFieldGet(this, _Collection_matched, "f").has(n));
183
304
  }
305
+ /**
306
+ * Adds nodes to the matched set. All nodes must belong to the original
307
+ * collection; external nodes will cause a ReferenceError.
308
+ *
309
+ * @param nodes - The child nodes to mark as matched.
310
+ * @returns True if the matched set grew (new nodes were added), false otherwise.
311
+ */
184
312
  addMatched(
185
313
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
186
314
  nodes) {
@@ -193,17 +321,43 @@ export class Collection {
193
321
  }
194
322
  return i < __classPrivateFieldGet(this, _Collection_matched, "f").size;
195
323
  }
324
+ /**
325
+ * Reverts the matched set to the last locked state, discarding
326
+ * any matches added since the last `lock()` call. Used for backtracking
327
+ * when a pattern match attempt fails after a zero-match.
328
+ */
196
329
  back() {
197
330
  __classPrivateFieldSet(this, _Collection_matched, new Set(__classPrivateFieldGet(this, _Collection_locked, "f")), "f");
198
331
  }
332
+ /**
333
+ * Saves the current matched set as a checkpoint that `back()` can
334
+ * revert to. Called after a successful backtrack recovery to preserve
335
+ * the known-good state.
336
+ */
199
337
  lock() {
200
338
  __classPrivateFieldSet(this, _Collection_locked, new Set(__classPrivateFieldGet(this, _Collection_matched, "f")), "f");
201
339
  }
340
+ /**
341
+ * Trims the matched set to at most `max` entries by removing
342
+ * the most recently added nodes beyond the limit. Used when the
343
+ * maximum occurrence count for a pattern is exceeded.
344
+ *
345
+ * @param max - The maximum number of matched nodes to retain.
346
+ */
202
347
  max(max) {
203
348
  const sliced = [...__classPrivateFieldGet(this, _Collection_matched, "f")].slice(max);
204
349
  for (const n of sliced)
205
350
  __classPrivateFieldGet(this, _Collection_matched, "f").delete(n);
206
351
  }
352
+ /**
353
+ * Returns a colored string representation of all nodes for debug logging.
354
+ * Matched nodes are shown in green, locked nodes in bold green, unmatched
355
+ * extra nodes in red (when highlighted), and transparent-mode nodes in
356
+ * blue/cyan/magenta variants.
357
+ *
358
+ * @param highlightExtraNodes - When true, unmatched nodes are highlighted in red/magenta.
359
+ * @returns A formatted string like `[ <div>, <span>, <p> ]` with ANSI colors.
360
+ */
207
361
  toString(highlightExtraNodes = false) {
208
362
  const out = [];
209
363
  for (const n of __classPrivateFieldGet(this, _Collection_origin, "f")) {
@@ -246,8 +400,23 @@ export class Collection {
246
400
  }
247
401
  }
248
402
  _Collection_locked = new WeakMap(), _Collection_matched = new WeakMap(), _Collection_nodes = new WeakMap(), _Collection_origin = new WeakMap();
403
+ /**
404
+ * Error class representing an unsupported content model feature.
405
+ * Thrown when the validation engine encounters a pattern type or
406
+ * configuration that is not yet implemented.
407
+ */
249
408
  export class UnsupportedError extends Error {
250
409
  }
410
+ /**
411
+ * Formats a content model (terminal model or pattern array) and its repeat sign
412
+ * into a regex-like string for debug logging output. Terminal selectors are
413
+ * rendered as `<selector>`, arrays of selectors as `(<s1>|<s2>)`, and
414
+ * nested patterns are recursively formatted.
415
+ *
416
+ * @param model - The model or pattern array to format.
417
+ * @param repeat - The quantifier sign to append (e.g., `+`, `*`, `?`, or `{m,n}`).
418
+ * @returns A human-readable regex-like string representation of the model.
419
+ */
251
420
  export function modelLog(model, repeat) {
252
421
  if (!isModel(model)) {
253
422
  return orderLog(model, repeat);
@@ -257,11 +426,28 @@ export function modelLog(model, repeat) {
257
426
  }
258
427
  return `(<${model.join('>|<')}>)${repeat}`;
259
428
  }
429
+ /**
430
+ * Formats an ordered array of content model patterns into a regex-like
431
+ * string for debug logging, with an optional repeat quantifier wrapping
432
+ * the entire sequence.
433
+ *
434
+ * @param order - The ordered array of patterns to format.
435
+ * @param repeat - The quantifier sign to wrap around the sequence.
436
+ * @returns A formatted string representation of the ordered patterns.
437
+ */
260
438
  function orderLog(order, repeat) {
261
439
  return order.length === 1 && order[0]
262
440
  ? markRepeat(patternLog(order[0]), repeat)
263
441
  : markRepeat(order.map(pattern => patternLog(pattern)).join(''), repeat);
264
442
  }
443
+ /**
444
+ * Formats a single content model pattern into a regex-like string for debug logging.
445
+ * Handles transparent, choice, and quantified patterns by dispatching to the
446
+ * appropriate formatting logic.
447
+ *
448
+ * @param pattern - The content model pattern to format.
449
+ * @returns A human-readable string representation of the pattern.
450
+ */
265
451
  function patternLog(pattern) {
266
452
  if (isTransparent(pattern)) {
267
453
  // 適当
@@ -273,6 +459,14 @@ function patternLog(pattern) {
273
459
  const { model, repeat } = normalizeModel(pattern);
274
460
  return modelLog(model, repeat);
275
461
  }
462
+ /**
463
+ * Wraps a pattern string with parentheses and a repeat quantifier if a
464
+ * repeat sign is present. If no repeat sign is given, returns the pattern unchanged.
465
+ *
466
+ * @param pattern - The pattern string to wrap.
467
+ * @param repeat - The quantifier sign to append, or an empty string for no repetition.
468
+ * @returns The pattern string, optionally wrapped as `(pattern)quantifier`.
469
+ */
276
470
  function markRepeat(pattern, repeat) {
277
471
  return repeat ? `(${pattern})${repeat}` : pattern;
278
472
  }
@@ -1,2 +1,9 @@
1
+ /**
2
+ * Rule that validates required `<select>` elements have a placeholder label option.
3
+ *
4
+ * Per the HTML spec, a `<select>` with `required`, without `multiple`, and with a
5
+ * display size of 1 must have a placeholder label option (first `<option>` with
6
+ * an empty value directly under `<select>`).
7
+ */
1
8
  declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, undefined>>;
2
9
  export default _default;
@@ -1,5 +1,12 @@
1
1
  import { createRule } from '@markuplint/ml-core';
2
2
  import meta from './meta.js';
3
+ /**
4
+ * Rule that validates required `<select>` elements have a placeholder label option.
5
+ *
6
+ * Per the HTML spec, a `<select>` with `required`, without `multiple`, and with a
7
+ * display size of 1 must have a placeholder label option (first `<option>` with
8
+ * an empty value directly under `<select>`).
9
+ */
3
10
  export default createRule({
4
11
  meta: meta,
5
12
  verify({ document, report, t }) {
@@ -18,13 +25,13 @@ export default createRule({
18
25
  },
19
26
  });
20
27
  /**
21
- * > If a select element has a required attribute specified,
22
- * > does not have a multiple attribute specified,
23
- * > and has a display size of 1,
24
- * > then the select element must have a placeholder label option.
28
+ * Determines whether a `<select>` element requires a placeholder label option.
25
29
  *
26
- * @param select
27
- * @returns
30
+ * Per the HTML spec, a select element needs a placeholder label option when it
31
+ * has `required`, does not have `multiple`, and has a display size of 1.
32
+ *
33
+ * @param select - The `<select>` element to evaluate.
34
+ * @returns `true` if the select element requires a placeholder label option.
28
35
  */
29
36
  function needPlaceholderLabelOption(
30
37
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -44,16 +51,13 @@ select) {
44
51
  return true;
45
52
  }
46
53
  /**
47
- * > If a select element has a required attribute specified,
48
- * > does not have a multiple attribute specified,
49
- * > and has a display size of 1;
50
- * > and if the value of the first option element
51
- * > in the select element's list of options (if any) is the empty string,
52
- * > and that option element's parent node is the select element (and not an optgroup element),
53
- * > then that option is the select element's **placeholder label option**.
54
+ * Checks whether a `<select>` element already has a valid placeholder label option.
55
+ *
56
+ * A placeholder label option is the first `<option>` whose value is the empty string
57
+ * and whose parent is the `<select>` element itself (not an `<optgroup>`).
54
58
  *
55
- * @param select
56
- * @returns
59
+ * @param select - The `<select>` element to check.
60
+ * @returns `true` if the element has a valid placeholder label option.
57
61
  */
58
62
  function hasPlaceholderLabelOption(
59
63
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `placeholder-label-option` rule, categorized as validation. */
1
2
  declare const _default: {
2
3
  readonly category: "validation";
3
4
  };
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `placeholder-label-option` rule, categorized as validation. */
1
2
  export default {
2
3
  category: 'validation',
3
4
  };
@@ -1,6 +1,17 @@
1
1
  import type { ARIAVersion } from '@markuplint/ml-spec';
2
+ /**
3
+ * Configuration options for the require-accessible-name rule.
4
+ */
2
5
  type Option = {
6
+ /** The ARIA specification version to use for role and accessible name computation. */
3
7
  ariaVersion: ARIAVersion;
4
8
  };
9
+ /**
10
+ * Rule that requires elements with roles that need accessible names to have one.
11
+ *
12
+ * For each element exposed to the accessibility tree whose computed ARIA role
13
+ * has `accessibleNameRequired` set to `true`, this rule verifies that the element
14
+ * provides a non-empty accessible name.
15
+ */
5
16
  declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, Option>>;
6
17
  export default _default;
@@ -2,6 +2,13 @@ import { createRule, getRoleSpec, getComputedRole } from '@markuplint/ml-core';
2
2
  import { ARIA_RECOMMENDED_VERSION, isExposed } from '@markuplint/ml-spec';
3
3
  import { accnameMayBeMutable } from '../helpers.js';
4
4
  import meta from './meta.js';
5
+ /**
6
+ * Rule that requires elements with roles that need accessible names to have one.
7
+ *
8
+ * For each element exposed to the accessibility tree whose computed ARIA role
9
+ * has `accessibleNameRequired` set to `true`, this rule verifies that the element
10
+ * provides a non-empty accessible name.
11
+ */
5
12
  export default createRule({
6
13
  meta: meta,
7
14
  defaultOptions: {
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `require-accessible-name` rule, categorized as accessibility. */
1
2
  declare const _default: {
2
3
  readonly category: "a11y";
3
4
  };
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `require-accessible-name` rule, categorized as accessibility. */
1
2
  export default {
2
3
  category: 'a11y',
3
4
  };
@@ -1,6 +1,18 @@
1
1
  import type { Lang } from './types.js';
2
+ /**
3
+ * Configuration options for the require-datetime rule.
4
+ */
2
5
  type Options = {
6
+ /** Languages to use when parsing natural language date/time text content. */
3
7
  langs?: Lang[];
4
8
  };
9
+ /**
10
+ * Rule that validates `<time>` elements without a `datetime` attribute have
11
+ * machine-readable date/time content.
12
+ *
13
+ * When a `<time>` element lacks the `datetime` attribute, this rule checks
14
+ * whether the text content is a valid datetime string. If not, it attempts
15
+ * to parse the content as natural language and suggests a `datetime` value.
16
+ */
5
17
  declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, Options>>;
6
18
  export default _default;
@@ -2,6 +2,14 @@ import { createRule } from '@markuplint/ml-core';
2
2
  import { check } from '@markuplint/types';
3
3
  import meta from './meta.js';
4
4
  import { getCandidateDatetimeString } from './utils.js';
5
+ /**
6
+ * Rule that validates `<time>` elements without a `datetime` attribute have
7
+ * machine-readable date/time content.
8
+ *
9
+ * When a `<time>` element lacks the `datetime` attribute, this rule checks
10
+ * whether the text content is a valid datetime string. If not, it attempts
11
+ * to parse the content as natural language and suggests a `datetime` value.
12
+ */
5
13
  export default createRule({
6
14
  meta: meta,
7
15
  defaultOptions: {
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `require-datetime` rule, categorized as validation. */
1
2
  declare const _default: {
2
3
  readonly category: "validation";
3
4
  };
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `require-datetime` rule, categorized as validation. */
1
2
  export default {
2
3
  category: 'validation',
3
4
  };
@@ -1,10 +1,17 @@
1
+ /** Union of possible date/time component keys used in parsed datetime data. */
1
2
  export type DateTimeKey = 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'ms';
3
+ /** A partial record mapping date/time component keys to their numeric values. */
2
4
  export type DateTimeData = Partial<Record<DateTimeKey, number>>;
5
+ /** Represents a parsed date/time value with optional timezone offset. */
3
6
  export type DateTime = {
7
+ /** The parsed date/time component values. */
4
8
  datetime: DateTimeData;
9
+ /** Timezone offset in minutes from UTC (e.g., -300 for UTC-5). */
5
10
  zone?: number;
6
11
  };
7
12
  /**
13
+ * Supported locale codes for natural language date/time parsing.
14
+ *
8
15
  * @see https://github.com/wanasit/chrono#locales
9
16
  */
10
17
  export type Lang = 'en' | 'ja' | 'fr' | 'nl' | 'ru' | 'de' | 'pt' | 'zh';
@@ -1,11 +1,24 @@
1
1
  import type { DateTime, Lang } from './types.js';
2
2
  /**
3
- * Datetime-ish text to a datetime data
3
+ * Parses natural language datetime text into structured datetime data.
4
4
  *
5
- * @param content
6
- * @param langs
7
- * @param base Reference date for a test
8
- * @returns
5
+ * Tries multiple locale parsers and returns the first successful parse result
6
+ * with only the certain (non-implied) date/time components included.
7
+ *
8
+ * @param content - The text content to parse as a datetime.
9
+ * @param langs - Locale codes to attempt parsing with.
10
+ * @param base - Optional reference date for relative date parsing (e.g., "tomorrow").
11
+ * @returns Parsed datetime data with timezone, or `null` if parsing fails.
9
12
  */
10
13
  export declare function parseADatetime(content: string, langs: readonly Lang[], base?: Readonly<Date>): DateTime | null;
14
+ /**
15
+ * Generates an HTML `datetime` attribute value from natural language text.
16
+ *
17
+ * Parses the text content using chrono-node and formats the result as an
18
+ * ISO 8601-like datetime string suitable for the `datetime` attribute.
19
+ *
20
+ * @param content - The text content to parse.
21
+ * @param langs - Locale codes to use for parsing. Defaults to all supported languages.
22
+ * @returns A formatted datetime string, or `null` if the content cannot be parsed.
23
+ */
11
24
  export declare function getCandidateDatetimeString(content: string, langs?: Lang[]): string | null;
@@ -1,12 +1,16 @@
1
1
  import * as chrono from 'chrono-node';
2
+ /** Default set of languages to try when parsing natural language datetime text. */
2
3
  const defaultLangs = ['en', 'ja', 'fr', 'nl', 'ru', 'de', 'pt', 'zh'];
3
4
  /**
4
- * Datetime-ish text to a datetime data
5
+ * Parses natural language datetime text into structured datetime data.
5
6
  *
6
- * @param content
7
- * @param langs
8
- * @param base Reference date for a test
9
- * @returns
7
+ * Tries multiple locale parsers and returns the first successful parse result
8
+ * with only the certain (non-implied) date/time components included.
9
+ *
10
+ * @param content - The text content to parse as a datetime.
11
+ * @param langs - Locale codes to attempt parsing with.
12
+ * @param base - Optional reference date for relative date parsing (e.g., "tomorrow").
13
+ * @returns Parsed datetime data with timezone, or `null` if parsing fails.
10
14
  */
11
15
  export function parseADatetime(content, langs, base) {
12
16
  const date = parseTryMultipleLangs(content, langs, base);
@@ -43,6 +47,16 @@ export function parseADatetime(content, langs, base) {
43
47
  }
44
48
  return datetime;
45
49
  }
50
+ /**
51
+ * Generates an HTML `datetime` attribute value from natural language text.
52
+ *
53
+ * Parses the text content using chrono-node and formats the result as an
54
+ * ISO 8601-like datetime string suitable for the `datetime` attribute.
55
+ *
56
+ * @param content - The text content to parse.
57
+ * @param langs - Locale codes to use for parsing. Defaults to all supported languages.
58
+ * @returns A formatted datetime string, or `null` if the content cannot be parsed.
59
+ */
46
60
  export function getCandidateDatetimeString(content, langs = defaultLangs) {
47
61
  const date = parseADatetime(content, langs);
48
62
  if (!date) {
@@ -60,6 +74,15 @@ export function getCandidateDatetimeString(content, langs = defaultLangs) {
60
74
  }
61
75
  return datetimeStr;
62
76
  }
77
+ /**
78
+ * Converts parsed datetime data into an ISO 8601-like string.
79
+ *
80
+ * Produces different formats depending on which components are present
81
+ * (e.g., date-only, time-only, or combined date-time).
82
+ *
83
+ * @param date - The parsed date/time component data.
84
+ * @returns A formatted datetime string, or `null` if the components do not match any known format.
85
+ */
63
86
  function toDatetimeString(date) {
64
87
  if (only(date, ['year', 'month'])) {
65
88
  return `${f(date.year, 4)}-${f(date.month, 2)}`;
@@ -90,6 +113,17 @@ function toDatetimeString(date) {
90
113
  }
91
114
  return null;
92
115
  }
116
+ /**
117
+ * Attempts to parse datetime text using multiple locale parsers sequentially.
118
+ *
119
+ * Returns the parsed start component from the first locale that produces a
120
+ * valid result (non-range, single datetime).
121
+ *
122
+ * @param content - The text content to parse.
123
+ * @param langs - Locale codes to try in order.
124
+ * @param base - Optional reference date for relative date parsing.
125
+ * @returns The parsed start component, or `null` if no locale succeeds.
126
+ */
93
127
  function parseTryMultipleLangs(content, langs, base) {
94
128
  for (const lang of langs) {
95
129
  const results =
@@ -111,6 +145,16 @@ function parseTryMultipleLangs(content, langs, base) {
111
145
  }
112
146
  return null;
113
147
  }
148
+ /**
149
+ * Type guard that checks if the given datetime data contains only the specified keys.
150
+ *
151
+ * @template K - The array of datetime keys to check for.
152
+ * @template U - Union of the key types.
153
+ * @template R - The resulting narrowed type with required properties.
154
+ * @param date - The datetime data to check.
155
+ * @param keys - The keys that should be the only ones present.
156
+ * @returns `true` if the date contains only the specified keys (and narrows the type).
157
+ */
114
158
  function only(date, keys) {
115
159
  const list = Object.keys(date);
116
160
  for (const exists of list) {
@@ -121,11 +165,11 @@ function only(date, keys) {
121
165
  return true;
122
166
  }
123
167
  /**
124
- * Formatter
168
+ * Formats a number with zero-padding to the specified width.
125
169
  *
126
- * @param n
127
- * @param pad zero padding
128
- * @returns
170
+ * @param n - The number to format.
171
+ * @param pad - The minimum number of digits in the output string.
172
+ * @returns The zero-padded string representation.
129
173
  */
130
174
  function f(n, pad) {
131
175
  return n.toString(10).padStart(pad, '0');