@markuplint/rules 4.11.2 → 4.18.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 +12 -1
  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 +23 -10
  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 +160 -0
  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 +11 -11
@@ -2,6 +2,18 @@ import { createRule } from '@markuplint/ml-core';
2
2
  import { contentModel } from './content-model.js';
3
3
  import meta from './meta.js';
4
4
  import { transparentMode } from './represent-transparent-nodes.js';
5
+ /**
6
+ * The `permitted-contents` rule validates that each element's child nodes conform
7
+ * to the HTML content model specification. It is the most complex rule in markuplint,
8
+ * implementing a full content model validation engine that handles ordered sequences,
9
+ * quantified patterns (require, optional, oneOrMore, zeroOrMore), choice alternations,
10
+ * transparent content models, and conditional child node branches.
11
+ *
12
+ * For each element, it resolves the applicable content model (from the HTML spec or
13
+ * user-defined tag rules), evaluates the element's children against that model, and
14
+ * reports violations such as unexpected elements, missing required elements, or
15
+ * disallowed content through transparent models.
16
+ */
5
17
  export default createRule({
6
18
  meta: meta,
7
19
  defaultValue: [],
@@ -91,6 +103,15 @@ export default createRule({
91
103
  });
92
104
  },
93
105
  });
106
+ /**
107
+ * Generates a localized, human-readable name for a child node based on its type.
108
+ * Used in error messages to describe the offending node (e.g., 'the "div" element',
109
+ * 'the text node', 'the comment', 'the doctype', 'the code block').
110
+ *
111
+ * @param scope - The child node to generate a name for.
112
+ * @param t - The translator function for localized message formatting.
113
+ * @returns A localized string describing the node.
114
+ */
94
115
  function name(
95
116
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
96
117
  scope, t) {
@@ -1,3 +1,22 @@
1
1
  import type { ChildNode, Result, Specs } from './types.js';
2
+ /**
3
+ * Extended result type for selector matching that includes additional
4
+ * intermediate states: a selector that did not match but allows empty content,
5
+ * a missing node, or unmatched selectors with partial matches.
6
+ */
2
7
  export type SelectorResult = Result<'UNMATCHED_SELECTOR_BUT_MAY_EMPTY' | 'MISSING_NODE' | 'UNMATCHED_SELECTORS'>;
8
+ /**
9
+ * Tests whether a single child node matches a content model query selector.
10
+ * Handles special node types (text nodes, preprocessor blocks, custom elements)
11
+ * and delegates standard element matching to the CSS selector engine.
12
+ *
13
+ * The query string may reference content model categories (e.g., `#phrasing`)
14
+ * which are expanded to concrete tag selectors via `optCondition`.
15
+ *
16
+ * @param query - The content model query string (e.g., `"div"`, `"#phrasing"`, `":model(flow)"`).
17
+ * @param childNode - The child node to test, or undefined if no node is available.
18
+ * @param specs - The resolved spec data for category-to-tag-name expansion.
19
+ * @param depth - The current recursion depth, used for debug logging namespacing.
20
+ * @returns A selector result indicating match status with diagnostic hints.
21
+ */
3
22
  export declare function matchesSelector(query: string, childNode: ChildNode | undefined, specs: Specs, depth: number): SelectorResult;
@@ -1,6 +1,20 @@
1
1
  import { contentModelCategoryToTagNames } from '@markuplint/ml-spec';
2
2
  import { cmLog } from './debug.js';
3
3
  import { cleanObject, matches } from './utils.js';
4
+ /**
5
+ * Tests whether a single child node matches a content model query selector.
6
+ * Handles special node types (text nodes, preprocessor blocks, custom elements)
7
+ * and delegates standard element matching to the CSS selector engine.
8
+ *
9
+ * The query string may reference content model categories (e.g., `#phrasing`)
10
+ * which are expanded to concrete tag selectors via `optCondition`.
11
+ *
12
+ * @param query - The content model query string (e.g., `"div"`, `"#phrasing"`, `":model(flow)"`).
13
+ * @param childNode - The child node to test, or undefined if no node is available.
14
+ * @param specs - The resolved spec data for category-to-tag-name expansion.
15
+ * @param depth - The current recursion depth, used for debug logging namespacing.
16
+ * @returns A selector result indicating match status with diagnostic hints.
17
+ */
4
18
  export function matchesSelector(query,
5
19
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
6
20
  childNode, specs, depth) {
@@ -127,6 +141,9 @@ childNode, specs, depth) {
127
141
  hint: {},
128
142
  };
129
143
  }
