@markuplint/ml-core 5.0.0-rc.0 → 5.0.0-rc.2
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/ARCHITECTURE.ja.md +1 -2
- package/ARCHITECTURE.md +1 -2
- package/CHANGELOG.md +34 -0
- package/docs/ml-dom/helpers.ja.md +1 -1
- package/docs/ml-dom/helpers.md +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/ml-core.js +31 -1
- package/lib/ml-dom/helper/accname.js +5 -7
- package/lib/ml-dom/helper/create-node.js +1 -1
- package/lib/ml-dom/manipulations/child-node-methods.js +1 -1
- package/lib/ml-dom/node/attr.js +1 -1
- package/lib/ml-dom/node/character-data.js +1 -1
- package/lib/ml-dom/node/document-fragment.js +1 -1
- package/lib/ml-dom/node/document.d.ts +32 -1
- package/lib/ml-dom/node/document.js +109 -1
- package/lib/ml-dom/node/dom-token-list.js +1 -1
- package/lib/ml-dom/node/element.d.ts +28 -9
- package/lib/ml-dom/node/element.js +25 -6
- package/lib/ml-dom/node/named-node-map.js +1 -1
- package/lib/ml-dom/node/node-store.d.ts +1 -0
- package/lib/ml-dom/node/node-store.js +10 -0
- package/lib/ml-dom/node/node.d.ts +7 -0
- package/lib/ml-dom/node/node.js +16 -4
- package/lib/ml-dom/node/parent-node.js +1 -1
- package/lib/ml-dom/node/text.js +1 -1
- package/lib/ruleset/index.d.ts +13 -1
- package/lib/ruleset/index.js +14 -1
- package/package.json +19 -15
- package/lib/ml-dom/helper/get-indent.d.ts +0 -20
- package/lib/ml-dom/helper/get-indent.js +0 -90
- package/lib/ml-dom/node/unexpected-call-error.d.ts +0 -2
- package/lib/ml-dom/node/unexpected-call-error.js +0 -2
package/ARCHITECTURE.ja.md
CHANGED
|
@@ -31,8 +31,7 @@ src/
|
|
|
31
31
|
│ │ ├── element-close-tag.ts — MLElementCloseTag
|
|
32
32
|
│ │ ├── rule-mapper.ts — RuleMapper(ルールセット → ノードマッピング)
|
|
33
33
|
│ │ ├── types.ts — ノード型定数、AccessibilityProperties
|
|
34
|
-
│ │
|
|
35
|
-
│ │ └── unexpected-call-error.ts — 未サポート DOM メソッドのエラー
|
|
34
|
+
│ │ └── node-list.ts — NodeList/HTMLCollection ユーティリティ
|
|
36
35
|
│ ├── token/
|
|
37
36
|
│ │ └── token.ts — MLToken(位置情報付き基底トークン)
|
|
38
37
|
│ ├── helper/
|
package/ARCHITECTURE.md
CHANGED
|
@@ -31,8 +31,7 @@ src/
|
|
|
31
31
|
│ │ ├── element-close-tag.ts — MLElementCloseTag
|
|
32
32
|
│ │ ├── rule-mapper.ts — RuleMapper (ruleset → node mapping)
|
|
33
33
|
│ │ ├── types.ts — Node type constants, AccessibilityProperties
|
|
34
|
-
│ │
|
|
35
|
-
│ │ └── unexpected-call-error.ts — Error for unsupported DOM methods
|
|
34
|
+
│ │ └── node-list.ts — NodeList/HTMLCollection utilities
|
|
36
35
|
│ ├── token/
|
|
37
36
|
│ │ └── token.ts — MLToken (base positional token)
|
|
38
37
|
│ ├── helper/
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,40 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [5.0.0-rc.2](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.1...v5.0.0-rc.2) (2026-04-15)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **ml-core:** propagate base rule disable to virtual rules in nodeRules/childNodeRules ([06fa269](https://github.com/markuplint/markuplint/commit/06fa2695d43671adc1ebcadf1304aca44fd10919)), closes [#3578](https://github.com/markuplint/markuplint/issues/3578)
|
|
11
|
+
|
|
12
|
+
- build!: remove ESLint and replace with oxlint ([1e0a337](https://github.com/markuplint/markuplint/commit/1e0a337707f76b903b16beeeb8c4d4fc0d8fc9e4))
|
|
13
|
+
- feat(ml-core)!: remove deprecated getIndent function ([7ab1a2d](https://github.com/markuplint/markuplint/commit/7ab1a2dae8f36002f4e5f3108a400bb9095db319))
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- **ml-core:** propagate option overrides to virtual rules in nodeRules/childNodeRules ([9cb9521](https://github.com/markuplint/markuplint/commit/9cb9521fc1303c132f547ffd1e8c82b3b9099bef))
|
|
18
|
+
|
|
19
|
+
### BREAKING CHANGES
|
|
20
|
+
|
|
21
|
+
- ESLint is no longer used. Use oxlint instead.
|
|
22
|
+
- getIndent() has been removed from the public API.
|
|
23
|
+
|
|
24
|
+
# [5.0.0-rc.1](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.0...v5.0.0-rc.1) (2026-03-27)
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
- add isFatalError guard to MLEngine.exec and fix accname Deno crash ([c4b20de](https://github.com/markuplint/markuplint/commit/c4b20de128b2cfee582b3588e5004cb90065825b))
|
|
29
|
+
- **ml-core:** add DOM stubs for TS 6 lib.dom.d.ts updates ([837a2ba](https://github.com/markuplint/markuplint/commit/837a2bad5afe967d4d309b91d056b46fc91c7512))
|
|
30
|
+
|
|
31
|
+
- feat(ml-core)!: resolve node references via UUID instead of object refs ([e9b6f4e](https://github.com/markuplint/markuplint/commit/e9b6f4e68bda2f60c9fa69699bf251b51874a4ac))
|
|
32
|
+
|
|
33
|
+
### BREAKING CHANGES
|
|
34
|
+
|
|
35
|
+
- MLDOM now resolves parent and pair nodes via UUID
|
|
36
|
+
strings from the AST instead of direct object references.
|
|
37
|
+
|
|
38
|
+
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
39
|
+
|
|
6
40
|
# [5.0.0-rc.0](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.3...v5.0.0-rc.0) (2026-03-12)
|
|
7
41
|
|
|
8
42
|
### Bug Fixes
|
|
@@ -18,7 +18,7 @@ AST ノード型を対応する MLDOM コンストラクタにディスパッチ
|
|
|
18
18
|
| `'invalid'`(`kind: 'starttag'`) | `MLElement`(`x-invalid`、`elementType: 'web-component'` として) | `1` |
|
|
19
19
|
| `'invalid'`(その他の kind) | `MLText` | `3` |
|
|
20
20
|
|
|
21
|
-
**注:** `'endtag'` は `createNode()` を通過しません -- ドキュメントのコンストラクション中にスキップされます。`MLElement` は `
|
|
21
|
+
**注:** `'endtag'` は `createNode()` を通過しません -- ドキュメントのコンストラクション中にスキップされます。`MLElement` は `pairNodeUuid` を解決して内部的に `MLElementCloseTag` を作成します。`MLASTAttr` は `MLElement` によって処理され、要素の `attributes` 配列から `MLAttr` インスタンスを作成します。
|
|
22
22
|
|
|
23
23
|
### ウォーカー
|
|
24
24
|
|
package/docs/ml-dom/helpers.md
CHANGED
|
@@ -18,7 +18,7 @@ Factory function that dispatches AST node types to their corresponding MLDOM con
|
|
|
18
18
|
| `'invalid'` (`kind: 'starttag'`) | `MLElement` (as `x-invalid`, `elementType: 'web-component'`) | `1` |
|
|
19
19
|
| `'invalid'` (other kind) | `MLText` | `3` |
|
|
20
20
|
|
|
21
|
-
**Note:** `'endtag'` is not passed through `createNode()` -- it is skipped during document construction. `MLElement` creates `MLElementCloseTag` internally
|
|
21
|
+
**Note:** `'endtag'` is not passed through `createNode()` -- it is skipped during document construction. `MLElement` creates `MLElementCloseTag` internally by resolving its `pairNodeUuid`. `MLASTAttr` is handled by `MLElement` which creates `MLAttr` instances from the element's `attributes` array.
|
|
22
22
|
|
|
23
23
|
### Walkers
|
|
24
24
|
|
package/lib/index.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ export { enableDebug } from './debug.js';
|
|
|
5
5
|
export { computeCursorOffset } from './cursor-offset.js';
|
|
6
6
|
export { applyFixes } from './fix-applier.js';
|
|
7
7
|
export type { FixResult } from './fix-applier.js';
|
|
8
|
-
export { getIndent } from './ml-dom/helper/get-indent.js';
|
|
9
8
|
export * from './convert-ruleset.js';
|
|
10
9
|
export * from './ml-core.js';
|
|
11
10
|
export * from './ml-dom/index.js';
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,6 @@ export { Ruleset } from './ruleset/index.js';
|
|
|
3
3
|
export { enableDebug } from './debug.js';
|
|
4
4
|
export { computeCursorOffset } from './cursor-offset.js';
|
|
5
5
|
export { applyFixes } from './fix-applier.js';
|
|
6
|
-
export { getIndent } from './ml-dom/helper/get-indent.js';
|
|
7
6
|
export * from './convert-ruleset.js';
|
|
8
7
|
export * from './ml-core.js';
|
|
9
8
|
export * from './ml-dom/index.js';
|
package/lib/ml-core.js
CHANGED
|
@@ -67,6 +67,8 @@ export class MLCore {
|
|
|
67
67
|
rules: resolvedRules,
|
|
68
68
|
nodeRules: nodeRuleResult.transformedNodeRules,
|
|
69
69
|
childNodeRules: childNodeRuleResult.transformedNodeRules,
|
|
70
|
+
baseRuleToVirtualNames: buildBaseRuleToVirtualNames(namedRulesResult.virtualRules),
|
|
71
|
+
mappingErrors: [],
|
|
70
72
|
};
|
|
71
73
|
this.#disabledNamespaces = extractDisabledNamespaces(resolvedRules);
|
|
72
74
|
this.#configErrors.push(...namedRulesResult.errors, ...nodeRuleResult.errors, ...childNodeRuleResult.errors);
|
|
@@ -100,7 +102,7 @@ export class MLCore {
|
|
|
100
102
|
this.#locale = locale ?? this.#locale;
|
|
101
103
|
this.#schemas = schemas ?? this.#schemas;
|
|
102
104
|
this.#configErrors = [...(configErrors ?? [])];
|
|
103
|
-
const baseRules = rules
|
|
105
|
+
const baseRules = rules ? [...rules] : this.#rules.filter(r => !r.baseRuleId);
|
|
104
106
|
// Use pre-expansion originals as fallback when ruleset is not provided
|
|
105
107
|
const incomingNodeRules = ruleset?.nodeRules ?? this.#originalNodeRules;
|
|
106
108
|
const incomingChildNodeRules = ruleset?.childNodeRules ?? this.#originalChildNodeRules;
|
|
@@ -123,6 +125,8 @@ export class MLCore {
|
|
|
123
125
|
rules: resolvedRules,
|
|
124
126
|
nodeRules: nodeRuleResult.transformedNodeRules,
|
|
125
127
|
childNodeRules: childNodeRuleResult.transformedNodeRules,
|
|
128
|
+
baseRuleToVirtualNames: buildBaseRuleToVirtualNames(namedRulesResult.virtualRules),
|
|
129
|
+
mappingErrors: [],
|
|
126
130
|
};
|
|
127
131
|
this.#disabledNamespaces = extractDisabledNamespaces(resolvedRules);
|
|
128
132
|
this.#configErrors.push(...namedRulesResult.errors, ...nodeRuleResult.errors, ...childNodeRuleResult.errors);
|
|
@@ -243,6 +247,9 @@ export class MLCore {
|
|
|
243
247
|
tagNameCaseSensitive: this.#parser.tagNameCaseSensitive,
|
|
244
248
|
pretenders: this.#pretenders,
|
|
245
249
|
});
|
|
250
|
+
// Collect errors from rule mapping (e.g., invalid wildcard usage)
|
|
251
|
+
this.#configErrors.push(...this.#ruleset.mappingErrors);
|
|
252
|
+
this.#ruleset.mappingErrors.length = 0;
|
|
246
253
|
}
|
|
247
254
|
catch (error) {
|
|
248
255
|
if (error instanceof ParserError) {
|
|
@@ -426,6 +433,29 @@ function extractDisabledNamespaces(rules) {
|
|
|
426
433
|
.filter(([key, value]) => key.endsWith('/*') && value === false)
|
|
427
434
|
.map(([key]) => key.slice(0, -1)); // "a11y/*" → "a11y/"
|
|
428
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* Builds a mapping from base rule names to virtual rule names.
|
|
438
|
+
* Used by nodeRules/childNodeRules to propagate settings (especially `false`)
|
|
439
|
+
* to virtual rules created by NamedRuleGroups.
|
|
440
|
+
*/
|
|
441
|
+
function buildBaseRuleToVirtualNames(
|
|
442
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
443
|
+
virtualRules) {
|
|
444
|
+
const map = new Map();
|
|
445
|
+
for (const vRule of virtualRules) {
|
|
446
|
+
if (!vRule.baseRuleId) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
const list = map.get(vRule.baseRuleId);
|
|
450
|
+
if (list) {
|
|
451
|
+
list.push(vRule.name);
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
map.set(vRule.baseRuleId, [vRule.name]);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return map;
|
|
458
|
+
}
|
|
429
459
|
/**
|
|
430
460
|
* Collects all `FixData` from violations that have a fix callback result.
|
|
431
461
|
*
|
|
@@ -14,20 +14,18 @@ export function getAccname(
|
|
|
14
14
|
el, version) {
|
|
15
15
|
// AccName computation involves DOM traversal, role resolution, and label
|
|
16
16
|
// lookup via querySelector. These may fail on unexpected DOM states (e.g.,
|
|
17
|
-
// detached nodes, malformed attributes)
|
|
17
|
+
// detached nodes, malformed attributes), incomplete spec data, or runtime
|
|
18
|
+
// environment differences (e.g., Deno lacking certain DOM APIs).
|
|
18
19
|
// A single element's failure must not abort the entire linting process,
|
|
19
|
-
// so we catch
|
|
20
|
-
//
|
|
21
|
-
//
|
|
20
|
+
// so we catch all errors and return an empty name (= "unnamed").
|
|
21
|
+
// This is an intentional exception to the Tier 1 re-throw policy — see
|
|
22
|
+
// docs/architectures/ERROR-HANDLING.md § "accname computation errors".
|
|
22
23
|
try {
|
|
23
24
|
const resolver = createMLCoreResolver(el, version);
|
|
24
25
|
const result = computeAccessibleName(el, resolver);
|
|
25
26
|
return result.name;
|
|
26
27
|
}
|
|
27
28
|
catch (error) {
|
|
28
|
-
if (error instanceof TypeError || error instanceof ReferenceError) {
|
|
29
|
-
throw error;
|
|
30
|
-
}
|
|
31
29
|
accnameLog('Raw: %s', el.raw);
|
|
32
30
|
accnameLog('Error: %O', error);
|
|
33
31
|
return '';
|
package/lib/ml-dom/node/attr.js
CHANGED
|
@@ -3,7 +3,7 @@ import { searchIDLAttribute } from '@markuplint/parser-utils';
|
|
|
3
3
|
import { MLToken } from '../token/token.js';
|
|
4
4
|
import { MLDomTokenList } from './dom-token-list.js';
|
|
5
5
|
import { MLNode } from './node.js';
|
|
6
|
-
import { UnexpectedCallError } from '
|
|
6
|
+
import { UnexpectedCallError } from '@markuplint/shared';
|
|
7
7
|
/**
|
|
8
8
|
* Represents a DOM Attr (attribute) node wrapper in the markuplint DOM tree.
|
|
9
9
|
* Wraps an AST attribute token and provides access to the attribute's name, value,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { after, before, nextElementSibling, previousElementSibling, remove, replaceWith, } from '../manipulations/child-node-methods.js';
|
|
2
2
|
import { MLNode } from './node.js';
|
|
3
|
-
import { UnexpectedCallError } from '
|
|
3
|
+
import { UnexpectedCallError } from '@markuplint/shared';
|
|
4
4
|
export class MLCharacterData extends MLNode {
|
|
5
5
|
/**
|
|
6
6
|
* @implements DOM API: `CharacterData`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MLParentNode } from './parent-node.js';
|
|
2
|
-
import { UnexpectedCallError } from '
|
|
2
|
+
import { UnexpectedCallError } from '@markuplint/shared';
|
|
3
3
|
/**
|
|
4
4
|
* Represents a DOM DocumentFragment node wrapper in the markuplint DOM tree.
|
|
5
5
|
* Used for JSX fragments and similar constructs where a set of nodes
|
|
@@ -10,7 +10,7 @@ import type { Ruleset } from '../../ruleset/index.js';
|
|
|
10
10
|
import type { MLSchema } from '../../types.js';
|
|
11
11
|
import type { Walker } from '../helper/walkers.js';
|
|
12
12
|
import type { MLToken } from '../token/token.js';
|
|
13
|
-
import type { EndTagType, MLASTDocument } from '@markuplint/ml-ast';
|
|
13
|
+
import type { EndTagType, MLASTDocument, MLASTNodeTreeItem } from '@markuplint/ml-ast';
|
|
14
14
|
import type { PlainData, Pretender, RuleCommonSettings, RuleConfigValue } from '@markuplint/ml-config';
|
|
15
15
|
import type { ARIAVersion, MLMLSpec } from '@markuplint/ml-spec';
|
|
16
16
|
import { MLParentNode } from './parent-node.js';
|
|
@@ -93,6 +93,13 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
|
|
|
93
93
|
readonly tagNameCaseSensitive?: boolean;
|
|
94
94
|
readonly pretenders?: readonly Pretender[];
|
|
95
95
|
});
|
|
96
|
+
/**
|
|
97
|
+
* Looks up an AST node by its UUID from the parsed document's node list.
|
|
98
|
+
*
|
|
99
|
+
* @param uuid - The UUID of the AST node to find
|
|
100
|
+
* @returns The AST node, or `undefined` if not found
|
|
101
|
+
*/
|
|
102
|
+
getAstNodeByUuid(uuid: string): MLASTNodeTreeItem | undefined;
|
|
96
103
|
/**
|
|
97
104
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
98
105
|
*
|
|
@@ -107,6 +114,14 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
|
|
|
107
114
|
* @implements DOM API: `Document`
|
|
108
115
|
*/
|
|
109
116
|
get activeElement(): Element | null;
|
|
117
|
+
/**
|
|
118
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
119
|
+
*
|
|
120
|
+
* @deprecated
|
|
121
|
+
* @unsupported
|
|
122
|
+
* @implements DOM API: `Document`
|
|
123
|
+
*/
|
|
124
|
+
get activeViewTransition(): ViewTransition | null;
|
|
110
125
|
/**
|
|
111
126
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
112
127
|
*
|
|
@@ -204,6 +219,14 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
|
|
|
204
219
|
* @implements DOM API: `Document`
|
|
205
220
|
*/
|
|
206
221
|
get currentScript(): HTMLOrSVGScriptElement | null;
|
|
222
|
+
/**
|
|
223
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
224
|
+
*
|
|
225
|
+
* @deprecated
|
|
226
|
+
* @unsupported
|
|
227
|
+
* @implements DOM API: `Document`
|
|
228
|
+
*/
|
|
229
|
+
get customElementRegistry(): CustomElementRegistry | null;
|
|
207
230
|
/**
|
|
208
231
|
* Window object for calling the `getComputedStyle` and the `getPropertyValue` that
|
|
209
232
|
* are needed by **Accessible Name and Description Computation**.
|
|
@@ -519,6 +542,14 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
|
|
|
519
542
|
* @implements DOM API: `Document`
|
|
520
543
|
*/
|
|
521
544
|
get onclose(): ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
545
|
+
/**
|
|
546
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
547
|
+
*
|
|
548
|
+
* @deprecated
|
|
549
|
+
* @unsupported
|
|
550
|
+
* @implements DOM API: `Document`
|
|
551
|
+
*/
|
|
552
|
+
get oncommand(): ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
522
553
|
/**
|
|
523
554
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
524
555
|
*
|
|
@@ -9,7 +9,7 @@ import { sequentialWalker, syncWalk } from '../helper/walkers.js';
|
|
|
9
9
|
import { nodeListToHTMLCollection } from './node-list.js';
|
|
10
10
|
import { MLParentNode } from './parent-node.js';
|
|
11
11
|
import { RuleMapper } from './rule-mapper.js';
|
|
12
|
-
import { UnexpectedCallError } from '
|
|
12
|
+
import { UnexpectedCallError } from '@markuplint/shared';
|
|
13
13
|
const log = coreLog.extend('ml-dom');
|
|
14
14
|
const docLog = log.extend('document');
|
|
15
15
|
const ruleLog = docLog.extend('rule');
|
|
@@ -51,6 +51,7 @@ export class MLDocument extends MLParentNode {
|
|
|
51
51
|
/**
|
|
52
52
|
* The file path of the source document, if available.
|
|
53
53
|
*/
|
|
54
|
+
#astNodeMap;
|
|
54
55
|
#filename;
|
|
55
56
|
/**
|
|
56
57
|
* Whether this document represents a fragment rather than a complete document.
|
|
@@ -98,6 +99,8 @@ export class MLDocument extends MLParentNode {
|
|
|
98
99
|
this.#filename = options?.filename;
|
|
99
100
|
this.tagNameCaseSensitive = options?.tagNameCaseSensitive ?? false;
|
|
100
101
|
this.ruleCommonSettings = ruleCommonSettings;
|
|
102
|
+
// Build UUID → AST node map for cross-reference lookups (e.g., pairNodeUuid)
|
|
103
|
+
this.#astNodeMap = new Map(ast.nodeList.map(n => [n.uuid, n]));
|
|
101
104
|
// console.log(ast.nodeList.map((n, i) => `${i}: ${n.uuid} "${n.raw.trim()}"(${n.type})`));
|
|
102
105
|
this.nodeList = Object.freeze(ast.nodeList
|
|
103
106
|
.map(astNode => {
|
|
@@ -120,6 +123,15 @@ export class MLDocument extends MLParentNode {
|
|
|
120
123
|
throw error;
|
|
121
124
|
}
|
|
122
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Looks up an AST node by its UUID from the parsed document's node list.
|
|
128
|
+
*
|
|
129
|
+
* @param uuid - The UUID of the AST node to find
|
|
130
|
+
* @returns The AST node, or `undefined` if not found
|
|
131
|
+
*/
|
|
132
|
+
getAstNodeByUuid(uuid) {
|
|
133
|
+
return this.#astNodeMap.get(uuid);
|
|
134
|
+
}
|
|
123
135
|
/**
|
|
124
136
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
125
137
|
*
|
|
@@ -138,6 +150,16 @@ export class MLDocument extends MLParentNode {
|
|
|
138
150
|
get activeElement() {
|
|
139
151
|
throw new UnexpectedCallError('Not supported "activeElement" property');
|
|
140
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
155
|
+
*
|
|
156
|
+
* @deprecated
|
|
157
|
+
* @unsupported
|
|
158
|
+
* @implements DOM API: `Document`
|
|
159
|
+
*/
|
|
160
|
+
get activeViewTransition() {
|
|
161
|
+
throw new UnexpectedCallError('Not supported "activeViewTransition" property');
|
|
162
|
+
}
|
|
141
163
|
/**
|
|
142
164
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
143
165
|
*
|
|
@@ -261,6 +283,16 @@ export class MLDocument extends MLParentNode {
|
|
|
261
283
|
get currentScript() {
|
|
262
284
|
throw new UnexpectedCallError('Not supported "currentScript" property');
|
|
263
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
288
|
+
*
|
|
289
|
+
* @deprecated
|
|
290
|
+
* @unsupported
|
|
291
|
+
* @implements DOM API: `Document`
|
|
292
|
+
*/
|
|
293
|
+
get customElementRegistry() {
|
|
294
|
+
throw new UnexpectedCallError('Not supported "customElementRegistry" property');
|
|
295
|
+
}
|
|
264
296
|
/**
|
|
265
297
|
* Window object for calling the `getComputedStyle` and the `getPropertyValue` that
|
|
266
298
|
* are needed by **Accessible Name and Description Computation**.
|
|
@@ -677,6 +709,16 @@ export class MLDocument extends MLParentNode {
|
|
|
677
709
|
get onclose() {
|
|
678
710
|
throw new UnexpectedCallError('Not supported "onclose" property');
|
|
679
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
714
|
+
*
|
|
715
|
+
* @deprecated
|
|
716
|
+
* @unsupported
|
|
717
|
+
* @implements DOM API: `Document`
|
|
718
|
+
*/
|
|
719
|
+
get oncommand() {
|
|
720
|
+
throw new UnexpectedCallError('Not supported "oncommand" property');
|
|
721
|
+
}
|
|
680
722
|
/**
|
|
681
723
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
682
724
|
*
|
|
@@ -2357,6 +2399,24 @@ export class MLDocument extends MLParentNode {
|
|
|
2357
2399
|
if (rule == null) {
|
|
2358
2400
|
continue;
|
|
2359
2401
|
}
|
|
2402
|
+
// Namespace wildcard (e.g., "a11y/*": false)
|
|
2403
|
+
if (ruleName.endsWith('/*')) {
|
|
2404
|
+
if (rule !== false) {
|
|
2405
|
+
ruleset.mappingErrors.push(new Error(`Namespace wildcard "${ruleName}" only accepts false; use a specific rule name for options`));
|
|
2406
|
+
continue;
|
|
2407
|
+
}
|
|
2408
|
+
const nsPrefix = ruleName.slice(0, -1); // "a11y/*" → "a11y/"
|
|
2409
|
+
for (const key of Object.keys(ruleset.rules)) {
|
|
2410
|
+
if (key.startsWith(nsPrefix)) {
|
|
2411
|
+
ruleMapper.set(node, key, {
|
|
2412
|
+
from: 'nodeRules',
|
|
2413
|
+
specificity: matches.specificity,
|
|
2414
|
+
rule: false,
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
continue;
|
|
2419
|
+
}
|
|
2360
2420
|
const convertedRule = exchangeValueOnRule(rule, matches.data ?? {});
|
|
2361
2421
|
if (convertedRule === undefined) {
|
|
2362
2422
|
continue;
|
|
@@ -2369,6 +2429,19 @@ export class MLDocument extends MLParentNode {
|
|
|
2369
2429
|
specificity: matches.specificity,
|
|
2370
2430
|
rule: mergedRule,
|
|
2371
2431
|
});
|
|
2432
|
+
// Propagate to virtual rules that wrap this base rule
|
|
2433
|
+
const virtualNames = ruleset.baseRuleToVirtualNames.get(ruleName);
|
|
2434
|
+
if (virtualNames) {
|
|
2435
|
+
for (const vName of virtualNames) {
|
|
2436
|
+
const vGlobalRule = ruleset.rules[vName];
|
|
2437
|
+
const vMergedRule = vGlobalRule == null ? convertedRule : mergeRule(vGlobalRule, convertedRule);
|
|
2438
|
+
ruleMapper.set(node, vName, {
|
|
2439
|
+
from: 'nodeRules',
|
|
2440
|
+
specificity: matches.specificity,
|
|
2441
|
+
rule: vMergedRule,
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2372
2445
|
}
|
|
2373
2446
|
}
|
|
2374
2447
|
// overwrite rule to child node
|
|
@@ -2400,6 +2473,26 @@ export class MLDocument extends MLParentNode {
|
|
|
2400
2473
|
if (rule == null) {
|
|
2401
2474
|
continue;
|
|
2402
2475
|
}
|
|
2476
|
+
// Namespace wildcard (e.g., "a11y/*": false)
|
|
2477
|
+
if (ruleName.endsWith('/*')) {
|
|
2478
|
+
if (rule !== false) {
|
|
2479
|
+
ruleset.mappingErrors.push(new Error(`Namespace wildcard "${ruleName}" only accepts false; use a specific rule name for options`));
|
|
2480
|
+
continue;
|
|
2481
|
+
}
|
|
2482
|
+
const nsPrefix = ruleName.slice(0, -1); // "a11y/*" → "a11y/"
|
|
2483
|
+
for (const key of Object.keys(ruleset.rules)) {
|
|
2484
|
+
if (key.startsWith(nsPrefix)) {
|
|
2485
|
+
for (const descendant of targetDescendants) {
|
|
2486
|
+
ruleMapper.set(descendant, key, {
|
|
2487
|
+
from: 'childNodeRules',
|
|
2488
|
+
specificity: matches.specificity,
|
|
2489
|
+
rule: false,
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2403
2496
|
const convertedRule = exchangeValueOnRule(rule, matches.data ?? {});
|
|
2404
2497
|
if (convertedRule === undefined) {
|
|
2405
2498
|
continue;
|
|
@@ -2414,6 +2507,21 @@ export class MLDocument extends MLParentNode {
|
|
|
2414
2507
|
rule: mergedRule,
|
|
2415
2508
|
});
|
|
2416
2509
|
}
|
|
2510
|
+
// Propagate to virtual rules that wrap this base rule
|
|
2511
|
+
const virtualNames = ruleset.baseRuleToVirtualNames.get(ruleName);
|
|
2512
|
+
if (virtualNames) {
|
|
2513
|
+
for (const vName of virtualNames) {
|
|
2514
|
+
const vGlobalRule = ruleset.rules[vName];
|
|
2515
|
+
const vMergedRule = vGlobalRule == null ? convertedRule : mergeRule(vGlobalRule, convertedRule);
|
|
2516
|
+
for (const descendant of targetDescendants) {
|
|
2517
|
+
ruleMapper.set(descendant, vName, {
|
|
2518
|
+
from: 'childNodeRules',
|
|
2519
|
+
specificity: matches.specificity,
|
|
2520
|
+
rule: vMergedRule,
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2417
2525
|
}
|
|
2418
2526
|
}
|
|
2419
2527
|
}
|
|
@@ -185,7 +185,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
185
185
|
* @unsupported
|
|
186
186
|
* @implements DOM API: `Element`
|
|
187
187
|
*/
|
|
188
|
-
get ariaControlsElements(): readonly MLElement<T, O>[];
|
|
188
|
+
get ariaControlsElements(): readonly MLElement<T, O>[] | null;
|
|
189
189
|
/**
|
|
190
190
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
191
191
|
*
|
|
@@ -201,7 +201,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
201
201
|
* @unsupported
|
|
202
202
|
* @implements DOM API: `Element`
|
|
203
203
|
*/
|
|
204
|
-
get ariaDescribedByElements(): readonly MLElement<T, O>[];
|
|
204
|
+
get ariaDescribedByElements(): readonly MLElement<T, O>[] | null;
|
|
205
205
|
/**
|
|
206
206
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
207
207
|
*
|
|
@@ -217,7 +217,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
217
217
|
* @unsupported
|
|
218
218
|
* @implements DOM API: `Element`
|
|
219
219
|
*/
|
|
220
|
-
get ariaDetailsElements(): readonly MLElement<T, O>[];
|
|
220
|
+
get ariaDetailsElements(): readonly MLElement<T, O>[] | null;
|
|
221
221
|
/**
|
|
222
222
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
223
223
|
*
|
|
@@ -233,7 +233,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
233
233
|
* @unsupported
|
|
234
234
|
* @implements DOM API: `Element`
|
|
235
235
|
*/
|
|
236
|
-
get ariaErrorMessageElements(): readonly MLElement<T, O>[];
|
|
236
|
+
get ariaErrorMessageElements(): readonly MLElement<T, O>[] | null;
|
|
237
237
|
/**
|
|
238
238
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
239
239
|
*
|
|
@@ -249,7 +249,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
249
249
|
* @unsupported
|
|
250
250
|
* @implements DOM API: `Element`
|
|
251
251
|
*/
|
|
252
|
-
get ariaFlowToElements(): readonly MLElement<T, O>[];
|
|
252
|
+
get ariaFlowToElements(): readonly MLElement<T, O>[] | null;
|
|
253
253
|
/**
|
|
254
254
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
255
255
|
*
|
|
@@ -297,7 +297,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
297
297
|
* @unsupported
|
|
298
298
|
* @implements DOM API: `Element`
|
|
299
299
|
*/
|
|
300
|
-
get ariaLabelledByElements(): readonly MLElement<T, O>[];
|
|
300
|
+
get ariaLabelledByElements(): readonly MLElement<T, O>[] | null;
|
|
301
301
|
/**
|
|
302
302
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
303
303
|
*
|
|
@@ -353,7 +353,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
353
353
|
* @unsupported
|
|
354
354
|
* @implements DOM API: `Element`
|
|
355
355
|
*/
|
|
356
|
-
get ariaOwnsElements(): readonly MLElement<T, O>[];
|
|
356
|
+
get ariaOwnsElements(): readonly MLElement<T, O>[] | null;
|
|
357
357
|
/**
|
|
358
358
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
359
359
|
*
|
|
@@ -600,6 +600,14 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
600
600
|
* @implements DOM API: `Element`
|
|
601
601
|
*/
|
|
602
602
|
get currentCSSZoom(): number;
|
|
603
|
+
/**
|
|
604
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
605
|
+
*
|
|
606
|
+
* @deprecated
|
|
607
|
+
* @unsupported
|
|
608
|
+
* @implements DOM API: `Element`
|
|
609
|
+
*/
|
|
610
|
+
get customElementRegistry(): CustomElementRegistry | null;
|
|
603
611
|
/**
|
|
604
612
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
605
613
|
*
|
|
@@ -739,7 +747,7 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
739
747
|
* @unsupported
|
|
740
748
|
* @implements DOM API: `Element`
|
|
741
749
|
*/
|
|
742
|
-
get nonce(): string
|
|
750
|
+
get nonce(): string;
|
|
743
751
|
/**
|
|
744
752
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
745
753
|
*
|
|
@@ -908,6 +916,14 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
908
916
|
* @implements DOM API: `Element`
|
|
909
917
|
*/
|
|
910
918
|
get onclose(): ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
919
|
+
/**
|
|
920
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
921
|
+
*
|
|
922
|
+
* @deprecated
|
|
923
|
+
* @unsupported
|
|
924
|
+
* @implements DOM API: `Element`
|
|
925
|
+
*/
|
|
926
|
+
get oncommand(): ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
911
927
|
/**
|
|
912
928
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
913
929
|
*
|
|
@@ -2065,7 +2081,10 @@ export declare class MLElement<T extends RuleConfigValue, O extends PlainData =
|
|
|
2065
2081
|
* @implements DOM API: `Element`
|
|
2066
2082
|
* @see https://dom.spec.whatwg.org/#ref-for-dom-element-matches%E2%91%A0
|
|
2067
2083
|
*/
|
|
2068
|
-
matches
|
|
2084
|
+
matches<K extends keyof HTMLElementTagNameMap>(selectors: K): this is HTMLElementTagNameMap[K];
|
|
2085
|
+
matches<K extends keyof SVGElementTagNameMap>(selectors: K): this is SVGElementTagNameMap[K];
|
|
2086
|
+
matches<K extends keyof MathMLElementTagNameMap>(selectors: K): this is MathMLElementTagNameMap[K];
|
|
2087
|
+
matches(selectors: string, scope?: MLParentNode<T, O>): boolean;
|
|
2069
2088
|
/**
|
|
2070
2089
|
* Matches this element against a CSS selector or regex selector pattern,
|
|
2071
2090
|
* returning detailed match results. When the element is a pretender,
|
|
@@ -9,7 +9,7 @@ import { MLElementCloseTag } from './element-close-tag.js';
|
|
|
9
9
|
import { toNamedNodeMap } from './named-node-map.js';
|
|
10
10
|
import { toHTMLCollection, toNodeList } from './node-list.js';
|
|
11
11
|
import { MLParentNode } from './parent-node.js';
|
|
12
|
-
import { UnexpectedCallError } from '
|
|
12
|
+
import { UnexpectedCallError } from '@markuplint/shared';
|
|
13
13
|
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
14
14
|
/**
|
|
15
15
|
* Represents a DOM Element node wrapper in the markuplint DOM tree.
|
|
@@ -116,7 +116,10 @@ export class MLElement extends MLParentNode {
|
|
|
116
116
|
document) {
|
|
117
117
|
super(astNode, document, astNode.isFragment);
|
|
118
118
|
this.#attributes = astNode.attributes.map(attr => new MLAttr(attr, this));
|
|
119
|
-
|
|
119
|
+
const pairAstNode = astNode.pairNodeUuid
|
|
120
|
+
? document.getAstNodeByUuid(astNode.pairNodeUuid)
|
|
121
|
+
: null;
|
|
122
|
+
this.closeTag = pairAstNode ? new MLElementCloseTag(pairAstNode, document, this) : null;
|
|
120
123
|
const ns = resolveNamespace(astNode.nodeName, astNode.namespace);
|
|
121
124
|
this.namespaceURI = astNode.namespace;
|
|
122
125
|
this.elementType = astNode.elementType;
|
|
@@ -808,6 +811,16 @@ export class MLElement extends MLParentNode {
|
|
|
808
811
|
get currentCSSZoom() {
|
|
809
812
|
throw new UnexpectedCallError('Not supported "currentCSSZoom" property');
|
|
810
813
|
}
|
|
814
|
+
/**
|
|
815
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
816
|
+
*
|
|
817
|
+
* @deprecated
|
|
818
|
+
* @unsupported
|
|
819
|
+
* @implements DOM API: `Element`
|
|
820
|
+
*/
|
|
821
|
+
get customElementRegistry() {
|
|
822
|
+
throw new UnexpectedCallError('Not supported "customElementRegistry" property');
|
|
823
|
+
}
|
|
811
824
|
/**
|
|
812
825
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
813
826
|
*
|
|
@@ -1209,6 +1222,16 @@ export class MLElement extends MLParentNode {
|
|
|
1209
1222
|
get onclose() {
|
|
1210
1223
|
throw new UnexpectedCallError('Not supported "onclose" property');
|
|
1211
1224
|
}
|
|
1225
|
+
/**
|
|
1226
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
1227
|
+
*
|
|
1228
|
+
* @deprecated
|
|
1229
|
+
* @unsupported
|
|
1230
|
+
* @implements DOM API: `Element`
|
|
1231
|
+
*/
|
|
1232
|
+
get oncommand() {
|
|
1233
|
+
throw new UnexpectedCallError('Not supported "oncommand" property');
|
|
1234
|
+
}
|
|
1212
1235
|
/**
|
|
1213
1236
|
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
1214
1237
|
*
|
|
@@ -2783,10 +2806,6 @@ export class MLElement extends MLParentNode {
|
|
|
2783
2806
|
}
|
|
2784
2807
|
return true;
|
|
2785
2808
|
}
|
|
2786
|
-
/**
|
|
2787
|
-
* @implements DOM API: `Element`
|
|
2788
|
-
* @see https://dom.spec.whatwg.org/#ref-for-dom-element-matches%E2%91%A0
|
|
2789
|
-
*/
|
|
2790
2809
|
matches(selector,
|
|
2791
2810
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2792
2811
|
scope) {
|
|
@@ -5,6 +5,7 @@ import type { PlainData, RuleConfigValue } from '@markuplint/ml-config';
|
|
|
5
5
|
declare class NodeStore {
|
|
6
6
|
#private;
|
|
7
7
|
getNode<N extends MLASTNode, T extends RuleConfigValue, O extends PlainData = undefined>(astNode: N): MappedNode<N, T, O>;
|
|
8
|
+
getNodeByUuid<T extends RuleConfigValue, O extends PlainData = undefined>(uuid: string): MLNode<T, O, any>;
|
|
8
9
|
setNode<A extends MLASTNode, T extends RuleConfigValue, O extends PlainData = undefined>(astNode: A, node: MLNode<T, O, A>): void;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
@@ -22,6 +22,16 @@ class NodeStore {
|
|
|
22
22
|
}
|
|
23
23
|
return node;
|
|
24
24
|
}
|
|
25
|
+
getNodeByUuid(uuid) {
|
|
26
|
+
const node = this.#store.get(uuid);
|
|
27
|
+
if (!node) {
|
|
28
|
+
nodeStoreError('Ref UUID: %s', uuid);
|
|
29
|
+
throw new TargetParserError('Broke mapping nodes.', {
|
|
30
|
+
raw: `uuid:${uuid}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return node;
|
|
34
|
+
}
|
|
25
35
|
setNode(astNode,
|
|
26
36
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
27
37
|
node) {
|
|
@@ -441,6 +441,13 @@ export declare abstract class MLNode<T extends RuleConfigValue, O extends PlainD
|
|
|
441
441
|
* @see https://dom.spec.whatwg.org/#dom-node-insertbefore
|
|
442
442
|
*/
|
|
443
443
|
insertBefore<T extends Node>(node: T, child: Node | null): T;
|
|
444
|
+
/**
|
|
445
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
446
|
+
*
|
|
447
|
+
* @unsupported
|
|
448
|
+
* @implements DOM API: `Node`
|
|
449
|
+
*/
|
|
450
|
+
moveBefore(node: Node, child: Node | null): Node;
|
|
444
451
|
/**
|
|
445
452
|
* @implements `@markuplint/ml-core` API: `MLNode`
|
|
446
453
|
*/
|
package/lib/ml-dom/node/node.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { branchesToPatterns } from '@markuplint/shared';
|
|
1
|
+
import { branchesToPatterns, UnexpectedCallError } from '@markuplint/shared';
|
|
2
2
|
import { MLToken } from '../token/token.js';
|
|
3
3
|
import { isChildNode } from './child-node.js';
|
|
4
4
|
import { toNodeList } from './node-list.js';
|
|
5
5
|
import { nodeStore } from './node-store.js';
|
|
6
|
-
import { UnexpectedCallError } from './unexpected-call-error.js';
|
|
7
6
|
/**
|
|
8
7
|
* Abstract base class for all markuplint DOM node wrappers.
|
|
9
8
|
* Extends `MLToken` with DOM `Node` interface compliance, tree traversal,
|
|
@@ -481,10 +480,10 @@ export class MLNode extends MLToken {
|
|
|
481
480
|
if (this._astToken.type === 'attr' || this._astToken.type === 'spread') {
|
|
482
481
|
return null;
|
|
483
482
|
}
|
|
484
|
-
if (!this._astToken.
|
|
483
|
+
if (!this._astToken.parentNodeUuid) {
|
|
485
484
|
return this.ownerMLDocument;
|
|
486
485
|
}
|
|
487
|
-
return nodeStore.
|
|
486
|
+
return nodeStore.getNodeByUuid(this._astToken.parentNodeUuid);
|
|
488
487
|
}
|
|
489
488
|
/**
|
|
490
489
|
* Return the text content.
|
|
@@ -753,6 +752,19 @@ export class MLNode extends MLToken {
|
|
|
753
752
|
child) {
|
|
754
753
|
throw new UnexpectedCallError('Not supported "insertBefore" method');
|
|
755
754
|
}
|
|
755
|
+
/**
|
|
756
|
+
* **IT THROWS AN ERROR WHEN CALLING THIS.**
|
|
757
|
+
*
|
|
758
|
+
* @unsupported
|
|
759
|
+
* @implements DOM API: `Node`
|
|
760
|
+
*/
|
|
761
|
+
moveBefore(
|
|
762
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
763
|
+
node,
|
|
764
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
765
|
+
child) {
|
|
766
|
+
throw new UnexpectedCallError('Not supported "moveBefore" method');
|
|
767
|
+
}
|
|
756
768
|
/**
|
|
757
769
|
* @implements `@markuplint/ml-core` API: `MLNode`
|
|
758
770
|
*/
|
|
@@ -2,7 +2,7 @@ import { syncWalk } from '../helper/walkers.js';
|
|
|
2
2
|
import { getChildren } from '../manipulations/get-children.js';
|
|
3
3
|
import { toNodeList } from './node-list.js';
|
|
4
4
|
import { MLNode } from './node.js';
|
|
5
|
-
import { UnexpectedCallError } from '
|
|
5
|
+
import { UnexpectedCallError } from '@markuplint/shared';
|
|
6
6
|
/**
|
|
7
7
|
*
|
|
8
8
|
* @see https://dom.spec.whatwg.org/#interface-parentnode
|
package/lib/ml-dom/node/text.js
CHANGED
package/lib/ruleset/index.d.ts
CHANGED
|
@@ -4,14 +4,26 @@ import type { ChildNodeRule, Config, NodeRule, Rules } from '@markuplint/ml-conf
|
|
|
4
4
|
* rule overrides extracted from a markuplint {@link Config}.
|
|
5
5
|
*/
|
|
6
6
|
export declare class Ruleset {
|
|
7
|
+
/**
|
|
8
|
+
* Maps base rule names to their virtual rule names created by NamedRuleGroups.
|
|
9
|
+
* For example, if `a11y/wai-aria` wraps `wai-aria`, this maps `"wai-aria"` → `["a11y/wai-aria"]`.
|
|
10
|
+
* Used by nodeRules/childNodeRules to propagate settings to virtual rules.
|
|
11
|
+
*/
|
|
12
|
+
readonly baseRuleToVirtualNames: ReadonlyMap<string, readonly string[]>;
|
|
7
13
|
/** Rule overrides that apply to child nodes matching specific selectors */
|
|
8
14
|
readonly childNodeRules: readonly ChildNodeRule[];
|
|
15
|
+
/**
|
|
16
|
+
* Errors collected during rule mapping (e.g., invalid wildcard usage).
|
|
17
|
+
* Consumed by MLCore and reported as config-error violations.
|
|
18
|
+
*/
|
|
19
|
+
readonly mappingErrors: Error[];
|
|
9
20
|
/** Rule overrides that apply to nodes matching specific selectors */
|
|
10
21
|
readonly nodeRules: readonly NodeRule[];
|
|
11
22
|
/** The global rule definitions */
|
|
12
23
|
readonly rules: Rules;
|
|
13
24
|
/**
|
|
14
25
|
* @param config - The markuplint configuration to extract rules from
|
|
26
|
+
* @param baseRuleToVirtualNames - Mapping from base rule names to virtual rule names
|
|
15
27
|
*/
|
|
16
|
-
constructor(config: Config);
|
|
28
|
+
constructor(config: Config, baseRuleToVirtualNames?: ReadonlyMap<string, readonly string[]>);
|
|
17
29
|
}
|
package/lib/ruleset/index.js
CHANGED
|
@@ -3,18 +3,31 @@
|
|
|
3
3
|
* rule overrides extracted from a markuplint {@link Config}.
|
|
4
4
|
*/
|
|
5
5
|
export class Ruleset {
|
|
6
|
+
/**
|
|
7
|
+
* Maps base rule names to their virtual rule names created by NamedRuleGroups.
|
|
8
|
+
* For example, if `a11y/wai-aria` wraps `wai-aria`, this maps `"wai-aria"` → `["a11y/wai-aria"]`.
|
|
9
|
+
* Used by nodeRules/childNodeRules to propagate settings to virtual rules.
|
|
10
|
+
*/
|
|
11
|
+
baseRuleToVirtualNames;
|
|
6
12
|
/** Rule overrides that apply to child nodes matching specific selectors */
|
|
7
13
|
childNodeRules;
|
|
14
|
+
/**
|
|
15
|
+
* Errors collected during rule mapping (e.g., invalid wildcard usage).
|
|
16
|
+
* Consumed by MLCore and reported as config-error violations.
|
|
17
|
+
*/
|
|
18
|
+
mappingErrors = [];
|
|
8
19
|
/** Rule overrides that apply to nodes matching specific selectors */
|
|
9
20
|
nodeRules;
|
|
10
21
|
/** The global rule definitions */
|
|
11
22
|
rules;
|
|
12
23
|
/**
|
|
13
24
|
* @param config - The markuplint configuration to extract rules from
|
|
25
|
+
* @param baseRuleToVirtualNames - Mapping from base rule names to virtual rule names
|
|
14
26
|
*/
|
|
15
|
-
constructor(config) {
|
|
27
|
+
constructor(config, baseRuleToVirtualNames) {
|
|
16
28
|
this.rules = config.rules ?? {};
|
|
17
29
|
this.nodeRules = config.nodeRules ?? [];
|
|
18
30
|
this.childNodeRules = config.childNodeRules ?? [];
|
|
31
|
+
this.baseRuleToVirtualNames = baseRuleToVirtualNames ?? new Map();
|
|
19
32
|
}
|
|
20
33
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/ml-core",
|
|
3
|
-
"version": "5.0.0-rc.
|
|
3
|
+
"version": "5.0.0-rc.2",
|
|
4
4
|
"description": "The core module of markuplint",
|
|
5
|
-
"repository":
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/markuplint/markuplint.git",
|
|
8
|
+
"directory": "packages/@markuplint/ml-core"
|
|
9
|
+
},
|
|
6
10
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"engines": {
|
|
@@ -30,20 +34,20 @@
|
|
|
30
34
|
"./lib/configs.js": "./lib/configs.browser.js"
|
|
31
35
|
},
|
|
32
36
|
"dependencies": {
|
|
33
|
-
"@markuplint/config-presets": "5.0.0-rc.
|
|
34
|
-
"@markuplint/html-parser": "5.0.0-rc.
|
|
35
|
-
"@markuplint/html-spec": "5.0.0-rc.
|
|
36
|
-
"@markuplint/i18n": "5.0.0-rc.
|
|
37
|
-
"@markuplint/ml-ast": "5.0.0-rc.
|
|
38
|
-
"@markuplint/ml-config": "5.0.0-rc.
|
|
39
|
-
"@markuplint/ml-spec": "5.0.0-rc.
|
|
40
|
-
"@markuplint/parser-utils": "5.0.0-rc.
|
|
41
|
-
"@markuplint/selector": "5.0.0-rc.
|
|
42
|
-
"@markuplint/shared": "5.0.0-rc.
|
|
43
|
-
"@types/debug": "4.1.
|
|
37
|
+
"@markuplint/config-presets": "5.0.0-rc.2",
|
|
38
|
+
"@markuplint/html-parser": "5.0.0-rc.2",
|
|
39
|
+
"@markuplint/html-spec": "5.0.0-rc.2",
|
|
40
|
+
"@markuplint/i18n": "5.0.0-rc.2",
|
|
41
|
+
"@markuplint/ml-ast": "5.0.0-rc.2",
|
|
42
|
+
"@markuplint/ml-config": "5.0.0-rc.2",
|
|
43
|
+
"@markuplint/ml-spec": "5.0.0-rc.2",
|
|
44
|
+
"@markuplint/parser-utils": "5.0.0-rc.2",
|
|
45
|
+
"@markuplint/selector": "5.0.0-rc.2",
|
|
46
|
+
"@markuplint/shared": "5.0.0-rc.2",
|
|
47
|
+
"@types/debug": "4.1.13",
|
|
44
48
|
"debug": "4.4.3",
|
|
45
49
|
"is-plain-object": "5.0.0",
|
|
46
|
-
"type-fest": "5.
|
|
50
|
+
"type-fest": "5.5.0"
|
|
47
51
|
},
|
|
48
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "e43763858d9234c417053becc73dbd088c1e7ea6"
|
|
49
53
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { MLNode } from '../node/node.js';
|
|
2
|
-
import type { MLText } from '../node/text.js';
|
|
3
|
-
/**
|
|
4
|
-
* Computes the indentation preceding the given node by analyzing
|
|
5
|
-
* the whitespace in adjacent text nodes.
|
|
6
|
-
*
|
|
7
|
-
* @deprecated
|
|
8
|
-
* @param node - The node whose indentation to determine
|
|
9
|
-
* @returns An indentation object describing the whitespace, or null if no indentation is found
|
|
10
|
-
*/
|
|
11
|
-
export declare function getIndent(node: MLNode<any, any>): MLDOMIndentation | null;
|
|
12
|
-
declare class MLDOMIndentation {
|
|
13
|
-
#private;
|
|
14
|
-
readonly line: number;
|
|
15
|
-
constructor(originTextNode: MLText<any, any>, raw: string, line: number, parentNode: MLNode<any, any>);
|
|
16
|
-
get raw(): string;
|
|
17
|
-
get type(): 'tab' | 'space' | 'mixed' | 'none';
|
|
18
|
-
get width(): number;
|
|
19
|
-
}
|
|
20
|
-
export {};
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Computes the indentation preceding the given node by analyzing
|
|
3
|
-
* the whitespace in adjacent text nodes.
|
|
4
|
-
*
|
|
5
|
-
* @deprecated
|
|
6
|
-
* @param node - The node whose indentation to determine
|
|
7
|
-
* @returns An indentation object describing the whitespace, or null if no indentation is found
|
|
8
|
-
*/
|
|
9
|
-
export function getIndent(
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
11
|
-
node) {
|
|
12
|
-
const prevToken = node.prevToken;
|
|
13
|
-
if (!prevToken) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
if (node.is(node.TEXT_NODE)) {
|
|
17
|
-
if (node.isRawTextElementContent()) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
const matched = node.raw.match(/^([\t\v\f\r \u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*\n\s*)\S+/);
|
|
21
|
-
if (matched) {
|
|
22
|
-
const spaces = matched[1];
|
|
23
|
-
if (spaces) {
|
|
24
|
-
const spaceLines = spaces.split(/\r?\n/);
|
|
25
|
-
const line = spaceLines.length + node.startLine - 1;
|
|
26
|
-
const lastSpace = spaceLines.pop();
|
|
27
|
-
if (lastSpace != null) {
|
|
28
|
-
return new MLDOMIndentation(node, lastSpace, line, node);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
if (!prevToken.is(node.TEXT_NODE)) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
// One or more newlines and zero or more spaces or tabs.
|
|
38
|
-
// Or, If textNode is first token and that is filled spaces, tabs and newlines only.
|
|
39
|
-
const matched = isFirstToken(prevToken)
|
|
40
|
-
? prevToken.raw.match(/^(?:[\t ]*\r?\n)*([\t ]*)$/)
|
|
41
|
-
: prevToken.raw.match(/\r?\n([\t ]*)$/);
|
|
42
|
-
if (matched) {
|
|
43
|
-
// Spaces will include empty string.
|
|
44
|
-
const spaces = matched[1];
|
|
45
|
-
if (spaces != null) {
|
|
46
|
-
return new MLDOMIndentation(prevToken, spaces, node.startLine, node);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
class MLDOMIndentation {
|
|
52
|
-
#raw;
|
|
53
|
-
line;
|
|
54
|
-
#node;
|
|
55
|
-
#parent;
|
|
56
|
-
constructor(
|
|
57
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
58
|
-
originTextNode, raw, line,
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
60
|
-
parentNode) {
|
|
61
|
-
this.line = line;
|
|
62
|
-
this.#node = originTextNode;
|
|
63
|
-
this.#parent = parentNode;
|
|
64
|
-
this.#raw = raw;
|
|
65
|
-
}
|
|
66
|
-
get raw() {
|
|
67
|
-
if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
|
|
68
|
-
return '';
|
|
69
|
-
}
|
|
70
|
-
return this.#raw;
|
|
71
|
-
}
|
|
72
|
-
get type() {
|
|
73
|
-
if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
|
|
74
|
-
return 'none';
|
|
75
|
-
}
|
|
76
|
-
const raw = this.#raw;
|
|
77
|
-
return raw === '' ? 'none' : /^\t+$/.test(raw) ? 'tab' : /^[^\t]+$/.test(raw) ? 'space' : 'mixed';
|
|
78
|
-
}
|
|
79
|
-
get width() {
|
|
80
|
-
if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
|
|
81
|
-
return 0;
|
|
82
|
-
}
|
|
83
|
-
return this.#raw.length;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function isFirstToken(
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
88
|
-
node) {
|
|
89
|
-
return !node.prevToken;
|
|
90
|
-
}
|