@markuplint/rules 2.4.2 → 3.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -5
- package/lib/attr-duplication/index.js +10 -7
- package/lib/attr-equal-space-after/index.d.ts +1 -1
- package/lib/attr-equal-space-before/index.d.ts +1 -1
- package/lib/attr-spacing/index.d.ts +3 -3
- package/lib/attr-value-quotes/index.js +21 -25
- package/lib/case-sensitive-attr-name/index.d.ts +1 -5
- package/lib/case-sensitive-attr-name/index.js +51 -81
- package/lib/case-sensitive-tag-name/index.js +38 -30
- package/lib/character-reference/index.d.ts +2 -1
- package/lib/character-reference/index.js +6 -8
- package/lib/class-naming/index.js +11 -11
- package/lib/deprecated-attr/index.js +17 -18
- package/lib/deprecated-element/index.js +5 -7
- package/lib/disallowed-element/index.js +8 -9
- package/lib/doctype/index.js +7 -7
- package/lib/end-tag/index.js +4 -1
- package/lib/helper/aria/get-aria.d.ts +7 -0
- package/lib/helper/aria/get-aria.js +53 -0
- package/lib/helper/aria/get-computed-role.d.ts +10 -0
- package/lib/helper/aria/get-computed-role.js +24 -0
- package/lib/helper/aria/get-implicit-role.d.ts +7 -0
- package/lib/helper/aria/get-implicit-role.js +12 -0
- package/lib/helper/aria/get-permitted-roles.d.ts +14 -0
- package/lib/helper/aria/get-permitted-roles.js +26 -0
- package/lib/helper/aria/resolve-version.d.ts +2 -0
- package/lib/helper/aria/resolve-version.js +21 -0
- package/lib/helper/spec/aria-spec.d.ts +5 -0
- package/lib/helper/spec/aria-spec.js +12 -0
- package/lib/helper/spec/get-role-spec.d.ts +11 -0
- package/lib/helper/spec/get-role-spec.js +39 -0
- package/lib/helper/spec/html-spec.d.ts +2 -0
- package/lib/helper/spec/html-spec.js +14 -0
- package/lib/helpers.d.ts +10 -28
- package/lib/helpers.js +29 -149
- package/lib/id-duplication/index.js +4 -6
- package/lib/indentation/index.d.ts +3 -3
- package/lib/index.d.ts +14 -19
- package/lib/index.js +0 -8
- package/lib/ineffective-attr/index.js +19 -27
- package/lib/invalid-attr/index.js +83 -83
- package/lib/landmark-roles/index.d.ts +2 -2
- package/lib/landmark-roles/index.js +9 -9
- package/lib/no-boolean-attr-value/index.js +33 -34
- package/lib/no-default-value/index.js +20 -24
- package/lib/no-hard-code-id/index.js +9 -13
- package/lib/no-refer-to-non-existent-id/index.d.ts +4 -1
- package/lib/no-refer-to-non-existent-id/index.js +77 -83
- package/lib/no-use-event-handler-attr/index.js +20 -22
- package/lib/permitted-contents/index.d.ts +5 -2
- package/lib/permitted-contents/index.js +67 -68
- package/lib/permitted-contents/permitted-content.spec-to-regexp.d.ts +5 -5
- package/lib/permitted-contents/permitted-content.spec-to-regexp.js +19 -14
- package/lib/permitted-contents/unfold-content-models-to-tags.d.ts +2 -2
- package/lib/require-accessible-name/index.d.ts +5 -1
- package/lib/require-accessible-name/index.js +6 -3
- package/lib/required-attr/index.js +16 -25
- package/lib/required-element/index.d.ts +1 -1
- package/lib/required-element/index.js +6 -6
- package/lib/required-h1/index.d.ts +2 -2
- package/lib/required-h1/index.js +3 -3
- package/lib/wai-aria/checkings/abstract-role.d.ts +3 -0
- package/lib/wai-aria/checkings/abstract-role.js +22 -0
- package/lib/wai-aria/checkings/checking-required-owned-elements.d.ts +11 -0
- package/lib/wai-aria/checkings/checking-required-owned-elements.js +63 -0
- package/lib/wai-aria/checkings/default-value.d.ts +6 -0
- package/lib/wai-aria/checkings/default-value.js +17 -0
- package/lib/wai-aria/checkings/deprecated-props.d.ts +7 -0
- package/lib/wai-aria/checkings/deprecated-props.js +18 -0
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +7 -0
- package/lib/wai-aria/checkings/disallowed-prop.js +22 -0
- package/lib/wai-aria/checkings/implicit-props.d.ts +7 -0
- package/lib/wai-aria/checkings/implicit-props.js +50 -0
- package/lib/wai-aria/checkings/implicit-role.d.ts +3 -0
- package/lib/wai-aria/checkings/implicit-role.js +21 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +11 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.js +47 -0
- package/lib/wai-aria/checkings/no-global-prop.d.ts +6 -0
- package/lib/wai-aria/checkings/no-global-prop.js +14 -0
- package/lib/wai-aria/checkings/non-existant-role.d.ts +3 -0
- package/lib/wai-aria/checkings/non-existant-role.js +28 -0
- package/lib/wai-aria/checkings/permitted-roles.d.ts +3 -0
- package/lib/wai-aria/checkings/permitted-roles.js +28 -0
- package/lib/wai-aria/checkings/presentational-children.d.ts +29 -0
- package/lib/wai-aria/checkings/presentational-children.js +60 -0
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +11 -0
- package/lib/wai-aria/checkings/required-owned-elements.js +63 -0
- package/lib/wai-aria/checkings/required-prop.d.ts +9 -0
- package/lib/wai-aria/checkings/required-prop.js +27 -0
- package/lib/wai-aria/checkings/value.d.ts +7 -0
- package/lib/wai-aria/checkings/value.js +21 -0
- package/lib/wai-aria/index.d.ts +1 -8
- package/lib/wai-aria/index.js +66 -207
- package/lib/wai-aria/types.d.ts +13 -0
- package/lib/wai-aria/types.js +2 -0
- package/package.json +6 -6
- package/schema.json +0 -12
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function unfoldContentModelsToTags(contentModel:
|
|
1
|
+
import type { Category } from '@markuplint/ml-spec';
|
|
2
|
+
export default function unfoldContentModelsToTags(contentModel: Category): string[];
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ARIAVersion } from '@markuplint/ml-spec';
|
|
2
|
+
declare type Option = {
|
|
3
|
+
ariaVersion: ARIAVersion;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Option>;
|
|
2
6
|
export default _default;
|
|
@@ -3,16 +3,19 @@ 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
|
exports.default = (0, ml_core_1.createRule)({
|
|
6
|
+
defaultOptions: {
|
|
7
|
+
ariaVersion: '1.2',
|
|
8
|
+
},
|
|
6
9
|
async verify({ document, report, t }) {
|
|
7
10
|
await document.walkOn('Element', el => {
|
|
8
11
|
if ((0, helpers_1.accnameMayBeMutable)(el, document)) {
|
|
9
12
|
return;
|
|
10
13
|
}
|
|
11
|
-
const
|
|
12
|
-
if (!role) {
|
|
14
|
+
const computed = (0, ml_core_1.getComputedRole)(document.specs, el, el.rule.option.ariaVersion);
|
|
15
|
+
if (!computed.role) {
|
|
13
16
|
return;
|
|
14
17
|
}
|
|
15
|
-
const roleSpec = (0,
|
|
18
|
+
const roleSpec = (0, ml_core_1.getRoleSpec)(document.specs, computed.role.name, el.namespaceURI, el.rule.option.ariaVersion);
|
|
16
19
|
if (!roleSpec || !roleSpec.accessibleNameRequired) {
|
|
17
20
|
return;
|
|
18
21
|
}
|
|
@@ -5,15 +5,14 @@ const helpers_1 = require("../helpers");
|
|
|
5
5
|
exports.default = (0, ml_core_1.createRule)({
|
|
6
6
|
defaultValue: [],
|
|
7
7
|
async verify({ document, report, t }) {
|
|
8
|
-
await document.walkOn('Element',
|
|
9
|
-
|
|
10
|
-
if (node.hasSpreadAttr) {
|
|
8
|
+
await document.walkOn('Element', el => {
|
|
9
|
+
if (el.hasSpreadAttr) {
|
|
11
10
|
return;
|
|
12
11
|
}
|
|
13
|
-
const customRequiredAttrs = typeof
|
|
14
|
-
const attrSpec = (0, ml_core_1.getAttrSpecs)(
|
|
12
|
+
const customRequiredAttrs = typeof el.rule.value === 'string' ? [el.rule.value] : el.rule.value;
|
|
13
|
+
const attrSpec = (0, ml_core_1.getAttrSpecs)(el, document.specs);
|
|
15
14
|
const attributeSpecs = {};
|
|
16
|
-
if (attrSpec && !
|
|
15
|
+
if (attrSpec && !el.isCustomElement) {
|
|
17
16
|
for (const spec of attrSpec) {
|
|
18
17
|
if (spec.required || spec.requiredEither || spec.condition) {
|
|
19
18
|
attributeSpecs[spec.name] = {
|
|
@@ -45,46 +44,38 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
45
44
|
};
|
|
46
45
|
}
|
|
47
46
|
for (const spec of Object.values(attributeSpecs)) {
|
|
48
|
-
const didntHave = !
|
|
47
|
+
const didntHave = !el.hasAttribute(spec.name);
|
|
49
48
|
let invalid = false;
|
|
50
49
|
if (spec.requiredEither) {
|
|
51
50
|
const candidate = [...spec.requiredEither, spec.name];
|
|
52
|
-
invalid = !candidate.some(attrName =>
|
|
51
|
+
invalid = !candidate.some(attrName => el.hasAttribute(attrName));
|
|
53
52
|
}
|
|
54
53
|
else if (spec.required === true) {
|
|
55
|
-
invalid = (0, helpers_1.attrMatches)(
|
|
54
|
+
invalid = (0, helpers_1.attrMatches)(el, spec.condition) && didntHave;
|
|
56
55
|
}
|
|
57
56
|
else if (spec.required) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
? spec.required.ancestor
|
|
61
|
-
: [spec.required.ancestor];
|
|
62
|
-
const ancestors = ancestorList
|
|
63
|
-
.join(',')
|
|
64
|
-
.split(',')
|
|
65
|
-
.map(a => a.trim());
|
|
66
|
-
invalid = ancestors.some(a => node.closest(a)) && didntHave;
|
|
67
|
-
}
|
|
57
|
+
const selector = Array.isArray(spec.required) ? spec.required.join(',') : spec.required;
|
|
58
|
+
invalid = el.matches(selector) && didntHave;
|
|
68
59
|
}
|
|
69
60
|
if (invalid) {
|
|
70
|
-
const message = t('{0} expects {1}', t('the "{0*}" {1}',
|
|
61
|
+
const message = t('{0} expects {1}', t('the "{0*}" {1}', el.localName, 'element'), t('the "{0*}" {1}', spec.name, 'attribute'));
|
|
71
62
|
report({
|
|
72
|
-
scope:
|
|
63
|
+
scope: el,
|
|
73
64
|
message,
|
|
74
65
|
});
|
|
75
66
|
}
|
|
76
|
-
const value =
|
|
67
|
+
const value = el.getAttribute(spec.name);
|
|
77
68
|
if (spec.values.length && value) {
|
|
78
69
|
const matched = spec.values.some(pattern => (0, helpers_1.match)(value, pattern));
|
|
79
70
|
if (!matched) {
|
|
80
71
|
const expects = spec.values.length === 1 ? t(spec.values) : t('either {0}', t(spec.values));
|
|
81
72
|
const message = t('{0} expects {1}', t('the "{0*}" {1}', spec.name, 'attribute'), expects);
|
|
82
|
-
const attrToken =
|
|
83
|
-
const valueToken =
|
|
73
|
+
const attrToken = el.getAttributeToken(spec.name);
|
|
74
|
+
const valueToken = attrToken[0].valueNode;
|
|
84
75
|
const token = valueToken || attrToken[0];
|
|
85
76
|
report({
|
|
86
77
|
scope: {
|
|
87
|
-
rule:
|
|
78
|
+
rule: el.rule,
|
|
88
79
|
raw: token.raw,
|
|
89
80
|
startCol: token.startCol,
|
|
90
81
|
startLine: token.startLine,
|
|
@@ -6,11 +6,11 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
6
6
|
defaultOptions: {
|
|
7
7
|
ignoreHasMutableContents: true,
|
|
8
8
|
},
|
|
9
|
-
async verify({ document, report, t
|
|
10
|
-
const hasMutableContent = document.nodeList.some(n =>
|
|
9
|
+
async verify({ document, report, t }) {
|
|
10
|
+
const hasMutableContent = document.nodeList.some(n => n.is(n.ELEMENT_NODE) && n.hasMutableChildren());
|
|
11
11
|
if (!hasMutableContent) {
|
|
12
|
-
for (const query of
|
|
13
|
-
const exists = document.
|
|
12
|
+
for (const query of document.rule.value) {
|
|
13
|
+
const exists = document.querySelectorAll(query);
|
|
14
14
|
if (exists.length === 0) {
|
|
15
15
|
const message = t('Require {0}', t('the "{0*}" {1}', query, 'element'));
|
|
16
16
|
report({
|
|
@@ -23,14 +23,14 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
await document.walkOn('Element', el => {
|
|
26
|
-
if (el.rule.value ===
|
|
26
|
+
if (el.rule.value === document.rule.value) {
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
if (el.rule.option.ignoreHasMutableContents && el.hasMutableChildren()) {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
for (const query of el.rule.value) {
|
|
33
|
-
const exists = el.children.find(child => child.matches(query));
|
|
33
|
+
const exists = Array.from(el.children).find(child => child.matches(query));
|
|
34
34
|
if (!exists) {
|
|
35
35
|
const message = t('Require {0}', t('the "{0*}" {1}', query, 'element'));
|
|
36
36
|
report({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export interface Options {
|
|
2
|
-
'expected-once'
|
|
3
|
-
'in-document-fragment'
|
|
2
|
+
'expected-once': boolean;
|
|
3
|
+
'in-document-fragment': boolean;
|
|
4
4
|
}
|
|
5
5
|
declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Options>;
|
|
6
6
|
export default _default;
|
package/lib/required-h1/index.js
CHANGED
|
@@ -6,12 +6,12 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
6
6
|
'expected-once': true,
|
|
7
7
|
'in-document-fragment': false,
|
|
8
8
|
},
|
|
9
|
-
async verify({ document, report,
|
|
9
|
+
async verify({ document, report, t }) {
|
|
10
10
|
const h1Stack = [];
|
|
11
11
|
if (document.nodeList.length === 0) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
|
-
if (!
|
|
14
|
+
if (!document.rule.option['in-document-fragment'] && document.isFragment) {
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
await document.walkOn('Element', node => {
|
|
@@ -28,7 +28,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
28
28
|
raw: document.nodeList[0].raw.slice(0, 1),
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
else if (
|
|
31
|
+
else if (document.rule.option['expected-once'] && h1Stack.length > 1) {
|
|
32
32
|
const message = t('{0} is {1:c}', t('the "{0*}" {1}', 'h1', 'element'), 'duplicated');
|
|
33
33
|
report({
|
|
34
34
|
message,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingAbstractRole = void 0;
|
|
4
|
+
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
|
+
const checkingAbstractRole = ({ attr }) => t => {
|
|
6
|
+
var _a;
|
|
7
|
+
const { roles } = (0, ml_spec_1.ariaSpecs)(attr.ownerMLDocument.specs, attr.rule.option.version);
|
|
8
|
+
const tokens = (_a = attr.tokenList) === null || _a === void 0 ? void 0 : _a.allTokens();
|
|
9
|
+
if (!tokens) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (const token of tokens) {
|
|
13
|
+
const role = roles.find(r => r.name === token.raw);
|
|
14
|
+
if (role === null || role === void 0 ? void 0 : role.isAbstract) {
|
|
15
|
+
return {
|
|
16
|
+
scope: token,
|
|
17
|
+
message: t('{0} is {1}', t('the "{0*}" {1}', token.raw, 'role'), 'the abstract role'),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
exports.checkingAbstractRole = checkingAbstractRole;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Options } from '../types';
|
|
2
|
+
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
|
+
import type { ARIARole } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Required Owned Elements
|
|
6
|
+
*
|
|
7
|
+
* @see https://w3c.github.io/aria/#mustContain
|
|
8
|
+
*/
|
|
9
|
+
export declare const checkingRequiredOwnedElements: ElementChecker<boolean, Options, {
|
|
10
|
+
role?: ARIARole | null;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
if (!el.children.length) {
|
|
32
|
+
return {
|
|
33
|
+
scope: el,
|
|
34
|
+
message: t('{0}. Or, {1}', t('Require {0} to content', t('the {0*} {1}', t(role.requiredOwnedElements), 'role')), t('require {0}', 'aria-busy="true"')),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const children = Array.from(el.childNodes).map(child => {
|
|
38
|
+
if (child.is(child.ELEMENT_NODE)) {
|
|
39
|
+
const computedChild = (0, ml_spec_1.getComputedRole)(child.ownerMLDocument.specs, child, child.rule.option.version);
|
|
40
|
+
if (role.requiredOwnedElements.some(ownedRole => (0, ml_spec_1.isRequiredOwnedElement)(computedChild, ownedRole, child.ownerMLDocument.specs, child.rule.option.version))) {
|
|
41
|
+
return 'REQUIRED';
|
|
42
|
+
}
|
|
43
|
+
return 'OTHER';
|
|
44
|
+
}
|
|
45
|
+
else if (child.MARKUPLINT_PREPROCESSOR_BLOCK) {
|
|
46
|
+
return 'PB';
|
|
47
|
+
}
|
|
48
|
+
return 'NO_ELEMENT';
|
|
49
|
+
});
|
|
50
|
+
if (children.includes('PB')) {
|
|
51
|
+
return {
|
|
52
|
+
scope: el,
|
|
53
|
+
message: t('{0} expects {1}', t('the "{0*}" {1}', role.name, 'role'), t(role.requiredContextRole.map(ownedRole => t('the "{0*}" {1}', ownedRole, 'role')))),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!children.includes('REQUIRED')) {
|
|
57
|
+
return {
|
|
58
|
+
scope: el,
|
|
59
|
+
message: t('{0} expects {1}', t('the "{0*}" {1}', role.name, 'role'), t('the {0*} {1}', t(role.requiredOwnedElements), 'roles')),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
exports.checkingRequiredOwnedElements = checkingRequiredOwnedElements;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingDefaultValue = void 0;
|
|
4
|
+
const checkingDefaultValue = ({ attr, propSpecs }) => t => {
|
|
5
|
+
if (attr.isDynamicValue) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const propSpec = propSpecs.find(p => p.name === attr.name);
|
|
9
|
+
const value = attr.value.trim().toLowerCase();
|
|
10
|
+
if ((propSpec === null || propSpec === void 0 ? void 0 : propSpec.defaultValue) != null && propSpec.defaultValue === value) {
|
|
11
|
+
return {
|
|
12
|
+
scope: attr,
|
|
13
|
+
message: t('It is {0}', 'default value'),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
exports.checkingDefaultValue = checkingDefaultValue;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Options } from '../types';
|
|
2
|
+
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
+
export declare const checkingDeprecatedProps: AttrChecker<boolean, Options, {
|
|
5
|
+
role: ARIARole | null;
|
|
6
|
+
propSpecs: ARIAProperty[];
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingDeprecatedProps = void 0;
|
|
4
|
+
const checkingDeprecatedProps = ({ attr, role, propSpecs }) => t => {
|
|
5
|
+
var _a;
|
|
6
|
+
if (!role) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const props = role.ownedProperties.find(p => p.name === attr.name);
|
|
10
|
+
if (props === null || props === void 0 ? void 0 : props.deprecated) {
|
|
11
|
+
const propSpec = propSpecs.find(p => p.name === attr.name);
|
|
12
|
+
return {
|
|
13
|
+
scope: attr,
|
|
14
|
+
message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0*}" {1}', attr.name, `ARIA ${(_a = propSpec === null || propSpec === void 0 ? void 0 : propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`), 'deprecated'), t('the "{0*}" {1}', role.name, 'role')),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
exports.checkingDeprecatedProps = checkingDeprecatedProps;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Options } from '../types';
|
|
2
|
+
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
+
export declare const checkingDisallowedProp: AttrChecker<boolean, Options, {
|
|
5
|
+
role: ARIARole | null;
|
|
6
|
+
propSpecs: ARIAProperty[];
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingDisallowedProp = void 0;
|
|
4
|
+
const checkingDisallowedProp = ({ attr, role, propSpecs }) => t => {
|
|
5
|
+
var _a;
|
|
6
|
+
if (!role) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (!/^aria-/i.test(attr.name)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const statesAndProp = role.ownedProperties.find(p => p.name === attr.name);
|
|
13
|
+
if (statesAndProp) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const propSpec = propSpecs.find(p => p.name === attr.name);
|
|
17
|
+
return {
|
|
18
|
+
scope: attr,
|
|
19
|
+
message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0*}" {1}', attr.name, `ARIA ${(_a = propSpec === null || propSpec === void 0 ? void 0 : propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`), 'disallowed'), t('the "{0*}" {1}', role.name, 'role')),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.checkingDisallowedProp = checkingDisallowedProp;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Options } from '../types';
|
|
2
|
+
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
import type { ARIAProperty, Attribute } from '@markuplint/ml-spec';
|
|
4
|
+
export declare const checkingImplicitProps: AttrChecker<boolean, Options, {
|
|
5
|
+
propSpecs: ARIAProperty[];
|
|
6
|
+
attrSpecs: Attribute[] | null;
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingImplicitProps = void 0;
|
|
4
|
+
const helpers_1 = require("../../helpers");
|
|
5
|
+
const checkingImplicitProps = ({ attr, propSpecs, attrSpecs }) => t => {
|
|
6
|
+
if (!attrSpecs) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (attr.isDynamicValue) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const propSpec = propSpecs.find(p => p.name === attr.name);
|
|
13
|
+
if (!(propSpec === null || propSpec === void 0 ? void 0 : propSpec.equivalentHtmlAttrs)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
for (const equivalentHtmlAttr of propSpec.equivalentHtmlAttrs) {
|
|
17
|
+
const htmlAttrSpec = attrSpecs.find(a => a.name === equivalentHtmlAttr.htmlAttrName);
|
|
18
|
+
const isValid = (0, helpers_1.isValidAttr)(t, equivalentHtmlAttr.htmlAttrName, equivalentHtmlAttr.value || '', false, attr.ownerElement, attrSpecs);
|
|
19
|
+
if (isValid && isValid.invalidType === 'non-existent') {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const value = attr.value.trim().toLowerCase();
|
|
23
|
+
if (attr.ownerElement.hasAttribute(equivalentHtmlAttr.htmlAttrName)) {
|
|
24
|
+
const targetAttrValue = attr.ownerElement.getAttribute(equivalentHtmlAttr.htmlAttrName);
|
|
25
|
+
if ((equivalentHtmlAttr.value == null && targetAttrValue === value) ||
|
|
26
|
+
equivalentHtmlAttr.value === value) {
|
|
27
|
+
return {
|
|
28
|
+
scope: attr,
|
|
29
|
+
message: t('{0} has {1}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec.type}`), t('the same {0} as {1}', 'semantics', t('{0} or {1}', t('the current "{0}" {1}', equivalentHtmlAttr.htmlAttrName, 'attribute'), t('the implicit "{0}" {1}', equivalentHtmlAttr.htmlAttrName, 'attribute')))),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if ((htmlAttrSpec === null || htmlAttrSpec === void 0 ? void 0 : htmlAttrSpec.type) === 'Boolean' && value !== 'false') {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
scope: attr,
|
|
37
|
+
message: t('{0} contradicts {1}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec.type}`), t('the current "{0}" {1}', equivalentHtmlAttr.htmlAttrName, 'attribute')),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
else if (value === 'true') {
|
|
41
|
+
if (!equivalentHtmlAttr.isNotStrictEquivalent && (htmlAttrSpec === null || htmlAttrSpec === void 0 ? void 0 : htmlAttrSpec.type) === 'Boolean') {
|
|
42
|
+
return {
|
|
43
|
+
scope: attr,
|
|
44
|
+
message: t('{0} contradicts {1}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec.type}`), t('the implicit "{0}" {1}', equivalentHtmlAttr.htmlAttrName, 'attribute')),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.checkingImplicitProps = checkingImplicitProps;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingImplicitRole = void 0;
|
|
4
|
+
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
|
+
const checkingImplicitRole = ({ attr }) => t => {
|
|
6
|
+
var _a;
|
|
7
|
+
const implictRole = (0, ml_spec_1.getImplicitRoleName)(attr.ownerElement, attr.rule.option.version, attr.ownerMLDocument.specs);
|
|
8
|
+
const tokens = (_a = attr.tokenList) === null || _a === void 0 ? void 0 : _a.allTokens();
|
|
9
|
+
if (!tokens) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (const token of tokens) {
|
|
13
|
+
if (implictRole === token.raw) {
|
|
14
|
+
return {
|
|
15
|
+
scope: token,
|
|
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'))),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.checkingImplicitRole = checkingImplicitRole;
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingNoGlobalProp = void 0;
|
|
4
|
+
const checkingNoGlobalProp = ({ attr, propSpecs }) => t => {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const propSpec = propSpecs.find(prop => prop.name === attr.name);
|
|
7
|
+
if (propSpec && !propSpec.isGlobal) {
|
|
8
|
+
return {
|
|
9
|
+
scope: attr,
|
|
10
|
+
message: t('{0} is not {1}', t('the "{0*}" {1}', attr.name, `ARIA ${(_a = propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`), `global ${(_b = propSpec.type) !== null && _b !== void 0 ? _b : 'property'}`),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
exports.checkingNoGlobalProp = checkingNoGlobalProp;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingNonExistantRole = void 0;
|
|
4
|
+
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
|
+
const checkingNonExistantRole = ({ attr }) => t => {
|
|
6
|
+
var _a;
|
|
7
|
+
const { roles, graphicsRoles } = (0, ml_spec_1.ariaSpecs)(attr.ownerMLDocument.specs, attr.rule.option.version);
|
|
8
|
+
const tokens = (_a = attr.tokenList) === null || _a === void 0 ? void 0 : _a.allTokens();
|
|
9
|
+
if (!tokens) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (const token of tokens) {
|
|
13
|
+
let role = roles.find(r => r.name === token.raw);
|
|
14
|
+
if (!role && attr.ownerElement.namespaceURI === 'http://www.w3.org/2000/svg') {
|
|
15
|
+
role = graphicsRoles.find(r => r.name === token.raw);
|
|
16
|
+
}
|
|
17
|
+
if (!role) {
|
|
18
|
+
return {
|
|
19
|
+
scope: token,
|
|
20
|
+
message: t('{0} according to {1}', t('{0} does not exist', t('the "{0*}" {1}', token.raw, 'role')), 'the WAI-ARIA specification') +
|
|
21
|
+
t('.') +
|
|
22
|
+
// TODO: Translate
|
|
23
|
+
` This "${token.raw}" role does not exist in WAI-ARIA.`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.checkingNonExistantRole = checkingNonExistantRole;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkingPermittedRoles = void 0;
|
|
4
|
+
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
|
+
const checkingPermittedRoles = ({ attr }) => t => {
|
|
6
|
+
var _a;
|
|
7
|
+
const el = attr.ownerElement;
|
|
8
|
+
const permittedRoles = (0, ml_spec_1.getPermittedRoles)(el, el.rule.option.version, attr.ownerMLDocument.specs);
|
|
9
|
+
if (permittedRoles.length === 0) {
|
|
10
|
+
return {
|
|
11
|
+
scope: attr,
|
|
12
|
+
message: t('{0} according to {1}', t('Cannot overwrite {0}', t('{0} of {1}', t('the {0}', 'role'), t('the "{0*}" {1}', el.localName, 'element'))), 'ARIA in HTML specification'),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const tokens = (_a = attr.tokenList) === null || _a === void 0 ? void 0 : _a.allTokens();
|
|
16
|
+
if (!tokens) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const token of tokens) {
|
|
20
|
+
if (Array.isArray(permittedRoles) && !permittedRoles.map(r => r.name).includes(token.raw)) {
|
|
21
|
+
return {
|
|
22
|
+
scope: token,
|
|
23
|
+
message: t('{0} according to {1}', t('Cannot overwrite {0} to {1}', t('the "{0*}" {1}', token.raw, 'role'), t('the "{0*}" {1}', el.localName, 'element')), 'ARIA in HTML specification'),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.checkingPermittedRoles = checkingPermittedRoles;
|