@markuplint/rules 3.0.0-alpha.66 → 3.0.0-dev.176

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 (211) hide show
  1. package/README.md +10 -44
  2. package/lib/attr-check.d.ts +22 -10
  3. package/lib/attr-check.js +32 -23
  4. package/lib/attr-duplication/index.d.ts +3 -1
  5. package/lib/attr-duplication/index.js +3 -2
  6. package/lib/attr-value-quotes/index.d.ts +5 -5
  7. package/lib/attr-value-quotes/index.js +1 -1
  8. package/lib/case-sensitive-attr-name/index.d.ts +2 -2
  9. package/lib/case-sensitive-attr-name/index.js +3 -3
  10. package/lib/case-sensitive-tag-name/index.d.ts +2 -2
  11. package/lib/case-sensitive-tag-name/index.js +3 -3
  12. package/lib/character-reference/index.d.ts +1 -1
  13. package/lib/character-reference/index.js +1 -1
  14. package/lib/class-naming/index.d.ts +2 -2
  15. package/lib/class-naming/index.js +3 -5
  16. package/lib/create-message.d.ts +13 -2
  17. package/lib/create-message.js +9 -8
  18. package/lib/debug.d.ts +1 -1
  19. package/lib/debug.js +1 -1
  20. package/lib/deprecated-attr/index.d.ts +3 -1
  21. package/lib/deprecated-element/index.d.ts +3 -1
  22. package/lib/deprecated-element/index.js +4 -4
  23. package/lib/disallowed-element/index.d.ts +1 -1
  24. package/lib/doctype/index.d.ts +3 -3
  25. package/lib/doctype/index.js +2 -2
  26. package/lib/end-tag/index.d.ts +1 -1
  27. package/lib/end-tag/index.js +3 -18
  28. package/lib/helpers.d.ts +38 -47
  29. package/lib/helpers.js +42 -93
  30. package/lib/id-duplication/index.d.ts +3 -1
  31. package/lib/index.d.ts +242 -62
  32. package/lib/index.js +10 -1
  33. package/lib/ineffective-attr/index.d.ts +3 -1
  34. package/lib/ineffective-attr/index.js +3 -6
  35. package/lib/invalid-attr/index.d.ts +40 -12
  36. package/lib/invalid-attr/index.js +159 -28
  37. package/lib/label-has-control/index.d.ts +4 -0
  38. package/lib/label-has-control/index.js +28 -0
  39. package/lib/landmark-roles/index.d.ts +6 -6
  40. package/lib/landmark-roles/index.js +10 -6
  41. package/lib/no-boolean-attr-value/index.d.ts +3 -1
  42. package/lib/no-boolean-attr-value/index.js +1 -1
  43. package/lib/no-default-value/index.d.ts +3 -1
  44. package/lib/no-default-value/index.js +1 -1
  45. package/lib/no-empty-palpable-content/index.d.ts +6 -0
  46. package/lib/no-empty-palpable-content/index.js +42 -0
  47. package/lib/no-hard-code-id/index.d.ts +3 -1
  48. package/lib/no-hard-code-id/index.js +1 -1
  49. package/lib/no-refer-to-non-existent-id/index.d.ts +9 -4
  50. package/lib/no-refer-to-non-existent-id/index.js +65 -5
  51. package/lib/no-use-event-handler-attr/index.d.ts +3 -3
  52. package/lib/no-use-event-handler-attr/index.js +6 -6
  53. package/lib/permitted-contents/choice.d.ts +10 -0
  54. package/lib/permitted-contents/choice.js +72 -0
  55. package/lib/permitted-contents/complex-branch.d.ts +20 -0
  56. package/lib/permitted-contents/complex-branch.js +29 -0
  57. package/lib/permitted-contents/content-model.d.ts +2 -0
  58. package/lib/permitted-contents/content-model.js +53 -0
  59. package/lib/permitted-contents/count-pattern.d.ts +29 -0
  60. package/lib/permitted-contents/count-pattern.js +162 -0
  61. package/lib/permitted-contents/debug.browser.d.ts +30 -0
  62. package/lib/permitted-contents/debug.browser.js +14 -0
  63. package/lib/permitted-contents/debug.d.ts +3 -0
  64. package/lib/permitted-contents/debug.js +13 -0
  65. package/lib/permitted-contents/index.d.ts +2 -8
  66. package/lib/permitted-contents/index.js +76 -249
  67. package/lib/permitted-contents/matches-selector.d.ts +8 -0
  68. package/lib/permitted-contents/matches-selector.js +187 -0
  69. package/lib/permitted-contents/order.d.ts +20 -0
  70. package/lib/permitted-contents/order.js +99 -0
  71. package/lib/permitted-contents/recursive-branch.d.ts +11 -0
  72. package/lib/permitted-contents/recursive-branch.js +45 -0
  73. package/lib/permitted-contents/represent-transparent-nodes.d.ts +10 -0
  74. package/lib/permitted-contents/represent-transparent-nodes.js +78 -0
  75. package/lib/permitted-contents/start.d.ts +18 -0
  76. package/lib/permitted-contents/start.js +73 -0
  77. package/lib/permitted-contents/transparent.d.ts +2 -0
  78. package/lib/permitted-contents/transparent.js +31 -0
  79. package/lib/permitted-contents/types.d.ts +52 -0
  80. package/lib/permitted-contents/types.js +2 -0
  81. package/lib/permitted-contents/utils.d.ts +100 -0
  82. package/lib/permitted-contents/utils.js +302 -0
  83. package/lib/placeholder-label-option/index.d.ts +2 -0
  84. package/lib/placeholder-label-option/index.js +88 -0
  85. package/lib/require-accessible-name/index.d.ts +3 -3
  86. package/lib/require-accessible-name/index.js +12 -4
  87. package/lib/require-datetime/index.d.ts +6 -0
  88. package/lib/require-datetime/index.js +34 -0
  89. package/lib/require-datetime/types.d.ts +10 -0
  90. package/lib/require-datetime/types.js +2 -0
  91. package/lib/require-datetime/utils.d.ts +11 -0
  92. package/lib/require-datetime/utils.js +137 -0
  93. package/lib/required-attr/index.d.ts +5 -5
  94. package/lib/required-attr/index.js +20 -17
  95. package/lib/required-element/index.d.ts +3 -3
  96. package/lib/required-element/index.js +3 -2
  97. package/lib/required-h1/index.d.ts +3 -3
  98. package/lib/required-h1/index.js +4 -3
  99. package/lib/use-list/index.d.ts +4 -4
  100. package/lib/use-list/index.js +9 -7
  101. package/lib/wai-aria/checkings/_.d.ts +15 -0
  102. package/lib/wai-aria/checkings/_.js +27 -0
  103. package/lib/wai-aria/checkings/abstract-role.js +1 -1
  104. package/lib/wai-aria/checkings/default-value.d.ts +7 -3
  105. package/lib/wai-aria/checkings/deprecated-props.d.ts +8 -4
  106. package/lib/wai-aria/checkings/disallowed-prop.d.ts +8 -4
  107. package/lib/wai-aria/checkings/disallowed-prop.js +27 -3
  108. package/lib/wai-aria/checkings/implicit-props.d.ts +8 -4
  109. package/lib/wai-aria/checkings/implicit-props.js +3 -2
  110. package/lib/wai-aria/checkings/implicit-role.js +2 -2
  111. package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +11 -0
  112. package/lib/wai-aria/checkings/interaction-in-hidden.js +49 -0
  113. package/lib/wai-aria/checkings/no-global-prop.d.ts +7 -3
  114. package/lib/wai-aria/checkings/{non-existant-role.d.ts → non-existent-role.d.ts} +1 -1
  115. package/lib/wai-aria/checkings/{non-existant-role.js → non-existent-role.js} +4 -4
  116. package/lib/wai-aria/checkings/permitted-roles.js +1 -1
  117. package/lib/wai-aria/checkings/presentational-children.d.ts +29 -0
  118. package/lib/wai-aria/checkings/presentational-children.js +62 -0
  119. package/lib/wai-aria/checkings/{checking-required-owned-elements.d.ts → required-owned-elements.d.ts} +7 -3
  120. package/lib/wai-aria/checkings/required-owned-elements.js +103 -0
  121. package/lib/wai-aria/checkings/required-prop copy.d.ts +15 -0
  122. package/lib/wai-aria/checkings/required-prop copy.js +27 -0
  123. package/lib/wai-aria/checkings/required-prop.d.ts +12 -6
  124. package/lib/wai-aria/checkings/unadopted-explicit-roles.d.ts +15 -0
  125. package/lib/wai-aria/checkings/unadopted-explicit-roles.js +17 -0
  126. package/lib/wai-aria/checkings/value.d.ts +19 -4
  127. package/lib/wai-aria/checkings/value.js +77 -5
  128. package/lib/wai-aria/index.d.ts +1 -1
  129. package/lib/wai-aria/index.js +27 -16
  130. package/lib/wai-aria/types.d.ts +11 -9
  131. package/lib/xxx/index.d.ts +2 -0
  132. package/lib/xxx/index.js +32 -0
  133. package/package.json +18 -12
  134. package/schema.json +12 -0
  135. package/test/attr-check.spec.js +77 -0
  136. package/test/attr-duplication/index.spec.js +159 -0
  137. package/test/attr-value-quotes/index.spec.js +133 -0
  138. package/test/case-sensitive-attr-name/index.spec.js +65 -0
  139. package/test/case-sensitive-tag-name/index.spec.js +80 -0
  140. package/test/character-reference/index.spec.js +57 -0
  141. package/test/class-naming/index.spec.js +470 -0
  142. package/test/create-message.spec.js +497 -0
  143. package/test/deprecated-attr/index.spec.js +48 -0
  144. package/test/deprecated-element/index.spec.js +48 -0
  145. package/test/disallowed-element/index.spec.js +90 -0
  146. package/test/doctype/index.spec.js +50 -0
  147. package/test/end-tag/index.spec.js +162 -0
  148. package/test/id-duplication/index.spec.js +47 -0
  149. package/test/ineffective-attr/index.spec.js +31 -0
  150. package/test/invalid-attr/index.spec.js +1632 -0
  151. package/test/label-has-control/index.spec.js +29 -0
  152. package/test/landmark-roles/index.spec.js +187 -0
  153. package/test/no-boolean-attr-value/index.spec.js +41 -0
  154. package/test/no-default-value/index.spec.js +74 -0
  155. package/test/no-empty-palpable-content/index.spec.js +115 -0
  156. package/test/no-hard-code-id/index.spec.js +100 -0
  157. package/test/no-refer-to-non-existent-id/index.spec.js +254 -0
  158. package/test/no-use-event-handler-attr/index.spec.js +57 -0
  159. package/test/permitted-contents/choice.spec.js +174 -0
  160. package/test/permitted-contents/count-pattern.spec.js +308 -0
  161. package/test/permitted-contents/index.spec.js +1371 -0
  162. package/test/permitted-contents/matches-selector.spec.js +59 -0
  163. package/test/permitted-contents/order.spec.js +351 -0
  164. package/test/permitted-contents/recursive-branch.spec.js +41 -0
  165. package/test/permitted-contents/represent-transparent-nodes.spec.js +24 -0
  166. package/test/permitted-contents/start.spec.js +67 -0
  167. package/test/placeholder-label-option/index.spec.js +113 -0
  168. package/test/require-accessible-name/index.spec.js +446 -0
  169. package/test/require-datetime/index.spec.js +54 -0
  170. package/test/require-datetime/utils.spec.js +52 -0
  171. package/test/required-attr/index.spec.js +414 -0
  172. package/test/required-element/index.spec.js +188 -0
  173. package/test/required-h1/index.spec.js +69 -0
  174. package/test/use-list/index.spec.js +109 -0
  175. package/test/wai-aria/checkings/value.spec.js +33 -0
  176. package/test/wai-aria/index.spec.js +1173 -0
  177. package/lib/__foo/index.d.ts +0 -2
  178. package/lib/__foo/index.js +0 -46
  179. package/lib/attr-equal-space-after/index.d.ts +0 -3
  180. package/lib/attr-equal-space-after/index.js +0 -90
  181. package/lib/attr-equal-space-before/index.d.ts +0 -3
  182. package/lib/attr-equal-space-before/index.js +0 -90
  183. package/lib/attr-spacing/index.d.ts +0 -6
  184. package/lib/attr-spacing/index.js +0 -100
  185. package/lib/helper/aria/get-aria.d.ts +0 -7
  186. package/lib/helper/aria/get-aria.js +0 -53
  187. package/lib/helper/aria/get-computed-role.d.ts +0 -10
  188. package/lib/helper/aria/get-computed-role.js +0 -24
  189. package/lib/helper/aria/get-implicit-role.d.ts +0 -7
  190. package/lib/helper/aria/get-implicit-role.js +0 -12
  191. package/lib/helper/aria/get-permitted-roles.d.ts +0 -14
  192. package/lib/helper/aria/get-permitted-roles.js +0 -26
  193. package/lib/helper/aria/resolve-version.d.ts +0 -2
  194. package/lib/helper/aria/resolve-version.js +0 -21
  195. package/lib/helper/spec/aria-spec.d.ts +0 -5
  196. package/lib/helper/spec/aria-spec.js +0 -12
  197. package/lib/helper/spec/get-role-spec.d.ts +0 -11
  198. package/lib/helper/spec/get-role-spec.js +0 -39
  199. package/lib/helper/spec/html-spec.d.ts +0 -2
  200. package/lib/helper/spec/html-spec.js +0 -14
  201. package/lib/indentation/index.d.ts +0 -7
  202. package/lib/indentation/index.js +0 -208
  203. package/lib/permitted-contents/array.combination.d.ts +0 -1
  204. package/lib/permitted-contents/array.combination.js +0 -33
  205. package/lib/permitted-contents/permitted-content.spec-to-regexp.d.ts +0 -11
  206. package/lib/permitted-contents/permitted-content.spec-to-regexp.js +0 -230
  207. package/lib/permitted-contents/unfold-content-models-to-tags.d.ts +0 -2
  208. package/lib/permitted-contents/unfold-content-models-to-tags.js +0 -8
  209. package/lib/wai-aria/checkings/checking-required-owned-elements.js +0 -63
  210. package/tsconfig.test.json +0 -3
  211. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkingRequiredOwnedElements = void 0;
