@markuplint/rules 3.0.0-dev.25 → 3.0.0-dev.300
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/lib/attr-check.d.ts +3 -2
- package/lib/attr-check.js +42 -38
- package/lib/attr-duplication/index.d.ts +1 -1
- package/lib/attr-duplication/index.js +3 -5
- package/lib/attr-value-quotes/index.d.ts +1 -1
- package/lib/attr-value-quotes/index.js +5 -9
- package/lib/case-sensitive-attr-name/index.d.ts +1 -1
- package/lib/case-sensitive-attr-name/index.js +9 -13
- package/lib/case-sensitive-tag-name/index.d.ts +1 -1
- package/lib/case-sensitive-tag-name/index.js +2 -4
- package/lib/character-reference/index.d.ts +1 -1
- package/lib/character-reference/index.js +7 -9
- package/lib/class-naming/index.d.ts +1 -1
- package/lib/class-naming/index.js +9 -13
- package/lib/create-message.d.ts +3 -2
- package/lib/create-message.js +15 -17
- package/lib/debug.js +2 -6
- package/lib/deprecated-attr/index.d.ts +1 -1
- package/lib/deprecated-attr/index.js +6 -9
- package/lib/deprecated-element/index.d.ts +1 -1
- package/lib/deprecated-element/index.js +5 -7
- package/lib/disallowed-element/index.d.ts +1 -1
- package/lib/disallowed-element/index.js +2 -4
- package/lib/doctype/index.d.ts +1 -1
- package/lib/doctype/index.js +2 -4
- package/lib/end-tag/index.d.ts +1 -1
- package/lib/end-tag/index.js +5 -8
- package/lib/helpers.d.ts +10 -13
- package/lib/helpers.js +39 -37
- package/lib/id-duplication/index.d.ts +1 -1
- package/lib/id-duplication/index.js +2 -4
- package/lib/index.d.ts +102 -3
- package/lib/index.js +64 -62
- package/lib/ineffective-attr/index.d.ts +1 -1
- package/lib/ineffective-attr/index.js +5 -10
- package/lib/invalid-attr/index.d.ts +25 -5
- package/lib/invalid-attr/index.js +166 -43
- package/lib/label-has-control/index.d.ts +1 -1
- package/lib/label-has-control/index.js +2 -4
- package/lib/landmark-roles/index.d.ts +1 -1
- package/lib/landmark-roles/index.js +10 -9
- package/lib/no-boolean-attr-value/index.d.ts +1 -1
- package/lib/no-boolean-attr-value/index.js +6 -9
- package/lib/no-default-value/index.d.ts +1 -1
- package/lib/no-default-value/index.js +9 -12
- package/lib/no-empty-palpable-content/index.d.ts +1 -1
- package/lib/no-empty-palpable-content/index.js +13 -7
- package/lib/no-hard-code-id/index.d.ts +1 -1
- package/lib/no-hard-code-id/index.js +2 -4
- package/lib/no-refer-to-non-existent-id/index.d.ts +4 -4
- package/lib/no-refer-to-non-existent-id/index.js +79 -23
- package/lib/no-use-event-handler-attr/index.d.ts +1 -1
- package/lib/no-use-event-handler-attr/index.js +4 -6
- package/lib/permitted-contents/choice.d.ts +3 -2
- package/lib/permitted-contents/choice.js +54 -14
- package/lib/permitted-contents/complex-branch.d.ts +3 -2
- package/lib/permitted-contents/complex-branch.js +12 -14
- package/lib/permitted-contents/content-model.d.ts +2 -2
- package/lib/permitted-contents/content-model.js +11 -11
- package/lib/permitted-contents/count-pattern.d.ts +3 -2
- package/lib/permitted-contents/count-pattern.js +76 -74
- package/lib/permitted-contents/debug.browser.js +9 -12
- package/lib/permitted-contents/debug.d.ts +8 -1
- package/lib/permitted-contents/debug.js +12 -13
- package/lib/permitted-contents/index.d.ts +2 -2
- package/lib/permitted-contents/index.js +18 -24
- package/lib/permitted-contents/matches-selector.d.ts +2 -2
- package/lib/permitted-contents/matches-selector.js +17 -20
- package/lib/permitted-contents/order.d.ts +3 -2
- package/lib/permitted-contents/order.js +33 -28
- package/lib/permitted-contents/recursive-branch.d.ts +4 -3
- package/lib/permitted-contents/recursive-branch.js +11 -13
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +1 -1
- package/lib/permitted-contents/represent-transparent-nodes.js +18 -21
- package/lib/permitted-contents/start.d.ts +3 -2
- package/lib/permitted-contents/start.js +16 -22
- package/lib/permitted-contents/transparent.d.ts +2 -2
- package/lib/permitted-contents/transparent.js +6 -9
- package/lib/permitted-contents/types.d.ts +20 -13
- package/lib/permitted-contents/types.js +1 -2
- package/lib/permitted-contents/utils.d.ts +27 -8
- package/lib/permitted-contents/utils.js +164 -65
- package/lib/placeholder-label-option/index.d.ts +2 -0
- package/lib/placeholder-label-option/index.js +84 -0
- package/lib/require-accessible-name/index.d.ts +1 -1
- package/lib/require-accessible-name/index.js +10 -13
- package/lib/require-datetime/index.d.ts +6 -0
- package/lib/require-datetime/index.js +32 -0
- package/lib/require-datetime/types.d.ts +10 -0
- package/lib/require-datetime/types.js +1 -0
- package/lib/require-datetime/utils.d.ts +11 -0
- package/lib/require-datetime/utils.js +130 -0
- package/lib/required-attr/index.d.ts +2 -2
- package/lib/required-attr/index.js +24 -24
- package/lib/required-element/index.d.ts +1 -1
- package/lib/required-element/index.js +3 -5
- package/lib/required-h1/index.d.ts +1 -1
- package/lib/required-h1/index.js +4 -6
- package/lib/use-list/index.d.ts +2 -2
- package/lib/use-list/index.js +7 -9
- package/lib/wai-aria/checkings/abstract-role.d.ts +1 -1
- package/lib/wai-aria/checkings/abstract-role.js +5 -10
- package/lib/wai-aria/checkings/default-value.d.ts +2 -2
- package/lib/wai-aria/checkings/default-value.js +2 -6
- package/lib/wai-aria/checkings/deprecated-props.d.ts +2 -2
- package/lib/wai-aria/checkings/deprecated-props.js +3 -8
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +2 -2
- package/lib/wai-aria/checkings/disallowed-prop.js +27 -8
- package/lib/wai-aria/checkings/implicit-props.d.ts +3 -3
- package/lib/wai-aria/checkings/implicit-props.js +7 -11
- package/lib/wai-aria/checkings/implicit-role.d.ts +1 -1
- package/lib/wai-aria/checkings/implicit-role.js +4 -9
- package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +1 -1
- package/lib/wai-aria/checkings/interaction-in-hidden.js +7 -9
- package/lib/wai-aria/checkings/no-global-prop.d.ts +2 -2
- package/lib/wai-aria/checkings/no-global-prop.js +2 -7
- package/lib/wai-aria/checkings/non-existent-role.d.ts +1 -1
- package/lib/wai-aria/checkings/non-existent-role.js +4 -9
- package/lib/wai-aria/checkings/permitted-roles.d.ts +1 -1
- package/lib/wai-aria/checkings/permitted-roles.js +4 -9
- package/lib/wai-aria/checkings/presentational-children.d.ts +1 -1
- package/lib/wai-aria/checkings/presentational-children.js +7 -10
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +1 -1
- package/lib/wai-aria/checkings/required-owned-elements.js +10 -12
- package/lib/wai-aria/checkings/required-prop.d.ts +2 -2
- package/lib/wai-aria/checkings/required-prop.js +2 -7
- package/lib/wai-aria/checkings/value.d.ts +3 -3
- package/lib/wai-aria/checkings/value.js +7 -11
- package/lib/wai-aria/index.d.ts +2 -2
- package/lib/wai-aria/index.js +38 -39
- package/lib/wai-aria/types.js +1 -2
- package/package.json +21 -14
- package/schema.json +6 -0
- package/tsconfig.test.json +0 -3
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,14 +1,15 @@
|
|
|
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
|
+
import type { ReadonlyDeep } from 'type-fest';
|
|
3
4
|
export type Element = _Element<TagRule[], Options>;
|
|
4
5
|
export type ChildNode = _ChildNode<TagRule[], Options>;
|
|
5
6
|
export type Specs = {
|
|
6
|
-
cites: MLMLSpec['cites'];
|
|
7
|
-
def: MLMLSpec['def'];
|
|
8
|
-
specs: {
|
|
9
|
-
name: string;
|
|
10
|
-
contentModel: {
|
|
11
|
-
contents: MLMLSpec['specs'][0]['contentModel']['contents'];
|
|
7
|
+
readonly cites: MLMLSpec['cites'];
|
|
8
|
+
readonly def: MLMLSpec['def'];
|
|
9
|
+
readonly specs: readonly {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly contentModel: {
|
|
12
|
+
readonly contents: MLMLSpec['specs'][0]['contentModel']['contents'];
|
|
12
13
|
};
|
|
13
14
|
}[];
|
|
14
15
|
};
|
|
@@ -24,22 +25,28 @@ export type Result<T extends string = MatchedReason> = {
|
|
|
24
25
|
unmatched: ChildNode[];
|
|
25
26
|
zeroMatch: boolean;
|
|
26
27
|
query: string;
|
|
27
|
-
hint:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
hint: Hints;
|
|
29
|
+
};
|
|
30
|
+
export type Hints = {
|
|
31
|
+
max?: number;
|
|
32
|
+
not?: ChildNode;
|
|
33
|
+
transparent?: Element;
|
|
34
|
+
missing?: {
|
|
35
|
+
barelyMatchedElements?: number;
|
|
36
|
+
need?: string;
|
|
31
37
|
};
|
|
32
38
|
};
|
|
33
39
|
export type MatchedReason = 'MATCHED' | 'MATCHED_ZERO';
|
|
34
40
|
export type UnmatchedReason = 'NOTHING' | 'UNEXPECTED_EXTRA_NODE' | 'TRANSPARENT_MODEL_DISALLOWS' | MissingNodeReason;
|
|
35
41
|
export type MissingNodeReason = 'MISSING_NODE_REQUIRED' | 'MISSING_NODE_ONE_OR_MORE';
|
|
42
|
+
export type RepeatSign = '' | '?' | '+' | '*' | `{${number},${number}}`;
|
|
36
43
|
export type TransparentModel = {
|
|
37
44
|
el: Element;
|
|
38
45
|
additionalCondition: string;
|
|
39
46
|
};
|
|
40
47
|
export type TagRule = {
|
|
41
|
-
tag: string;
|
|
42
|
-
} & ContentModel
|
|
48
|
+
readonly tag: string;
|
|
49
|
+
} & ReadonlyDeep<ContentModel>;
|
|
43
50
|
export type Options = {
|
|
44
|
-
ignoreHasMutableChildren: boolean;
|
|
51
|
+
readonly ignoreHasMutableChildren: boolean;
|
|
45
52
|
};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { ChildNode, Element, Specs } from './types';
|
|
1
|
+
import type { ChildNode, Element, Hints, MissingNodeReason, RepeatSign, Specs } from './types.js';
|
|
2
2
|
import type { PermittedContentPattern, PermittedContentChoice, PermittedContentOneOrMore, PermittedContentOptional, PermittedContentRequire, PermittedContentTransparent, PermittedContentZeroOrMore, Model } from '@markuplint/ml-spec';
|
|
3
|
+
import type { ReadonlyDeep } from 'type-fest';
|
|
3
4
|
export declare function getChildNodesWithoutWhitespaces(el: Element): ChildNode[];
|
|
4
|
-
export declare function isModel(model: Model | PermittedContentPattern[]): model is Model
|
|
5
|
+
export declare function isModel(model: ReadonlyDeep<Model | PermittedContentPattern[]>): model is ReadonlyDeep<Model>;
|
|
5
6
|
export declare function matches(selector: string, node: ChildNode, specs: Specs): {
|
|
6
7
|
matched: boolean;
|
|
7
8
|
not?: undefined;
|
|
@@ -9,12 +10,29 @@ export declare function matches(selector: string, node: ChildNode, specs: Specs)
|
|
|
9
10
|
matched: boolean;
|
|
10
11
|
not: ChildNode | undefined;
|
|
11
12
|
};
|
|
12
|
-
export declare function isRequire(content: PermittedContentPattern): content is PermittedContentRequire
|
|
13
|
-
export declare function isOptional(content: PermittedContentPattern): content is PermittedContentOptional
|
|
14
|
-
export declare function isOneOrMore(content: PermittedContentPattern): content is PermittedContentOneOrMore
|
|
15
|
-
export declare function isZeroOrMore(content: PermittedContentPattern): content is PermittedContentZeroOrMore
|
|
16
|
-
export declare function isChoice(content: PermittedContentPattern): content is PermittedContentChoice
|
|
17
|
-
export declare function isTransparent(content: PermittedContentPattern): content is PermittedContentTransparent
|
|
13
|
+
export declare function isRequire(content: ReadonlyDeep<PermittedContentPattern>): content is ReadonlyDeep<PermittedContentRequire>;
|
|
14
|
+
export declare function isOptional(content: ReadonlyDeep<PermittedContentPattern>): content is ReadonlyDeep<PermittedContentOptional>;
|
|
15
|
+
export declare function isOneOrMore(content: ReadonlyDeep<PermittedContentPattern>): content is ReadonlyDeep<PermittedContentOneOrMore>;
|
|
16
|
+
export declare function isZeroOrMore(content: ReadonlyDeep<PermittedContentPattern>): content is ReadonlyDeep<PermittedContentZeroOrMore>;
|
|
17
|
+
export declare function isChoice(content: ReadonlyDeep<PermittedContentPattern>): content is ReadonlyDeep<PermittedContentChoice>;
|
|
18
|
+
export declare function isTransparent(content: ReadonlyDeep<PermittedContentPattern>): content is ReadonlyDeep<PermittedContentTransparent>;
|
|
19
|
+
export declare function normalizeModel(pattern: ReadonlyDeep<PermittedContentRequire> | ReadonlyDeep<PermittedContentOptional> | ReadonlyDeep<PermittedContentOneOrMore> | ReadonlyDeep<PermittedContentZeroOrMore>): {
|
|
20
|
+
model: ReadonlyDeep<PermittedContentPattern[] | Model>;
|
|
21
|
+
min: number;
|
|
22
|
+
max: number;
|
|
23
|
+
repeat: RepeatSign;
|
|
24
|
+
missingType: MissingNodeReason | undefined;
|
|
25
|
+
};
|
|
26
|
+
export declare function mergeHints(a: Readonly<Hints>, b: Readonly<Hints>): Partial<{
|
|
27
|
+
missing: Partial<{
|
|
28
|
+
barelyMatchedElements?: number | undefined;
|
|
29
|
+
need?: string | undefined;
|
|
30
|
+
}> | undefined;
|
|
31
|
+
max?: number | undefined;
|
|
32
|
+
not?: ChildNode | undefined;
|
|
33
|
+
transparent?: Element | undefined;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function cleanObject<T extends Object>(object: T): Partial<T>;
|
|
18
36
|
export declare class Collection {
|
|
19
37
|
#private;
|
|
20
38
|
constructor(origin: readonly ChildNode[]);
|
|
@@ -30,3 +48,4 @@ export declare class Collection {
|
|
|
30
48
|
}
|
|
31
49
|
export declare class UnsupportedError extends Error {
|
|
32
50
|
}
|
|
51
|
+
export declare function modelLog(model: ReadonlyDeep<Model | PermittedContentPattern[]>, repeat: RepeatSign): string;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var _Collection_locked, _Collection_matched, _Collection_nodes, _Collection_origin;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const debug_1 = require("./debug");
|
|
8
|
-
const represent_transparent_nodes_1 = require("./represent-transparent-nodes");
|
|
2
|
+
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
3
|
+
import { createSelector } from '@markuplint/selector';
|
|
4
|
+
import { bgGreen, green, bgRed, bgBlue, blue, bgMagenta, cyan } from './debug.js';
|
|
5
|
+
import { transparentMode } from './represent-transparent-nodes.js';
|
|
9
6
|
const getChildNodesWithoutWhitespacesCaches = new Map();
|
|
10
|
-
function getChildNodesWithoutWhitespaces(
|
|
7
|
+
export function getChildNodesWithoutWhitespaces(
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
9
|
+
el) {
|
|
11
10
|
let nodes = getChildNodesWithoutWhitespacesCaches.get(el);
|
|
12
11
|
if (nodes) {
|
|
13
12
|
return nodes;
|
|
@@ -18,8 +17,7 @@ function getChildNodesWithoutWhitespaces(el) {
|
|
|
18
17
|
getChildNodesWithoutWhitespacesCaches.set(el, nodes);
|
|
19
18
|
return nodes;
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
function isModel(model) {
|
|
20
|
+
export function isModel(model) {
|
|
23
21
|
if (typeof model === 'string') {
|
|
24
22
|
return true;
|
|
25
23
|
}
|
|
@@ -35,17 +33,18 @@ function isModel(model) {
|
|
|
35
33
|
}
|
|
36
34
|
return modelMode;
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
export function matches(selector,
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
38
|
+
node, specs) {
|
|
39
|
+
const selectorResult = createSelector(selector, specs).search(node);
|
|
41
40
|
const matched = selectorResult.filter((r) => r.matched);
|
|
42
|
-
if (matched.length) {
|
|
41
|
+
if (matched.length > 0) {
|
|
43
42
|
return {
|
|
44
43
|
matched: true,
|
|
45
44
|
};
|
|
46
45
|
}
|
|
47
46
|
const not = selectorResult
|
|
48
|
-
.map(r =>
|
|
47
|
+
.map(r => (r.matched ? [] : r.not ?? []))
|
|
49
48
|
.flat()
|
|
50
49
|
.map(descendants)
|
|
51
50
|
.flat()
|
|
@@ -55,12 +54,13 @@ function matches(selector, node, specs) {
|
|
|
55
54
|
not,
|
|
56
55
|
};
|
|
57
56
|
}
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
function descendants(
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
59
|
+
selectorResult) {
|
|
60
60
|
let nodes = selectorResult.nodes.slice();
|
|
61
|
-
while (selectorResult.has.length) {
|
|
61
|
+
while (selectorResult.has.length > 0) {
|
|
62
62
|
for (const dep of selectorResult.has) {
|
|
63
|
-
if (
|
|
63
|
+
if (dep.has.length === 0) {
|
|
64
64
|
nodes = dep.nodes;
|
|
65
65
|
continue;
|
|
66
66
|
}
|
|
@@ -71,104 +71,177 @@ function descendants(selectorResult) {
|
|
|
71
71
|
}
|
|
72
72
|
return nodes;
|
|
73
73
|
}
|
|
74
|
-
function isRequire(content) {
|
|
74
|
+
export function isRequire(content) {
|
|
75
75
|
return 'require' in content;
|
|
76
76
|
}
|
|
77
|
-
|
|
78
|
-
function isOptional(content) {
|
|
77
|
+
export function isOptional(content) {
|
|
79
78
|
return 'optional' in content;
|
|
80
79
|
}
|
|
81
|
-
|
|
82
|
-
function isOneOrMore(content) {
|
|
80
|
+
export function isOneOrMore(content) {
|
|
83
81
|
return 'oneOrMore' in content;
|
|
84
82
|
}
|
|
85
|
-
|
|
86
|
-
function isZeroOrMore(content) {
|
|
83
|
+
export function isZeroOrMore(content) {
|
|
87
84
|
return 'zeroOrMore' in content;
|
|
88
85
|
}
|
|
89
|
-
|
|
90
|
-
function isChoice(content) {
|
|
86
|
+
export function isChoice(content) {
|
|
91
87
|
return 'choice' in content;
|
|
92
88
|
}
|
|
93
|
-
|
|
94
|
-
function isTransparent(content) {
|
|
89
|
+
export function isTransparent(content) {
|
|
95
90
|
return 'transparent' in content;
|
|
96
91
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
export function normalizeModel(pattern) {
|
|
93
|
+
let model;
|
|
94
|
+
let min;
|
|
95
|
+
let max;
|
|
96
|
+
let repeat;
|
|
97
|
+
let missingType;
|
|
98
|
+
if (isRequire(pattern)) {
|
|
99
|
+
model = pattern.require;
|
|
100
|
+
min = pattern.min ?? 1;
|
|
101
|
+
max = Math.max(pattern.max ?? 1, min);
|
|
102
|
+
missingType = 'MISSING_NODE_REQUIRED';
|
|
103
|
+
}
|
|
104
|
+
else if (isOptional(pattern)) {
|
|
105
|
+
model = pattern.optional;
|
|
106
|
+
min = 0;
|
|
107
|
+
max = Math.max(pattern.max ?? 1, 1);
|
|
108
|
+
}
|
|
109
|
+
else if (isOneOrMore(pattern)) {
|
|
110
|
+
model = pattern.oneOrMore;
|
|
111
|
+
min = 1;
|
|
112
|
+
max = Math.max(pattern.max ?? Infinity, 1);
|
|
113
|
+
missingType = 'MISSING_NODE_ONE_OR_MORE';
|
|
114
|
+
}
|
|
115
|
+
else if (isZeroOrMore(pattern)) {
|
|
116
|
+
model = pattern.zeroOrMore;
|
|
117
|
+
min = 0;
|
|
118
|
+
max = Math.max(pattern.max ?? Infinity, 1);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
throw new Error('Unreachable code');
|
|
122
|
+
}
|
|
123
|
+
if (min === 0 && max === 1) {
|
|
124
|
+
repeat = '?';
|
|
125
|
+
}
|
|
126
|
+
else if (min === 0 && !Number.isFinite(max)) {
|
|
127
|
+
repeat = '*';
|
|
128
|
+
}
|
|
129
|
+
else if (min === 1 && max === 1) {
|
|
130
|
+
repeat = '';
|
|
131
|
+
}
|
|
132
|
+
else if (min === 1 && !Number.isFinite(max)) {
|
|
133
|
+
repeat = '+';
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
repeat = `{${min},${max}}`;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
model,
|
|
140
|
+
min,
|
|
141
|
+
max,
|
|
142
|
+
repeat,
|
|
143
|
+
missingType,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export function mergeHints(
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
148
|
+
a,
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
150
|
+
b) {
|
|
151
|
+
const missing = [a.missing, b.missing].sort((a, b) => (b?.barelyMatchedElements ?? 0) - (a?.barelyMatchedElements ?? 0))[0];
|
|
152
|
+
return cleanObject({
|
|
153
|
+
...a,
|
|
154
|
+
...b,
|
|
155
|
+
missing: missing && cleanObject(missing),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
export function cleanObject(object) {
|
|
159
|
+
const newObject = {};
|
|
160
|
+
Object.entries(object).forEach(([key, value]) => {
|
|
161
|
+
if (value !== undefined) {
|
|
162
|
+
newObject[key] = value;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return newObject;
|
|
166
|
+
}
|
|
167
|
+
export class Collection {
|
|
168
|
+
constructor(
|
|
169
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
170
|
+
origin) {
|
|
100
171
|
_Collection_locked.set(this, new Set());
|
|
101
172
|
_Collection_matched.set(this, new Set());
|
|
102
173
|
_Collection_nodes.set(this, void 0);
|
|
103
174
|
_Collection_origin.set(this, void 0);
|
|
104
|
-
|
|
105
|
-
|
|
175
|
+
__classPrivateFieldSet(this, _Collection_origin, origin.slice(), "f");
|
|
176
|
+
__classPrivateFieldSet(this, _Collection_nodes, new Set(__classPrivateFieldGet(this, _Collection_origin, "f")), "f");
|
|
106
177
|
}
|
|
107
178
|
get matched() {
|
|
108
|
-
return Array.from(
|
|
179
|
+
return Array.from(__classPrivateFieldGet(this, _Collection_matched, "f"));
|
|
109
180
|
}
|
|
110
181
|
get matchedCount() {
|
|
111
|
-
return
|
|
182
|
+
return __classPrivateFieldGet(this, _Collection_matched, "f").size;
|
|
112
183
|
}
|
|
113
184
|
get nodes() {
|
|
114
|
-
return
|
|
185
|
+
return __classPrivateFieldGet(this, _Collection_origin, "f").slice();
|
|
115
186
|
}
|
|
116
187
|
get unmatched() {
|
|
117
|
-
return Array.from(
|
|
188
|
+
return Array.from(__classPrivateFieldGet(this, _Collection_nodes, "f")).filter(n => !__classPrivateFieldGet(this, _Collection_matched, "f").has(n));
|
|
118
189
|
}
|
|
119
|
-
addMatched(
|
|
120
|
-
|
|
190
|
+
addMatched(
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
192
|
+
nodes) {
|
|
193
|
+
const i = __classPrivateFieldGet(this, _Collection_matched, "f").size;
|
|
121
194
|
for (const node of nodes) {
|
|
122
|
-
if (!
|
|
195
|
+
if (!__classPrivateFieldGet(this, _Collection_nodes, "f").has(node)) {
|
|
123
196
|
throw new ReferenceError(`External Node: ${node.nodeName}`);
|
|
124
197
|
}
|
|
125
|
-
|
|
198
|
+
__classPrivateFieldGet(this, _Collection_matched, "f").add(node);
|
|
126
199
|
}
|
|
127
|
-
return i <
|
|
200
|
+
return i < __classPrivateFieldGet(this, _Collection_matched, "f").size;
|
|
128
201
|
}
|
|
129
202
|
back() {
|
|
130
|
-
|
|
203
|
+
__classPrivateFieldSet(this, _Collection_matched, new Set(__classPrivateFieldGet(this, _Collection_locked, "f")), "f");
|
|
131
204
|
}
|
|
132
205
|
lock() {
|
|
133
|
-
|
|
206
|
+
__classPrivateFieldSet(this, _Collection_locked, new Set(__classPrivateFieldGet(this, _Collection_matched, "f")), "f");
|
|
134
207
|
}
|
|
135
208
|
max(max) {
|
|
136
|
-
const sliced = Array.from(
|
|
137
|
-
sliced.forEach(n =>
|
|
209
|
+
const sliced = Array.from(__classPrivateFieldGet(this, _Collection_matched, "f")).slice(max);
|
|
210
|
+
sliced.forEach(n => __classPrivateFieldGet(this, _Collection_matched, "f").delete(n));
|
|
138
211
|
}
|
|
139
212
|
toString(highlightExtraNodes = false) {
|
|
140
213
|
const out = [];
|
|
141
|
-
for (const n of
|
|
214
|
+
for (const n of __classPrivateFieldGet(this, _Collection_origin, "f")) {
|
|
142
215
|
const raw = n.is(n.TEXT_NODE) ? `:text(${n.raw.replace(/\n/g, '\\n')})` : n.raw;
|
|
143
|
-
if (
|
|
144
|
-
if (
|
|
145
|
-
out.push(
|
|
216
|
+
if (__classPrivateFieldGet(this, _Collection_locked, "f").has(n)) {
|
|
217
|
+
if (transparentMode.has(n)) {
|
|
218
|
+
out.push(bgBlue.bold(raw));
|
|
146
219
|
}
|
|
147
220
|
else {
|
|
148
|
-
out.push(
|
|
221
|
+
out.push(bgGreen.bold(raw));
|
|
149
222
|
}
|
|
150
223
|
continue;
|
|
151
224
|
}
|
|
152
|
-
if (
|
|
153
|
-
if (
|
|
154
|
-
out.push(
|
|
225
|
+
if (__classPrivateFieldGet(this, _Collection_matched, "f").has(n)) {
|
|
226
|
+
if (transparentMode.has(n)) {
|
|
227
|
+
out.push(blue.bold(raw));
|
|
155
228
|
}
|
|
156
229
|
else {
|
|
157
|
-
out.push(
|
|
230
|
+
out.push(green.bold(raw));
|
|
158
231
|
}
|
|
159
232
|
continue;
|
|
160
233
|
}
|
|
161
234
|
if (highlightExtraNodes) {
|
|
162
|
-
if (
|
|
163
|
-
out.push(
|
|
235
|
+
if (transparentMode.has(n)) {
|
|
236
|
+
out.push(bgMagenta.bold(raw));
|
|
164
237
|
}
|
|
165
238
|
else {
|
|
166
|
-
out.push(
|
|
239
|
+
out.push(bgRed.bold(raw));
|
|
167
240
|
}
|
|
168
241
|
continue;
|
|
169
242
|
}
|
|
170
|
-
if (
|
|
171
|
-
out.push(
|
|
243
|
+
if (transparentMode.has(n)) {
|
|
244
|
+
out.push(cyan(raw));
|
|
172
245
|
}
|
|
173
246
|
else {
|
|
174
247
|
out.push(raw);
|
|
@@ -177,8 +250,34 @@ class Collection {
|
|
|
177
250
|
return `[ ${out.join(', ')} ]`;
|
|
178
251
|
}
|
|
179
252
|
}
|
|
180
|
-
exports.Collection = Collection;
|
|
181
253
|
_Collection_locked = new WeakMap(), _Collection_matched = new WeakMap(), _Collection_nodes = new WeakMap(), _Collection_origin = new WeakMap();
|
|
182
|
-
class UnsupportedError extends Error {
|
|
254
|
+
export class UnsupportedError extends Error {
|
|
255
|
+
}
|
|
256
|
+
export function modelLog(model, repeat) {
|
|
257
|
+
if (!isModel(model)) {
|
|
258
|
+
return orderLog(model, repeat);
|
|
259
|
+
}
|
|
260
|
+
if (typeof model === 'string') {
|
|
261
|
+
return `<${model}>${repeat}`;
|
|
262
|
+
}
|
|
263
|
+
return `(<${model.join('>|<')}>)${repeat}`;
|
|
264
|
+
}
|
|
265
|
+
function orderLog(order, repeat) {
|
|
266
|
+
return order.length === 1 && order[0]
|
|
267
|
+
? markRepeat(patternLog(order[0]), repeat)
|
|
268
|
+
: markRepeat(order.map(pattern => patternLog(pattern)).join(''), repeat);
|
|
269
|
+
}
|
|
270
|
+
function patternLog(pattern) {
|
|
271
|
+
if (isTransparent(pattern)) {
|
|
272
|
+
// 適当
|
|
273
|
+
return `:transparent(${modelLog(pattern.transparent, '')})`;
|
|
274
|
+
}
|
|
275
|
+
if (isChoice(pattern)) {
|
|
276
|
+
return `(${pattern.choice.map(candidate => orderLog(candidate, '')).join('|')})`;
|
|
277
|
+
}
|
|
278
|
+
const { model, repeat } = normalizeModel(pattern);
|
|
279
|
+
return modelLog(model, repeat);
|
|
280
|
+
}
|
|
281
|
+
function markRepeat(pattern, repeat) {
|
|
282
|
+
return repeat ? `(${pattern})${repeat}` : pattern;
|
|
183
283
|
}
|
|
184
|
-
exports.UnsupportedError = UnsupportedError;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
3
|
+
verify({ document, report, t }) {
|
|
4
|
+
document.querySelectorAll('select').forEach(select => {
|
|
5
|
+
if (hasPlaceholderLabelOption(select)) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (!needPlaceholderLabelOption(select)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
report({
|
|
12
|
+
scope: select,
|
|
13
|
+
message: t('need {0}', t('the {0}', 'placeholder label option')),
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* > If a select element has a required attribute specified,
|
|
20
|
+
* > does not have a multiple attribute specified,
|
|
21
|
+
* > and has a display size of 1,
|
|
22
|
+
* > then the select element must have a placeholder label option.
|
|
23
|
+
*
|
|
24
|
+
* @param select
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
27
|
+
function needPlaceholderLabelOption(
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
29
|
+
select) {
|
|
30
|
+
const hasRequired = select.hasAttribute('required');
|
|
31
|
+
if (!hasRequired) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const hasMultiple = select.hasAttribute('multiple');
|
|
35
|
+
if (hasMultiple) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const size = select.getAttribute('size') ?? '1';
|
|
39
|
+
if (size !== '1') {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* > If a select element has a required attribute specified,
|
|
46
|
+
* > does not have a multiple attribute specified,
|
|
47
|
+
* > and has a display size of 1;
|
|
48
|
+
* > and if the value of the first option element
|
|
49
|
+
* > in the select element's list of options (if any) is the empty string,
|
|
50
|
+
* > and that option element's parent node is the select element (and not an optgroup element),
|
|
51
|
+
* > then that option is the select element's **placeholder label option**.
|
|
52
|
+
*
|
|
53
|
+
* @param select
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
function hasPlaceholderLabelOption(
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
58
|
+
select) {
|
|
59
|
+
// > has a required attribute specified
|
|
60
|
+
if (!select.hasAttribute('required')) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
// > does not have a multiple attribute specified
|
|
64
|
+
if (select.hasAttribute('multiple')) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
// > has a display size of 1
|
|
68
|
+
const size = select.getAttribute('size') ?? '1';
|
|
69
|
+
if (size !== '1') {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
// > in the select element's list of options (if any) is the empty string
|
|
73
|
+
const firstOption = select.querySelector('option');
|
|
74
|
+
if (!firstOption) {
|
|
75
|
+
// if any
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
// > that option element's parent node is the select element (and not an optgroup element)
|
|
79
|
+
if (firstOption.parentElement?.localName === 'optgroup') {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const value = firstOption.getAttribute('value');
|
|
83
|
+
return value === '' || value === null;
|
|
84
|
+
}
|
|
@@ -2,5 +2,5 @@ import type { ARIAVersion } from '@markuplint/ml-spec';
|
|
|
2
2
|
type Option = {
|
|
3
3
|
ariaVersion: ARIAVersion;
|
|
4
4
|
};
|
|
5
|
-
declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Option
|
|
5
|
+
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, Option>>;
|
|
6
6
|
export default _default;
|
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const helpers_1 = require("../helpers");
|
|
6
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule, getRoleSpec, getComputedRole } from '@markuplint/ml-core';
|
|
2
|
+
import { ARIA_RECOMMENDED_VERSION, isExposed } from '@markuplint/ml-spec';
|
|
3
|
+
import { accnameMayBeMutable } from '../helpers.js';
|
|
4
|
+
export default createRule({
|
|
7
5
|
defaultOptions: {
|
|
8
|
-
ariaVersion:
|
|
6
|
+
ariaVersion: ARIA_RECOMMENDED_VERSION,
|
|
9
7
|
},
|
|
10
8
|
async verify({ document, report, t }) {
|
|
11
9
|
await document.walkOn('Element', el => {
|
|
12
|
-
|
|
13
|
-
if (((_a = el.pretenderContext) === null || _a === void 0 ? void 0 : _a.type) === 'pretender') {
|
|
10
|
+
if (el.pretenderContext?.type === 'pretender') {
|
|
14
11
|
return;
|
|
15
12
|
}
|
|
16
|
-
if (
|
|
13
|
+
if (accnameMayBeMutable(el, document)) {
|
|
17
14
|
return;
|
|
18
15
|
}
|
|
19
|
-
if (!
|
|
16
|
+
if (!isExposed(el, document.specs, el.rule.options.ariaVersion)) {
|
|
20
17
|
return;
|
|
21
18
|
}
|
|
22
|
-
const computed =
|
|
19
|
+
const computed = getComputedRole(document.specs, el, el.rule.options.ariaVersion);
|
|
23
20
|
if (!computed.role) {
|
|
24
21
|
return;
|
|
25
22
|
}
|
|
26
|
-
const roleSpec =
|
|
23
|
+
const roleSpec = getRoleSpec(document.specs, computed.role.name, el.namespaceURI, el.rule.options.ariaVersion);
|
|
27
24
|
if (!roleSpec || !roleSpec.accessibleNameRequired) {
|
|
28
25
|
return;
|
|
29
26
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
import { check } from '@markuplint/types';
|
|
3
|
+
import { getCandidateDatetimeString } from './utils.js';
|
|
4
|
+
export default createRule({
|
|
5
|
+
defaultOptions: {
|
|
6
|
+
langs: undefined,
|
|
7
|
+
},
|
|
8
|
+
verify({ document, report, t }) {
|
|
9
|
+
document.querySelectorAll('time:not([datetime])').forEach(time => {
|
|
10
|
+
if (time.hasMutableChildren()) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const content = time.textContent.trim();
|
|
14
|
+
const result = check(content, 'DateTime');
|
|
15
|
+
if (result.matched) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const candidate = getCandidateDatetimeString(content, time.rule.options.langs);
|
|
19
|
+
if (candidate) {
|
|
20
|
+
report({
|
|
21
|
+
scope: time,
|
|
22
|
+
message: t('need {0*}', `datetime="${candidate}"`),
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
report({
|
|
27
|
+
scope: time,
|
|
28
|
+
message: t('need {0}', t('the "{0*}" {1}', 'datetime', 'attribute')),
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type DateTimeKey = 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'ms';
|
|
2
|
+
export type DateTimeData = Partial<Record<DateTimeKey, number>>;
|
|
3
|
+
export type DateTime = {
|
|
4
|
+
datetime: DateTimeData;
|
|
5
|
+
zone?: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* @see https://github.com/wanasit/chrono#locales
|
|
9
|
+
*/
|
|
10
|
+
export type Lang = 'en' | 'ja' | 'fr' | 'nl' | 'ru' | 'de' | 'pt' | 'zh';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DateTime, Lang } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Datetime-ish text to a datetime data
|
|
4
|
+
*
|
|
5
|
+
* @param content
|
|
6
|
+
* @param langs
|
|
7
|
+
* @param base Reference date for a test
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseADatetime(content: string, langs: readonly Lang[], base?: Readonly<Date>): DateTime | null;
|
|
11
|
+
export declare function getCandidateDatetimeString(content: string, langs?: Lang[]): string | null;
|