144
+ /**
145
+ * Pre-computed conditions for well-known queries that do not depend on specs.
146
+ */
130
147
  const conditionWithoutSpecs = {
131
148
  '#custom': {
132
149
  selector: '#custom',
@@ -139,7 +156,23 @@ const conditionWithoutSpecs = {
139
156
  hasText: true,
140
157
  },
141
158
  };
159
+ /**
160
+ * Cache of parsed conditions keyed by specs instance and query string.
161
+ * Prevents redundant category expansion for the same query across multiple elements.
162
+ */
142
163
  const optConditionSpecsBaseCaches = new Map();
164
+ /**
165
+ * Parses a content model query string into a Condition object by expanding
166
+ * content model category references (e.g., `#phrasing`, `:model(flow)`) into
167
+ * concrete CSS `:is(...)` selectors. Also detects whether the query implicitly
168
+ * includes custom elements or text nodes.
169
+ *
170
+ * Results are cached per specs instance and query string.
171
+ *
172
+ * @param query - The raw content model query string to parse.
173
+ * @param specs - The spec data used to resolve category names to tag lists.
174
+ * @returns A readonly Condition with the resolved selector and flags.
175
+ */
143
176
  function optCondition(query, specs) {
144
177
  const condWithoutSpecs = conditionWithoutSpecs[query];
145
178
  if (condWithoutSpecs) {
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `permitted-contents` validation rule. */
1
2
  declare const _default: {
2
3
  readonly category: "validation";
3
4
  };
@@ -1,3 +1,4 @@
1
+ /** Rule metadata for the `permitted-contents` validation rule. */
1
2
  export default {
2
3
  category: 'validation',
3
4
  };
@@ -2,13 +2,20 @@ import type { ChildNode, Options, Result, Specs } from './types.js';
2
2
  import type { PermittedContentPattern } from '@markuplint/ml-spec';
3
3
  import type { ReadonlyDeep } from 'type-fest';
4
4
  /**
5
- * Check ordered array
5
+ * Validates an ordered sequence of content model patterns against a list of child nodes.
6
+ * Each pattern in the `contents` array is matched in order against the remaining unmatched
7
+ * child nodes, consuming nodes as they match. This implements the sequential composition
8
+ * semantics of HTML content models (e.g., "a `<caption>` followed by zero or more `<colgroup>`s
9
+ * followed by a `<thead>`...").
6
10
  *
7
- * @param contents
8
- * @param childNodes
9
- * @param specs
10
- * @param options
11
- * @param depth
12
- * @returns
11
+ * Supports backtracking: when a pattern matches zero nodes (zeroMatch), the algorithm
12
+ * can backtrack to try the next pattern from the previous position if the current pattern fails.
13
+ *
14
+ * @param contents - An ordered array of content model patterns to match sequentially.
15
+ * @param childNodes - The child nodes to validate against the patterns.
16
+ * @param specs - The resolved spec data for content model lookups.
17
+ * @param options - Validation behavior options.
18
+ * @param depth - The current recursion depth, used for debug logging and nested pattern matching.
19
+ * @returns A result indicating overall match status and the matched/unmatched node partitioning.
13
20
  */
14
21
  export declare function order(contents: ReadonlyDeep<PermittedContentPattern[]>, childNodes: readonly ChildNode[], specs: Specs, options: Options, depth: number): Result;
@@ -3,14 +3,21 @@ import { complexBranch } from './complex-branch.js';
3
3
  import { cmLog } from './debug.js';
4
4
  import { Collection, mergeHints, modelLog } from './utils.js';
5
5
  /**
6
- * Check ordered array
6
+ * Validates an ordered sequence of content model patterns against a list of child nodes.
7
+ * Each pattern in the `contents` array is matched in order against the remaining unmatched
8
+ * child nodes, consuming nodes as they match. This implements the sequential composition
9
+ * semantics of HTML content models (e.g., "a `<caption>` followed by zero or more `<colgroup>`s
10
+ * followed by a `<thead>`...").
7
11
  *
8
- * @param contents
9
- * @param childNodes
10
- * @param specs
11
- * @param options
12
- * @param depth
13
- * @returns
12
+ * Supports backtracking: when a pattern matches zero nodes (zeroMatch), the algorithm
13
+ * can backtrack to try the next pattern from the previous position if the current pattern fails.
14
+ *
15
+ * @param contents - An ordered array of content model patterns to match sequentially.
16
+ * @param childNodes - The child nodes to validate against the patterns.
17
+ * @param specs - The resolved spec data for content model lookups.
18
+ * @param options - Validation behavior options.
19
+ * @param depth - The current recursion depth, used for debug logging and nested pattern matching.
20
+ * @returns A result indicating overall match status and the matched/unmatched node partitioning.
14
21
  */
15
22
  export function order(contents,
16
23
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -2,4 +2,21 @@ import type { SelectorResult } from './matches-selector.js';
2
2
  import type { ChildNode, Options, Specs } from './types.js';
3
3
  import type { PermittedContentPattern, Model } from '@markuplint/ml-spec';
4
4
  import type { ReadonlyDeep } from 'type-fest';
5
+ /**
6
+ * Evaluates a model or nested pattern array against child nodes at the leaf level
7
+ * of the content model tree. If the input is a nested pattern array (not a terminal model),
8
+ * it recurses back into `order` for sequential evaluation. If it is a terminal model
9
+ * (a single selector string or an array of selector strings representing alternatives),
10
+ * it tests the first unmatched child node against each selector via `matchesSelector`.
11
+ *
12
+ * For array-of-selectors models, the selectors act as alternatives (logical OR): the first
13
+ * selector to match the child node produces the result.
14
+ *
15
+ * @param model - Either a terminal model (selector string or array of selector strings) or a nested pattern array.
16
+ * @param childNodes - The child nodes to validate against the model.
17
+ * @param specs - The resolved spec data for content model lookups.
18
+ * @param options - Validation behavior options.
19
+ * @param depth - The current recursion depth, used for debug logging and nested evaluation.
20
+ * @returns A selector result indicating whether the first unmatched child node matches the model.
21
+ */
5
22
  export declare function recursiveBranch(model: ReadonlyDeep<Model | PermittedContentPattern[]>, childNodes: readonly ChildNode[], specs: Specs, options: Options, depth: number): SelectorResult;
@@ -1,6 +1,23 @@
1
1
  import { matchesSelector } from './matches-selector.js';
2
2
  import { order } from './order.js';
3
3
  import { Collection, isModel } from './utils.js';
4
+ /**
5
+ * Evaluates a model or nested pattern array against child nodes at the leaf level
6
+ * of the content model tree. If the input is a nested pattern array (not a terminal model),
7
+ * it recurses back into `order` for sequential evaluation. If it is a terminal model
8
+ * (a single selector string or an array of selector strings representing alternatives),
9
+ * it tests the first unmatched child node against each selector via `matchesSelector`.
10
+ *
11
+ * For array-of-selectors models, the selectors act as alternatives (logical OR): the first
12
+ * selector to match the child node produces the result.
13
+ *
14
+ * @param model - Either a terminal model (selector string or array of selector strings) or a nested pattern array.
15
+ * @param childNodes - The child nodes to validate against the model.
16
+ * @param specs - The resolved spec data for content model lookups.
17
+ * @param options - Validation behavior options.
18
+ * @param depth - The current recursion depth, used for debug logging and nested evaluation.
19
+ * @returns A selector result indicating whether the first unmatched child node matches the model.
20
+ */
4
21
  export function recursiveBranch(model,
5
22
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
6
23
  childNodes, specs, options, depth) {
@@ -1,8 +1,37 @@
1
1
  import type { ChildNode, Options, Result, Specs } from './types.js';
2
+ /**
3
+ * A map tracking child nodes that are currently being evaluated through
4
+ * a transparent content model. Used to prevent infinite recursion and
5
+ * to enable special handling in error messages and debug output.
6
+ */
2
7
  export declare const transparentMode: Map<ChildNode, true>;
8
+ /**
9
+ * Represents a possible resolution of transparent content model nodes,
10
+ * containing the flattened list of child nodes to validate and any
11
+ * errors detected during transparent model resolution.
12
+ */
3
13
  type TransparentNode = {
4
14
  nodes: ChildNode[];
5
15
  errors: Result[];
6
16
  };
17
+ /**
18
+ * Resolves transparent content model elements by replacing them with their
19
+ * children for validation purposes. In HTML, elements like `<a>`, `<ins>`, and `<del>`
20
+ * have transparent content models, meaning their children must be valid in the
21
+ * parent's content model as if the transparent element were not present.
22
+ *
23
+ * This function:
24
+ * 1. Identifies child elements with transparent content models.
25
+ * 2. Filters out children that match non-transparent parts of the element's content model.
26
+ * 3. Replaces the transparent element with its remaining (unmatched) children.
27
+ * 4. Validates that each remaining child satisfies the transparent model's condition selector.
28
+ * 5. Recursively resolves parent-level transparent nodes to propagate errors up the tree.
29
+ * 6. Uses `branchesToPatterns` to handle branching when multiple resolutions are possible.
30
+ *
31
+ * @param childNodes - The child nodes of the element being validated, some of which may be transparent.
32
+ * @param specs - The resolved spec data for content model lookups.
33
+ * @param options - Validation behavior options.
34
+ * @returns An array of possible transparent node resolutions, each with flattened nodes and accumulated errors.
35
+ */
7
36
  export declare function representTransparentNodes(childNodes: readonly ChildNode[], specs: Specs, options: Options): TransparentNode[];
8
37
  export {};
@@ -2,7 +2,31 @@ import { getContentModel } from '@markuplint/ml-spec';
2
2
  import { branchesToPatterns } from '@markuplint/shared';
3
3
  import { order } from './order.js';
4
4
  import { Collection, isTransparent, matches } from './utils.js';
5
+ /**
6
+ * A map tracking child nodes that are currently being evaluated through
7
+ * a transparent content model. Used to prevent infinite recursion and
8
+ * to enable special handling in error messages and debug output.
9
+ */
5
10
  export const transparentMode = new Map();
11
+ /**
12
+ * Resolves transparent content model elements by replacing them with their
13
+ * children for validation purposes. In HTML, elements like `<a>`, `<ins>`, and `<del>`
14
+ * have transparent content models, meaning their children must be valid in the
15
+ * parent's content model as if the transparent element were not present.
16
+ *
17
+ * This function:
18
+ * 1. Identifies child elements with transparent content models.
19
+ * 2. Filters out children that match non-transparent parts of the element's content model.
20
+ * 3. Replaces the transparent element with its remaining (unmatched) children.
21
+ * 4. Validates that each remaining child satisfies the transparent model's condition selector.
22
+ * 5. Recursively resolves parent-level transparent nodes to propagate errors up the tree.
23
+ * 6. Uses `branchesToPatterns` to handle branching when multiple resolutions are possible.
24
+ *
25
+ * @param childNodes - The child nodes of the element being validated, some of which may be transparent.
26
+ * @param specs - The resolved spec data for content model lookups.
27
+ * @param options - Validation behavior options.
28
+ * @returns An array of possible transparent node resolutions, each with flattened nodes and accumulated errors.
29
+ */
6
30
  export function representTransparentNodes(
7
31
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
8
32
  childNodes, specs, options) {
@@ -2,12 +2,18 @@ import type { ContentModelResult, Element, Options, Specs } from './types.js';
2
2
  import type { ContentModel } from '@markuplint/ml-spec';
3
3
  import type { ReadonlyDeep } from 'type-fest';
4
4
  /**
5
- * Check start
5
+ * Entry point for validating an element's child nodes against a content model definition.
6
+ * Handles the three forms of content model: `false` (no content allowed), `true` (any content
7
+ * allowed), or an ordered pattern array. For pattern arrays, transparent content model nodes
8
+ * are first resolved, then each resulting pattern of child nodes is validated via `order`.
6
9
  *
7
- * @param contents
8
- * @param el
9
- * @param specs
10
- * @param options
11
- * @returns
10
+ * When `options.evaluateConditionalChildNodes` is enabled, all conditional branches
11
+ * (e.g., from template directives) are evaluated independently.
12
+ *
13
+ * @param contents - The content model definition: `false` for empty, `true` for any, or an array of patterns.
14
+ * @param el - The parent element whose children are being validated.
15
+ * @param specs - The resolved spec data for content model lookups.
16
+ * @param options - Validation behavior options.
17
+ * @returns An array of content model results describing any violations found.
12
18
  */
13
19
  export declare function start(contents: ReadonlyDeep<ContentModel['contents']>, el: Element, specs: Specs, options: Options): ContentModelResult[];
@@ -1,13 +1,19 @@
1
1
  import { order } from './order.js';
2
2
  import { representTransparentNodes } from './represent-transparent-nodes.js';
3
3
  /**
4
- * Check start
4
+ * Entry point for validating an element's child nodes against a content model definition.
5
+ * Handles the three forms of content model: `false` (no content allowed), `true` (any content
6
+ * allowed), or an ordered pattern array. For pattern arrays, transparent content model nodes
7
+ * are first resolved, then each resulting pattern of child nodes is validated via `order`.
5
8
  *
6
- * @param contents
7
- * @param el
8
- * @param specs
9
- * @param options
10
- * @returns
9
+ * When `options.evaluateConditionalChildNodes` is enabled, all conditional branches
10
+ * (e.g., from template directives) are evaluated independently.
11
+ *
12
+ * @param contents - The content model definition: `false` for empty, `true` for any, or an array of patterns.
13
+ * @param el - The parent element whose children are being validated.
14
+ * @param specs - The resolved spec data for content model lookups.
15
+ * @param options - Validation behavior options.
16
+ * @returns An array of content model results describing any violations found.
11
17
  */
12
18
  export function start(contents,
13
19
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -1,2 +1,14 @@
1
1
  import type { ChildNode, Result } from './types.js';
2
+ /**
3
+ * Handles the transparent content model pattern by passing all child nodes
4
+ * through as matched. In HTML, a transparent element inherits the content model
5
+ * of its parent, so its children are validated against the parent's model instead.
6
+ *
7
+ * If the element is a component root (has no grandparent element), all children
8
+ * are treated as matched. Otherwise, validation is deferred to the parent's
9
+ * content model processing.
10
+ *
11
+ * @param childNodes - The child nodes to evaluate under the transparent model.
12
+ * @returns A result indicating all children are matched (validation deferred to parent).
13
+ */
2
14
  export declare function transparent(childNodes: readonly ChildNode[]): Result;
@@ -1,5 +1,17 @@
1
1
  import { cmLog } from './debug.js';
2
2
  const transparentLog = cmLog.extend('transparent');
3
+ /**
4
+ * Handles the transparent content model pattern by passing all child nodes
5
+ * through as matched. In HTML, a transparent element inherits the content model
6
+ * of its parent, so its children are validated against the parent's model instead.
7
+ *
8
+ * If the element is a component root (has no grandparent element), all children
9
+ * are treated as matched. Otherwise, validation is deferred to the parent's
10
+ * content model processing.
11
+ *
12
+ * @param childNodes - The child nodes to evaluate under the transparent model.
13
+ * @returns A result indicating all children are matched (validation deferred to parent).
14
+ */
3
15
  export function transparent(
4
16
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
5
17
  childNodes) {
@@ -1,8 +1,19 @@
1
1
  import type { Element as _Element, ChildNode as _ChildNode } from '@markuplint/ml-core';
2
2
  import type { ContentModel, MLMLSpec } from '@markuplint/ml-spec';
3
3
  import type { ReadonlyDeep } from 'type-fest';
4
+ /**
5
+ * An element node parameterized with the permitted-contents rule's TagRule and Options.
6
+ */
4
7
  export type Element = _Element<TagRule[], Options>;
8
+ /**
9
+ * A child node parameterized with the permitted-contents rule's TagRule and Options.
10
+ */
5
11
  export type ChildNode = _ChildNode<TagRule[], Options>;
12
+ /**
13
+ * A subset of the full ML spec containing only the fields needed
14
+ * for content model validation: citation references, global definitions,
15
+ * and per-element content model specifications.
16
+ */
6
17
  export type Specs = {
7
18
  readonly cites: MLMLSpec['cites'];
8
19
  readonly def: MLMLSpec['def'];
@@ -13,12 +24,24 @@ export type Specs = {
13
24
  };
14
25
  }[];
15
26
  };
27
+ /**
28
+ * The final result of content model validation for a single child node,
29
+ * indicating whether the node is permitted, missing, or unexpected
30
+ * within its parent element's content model.
31
+ */
16
32
  export type ContentModelResult = {
17
33
  type: MatchedReason | UnmatchedReason;
18
34
  scope: ChildNode;
19
35
  query: Result['query'];
20
36
  hint: Result['hint'];
21
37
  };
38
+ /**
39
+ * An intermediate result produced during content model pattern matching.
40
+ * Tracks which child nodes were matched, which were unmatched, and
41
+ * provides diagnostic hints about the nature of a mismatch.
42
+ *
43
+ * @template T - Additional result type strings beyond the standard matched/unmatched reasons.
44
+ */
22
45
  export type Result<T extends string = MatchedReason> = {
23
46
  type: MatchedReason | UnmatchedReason | T;
24
47
  matched: ChildNode[];
@@ -27,6 +50,11 @@ export type Result<T extends string = MatchedReason> = {
27
50
  query: string;
28
51
  hint: Hints;
29
52
  };
53
+ /**
54
+ * Diagnostic hints attached to a content model result, providing additional
55
+ * context for error reporting such as maximum allowed count, the offending
56
+ * node, or information about transparent model violations.
57
+ */
30
58
  export type Hints = {
31
59
  max?: number;
32
60
  not?: ChildNode;
@@ -36,21 +64,60 @@ export type Hints = {
36
64
  need?: string;
37
65
  };
38
66
  };
67
+ /**
68
+ * Reasons indicating that a content model pattern successfully matched.
69
+ * `MATCHED` means one or more nodes matched; `MATCHED_ZERO` means the pattern
70
+ * matched vacuously (zero nodes consumed, but the pattern allows it).
71
+ */
39
72
  export type MatchedReason = 'MATCHED' | 'MATCHED_ZERO';
73
+ /**
74
+ * Reasons indicating that a content model pattern did not match.
75
+ * Includes cases where content is disallowed entirely, an unexpected node
76
+ * was found, a transparent model forbids the node, or a required node is missing.
77
+ */
40
78
  export type UnmatchedReason = 'NOTHING' | 'UNEXPECTED_EXTRA_NODE' | 'TRANSPARENT_MODEL_DISALLOWS' | MissingNodeReason;
79
+ /**
80
+ * Specific reasons for a missing node: either a required element is absent,
81
+ * or one-or-more occurrences are expected but none were found.
82
+ */
41
83
  export type MissingNodeReason = 'MISSING_NODE_REQUIRED' | 'MISSING_NODE_ONE_OR_MORE';
84
+ /**
85
+ * A regular-expression-like repeat sign used to describe the quantifier
86
+ * of a content model pattern (e.g., `?` for optional, `+` for one-or-more,
87
+ * `*` for zero-or-more, or `{min,max}` for a specific range).
88
+ */
42
89
  export type RepeatSign = '' | '?' | '+' | '*' | `{${number},${number}}`;
90
+ /**
91
+ * Describes a transparent content model element along with any additional
92
+ * CSS selector condition that must be satisfied for the transparency to apply.
93
+ */
43
94
  export type TransparentModel = {
44
95
  el: Element;
45
96
  additionalCondition: string;
46
97
  };
98
+ /**
99
+ * A user-defined tag rule that associates an element tag name with
100
+ * its permitted content model definition, used to override or extend
101
+ * the built-in HTML spec content models.
102
+ */
47
103
  export type TagRule = {
48
104
  readonly tag: string;
49
105
  } & ReadonlyDeep<ContentModel>;
106
+ /**
107
+ * Options for the permitted-contents rule that control validation behavior.
108
+ */
50
109
  export type Options = {
110
+ /**
111
+ * When true, skips reporting missing-node errors on elements that
112
+ * have mutable children (e.g., elements whose children may be
113
+ * dynamically injected by a framework or template engine).
114
+ */
51
115
  readonly ignoreHasMutableChildren: boolean;
52
116
  /**
53
117
  * @experimental
118
+ * When true, evaluates conditional child node branches (e.g., from
119
+ * template directives like `v-if`) to validate each possible branch
120
+ * against the content model.
54
121
  */
55
122
  readonly evaluateConditionalChildNodes: boolean;
56
123
  };