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

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 (129) hide show
  1. package/README.md +10 -44
  2. package/lib/attr-check.d.ts +2 -2
  3. package/lib/attr-check.js +1 -1
  4. package/lib/attr-duplication/index.js +1 -1
  5. package/lib/attr-value-quotes/index.d.ts +3 -3
  6. package/lib/attr-value-quotes/index.js +1 -1
  7. package/lib/case-sensitive-attr-name/index.d.ts +1 -1
  8. package/lib/case-sensitive-attr-name/index.js +3 -3
  9. package/lib/case-sensitive-tag-name/index.d.ts +1 -1
  10. package/lib/case-sensitive-tag-name/index.js +3 -3
  11. package/lib/character-reference/index.js +1 -1
  12. package/lib/class-naming/index.d.ts +1 -1
  13. package/lib/class-naming/index.js +2 -2
  14. package/lib/create-message.d.ts +1 -1
  15. package/lib/create-message.js +5 -5
  16. package/lib/debug.d.ts +1 -1
  17. package/lib/deprecated-element/index.js +2 -2
  18. package/lib/doctype/index.d.ts +2 -2
  19. package/lib/doctype/index.js +2 -2
  20. package/lib/end-tag/index.js +3 -18
  21. package/lib/helpers.d.ts +8 -32
  22. package/lib/helpers.js +17 -81
  23. package/lib/index.d.ts +2 -62
  24. package/lib/index.js +4 -0
  25. package/lib/ineffective-attr/index.js +1 -1
  26. package/lib/invalid-attr/index.d.ts +3 -2
  27. package/lib/invalid-attr/index.js +19 -14
  28. package/lib/label-has-control/index.d.ts +2 -0
  29. package/lib/label-has-control/index.js +28 -0
  30. package/lib/landmark-roles/index.d.ts +3 -3
  31. package/lib/landmark-roles/index.js +3 -3
  32. package/lib/no-boolean-attr-value/index.js +1 -1
  33. package/lib/no-default-value/index.js +1 -1
  34. package/lib/no-empty-palpable-content/index.d.ts +6 -0
  35. package/lib/no-empty-palpable-content/index.js +34 -0
  36. package/lib/no-hard-code-id/index.js +1 -1
  37. package/lib/no-refer-to-non-existent-id/index.js +1 -1
  38. package/lib/no-use-event-handler-attr/index.d.ts +1 -1
  39. package/lib/no-use-event-handler-attr/index.js +6 -6
  40. package/lib/permitted-contents/choice.d.ts +3 -0
  41. package/lib/permitted-contents/choice.js +37 -0
  42. package/lib/permitted-contents/complex-branch.d.ts +13 -0
  43. package/lib/permitted-contents/complex-branch.js +27 -0
  44. package/lib/permitted-contents/content-model.d.ts +2 -0
  45. package/lib/permitted-contents/content-model.js +49 -0
  46. package/lib/permitted-contents/count-pattern.d.ts +13 -0
  47. package/lib/permitted-contents/count-pattern.js +155 -0
  48. package/lib/permitted-contents/debug.browser.d.ts +30 -0
  49. package/lib/permitted-contents/debug.browser.js +14 -0
  50. package/lib/permitted-contents/debug.d.ts +3 -0
  51. package/lib/permitted-contents/debug.js +13 -0
  52. package/lib/permitted-contents/index.d.ts +1 -7
  53. package/lib/permitted-contents/index.js +76 -246
  54. package/lib/permitted-contents/matches-selector.d.ts +3 -0
  55. package/lib/permitted-contents/matches-selector.js +185 -0
  56. package/lib/permitted-contents/order.d.ts +13 -0
  57. package/lib/permitted-contents/order.js +89 -0
  58. package/lib/permitted-contents/recursive-branch.d.ts +4 -0
  59. package/lib/permitted-contents/recursive-branch.js +43 -0
  60. package/lib/permitted-contents/represent-transparent-nodes.d.ts +6 -0
  61. package/lib/permitted-contents/represent-transparent-nodes.js +76 -0
  62. package/lib/permitted-contents/start.d.ts +12 -0
  63. package/lib/permitted-contents/start.js +71 -0
  64. package/lib/permitted-contents/transparent.d.ts +2 -0
  65. package/lib/permitted-contents/transparent.js +29 -0
  66. package/lib/permitted-contents/types.d.ts +45 -0
  67. package/lib/permitted-contents/types.js +2 -0
  68. package/lib/permitted-contents/utils.d.ts +32 -0
  69. package/lib/permitted-contents/utils.js +184 -0
  70. package/lib/require-accessible-name/index.d.ts +1 -1
  71. package/lib/require-accessible-name/index.js +11 -3
  72. package/lib/required-attr/index.d.ts +2 -2
  73. package/lib/required-attr/index.js +1 -1
  74. package/lib/required-element/index.d.ts +1 -1
  75. package/lib/required-element/index.js +1 -1
  76. package/lib/required-h1/index.js +2 -2
  77. package/lib/use-list/index.d.ts +2 -2
  78. package/lib/use-list/index.js +3 -3
  79. package/lib/wai-aria/checkings/abstract-role.js +1 -1
  80. package/lib/wai-aria/checkings/implicit-role.js +2 -2
  81. package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +11 -0
  82. package/lib/wai-aria/checkings/interaction-in-hidden.js +47 -0
  83. package/lib/wai-aria/checkings/{non-existant-role.d.ts → non-existent-role.d.ts} +1 -1
  84. package/lib/wai-aria/checkings/{non-existant-role.js → non-existent-role.js} +4 -4
  85. package/lib/wai-aria/checkings/permitted-roles.js +1 -1
  86. package/lib/wai-aria/checkings/presentational-children.d.ts +29 -0
  87. package/lib/wai-aria/checkings/presentational-children.js +60 -0
  88. package/lib/wai-aria/checkings/{checking-required-owned-elements.d.ts → required-owned-elements.d.ts} +0 -0
  89. package/lib/wai-aria/checkings/required-owned-elements.js +101 -0
  90. package/lib/wai-aria/checkings/value.d.ts +6 -0
  91. package/lib/wai-aria/checkings/value.js +74 -4
  92. package/lib/wai-aria/index.js +25 -15
  93. package/lib/wai-aria/types.d.ts +3 -1
  94. package/package.json +12 -8
  95. package/schema.json +6 -0
  96. package/tsconfig.tsbuildinfo +1 -1
  97. package/lib/__foo/index.d.ts +0 -2
  98. package/lib/__foo/index.js +0 -46
  99. package/lib/attr-equal-space-after/index.d.ts +0 -3
  100. package/lib/attr-equal-space-after/index.js +0 -90
  101. package/lib/attr-equal-space-before/index.d.ts +0 -3
  102. package/lib/attr-equal-space-before/index.js +0 -90
  103. package/lib/attr-spacing/index.d.ts +0 -6
  104. package/lib/attr-spacing/index.js +0 -100
  105. package/lib/helper/aria/get-aria.d.ts +0 -7
  106. package/lib/helper/aria/get-aria.js +0 -53
  107. package/lib/helper/aria/get-computed-role.d.ts +0 -10
  108. package/lib/helper/aria/get-computed-role.js +0 -24
  109. package/lib/helper/aria/get-implicit-role.d.ts +0 -7
  110. package/lib/helper/aria/get-implicit-role.js +0 -12
  111. package/lib/helper/aria/get-permitted-roles.d.ts +0 -14
  112. package/lib/helper/aria/get-permitted-roles.js +0 -26
  113. package/lib/helper/aria/resolve-version.d.ts +0 -2
  114. package/lib/helper/aria/resolve-version.js +0 -21
  115. package/lib/helper/spec/aria-spec.d.ts +0 -5
  116. package/lib/helper/spec/aria-spec.js +0 -12
  117. package/lib/helper/spec/get-role-spec.d.ts +0 -11
  118. package/lib/helper/spec/get-role-spec.js +0 -39
  119. package/lib/helper/spec/html-spec.d.ts +0 -2
  120. package/lib/helper/spec/html-spec.js +0 -14
  121. package/lib/indentation/index.d.ts +0 -7
  122. package/lib/indentation/index.js +0 -208
  123. package/lib/permitted-contents/array.combination.d.ts +0 -1
  124. package/lib/permitted-contents/array.combination.js +0 -33
  125. package/lib/permitted-contents/permitted-content.spec-to-regexp.d.ts +0 -11
  126. package/lib/permitted-contents/permitted-content.spec-to-regexp.js +0 -230
  127. package/lib/permitted-contents/unfold-content-models-to-tags.d.ts +0 -2
  128. package/lib/permitted-contents/unfold-content-models-to-tags.js +0 -8
  129. package/lib/wai-aria/checkings/checking-required-owned-elements.js +0 -63