4
+ const ml_spec_1 = require("@markuplint/ml-spec");
5
+ /**
6
+ * Required Owned Elements
7
+ *
8
+ * @see https://w3c.github.io/aria/#mustContain
9
+ */
10
+ const checkingRequiredOwnedElements = ({ el, role }) => t => {
11
+ if (!role) {
12
+ return;
13
+ }
14
+ if (role.requiredOwnedElements.length === 0) {
15
+ return;
16
+ }
17
+ /**
18
+ * > There may be times that required owned elements are missing,
19
+ * > for example, while editing or while loading a data set.
20
+ * > When a widget is missing required owned elements due to script execution or loading,
21
+ * > authors MUST mark a containing element with aria-busy equal to true.
22
+ * > For example, until a page is fully initialized and complete,
23
+ * > an author could mark the document element as busy.
24
+ *
25
+ * Stop to evaluate when it has `aria-busy=true` for it considers the contents are missing.
26
+ */
27
+ if (el.matches('[aria-busy="true" i]')) {
28
+ return;
29
+ }
30
+ // TODO: Needs to resolve `aria-own`
31
+ const children = Array.from(el.childNodes).map(child => {
32
+ if (child.is(child.ELEMENT_NODE)) {
33
+ if (child.matches('[aria-busy="true" i]')) {
34
+ return [child, 'BUSY'];
35
+ }
36
+ const computedChild = (0, ml_spec_1.getComputedRole)(child.ownerMLDocument.specs, child, child.rule.options.version);
37
+ if (role.requiredOwnedElements.some(ownedRole => (0, ml_spec_1.isRequiredOwnedElement)(computedChild.el, computedChild.role, ownedRole, child.ownerMLDocument.specs, child.rule.options.version))) {
38
+ return [child, 'REQUIRED'];
39
+ }
40
+ return [child, 'OTHER'];
41
+ }
42
+ else if (child.is(child.MARKUPLINT_PREPROCESSOR_BLOCK)) {
43
+ return [child, 'PB'];
44
+ }
45
+ return [null, 'NO_ELEMENT'];
46
+ });
47
+ if (children.some(([, type]) => type === 'BUSY')) {
48
+ return;
49
+ }
50
+ /**
51
+ * > Any element that will be owned by the element with this role.
52
+ * > For example, an element with the role list
53
+ * > **will own at least one element** with the role listitem.
54
+ */
55
+ if (children.some(([, type]) => type === 'REQUIRED')) {
56
+ return;
57
+ }
58
+ if (children.some(([, type]) => type === 'PB')) {
59
+ // TODO: https://github.com/markuplint/markuplint/issues/490
60
+ return;
61
+ }
62
+ /**
63
+ * Has mutable children
64
+ *
65
+ * Ex:
66
+ *
67
+ * ```jsx
68
+ * <table>
69
+ * <tbody>
70
+ * {list.map((item) => <tr><td>{item}</td></tr>)}
71
+ * </tbody>
72
+ * </table>
73
+ * ```
74
+ */
75
+ if (el.hasMutableChildren(true)) {
76
+ return;
77
+ }
78
+ if (mayBeBeforeCreated(el)) {
79
+ return {
80
+ scope: el,
81
+ message: t('{0}. Or, {1}', t('require {0}', role.requiredOwnedElements.length === 1 && role.requiredOwnedElements[0]
82
+ ? t('the "{0*}" {1}', role.requiredOwnedElements[0], 'role')
83
+ : t('the {0}', 'roles') + `: ${t(role.requiredOwnedElements)}`), t('require {0}', 'aria-busy="true"')),
84
+ };
85
+ }
86
+ return {
87
+ scope: el,
88
+ message: t('{0} expects {1}', t('the "{0*}" {1}', role.name, 'role'), role.requiredOwnedElements.length === 1 && role.requiredOwnedElements[0]
89
+ ? t('the "{0*}" {1}', role.requiredOwnedElements[0], 'role')
90
+ : t('the {0}', 'roles') + `: ${t(role.requiredOwnedElements)}`),
91
+ };
92
+ };
93
+ exports.checkingRequiredOwnedElements = checkingRequiredOwnedElements;
94
+ function mayBeBeforeCreated(
95
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
96
+ el) {
97
+ if (el.isEmpty()) {
98
+ return true;
99
+ }
100
+ return Array.from(el.children).every(child => {
101
+ return ['script', 'template'].includes(child.localName);
102
+ });
103
+ }
@@ -0,0 +1,15 @@
1
+ import type { Options } from '../types';
2
+ import type { ElementChecker } from '@markuplint/ml-core';
3
+ import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
+ export declare const checkingRequiredProp: ElementChecker<
5
+ boolean,
6
+ Options,
7
+ {
8
+ role?:
9
+ | (ARIARole & {
10
+ isImplicit?: boolean;
11
+ })
12
+ | null;
13
+ propSpecs: readonly ARIAProperty[];
14
+ }
15
+ >;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkingRequiredProp = void 0;
4
+ const checkingRequiredProp = ({ el, role, propSpecs }) => t => {
5
+ var _a;
6
+ if (!role) {
7
+ return;
8
+ }
9
+ if (role.isImplicit) {
10
+ return;
11
+ }
12
+ const requiredProps = role.ownedProperties.filter(s => s.required).map(s => s.name);
13
+ for (const requiredProp of requiredProps) {
14
+ const has = el.attributes.some(attr => {
15
+ const attrName = attr.name.toLowerCase();
16
+ return attrName === requiredProp;
17
+ });
18
+ if (!has) {
19
+ const propSpec = propSpecs.find(p => p.name === requiredProp);
20
+ return {
21
+ scope: el,
22
+ message: t('{0:c} on {1}', t('Require {0}', t('the "{0*}" {1}', requiredProp, `ARIA ${(_a = propSpec === null || propSpec === void 0 ? void 0 : propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`)), t('the "{0*}" {1}', role.name, 'role')),
23
+ };
24
+ }
25
+ }
26
+ };
27
+ exports.checkingRequiredProp = checkingRequiredProp;
@@ -1,9 +1,15 @@
1
1
  import type { Options } from '../types';
