@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.
- package/CHANGELOG.md +9 -3
- 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 +14 -1
- 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 +161 -1
- 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 +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
|
-
*
|
|
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
|
-
*
|
|
27
|
-
*
|
|
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
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
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,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,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,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
|
-
*
|
|
3
|
+
* Parses natural language datetime text into structured datetime data.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
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
|
-
*
|
|
5
|
+
* Parses natural language datetime text into structured datetime data.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @
|
|
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
|
-
*
|
|
168
|
+
* Formats a number with zero-padding to the specified width.
|
|
125
169
|
*
|
|
126
|
-
* @param n
|
|
127
|
-
* @param pad
|
|
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');
|