@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,470 @@
1
+ const { mlRuleTest } = require('markuplint');
2
+
3
+ const rule = require('../../lib/class-naming').default;
4
+
5
+ test('pass class name', async () => {
6
+ const { violations } = await mlRuleTest(
7
+ rule,
8
+ `
9
+ <div class="c-root">
10
+ <div class="c-root__el"></div>
11
+ <div class="c-root__el2"></div>
12
+ </div>
13
+ `,
14
+ {
15
+ rule: {
16
+ severity: 'error',
17
+ value: '/^c-[a-z]+/',
18
+ },
19
+ },
20
+ );
21
+ expect(violations.length).toBe(0);
22
+ });
23
+
24
+ test('unmatched class name', async () => {
25
+ const { violations } = await mlRuleTest(
26
+ rule,
27
+ `
28
+ <div class="c-root">
29
+ <div class="c-root__el"></div>
30
+ <div class="c-root__el2"></div>
31
+ </div>
32
+ `,
33
+ {
34
+ rule: {
35
+ severity: 'error',
36
+ value: '/^c-[a-z]+/',
37
+ },
38
+ nodeRule: [
39
+ {
40
+ selector: '[class^="c-"]:not([class*="__"])',
41
+ rule: {
42
+ severity: 'error',
43
+ value: '/^c-[a-z]+__[a-z0-9]+/',
44
+ },
45
+ },
46
+ ],
47
+ },
48
+ );
49
+ expect(violations).toStrictEqual([
50
+ {
51
+ severity: 'error',
52
+ message: 'The "c-root" class name is unmatched with the below patterns: "/^c-[a-z]+__[a-z0-9]+/"',
53
+ line: 2,
54
+ col: 15,
55
+ raw: 'c-root',
56
+ },
57
+ ]);
58
+ });
59
+
60
+ test('childNodeRules', async () => {
61
+ const { violations } = await mlRuleTest(
62
+ rule,
63
+ `
64
+ <div class="c-root">
65
+ <div class="c-root_x"></div>
66
+ </div>
67
+ `,
68
+ {
69
+ rule: {
70
+ severity: 'error',
71
+ value: '/^c-[a-z]+/',
72
+ },
73
+ childNodeRule: [
74
+ {
75
+ selector: '[class^="c-"]:not([class*="__"])',
76
+ rule: {
77
+ severity: 'error',
78
+ value: '/^c-[a-z]+__[a-z0-9]+/',
79
+ },
80
+ },
81
+ ],
82
+ },
83
+ );
84
+ expect(violations).toStrictEqual([
85
+ {
86
+ severity: 'error',
87
+ message: 'The "c-root_x" class name is unmatched with the below patterns: "/^c-[a-z]+__[a-z0-9]+/"',
88
+ line: 3,
89
+ col: 16,
90
+ raw: 'c-root_x',
91
+ },
92
+ ]);
93
+ });
94
+
95
+ test('unmatched class name (2)', async () => {
96
+ const { violations } = await mlRuleTest(
97
+ rule,
98
+ `
99
+ <div class="c-root">
100
+ <div class="c-root__x">
101
+ <div class="c-root__y"></div>
102
+ <main>
103
+ <div class="hoge"></div>
104
+ </main>
105
+ </div>
106
+ </div>
107
+ `,
108
+ {
109
+ rule: {
110
+ severity: 'error',
111
+ value: '/^c-[a-z]+/',
112
+ },
113
+ },
114
+ );
115
+ expect(violations).toStrictEqual([
116
+ {
117
+ severity: 'error',
118
+ message: 'The "hoge" class name is unmatched with the below patterns: "/^c-[a-z]+/"',
119
+ line: 6,
120
+ col: 18,
121
+ raw: 'hoge',
122
+ },
123
+ ]);
124
+ });
125
+
126
+ test('multi pattern', async () => {
127
+ const { violations } = await mlRuleTest(
128
+ rule,
129
+ `
130
+ <div class="c-root">
131
+ <div class="c-root__el"></div>
132
+ <div class="exceptional"></div>
133
+ </div>
134
+ `,
135
+ {
136
+ rule: {
137
+ severity: 'error',
138
+ value: ['/^c-[a-z]+/', 'exceptional'],
139
+ },
140
+ },
141
+ );
142
+ expect(violations.length).toBe(0);
143
+ });
144
+
145
+ test('childNodeRules multi selectors', async () => {
146
+ const { violations } = await mlRuleTest(
147
+ rule,
148
+ `
149
+ <div class="c-root">
150
+ <div class="c-root__x">
151
+ <div class="c-root__y"></div>
152
+ <main>
153
+ <div class="hoge"></div>
154
+ </main>
155
+ </div>
156
+ </div>
157
+ `,
158
+ {
159
+ rule: {
160
+ severity: 'error',
161
+ value: '/^c-[a-z]+/',
162
+ },
163
+ childNodeRule: [
164
+ {
165
+ selector: ':where([class^="c-"]:not([class*="__"]))',
166
+ rule: {
167
+ severity: 'error',
168
+ value: '/^c-[a-z]+__[a-z0-9]+/',
169
+ },
170
+ inheritance: true,
171
+ },
172
+ {
173
+ selector: 'main',
174
+ rule: {
175
+ severity: 'error',
176
+ value: 'hoge2',
177
+ },
178
+ inheritance: true,
179
+ },
180
+ ],
181
+ },
182
+ );
183
+ expect(violations).toStrictEqual([
184
+ {
185
+ severity: 'error',
186
+ message: 'The "hoge" class name is unmatched with the below patterns: "hoge2"',
187
+ line: 6,
188
+ col: 18,
189
+ raw: 'hoge',
190
+ },
191
+ ]);
192
+ });
193
+
194
+ test('childNodeRules multi selectors (No error)', async () => {
195
+ const { violations } = await mlRuleTest(
196
+ rule,
197
+ `
198
+ <div class="c-root">
199
+ <div class="c-root__x">
200
+ <div class="c-root__y"></div>
201
+ <main>
202
+ <div class="hoge"></div>
203
+ </main>
204
+ </div>
205
+ </div>
206
+ `,
207
+ {
208
+ rule: {
209
+ severity: 'error',
210
+ value: '/^c-[a-z]+/',
211
+ },
212
+ childNodeRule: [
213
+ {
214
+ selector: ':where([class^="c-"]:not([class*="__"]))',
215
+ rule: {
216
+ severity: 'error',
217
+ value: '/^c-[a-z]+__[a-z0-9]+/',
218
+ },
219
+ inheritance: true,
220
+ },
221
+ {
222
+ selector: 'main',
223
+ rule: {
224
+ severity: 'error',
225
+ value: '/^(?!c-).+$/',
226
+ },
227
+ inheritance: true,
228
+ },
229
+ ],
230
+ },
231
+ );
232
+ expect(violations.length).toBe(0);
233
+ });
234
+
235
+ test('Dynamic value', async () => {
236
+ const { violations } = await mlRuleTest(rule, '<div className={style}></div>', {
237
+ rule: {
238
+ value: '/^c-[a-z]+/',
239
+ },
240
+ parser: {
241
+ '.*': '@markuplint/jsx-parser',
242
+ },
243
+ });
244
+ expect(violations.length).toBe(0);
245
+ });
246
+
247
+ test('regexSelector', async () => {
248
+ const { violations } = await mlRuleTest(
249
+ rule,
250
+ `<section class="Card">
251
+ <div class="Card__header">
252
+ <div class="Heading"><h3 class="Heading__lv3">Title</h3></div>
253
+ </div>
254
+ <div class="Card__body">
255
+ <div class="List">
256
+ <ul class="List__group">
257
+ <li>...</li>
258
+ <li>...</li>
259
+ <li>...</li>
260
+ </ul>
261
+ </div>
262
+ </div>
263
+ </section>
264
+
265
+ <section class="Card">
266
+ <div class="Card__header">
267
+ <!-- 👎 It is "Card" scope, Don't use the element owned "Heading" -->
268
+ <h3 class="Heading__lv3">Title</h3>
269
+ </div>
270
+ <div class="Card__body">
271
+ <div class="Card__body-el">...</div>
272
+ <!-- 👎 It is "Card" scope, Don't use the element owned "List" -->
273
+ <ul class="List__group">
274
+ <li>...</li>
275
+ <li>...</li>
276
+ <li>...</li>
277
+ </ul>
278
+ <div class="List">
279
+ <!-- 👎 It is not "Card" scope instead of "List" scope here -->
280
+ <ul class="Card__list">
281
+ <li>...</li>
282
+ <li>...</li>
283
+ <li>...</li>
284
+ </ul>
285
+ </div>
286
+ </div>
287
+ </section>
288
+ `,
289
+ {
290
+ rule: '/.+/',
291
+ childNodeRule: [
292
+ {
293
+ regexSelector: {
294
+ attrName: 'class',
295
+ attrValue: '/^(?<BlockName>[A-Z][a-z0-9]+)(?:__[a-z][a-z0-9-]+)?$/',
296
+ },
297
+ rule: {
298
+ value: ['/^{{BlockName}}__[a-z][a-z0-9-]+$/', '/^([A-Z][a-z0-9]+)$/'],
299
+ reason: 'Do not allow include the element in a no-own block.',
300
+ },
301
+ },
302
+ ],
303
+ },
304
+ );
305
+ expect(violations).toStrictEqual([
306
+ {
307
+ severity: 'warning',
308
+ line: 19,
309
+ col: 14,
310
+ raw: 'Heading__lv3',
311
+ message:
312
+ 'The "Heading__lv3" class name is unmatched with the below patterns: "/^Card__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
313
+ reason: 'Do not allow include the element in a no-own block.',
314
+ },
315
+ {
316
+ severity: 'warning',
317
+ line: 24,
318
+ col: 14,
319
+ raw: 'List__group',
320
+ message:
321
+ 'The "List__group" class name is unmatched with the below patterns: "/^Card__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
322
+ reason: 'Do not allow include the element in a no-own block.',
323
+ },
324
+ {
325
+ severity: 'warning',
326
+ line: 31,
327
+ col: 15,
328
+ raw: 'Card__list',
329
+ message:
330
+ 'The "Card__list" class name is unmatched with the below patterns: "/^List__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
331
+ reason: 'Do not allow include the element in a no-own block.',
332
+ },
333
+ ]);
334
+ });
335
+
336
+ test('regexSelector inheritance', async () => {
337
+ const { violations } = await mlRuleTest(
338
+ rule,
339
+ `<html>
340
+ <body class="Card">
341
+ <div class="Card__heading">
342
+ <div class="Heading">
343
+ <div class="Heading__text"></div>
344
+ </div>
345
+ </div>
346
+ <div class="Card__text"></div>
347
+ <div class="Heading_text"></div>
348
+ <div class="Card_text"></div>
349
+ </body>
350
+ </html>
351
+ `,
352
+ {
353
+ rule: '/.+/',
354
+ childNodeRule: [
355
+ {
356
+ regexSelector: {
357
+ attrName: 'class',
358
+ attrValue: '/^(?<BlockName>[A-Z][a-z0-9]+)(?:__[a-z][a-z0-9-]+)?$/',
359
+ },
360
+ inheritance: true,
361
+ rule: {
362
+ value: ['/^{{BlockName}}__[a-z][a-z0-9-]+$/', '/^([A-Z][a-z0-9]+)$/'],
363
+ reason: 'Do not allow include the element in a no-own block.',
364
+ },
365
+ },
366
+ ],
367
+ },
368
+ );
369
+ expect(violations).toStrictEqual([
370
+ {
371
+ severity: 'warning',
372
+ line: 9,
373
+ col: 14,
374
+ message:
375
+ 'The "Heading_text" class name is unmatched with the below patterns: "/^Card__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
376
+ raw: 'Heading_text',
377
+ reason: 'Do not allow include the element in a no-own block.',
378
+ },
379
+ {
380
+ severity: 'warning',
381
+ line: 10,
382
+ col: 14,
383
+ message:
384
+ 'The "Card_text" class name is unmatched with the below patterns: "/^Card__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
385
+ raw: 'Card_text',
386
+ reason: 'Do not allow include the element in a no-own block.',
387
+ },
388
+ ]);
389
+ });
390
+
391
+ test('pug + regexSelector', async () => {
392
+ const { violations } = await mlRuleTest(
393
+ rule,
394
+ `section.Card
395
+ .Card__header
396
+ .Heading
397
+ h3.Heading__lv3 Title
398
+ .Card__body
399
+ .List
400
+ ul.List__group
401
+ li ...
402
+ li ...
403
+ li ...
404
+ section.Card
405
+ .Card__header
406
+ // 👎 It is "Card" scope, Don't use the element owned "Heading"
407
+ h3.Heading__lv3 Title
408
+ .Card__body
409
+ .Card__body-el ...
410
+ // 👎 It is "Card" scope, Don't use the element owned "List"
411
+ ul.List__group
412
+ li ...
413
+ li ...
414
+ li ...
415
+ .List
416
+ // 👎 It is not "Card" scope instead of "List" scope here
417
+ ul.Card__list
418
+ li ...
419
+ li ...
420
+ li ...
421
+ `,
422
+ {
423
+ parser: {
424
+ '.*': '@markuplint/pug-parser',
425
+ },
426
+ rule: '/.+/',
427
+ childNodeRule: [
428
+ {
429
+ regexSelector: {
430
+ attrName: 'class',
431
+ attrValue: '/^(?<BlockName>[A-Z][a-z0-9]+)(?:__[a-z][a-z0-9-]+)?$/',
432
+ },
433
+ rule: {
434
+ value: ['/^{{BlockName}}__[a-z][a-z0-9-]+$/', '/^([A-Z][a-z0-9]+)$/'],
435
+ reason: 'Do not allow include the element in a no-own block.',
436
+ },
437
+ },
438
+ ],
439
+ },
440
+ );
441
+ expect(violations).toStrictEqual([
442
+ {
443
+ severity: 'warning',
444
+ line: 14,
445
+ col: 5,
446
+ message:
447
+ 'The "Heading__lv3" class name is unmatched with the below patterns: "/^Card__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
448
+ raw: '.Heading__lv3',
449
+ reason: 'Do not allow include the element in a no-own block.',
450
+ },
451
+ {
452
+ severity: 'warning',
453
+ line: 18,
454
+ col: 5,
455
+ message:
456
+ 'The "List__group" class name is unmatched with the below patterns: "/^Card__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
457
+ raw: '.List__group',
458
+ reason: 'Do not allow include the element in a no-own block.',
459
+ },
460
+ {
461
+ severity: 'warning',
462
+ line: 24,
463
+ col: 6,
464
+ message:
465
+ 'The "Card__list" class name is unmatched with the below patterns: "/^List__[a-z][a-z0-9-]+$/", "/^([A-Z][a-z0-9]+)$/"',
466
+ raw: '.Card__list',
467
+ reason: 'Do not allow include the element in a no-own block.',
468
+ },
469
+ ]);
470
+ });