@@ -4,13 +4,13 @@ exports.checkingImplicitRole = void 0;
4
4
  const ml_spec_1 = require("@markuplint/ml-spec");
5
5
  const checkingImplicitRole = ({ attr }) => t => {
6
6
  var _a;
7
- const implictRole = (0, ml_spec_1.getImplicitRoleName)(attr.ownerElement, attr.rule.option.version, attr.ownerMLDocument.specs);
7
+ const implicitRole = (0, ml_spec_1.getImplicitRoleName)(attr.ownerElement, attr.rule.options.version, attr.ownerMLDocument.specs);
8
8
  const tokens = (_a = attr.tokenList) === null || _a === void 0 ? void 0 : _a.allTokens();
9
9
  if (!tokens) {
10
10
  return;
11
11
  }
12
12
  for (const token of tokens) {
13
- if (implictRole === token.raw) {
13
+ if (implicitRole === token.raw) {
14
14
  return {
15
15
  scope: token,
16
16
  message: t('{0} is {1}', t('the "{0*}" {1}', token.raw, 'role'), t('{0} of {1}', 'the implicit role', t('the "{0*}" {1}', attr.ownerElement.localName, 'element'))),
@@ -0,0 +1,11 @@
1
+ import type { Options } from '../types';
2
+ import type { ElementChecker } from '@markuplint/ml-core';
3
+ /**
4
+ * Including Elements in the Accessibility Tree
5
+ *
6
+ * @see https://w3c.github.io/aria/#tree_inclusion
7
+ * > Elements that are not hidden and may fire an accessibility API event, including:
8
+ * > - Elements that are currently focused, even if the element or one of its ancestor elements has its aria-hidden attribute set to true.
9
+ * > - Elements that are a valid target of an aria-activedescendant attribute.
10
+ */
11
+ export declare const checkingInteractionInHidden: ElementChecker<boolean, Options>;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkingInteractionInHidden = void 0;
4
+ const ml_spec_1 = require("@markuplint/ml-spec");
5
+ /**
6
+ * Including Elements in the Accessibility Tree
7
+ *
8
+ * @see https://w3c.github.io/aria/#tree_inclusion
9
+ * > Elements that are not hidden and may fire an accessibility API event, including:
10
+ * > - Elements that are currently focused, even if the element or one of its ancestor elements has its aria-hidden attribute set to true.
11
+ * > - Elements that are a valid target of an aria-activedescendant attribute.
12
+ */
13
+ // フォーカスがあたっている場合に限り、先祖がaria-hidden=trueでもアクセシビリティツリーに提示される
14
+ // なので、aria-hidden=trueの子孫要素で且つインタラクティブ要素である場合、
15
+ // それは開発者にとってはほとんどの場合、意図しないことが多いはずなので、
16
+ // 仕様上不正にはならないが、十分に注意しなければならない状態である。
17
+ const checkingInteractionInHidden = ({ el }) => t => {
18
+ if (!(0, ml_spec_1.mayBeFocusable)(el, el.ownerMLDocument.specs)) {
19
+ return;
20
+ }
21
+ const ariaHidden = getClosestAriaHidden(el);
22
+ if (!ariaHidden) {
23
+ return;
24
+ }
25
+ if (el === ariaHidden.ownerElement) {
26
+ return {
27
+ scope: el,
28
+ message: t('It may be focusable in spite of it has aria-hidden=true'),
29
+ };
30
+ }
31
+ return {
32
+ scope: el,
33
+ message: t('It may be focusable in spite of it has the ancestor that has aria-hidden=true'),
34
+ };
35
+ };
36
+ exports.checkingInteractionInHidden = checkingInteractionInHidden;
37
+ function getClosestAriaHidden(el) {
38
+ let current = el;
39
+ while (current) {
40
+ const ariaHidden = current.getAttributeNode('aria-hidden');
41
+ if ((ariaHidden === null || ariaHidden === void 0 ? void 0 : ariaHidden.value) === 'true') {
42
+ return ariaHidden;
43
+ }
44
+ current = current.parentElement;
45
+ }
46
+ return null;
47
+ }
@@ -1,3 +1,3 @@
1
1
  import type { Options } from '../types';
2
2
  import type { AttrChecker } from '@markuplint/ml-core';
3
- export declare const checkingNonExistantRole: AttrChecker<boolean, Options>;
3
+ export declare const checkingNonExistentRole: AttrChecker<boolean, Options>;
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkingNonExistantRole = void 0;
3
+ exports.checkingNonExistentRole = void 0;
4
4
  const ml_spec_1 = require("@markuplint/ml-spec");
5
- const checkingNonExistantRole = ({ attr }) => t => {
5
+ const checkingNonExistentRole = ({ attr }) => t => {
6
6
  var _a;
7
- const { roles, graphicsRoles } = (0, ml_spec_1.ariaSpecs)(attr.ownerMLDocument.specs, attr.rule.option.version);
7
+ const { roles, graphicsRoles } = (0, ml_spec_1.ariaSpecs)(attr.ownerMLDocument.specs, attr.rule.options.version);
8
8
  const tokens = (_a = attr.tokenList) === null || _a === void 0 ? void 0 : _a.allTokens();
9
9
  if (!tokens) {
10
10
  return;
@@ -25,4 +25,4 @@ const checkingNonExistantRole = ({ attr }) => t => {
25
25
  }
26
26
  }
27
27
  };
28
- exports.checkingNonExistantRole = checkingNonExistantRole;
28
+ exports.checkingNonExistentRole = checkingNonExistentRole;
@@ -5,7 +5,7 @@ const ml_spec_1 = require("@markuplint/ml-spec");
5
5
  const checkingPermittedRoles = ({ attr }) => t => {
6
6
  var _a;
7
7
  const el = attr.ownerElement;
8
- const permittedRoles = (0, ml_spec_1.getPermittedRoles)(el, el.rule.option.version, attr.ownerMLDocument.specs);
8
+ const permittedRoles = (0, ml_spec_1.getPermittedRoles)(el, el.rule.options.version, attr.ownerMLDocument.specs);
9
9
  if (permittedRoles.length === 0) {
10
10
  return {
11
11
  scope: attr,
@@ -0,0 +1,29 @@
1
+ import type { Options } from '../types';
2
+ import type { ElementChecker } from '@markuplint/ml-core';
3
+ /**
4
+ * Presentational Children
5
+ *
6
+ * @see https://www.w3.org/TR/wai-aria/#childrenArePresentational
7
+ * @see https://w3c.github.io/aria/#childrenArePresentational
8
+ *
9
+ * > The DOM descendants are presentational.
10
+ * > user agents SHOULD NOT expose descendants of
11
+ * > this element through the platform accessibility API.
12
+ * > If user agents do not hide the descendant nodes,
13
+ * > some information may be read twice.
14
+ *
15
+ * @see https://w3c.github.io/aria/#tree_exclusion
16
+ *
17
+ * > Any descendants of elements that have the characteristic "Children Presentational: True"
18
+ * > unless the descendant is not allowed to be presentational
19
+ * > because it meets one of the conditions for exception described
20
+ * > in Presentational Roles Conflict Resolution.
21
+ * > However, the text content of any excluded descendants is included.
22
+ *
23
+ * @see https://w3c.github.io/aria/#tree_inclusion
24
+ *
25
+ * > Text equivalents for hidden referenced objects
26
+ * > may still be used in the name and description computation
27
+ * > even when not included in the accessibility tree.
28
+ */
29
+ export declare const checkingPresentationalChildren: ElementChecker<boolean, Options>;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkingPresentationalChildren = void 0;
4
+ const ml_spec_1 = require("@markuplint/ml-spec");
5
+ /**
6
+ * Presentational Children
7
+ *
8
+ * @see https://www.w3.org/TR/wai-aria/#childrenArePresentational
9
+ * @see https://w3c.github.io/aria/#childrenArePresentational
10
+ *
11
+ * > The DOM descendants are presentational.
12
+ * > user agents SHOULD NOT expose descendants of
13
+ * > this element through the platform accessibility API.
14
+ * > If user agents do not hide the descendant nodes,
15
+ * > some information may be read twice.
16
+ *
17
+ * @see https://w3c.github.io/aria/#tree_exclusion
18
+ *
19
+ * > Any descendants of elements that have the characteristic "Children Presentational: True"
20
+ * > unless the descendant is not allowed to be presentational
21
+ * > because it meets one of the conditions for exception described
22
+ * > in Presentational Roles Conflict Resolution.
23
+ * > However, the text content of any excluded descendants is included.
24
+ *
25
+ * @see https://w3c.github.io/aria/#tree_inclusion
26
+ *
27
+ * > Text equivalents for hidden referenced objects
28
+ * > may still be used in the name and description computation
29
+ * > even when not included in the accessibility tree.
30
+ */
31
+ const checkingPresentationalChildren = ({ el }) => t => {
32
+ const ancestor = getAncestorHasPresentationalChildren(el);
33
+ if (!ancestor) {
34
+ return;
35
+ }
36
+ if (!ancestor.role) {
37
+ return;
38
+ }
39
+ const hasAriaAttr = Array.from(el.attributes).some(attr => /^aria-|^role$/i.test(attr.name));
40
+ if (!hasAriaAttr) {
41
+ return;
42
+ }
43
+ return {
44
+ scope: el,
45
+ message: t('it may be ineffective because {0}', t("it has {0} as an ancestor that doesn't expose its descendants to the accessibility tree", t('the "{0*}" {1}', ancestor.role.name, 'role'))),
46
+ };
47
+ };
48
+ exports.checkingPresentationalChildren = checkingPresentationalChildren;
49
+ function getAncestorHasPresentationalChildren(el) {
50
+ var _a;
51
+ let current = el.parentElement;
52
+ while (current) {
53
+ const computed = (0, ml_spec_1.getComputedRole)(el.ownerMLDocument.specs, current, el.rule.options.version);
54
+ if ((_a = computed.role) === null || _a === void 0 ? void 0 : _a.childrenPresentational) {
55
+ return computed;
56
+ }
57
+ current = current.parentElement;
58
+ }
59
+ return null;
60
+ }
@@ -0,0 +1,101 @@
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) {
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, 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
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
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(el) {
95
+ if (el.isEmpty()) {
96
+ return true;
97
+ }
98
+ return Array.from(el.children).every(child => {
99
+ return ['script', 'template'].includes(child.localName);
100
+ });
101
+ }
@@ -4,4 +4,10 @@ import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
4
  export declare const checkingValue: AttrChecker<boolean, Options, {
5
5
  role?: ARIARole | null;
6
6
  propSpecs: ARIAProperty[];
7
+ booleanish?: boolean;
7
8
  }>;
9
+ /**
10
+ *
11
+ * @see https://www.w3.org/TR/wai-aria-1.2/#propcharacteristic_value
12
+ */
13
+ export declare function checkAriaValue(type: string, value: string, tokenEnum: string[], booleanish?: boolean): boolean;
@@ -1,14 +1,13 @@
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
  }
@@ -19,3 +18,74 @@ const checkingValue = ({ attr, role, propSpecs }) => t => {
19
18
  };
20
19
  };
21
20
  exports.checkingValue = checkingValue;
21
+ function checkAria(propSpec, currentValue, role, booleanish) {
22
+ if (!propSpec) {
23
+ return {
24
+ currentValue,
25
+ // For skipping checking
26
+ isValid: true,
27
+ };
28
+ }
29
+ let valueType = propSpec.value;
30
+ if (role && propSpec.conditionalValue) {
31
+ for (const cond of propSpec.conditionalValue) {
32
+ if (cond.role.includes(role)) {
33
+ valueType = cond.value;
34
+ break;
35
+ }
36
+ }
37
+ }
38
+ const isValid = checkAriaValue(valueType, currentValue, propSpec.enum, booleanish);
39
+ return {
40
+ ...propSpec,
41
+ currentValue,
42
+ isValid,
43
+ };
44
+ }
45
+ /**
46
+ *
47
+ * @see https://www.w3.org/TR/wai-aria-1.2/#propcharacteristic_value
48
+ */
49
+ function checkAriaValue(type, value, tokenEnum, booleanish) {
50
+ switch (type) {
51
+ case 'token': {
52
+ return tokenEnum.includes(value);
53
+ }
54
+ case 'token list': {
55
+ const list = value.split(/\s+/g).map(s => s.trim());
56
+ return list.every(token => tokenEnum.includes(token));
57
+ }
58
+ case 'string':
59
+ case 'ID reference':
60
+ case 'ID reference list': {
61
+ return true;
62
+ }
63
+ case 'true/false': {
64
+ if (booleanish && value === '') {
65
+ return true;
66
+ }
67
+ return ['true', 'false'].includes(value);
68
+ }
69
+ case 'tristate': {
70
+ if (booleanish && value === '') {
71
+ return true;
72
+ }
73
+ return ['mixed', 'true', 'false', 'undefined'].includes(value);
74
+ }
75
+ case 'true/false/undefined': {
76
+ if (booleanish && value === '') {
77
+ return true;
78
+ }
79
+ return ['true', 'false', 'undefined'].includes(value);
80
+ }
81
+ case 'integer': {
82
+ return parseInt(value).toString() === value;
83
+ }
84
+ case 'number': {
85
+ return parseFloat(value).toString() === value;
86
+ }
87
+ }
88
+ // For skipping checking
89
+ return true;
90
+ }
91
+ exports.checkAriaValue = checkAriaValue;
@@ -3,15 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ml_core_1 = require("@markuplint/ml-core");
4
4
  const helpers_1 = require("../helpers");
5
5
  const abstract_role_1 = require("./checkings/abstract-role");
6
- const checking_required_owned_elements_1 = require("./checkings/checking-required-owned-elements");
7
6
  const default_value_1 = require("./checkings/default-value");
8
7
  const deprecated_props_1 = require("./checkings/deprecated-props");
9
8
  const disallowed_prop_1 = require("./checkings/disallowed-prop");
10
9
  const implicit_props_1 = require("./checkings/implicit-props");
11
10
  const implicit_role_1 = require("./checkings/implicit-role");
11
+ const interaction_in_hidden_1 = require("./checkings/interaction-in-hidden");
12
12
  const no_global_prop_1 = require("./checkings/no-global-prop");
13
- const non_existant_role_1 = require("./checkings/non-existant-role");
13
+ const non_existent_role_1 = require("./checkings/non-existent-role");
14
14
  const permitted_roles_1 = require("./checkings/permitted-roles");
15
+ const presentational_children_1 = require("./checkings/presentational-children");
16
+ const required_owned_elements_1 = require("./checkings/required-owned-elements");
15
17
  const required_prop_1 = require("./checkings/required-prop");
16
18
  const value_1 = require("./checkings/value");
17
19
  exports.default = (0, ml_core_1.createRule)({
@@ -20,6 +22,8 @@ exports.default = (0, ml_core_1.createRule)({
20
22
  checkingDeprecatedProps: true,
21
23
  permittedAriaRoles: true,
22
24
  checkingRequiredOwnedElements: true,
25
+ checkingPresentationalChildren: false,
26
+ checkingInteractionInHidden: false,
23
27
  disallowSetImplicitRole: true,
24
28
  disallowSetImplicitProps: true,
25
29
  disallowDefaultValue: false,
@@ -30,7 +34,7 @@ exports.default = (0, ml_core_1.createRule)({
30
34
  const roleAttr = el.getAttributeNode('role');
31
35
  const propAttrs = el.attributes.filter(attr => /^aria-/i.test(attr.name));
32
36
  const ariaAttrs = new helpers_1.Collection(roleAttr, ...propAttrs);
33
- const elSpec = (0, ml_core_1.getSpec)(el, document.specs);
37
+ const elSpec = (0, ml_core_1.getSpec)(el, document.specs.specs);
34
38
  if (!elSpec) {
35
39
  return;
36
40
  }
@@ -43,44 +47,50 @@ exports.default = (0, ml_core_1.createRule)({
43
47
  }
44
48
  return;
45
49
  }
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);
50
+ const computed = (0, ml_core_1.getComputedRole)(document.specs, el, el.rule.options.version);
51
+ const { props: propSpecs } = (0, ml_core_1.ariaSpecs)(document.specs, el.rule.options.version);
48
52
  if (roleAttr) {
49
- if (report((0, non_existant_role_1.checkingNonExistantRole)({ attr: roleAttr }))) {
53
+ if (report((0, non_existent_role_1.checkingNonExistentRole)({ attr: roleAttr }))) {
50
54
  return;
51
55
  }
52
56
  if (report((0, abstract_role_1.checkingAbstractRole)({ attr: roleAttr }))) {
53
57
  return;
54
58
  }
55
59
  report((0, required_prop_1.checkingRequiredProp)({ el, role: computed.role, propSpecs }));
56
- if (el.rule.option.disallowSetImplicitRole) {
60
+ if (el.rule.options.disallowSetImplicitRole) {
57
61
  report((0, implicit_role_1.checkingImplicitRole)({ attr: roleAttr }));
58
62
  }
59
- if (el.rule.option.permittedAriaRoles) {
63
+ if (el.rule.options.permittedAriaRoles) {
60
64
  report((0, permitted_roles_1.checkingPermittedRoles)({ attr: roleAttr }));
61
65
  }
62
66
  }
63
67
  for (const attr of propAttrs) {
64
68
  report((0, disallowed_prop_1.checkingDisallowedProp)({ attr, role: computed.role, propSpecs }));
65
- if (el.rule.option.checkingDeprecatedProps) {
69
+ if (el.rule.options.checkingDeprecatedProps) {
66
70
  report((0, deprecated_props_1.checkingDeprecatedProps)({ attr, role: computed.role, propSpecs }));
67
71
  }
68
- if (el.rule.option.disallowSetImplicitProps) {
72
+ if (el.rule.options.disallowSetImplicitProps) {
69
73
  const attrSpecs = (0, ml_core_1.getAttrSpecs)(el, document.specs);
70
74
  report((0, implicit_props_1.checkingImplicitProps)({ attr, propSpecs, attrSpecs }));
71
75
  }
72
- if (el.rule.option.checkingValue) {
73
- report((0, value_1.checkingValue)({ attr, role: computed.role, propSpecs }));
76
+ if (el.rule.options.checkingValue) {
77
+ report((0, value_1.checkingValue)({ attr, role: computed.role, propSpecs, booleanish: document.booleanish }));
74
78
  }
75
- if (el.rule.option.disallowDefaultValue) {
79
+ if (el.rule.options.disallowDefaultValue) {
76
80
  report((0, default_value_1.checkingDefaultValue)({ attr, propSpecs }));
77
81
  }
78
82
  if (!computed.role) {
79
83
  report((0, no_global_prop_1.checkingNoGlobalProp)({ attr, propSpecs }));
80
84
  }
81
85
  }
82
- if (el.rule.option.checkingRequiredOwnedElements) {
83
- report((0, checking_required_owned_elements_1.checkingRequiredOwnedElements)({ el, role: computed.role }));
86
+ if (el.rule.options.checkingRequiredOwnedElements) {
87
+ report((0, required_owned_elements_1.checkingRequiredOwnedElements)({ el, role: computed.role }));
88
+ }
89
+ if (el.rule.options.checkingPresentationalChildren) {
90
+ report((0, presentational_children_1.checkingPresentationalChildren)({ el }));
91
+ }
92
+ if (el.rule.options.checkingInteractionInHidden) {
93
+ report((0, interaction_in_hidden_1.checkingInteractionInHidden)({ el }));
84
94
  }
85
95
  });
86
96
  },
@@ -1,9 +1,11 @@
1
1
  import type { ARIAVersion } from '@markuplint/ml-spec';
2
- export declare type Options = {
2
+ export type Options = {
3
3
  checkingValue: boolean;
4
4
  checkingDeprecatedProps: boolean;
5
5
  permittedAriaRoles: boolean;
6
6
  checkingRequiredOwnedElements: boolean;
7
+ checkingPresentationalChildren: boolean;
8
+ checkingInteractionInHidden: boolean;
7
9
  disallowSetImplicitRole: boolean;
8
10
  disallowSetImplicitProps: boolean;
9
11
  disallowDefaultValue: boolean;
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.24+f55f5eff",
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,21 @@
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.24+f55f5eff",
24
+ "@markuplint/ml-core": "3.0.0-dev.24+f55f5eff",
25
+ "@markuplint/ml-spec": "3.0.0-dev.24+f55f5eff",
26
+ "@markuplint/types": "3.0.0-dev.24+f55f5eff",
27
+ "@ungap/structured-clone": "^1.0.1",
24
28
  "debug": "^4.3.4",
25
29
  "html-entities": "^2.3.3",
26
- "tslib": "^2.3.1"
30
+ "tslib": "^2.4.1"
27
31
  },
28
32
  "devDependencies": {
29
33
  "@types/debug": "^4.1.7"
30
34
  },
31
- "gitHead": "6cde113402758a8fdbd6a0fcf98e78efd2cdb778"
35
+ "gitHead": "f55f5eff289296feba26f20b0c085e0528c80ac4"
32
36
  }
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
  },