2
2
  import type { ElementChecker } from '@markuplint/ml-core';
3
3
  import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
- export declare const checkingRequiredProp: ElementChecker<boolean, Options, {
5
- role?: (ARIARole & {
6
- isImplicit?: boolean;
7
- }) | null;
8
- propSpecs: ARIAProperty[];
9
- }>;
4
+ export declare const checkingRequiredProp: ElementChecker<
5
+ boolean,
6
+ Options,
7
+ {
8
+ role?:
9
+ | (ARIARole & {
10
+ isImplicit?: boolean;
11
+ })
12
+ | null;
13
+ propSpecs: readonly ARIAProperty[];
14
+ }
15
+ >;
@@ -0,0 +1,15 @@
1
+ import type { Options } from '../types';
2
+ import type { ElementChecker } from '@markuplint/ml-core';
3
+ import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
+ export declare const checkingUnadoptedExplicitRoles: ElementChecker<
5
+ boolean,
6
+ Options,
7
+ {
8
+ role?:
9
+ | (ARIARole & {
10
+ isImplicit?: boolean;
11
+ })
12
+ | null;
13
+ propSpecs: readonly ARIAProperty[];
14
+ }
15
+ >;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkingUnadoptedExplicitRoles = void 0;
4
+ const checkingUnadoptedExplicitRoles = ({ el, role, propSpecs }) => t => {
5
+ if (!role) {
6
+ return;
7
+ }
8
+ if (role.name) {
9
+ console.log(el.localName, role.name);
10
+ return {
11
+ scope: el,
12
+ message: '',
13
+ };
14
+ }
15
+ return;
16
+ };
17
+ exports.checkingUnadoptedExplicitRoles = checkingUnadoptedExplicitRoles;
@@ -1,7 +1,22 @@
1
1
  import type { Options } from '../types';
