@markuplint/rules 3.8.0 → 3.9.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.
Files changed (52) hide show
  1. package/lib/helpers.d.ts +2 -5
  2. package/lib/index.d.ts +240 -99
  3. package/lib/permitted-contents/utils.d.ts +90 -41
  4. package/lib/wai-aria/checkings/_.d.ts +12 -6
  5. package/lib/wai-aria/checkings/disallowed-prop.d.ts +8 -4
  6. package/lib/wai-aria/checkings/required-prop copy.d.ts +12 -6
  7. package/lib/wai-aria/checkings/unadopted-explicit-roles.d.ts +12 -6
  8. package/lib/xxx/index.d.ts +2 -0
  9. package/lib/xxx/index.js +32 -0
  10. package/package.json +11 -13
  11. package/test/attr-check.spec.js +77 -0
  12. package/test/attr-duplication/index.spec.js +159 -0
  13. package/test/attr-value-quotes/index.spec.js +133 -0
  14. package/test/case-sensitive-attr-name/index.spec.js +65 -0
  15. package/test/case-sensitive-tag-name/index.spec.js +80 -0
  16. package/test/character-reference/index.spec.js +57 -0
  17. package/test/class-naming/index.spec.js +470 -0
  18. package/test/create-message.spec.js +497 -0
  19. package/test/deprecated-attr/index.spec.js +48 -0
  20. package/test/deprecated-element/index.spec.js +48 -0
  21. package/test/disallowed-element/index.spec.js +90 -0
  22. package/test/doctype/index.spec.js +50 -0
  23. package/test/end-tag/index.spec.js +162 -0
  24. package/test/id-duplication/index.spec.js +47 -0
  25. package/test/ineffective-attr/index.spec.js +31 -0
  26. package/test/invalid-attr/index.spec.js +1632 -0
  27. package/test/label-has-control/index.spec.js +29 -0
  28. package/test/landmark-roles/index.spec.js +187 -0
  29. package/test/no-boolean-attr-value/index.spec.js +41 -0
  30. package/test/no-default-value/index.spec.js +74 -0
  31. package/test/no-empty-palpable-content/index.spec.js +115 -0
  32. package/test/no-hard-code-id/index.spec.js +100 -0
  33. package/test/no-refer-to-non-existent-id/index.spec.js +254 -0
  34. package/test/no-use-event-handler-attr/index.spec.js +57 -0
  35. package/test/permitted-contents/choice.spec.js +174 -0
  36. package/test/permitted-contents/count-pattern.spec.js +308 -0
  37. package/test/permitted-contents/index.spec.js +1371 -0
  38. package/test/permitted-contents/matches-selector.spec.js +59 -0
  39. package/test/permitted-contents/order.spec.js +351 -0
  40. package/test/permitted-contents/recursive-branch.spec.js +41 -0
  41. package/test/permitted-contents/represent-transparent-nodes.spec.js +24 -0
  42. package/test/permitted-contents/start.spec.js +67 -0
  43. package/test/placeholder-label-option/index.spec.js +113 -0
  44. package/test/require-accessible-name/index.spec.js +446 -0
  45. package/test/require-datetime/index.spec.js +54 -0
  46. package/test/require-datetime/utils.spec.js +52 -0
  47. package/test/required-attr/index.spec.js +414 -0
  48. package/test/required-element/index.spec.js +188 -0
  49. package/test/required-h1/index.spec.js +69 -0
  50. package/test/use-list/index.spec.js +109 -0
  51. package/test/wai-aria/checkings/value.spec.js +33 -0
  52. package/test/wai-aria/index.spec.js +1173 -0
