@markuplint/rules 3.0.0-dev.24 → 3.0.0-dev.290

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/lib/attr-check.d.ts +3 -2
  2. package/lib/attr-check.js +42 -38
  3. package/lib/attr-duplication/index.d.ts +1 -1
  4. package/lib/attr-duplication/index.js +3 -5
  5. package/lib/attr-value-quotes/index.d.ts +1 -1
  6. package/lib/attr-value-quotes/index.js +5 -9
  7. package/lib/case-sensitive-attr-name/index.d.ts +1 -1
  8. package/lib/case-sensitive-attr-name/index.js +9 -13
  9. package/lib/case-sensitive-tag-name/index.d.ts +1 -1
  10. package/lib/case-sensitive-tag-name/index.js +2 -4
  11. package/lib/character-reference/index.d.ts +1 -1
  12. package/lib/character-reference/index.js +7 -9
  13. package/lib/class-naming/index.d.ts +1 -1
  14. package/lib/class-naming/index.js +9 -13
  15. package/lib/create-message.d.ts +3 -2
  16. package/lib/create-message.js +15 -17
  17. package/lib/debug.js +2 -6
  18. package/lib/deprecated-attr/index.d.ts +1 -1
  19. package/lib/deprecated-attr/index.js +6 -9
  20. package/lib/deprecated-element/index.d.ts +1 -1
  21. package/lib/deprecated-element/index.js +5 -7
  22. package/lib/disallowed-element/index.d.ts +1 -1
  23. package/lib/disallowed-element/index.js +2 -4
  24. package/lib/doctype/index.d.ts +1 -1
  25. package/lib/doctype/index.js +2 -4
  26. package/lib/end-tag/index.d.ts +1 -1
  27. package/lib/end-tag/index.js +5 -8
  28. package/lib/helpers.d.ts +10 -13
  29. package/lib/helpers.js +39 -37
  30. package/lib/id-duplication/index.d.ts +1 -1
  31. package/lib/id-duplication/index.js +2 -4
  32. package/lib/index.d.ts +102 -3
  33. package/lib/index.js +64 -62
  34. package/lib/ineffective-attr/index.d.ts +1 -1
  35. package/lib/ineffective-attr/index.js +5 -10
  36. package/lib/invalid-attr/index.d.ts +25 -5
  37. package/lib/invalid-attr/index.js +166 -43
  38. package/lib/label-has-control/index.d.ts +1 -1
  39. package/lib/label-has-control/index.js +2 -4
  40. package/lib/landmark-roles/index.d.ts +1 -1
  41. package/lib/landmark-roles/index.js +10 -9
  42. package/lib/no-boolean-attr-value/index.d.ts +1 -1
  43. package/lib/no-boolean-attr-value/index.js +6 -9
  44. package/lib/no-default-value/index.d.ts +1 -1
  45. package/lib/no-default-value/index.js +9 -12
  46. package/lib/no-empty-palpable-content/index.d.ts +1 -1
  47. package/lib/no-empty-palpable-content/index.js +13 -7
  48. package/lib/no-hard-code-id/index.d.ts +1 -1
  49. package/lib/no-hard-code-id/index.js +2 -4
  50. package/lib/no-refer-to-non-existent-id/index.d.ts +4 -4
  51. package/lib/no-refer-to-non-existent-id/index.js +79 -23
  52. package/lib/no-use-event-handler-attr/index.d.ts +1 -1
  53. package/lib/no-use-event-handler-attr/index.js +4 -6
  54. package/lib/permitted-contents/choice.d.ts +3 -2
  55. package/lib/permitted-contents/choice.js +54 -14
  56. package/lib/permitted-contents/complex-branch.d.ts +3 -2
  57. package/lib/permitted-contents/complex-branch.js +12 -14
  58. package/lib/permitted-contents/content-model.d.ts +2 -2
  59. package/lib/permitted-contents/content-model.js +11 -11
  60. package/lib/permitted-contents/count-pattern.d.ts +3 -2
  61. package/lib/permitted-contents/count-pattern.js +76 -74
  62. package/lib/permitted-contents/debug.browser.js +9 -12
  63. package/lib/permitted-contents/debug.d.ts +8 -1
  64. package/lib/permitted-contents/debug.js +12 -13
  65. package/lib/permitted-contents/index.d.ts +2 -2
  66. package/lib/permitted-contents/index.js +18 -24
  67. package/lib/permitted-contents/matches-selector.d.ts +2 -2
  68. package/lib/permitted-contents/matches-selector.js +17 -20
  69. package/lib/permitted-contents/order.d.ts +3 -2
  70. package/lib/permitted-contents/order.js +33 -28
  71. package/lib/permitted-contents/recursive-branch.d.ts +4 -3
  72. package/lib/permitted-contents/recursive-branch.js +11 -13
  73. package/lib/permitted-contents/represent-transparent-nodes.d.ts +1 -1
  74. package/lib/permitted-contents/represent-transparent-nodes.js +18 -21
  75. package/lib/permitted-contents/start.d.ts +3 -2
  76. package/lib/permitted-contents/start.js +16 -22
  77. package/lib/permitted-contents/transparent.d.ts +2 -2
  78. package/lib/permitted-contents/transparent.js +6 -9
  79. package/lib/permitted-contents/types.d.ts +20 -13
  80. package/lib/permitted-contents/types.js +1 -2
  81. package/lib/permitted-contents/utils.d.ts +27 -8
  82. package/lib/permitted-contents/utils.js +164 -65
  83. package/lib/placeholder-label-option/index.d.ts +2 -0
  84. package/lib/placeholder-label-option/index.js +84 -0
  85. package/lib/require-accessible-name/index.d.ts +1 -1
  86. package/lib/require-accessible-name/index.js +10 -13
  87. package/lib/require-datetime/index.d.ts +6 -0
  88. package/lib/require-datetime/index.js +32 -0
  89. package/lib/require-datetime/types.d.ts +10 -0
  90. package/lib/require-datetime/types.js +1 -0
  91. package/lib/require-datetime/utils.d.ts +11 -0
  92. package/lib/require-datetime/utils.js +130 -0
  93. package/lib/required-attr/index.d.ts +2 -2
  94. package/lib/required-attr/index.js +24 -24
  95. package/lib/required-element/index.d.ts +1 -1
  96. package/lib/required-element/index.js +3 -5
  97. package/lib/required-h1/index.d.ts +1 -1
  98. package/lib/required-h1/index.js +4 -6
  99. package/lib/use-list/index.d.ts +2 -2
  100. package/lib/use-list/index.js +7 -9
  101. package/lib/wai-aria/checkings/abstract-role.d.ts +1 -1
  102. package/lib/wai-aria/checkings/abstract-role.js +5 -10
  103. package/lib/wai-aria/checkings/default-value.d.ts +2 -2
  104. package/lib/wai-aria/checkings/default-value.js +2 -6
  105. package/lib/wai-aria/checkings/deprecated-props.d.ts +2 -2
  106. package/lib/wai-aria/checkings/deprecated-props.js +3 -8
  107. package/lib/wai-aria/checkings/disallowed-prop.d.ts +2 -2
  108. package/lib/wai-aria/checkings/disallowed-prop.js +27 -8
  109. package/lib/wai-aria/checkings/implicit-props.d.ts +3 -3
  110. package/lib/wai-aria/checkings/implicit-props.js +7 -11
  111. package/lib/wai-aria/checkings/implicit-role.d.ts +1 -1
  112. package/lib/wai-aria/checkings/implicit-role.js +4 -9
  113. package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +1 -1
  114. package/lib/wai-aria/checkings/interaction-in-hidden.js +7 -9
  115. package/lib/wai-aria/checkings/no-global-prop.d.ts +2 -2
  116. package/lib/wai-aria/checkings/no-global-prop.js +2 -7
  117. package/lib/wai-aria/checkings/non-existent-role.d.ts +1 -1
  118. package/lib/wai-aria/checkings/non-existent-role.js +4 -9
  119. package/lib/wai-aria/checkings/permitted-roles.d.ts +1 -1
  120. package/lib/wai-aria/checkings/permitted-roles.js +4 -9
  121. package/lib/wai-aria/checkings/presentational-children.d.ts +1 -1
  122. package/lib/wai-aria/checkings/presentational-children.js +7 -10
  123. package/lib/wai-aria/checkings/required-owned-elements.d.ts +1 -1
  124. package/lib/wai-aria/checkings/required-owned-elements.js +10 -12
  125. package/lib/wai-aria/checkings/required-prop.d.ts +2 -2
  126. package/lib/wai-aria/checkings/required-prop.js +2 -7
  127. package/lib/wai-aria/checkings/value.d.ts +3 -3
  128. package/lib/wai-aria/checkings/value.js +7 -11
  129. package/lib/wai-aria/index.d.ts +2 -2
  130. package/lib/wai-aria/index.js +38 -39
  131. package/lib/wai-aria/types.js +1 -2
  132. package/package.json +21 -14
  133. package/schema.json +6 -0
  134. package/tsconfig.test.json +0 -3
  135. 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