2
2
  import type { AttrChecker } from '@markuplint/ml-core';
3
3
  import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
- export declare const checkingValue: AttrChecker<boolean, Options, {
5
- role?: ARIARole | null;
6
- propSpecs: ARIAProperty[];
7
- }>;
4
+ export declare const checkingValue: AttrChecker<
5
+ boolean,
6
+ Options,
7
+ {
8
+ role?: ARIARole | null;
9
+ propSpecs: readonly ARIAProperty[];
10
+ booleanish?: boolean;
11
+ }
12
+ >;
13
+ /**
14
+ *
15
+ * @see https://www.w3.org/TR/wai-aria-1.2/#propcharacteristic_value
16
+ */
17
+ export declare function checkAriaValue(
18
+ type: string,
19
+ value: string,
20
+ tokenEnum: readonly string[],
21
+ booleanish?: boolean,
22
+ ): boolean;
@@ -1,21 +1,93 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkingValue = void 0;
4
- const helpers_1 = require("../../helpers");
5
- const checkingValue = ({ attr, role, propSpecs }) => t => {
3
+ exports.checkAriaValue = exports.checkingValue = void 0;
4
+ const checkingValue = ({ attr, role, propSpecs, booleanish }) => t => {
6
5
  var _a;
7
6
  if (attr.isDynamicValue) {
8
7
  return;
9
8
  }
10
9
  const propSpec = propSpecs.find(p => p.name === attr.name);
11
- const result = (0, helpers_1.checkAria)(attr.ownerMLDocument.specs, attr.name, attr.value, attr.rule.option.version, role === null || role === void 0 ? void 0 : role.name);
10
+ const result = checkAria(propSpec, attr.value, role === null || role === void 0 ? void 0 : role.name, booleanish);
12
11
  if (result.isValid) {
13
12
  return;
14
13
  }
15
14
  return {
16
15
  scope: attr,
17
16
  message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0}"', attr.value), 'disallowed'), t('the "{0*}" {1}', attr.name, `ARIA ${(_a = propSpec === null || propSpec === void 0 ? void 0 : propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`)) +
18
- ('enum' in result && result.enum.length ? t('. ') + t('Allowed values are: {0}', t(result.enum)) : ''),
17
+ ('enum' in result && result.enum.length > 0
18
+ ? t('. ') + t('Allowed values are: {0}', t(result.enum))
19
+ : ''),
19
20
  };
20
21
  };
