@markuplint/rules 1.10.4 → 2.0.0-dev.20211115.1
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 +21 -20
- package/lib/attr-check.d.ts +16 -0
- package/lib/attr-check.js +498 -0
- package/lib/attr-duplication/index.d.ts +1 -1
- package/lib/attr-duplication/index.js +5 -8
- package/lib/attr-equal-space-after/index.d.ts +1 -1
- package/lib/attr-equal-space-after/index.js +8 -11
- package/lib/attr-equal-space-before/index.d.ts +1 -1
- package/lib/attr-equal-space-before/index.js +8 -11
- package/lib/attr-spacing/index.d.ts +3 -3
- package/lib/attr-spacing/index.js +19 -21
- package/lib/attr-value-quotes/index.d.ts +1 -1
- package/lib/attr-value-quotes/index.js +9 -12
- package/lib/case-sensitive-attr-name/index.d.ts +1 -1
- package/lib/case-sensitive-attr-name/index.js +11 -14
- package/lib/case-sensitive-tag-name/index.d.ts +1 -1
- package/lib/case-sensitive-tag-name/index.js +8 -11
- package/lib/character-reference/index.d.ts +1 -1
- package/lib/character-reference/index.js +15 -11
- package/lib/class-naming/index.d.ts +1 -1
- package/lib/class-naming/index.js +7 -10
- package/lib/deprecated-attr/index.d.ts +1 -1
- package/lib/deprecated-attr/index.js +6 -9
- package/lib/deprecated-element/index.d.ts +1 -1
- package/lib/deprecated-element/index.js +10 -15
- package/lib/doctype/index.d.ts +1 -1
- package/lib/doctype/index.js +16 -25
- package/lib/helpers.d.ts +12 -11
- package/lib/helpers.js +38 -25
- package/lib/id-duplication/index.d.ts +1 -1
- package/lib/id-duplication/index.js +5 -8
- package/lib/indentation/index.d.ts +3 -3
- package/lib/indentation/index.js +81 -116
- package/lib/index.d.ts +45 -24
- package/lib/index.js +42 -42
- package/lib/invalid-attr/index.d.ts +2 -2
- package/lib/invalid-attr/index.js +23 -25
- package/lib/landmark-roles/index.d.ts +3 -3
- package/lib/landmark-roles/index.js +12 -20
- package/lib/permitted-contents/index.d.ts +2 -2
- package/lib/permitted-contents/index.js +63 -45
- package/lib/permitted-contents/permitted-content.spec-to-regexp.d.ts +2 -2
- package/lib/permitted-contents/permitted-content.spec-to-regexp.js +49 -30
- package/lib/permitted-contents/unfold-content-models-to-tags.d.ts +1 -1
- package/lib/permitted-contents/unfold-content-models-to-tags.js +2 -3
- package/lib/{type-check.d.ts → primitive-check.d.ts} +24 -7
- package/lib/primitive-check.js +109 -0
- package/lib/required-attr/index.d.ts +1 -1
- package/lib/required-attr/index.js +12 -16
- package/lib/required-h1/index.d.ts +3 -3
- package/lib/required-h1/index.js +8 -13
- package/lib/wai-aria/index.d.ts +1 -1
- package/lib/wai-aria/index.js +57 -64
- package/package.json +6 -6
- package/tsconfig.test.json +1 -24
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/type-check.js +0 -321
package/README.md
CHANGED
|
@@ -12,26 +12,27 @@
|
|
|
12
12
|
| -------- | ---- | -------- | ------------------------------------------------- | ------- |
|
|
13
13
|
| ✅ | ✅ | ✅ | [attr-duplication](./src/attr-duplication/) | 🚧 |
|
|
14
14
|
| ✅ | ✅ | ✅ | [character-reference](./src/character-reference/) | 🚧 |
|
|
15
|
-
| 🚧 | 🚧 | 🚧 | [comment](./src/comment/) |
|
|
16
|
-
| ✅ | ✅ | ✅ | [deprecated-attr](./src/deprecated-attr/) |
|
|
17
|
-
| ✅ | ✅ | ✅ | [deprecated-element](./src/deprecated-element/) |
|
|
15
|
+
| 🚧 | 🚧 | 🚧 | [comment](./src/comment/) | |
|
|
16
|
+
| ✅ | ✅ | ✅ | [deprecated-attr](./src/deprecated-attr/) | |
|
|
17
|
+
| ✅ | ✅ | ✅ | [deprecated-element](./src/deprecated-element/) | |
|
|
18
18
|
| ✅ | ✅ | ✅ | [doctype](./src/doctype/) | 🚧 |
|
|
19
|
-
| ✅ | ✅ | ✅ | [id-duplication](./src/id-duplication/) |
|
|
20
|
-
| ✅ | ✅ | ✅ | [permitted-contents](./src/permitted-contents/) |
|
|
21
|
-
| ✅ | ✅ | ✅ | [required-attr](./src/required-attr/) |
|
|
19
|
+
| ✅ | ✅ | ✅ | [id-duplication](./src/id-duplication/) | |
|
|
20
|
+
| ✅ | ✅ | ✅ | [permitted-contents](./src/permitted-contents/) | |
|
|
21
|
+
| ✅ | ✅ | ✅ | [required-attr](./src/required-attr/) | |
|
|
22
|
+
| ✅ | ✅ | ✅ | [invalid-attr](./src/invalid-attr/) | |
|
|
22
23
|
|
|
23
24
|
### Accessibility
|
|
24
25
|
|
|
25
26
|
| Avaiable | Docs | Docs(ja) | Rule | Fixable |
|
|
26
27
|
| -------- | ---- | -------- | --------------------------------------------------------------------- | ------- |
|
|
27
|
-
| 🚧 | 🚧 | 🚧 | [accessible-text](./src/accessible-text/) |
|
|
28
|
-
| 🚧 | 🚧 | 🚧 | [attr-role](./src/permitted-role/) |
|
|
29
|
-
| 🚧 | 🚧 | 🚧 | [heading-in-sectioning-content](./src/heading-in-sectioning-content/) |
|
|
30
|
-
| 🚧 | 🚧 | 🚧 | [heading-in-sectioning-root](./src/heading-in-sectioning-root/) |
|
|
31
|
-
| 🚧 | 🚧 | 🚧 | [heading-levels-skipping](./src/heading-levels-skipping/) |
|
|
32
|
-
| 🚧 | 🚧 | 🚧 | [labeling-controls](./src/labeling-controls/) |
|
|
33
|
-
| ✅ | ✅ | ✅ | [landmark-roles](./src/landmark-roles/) |
|
|
34
|
-
| ✅ | ✅ | ✅ | [required-h1](./src/required-h1/) |
|
|
28
|
+
| 🚧 | 🚧 | 🚧 | [accessible-text](./src/accessible-text/) | |
|
|
29
|
+
| 🚧 | 🚧 | 🚧 | [attr-role](./src/permitted-role/) | |
|
|
30
|
+
| 🚧 | 🚧 | 🚧 | [heading-in-sectioning-content](./src/heading-in-sectioning-content/) | |
|
|
31
|
+
| 🚧 | 🚧 | 🚧 | [heading-in-sectioning-root](./src/heading-in-sectioning-root/) | |
|
|
32
|
+
| 🚧 | 🚧 | 🚧 | [heading-levels-skipping](./src/heading-levels-skipping/) | |
|
|
33
|
+
| 🚧 | 🚧 | 🚧 | [labeling-controls](./src/labeling-controls/) | |
|
|
34
|
+
| ✅ | ✅ | ✅ | [landmark-roles](./src/landmark-roles/) | |
|
|
35
|
+
| ✅ | ✅ | ✅ | [required-h1](./src/required-h1/) | |
|
|
35
36
|
|
|
36
37
|
### Usability
|
|
37
38
|
|
|
@@ -43,10 +44,10 @@
|
|
|
43
44
|
|
|
44
45
|
| Avaiable | Docs | Docs(ja) | Rule | Fixable |
|
|
45
46
|
| -------- | ---- | -------- | ----------------------------------------------------- | ------- |
|
|
46
|
-
| ✅ | ✅ | ✅ | [class-naming](./src/class-naming/) |
|
|
47
|
-
| 🚧 | 🚧 | 🚧 | [custom-element-naming](./src/custom-element-naming/) |
|
|
48
|
-
| 🚧 | 🚧 | 🚧 | [data-attr-naming](./src/data-attr-naming/) |
|
|
49
|
-
| 🚧 | 🚧 | 🚧 | [required-element](./src/required-element/) |
|
|
47
|
+
| ✅ | ✅ | ✅ | [class-naming](./src/class-naming/) | |
|
|
48
|
+
| 🚧 | 🚧 | 🚧 | [custom-element-naming](./src/custom-element-naming/) | |
|
|
49
|
+
| 🚧 | 🚧 | 🚧 | [data-attr-naming](./src/data-attr-naming/) | |
|
|
50
|
+
| 🚧 | 🚧 | 🚧 | [required-element](./src/required-element/) | |
|
|
50
51
|
|
|
51
52
|
### Style
|
|
52
53
|
|
|
@@ -59,10 +60,10 @@
|
|
|
59
60
|
| ✅ | ✅ | ✅ | [case-sensitive-attr-name](./src/case-sensitive-attr-name/) | ✅ |
|
|
60
61
|
| ✅ | ✅ | ✅ | [case-sensitive-tag-name](./src/case-sensitive-tag-name/) | ✅ |
|
|
61
62
|
| 🚧 | 🚧 | 🚧 | [comment-spasing](./src/comment-spasing/) | 🚧 |
|
|
62
|
-
| 🚧 | 🚧 | 🚧 | [event-attr](./src/event-attr/) |
|
|
63
|
+
| 🚧 | 🚧 | 🚧 | [event-attr](./src/event-attr/) | |
|
|
63
64
|
| ✅ | ✅ | ✅ | [indentation](./src/indentation/) | ✅ |
|
|
64
65
|
| 🚧 | 🚧 | 🚧 | [indentation-attr](./src/indentation-attr/) | 🚧 |
|
|
65
|
-
| 🚧 | 🚧 | 🚧 | [path](./src/path/) |
|
|
66
|
+
| 🚧 | 🚧 | 🚧 | [path](./src/path/) | |
|
|
66
67
|
| 🚧 | 🚧 | ✅ | [self-closing-tag](./src/self-closing-tag/) | 🚧 |
|
|
67
68
|
| 🚧 | 🚧 | 🚧 | [tag-omission](./src/tag-omission/) | 🚧 |
|
|
68
69
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Translator } from '@markuplint/i18n';
|
|
2
|
+
import type { Attribute as AttrSpec } from '@markuplint/ml-spec';
|
|
3
|
+
declare type Invalid = {
|
|
4
|
+
invalidType: 'non-existent' | 'invalid-value';
|
|
5
|
+
message: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Use in rules `invalid-attr` and `wai-aria`
|
|
9
|
+
*
|
|
10
|
+
* @param name
|
|
11
|
+
* @param value
|
|
12
|
+
* @param isCustomRule
|
|
13
|
+
* @param spec
|
|
14
|
+
*/
|
|
15
|
+
export declare function attrCheck(t: Translator, name: string, value: string, isCustomRule: boolean, spec?: AttrSpec): Invalid | false;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attrCheck = void 0;
|
|
4
|
+
const primitive_check_1 = require("./primitive-check");
|
|
5
|
+
/**
|
|
6
|
+
* Use in rules `invalid-attr` and `wai-aria`
|
|
7
|
+
*
|
|
8
|
+
* @param name
|
|
9
|
+
* @param value
|
|
10
|
+
* @param isCustomRule
|
|
11
|
+
* @param spec
|
|
12
|
+
*/
|
|
13
|
+
function attrCheck(t, name, value, isCustomRule, spec) {
|
|
14
|
+
if (!isCustomRule) {
|
|
15
|
+
if (/^data-.+$/.test(name)) {
|
|
16
|
+
// Ignore checking because "data-*" attribute is any type
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (/^aria-.+$|^role$/.test(name)) {
|
|
20
|
+
// Ignore checking because ARIA attributes are check on another rule
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Existance
|
|
25
|
+
if (!spec) {
|
|
26
|
+
return {
|
|
27
|
+
invalidType: 'non-existent',
|
|
28
|
+
message: t('{0} is {1:c}', t('the "{0}" {1}', name, 'attribute'), 'disallowed'),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const invalid = valueCheck(t, name, value, spec);
|
|
32
|
+
if (invalid) {
|
|
33
|
+
return {
|
|
34
|
+
invalidType: 'invalid-value',
|
|
35
|
+
message: invalid,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
exports.attrCheck = attrCheck;
|
|
41
|
+
function valueCheck(t, name, value, spec) {
|
|
42
|
+
// Valid because any string value is acceptable
|
|
43
|
+
if (typeof spec.type !== 'string' && 'enum' in spec.type) {
|
|
44
|
+
// has "enum"
|
|
45
|
+
return includesEnum(t, name, value, spec.type.enum);
|
|
46
|
+
}
|
|
47
|
+
const t_theNameAttribute = t('the "{0}" {1}', name, 'attribute');
|
|
48
|
+
if (spec.type === 'NonEmptyString' && value === '') {
|
|
49
|
+
return t('{0} must not be {1}', t('{0} of {1}', t('the {0}', 'value'), t_theNameAttribute), 'empty string');
|
|
50
|
+
}
|
|
51
|
+
if (spec.type === 'Boolean') {
|
|
52
|
+
// Valid because an attribute is exist
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (spec.type === 'Function') {
|
|
56
|
+
// TODO: To eval function-body string
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (spec.type === 'Date') {
|
|
60
|
+
// TODO: https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (spec.type === 'Int') {
|
|
64
|
+
if ((0, primitive_check_1.intCheck)(value)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return t('{0} expects {1}', t_theNameAttribute, 'integer');
|
|
68
|
+
}
|
|
69
|
+
if (spec.type === 'Uint') {
|
|
70
|
+
if ((0, primitive_check_1.uintCheck)(value)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return t('{0} expects {1}', t_theNameAttribute, 'non-negative integer');
|
|
74
|
+
}
|
|
75
|
+
if (spec.type === 'Float') {
|
|
76
|
+
if ((0, primitive_check_1.floatCheck)(value)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return t('{0} expects {1}', t_theNameAttribute, 'floating-point number');
|
|
80
|
+
}
|
|
81
|
+
if (spec.type === 'NonZeroUint') {
|
|
82
|
+
if ((0, primitive_check_1.nonZeroUintCheck)(value)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return t('{0} expects {1}', t_theNameAttribute, t('{0} greater than {1}', 'floating-point number', 'zero'));
|
|
86
|
+
}
|
|
87
|
+
if (spec.type === 'ZeroToOne') {
|
|
88
|
+
if ((0, primitive_check_1.range)(value, 0, 1)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('in the range between {0} and {1}', 'zero', 'one'));
|
|
92
|
+
}
|
|
93
|
+
if (spec.type === 'AcceptList') {
|
|
94
|
+
// TODO: https://html.spec.whatwg.org/multipage/input.html#attr-input-accept
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (spec.type === 'AutoComplete') {
|
|
98
|
+
// TODO: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-detail-tokens
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (spec.type === 'BCP47') {
|
|
102
|
+
// TODO: https://tools.ietf.org/html/bcp47
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (spec.type === 'Color') {
|
|
106
|
+
// TODO: https://drafts.csswg.org/css-color/#typedef-color
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (spec.type === 'ColSpan') {
|
|
110
|
+
/**
|
|
111
|
+
* > value must be a valid non-negative integer greater than zero and less than or equal to 1000.
|
|
112
|
+
*
|
|
113
|
+
* @see https://html.spec.whatwg.org/multipage/tables.html#attr-tdth-colspan
|
|
114
|
+
*/
|
|
115
|
+
if ((0, primitive_check_1.intCheck)(value) && (0, primitive_check_1.range)(value, 0, 1000)) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('{0:c} and {1:c}', t('{0} greater than {1}', 'non-negative integer', 'zero'), t('less than or equal to {0}', 1000)));
|
|
119
|
+
}
|
|
120
|
+
if (spec.type === 'Coords') {
|
|
121
|
+
// TODO: https://html.spec.whatwg.org/multipage/image-maps.html#attr-area-coords
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
if (spec.type === 'Crossorigin') {
|
|
125
|
+
// TODO: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (spec.type === 'DateTime') {
|
|
129
|
+
// TODO: https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
if (spec.type === 'Destination') {
|
|
133
|
+
// TODO: https://html.spec.whatwg.org/multipage/semantics.html#attr-link-as
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (spec.type === 'DOMID') {
|
|
137
|
+
// TODO: Searching ID in Document
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (spec.type === 'DOMIDList') {
|
|
141
|
+
// TODO: Searching ID in Document
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (spec.type === 'IRI') {
|
|
145
|
+
// TODO: https://developer.mozilla.org/ja/docs/Web/SVG/Content_type#iri
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
if (spec.type === 'ItemType') {
|
|
149
|
+
// TODO: https://html.spec.whatwg.org/multipage/microdata.html#attr-itemtype
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
if (spec.type === 'LinkSizes') {
|
|
153
|
+
// TODO: https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
if (spec.type === 'LinkType') {
|
|
157
|
+
// TODO: https://html.spec.whatwg.org/multipage/links.html#linkTypes
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
if (spec.type === 'LinkTypeList') {
|
|
161
|
+
// TODO: https://html.spec.whatwg.org/multipage/links.html#linkTypes
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (spec.type === 'MediaQuery') {
|
|
165
|
+
// TODO: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-media-query-list
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (spec.type === 'MediaQueryList') {
|
|
169
|
+
// TODO: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-media-query-list
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
if (spec.type === 'MIMEType') {
|
|
173
|
+
// TODO: https://mimesniff.spec.whatwg.org/#valid-mime-type
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (spec.type === 'ReferrerPolicy') {
|
|
177
|
+
/**
|
|
178
|
+
* @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#referrer-policy-attributes
|
|
179
|
+
*/
|
|
180
|
+
return includesEnum(t, name, value, [
|
|
181
|
+
'',
|
|
182
|
+
'no-referrer',
|
|
183
|
+
'no-referrer-when-downgrade',
|
|
184
|
+
'same-origin',
|
|
185
|
+
'origin',
|
|
186
|
+
'strict-origin',
|
|
187
|
+
'origin-when-cross-origin',
|
|
188
|
+
'strict-origin-when-cross-origin',
|
|
189
|
+
'unsafe-url',
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
if (spec.type === 'RowSpan') {
|
|
193
|
+
/**
|
|
194
|
+
* > value must be a valid non-negative integer less than or equal to 65534.
|
|
195
|
+
*
|
|
196
|
+
* @see https://html.spec.whatwg.org/multipage/tables.html#attr-tdth-rowspan
|
|
197
|
+
*/
|
|
198
|
+
if ((0, primitive_check_1.intCheck)(value) && (0, primitive_check_1.range)(value, 0, 65534)) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('{0:c} and {1:c}', t('{0} greater than {1}', 'non-negative integer', 'zero'), t('less than or equal to {0}', 65534)));
|
|
202
|
+
}
|
|
203
|
+
if (spec.type === 'SourceSizeList') {
|
|
204
|
+
// TODO: https://html.spec.whatwg.org/multipage/images.html#sizes-attributes
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (spec.type === 'SrcSet') {
|
|
208
|
+
// TODO: https://html.spec.whatwg.org/multipage/images.html#srcset-attribute
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
if (spec.type === 'TabIndex') {
|
|
212
|
+
/**
|
|
213
|
+
* > ## omitted (or non-integer values)
|
|
214
|
+
* >
|
|
215
|
+
* > The user agent will decide whether the element is focusable, and if it is, whether it is sequentially focusable or click focusable (or both).
|
|
216
|
+
* >
|
|
217
|
+
* > ## −1 (or other negative integer values)
|
|
218
|
+
* >
|
|
219
|
+
* > Causes the element to be focusable, and indicates that the author would prefer the element to be click focusable but not sequentially focusable. The user agent might ignore this preference for click and sequential focusability, e.g., for specific element types according to platform conventions, or for keyboard-only users.
|
|
220
|
+
* >
|
|
221
|
+
* > ## 0
|
|
222
|
+
* >
|
|
223
|
+
* > Causes the element to be focusable, and indicates that the author would prefer the element to be both click focusable and sequentially focusable. The user agent might ignore this preference for click and sequential focusabiity.
|
|
224
|
+
* >
|
|
225
|
+
* > ## positive integer values
|
|
226
|
+
* >
|
|
227
|
+
* > Behaves the same as 0, but in addition creates a relative ordering within a tabindex-ordered focus navigation scope, so that elements with higher tabindex attribute value come later.
|
|
228
|
+
*
|
|
229
|
+
* @see https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex
|
|
230
|
+
*/
|
|
231
|
+
if ((0, primitive_check_1.intCheck)(value)) {
|
|
232
|
+
const i = parseInt(value);
|
|
233
|
+
if (-1 <= i) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
if (-1 > i) {
|
|
237
|
+
return t('{0} behaves the same as {1} if {2}', t_theNameAttribute, '-1', t('less than {0}', '-1'));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('either {0}', t(['-1', 'zero', 'non-negative integer'])));
|
|
241
|
+
}
|
|
242
|
+
if (spec.type === 'Target') {
|
|
243
|
+
// TODO: https://html.spec.whatwg.org/multipage/links.html#attr-hyperlink-target
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (spec.type === 'URL') {
|
|
247
|
+
// TODO: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#valid-url-potentially-surrounded-by-spaces
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
if (spec.type === 'URLHash') {
|
|
251
|
+
/**
|
|
252
|
+
* https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-hash-name-reference
|
|
253
|
+
*/
|
|
254
|
+
const valid = value[0] === '#';
|
|
255
|
+
if (valid) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('valid {0}', 'hash-name reference'));
|
|
259
|
+
}
|
|
260
|
+
if (spec.type === 'URLList') {
|
|
261
|
+
// TODO: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#valid-url-potentially-surrounded-by-spaces
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
if (spec.type === 'CSSAngle') {
|
|
265
|
+
/**
|
|
266
|
+
* @see https://drafts.csswg.org/css-values/#angles
|
|
267
|
+
*/
|
|
268
|
+
const valid = (0, primitive_check_1.numberCheckWithUnit)(value, ['deg', 'grad', 'rad', 'turn']);
|
|
269
|
+
if (valid) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
return t('{0} expects {1}', t_theNameAttribute, 'angle');
|
|
273
|
+
}
|
|
274
|
+
if (spec.type === 'CSSBlendMode') {
|
|
275
|
+
/**
|
|
276
|
+
* @see https://drafts.fxtf.org/compositing/#ltblendmodegt
|
|
277
|
+
*/
|
|
278
|
+
return includesEnum(t, name, value, [
|
|
279
|
+
'normal',
|
|
280
|
+
'multiply',
|
|
281
|
+
'screen',
|
|
282
|
+
'overlay',
|
|
283
|
+
'darken',
|
|
284
|
+
'lighten',
|
|
285
|
+
'color-dodge',
|
|
286
|
+
'color-burn',
|
|
287
|
+
'hard-light',
|
|
288
|
+
'soft-light',
|
|
289
|
+
'difference',
|
|
290
|
+
'exclusion',
|
|
291
|
+
'hue',
|
|
292
|
+
'saturation',
|
|
293
|
+
'color',
|
|
294
|
+
'luminosity',
|
|
295
|
+
]);
|
|
296
|
+
}
|
|
297
|
+
if (spec.type === 'CSSClipPath') {
|
|
298
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
if (spec.type === 'CSSCustomIdent') {
|
|
302
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
if (spec.type === 'CSSDisplay') {
|
|
306
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/display
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
if (spec.type === 'CSSFilter') {
|
|
310
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/filter
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
if (spec.type === 'CSSFontFamily') {
|
|
314
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/font-family
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
if (spec.type === 'CSSFontSize') {
|
|
318
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/font-size
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
if (spec.type === 'CSSFontVariant') {
|
|
322
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
if (spec.type === 'CSSFontWeight') {
|
|
326
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
if (spec.type === 'CSSMask') {
|
|
330
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/mask
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
if (spec.type === 'CSSOpacity') {
|
|
334
|
+
/**
|
|
335
|
+
* @see https://drafts.csswg.org/css-color/#typedef-alpha-value
|
|
336
|
+
*/
|
|
337
|
+
const { num, unit } = (0, primitive_check_1.splitUnit)(value);
|
|
338
|
+
if (unit === '%') {
|
|
339
|
+
const vaild = (0, primitive_check_1.range)(num, 0, 100);
|
|
340
|
+
if (vaild) {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('{0} as {1}', t('{0} to {1}', '0%', '100%'), 'alpha channel value'));
|
|
344
|
+
}
|
|
345
|
+
const vaild = (0, primitive_check_1.range)(num, 0, 1);
|
|
346
|
+
if (vaild) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
return t('{0} expects {1:c}', t_theNameAttribute, t('{0} as {1}', t('{0} to {1}', '0', '1'), 'alpha channel value'));
|
|
350
|
+
}
|
|
351
|
+
if (spec.type === 'CSSTextDecoration') {
|
|
352
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
if (spec.type === 'CSSTransformList') {
|
|
356
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
if (spec.type === 'CSSTransformOrigin') {
|
|
360
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
if (spec.type === 'CSSURL') {
|
|
364
|
+
// TODO: https://www.w3.org/TR/css3-values/#url-value
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
if (spec.type === 'SVGAnimatableValue') {
|
|
368
|
+
// TODO
|
|
369
|
+
/**
|
|
370
|
+
* The exact value type for this attribute depends on the value of the attribute
|
|
371
|
+
* that will be animated.
|
|
372
|
+
*
|
|
373
|
+
* ```svg
|
|
374
|
+
* <rect x="10" y="10" height="100">
|
|
375
|
+
* <animate attributeName="width" fill="freeze" from="100" to="150" dur="3s"/>
|
|
376
|
+
* </rect>
|
|
377
|
+
* ```
|
|
378
|
+
*
|
|
379
|
+
* The `from` and `to` attributes of the `animate` element are SVGAnimatableValue.
|
|
380
|
+
*/
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
if (spec.type === 'SVGBeginValueList') {
|
|
384
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/begin
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
if (spec.type === 'SVGClockValue') {
|
|
388
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#clock-value
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
if (spec.type === 'SVGColorMatrix') {
|
|
392
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feColorMatrix
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
if (spec.type === 'SVGDashArray') {
|
|
396
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
if (spec.type === 'SVGEndValueList') {
|
|
400
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/end
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
if (spec.type === 'SVGFilterPrimitiveReference') {
|
|
404
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/result#usage_notes
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
if (spec.type === 'SVGKernelMatrix') {
|
|
408
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelMatrix
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
if (spec.type === 'SVGKeyPoints') {
|
|
412
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyPoints
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
if (spec.type === 'SVGKeySplines') {
|
|
416
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keySplines
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
if (spec.type === 'SVGKeyTimes') {
|
|
420
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyTimes
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
if (spec.type === 'SVGLanguageTags') {
|
|
424
|
+
/**
|
|
425
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/systemLanguage
|
|
426
|
+
*/
|
|
427
|
+
// TODO: List of BCP47
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
if (spec.type === 'SVGLength') {
|
|
431
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#length
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (spec.type === 'SVGLengthList') {
|
|
435
|
+
/**
|
|
436
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#length
|
|
437
|
+
*/
|
|
438
|
+
// TODO: List of SVGLength
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
if (spec.type === 'SVGNumberList') {
|
|
442
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/tableValues#usage_notes
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
if (spec.type === 'SVGNumberOptionalNumber') {
|
|
446
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#number-optional-number
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (spec.type === 'SVGOrigin') {
|
|
450
|
+
// TODO: https://www.w3.org/TR/2001/REC-smil-animation-20010904/#MotionOriginAttribute
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
if (spec.type === 'SVGPaint') {
|
|
454
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#paint
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
if (spec.type === 'SVGPathCommands') {
|
|
458
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
if (spec.type === 'SVGPercentage') {
|
|
462
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#percentage
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
if (spec.type === 'SVGPercentageList') {
|
|
466
|
+
/**
|
|
467
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#percentage
|
|
468
|
+
*/
|
|
469
|
+
// TODO: List of SVGPercentage
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
if (spec.type === 'SVGPoints') {
|
|
473
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/points
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
if (spec.type === 'SVGPreserveAspectRatio') {
|
|
477
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
if (spec.type === 'SVGViewBox') {
|
|
481
|
+
// TODO: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
*
|
|
488
|
+
* @param name
|
|
489
|
+
* @param value
|
|
490
|
+
* @param enumValues
|
|
491
|
+
*/
|
|
492
|
+
function includesEnum(t, name, value, enumValues) {
|
|
493
|
+
const valid = enumValues.includes(value.toLowerCase());
|
|
494
|
+
if (valid) {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
return t('{0} expects {1:c}', t('the "{0}" {1}', name, 'attribute'), t('either {0}', t(enumValues)));
|
|
498
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("@markuplint/ml-core").
|
|
1
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<null, null>;
|
|
2
2
|
export default _default;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = ml_core_1.createRule({
|
|
5
|
-
name: 'attr-duplication',
|
|
4
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
6
5
|
defaultValue: null,
|
|
7
6
|
defaultOptions: null,
|
|
8
|
-
async verify(document,
|
|
9
|
-
const
|
|
10
|
-
const message = translate('Duplicate {0}', 'attribute name');
|
|
7
|
+
async verify({ document, report, t }) {
|
|
8
|
+
const message = t('{0} is {1:c}', t('the {0}', 'attribute name'), 'duplicated');
|
|
11
9
|
await document.walkOn('Element', async (node) => {
|
|
12
10
|
const attrNameStack = [];
|
|
13
11
|
for (const attr of node.attributes) {
|
|
@@ -17,8 +15,8 @@ exports.default = ml_core_1.createRule({
|
|
|
17
15
|
const attrName = attr.getName();
|
|
18
16
|
const name = node.isCustomElement ? attrName.potential : attrName.potential.toLowerCase();
|
|
19
17
|
if (attrNameStack.includes(name)) {
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
report({
|
|
19
|
+
scope: node,
|
|
22
20
|
message,
|
|
23
21
|
line: attrName.line,
|
|
24
22
|
col: attrName.col,
|
|
@@ -30,6 +28,5 @@ exports.default = ml_core_1.createRule({
|
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
30
|
});
|
|
33
|
-
return reports;
|
|
34
31
|
},
|
|
35
32
|
});
|