@markuplint/rules 2.0.0-dev.2021117.3 → 2.0.0-dev.20211213.2
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 +51 -455
- package/lib/case-sensitive-attr-name/index.js +2 -3
- 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.js +1 -2
- package/lib/helpers.d.ts +8 -3
- package/lib/helpers.js +8 -41
- package/lib/index.d.ts +9 -2
- package/lib/index.js +4 -0
- package/lib/ineffective-attr/index.d.ts +2 -0
- package/lib/ineffective-attr/index.js +42 -0
- package/lib/invalid-attr/index.d.ts +3 -1
- package/lib/invalid-attr/index.js +16 -6
- package/lib/no-boolean-attr-value/index.d.ts +2 -0
- package/lib/no-boolean-attr-value/index.js +49 -0
- package/lib/required-attr/index.d.ts +5 -1
- package/lib/required-attr/index.js +60 -18
- package/lib/wai-aria/index.js +2 -2
- package/package.json +10 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/primitive-check.d.ts +0 -48
- package/lib/primitive-check.js +0 -109
package/lib/attr-check.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { Translator } from '@markuplint/i18n';
|
|
2
|
-
import type { Attribute as AttrSpec } from '@markuplint/ml-spec';
|
|
2
|
+
import type { Attribute as AttrSpec, AttributeType } from '@markuplint/ml-spec';
|
|
3
3
|
declare type Invalid = {
|
|
4
4
|
invalidType: 'non-existent' | 'invalid-value';
|
|
5
5
|
message: string;
|
|
6
|
+
loc?: Loc;
|
|
7
|
+
};
|
|
8
|
+
declare type Loc = {
|
|
9
|
+
raw: string;
|
|
10
|
+
line: number;
|
|
11
|
+
col: number;
|
|
6
12
|
};
|
|
7
13
|
/**
|
|
8
14
|
* Use in rules `invalid-attr` and `wai-aria`
|
|
@@ -13,4 +19,5 @@ declare type Invalid = {
|
|
|
13
19
|
* @param spec
|
|
14
20
|
*/
|
|
15
21
|
export declare function attrCheck(t: Translator, name: string, value: string, isCustomRule: boolean, spec?: AttrSpec): Invalid | false;
|
|
22
|
+
export declare function valueCheck(t: Translator, name: string, value: string, type: AttributeType): string | [string, Loc] | false;
|
|
16
23
|
export {};
|
package/lib/attr-check.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.attrCheck = void 0;
|
|
4
|
-
const
|
|
3
|
+
exports.valueCheck = exports.attrCheck = void 0;
|
|
4
|
+
const types_1 = require("@markuplint/types");
|
|
5
|
+
const create_message_1 = require("./create-message");
|
|
6
|
+
const debug_1 = require("./debug");
|
|
5
7
|
/**
|
|
6
8
|
* Use in rules `invalid-attr` and `wai-aria`
|
|
7
9
|
*
|
|
@@ -23,476 +25,70 @@ function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
23
25
|
}
|
|
24
26
|
// Existance
|
|
25
27
|
if (!spec) {
|
|
28
|
+
(0, debug_1.log)('The "%s" attribute DOES\'NT EXIST in the spec', name);
|
|
26
29
|
return {
|
|
27
30
|
invalidType: 'non-existent',
|
|
28
31
|
message: t('{0} is {1:c}', t('the "{0}" {1}', name, 'attribute'), 'disallowed'),
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
34
|
+
const nameCaseSensitive = /[A-Z]/.test(spec.name);
|
|
35
|
+
if (nameCaseSensitive && name !== spec.name) {
|
|
36
|
+
(0, debug_1.log)('The "%s" attribute name is unmatched in case-sensitive', name);
|
|
33
37
|
return {
|
|
34
|
-
invalidType: '
|
|
35
|
-
message:
|
|
38
|
+
invalidType: 'non-existent',
|
|
39
|
+
message: t('{0} is {1:c}', t('the "{0}" {1}', name, 'attribute'), 'disallowed') +
|
|
40
|
+
t('. ') +
|
|
41
|
+
t('Did you mean "{0*}"?', spec.name),
|
|
36
42
|
};
|
|
37
43
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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;
|
|
44
|
+
const types = Array.isArray(spec.type) ? spec.type : [spec.type];
|
|
45
|
+
const invalidList = types.map(type => {
|
|
46
|
+
if (!type) {
|
|
47
|
+
(0, debug_1.log)('attrCheck: %o', arguments);
|
|
48
|
+
throw new Error('type is empty in spec');
|
|
117
49
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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;
|
|
50
|
+
const invalid = valueCheck(t, name, value, type);
|
|
51
|
+
if (invalid) {
|
|
52
|
+
if (typeof invalid === 'string') {
|
|
53
|
+
return {
|
|
54
|
+
invalidType: 'invalid-value',
|
|
55
|
+
message: invalid,
|
|
56
|
+
};
|
|
235
57
|
}
|
|
236
|
-
|
|
237
|
-
return
|
|
58
|
+
else {
|
|
59
|
+
return {
|
|
60
|
+
invalidType: 'invalid-value',
|
|
61
|
+
message: invalid[0],
|
|
62
|
+
loc: invalid[1],
|
|
63
|
+
};
|
|
238
64
|
}
|
|
239
65
|
}
|
|
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
66
|
return false;
|
|
249
|
-
}
|
|
250
|
-
if (
|
|
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
|
|
67
|
+
});
|
|
68
|
+
if (invalidList.some(i => !i)) {
|
|
299
69
|
return false;
|
|
300
70
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
|
71
|
+
const invalid = invalidList.find(i => i);
|
|
72
|
+
return invalid || false;
|
|
73
|
+
}
|
|
74
|
+
exports.attrCheck = attrCheck;
|
|
75
|
+
function valueCheck(t, name, value, type) {
|
|
76
|
+
if (type === 'Boolean') {
|
|
77
|
+
// Valid because an attribute is exist
|
|
478
78
|
return false;
|
|
479
79
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
80
|
+
const matches = (0, types_1.check)(value, type);
|
|
81
|
+
(0, debug_1.log)(`Result ([${name}="${value}"]): %O`, { ...matches, type });
|
|
82
|
+
if (!matches.matched) {
|
|
83
|
+
const location = {
|
|
84
|
+
raw: matches.raw,
|
|
85
|
+
line: matches.line - 1,
|
|
86
|
+
col: matches.column - 1,
|
|
87
|
+
};
|
|
88
|
+
const base = t('the "{0*}" {1}', name, 'attribute');
|
|
89
|
+
const message = (0, create_message_1.createMessageValueExpected)(t, base, type, matches);
|
|
90
|
+
return [message, location];
|
|
483
91
|
}
|
|
484
92
|
return false;
|
|
485
93
|
}
|
|
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
|
-
}
|
|
94
|
+
exports.valueCheck = valueCheck;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
const helpers_1 = require("../helpers");
|
|
5
4
|
exports.default = (0, ml_core_1.createRule)({
|
|
6
5
|
defaultServerity: 'warning',
|
|
7
6
|
defaultValue: 'no-upper',
|
|
@@ -15,7 +14,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
15
14
|
const deny = node.rule.value === 'no-upper' ? /[A-Z]/ : /[a-z]/;
|
|
16
15
|
const cases = node.rule.value === 'no-upper' ? 'lower' : 'upper';
|
|
17
16
|
const message = t(`{0} ${ms} be {1}`, t('{0} of {1}', 'attribute names', 'HTML elements'), `${cases}case`);
|
|
18
|
-
const attrSpecs = (0,
|
|
17
|
+
const attrSpecs = (0, ml_core_1.getAttrSpecs)(node.nameWithNS, document.specs);
|
|
19
18
|
for (const attr of node.attributes) {
|
|
20
19
|
if (attr.attrType === 'ps-attr') {
|
|
21
20
|
continue;
|
|
@@ -51,7 +50,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
51
50
|
if (node.isForeignElement || node.isCustomElement) {
|
|
52
51
|
return;
|
|
53
52
|
}
|
|
54
|
-
const attrSpecs = (0,
|
|
53
|
+
const attrSpecs = (0, ml_core_1.getAttrSpecs)(node.nameWithNS, document.specs);
|
|
55
54
|
if (node.attributes) {
|
|
56
55
|
for (const attr of node.attributes) {
|
|
57
56
|
if (attr.attrType === 'ps-attr') {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Translator } from '@markuplint/i18n';
|
|
2
|
+
import type { AttributeType } from '@markuplint/ml-spec';
|
|
3
|
+
import type { UnmatchedResult } from '@markuplint/types';
|
|
4
|
+
export declare function createMessageValueExpected(t: Translator, baseTarget: string, type: AttributeType, matches: UnmatchedResult): string;
|
|
5
|
+
export declare function __createMessageValueExpected(t: Translator, baseTarget: string, expected: string | null, matches: Pick<UnmatchedResult, 'partName' | 'reason' | 'raw' | 'candicate' | 'ref' | 'extra'>): string;
|