21
22
  exports.checkingValue = checkingValue;
23
+ function checkAria(propSpec, currentValue, role, booleanish) {
24
+ if (!propSpec) {
25
+ return {
26
+ currentValue,
27
+ // For skipping checking
28
+ isValid: true,
29
+ };
30
+ }
31
+ let valueType = propSpec.value;
32
+ if (role && propSpec.conditionalValue) {
33
+ for (const cond of propSpec.conditionalValue) {
34
+ if (cond.role.includes(role)) {
35
+ valueType = cond.value;
36
+ break;
37
+ }
38
+ }
39
+ }
40
+ const isValid = checkAriaValue(valueType, currentValue, propSpec.enum, booleanish);
41
+ return {
42
+ ...propSpec,
43
+ currentValue,
44
+ isValid,
45
+ };
46
+ }
47
+ /**
48
+ *
49
+ * @see https://www.w3.org/TR/wai-aria-1.2/#propcharacteristic_value
50
+ */
51
+ function checkAriaValue(type, value, tokenEnum, booleanish) {
52
+ switch (type) {
53
+ case 'token': {
54
+ return tokenEnum.includes(value);
55
+ }
56
+ case 'token list': {
57
+ const list = value.split(/\s+/g).map(s => s.trim());
58
+ return list.every(token => tokenEnum.includes(token));
59
+ }
60
+ case 'string':
61
+ case 'ID reference':
62
+ case 'ID reference list': {
63
+ return true;
64
+ }
65
+ case 'true/false': {
66
+ if (booleanish && value === '') {
67
+ return true;
68
+ }
69
+ return ['true', 'false'].includes(value);
70
+ }
71
+ case 'tristate': {
72
+ if (booleanish && value === '') {
73
+ return true;
74
+ }
75
+ return ['mixed', 'true', 'false', 'undefined'].includes(value);
76
+ }
77
+ case 'true/false/undefined': {
78
+ if (booleanish && value === '') {
79
+ return true;
80
+ }
81
+ return ['true', 'false', 'undefined'].includes(value);
82
+ }
83
+ case 'integer': {
84
+ return parseInt(value).toString() === value;
85
+ }
86
+ case 'number': {
87
+ return parseFloat(value).toString() === value;
88
+ }
89
+ }
90
+ // For skipping checking
91
+ return true;
92
+ }
93
+ exports.checkAriaValue = checkAriaValue;
@@ -1,3 +1,3 @@
1
1
  import type { Options } from './types';