@@ -0,0 +1,29 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/label-has-control').default;
4
+
5
+ it('No control', async () => {
6
+ const { violations } = await mlRuleTest(rule, '<label>foo</label>');
7
+ expect(violations).toStrictEqual([
8
+ {
9
+ severity: 'warning',
10
+ line: 1,
11
+ col: 1,
12
+ raw: '<label>',
13
+ message: 'The "label" element should associate with a control',
14
+ },
15
+ ]);
16
+ });
17
+
18
+ it('Not single control', async () => {
19
+ const { violations } = await mlRuleTest(rule, '<label><input><select></select></label>');
20
+ expect(violations).toStrictEqual([
21
+ {
22
+ severity: 'warning',
23
+ line: 1,
24
+ col: 15,
25
+ raw: '<select>',
26
+ message: 'The "label" element associates only first control',
27
+ },
28
+ ]);
29
+ });
@@ -0,0 +1,187 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/landmark-roles').default;
4
+
5
+ test('No warning', async () => {
6
+ const { violations } = await mlRuleTest(
7
+ rule,
8
+ `
9
+ <html>
10
+ <body>
11
+ <header></header>
12
+ <nav></nav>
13
+ <main>
14
+ <header></header>
15
+ <footer></footer>
16
+ </main>
17
+ <aside></aside>
18
+ <footer></footer>
19
+ </body>
20
+ </html>
21
+ `,
22
+ );
23
+
24
+ expect(violations).toStrictEqual([]);
25
+ });
26
+
27
+ test('Top level landmarks', async () => {
28
+ const { violations } = await mlRuleTest(
29
+ rule,
30
+ `
31
+ <html>
32
+ <body>
33
+ <header></header>
34
+ <nav></nav>
35
+ <main>
36
+ <header></header>
37
+ <footer></footer>
38
+ <aside></aside>
39
+ </main>
40
+ <footer></footer>
41
+ </body>
42
+ </html>
43
+ `,
44
+ );
45
+
46
+ expect(violations).toStrictEqual([
47
+ {
48
+ severity: 'warning',
49
+ line: 9,
50
+ col: 3,
51
+ raw: '<aside>',
52
+ message: 'The "complementary" role should be top level',
53
+ },
54
+ ]);
55
+ });
56
+
57
+ test('Top level landmarks: disabled', async () => {
58
+ const { violations } = await mlRuleTest(
59
+ rule,
60
+ `
61
+ <html>
62
+ <body>
63
+ <header></header>
64
+ <nav></nav>
65
+ <main>
66
+ <header></header>
67
+ <footer></footer>
68
+ <aside></aside>
69
+ </main>
70
+ <footer></footer>
71
+ </body>
72
+ </html>
73
+ `,
74
+ {
75
+ nodeRule: [
76
+ {
77
+ selector: 'aside',
78
+ rule: false,
79
+ },
80
+ ],
81
+ },
82
+ );
83
+
84
+ expect(violations).toStrictEqual([]);
85
+ });
86
+
87
+ test('Top level landmarks: ignoreRoles option', async () => {
88
+ const { violations } = await mlRuleTest(
89
+ rule,
90
+ `
91
+ <html>
92
+ <body>
93
+ <header></header>
94
+ <nav></nav>
95
+ <main>
96
+ <header></header>
97
+ <footer></footer>
98
+ <aside></aside>
99
+ </main>
100
+ <footer></footer>
101
+ </body>
102
+ </html>
103
+ `,
104
+ {
105
+ rule: {
106
+ options: {
107
+ ignoreRoles: ['complementary'],
108
+ },
109
+ },
110
+ },
111
+ );
112
+
113
+ expect(violations).toStrictEqual([]);
114
+ });
115
+
116
+ test('Duplicated area: has-label', async () => {
117
+ const { violations } = await mlRuleTest(
118
+ rule,
119
+ `
120
+ <html>
121
+ <body>
122
+ <header></header>
123
+ <nav aria-label="main"></nav>
124
+ <main>
125
+ <header></header>
126
+ <nav aria-label="sub"></nav>
127
+ <footer></footer>
128
+ </main>
129
+ <footer></footer>
130
+ </body>
131
+ </html>
132
+ `,
133
+ {
134
+ rule: {
135
+ options: {
136
+ ignoreRoles: ['complementary'],
137
+ },
138
+ },
139
+ },
140
+ );
141
+
142
+ expect(violations).toStrictEqual([]);
143
+ });
144
+
145
+ test('Duplicated area: no-label', async () => {
146
+ const { violations } = await mlRuleTest(
147
+ rule,
148
+ `
149
+ <html>
150
+ <body>
151
+ <header></header>
152
+ <nav></nav>
153
+ <main>
154
+ <header></header>
155
+ <nav></nav>
156
+ <footer></footer>
157
+ </main>
158
+ <footer></footer>
159
+ </body>
160
+ </html>
161
+ `,
162
+ {
163
+ rule: {
164
+ options: {
165
+ ignoreRoles: ['complementary'],
166
+ },
167
+ },
168
+ },
169
+ );
170
+
171
+ expect(violations).toStrictEqual([
172
+ {
173
+ severity: 'warning',
174
+ line: 5,
175
+ col: 2,
176
+ raw: '<nav>',
177
+ message: 'Require unique accessible name',
178
+ },
179
+ {
180
+ severity: 'warning',
181
+ line: 8,
182
+ col: 3,
183
+ raw: '<nav>',
184
+ message: 'Require unique accessible name',
185
+ },
186
+ ]);
187
+ });
@@ -0,0 +1,41 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/no-boolean-attr-value').default;
4
+
5
+ test('input[required]', async () => {
6
+ const { violations } = await mlRuleTest(
7
+ rule,
8
+ '<input type="text" required /><input type="text" required="required" />',
9
+ );
10
+
11
+ expect(violations).toStrictEqual([
12
+ {
13
+ severity: 'warning',
14
+ line: 1,
15
+ col: 58,
16
+ message: 'The "required" attribute is a boolean attribute. It doesn\'t need the value',
17
+ raw: '="required"',
18
+ },
19
+ ]);
20
+ });
21
+
22
+ test('input[disabled] (Mutable)', async () => {
23
+ const { violations } = await mlRuleTest(
24
+ rule,
25
+ '<><input type="text" disabled /><input type="text" disabled={disabled} /></>',
26
+ {
27
+ parser: {
28
+ '.*': '@markuplint/jsx-parser',
29
+ },
30
+ },
31
+ );
32
+
33
+ expect(violations).toStrictEqual([]);
34
+ });
35
+
36
+ test('Updated the hidden attribute type to Enum form Boolean', async () => {
37
+ expect((await mlRuleTest(rule, '<div hidden></div>')).violations.length).toBe(0);
38
+ expect((await mlRuleTest(rule, '<div hidden=""></div>')).violations.length).toBe(0);
39
+ expect((await mlRuleTest(rule, '<div hidden="hidden"></div>')).violations.length).toBe(0);
40
+ expect((await mlRuleTest(rule, '<div hidden="until-found"></div>')).violations.length).toBe(0);
41
+ });
@@ -0,0 +1,74 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/no-default-value').default;
4
+
5
+ test('canvas', async () => {
6
+ const { violations } = await mlRuleTest(rule, '<canvas width="300" height="150"></canvas>');
7
+ expect(violations).toStrictEqual([
8
+ {
9
+ severity: 'warning',
10
+ line: 1,
11
+ col: 16,
12
+ raw: '300',
13
+ message: 'It is the default value',
14
+ },
15
+ {
16
+ severity: 'warning',
17
+ line: 1,
18
+ col: 29,
19
+ raw: '150',
20
+ message: 'It is the default value',
21
+ },
22
+ ]);
23
+ });
24
+
25
+ test('svg|image', async () => {
26
+ const { violations } = await mlRuleTest(
27
+ rule,
28
+ `<svg>
29
+ <image preserveAspectRatio="xMidYMid meet" />
30
+ <image preserveAspectRatio="xMidYMid meet" />
31
+ <image preserveAspectRatio=" xMidYMid meet " />
32
+ <image preserveAspectRatio="XMIDYMID MEET" />
33
+ <image preserveAspectRatio="xMidYMid" />
34
+ <image preserveAspectRatio="meet" />
35
+ </svg>`,
36
+ );
37
+ expect(violations).toStrictEqual([
38
+ {
39
+ severity: 'warning',
40
+ line: 2,
41
+ col: 31,
42
+ raw: 'xMidYMid meet',
43
+ message: 'It is the default value',
44
+ },
45
+ {
46
+ severity: 'warning',
47
+ line: 3,
48
+ col: 31,
49
+ raw: 'xMidYMid meet',
50
+ message: 'It is the default value',
51
+ },
52
+ {
53
+ severity: 'warning',
54
+ line: 4,
55
+ col: 31,
56
+ raw: ' xMidYMid meet ',
57
+ message: 'It is the default value',
58
+ },
59
+ {
60
+ severity: 'warning',
61
+ line: 5,
62
+ col: 31,
63
+ raw: 'XMIDYMID MEET',
64
+ message: 'It is the default value',
65
+ },
66
+ ]);
67
+ });
68
+
69
+ test('Updated the hidden attribute type to Enum form Boolean', async () => {
70
+ expect((await mlRuleTest(rule, '<div hidden></div>')).violations.length).toBe(0);
71
+ expect((await mlRuleTest(rule, '<div hidden=""></div>')).violations.length).toBe(0);
72
+ expect((await mlRuleTest(rule, '<div hidden="hidden"></div>')).violations.length).toBe(0);
73
+ expect((await mlRuleTest(rule, '<div hidden="until-found"></div>')).violations.length).toBe(0);
74
+ });
@@ -0,0 +1,115 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/no-empty-palpable-content').default;
4
+
5
+ test('No space', async () => {
6
+ expect((await mlRuleTest(rule, '<div></div>')).violations).toStrictEqual([
7
+ {
8
+ severity: 'warning',
9
+ line: 1,
10
+ col: 1,
11
+ message: 'The element should not empty',
12
+ raw: '<div>',
13
+ },
14
+ ]);
15
+ expect((await mlRuleTest(rule, '<p></p>')).violations).toStrictEqual([
16
+ {
17
+ severity: 'warning',
18
+ line: 1,
19
+ col: 1,
20
+ message: 'The element should not empty',
21
+ raw: '<p>',
22
+ },
23
+ ]);
24
+ expect((await mlRuleTest(rule, '<span></span>')).violations).toStrictEqual([
25
+ {
26
+ severity: 'warning',
27
+ line: 1,
28
+ col: 1,
29
+ message: 'The element should not empty',
30
+ raw: '<span>',
31
+ },
32
+ ]);
33
+ expect((await mlRuleTest(rule, '<li></li>')).violations).toStrictEqual([
34
+ {
35
+ severity: 'warning',
36
+ line: 1,
37
+ col: 1,
38
+ message: 'The element should not empty',
39
+ raw: '<li>',
40
+ },
41
+ ]);
42
+ expect((await mlRuleTest(rule, '<svg><rect /></svg>')).violations).toStrictEqual([]);
43
+ });
44
+
45
+ test('White space', async () => {
46
+ expect((await mlRuleTest(rule, '<div> </div>')).violations).toStrictEqual([
47
+ {
48
+ severity: 'warning',
49
+ line: 1,
50
+ col: 1,
51
+ message: 'The element should not empty',
52
+ raw: '<div>',
53
+ },
54
+ ]);
55
+ expect((await mlRuleTest(rule, '<div>\n\t \n\n</div>')).violations).toStrictEqual([
56
+ {
57
+ severity: 'warning',
58
+ line: 1,
59
+ col: 1,
60
+ message: 'The element should not empty',
61
+ raw: '<div>',
62
+ },
63
+ ]);
64
+ });
65
+
66
+ test('Has content', async () => {
67
+ expect((await mlRuleTest(rule, '<div>\n\ttext\n\n</div>')).violations).toStrictEqual([]);
68
+ expect((await mlRuleTest(rule, '<div><img /></div>')).violations).toStrictEqual([]);
69
+ });
70
+
71
+ test('Has content', async () => {
72
+ expect((await mlRuleTest(rule, '<div>\n\ttext\n\n</div>')).violations).toStrictEqual([]);
73
+ expect((await mlRuleTest(rule, '<div><img /></div>')).violations).toStrictEqual([]);
74
+ });
75
+
76
+ test('Element exception', async () => {
77
+ expect((await mlRuleTest(rule, '<textarea></textarea>')).violations).toStrictEqual([]);
78
+ });
79
+
80
+ test('Ignore aria-busy', async () => {
81
+ expect((await mlRuleTest(rule, '<div aria-busy="true"></div>')).violations).toStrictEqual([]);
82
+ expect((await mlRuleTest(rule, '<div aria-busy="true">\n\t\n\n</div>')).violations).toStrictEqual([]);
83
+ expect(
84
+ (
85
+ await mlRuleTest(rule, '<div aria-busy="true">\n\t\n\n</div>', {
86
+ rule: {
87
+ options: {
88
+ ignoreIfAriaBusy: false,
89
+ },
90
+ },
91
+ })
92
+ ).violations,
93
+ ).toStrictEqual([
94
+ {
95
+ severity: 'warning',
96
+ line: 1,
97
+ col: 1,
98
+ message: 'The element should not empty',
99
+ raw: '<div aria-busy="true">',
100
+ },
101
+ ]);
102
+ });
103
+
104
+ describe('Issues', () => {
105
+ test('#593', async () => {
106
+ expect((await mlRuleTest(rule, '<iframe></iframe>')).violations).toStrictEqual([]);
107
+ });
108
+
109
+ test('#775', async () => {
110
+ expect((await mlRuleTest(rule, '<pre>text</pre>')).violations).toStrictEqual([]);
111
+ expect((await mlRuleTest(rule, '<pre>\n\ttext</pre>')).violations).toStrictEqual([]);
112
+ expect((await mlRuleTest(rule, '<pre>text\ntext</pre>')).violations).toStrictEqual([]);
113
+ expect((await mlRuleTest(rule, '<pre>\ntext</pre>')).violations).toStrictEqual([]);
114
+ });
115
+ });
@@ -0,0 +1,100 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/no-hard-code-id').default;
4
+
5
+ it('is hard-coded', async () => {
6
+ const { violations } = await mlRuleTest(rule, '<div id="foo"></div>');
7
+ expect(violations).toStrictEqual([
8
+ {
9
+ severity: 'warning',
10
+ line: 1,
11
+ col: 6,
12
+ raw: 'id="foo"',
13
+ message: 'It is hard-coded',
14
+ },
15
+ ]);
16
+ });
17
+
18
+ it("does't have id", async () => {
19
+ const { violations } = await mlRuleTest(rule, '<div class="foo"></div>');
20
+ expect(violations).toStrictEqual([]);
21
+ });
22
+
23
+ it("does't have id", async () => {
24
+ const { violations } = await mlRuleTest(rule, '<div data-id="foo"></div>');
25
+ expect(violations).toStrictEqual([]);
26
+ });
27
+
28
+ it('is hard-coded', async () => {
29
+ const { violations } = await mlRuleTest(rule, 'div#foo', {
30
+ parser: {
31
+ '/.*/': '@markuplint/pug-parser',
32
+ },
33
+ });
34
+ expect(violations).toStrictEqual([
35
+ {
36
+ severity: 'warning',
37
+ line: 1,
38
+ col: 4,
39
+ raw: '#foo',
40
+ message: 'It is hard-coded',
41
+ },
42
+ ]);
43
+ });
44
+
45
+ it('is hard-coded', async () => {
46
+ const { violations } = await mlRuleTest(rule, 'div(id="foo")', {
47
+ parser: {
48
+ '/.*/': '@markuplint/pug-parser',
49
+ },
50
+ });
51
+ expect(violations).toStrictEqual([
52
+ {
53
+ severity: 'warning',
54
+ line: 1,
55
+ col: 5,
56
+ raw: 'id="foo"',
57
+ message: 'It is hard-coded',
58
+ },
59
+ ]);
60
+ });
61
+
62
+ it('is hard-coded', async () => {
63
+ const { violations } = await mlRuleTest(rule, '<div id="foo"></div>', {
64
+ parser: {
65
+ '.*': '@markuplint/jsx-parser',
66
+ },
67
+ });
68
+ expect(violations).toStrictEqual([
69
+ {
70
+ severity: 'warning',
71
+ line: 1,
72
+ col: 6,
73
+ raw: 'id="foo"',
74
+ message: 'It is hard-coded',
75
+ },
76
+ ]);
77
+ });
78
+
79
+ it('is no hard-coded', async () => {
80
+ const { violations } = await mlRuleTest(rule, 'div(id=foo)', {
81
+ parser: {
82
+ '/.*/': '@markuplint/pug-parser',
83
+ },
84
+ });
85
+ expect(violations.length).toBe(0);
86
+ });
87
+
88
+ it('is no hard-coded', async () => {
89
+ const { violations } = await mlRuleTest(rule, '<div id={foo}></div>', {
90
+ parser: {
91
+ '/.*/': '@markuplint/jsx-parser',
92
+ },
93
+ });
94
+ expect(violations.length).toBe(0);
95
+ });
96
+
97
+ it('is no fragment', async () => {
98
+ const { violations } = await mlRuleTest(rule, '<html><body><div id="foo"></div></body></html>');
99
+ expect(violations.length).toBe(0);
100
+ });