- max?: number;
29
- not?: ChildNode;
30
- transparent?: Element;
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
- "use strict";
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
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.UnsupportedError = exports.Collection = exports.isTransparent = exports.isChoice = exports.isZeroOrMore = exports.isOneOrMore = exports.isOptional = exports.isRequire = exports.matches = exports.isModel = exports.getChildNodesWithoutWhitespaces = void 0;
5
- const tslib_1 = require("tslib");
6
- const selector_1 = require("@markuplint/selector");
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(el) {
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
- exports.getChildNodesWithoutWhitespaces = getChildNodesWithoutWhitespaces;
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
- exports.isModel = isModel;
39
- function matches(selector, node, specs) {
40
- const selectorResult = (0, selector_1.createSelector)(selector, specs).search(node);
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 => { var _a; return (r.matched ? [] : (_a = r.not) !== null && _a !== void 0 ? _a : []); })
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
- exports.matches = matches;
59
- function descendants(selectorResult) {
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 (!dep.has.length) {
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
- exports.isRequire = isRequire;
78
- function isOptional(content) {
77
+ export function isOptional(content) {
79
78
  return 'optional' in content;
80
79
  }
81
- exports.isOptional = isOptional;
82
- function isOneOrMore(content) {
80
+ export function isOneOrMore(content) {
83
81
  return 'oneOrMore' in content;
84
82
  }
85
- exports.isOneOrMore = isOneOrMore;
86
- function isZeroOrMore(content) {
83
+ export function isZeroOrMore(content) {
87
84
  return 'zeroOrMore' in content;
88
85
  }
89
- exports.isZeroOrMore = isZeroOrMore;
90
- function isChoice(content) {
86
+ export function isChoice(content) {
91
87
  return 'choice' in content;
92
88
  }
93
- exports.isChoice = isChoice;
94
- function isTransparent(content) {
89
+ export function isTransparent(content) {
95
90
  return 'transparent' in content;
96
91
  }
97
- exports.isTransparent = isTransparent;
98
- class Collection {
99
- constructor(origin) {
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
- tslib_1.__classPrivateFieldSet(this, _Collection_origin, origin.slice(), "f");
105
- tslib_1.__classPrivateFieldSet(this, _Collection_nodes, new Set(tslib_1.__classPrivateFieldGet(this, _Collection_origin, "f")), "f");
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(tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f"));
179
+ return Array.from(__classPrivateFieldGet(this, _Collection_matched, "f"));
109
180
  }
110
181
  get matchedCount() {
111
- return tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").size;
182
+ return __classPrivateFieldGet(this, _Collection_matched, "f").size;
112
183
  }
113
184
  get nodes() {
114
- return tslib_1.__classPrivateFieldGet(this, _Collection_origin, "f").slice();
185
+ return __classPrivateFieldGet(this, _Collection_origin, "f").slice();
115
186
  }
116
187
  get unmatched() {
117
- return Array.from(tslib_1.__classPrivateFieldGet(this, _Collection_nodes, "f")).filter(n => !tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").has(n));
188
+ return Array.from(__classPrivateFieldGet(this, _Collection_nodes, "f")).filter(n => !__classPrivateFieldGet(this, _Collection_matched, "f").has(n));
118
189
  }
119
- addMatched(nodes) {
120
- const i = tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").size;
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 (!tslib_1.__classPrivateFieldGet(this, _Collection_nodes, "f").has(node)) {
195
+ if (!__classPrivateFieldGet(this, _Collection_nodes, "f").has(node)) {
123
196
  throw new ReferenceError(`External Node: ${node.nodeName}`);
124
197
  }
125
- tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").add(node);
198
+ __classPrivateFieldGet(this, _Collection_matched, "f").add(node);
126
199
  }
127
- return i < tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").size;
200
+ return i < __classPrivateFieldGet(this, _Collection_matched, "f").size;
128
201
  }
129
202
  back() {
130
- tslib_1.__classPrivateFieldSet(this, _Collection_matched, new Set(tslib_1.__classPrivateFieldGet(this, _Collection_locked, "f")), "f");
203
+ __classPrivateFieldSet(this, _Collection_matched, new Set(__classPrivateFieldGet(this, _Collection_locked, "f")), "f");
131
204
  }
132
205
  lock() {
133
- tslib_1.__classPrivateFieldSet(this, _Collection_locked, new Set(tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f")), "f");
206
+ __classPrivateFieldSet(this, _Collection_locked, new Set(__classPrivateFieldGet(this, _Collection_matched, "f")), "f");
134
207
  }
135
208
  max(max) {
136
- const sliced = Array.from(tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f")).slice(max);
137
- sliced.forEach(n => tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").delete(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 tslib_1.__classPrivateFieldGet(this, _Collection_origin, "f")) {
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 (tslib_1.__classPrivateFieldGet(this, _Collection_locked, "f").has(n)) {
144
- if (represent_transparent_nodes_1.transparentMode.has(n)) {
145
- out.push(debug_1.bgBlue.bold(raw));
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(debug_1.bgGreen.bold(raw));
221
+ out.push(bgGreen.bold(raw));
149
222
  }
150
223
  continue;
151
224
  }
152
- if (tslib_1.__classPrivateFieldGet(this, _Collection_matched, "f").has(n)) {
153
- if (represent_transparent_nodes_1.transparentMode.has(n)) {
154
- out.push(debug_1.blue.bold(raw));
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(debug_1.green.bold(raw));
230
+ out.push(green.bold(raw));
158
231
  }
159
232
  continue;
160
233
  }
161
234
  if (highlightExtraNodes) {
162
- if (represent_transparent_nodes_1.transparentMode.has(n)) {
163
- out.push(debug_1.bgMagenta.bold(raw));
235
+ if (transparentMode.has(n)) {
236
+ out.push(bgMagenta.bold(raw));
164
237
  }
165
238
  else {
166
- out.push(debug_1.bgRed.bold(raw));
239
+ out.push(bgRed.bold(raw));
167
240
  }
168
241
  continue;
169
242
  }
170
- if (represent_transparent_nodes_1.transparentMode.has(n)) {
171
- out.push((0, debug_1.cyan)(raw));
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,2 @@
1
+ declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, undefined>>;
2
+ export default _default;
@@ -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
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const ml_core_1 = require("@markuplint/ml-core");
4
- const ml_spec_1 = require("@markuplint/ml-spec");
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: '1.2',
6
+ ariaVersion: ARIA_RECOMMENDED_VERSION,
9
7
  },
10
8
  async verify({ document, report, t }) {
11
9
  await document.walkOn('Element', el => {
12
- var _a;
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 ((0, helpers_1.accnameMayBeMutable)(el, document)) {
13
+ if (accnameMayBeMutable(el, document)) {
17
14
  return;
18
15
  }
19
- if (!(0, ml_spec_1.isExposed)(el, document.specs, el.rule.options.ariaVersion)) {
16
+ if (!isExposed(el, document.specs, el.rule.options.ariaVersion)) {
20
17
  return;
21
18
  }
22
- const computed = (0, ml_core_1.getComputedRole)(document.specs, el, el.rule.options.ariaVersion);
19
+ const computed = getComputedRole(document.specs, el, el.rule.options.ariaVersion);
23
20
  if (!computed.role) {
24
21
  return;
25
22
  }
26
- const roleSpec = (0, ml_core_1.getRoleSpec)(document.specs, computed.role.name, el.namespaceURI, el.rule.options.ariaVersion);
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,6 @@
1
+ import type { Lang } from './types.js';
2
+ type Options = {
3
+ langs?: Lang[];
4
+ };
5
+ declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, Options>>;
6
+ export default _default;
@@ -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;