2
- declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Options>;
2
+ declare const _default: Readonly<import('@markuplint/ml-core').RuleSeed<boolean, Options>>;
3
3
  export default _default;
@@ -1,17 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ml_core_1 = require("@markuplint/ml-core");
4
+ const ml_spec_1 = require("@markuplint/ml-spec");
4
5
  const helpers_1 = require("../helpers");
5
6
  const abstract_role_1 = require("./checkings/abstract-role");
6
- const checking_required_owned_elements_1 = require("./checkings/checking-required-owned-elements");
7
7
  const default_value_1 = require("./checkings/default-value");
8
8
  const deprecated_props_1 = require("./checkings/deprecated-props");
9
9
  const disallowed_prop_1 = require("./checkings/disallowed-prop");
10
10
  const implicit_props_1 = require("./checkings/implicit-props");
11
11
  const implicit_role_1 = require("./checkings/implicit-role");
12
+ const interaction_in_hidden_1 = require("./checkings/interaction-in-hidden");
12
13
  const no_global_prop_1 = require("./checkings/no-global-prop");
13
- const non_existant_role_1 = require("./checkings/non-existant-role");
14
+ const non_existent_role_1 = require("./checkings/non-existent-role");
14
15
  const permitted_roles_1 = require("./checkings/permitted-roles");
16
+ const presentational_children_1 = require("./checkings/presentational-children");
17
+ const required_owned_elements_1 = require("./checkings/required-owned-elements");
15
18
  const required_prop_1 = require("./checkings/required-prop");
16
19
  const value_1 = require("./checkings/value");
