@markuplint/rules 3.10.0 → 3.12.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/lib/attr-check.d.ts +8 -19
- package/lib/character-reference/index.js +1 -1
- package/lib/permitted-contents/utils.d.ts +1 -1
- package/package.json +11 -11
- package/test/character-reference/index.spec.js +15 -0
- package/test/deprecated-element/index.spec.js +0 -13
- package/test/invalid-attr/index.spec.js +9 -0
- package/test/permitted-contents/index.spec.js +24 -0
- package/test/require-accessible-name/index.spec.js +23 -25
- package/test/wai-aria/index.spec.js +30 -0
- package/lib/wai-aria/checkings/_.d.ts +0 -15
- package/lib/wai-aria/checkings/_.js +0 -27
- package/lib/wai-aria/checkings/required-prop copy.d.ts +0 -15
- package/lib/wai-aria/checkings/required-prop copy.js +0 -27
- package/lib/wai-aria/checkings/unadopted-explicit-roles.d.ts +0 -15
- package/lib/wai-aria/checkings/unadopted-explicit-roles.js +0 -17
- package/lib/xxx/index.d.ts +0 -2
- package/lib/xxx/index.js +0 -32
package/lib/attr-check.d.ts
CHANGED
|
@@ -2,14 +2,14 @@ import type { Translator } from '@markuplint/i18n';
|
|
|
2
2
|
import type { Attribute as AttrSpec, AttributeType } from '@markuplint/ml-spec';
|
|
3
3
|
import type { ReadonlyDeep } from 'type-fest';
|
|
4
4
|
type Invalid = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
invalidType: 'non-existent' | 'invalid-value' | 'disallowed-attr';
|
|
6
|
+
message: string;
|
|
7
|
+
loc?: Loc;
|
|
8
8
|
};
|
|
9
9
|
type Loc = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
raw: string;
|
|
11
|
+
line: number;
|
|
12
|
+
col: number;
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* Use in rules `invalid-attr` and `wai-aria`
|
|
@@ -19,17 +19,6 @@ type Loc = {
|
|
|
19
19
|
* @param isCustomRule
|
|
20
20
|
* @param spec
|
|
21
21
|
*/
|
|
22
|
-
export declare function attrCheck(
|
|
23
|
-
|
|
24
|
-
name: string,
|
|
25
|
-
value: string,
|
|
26
|
-
isCustomRule: boolean,
|
|
27
|
-
spec?: AttrSpec,
|
|
28
|
-
): Invalid | false;
|
|
29
|
-
export declare function valueCheck(
|
|
30
|
-
t: Translator,
|
|
31
|
-
name: string,
|
|
32
|
-
value: string,
|
|
33
|
-
type: ReadonlyDeep<AttributeType>,
|
|
34
|
-
): [string, Loc] | false;
|
|
22
|
+
export declare function attrCheck(t: Translator, name: string, value: string, isCustomRule: boolean, spec?: AttrSpec): Invalid | false;
|
|
23
|
+
export declare function valueCheck(t: Translator, name: string, value: string, type: ReadonlyDeep<AttributeType>): [string, Loc] | false;
|
|
35
24
|
export {};
|
|
@@ -43,7 +43,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
43
43
|
if (!('scope' in targetNode && 'line' in targetNode && targetNode.line != null)) {
|
|
44
44
|
continue;
|
|
45
45
|
}
|
|
46
|
-
const escapedText = targetNode.raw.replace(/&(?:[a-z]+|#[0-9]
|
|
46
|
+
const escapedText = targetNode.raw.replace(/&(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);/gi, $0 => '*'.repeat($0.length));
|
|
47
47
|
(0, ml_core_1.getLocationFromChars)(defaultChars, escapedText, targetNode.line, targetNode.col).forEach(location => {
|
|
48
48
|
report({
|
|
49
49
|
scope: targetNode.scope,
|
|
@@ -29,7 +29,7 @@ export declare function mergeHints(a: Readonly<Hints>, b: Readonly<Hints>): Part
|
|
|
29
29
|
need?: string | undefined;
|
|
30
30
|
}> | undefined;
|
|
31
31
|
max?: number | undefined;
|
|
32
|
-
not?:
|
|
32
|
+
not?: ChildNode | undefined;
|
|
33
33
|
transparent?: Element | undefined;
|
|
34
34
|
}>;
|
|
35
35
|
export declare function cleanObject<T extends Object>(object: T): Partial<T>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/rules",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.0",
|
|
4
4
|
"description": "Built-in rules of markuplint",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -20,19 +20,19 @@
|
|
|
20
20
|
"./lib/permitted-contents/debug.js": "./lib/permitted-contents/debug.browser.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@markuplint/html-spec": "3.
|
|
24
|
-
"@markuplint/ml-core": "3.
|
|
25
|
-
"@markuplint/ml-spec": "3.
|
|
26
|
-
"@markuplint/selector": "3.
|
|
27
|
-
"@markuplint/shared": "3.
|
|
28
|
-
"@markuplint/types": "3.
|
|
29
|
-
"@types/debug": "^4.1.
|
|
23
|
+
"@markuplint/html-spec": "3.11.0",
|
|
24
|
+
"@markuplint/ml-core": "3.12.0",
|
|
25
|
+
"@markuplint/ml-spec": "3.11.0",
|
|
26
|
+
"@markuplint/selector": "3.11.0",
|
|
27
|
+
"@markuplint/shared": "3.8.0",
|
|
28
|
+
"@markuplint/types": "3.9.0",
|
|
29
|
+
"@types/debug": "^4.1.8",
|
|
30
30
|
"@ungap/structured-clone": "^1.2.0",
|
|
31
31
|
"ansi-colors": "^4.1.3",
|
|
32
32
|
"chrono-node": "^2.6.3",
|
|
33
33
|
"debug": "^4.3.4",
|
|
34
|
-
"tslib": "^2.
|
|
35
|
-
"type-fest": "^3.
|
|
34
|
+
"tslib": "^2.6.0",
|
|
35
|
+
"type-fest": "^3.12.0"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "4ab20276db48a6acb29a923ea8666890ca853442"
|
|
38
38
|
}
|
|
@@ -55,3 +55,18 @@ test('in EJS', async () => {
|
|
|
55
55
|
});
|
|
56
56
|
expect(violations.length).toBe(0);
|
|
57
57
|
});
|
|
58
|
+
|
|
59
|
+
describe('Issues', () => {
|
|
60
|
+
test('#1074', async () => {
|
|
61
|
+
const { violations } = await mlRuleTest(rule, '<span>▼</span><span>▼</span><span>&x25BC;</span>');
|
|
62
|
+
expect(violations).toStrictEqual([
|
|
63
|
+
{
|
|
64
|
+
severity: 'error',
|
|
65
|
+
message: 'Illegal characters must escape in character reference',
|
|
66
|
+
line: 1,
|
|
67
|
+
col: 48,
|
|
68
|
+
raw: '&',
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -33,16 +33,3 @@ test('deprecated', async () => {
|
|
|
33
33
|
},
|
|
34
34
|
]);
|
|
35
35
|
});
|
|
36
|
-
|
|
37
|
-
test('svg', async () => {
|
|
38
|
-
const { violations } = await mlRuleTest(rule, '<svg><altGlyph>text</altGlyph></svg>');
|
|
39
|
-
expect(violations).toStrictEqual([
|
|
40
|
-
{
|
|
41
|
-
severity: 'error',
|
|
42
|
-
message: 'The "altGlyph" element is obsolete',
|
|
43
|
-
line: 1,
|
|
44
|
-
col: 6,
|
|
45
|
-
raw: '<altGlyph>',
|
|
46
|
-
},
|
|
47
|
-
]);
|
|
48
|
-
});
|
|
@@ -1629,4 +1629,13 @@ ol(itemscope itemtype="https://schema.org/BreadcrumbList")
|
|
|
1629
1629
|
).violations,
|
|
1630
1630
|
).toStrictEqual([]);
|
|
1631
1631
|
});
|
|
1632
|
+
|
|
1633
|
+
test('#1078', async () => {
|
|
1634
|
+
expect(
|
|
1635
|
+
(await mlRuleTest(rule, '<script src="foo.js" referrerpolicy="no-referrer"></script>')).violations,
|
|
1636
|
+
).toStrictEqual([]);
|
|
1637
|
+
expect(
|
|
1638
|
+
(await mlRuleTest(rule, '<img src="foo.png" referrerpolicy="no-referrer"></img>')).violations,
|
|
1639
|
+
).toStrictEqual([]);
|
|
1640
|
+
});
|
|
1632
1641
|
});
|
|
@@ -1368,4 +1368,28 @@ describe('Issues', () => {
|
|
|
1368
1368
|
.violations,
|
|
1369
1369
|
).toStrictEqual([]);
|
|
1370
1370
|
});
|
|
1371
|
+
|
|
1372
|
+
test('#1046', async () => {
|
|
1373
|
+
const sourceCode = '<span><div></div></span>';
|
|
1374
|
+
expect(
|
|
1375
|
+
(
|
|
1376
|
+
await mlRuleTest(rule, sourceCode, {
|
|
1377
|
+
rule: {
|
|
1378
|
+
severity: 'warning',
|
|
1379
|
+
},
|
|
1380
|
+
parser: {
|
|
1381
|
+
'.*': '@markuplint/jsx-parser',
|
|
1382
|
+
},
|
|
1383
|
+
})
|
|
1384
|
+
).violations,
|
|
1385
|
+
).toStrictEqual([
|
|
1386
|
+
{
|
|
1387
|
+
severity: 'warning',
|
|
1388
|
+
line: 1,
|
|
1389
|
+
col: 7,
|
|
1390
|
+
message: 'The "div" element is not allowed in the "span" element in this context',
|
|
1391
|
+
raw: '<div>',
|
|
1392
|
+
},
|
|
1393
|
+
]);
|
|
1394
|
+
});
|
|
1371
1395
|
});
|
|
@@ -392,22 +392,7 @@ describe('Issues', () => {
|
|
|
392
392
|
test('#592', async () => {
|
|
393
393
|
expect(
|
|
394
394
|
(await mlRuleTest(rule, '<svg aria-label="i-have-name"><path /><rect><path /></rect></svg>')).violations,
|
|
395
|
-
).toStrictEqual([
|
|
396
|
-
{
|
|
397
|
-
col: 31,
|
|
398
|
-
line: 1,
|
|
399
|
-
message: 'Require accessible name',
|
|
400
|
-
raw: '<path />',
|
|
401
|
-
severity: 'error',
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
col: 39,
|
|
405
|
-
line: 1,
|
|
406
|
-
message: 'Require accessible name',
|
|
407
|
-
raw: '<rect>',
|
|
408
|
-
severity: 'error',
|
|
409
|
-
},
|
|
410
|
-
]);
|
|
395
|
+
).toStrictEqual([]);
|
|
411
396
|
expect(
|
|
412
397
|
(await mlRuleTest(rule, '<svg role="img" aria-label="i-have-name"><path /><rect><path /></rect></svg>'))
|
|
413
398
|
.violations,
|
|
@@ -419,15 +404,7 @@ describe('Issues', () => {
|
|
|
419
404
|
'<svg aria-label="i-have-name"><path aria-label="i-have-name" /><rect><path /></rect></svg>',
|
|
420
405
|
)
|
|
421
406
|
).violations,
|
|
422
|
-
).toStrictEqual([
|
|
423
|
-
{
|
|
424
|
-
col: 64,
|
|
425
|
-
line: 1,
|
|
426
|
-
message: 'Require accessible name',
|
|
427
|
-
raw: '<rect>',
|
|
428
|
-
severity: 'error',
|
|
429
|
-
},
|
|
430
|
-
]);
|
|
407
|
+
).toStrictEqual([]);
|
|
431
408
|
expect(
|
|
432
409
|
(
|
|
433
410
|
await mlRuleTest(
|
|
@@ -443,4 +420,25 @@ describe('Issues', () => {
|
|
|
443
420
|
expect((await mlRuleTest(rule, '<dialog></dialog>')).violations.length).toBe(1);
|
|
444
421
|
expect((await mlRuleTest(rule, '<div role="dialog"></div>')).violations.length).toBe(1);
|
|
445
422
|
});
|
|
423
|
+
|
|
424
|
+
test('#1018', async () => {
|
|
425
|
+
expect(
|
|
426
|
+
(
|
|
427
|
+
await mlRuleTest(rule, '<button><slot /></button>', {
|
|
428
|
+
parser: {
|
|
429
|
+
'.*': '@markuplint/svelte-parser',
|
|
430
|
+
},
|
|
431
|
+
})
|
|
432
|
+
).violations.length,
|
|
433
|
+
).toBe(0);
|
|
434
|
+
expect(
|
|
435
|
+
(
|
|
436
|
+
await mlRuleTest(rule, '<button></button>', {
|
|
437
|
+
parser: {
|
|
438
|
+
'.*': '@markuplint/svelte-parser',
|
|
439
|
+
},
|
|
440
|
+
})
|
|
441
|
+
).violations.length,
|
|
442
|
+
).toBe(1);
|
|
443
|
+
});
|
|
446
444
|
});
|
|
@@ -1170,4 +1170,34 @@ describe('Issues', () => {
|
|
|
1170
1170
|
},
|
|
1171
1171
|
]);
|
|
1172
1172
|
});
|
|
1173
|
+
|
|
1174
|
+
test('#1084', async () => {
|
|
1175
|
+
const { violations } = await mlRuleTest(
|
|
1176
|
+
rule,
|
|
1177
|
+
`
|
|
1178
|
+
<select multiple aria-label="some label text">
|
|
1179
|
+
<option>foo</option>
|
|
1180
|
+
<option>bar</option>
|
|
1181
|
+
</select>
|
|
1182
|
+
|
|
1183
|
+
<select aria-label="some label text">
|
|
1184
|
+
<option>foo</option>
|
|
1185
|
+
<option>bar</option>
|
|
1186
|
+
</select>
|
|
1187
|
+
|
|
1188
|
+
<select aria-label="some label text">
|
|
1189
|
+
<option>foo</option>
|
|
1190
|
+
<optgroup label="group">
|
|
1191
|
+
<option>bar</option>
|
|
1192
|
+
</optgroup>
|
|
1193
|
+
</select>
|
|
1194
|
+
|
|
1195
|
+
<datalist>
|
|
1196
|
+
<option>foo</option>
|
|
1197
|
+
<option>bar</option>
|
|
1198
|
+
</datalist>
|
|
1199
|
+
`,
|
|
1200
|
+
);
|
|
1201
|
+
expect(violations).toStrictEqual([]);
|
|
1202
|
+
});
|
|
1173
1203
|
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Options } from '../types';
|
|
2
|
-
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
|
-
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
-
export declare const checkingRequiredProp: ElementChecker<
|
|
5
|
-
boolean,
|
|
6
|
-
Options,
|
|
7
|
-
{
|
|
8
|
-
role?:
|
|
9
|
-
| (ARIARole & {
|
|
10
|
-
isImplicit?: boolean;
|
|
11
|
-
})
|
|
12
|
-
| null;
|
|
13
|
-
propSpecs: readonly ARIAProperty[];
|
|
14
|
-
}
|
|
15
|
-
>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkingRequiredProp = void 0;
|
|
4
|
-
const checkingRequiredProp = ({ el, role, propSpecs }) => t => {
|
|
5
|
-
var _a;
|
|
6
|
-
if (!role) {
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
|
-
if (role.isImplicit) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const requiredProps = role.ownedProperties.filter(s => s.required).map(s => s.name);
|
|
13
|
-
for (const requiredProp of requiredProps) {
|
|
14
|
-
const has = el.attributes.some(attr => {
|
|
15
|
-
const attrName = attr.name.toLowerCase();
|
|
16
|
-
return attrName === requiredProp;
|
|
17
|
-
});
|
|
18
|
-
if (!has) {
|
|
19
|
-
const propSpec = propSpecs.find(p => p.name === requiredProp);
|
|
20
|
-
return {
|
|
21
|
-
scope: el,
|
|
22
|
-
message: t('{0:c} on {1}', t('Require {0}', t('the "{0*}" {1}', requiredProp, `ARIA ${(_a = propSpec === null || propSpec === void 0 ? void 0 : propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`)), t('the "{0*}" {1}', role.name, 'role')),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
exports.checkingRequiredProp = checkingRequiredProp;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Options } from '../types';
|
|
2
|
-
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
|
-
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
-
export declare const checkingRequiredProp: ElementChecker<
|
|
5
|
-
boolean,
|
|
6
|
-
Options,
|
|
7
|
-
{
|
|
8
|
-
role?:
|
|
9
|
-
| (ARIARole & {
|
|
10
|
-
isImplicit?: boolean;
|
|
11
|
-
})
|
|
12
|
-
| null;
|
|
13
|
-
propSpecs: readonly ARIAProperty[];
|
|
14
|
-
}
|
|
15
|
-
>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkingRequiredProp = void 0;
|
|
4
|
-
const checkingRequiredProp = ({ el, role, propSpecs }) => t => {
|
|
5
|
-
var _a;
|
|
6
|
-
if (!role) {
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
|
-
if (role.isImplicit) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const requiredProps = role.ownedProperties.filter(s => s.required).map(s => s.name);
|
|
13
|
-
for (const requiredProp of requiredProps) {
|
|
14
|
-
const has = el.attributes.some(attr => {
|
|
15
|
-
const attrName = attr.name.toLowerCase();
|
|
16
|
-
return attrName === requiredProp;
|
|
17
|
-
});
|
|
18
|
-
if (!has) {
|
|
19
|
-
const propSpec = propSpecs.find(p => p.name === requiredProp);
|
|
20
|
-
return {
|
|
21
|
-
scope: el,
|
|
22
|
-
message: t('{0:c} on {1}', t('Require {0}', t('the "{0*}" {1}', requiredProp, `ARIA ${(_a = propSpec === null || propSpec === void 0 ? void 0 : propSpec.type) !== null && _a !== void 0 ? _a : 'property'}`)), t('the "{0*}" {1}', role.name, 'role')),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
exports.checkingRequiredProp = checkingRequiredProp;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Options } from '../types';
|
|
2
|
-
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
|
-
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
-
export declare const checkingUnadoptedExplicitRoles: ElementChecker<
|
|
5
|
-
boolean,
|
|
6
|
-
Options,
|
|
7
|
-
{
|
|
8
|
-
role?:
|
|
9
|
-
| (ARIARole & {
|
|
10
|
-
isImplicit?: boolean;
|
|
11
|
-
})
|
|
12
|
-
| null;
|
|
13
|
-
propSpecs: readonly ARIAProperty[];
|
|
14
|
-
}
|
|
15
|
-
>;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkingUnadoptedExplicitRoles = void 0;
|
|
4
|
-
const checkingUnadoptedExplicitRoles = ({ el, role, propSpecs }) => t => {
|
|
5
|
-
if (!role) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
if (role.name) {
|
|
9
|
-
console.log(el.localName, role.name);
|
|
10
|
-
return {
|
|
11
|
-
scope: el,
|
|
12
|
-
message: '',
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
return;
|
|
16
|
-
};
|
|
17
|
-
exports.checkingUnadoptedExplicitRoles = checkingUnadoptedExplicitRoles;
|
package/lib/xxx/index.d.ts
DELETED
package/lib/xxx/index.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
5
|
-
defaultValue: true,
|
|
6
|
-
defaultOptions: null,
|
|
7
|
-
async verify({ document, report, t }) {
|
|
8
|
-
// Element
|
|
9
|
-
await document.walkOn("Element", (el) => {
|
|
10
|
-
const raw = el.raw.trim();
|
|
11
|
-
if (/./i.test(raw)) {
|
|
12
|
-
report({
|
|
13
|
-
scope: el,
|
|
14
|
-
message: t("It is {0}", "issue"),
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
// Attribute
|
|
19
|
-
await document.walkOn("Attr", (attr) => {
|
|
20
|
-
var _a, _b, _c;
|
|
21
|
-
if (/./i.test(attr.name)) {
|
|
22
|
-
report({
|
|
23
|
-
scope: attr,
|
|
24
|
-
line: (_a = attr.nameNode) === null || _a === void 0 ? void 0 : _a.startLine,
|
|
25
|
-
col: (_b = attr.nameNode) === null || _b === void 0 ? void 0 : _b.startCol,
|
|
26
|
-
raw: (_c = attr.nameNode) === null || _c === void 0 ? void 0 : _c.raw,
|
|
27
|
-
message: t("It is {0}", "issue"),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
});
|