@markuplint/rules 2.0.0-dev.23 → 2.0.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/attr-check.d.ts +8 -1
- package/lib/attr-check.js +53 -455
- package/lib/attr-duplication/index.d.ts +1 -1
- package/lib/attr-duplication/index.js +0 -2
- package/lib/attr-equal-space-after/index.js +0 -1
- package/lib/attr-equal-space-before/index.js +0 -1
- package/lib/attr-spacing/index.js +0 -1
- package/lib/attr-value-quotes/index.js +0 -1
- package/lib/case-sensitive-attr-name/index.d.ts +6 -2
- package/lib/case-sensitive-attr-name/index.js +30 -8
- package/lib/case-sensitive-tag-name/index.js +0 -1
- package/lib/character-reference/index.d.ts +1 -2
- package/lib/character-reference/index.js +0 -2
- package/lib/class-naming/index.js +23 -23
- package/lib/create-message.d.ts +5 -0
- package/lib/create-message.js +270 -0
- package/lib/debug.d.ts +3 -0
- package/lib/debug.js +6 -0
- package/lib/deprecated-attr/index.d.ts +1 -1
- package/lib/deprecated-attr/index.js +2 -5
- package/lib/deprecated-element/index.d.ts +1 -1
- package/lib/deprecated-element/index.js +1 -3
- package/lib/disallowed-element/index.d.ts +2 -0
- package/lib/disallowed-element/index.js +34 -0
- package/lib/helpers.d.ts +15 -9
- package/lib/helpers.js +63 -68
- package/lib/id-duplication/index.d.ts +1 -1
- package/lib/id-duplication/index.js +1 -3
- package/lib/index.d.ts +28 -11
- package/lib/index.js +16 -0
- package/lib/ineffective-attr/index.d.ts +2 -0
- package/lib/ineffective-attr/index.js +40 -0
- package/lib/invalid-attr/index.d.ts +4 -2
- package/lib/invalid-attr/index.js +25 -9
- package/lib/landmark-roles/index.js +1 -2
- package/lib/no-boolean-attr-value/index.d.ts +2 -0
- package/lib/no-boolean-attr-value/index.js +47 -0
- package/lib/no-default-value/index.d.ts +2 -0
- package/lib/no-default-value/index.js +38 -0
- package/lib/no-hard-code-id/index.d.ts +2 -0
- package/lib/no-hard-code-id/index.js +27 -0
- package/lib/no-refer-to-non-existent-id/index.d.ts +2 -0
- package/lib/no-refer-to-non-existent-id/index.js +110 -0
- package/lib/no-use-event-handler-attr/index.d.ts +5 -0
- package/lib/no-use-event-handler-attr/index.js +37 -0
- package/lib/permitted-contents/index.js +24 -13
- package/lib/permitted-contents/types.d.ts +8 -0
- package/lib/permitted-contents/types.js +2 -0
- package/lib/require-element/index.d.ts +2 -0
- package/lib/require-element/index.js +38 -0
- package/lib/required-attr/index.d.ts +5 -1
- package/lib/required-attr/index.js +60 -19
- package/lib/required-element/index.d.ts +5 -0
- package/lib/required-element/index.js +44 -0
- package/lib/required-h1/index.d.ts +2 -3
- package/lib/required-h1/index.js +2 -3
- package/lib/wai-aria/index.d.ts +1 -1
- package/lib/wai-aria/index.js +23 -24
- package/package.json +10 -5
- package/schema.json +24 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/primitive-check.d.ts +0 -48
- package/lib/primitive-check.js +0 -109
package/lib/helpers.js
CHANGED
|
@@ -1,45 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkAria = exports.checkAriaValue = exports.getComputedRole = exports.getImplicitRole = exports.getPermittedRoles = exports.getRoleSpec = exports.ariaSpec = exports.isValidAttr = exports.htmlSpec = exports.rePCENChar = exports.match = exports.attrMatches =
|
|
4
|
-
const html_spec_1 = require("@markuplint/html-spec");
|
|
3
|
+
exports.checkAria = exports.checkAriaValue = exports.getComputedRole = exports.getImplicitRole = exports.getPermittedRoles = exports.getRoleSpec = exports.ariaSpec = exports.toNormalizedValue = exports.isValidAttr = exports.htmlSpec = exports.rePCENChar = exports.match = exports.attrMatches = void 0;
|
|
5
4
|
const attr_check_1 = require("./attr-check");
|
|
6
|
-
function getAttrSpecs(nameWithNS, { specs, def }) {
|
|
7
|
-
const spec = specs.find(spec => spec.name === nameWithNS);
|
|
8
|
-
if (!spec) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
const globalAttrs = def['#globalAttrs'];
|
|
12
|
-
const attrs = [];
|
|
13
|
-
if (!/[a-z]:[a-z]/i.test(nameWithNS)) {
|
|
14
|
-
// It's HTML tag
|
|
15
|
-
const hasGlobalAttr = spec.attributes.some(attr => attr === '#globalAttrs');
|
|
16
|
-
if (hasGlobalAttr) {
|
|
17
|
-
attrs.push(...(globalAttrs['#HTMLGlobalAttrs'] || []));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
for (const attr of spec.attributes) {
|
|
21
|
-
if (typeof attr === 'string') {
|
|
22
|
-
const globalAttr = globalAttrs[attr];
|
|
23
|
-
if (!globalAttr) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
attrs.push(...globalAttr);
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const definedIndex = attrs.findIndex(a => a.name === attr.name);
|
|
30
|
-
if (definedIndex !== -1) {
|
|
31
|
-
attrs[definedIndex] = {
|
|
32
|
-
...attrs[definedIndex],
|
|
33
|
-
...attr,
|
|
34
|
-
};
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
attrs.push(attr);
|
|
38
|
-
}
|
|
39
|
-
attrs.push(...(globalAttrs['#extends'] || []));
|
|
40
|
-
return attrs;
|
|
41
|
-
}
|
|
42
|
-
exports.getAttrSpecs = getAttrSpecs;
|
|
43
5
|
function attrMatches(node, condition) {
|
|
44
6
|
if (!condition) {
|
|
45
7
|
return true;
|
|
@@ -53,7 +15,10 @@ function attrMatches(node, condition) {
|
|
|
53
15
|
let _node = node.parentNode;
|
|
54
16
|
while (_node) {
|
|
55
17
|
if (_node.type === 'Element') {
|
|
56
|
-
|
|
18
|
+
const condSelector = Array.isArray(condition.ancestor)
|
|
19
|
+
? condition.ancestor.join(',')
|
|
20
|
+
: condition.ancestor;
|
|
21
|
+
if (_node.matches(condSelector)) {
|
|
57
22
|
matched = true;
|
|
58
23
|
break;
|
|
59
24
|
}
|
|
@@ -109,19 +74,20 @@ exports.rePCENChar = [
|
|
|
109
74
|
'[\uFDF0-\uFFFD]',
|
|
110
75
|
'[\uD800-\uDBFF][\uDC00-\uDFFF]',
|
|
111
76
|
].join('|');
|
|
112
|
-
function htmlSpec(nameWithNS) {
|
|
113
|
-
const spec =
|
|
77
|
+
function htmlSpec(specs, nameWithNS) {
|
|
78
|
+
const spec = specs.specs.find(spec => spec.name === nameWithNS);
|
|
114
79
|
return spec || null;
|
|
115
80
|
}
|
|
116
81
|
exports.htmlSpec = htmlSpec;
|
|
117
|
-
function isValidAttr(t, name, value, isDynamicValue, node, attrSpecs) {
|
|
82
|
+
function isValidAttr(t, name, value, isDynamicValue, node, attrSpecs, log) {
|
|
118
83
|
let invalid = false;
|
|
119
|
-
const spec = attrSpecs.find(s => s.name === name);
|
|
84
|
+
const spec = attrSpecs.find(s => s.name.toLowerCase() === name.toLowerCase());
|
|
85
|
+
log && log('Spec of the %s attr: %o', name, spec);
|
|
120
86
|
invalid = (0, attr_check_1.attrCheck)(t, name, value, false, spec);
|
|
121
87
|
if (!invalid && spec && spec.condition && !node.hasSpreadAttr && !attrMatches(node, spec.condition)) {
|
|
122
88
|
invalid = {
|
|
123
89
|
invalidType: 'non-existent',
|
|
124
|
-
message: t('{0} is {1}', t('the "{0}" {1}', name, 'attribute'), 'disallowed'),
|
|
90
|
+
message: t('{0} is {1}', t('the "{0*}" {1}', name, 'attribute'), 'disallowed'),
|
|
125
91
|
};
|
|
126
92
|
}
|
|
127
93
|
if (invalid && invalid.invalidType === 'invalid-value' && isDynamicValue) {
|
|
@@ -130,21 +96,50 @@ function isValidAttr(t, name, value, isDynamicValue, node, attrSpecs) {
|
|
|
130
96
|
return invalid;
|
|
131
97
|
}
|
|
132
98
|
exports.isValidAttr = isValidAttr;
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
99
|
+
function toNormalizedValue(value, spec) {
|
|
100
|
+
let normalized = value;
|
|
101
|
+
if (!spec.caseSensitive) {
|
|
102
|
+
normalized = normalized.toLowerCase();
|
|
103
|
+
}
|
|
104
|
+
if (typeof spec.type === 'string') {
|
|
105
|
+
if (spec.type[0] === '<') {
|
|
106
|
+
normalized = normalized.toLowerCase().trim().replace(/\s+/g, ' ');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if ('token' in spec.type) {
|
|
111
|
+
if (spec.type.caseInsensitive) {
|
|
112
|
+
normalized = normalized.toLowerCase();
|
|
113
|
+
}
|
|
114
|
+
if (!spec.type.disallowToSurroundBySpaces) {
|
|
115
|
+
normalized = normalized.trim();
|
|
116
|
+
}
|
|
117
|
+
if (spec.type.separator === 'space') {
|
|
118
|
+
normalized = normalized.replace(/\s+/g, ' ');
|
|
119
|
+
}
|
|
120
|
+
if (spec.type.separator === 'comma') {
|
|
121
|
+
normalized = normalized.replace(/\s*,\s*/g, ',');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return normalized;
|
|
126
|
+
}
|
|
127
|
+
exports.toNormalizedValue = toNormalizedValue;
|
|
128
|
+
function ariaSpec(specs) {
|
|
129
|
+
const roles = specs.def['#roles'];
|
|
130
|
+
const ariaAttrs = specs.def['#ariaAttrs'];
|
|
136
131
|
return {
|
|
137
132
|
roles,
|
|
138
133
|
ariaAttrs,
|
|
139
134
|
};
|
|
140
135
|
}
|
|
141
136
|
exports.ariaSpec = ariaSpec;
|
|
142
|
-
function getRoleSpec(roleName) {
|
|
143
|
-
const role = getRoleByName(roleName);
|
|
137
|
+
function getRoleSpec(specs, roleName) {
|
|
138
|
+
const role = getRoleByName(specs, roleName);
|
|
144
139
|
if (!role) {
|
|
145
140
|
return null;
|
|
146
141
|
}
|
|
147
|
-
const superClassRoles = recursiveTraverseSuperClassRoles(roleName);
|
|
142
|
+
const superClassRoles = recursiveTraverseSuperClassRoles(specs, roleName);
|
|
148
143
|
return {
|
|
149
144
|
name: role.name,
|
|
150
145
|
isAbstract: !!role.isAbstract,
|
|
@@ -153,22 +148,22 @@ function getRoleSpec(roleName) {
|
|
|
153
148
|
};
|
|
154
149
|
}
|
|
155
150
|
exports.getRoleSpec = getRoleSpec;
|
|
156
|
-
function getRoleByName(roleName) {
|
|
157
|
-
const roles =
|
|
151
|
+
function getRoleByName(specs, roleName) {
|
|
152
|
+
const roles = specs.def['#roles'];
|
|
158
153
|
const role = roles.find(r => r.name === roleName);
|
|
159
154
|
return role;
|
|
160
155
|
}
|
|
161
|
-
function getSuperClassRoles(roleName) {
|
|
162
|
-
const role = getRoleByName(roleName);
|
|
163
|
-
return ((role === null || role === void 0 ? void 0 : role.generalization.map(roleName => getRoleByName(roleName)).filter((role) => !!role)) || null);
|
|
156
|
+
function getSuperClassRoles(specs, roleName) {
|
|
157
|
+
const role = getRoleByName(specs, roleName);
|
|
158
|
+
return ((role === null || role === void 0 ? void 0 : role.generalization.map(roleName => getRoleByName(specs, roleName)).filter((role) => !!role)) || null);
|
|
164
159
|
}
|
|
165
|
-
function recursiveTraverseSuperClassRoles(roleName) {
|
|
160
|
+
function recursiveTraverseSuperClassRoles(specs, roleName) {
|
|
166
161
|
const roles = [];
|
|
167
|
-
const superClassRoles = getSuperClassRoles(roleName);
|
|
162
|
+
const superClassRoles = getSuperClassRoles(specs, roleName);
|
|
168
163
|
if (superClassRoles) {
|
|
169
164
|
roles.push(...superClassRoles);
|
|
170
165
|
for (const superClassRole of superClassRoles) {
|
|
171
|
-
const ancestorRoles = recursiveTraverseSuperClassRoles(superClassRole.name);
|
|
166
|
+
const ancestorRoles = recursiveTraverseSuperClassRoles(specs, superClassRole.name);
|
|
172
167
|
roles.push(...ancestorRoles);
|
|
173
168
|
}
|
|
174
169
|
}
|
|
@@ -181,10 +176,10 @@ function recursiveTraverseSuperClassRoles(roleName) {
|
|
|
181
176
|
* - If `true`, this mean is "Any".
|
|
182
177
|
* - If `false`, this mean is "No".
|
|
183
178
|
*/
|
|
184
|
-
function getPermittedRoles(el) {
|
|
179
|
+
function getPermittedRoles(specs, el) {
|
|
185
180
|
var _a;
|
|
186
|
-
const implicitRole = getImplicitRole(el);
|
|
187
|
-
const spec = (_a = htmlSpec(el.nodeName)) === null || _a === void 0 ? void 0 : _a.permittedRoles;
|
|
181
|
+
const implicitRole = getImplicitRole(specs, el);
|
|
182
|
+
const spec = (_a = htmlSpec(specs, el.nodeName)) === null || _a === void 0 ? void 0 : _a.permittedRoles;
|
|
188
183
|
if (!spec) {
|
|
189
184
|
return true;
|
|
190
185
|
}
|
|
@@ -213,9 +208,9 @@ function mergeRoleList(implicitRole, permittedRoles) {
|
|
|
213
208
|
}
|
|
214
209
|
return permittedRoles;
|
|
215
210
|
}
|
|
216
|
-
function getImplicitRole(el) {
|
|
211
|
+
function getImplicitRole(specs, el) {
|
|
217
212
|
var _a;
|
|
218
|
-
const implicitRole = (_a = htmlSpec(el.nodeName)) === null || _a === void 0 ? void 0 : _a.implicitRole;
|
|
213
|
+
const implicitRole = (_a = htmlSpec(specs, el.nodeName)) === null || _a === void 0 ? void 0 : _a.implicitRole;
|
|
219
214
|
if (!implicitRole) {
|
|
220
215
|
return false;
|
|
221
216
|
}
|
|
@@ -229,7 +224,7 @@ function getImplicitRole(el) {
|
|
|
229
224
|
return implicitRole.role;
|
|
230
225
|
}
|
|
231
226
|
exports.getImplicitRole = getImplicitRole;
|
|
232
|
-
function getComputedRole(el) {
|
|
227
|
+
function getComputedRole(specs, el) {
|
|
233
228
|
const roleAttrTokens = el.getAttributeToken('role');
|
|
234
229
|
const roleAttr = roleAttrTokens[0];
|
|
235
230
|
if (roleAttr) {
|
|
@@ -239,7 +234,7 @@ function getComputedRole(el) {
|
|
|
239
234
|
isImplicit: false,
|
|
240
235
|
};
|
|
241
236
|
}
|
|
242
|
-
const implicitRole = getImplicitRole(el);
|
|
237
|
+
const implicitRole = getImplicitRole(specs, el);
|
|
243
238
|
if (implicitRole) {
|
|
244
239
|
return {
|
|
245
240
|
name: implicitRole,
|
|
@@ -291,8 +286,8 @@ function checkAriaValue(type, value, tokenEnum) {
|
|
|
291
286
|
return true;
|
|
292
287
|
}
|
|
293
288
|
exports.checkAriaValue = checkAriaValue;
|
|
294
|
-
function checkAria(attrName, currentValue, role) {
|
|
295
|
-
const ariaAttrs =
|
|
289
|
+
function checkAria(specs, attrName, currentValue, role) {
|
|
290
|
+
const ariaAttrs = specs.def['#ariaAttrs'];
|
|
296
291
|
const aria = ariaAttrs.find(a => a.name === attrName);
|
|
297
292
|
if (!aria) {
|
|
298
293
|
return {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("@markuplint/ml-core").RuleSeed<
|
|
1
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, null>;
|
|
2
2
|
export default _default;
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
4
|
exports.default = (0, ml_core_1.createRule)({
|
|
5
|
-
defaultValue: null,
|
|
6
|
-
defaultOptions: null,
|
|
7
5
|
async verify({ document, report, t }) {
|
|
8
|
-
const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'value'), t('the "{0}" {1}', 'id', 'attribute')), 'duplicated');
|
|
6
|
+
const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'value'), t('the "{0*}" {1}', 'id', 'attribute')), 'duplicated');
|
|
9
7
|
const idStack = [];
|
|
10
8
|
await document.walkOn('Element', async (node) => {
|
|
11
9
|
const idAttrs = node.getAttributeToken('id');
|
package/lib/index.d.ts
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
-
'attr-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<
|
|
2
|
+
'attr-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
3
3
|
'attr-equal-space-after': import("packages/@markuplint/ml-core/lib").RuleSeed<"always" | "never" | "always-single-line" | "never-single-line", null>;
|
|
4
4
|
'attr-equal-space-before': import("packages/@markuplint/ml-core/lib").RuleSeed<"always" | "never" | "always-single-line" | "never-single-line", null>;
|
|
5
5
|
'attr-spacing': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./attr-spacing").AttrSpasingOptions>;
|
|
6
6
|
'attr-value-quotes': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./attr-value-quotes").Type, null>;
|
|
7
|
-
'case-sensitive-attr-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-attr-name").Value, null>;
|
|
7
|
+
'case-sensitive-attr-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-attr-name").Value | import("./case-sensitive-attr-name").Value_v1, null>;
|
|
8
8
|
'case-sensitive-tag-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-tag-name").Value, null>;
|
|
9
|
-
'character-reference': import("packages/@markuplint/ml-core/lib").RuleSeed<
|
|
9
|
+
'character-reference': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
10
10
|
'class-naming': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./class-naming").Value, null>;
|
|
11
|
-
'deprecated-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<
|
|
12
|
-
'deprecated-element': import("packages/@markuplint/ml-core/lib").RuleSeed<
|
|
11
|
+
'deprecated-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
12
|
+
'deprecated-element': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
13
|
+
'disallowed-element': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], null>;
|
|
13
14
|
doctype: import("packages/@markuplint/ml-core/lib").RuleSeed<"always", {
|
|
14
15
|
denyObsolateType: boolean;
|
|
15
16
|
}>;
|
|
16
|
-
'id-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<
|
|
17
|
+
'id-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
17
18
|
indentation: import("packages/@markuplint/ml-core/lib").RuleSeed<import("./indentation").Value, import("./indentation").IndentationOptions>;
|
|
18
|
-
'
|
|
19
|
+
'ineffective-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
20
|
+
'invalid-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
19
21
|
attrs?: Record<string, {
|
|
20
|
-
enum: string[];
|
|
22
|
+
enum: [string, ...string[]];
|
|
21
23
|
} | {
|
|
22
24
|
pattern: string;
|
|
23
25
|
} | {
|
|
24
26
|
type: import("packages/@markuplint/ml-spec/lib").AttributeType;
|
|
27
|
+
} | {
|
|
28
|
+
disallowed: true;
|
|
25
29
|
}> | undefined;
|
|
26
30
|
ignoreAttrNamePrefix?: string | string[] | undefined;
|
|
27
31
|
}>;
|
|
@@ -29,12 +33,25 @@ declare const _default: {
|
|
|
29
33
|
ignoreRoles?: (("banner" | "main" | "complementary" | "contentinfo") | "form" | "navigation" | "region")[] | undefined;
|
|
30
34
|
labelEachArea?: boolean | undefined;
|
|
31
35
|
}>;
|
|
36
|
+
'no-boolean-attr-value': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
37
|
+
'no-default-value': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
38
|
+
'no-hard-code-id': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
39
|
+
'no-refer-to-non-existent-id': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
40
|
+
'no-use-event-handler-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
41
|
+
ignore?: string | string[] | undefined;
|
|
42
|
+
}>;
|
|
32
43
|
'permitted-contents': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-spec/lib").PermittedStructuresSchema[], {
|
|
33
44
|
ignoreHasMutableChildren: boolean;
|
|
34
45
|
}>;
|
|
35
|
-
'required-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<string | string
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
'required-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<string | (string | {
|
|
47
|
+
name: string;
|
|
48
|
+
value: string | string[];
|
|
49
|
+
})[], null>;
|
|
50
|
+
'required-element': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], {
|
|
51
|
+
ignoreHasMutableContents?: boolean | undefined;
|
|
52
|
+
}>;
|
|
53
|
+
'required-h1': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./required-h1").Options>;
|
|
54
|
+
'wai-aria': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
38
55
|
checkingValue?: boolean | undefined;
|
|
39
56
|
checkingDeprecatedProps?: boolean | undefined;
|
|
40
57
|
permittedAriaRoles?: boolean | undefined;
|
package/lib/index.js
CHANGED
|
@@ -12,13 +12,21 @@ const character_reference_1 = (0, tslib_1.__importDefault)(require("./character-
|
|
|
12
12
|
const class_naming_1 = (0, tslib_1.__importDefault)(require("./class-naming"));
|
|
13
13
|
const deprecated_attr_1 = (0, tslib_1.__importDefault)(require("./deprecated-attr"));
|
|
14
14
|
const deprecated_element_1 = (0, tslib_1.__importDefault)(require("./deprecated-element"));
|
|
15
|
+
const disallowed_element_1 = (0, tslib_1.__importDefault)(require("./disallowed-element"));
|
|
15
16
|
const doctype_1 = (0, tslib_1.__importDefault)(require("./doctype"));
|
|
16
17
|
const id_duplication_1 = (0, tslib_1.__importDefault)(require("./id-duplication"));
|
|
17
18
|
const indentation_1 = (0, tslib_1.__importDefault)(require("./indentation"));
|
|
19
|
+
const ineffective_attr_1 = (0, tslib_1.__importDefault)(require("./ineffective-attr"));
|
|
18
20
|
const invalid_attr_1 = (0, tslib_1.__importDefault)(require("./invalid-attr"));
|
|
19
21
|
const landmark_roles_1 = (0, tslib_1.__importDefault)(require("./landmark-roles"));
|
|
22
|
+
const no_boolean_attr_value_1 = (0, tslib_1.__importDefault)(require("./no-boolean-attr-value"));
|
|
23
|
+
const no_default_value_1 = (0, tslib_1.__importDefault)(require("./no-default-value"));
|
|
24
|
+
const no_hard_code_id_1 = (0, tslib_1.__importDefault)(require("./no-hard-code-id"));
|
|
25
|
+
const no_refer_to_non_existent_id_1 = (0, tslib_1.__importDefault)(require("./no-refer-to-non-existent-id"));
|
|
26
|
+
const no_use_event_handler_attr_1 = (0, tslib_1.__importDefault)(require("./no-use-event-handler-attr"));
|
|
20
27
|
const permitted_contents_1 = (0, tslib_1.__importDefault)(require("./permitted-contents"));
|
|
21
28
|
const required_attr_1 = (0, tslib_1.__importDefault)(require("./required-attr"));
|
|
29
|
+
const required_element_1 = (0, tslib_1.__importDefault)(require("./required-element"));
|
|
22
30
|
const required_h1_1 = (0, tslib_1.__importDefault)(require("./required-h1"));
|
|
23
31
|
const wai_aria_1 = (0, tslib_1.__importDefault)(require("./wai-aria"));
|
|
24
32
|
exports.default = {
|
|
@@ -33,13 +41,21 @@ exports.default = {
|
|
|
33
41
|
'class-naming': class_naming_1.default,
|
|
34
42
|
'deprecated-attr': deprecated_attr_1.default,
|
|
35
43
|
'deprecated-element': deprecated_element_1.default,
|
|
44
|
+
'disallowed-element': disallowed_element_1.default,
|
|
36
45
|
doctype: doctype_1.default,
|
|
37
46
|
'id-duplication': id_duplication_1.default,
|
|
38
47
|
indentation: indentation_1.default,
|
|
48
|
+
'ineffective-attr': ineffective_attr_1.default,
|
|
39
49
|
'invalid-attr': invalid_attr_1.default,
|
|
40
50
|
'landmark-roles': landmark_roles_1.default,
|
|
51
|
+
'no-boolean-attr-value': no_boolean_attr_value_1.default,
|
|
52
|
+
'no-default-value': no_default_value_1.default,
|
|
53
|
+
'no-hard-code-id': no_hard_code_id_1.default,
|
|
54
|
+
'no-refer-to-non-existent-id': no_refer_to_non_existent_id_1.default,
|
|
55
|
+
'no-use-event-handler-attr': no_use_event_handler_attr_1.default,
|
|
41
56
|
'permitted-contents': permitted_contents_1.default,
|
|
42
57
|
'required-attr': required_attr_1.default,
|
|
58
|
+
'required-element': required_element_1.default,
|
|
43
59
|
'required-h1': required_h1_1.default,
|
|
44
60
|
'wai-aria': wai_aria_1.default,
|
|
45
61
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
defaultServerity: 'warning',
|
|
6
|
+
async verify({ document, report, t }) {
|
|
7
|
+
document.walkOn('Element', el => {
|
|
8
|
+
const attrSpec = (0, ml_core_1.getAttrSpecs)(el.nameWithNS, document.specs);
|
|
9
|
+
if (!attrSpec) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (const attr of el.attributes) {
|
|
13
|
+
if (attr.attrType === 'ps-attr') {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const name = attr.getName().potential;
|
|
17
|
+
const spec = attrSpec.find(s => s.name === name);
|
|
18
|
+
if (!spec) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const ineffectiveConditions = spec.ineffective
|
|
22
|
+
? Array.isArray(spec.ineffective)
|
|
23
|
+
? spec.ineffective
|
|
24
|
+
: [spec.ineffective]
|
|
25
|
+
: [];
|
|
26
|
+
if (ineffectiveConditions.some(selector => el.matches(selector))) {
|
|
27
|
+
report({
|
|
28
|
+
scope: el,
|
|
29
|
+
raw: attr.raw,
|
|
30
|
+
line: attr.startLine,
|
|
31
|
+
col: attr.startCol,
|
|
32
|
+
message: t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), 'ineffective') +
|
|
33
|
+
t('. ') +
|
|
34
|
+
t("It doesn't need {0}", t('the {0}', 'attribute')),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -4,11 +4,13 @@ declare type Option = {
|
|
|
4
4
|
ignoreAttrNamePrefix?: string | string[];
|
|
5
5
|
};
|
|
6
6
|
declare type Rule = {
|
|
7
|
-
enum: string[];
|
|
7
|
+
enum: [string, ...string[]];
|
|
8
8
|
} | {
|
|
9
9
|
pattern: string;
|
|
10
10
|
} | {
|
|
11
11
|
type: AttributeType;
|
|
12
|
+
} | {
|
|
13
|
+
disallowed: true;
|
|
12
14
|
};
|
|
13
|
-
declare const _default: import("@markuplint/ml-core").RuleSeed<
|
|
15
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Option>;
|
|
14
16
|
export default _default;
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
4
|
const attr_check_1 = require("../attr-check");
|
|
5
|
+
const debug_1 = require("../debug");
|
|
5
6
|
const helpers_1 = require("../helpers");
|
|
7
|
+
const log = debug_1.log.extend('invalid-attr');
|
|
6
8
|
exports.default = (0, ml_core_1.createRule)({
|
|
7
|
-
defaultValue: true,
|
|
8
9
|
defaultOptions: {},
|
|
9
10
|
async verify({ document, report, t }) {
|
|
10
11
|
await document.walkOn('Element', async (node) => {
|
|
11
|
-
|
|
12
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
13
|
+
const attrSpecs = (0, ml_core_1.getAttrSpecs)(node.nameWithNS, document.specs);
|
|
12
14
|
for (const attr of node.attributes) {
|
|
13
15
|
if (attr.attrType === 'html-attr' && attr.isDirective) {
|
|
14
16
|
continue;
|
|
@@ -16,7 +18,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
16
18
|
const attrName = attr.getName();
|
|
17
19
|
const name = attrName.potential;
|
|
18
20
|
if (!node.isCustomElement && attr.attrType === 'html-attr' && attr.candidate) {
|
|
19
|
-
const message = t('{0} is {1:c}', t('the "{0}" {1}', attrName.raw, 'attribute'), 'disallowed') +
|
|
21
|
+
const message = t('{0} is {1:c}', t('the "{0*}" {1}', attrName.raw, 'attribute'), 'disallowed') +
|
|
20
22
|
t('. ') +
|
|
21
23
|
t('Did you mean "{0}"?', attr.candidate);
|
|
22
24
|
report({
|
|
@@ -29,7 +31,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
29
31
|
continue;
|
|
30
32
|
}
|
|
31
33
|
const attrValue = attr.getValue();
|
|
32
|
-
const value = attrValue.
|
|
34
|
+
const value = attrValue.potential;
|
|
33
35
|
if (node.rule.option.ignoreAttrNamePrefix) {
|
|
34
36
|
const ignoreAttrNamePrefixes = Array.isArray(node.rule.option.ignoreAttrNamePrefix)
|
|
35
37
|
? node.rule.option.ignoreAttrNamePrefix
|
|
@@ -41,6 +43,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
41
43
|
let invalid = false;
|
|
42
44
|
const customRule = node.rule.option.attrs ? node.rule.option.attrs[name] : null;
|
|
43
45
|
if (customRule) {
|
|
46
|
+
if (attr.attrType === 'html-attr' && attr.isDynamicValue) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
44
49
|
if ('enum' in customRule) {
|
|
45
50
|
invalid = (0, attr_check_1.attrCheck)(t, name.toLowerCase(), value, true, {
|
|
46
51
|
name,
|
|
@@ -54,16 +59,23 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
54
59
|
if (!(0, helpers_1.match)(value, customRule.pattern)) {
|
|
55
60
|
invalid = {
|
|
56
61
|
invalidType: 'invalid-value',
|
|
57
|
-
message: t('{0} is unmatched with the below patterns: {1}', t('the "{0}" {1}', name, 'attribute'), customRule.pattern),
|
|
62
|
+
message: t('{0} is unmatched with the below patterns: {1}', t('the "{0*}" {1}', name, 'attribute'), customRule.pattern),
|
|
58
63
|
};
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
else if ('type' in customRule) {
|
|
62
67
|
invalid = (0, attr_check_1.attrCheck)(t, name, value, true, { name, type: customRule.type, description: '' });
|
|
63
68
|
}
|
|
69
|
+
else if ('disallowed' in customRule && customRule.disallowed) {
|
|
70
|
+
invalid = {
|
|
71
|
+
invalidType: 'non-existent',
|
|
72
|
+
message: t('{0} is disallowed', t('the "{0*}" {1}', name, 'attribute')),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
64
75
|
}
|
|
65
76
|
else if (!node.isCustomElement && attrSpecs) {
|
|
66
|
-
|
|
77
|
+
log('Checking %s[%s="%s"]', node.nodeName, name, value);
|
|
78
|
+
invalid = (0, helpers_1.isValidAttr)(t, name, value, (attr.attrType === 'html-attr' && attr.isDynamicValue) || false, node, attrSpecs, log);
|
|
67
79
|
}
|
|
68
80
|
if (invalid) {
|
|
69
81
|
switch (invalid.invalidType) {
|
|
@@ -71,13 +83,17 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
71
83
|
report({
|
|
72
84
|
scope: node,
|
|
73
85
|
message: invalid.message,
|
|
74
|
-
line: attrValue.line,
|
|
75
|
-
col: attrValue.col,
|
|
76
|
-
raw: value,
|
|
86
|
+
line: attrValue.line + ((_b = (_a = invalid.loc) === null || _a === void 0 ? void 0 : _a.line) !== null && _b !== void 0 ? _b : 0),
|
|
87
|
+
col: ((_c = invalid.loc) === null || _c === void 0 ? void 0 : _c.line) ? ((_d = invalid.loc) === null || _d === void 0 ? void 0 : _d.col) + 1 : attrValue.col + ((_f = (_e = invalid.loc) === null || _e === void 0 ? void 0 : _e.col) !== null && _f !== void 0 ? _f : 0),
|
|
88
|
+
raw: (_h = (_g = invalid.loc) === null || _g === void 0 ? void 0 : _g.raw) !== null && _h !== void 0 ? _h : value,
|
|
77
89
|
});
|
|
78
90
|
break;
|
|
79
91
|
}
|
|
80
92
|
case 'non-existent': {
|
|
93
|
+
const spec = (0, helpers_1.htmlSpec)(document.specs, node.nameWithNS);
|
|
94
|
+
if (spec === null || spec === void 0 ? void 0 : spec.possibleToAddProperties) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
81
97
|
report({
|
|
82
98
|
scope: node,
|
|
83
99
|
message: invalid.message,
|
|
@@ -13,7 +13,6 @@ const selectors = {
|
|
|
13
13
|
const topLevelRoles = ['banner', 'main', 'complementary', 'contentinfo'];
|
|
14
14
|
exports.default = (0, ml_core_1.createRule)({
|
|
15
15
|
defaultServerity: 'warning',
|
|
16
|
-
defaultValue: true,
|
|
17
16
|
defaultOptions: {
|
|
18
17
|
ignoreRoles: [],
|
|
19
18
|
labelEachArea: true,
|
|
@@ -79,7 +78,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
79
78
|
if (el.isDescendantByUUIDList(uuidList)) {
|
|
80
79
|
report({
|
|
81
80
|
scope: el,
|
|
82
|
-
message: t('{0} should be {1}', t('the "{0}" {1}', role, 'role'), 'top level'),
|
|
81
|
+
message: t('{0} should be {1}', t('the "{0*}" {1}', role, 'role'), 'top level'),
|
|
83
82
|
});
|
|
84
83
|
}
|
|
85
84
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
defaultServerity: 'warning',
|
|
6
|
+
async verify({ document, report, t }) {
|
|
7
|
+
await document.walkOn('Element', el => {
|
|
8
|
+
const attrSpec = (0, ml_core_1.getAttrSpecs)(el.nameWithNS, document.specs);
|
|
9
|
+
if (!attrSpec) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (const attr of el.attributes) {
|
|
13
|
+
if (attr.attrType === 'ps-attr' || attr.isDynamicValue) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const name = attr.getName().potential;
|
|
17
|
+
const spec = attrSpec.find(s => s.name === name);
|
|
18
|
+
if (!spec) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (spec.type !== 'Boolean') {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const extraTokens = [
|
|
25
|
+
attr.spacesBeforeEqual,
|
|
26
|
+
attr.equal,
|
|
27
|
+
attr.spacesAfterEqual,
|
|
28
|
+
attr.startQuote,
|
|
29
|
+
attr.value,
|
|
30
|
+
attr.endQuote,
|
|
31
|
+
];
|
|
32
|
+
const extraRaw = extraTokens.reduce((raw, t) => raw + t.raw, '');
|
|
33
|
+
if (extraRaw) {
|
|
34
|
+
report({
|
|
35
|
+
scope: el,
|
|
36
|
+
raw: extraRaw,
|
|
37
|
+
line: attr.spacesBeforeEqual.startLine,
|
|
38
|
+
col: attr.spacesBeforeEqual.startCol,
|
|
39
|
+
message: t('{0} is {1}', t('the "{0*}" {1}', name, 'attribute'), t('a {0}', 'boolean attribute')) +
|
|
40
|
+
t('. ') +
|
|
41
|
+
t("It doesn't need {0}", t('the {0}', 'value')),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
+
const helpers_1 = require("../helpers");
|
|
5
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
6
|
+
defaultServerity: 'warning',
|
|
7
|
+
async verify({ document, report, t }) {
|
|
8
|
+
await document.walkOn('Element', el => {
|
|
9
|
+
const attrSpec = (0, ml_core_1.getAttrSpecs)(el.nameWithNS, document.specs);
|
|
10
|
+
if (!attrSpec) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
for (const attr of el.attributes) {
|
|
14
|
+
if (attr.attrType !== 'html-attr') {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const spec = attrSpec.find(s => s.name === attr.getName().potential);
|
|
18
|
+
if (!spec) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (!spec.defaultValue) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const normalizedValue = (0, helpers_1.toNormalizedValue)(attr.getValue().potential, spec);
|
|
25
|
+
const defaultValue = (0, helpers_1.toNormalizedValue)(spec.defaultValue, spec);
|
|
26
|
+
if (defaultValue === normalizedValue) {
|
|
27
|
+
report({
|
|
28
|
+
scope: el,
|
|
29
|
+
line: attr.value.startLine,
|
|
30
|
+
col: attr.value.startCol,
|
|
31
|
+
raw: attr.value.raw,
|
|
32
|
+
message: t('It is {0}', t('the {0}', 'default value')),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
});
|