@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.
- package/CHANGELOG.md +12 -1
- package/SKILL.md +76 -0
- package/lib/attr-check.d.ts +41 -5
- package/lib/attr-check.js +29 -5
- package/lib/attr-duplication/index.d.ts +7 -0
- package/lib/attr-duplication/index.js +7 -0
- package/lib/attr-duplication/meta.d.ts +1 -0
- package/lib/attr-duplication/meta.js +1 -0
- package/lib/attr-value-quotes/index.d.ts +10 -0
- package/lib/attr-value-quotes/index.js +10 -0
- package/lib/attr-value-quotes/meta.d.ts +1 -0
- package/lib/attr-value-quotes/meta.js +1 -0
- package/lib/case-sensitive-attr-name/index.d.ts +9 -0
- package/lib/case-sensitive-attr-name/index.js +8 -0
- package/lib/case-sensitive-attr-name/meta.d.ts +1 -0
- package/lib/case-sensitive-attr-name/meta.js +1 -0
- package/lib/case-sensitive-tag-name/index.d.ts +9 -0
- package/lib/case-sensitive-tag-name/index.js +8 -0
- package/lib/case-sensitive-tag-name/meta.d.ts +1 -0
- package/lib/case-sensitive-tag-name/meta.js +1 -0
- package/lib/character-reference/index.d.ts +8 -0
- package/lib/character-reference/index.js +16 -0
- package/lib/character-reference/meta.d.ts +1 -0
- package/lib/character-reference/meta.js +1 -0
- package/lib/class-naming/index.d.ts +9 -0
- package/lib/class-naming/index.js +8 -0
- package/lib/class-naming/meta.d.ts +1 -0
- package/lib/class-naming/meta.js +1 -0
- package/lib/create-message.d.ts +27 -0
- package/lib/create-message.js +56 -1
- package/lib/debug.d.ts +9 -0
- package/lib/debug.js +5 -0
- package/lib/deprecated-attr/index.d.ts +6 -0
- package/lib/deprecated-attr/index.js +6 -0
- package/lib/deprecated-attr/meta.d.ts +1 -0
- package/lib/deprecated-attr/meta.js +1 -0
- package/lib/deprecated-element/index.d.ts +8 -0
- package/lib/deprecated-element/index.js +8 -0
- package/lib/deprecated-element/meta.d.ts +1 -0
- package/lib/deprecated-element/meta.js +1 -0
- package/lib/disallowed-element/index.d.ts +7 -0
- package/lib/disallowed-element/index.js +7 -0
- package/lib/disallowed-element/meta.d.ts +1 -0
- package/lib/disallowed-element/meta.js +1 -0
- package/lib/doctype/index.d.ts +10 -0
- package/lib/doctype/index.js +8 -0
- package/lib/doctype/meta.d.ts +1 -0
- package/lib/doctype/meta.js +1 -0
- package/lib/end-tag/index.d.ts +7 -0
- package/lib/end-tag/index.js +7 -0
- package/lib/end-tag/meta.d.ts +1 -0
- package/lib/end-tag/meta.js +1 -0
- package/lib/heading-levels/index.d.ts +6 -0
- package/lib/heading-levels/index.js +6 -0
- package/lib/heading-levels/meta.d.ts +1 -0
- package/lib/heading-levels/meta.js +1 -0
- package/lib/helpers.d.ts +104 -0
- package/lib/helpers.js +105 -2
- package/lib/id-duplication/index.d.ts +7 -0
- package/lib/id-duplication/index.js +7 -0
- package/lib/id-duplication/meta.d.ts +1 -0
- package/lib/id-duplication/meta.js +1 -0
- package/lib/index.d.ts +23 -10
- package/lib/index.js +12 -0
- package/lib/ineffective-attr/index.d.ts +7 -0
- package/lib/ineffective-attr/index.js +7 -0
- package/lib/ineffective-attr/meta.d.ts +1 -0
- package/lib/ineffective-attr/meta.js +1 -0
- package/lib/invalid-attr/index.d.ts +24 -0
- package/lib/invalid-attr/index.js +17 -0
- package/lib/invalid-attr/meta.d.ts +1 -0
- package/lib/invalid-attr/meta.js +1 -0
- package/lib/label-has-control/index.d.ts +7 -0
- package/lib/label-has-control/index.js +11 -0
- package/lib/label-has-control/meta.d.ts +1 -0
- package/lib/label-has-control/meta.js +1 -0
- package/lib/landmark-roles/index.d.ts +14 -0
- package/lib/landmark-roles/index.js +21 -0
- package/lib/landmark-roles/meta.d.ts +1 -0
- package/lib/landmark-roles/meta.js +1 -0
- package/lib/neighbor-popovers/index.d.ts +8 -0
- package/lib/neighbor-popovers/index.js +26 -2
- package/lib/neighbor-popovers/meta.d.ts +1 -0
- package/lib/neighbor-popovers/meta.js +1 -0
- package/lib/no-ambiguous-navigable-target-names/index.d.ts +8 -0
- package/lib/no-ambiguous-navigable-target-names/index.js +8 -0
- package/lib/no-ambiguous-navigable-target-names/meta.d.ts +1 -0
- package/lib/no-ambiguous-navigable-target-names/meta.js +1 -0
- package/lib/no-boolean-attr-value/index.d.ts +7 -0
- package/lib/no-boolean-attr-value/index.js +7 -0
- package/lib/no-boolean-attr-value/meta.d.ts +1 -0
- package/lib/no-boolean-attr-value/meta.js +1 -0
- package/lib/no-consecutive-br/index.d.ts +8 -0
- package/lib/no-consecutive-br/index.js +8 -0
- package/lib/no-consecutive-br/meta.d.ts +1 -0
- package/lib/no-consecutive-br/meta.js +1 -0
- package/lib/no-default-value/index.d.ts +7 -0
- package/lib/no-default-value/index.js +7 -0
- package/lib/no-default-value/meta.d.ts +1 -0
- package/lib/no-default-value/meta.js +1 -0
- package/lib/no-duplicate-dt/index.d.ts +6 -0
- package/lib/no-duplicate-dt/index.js +6 -0
- package/lib/no-duplicate-dt/meta.d.ts +1 -0
- package/lib/no-duplicate-dt/meta.js +1 -0
- package/lib/no-empty-palpable-content/index.d.ts +13 -0
- package/lib/no-empty-palpable-content/index.js +12 -0
- package/lib/no-empty-palpable-content/meta.d.ts +1 -0
- package/lib/no-empty-palpable-content/meta.js +1 -0
- package/lib/no-hard-code-id/index.d.ts +8 -0
- package/lib/no-hard-code-id/index.js +8 -0
- package/lib/no-hard-code-id/meta.d.ts +1 -0
- package/lib/no-hard-code-id/meta.js +1 -0
- package/lib/no-orphaned-end-tag/index.d.ts +7 -0
- package/lib/no-orphaned-end-tag/index.js +7 -0
- package/lib/no-orphaned-end-tag/meta.d.ts +1 -0
- package/lib/no-orphaned-end-tag/meta.js +1 -0
- package/lib/no-refer-to-non-existent-id/index.d.ts +8 -0
- package/lib/no-refer-to-non-existent-id/index.js +9 -0
- package/lib/no-refer-to-non-existent-id/meta.d.ts +1 -0
- package/lib/no-refer-to-non-existent-id/meta.js +1 -0
- package/lib/no-use-event-handler-attr/index.d.ts +10 -0
- package/lib/no-use-event-handler-attr/index.js +8 -0
- package/lib/no-use-event-handler-attr/meta.d.ts +1 -0
- package/lib/no-use-event-handler-attr/meta.js +1 -0
- package/lib/permitted-contents/choice.d.ts +17 -0
- package/lib/permitted-contents/choice.js +30 -0
- package/lib/permitted-contents/complex-branch.d.ts +11 -7
- package/lib/permitted-contents/complex-branch.js +11 -7
- package/lib/permitted-contents/content-model.d.ts +11 -0
- package/lib/permitted-contents/content-model.js +32 -0
- package/lib/permitted-contents/count-pattern.d.ts +13 -7
- package/lib/permitted-contents/count-pattern.js +23 -7
- package/lib/permitted-contents/debug.browser.d.ts +12 -0
- package/lib/permitted-contents/debug.browser.js +12 -0
- package/lib/permitted-contents/debug.d.ts +12 -0
- package/lib/permitted-contents/debug.js +12 -0
- package/lib/permitted-contents/index.d.ts +12 -0
- package/lib/permitted-contents/index.js +21 -0
- package/lib/permitted-contents/matches-selector.d.ts +19 -0
- package/lib/permitted-contents/matches-selector.js +33 -0
- package/lib/permitted-contents/meta.d.ts +1 -0
- package/lib/permitted-contents/meta.js +1 -0
- package/lib/permitted-contents/order.d.ts +14 -7
- package/lib/permitted-contents/order.js +14 -7
- package/lib/permitted-contents/recursive-branch.d.ts +17 -0
- package/lib/permitted-contents/recursive-branch.js +17 -0
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +29 -0
- package/lib/permitted-contents/represent-transparent-nodes.js +24 -0
- package/lib/permitted-contents/start.d.ts +12 -6
- package/lib/permitted-contents/start.js +12 -6
- package/lib/permitted-contents/transparent.d.ts +12 -0
- package/lib/permitted-contents/transparent.js +12 -0
- package/lib/permitted-contents/types.d.ts +67 -0
- package/lib/permitted-contents/utils.d.ts +160 -0
- package/lib/permitted-contents/utils.js +194 -0
- package/lib/placeholder-label-option/index.d.ts +7 -0
- package/lib/placeholder-label-option/index.js +19 -15
- package/lib/placeholder-label-option/meta.d.ts +1 -0
- package/lib/placeholder-label-option/meta.js +1 -0
- package/lib/require-accessible-name/index.d.ts +11 -0
- package/lib/require-accessible-name/index.js +7 -0
- package/lib/require-accessible-name/meta.d.ts +1 -0
- package/lib/require-accessible-name/meta.js +1 -0
- package/lib/require-datetime/index.d.ts +12 -0
- package/lib/require-datetime/index.js +8 -0
- package/lib/require-datetime/meta.d.ts +1 -0
- package/lib/require-datetime/meta.js +1 -0
- package/lib/require-datetime/types.d.ts +7 -0
- package/lib/require-datetime/utils.d.ts +18 -5
- package/lib/require-datetime/utils.js +53 -9
- package/lib/required-attr/index.d.ts +13 -0
- package/lib/required-attr/index.js +7 -0
- package/lib/required-attr/meta.d.ts +1 -0
- package/lib/required-attr/meta.js +1 -0
- package/lib/required-element/index.d.ts +14 -0
- package/lib/required-element/index.js +14 -2
- package/lib/required-element/meta.d.ts +1 -0
- package/lib/required-element/meta.js +1 -0
- package/lib/required-h1/index.d.ts +12 -0
- package/lib/required-h1/index.js +7 -0
- package/lib/required-h1/meta.d.ts +1 -0
- package/lib/required-h1/meta.js +1 -0
- package/lib/table-row-column-alignment/find-children.d.ts +10 -0
- package/lib/table-row-column-alignment/find-children.js +11 -0
- package/lib/table-row-column-alignment/grid.d.ts +60 -0
- package/lib/table-row-column-alignment/grid.js +85 -0
- package/lib/table-row-column-alignment/index.d.ts +8 -0
- package/lib/table-row-column-alignment/index.js +8 -0
- package/lib/table-row-column-alignment/meta.d.ts +1 -0
- package/lib/table-row-column-alignment/meta.js +1 -0
- package/lib/table-row-column-alignment/types.d.ts +10 -0
- package/lib/use-list/index.d.ts +16 -0
- package/lib/use-list/index.js +20 -0
- package/lib/use-list/meta.d.ts +1 -0
- package/lib/use-list/meta.js +1 -0
- package/lib/wai-aria/checkings/abstract-role.d.ts +9 -0
- package/lib/wai-aria/checkings/abstract-role.js +9 -0
- package/lib/wai-aria/checkings/default-value.d.ts +11 -0
- package/lib/wai-aria/checkings/default-value.js +11 -0
- package/lib/wai-aria/checkings/deprecated-props.d.ts +11 -0
- package/lib/wai-aria/checkings/deprecated-props.js +11 -0
- package/lib/wai-aria/checkings/deprecated-role.d.ts +10 -0
- package/lib/wai-aria/checkings/deprecated-role.js +10 -0
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +14 -0
- package/lib/wai-aria/checkings/disallowed-prop.js +14 -0
- package/lib/wai-aria/checkings/implicit-props.d.ts +13 -0
- package/lib/wai-aria/checkings/implicit-props.js +13 -0
- package/lib/wai-aria/checkings/implicit-role.d.ts +9 -0
- package/lib/wai-aria/checkings/implicit-role.js +9 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +9 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.js +15 -4
- package/lib/wai-aria/checkings/no-global-prop.d.ts +10 -0
- package/lib/wai-aria/checkings/no-global-prop.js +10 -0
- package/lib/wai-aria/checkings/non-existent-role.d.ts +10 -0
- package/lib/wai-aria/checkings/non-existent-role.js +10 -0
- package/lib/wai-aria/checkings/permitted-roles.d.ts +10 -0
- package/lib/wai-aria/checkings/permitted-roles.js +10 -0
- package/lib/wai-aria/checkings/presentational-children.d.ts +7 -1
- package/lib/wai-aria/checkings/presentational-children.js +14 -1
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +9 -1
- package/lib/wai-aria/checkings/required-owned-elements.js +16 -1
- package/lib/wai-aria/checkings/required-prop.d.ts +13 -0
- package/lib/wai-aria/checkings/required-prop.js +13 -0
- package/lib/wai-aria/checkings/value.d.ts +23 -0
- package/lib/wai-aria/checkings/value.js +32 -0
- package/lib/wai-aria/index.d.ts +10 -0
- package/lib/wai-aria/index.js +10 -0
- package/lib/wai-aria/meta.d.ts +1 -0
- package/lib/wai-aria/meta.js +1 -0
- package/lib/wai-aria/types.d.ts +17 -0
- 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) {
|
|
@@ -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
|
-
*
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
12
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param
|
|
11
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @param
|
|
10
|
-
* @
|
|
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
|
};
|