17
20
  exports.default = (0, ml_core_1.createRule)({
@@ -20,17 +23,19 @@ exports.default = (0, ml_core_1.createRule)({
20
23
  checkingDeprecatedProps: true,
21
24
  permittedAriaRoles: true,
22
25
  checkingRequiredOwnedElements: true,
26
+ checkingPresentationalChildren: false,
27
+ checkingInteractionInHidden: false,
23
28
  disallowSetImplicitRole: true,
24
29
  disallowSetImplicitProps: true,
25
30
  disallowDefaultValue: false,
26
- version: '1.2',
31
+ version: ml_spec_1.ARIA_RECOMMENDED_VERSION,
27
32
  },
28
33
  async verify({ document, report, t }) {
29
34
  await document.walkOn('Element', el => {
30
35
  const roleAttr = el.getAttributeNode('role');
31
36
  const propAttrs = el.attributes.filter(attr => /^aria-/i.test(attr.name));
32
37
  const ariaAttrs = new helpers_1.Collection(roleAttr, ...propAttrs);
33
- const elSpec = (0, ml_core_1.getSpec)(el, document.specs);
38
+ const elSpec = (0, ml_core_1.getSpec)(el, document.specs.specs);
34
39
  if (!elSpec) {
35
40
  return;
36
41
  }
@@ -43,44 +48,50 @@ exports.default = (0, ml_core_1.createRule)({
43
48
  }
44
49
  return;
45
50
  }
46
- const computed = (0, ml_core_1.getComputedRole)(document.specs, el, el.rule.option.version);
47
- const { props: propSpecs } = (0, ml_core_1.ariaSpecs)(document.specs, el.rule.option.version);
51
+ const computed = (0, ml_core_1.getComputedRole)(document.specs, el, el.rule.options.version);
52
+ const { props: propSpecs } = (0, ml_core_1.ariaSpecs)(document.specs, el.rule.options.version);
48
53
  if (roleAttr) {
49
- if (report((0, non_existant_role_1.checkingNonExistantRole)({ attr: roleAttr }))) {
54
+ if (report((0, non_existent_role_1.checkingNonExistentRole)({ attr: roleAttr }))) {
50
55
  return;
51
56
  }
52
57
  if (report((0, abstract_role_1.checkingAbstractRole)({ attr: roleAttr }))) {
53
58
  return;
54
59
  }
55
60
  report((0, required_prop_1.checkingRequiredProp)({ el, role: computed.role, propSpecs }));
56
- if (el.rule.option.disallowSetImplicitRole) {
61
+ if (el.rule.options.disallowSetImplicitRole) {
57
62
  report((0, implicit_role_1.checkingImplicitRole)({ attr: roleAttr }));
58
63
  }
59
- if (el.rule.option.permittedAriaRoles) {
64
+ if (el.rule.options.permittedAriaRoles) {
60
65
  report((0, permitted_roles_1.checkingPermittedRoles)({ attr: roleAttr }));
61
66
  }
62
67
  }
63
68
  for (const attr of propAttrs) {
64
69
  report((0, disallowed_prop_1.checkingDisallowedProp)({ attr, role: computed.role, propSpecs }));
65
- if (el.rule.option.checkingDeprecatedProps) {
70
+ if (el.rule.options.checkingDeprecatedProps) {
66
71
  report((0, deprecated_props_1.checkingDeprecatedProps)({ attr, role: computed.role, propSpecs }));
67
72
  }
68
- if (el.rule.option.disallowSetImplicitProps) {
73
+ if (el.rule.options.disallowSetImplicitProps) {
69
74
  const attrSpecs = (0, ml_core_1.getAttrSpecs)(el, document.specs);
70
75
  report((0, implicit_props_1.checkingImplicitProps)({ attr, propSpecs, attrSpecs }));
71
76
  }
72
- if (el.rule.option.checkingValue) {
73
- report((0, value_1.checkingValue)({ attr, role: computed.role, propSpecs }));
77
+ if (el.rule.options.checkingValue) {
78
+ report((0, value_1.checkingValue)({ attr, role: computed.role, propSpecs, booleanish: document.booleanish }));
74
79
  }
75
- if (el.rule.option.disallowDefaultValue) {
80
+ if (el.rule.options.disallowDefaultValue) {
76
81
  report((0, default_value_1.checkingDefaultValue)({ attr, propSpecs }));
77
82
  }
78
83
  if (!computed.role) {
79
84
  report((0, no_global_prop_1.checkingNoGlobalProp)({ attr, propSpecs }));
80
85
  }
81
86
  }
82
- if (el.rule.option.checkingRequiredOwnedElements) {
83
- report((0, checking_required_owned_elements_1.checkingRequiredOwnedElements)({ el, role: computed.role }));
87
+ if (el.rule.options.checkingRequiredOwnedElements) {
88
+ report((0, required_owned_elements_1.checkingRequiredOwnedElements)({ el, role: computed.role }));
89
+ }
90
+ if (el.rule.options.checkingPresentationalChildren) {
91
+ report((0, presentational_children_1.checkingPresentationalChildren)({ el }));
92
+ }
93
+ if (el.rule.options.checkingInteractionInHidden) {
94
+ report((0, interaction_in_hidden_1.checkingInteractionInHidden)({ el }));
84
95
  }
85
96
  });
86
97
  },
@@ -1,11 +1,13 @@
1
1
  import type { ARIAVersion } from '@markuplint/ml-spec';
2
- export declare type Options = {
3
- checkingValue: boolean;
4
- checkingDeprecatedProps: boolean;
5
- permittedAriaRoles: boolean;
6
- checkingRequiredOwnedElements: boolean;
7
- disallowSetImplicitRole: boolean;
8
- disallowSetImplicitProps: boolean;
9
- disallowDefaultValue: boolean;
10
- version: ARIAVersion;
2
+ export type Options = {
3
+ checkingValue: boolean;
4
+ checkingDeprecatedProps: boolean;
5
+ permittedAriaRoles: boolean;
6
+ checkingRequiredOwnedElements: boolean;
7
+ checkingPresentationalChildren: boolean;
8
+ checkingInteractionInHidden: boolean;
9
+ disallowSetImplicitRole: boolean;
10
+ disallowSetImplicitProps: boolean;
11
+ disallowDefaultValue: boolean;
12
+ version: ARIAVersion;
11
13
  };
@@ -0,0 +1,2 @@
1
+ declare const _default: Readonly<import('@markuplint/ml-core').RuleSeed<boolean, null>>;
2
+ export default _default;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ml_core_1 = require("@markuplint/ml-core");
4
+ exports.default = (0, ml_core_1.createRule)({
5
+ defaultValue: true,
6
+ defaultOptions: null,
7
+ async verify({ document, report, t }) {
8
+ // Element
9
+ await document.walkOn("Element", (el) => {
10
+ const raw = el.raw.trim();
11
+ if (/./i.test(raw)) {
12
+ report({
13
+ scope: el,
14
+ message: t("It is {0}", "issue"),
15
+ });
16
+ }
17
+ });
18
+ // Attribute
19
+ await document.walkOn("Attr", (attr) => {
20
+ var _a, _b, _c;
21
+ if (/./i.test(attr.name)) {
22
+ report({
23
+ scope: attr,
24
+ line: (_a = attr.nameNode) === null || _a === void 0 ? void 0 : _a.startLine,
25
+ col: (_b = attr.nameNode) === null || _b === void 0 ? void 0 : _b.startCol,
26
+ raw: (_c = attr.nameNode) === null || _c === void 0 ? void 0 : _c.raw,
27
+ message: t("It is {0}", "issue"),
28
+ });
29
+ }
30
+ });
31
+ },
32
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@markuplint/rules",
3
- "version": "3.0.0-alpha.66+6cde1134",
4
- "description": "Rules for markuplint",
3
+ "version": "3.0.0-dev.176+f6ad62e9",
4
+ "description": "Built-in rules of markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
7
7
  "license": "MIT",
@@ -16,17 +16,23 @@
16
16
  "dev": "tsc --build --watch",
17
17
  "clean": "tsc --build --clean"
18
18
  },
19
+ "browser": {
20
+ "./lib/permitted-contents/debug.js": "./lib/permitted-contents/debug.browser.js"
21
+ },
19
22
  "dependencies": {
20
- "@markuplint/html-spec": "3.0.0-alpha.66+6cde1134",
21
- "@markuplint/ml-core": "3.0.0-alpha.66+6cde1134",
22
- "@markuplint/ml-spec": "3.0.0-alpha.82+6cde1134",
23
- "@markuplint/types": "2.1.0",
23
+ "@markuplint/html-spec": "3.0.0-dev.176+f6ad62e9",
24
+ "@markuplint/ml-core": "3.0.0-dev.176+f6ad62e9",
25
+ "@markuplint/ml-spec": "3.0.0-dev.176+f6ad62e9",
26
+ "@markuplint/selector": "3.0.0-dev.176+f6ad62e9",
27
+ "@markuplint/shared": "3.5.1-dev.3129+f6ad62e9",
28
+ "@markuplint/types": "3.0.0-dev.176+f6ad62e9",
29
+ "@types/debug": "^4.1.7",
30
+ "@ungap/structured-clone": "^1.0.1",
31
+ "ansi-colors": "^4.1.3",
32
+ "chrono-node": "^2.5.0",
24
33
  "debug": "^4.3.4",
25
- "html-entities": "^2.3.3",
26
- "tslib": "^2.3.1"
27
- },
28
- "devDependencies": {
29
- "@types/debug": "^4.1.7"
34
+ "tslib": "^2.4.1",
35
+ "type-fest": "^3.8.0"
30
36
  },
31
- "gitHead": "6cde113402758a8fdbd6a0fcf98e78efd2cdb778"
37
+ "gitHead": "f6ad62e992e1569be4067f1e90d2d6017a658f57"
32
38
  }
package/schema.json CHANGED
@@ -48,6 +48,9 @@
48
48
  "invalid-attr": {
49
49
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/invalid-attr/schema.json"
50
50
  },
51
+ "label-has-control": {
52
+ "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/label-has-control/schema.json"
53
+ },
51
54
  "landmark-roles": {
52
55
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/landmark-roles/schema.json"
53
56
  },
@@ -57,6 +60,9 @@
57
60
  "no-default-value": {
58
61
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/no-default-value/schema.json"
59
62
  },
63
+ "no-empty-palpable-content": {
64
+ "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/no-empty-palpable-content/schema.json"
65
+ },
60
66
  "no-hard-code-id": {
61
67
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/no-hard-code-id/schema.json"
62
68
  },
@@ -69,9 +75,15 @@
69
75
  "permitted-contents": {
70
76
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/permitted-contents/schema.json"
71
77
  },
78
+ "placeholder-label-option": {
79
+ "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/placeholder-label-option/schema.json"
80
+ },
72
81
  "require-accessible-name": {
73
82
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/require-accessible-name/schema.json"
74
83
  },
84
+ "require-datetime": {
85
+ "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/require-datetime/schema.json"
86
+ },
75
87
  "required-attr": {
76
88
  "$ref": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/%40markuplint/rules/src/required-attr/schema.json"
77
89
  },
@@ -0,0 +1,77 @@
1
+ const { translator } = require('@markuplint/i18n');
2
+ const { i18n } = require('markuplint');
3
+
4
+ const { valueCheck } = require('../lib/attr-check');
5
+
6
+ let t;
7
+
8
+ beforeAll(async () => {
9
+ const locale = await i18n('en');
10
+ t = translator(locale);
11
+ });
12
+
13
+ test('OneCodePointChar List', () => {
14
+ expect(
15
+ valueCheck(t, 'accesskey', '@ 12', {
16
+ token: 'OneCodePointChar',
17
+ separator: 'space',
18
+ unique: true,
19
+ }),
20
+ ).toStrictEqual([
21
+ 'the "accesskey" attribute expects space-separated list. the the content of the list part includes unexpected characters. It expects one code point character (https://html.spec.whatwg.org/multipage/interaction.html#the-accesskey-attribute)',
22
+ {
23
+ col: 2,
24
+ line: 0,
25
+ raw: '12',
26
+ },
27
+ ]);
28
+ });
29
+
30
+ test('BrowsingContextNameOrKeyword', () => {
31
+ expect(valueCheck(t, 'target', '', 'BrowsingContextNameOrKeyword')).toStrictEqual([
32
+ 'the "target" attribute must not be empty. It expects either "_blank", "_self", "_parent", "_top", "browsing context name" (https://html.spec.whatwg.org/multipage/browsers.html#valid-browsing-context-name-or-keyword)',
33
+ {
34
+ col: 0,
35
+ line: 0,
36
+ raw: '',
37
+ },
38
+ ]);
39
+ });
40
+
41
+ test('BCP47', () => {
42
+ expect(valueCheck(t, 'lang', '', 'BCP47')).toStrictEqual([
43
+ 'the "lang" attribute must not be empty. It expects the BCP47 format (https://tools.ietf.org/rfc/bcp/bcp47.html)',
44
+ {
45
+ col: 0,
46
+ line: 0,
47
+ raw: '',
48
+ },
49
+ ]);
50
+ });
51
+
52
+ test('DateTime', () => {
53
+ expect(valueCheck(t, 'datetime', '200-1-1', 'DateTime')).toStrictEqual([
54
+ 'the year part of the "datetime" attribute expects four or more digits (https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value)',
55
+ {
56
+ col: 0,
57
+ line: 0,
58
+ raw: '200',
59
+ },
60
+ ]);
61
+ expect(valueCheck(t, 'datetime', '2000-1-1', 'DateTime')).toStrictEqual([
62
+ 'the month part of the "datetime" attribute expects two digits (https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value)',
63
+ {
64
+ col: 5,
65
+ line: 0,
66
+ raw: '1',
67
+ },
68
+ ]);
69
+ expect(valueCheck(t, 'datetime', '00:00:00.0000', 'DateTime')).toStrictEqual([
70
+ 'the fractional part part of the "datetime" attribute expects one to three digits (https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value)',
71
+ {
72
+ col: 9,
73
+ line: 0,
74
+ raw: '0000',
75
+ },
76
+ ]);
77
+ });