@markuplint/types 1.0.0-dev.20211213.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 (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/extends.json +12 -0
  4. package/gen/specific-schema.json +98 -0
  5. package/gen/types.ts +66 -0
  6. package/lib/check-multi-types.d.ts +2 -0
  7. package/lib/check-multi-types.js +29 -0
  8. package/lib/check.d.ts +8 -0
  9. package/lib/check.js +49 -0
  10. package/lib/check.spec.d.ts +1 -0
  11. package/lib/check.spec.js +57 -0
  12. package/lib/css-syntax.d.ts +2 -0
  13. package/lib/css-syntax.js +141 -0
  14. package/lib/css-syntax.spec.d.ts +1 -0
  15. package/lib/css-syntax.spec.js +157 -0
  16. package/lib/debug.d.ts +2 -0
  17. package/lib/debug.js +6 -0
  18. package/lib/defs.d.ts +3 -0
  19. package/lib/defs.js +752 -0
  20. package/lib/enum.d.ts +3 -0
  21. package/lib/enum.js +26 -0
  22. package/lib/get-candicate.d.ts +3 -0
  23. package/lib/get-candicate.js +26 -0
  24. package/lib/index.d.ts +3 -0
  25. package/lib/index.js +6 -0
  26. package/lib/keyword-type.d.ts +3 -0
  27. package/lib/keyword-type.js +46 -0
  28. package/lib/list.d.ts +3 -0
  29. package/lib/list.js +29 -0
  30. package/lib/list.spec.d.ts +1 -0
  31. package/lib/list.spec.js +129 -0
  32. package/lib/match-result.d.ts +9 -0
  33. package/lib/match-result.js +33 -0
  34. package/lib/number.d.ts +3 -0
  35. package/lib/number.js +41 -0
  36. package/lib/primitive/index.d.ts +7 -0
  37. package/lib/primitive/index.js +17 -0
  38. package/lib/primitive/index.spec.d.ts +1 -0
  39. package/lib/primitive/index.spec.js +62 -0
  40. package/lib/primitive/is-float.d.ts +6 -0
  41. package/lib/primitive/is-float.js +12 -0
  42. package/lib/primitive/is-int.d.ts +6 -0
  43. package/lib/primitive/is-int.js +12 -0
  44. package/lib/primitive/is-non-zero-uint.d.ts +6 -0
  45. package/lib/primitive/is-non-zero-uint.js +12 -0
  46. package/lib/primitive/is-quantity.d.ts +7 -0
  47. package/lib/primitive/is-quantity.js +41 -0
  48. package/lib/primitive/is-uint.d.ts +8 -0
  49. package/lib/primitive/is-uint.js +19 -0
  50. package/lib/primitive/range.d.ts +8 -0
  51. package/lib/primitive/range.js +18 -0
  52. package/lib/primitive/split-unit.d.ts +9 -0
  53. package/lib/primitive/split-unit.js +24 -0
  54. package/lib/rfc/is-bcp-47.d.ts +5 -0
  55. package/lib/rfc/is-bcp-47.js +14 -0
  56. package/lib/rfc/is-bcp-47.spec.d.ts +1 -0
  57. package/lib/rfc/is-bcp-47.spec.js +19 -0
  58. package/lib/token/index.d.ts +2 -0
  59. package/lib/token/index.js +7 -0
  60. package/lib/token/token-collection.d.ts +62 -0
  61. package/lib/token/token-collection.js +383 -0
  62. package/lib/token/token-collection.spec.d.ts +1 -0
  63. package/lib/token/token-collection.spec.js +144 -0
  64. package/lib/token/token.d.ts +55 -0
  65. package/lib/token/token.js +128 -0
  66. package/lib/types.d.ts +78 -0
  67. package/lib/types.js +2 -0
  68. package/lib/types.schema.d.ts +54 -0
  69. package/lib/types.schema.js +8 -0
  70. package/lib/w3c/check-serialized-permissions-policy.d.ts +15 -0
  71. package/lib/w3c/check-serialized-permissions-policy.js +251 -0
  72. package/lib/w3c/check-serialized-permissions-policy.spec.d.ts +1 -0
  73. package/lib/w3c/check-serialized-permissions-policy.spec.js +26 -0
  74. package/lib/whatwg/check-autocomplete.d.ts +5 -0
  75. package/lib/whatwg/check-autocomplete.js +282 -0
  76. package/lib/whatwg/check-autocomplete.spec.d.ts +1 -0
  77. package/lib/whatwg/check-autocomplete.spec.js +370 -0
  78. package/lib/whatwg/check-datetime/date-string.d.ts +5 -0
  79. package/lib/whatwg/check-datetime/date-string.js +31 -0
  80. package/lib/whatwg/check-datetime/datetime-tokens.d.ts +3 -0
  81. package/lib/whatwg/check-datetime/datetime-tokens.js +509 -0
  82. package/lib/whatwg/check-datetime/duration-string.d.ts +6 -0
  83. package/lib/whatwg/check-datetime/duration-string.js +322 -0
  84. package/lib/whatwg/check-datetime/global-date-and-time-string.d.ts +5 -0
  85. package/lib/whatwg/check-datetime/global-date-and-time-string.js +66 -0
  86. package/lib/whatwg/check-datetime/index.d.ts +5 -0
  87. package/lib/whatwg/check-datetime/index.js +35 -0
  88. package/lib/whatwg/check-datetime/index.spec.d.ts +1 -0
  89. package/lib/whatwg/check-datetime/index.spec.js +318 -0
  90. package/lib/whatwg/check-datetime/local-date-and-time-string.d.ts +9 -0
  91. package/lib/whatwg/check-datetime/local-date-and-time-string.js +116 -0
  92. package/lib/whatwg/check-datetime/month-string.d.ts +5 -0
  93. package/lib/whatwg/check-datetime/month-string.js +20 -0
  94. package/lib/whatwg/check-datetime/time-string.d.ts +5 -0
  95. package/lib/whatwg/check-datetime/time-string.js +35 -0
  96. package/lib/whatwg/check-datetime/time-zone-offset-string.d.ts +7 -0
  97. package/lib/whatwg/check-datetime/time-zone-offset-string.js +75 -0
  98. package/lib/whatwg/check-datetime/week-string.d.ts +5 -0
  99. package/lib/whatwg/check-datetime/week-string.js +29 -0
  100. package/lib/whatwg/check-datetime/year-string.d.ts +5 -0
  101. package/lib/whatwg/check-datetime/year-string.js +20 -0
  102. package/lib/whatwg/check-datetime/yearless-date-string.d.ts +5 -0
  103. package/lib/whatwg/check-datetime/yearless-date-string.js +27 -0
  104. package/lib/whatwg/check-mime-type.d.ts +11 -0
  105. package/lib/whatwg/check-mime-type.js +42 -0
  106. package/lib/whatwg/check-mime-type.spec.d.ts +1 -0
  107. package/lib/whatwg/check-mime-type.spec.js +58 -0
  108. package/lib/whatwg/is-abs-url.d.ts +15 -0
  109. package/lib/whatwg/is-abs-url.js +34 -0
  110. package/lib/whatwg/is-abs-url.spec.d.ts +1 -0
  111. package/lib/whatwg/is-abs-url.spec.js +8 -0
  112. package/lib/whatwg/is-browser-context-name.d.ts +11 -0
  113. package/lib/whatwg/is-browser-context-name.js +18 -0
  114. package/lib/whatwg/is-custom-element-name.d.ts +22 -0
  115. package/lib/whatwg/is-custom-element-name.js +77 -0
  116. package/lib/whatwg/is-itemprop-name.d.ts +12 -0
  117. package/lib/whatwg/is-itemprop-name.js +19 -0
  118. package/package.json +33 -0
  119. package/src/check-multi-types.ts +35 -0
  120. package/src/check.spec.ts +62 -0
  121. package/src/check.ts +48 -0
  122. package/src/css-syntax.spec.ts +167 -0
  123. package/src/css-syntax.ts +177 -0
  124. package/src/debug.ts +3 -0
  125. package/src/defs.ts +810 -0
  126. package/src/enum.ts +25 -0
  127. package/src/get-candicate.ts +24 -0
  128. package/src/index.ts +3 -0
  129. package/src/keyword-type.ts +52 -0
  130. package/src/list.spec.ts +133 -0
  131. package/src/list.ts +34 -0
  132. package/src/match-result.ts +49 -0
  133. package/src/number.ts +46 -0
  134. package/src/primitive/index.spec.ts +65 -0
  135. package/src/primitive/index.ts +7 -0
  136. package/src/primitive/is-float.ts +8 -0
  137. package/src/primitive/is-int.ts +8 -0
  138. package/src/primitive/is-non-zero-uint.ts +8 -0
  139. package/src/primitive/is-quantity.ts +38 -0
  140. package/src/primitive/is-uint.ts +15 -0
  141. package/src/primitive/range.ts +14 -0
  142. package/src/primitive/split-unit.ts +20 -0
  143. package/src/rfc/is-bcp-47.spec.ts +23 -0
  144. package/src/rfc/is-bcp-47.ts +13 -0
  145. package/src/token/index.ts +2 -0
  146. package/src/token/token-collection.spec.ts +147 -0
  147. package/src/token/token-collection.ts +444 -0
  148. package/src/token/token.ts +144 -0
  149. package/src/types.schema.ts +1059 -0
  150. package/src/types.ts +118 -0
  151. package/src/w3c/check-serialized-permissions-policy.spec.ts +27 -0
  152. package/src/w3c/check-serialized-permissions-policy.ts +287 -0
  153. package/src/whatwg/check-autocomplete.spec.ts +378 -0
  154. package/src/whatwg/check-autocomplete.ts +324 -0
  155. package/src/whatwg/check-datetime/date-string.ts +44 -0
  156. package/src/whatwg/check-datetime/datetime-tokens.ts +600 -0
  157. package/src/whatwg/check-datetime/duration-string.ts +399 -0
  158. package/src/whatwg/check-datetime/global-date-and-time-string.ts +96 -0
  159. package/src/whatwg/check-datetime/index.spec.ts +333 -0
  160. package/src/whatwg/check-datetime/index.ts +36 -0
  161. package/src/whatwg/check-datetime/local-date-and-time-string.ts +163 -0
  162. package/src/whatwg/check-datetime/month-string.ts +31 -0
  163. package/src/whatwg/check-datetime/time-string.ts +49 -0
  164. package/src/whatwg/check-datetime/time-zone-offset-string.ts +93 -0
  165. package/src/whatwg/check-datetime/week-string.ts +41 -0
  166. package/src/whatwg/check-datetime/year-string.ts +26 -0
  167. package/src/whatwg/check-datetime/yearless-date-string.ts +38 -0
  168. package/src/whatwg/check-mime-type.spec.ts +59 -0
  169. package/src/whatwg/check-mime-type.ts +46 -0
  170. package/src/whatwg/is-abs-url.spec.ts +8 -0
  171. package/src/whatwg/is-abs-url.ts +31 -0
  172. package/src/whatwg/is-browser-context-name.ts +16 -0
  173. package/src/whatwg/is-custom-element-name.ts +76 -0
  174. package/src/whatwg/is-itemprop-name.ts +17 -0
  175. package/tsconfig.test.json +3 -0
  176. package/tsconfig.tsbuildinfo +1 -0
  177. package/types.schema.json +1092 -0
package/src/defs.ts ADDED
@@ -0,0 +1,810 @@
1
+ import type { Defs, CssSyntaxTokenizer } from './types';
2
+
3
+ import { getCandicate } from './get-candicate';
4
+ import { matched, matches, unmatched } from './match-result';
5
+ import { splitUnit, isFloat, isUint, isInt } from './primitive';
6
+ import { isBCP47 } from './rfc/is-bcp-47';
7
+ import { Token, TokenCollection } from './token';
8
+ import { checkSerializedPermissionsPolicy } from './w3c/check-serialized-permissions-policy';
9
+ import { checkAutoComplete } from './whatwg/check-autocomplete';
10
+ import { checkDateTime } from './whatwg/check-datetime';
11
+ import { checkMIMEType } from './whatwg/check-mime-type';
12
+ import { isAbsURL } from './whatwg/is-abs-url';
13
+ import { isBrowserContextName } from './whatwg/is-browser-context-name';
14
+ import { isCustomElementName } from './whatwg/is-custom-element-name';
15
+ import { isItempropName } from './whatwg/is-itemprop-name';
16
+
17
+ export const types: Defs = {
18
+ Any: {
19
+ ref: '',
20
+ is: () => matched(),
21
+ },
22
+
23
+ NoEmptyAny: {
24
+ ref: '',
25
+ is: value => (0 < value.length ? matched() : unmatched(value, 'empty-token')),
26
+ },
27
+
28
+ OneLineAny: {
29
+ ref: '',
30
+ is: value => {
31
+ const tokens = new TokenCollection(value);
32
+ /**
33
+ * @see https://infra.spec.whatwg.org/#ascii-tab-or-newline
34
+ */
35
+ const newline = ['\u000A', '\u000D'];
36
+ const newlineToken = tokens.search(newline);
37
+ if (newlineToken) {
38
+ return newlineToken.unmatched({
39
+ reason: 'unexpected-newline',
40
+ });
41
+ }
42
+ return matched();
43
+ },
44
+ },
45
+
46
+ Zero: {
47
+ ref: '',
48
+ expects: [
49
+ {
50
+ type: 'common',
51
+ value: 'zero',
52
+ },
53
+ ],
54
+ is: value => (value === '0' ? matched() : unmatched(value, 'syntax-error')),
55
+ },
56
+
57
+ Number: {
58
+ ref: '',
59
+ expects: [
60
+ {
61
+ type: 'common',
62
+ value: 'number',
63
+ },
64
+ ],
65
+ is: value => (isFloat(value) ? matched() : unmatched(value, 'unexpected-token')),
66
+ },
67
+
68
+ Int: {
69
+ ref: '',
70
+ expects: [
71
+ {
72
+ type: 'common',
73
+ value: 'integer',
74
+ },
75
+ ],
76
+ is: value => (isInt(value) ? matched() : unmatched(value, 'unexpected-token')),
77
+ },
78
+
79
+ Uint: {
80
+ ref: '',
81
+ expects: [
82
+ {
83
+ type: 'common',
84
+ value: 'non-negative integer',
85
+ },
86
+ ],
87
+ is: value => (isUint(value) ? matched() : unmatched(value, 'unexpected-token')),
88
+ },
89
+
90
+ XMLName: {
91
+ ref: 'https://www.w3.org/TR/xml/#NT-Name',
92
+ expects: [
93
+ {
94
+ type: 'format',
95
+ value: 'XML name',
96
+ },
97
+ ],
98
+ is: value => {
99
+ // NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
100
+ const nameStartChar =
101
+ /[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u{10000}-\u{EFFFF}]/u;
102
+ // NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
103
+ const nameCharTail = /-|[.0-9\u00B7]|[\u0300-\u036F\u203F-\u2040]/;
104
+ // Name ::= NameStartChar (NameChar)*
105
+ const name = RegExp(`(?:${nameStartChar.source})(?:${nameCharTail})*`, 'u');
106
+ return name.test(value) ? matched() : unmatched(value, 'unexpected-token');
107
+ },
108
+ },
109
+
110
+ DOMID: {
111
+ ref: 'https://html.spec.whatwg.org/multipage/dom.html#global-attributes:concept-id',
112
+ expects: [
113
+ {
114
+ type: 'format',
115
+ value: 'ID',
116
+ },
117
+ ],
118
+ is: value => {
119
+ const tokens = new TokenCollection(value);
120
+ const ws = tokens.search(Token.WhiteSpace);
121
+ if (ws) {
122
+ return ws.unmatched({
123
+ reason: 'unexpected-space',
124
+ });
125
+ }
126
+ if (!tokens.length) {
127
+ return unmatched(value, 'empty-token');
128
+ }
129
+ return matched();
130
+ },
131
+ },
132
+
133
+ FunctionBody: {
134
+ ref: '',
135
+ expects: [
136
+ {
137
+ type: 'syntax',
138
+ value: 'JavaScript',
139
+ },
140
+ ],
141
+ // **NO IMPLEMENT PLAN NOW**
142
+ is: () => matched(),
143
+ },
144
+
145
+ Pattern: {
146
+ ref: 'https://html.spec.whatwg.org/multipage/input.html#compiled-pattern-regular-expression',
147
+ expects: [
148
+ {
149
+ type: 'common',
150
+ value: 'regular expression',
151
+ },
152
+ ],
153
+ is: value => {
154
+ try {
155
+ new RegExp(`^(?:${value})$`);
156
+ } catch {
157
+ return unmatched(value);
158
+ }
159
+ return matched();
160
+ },
161
+ },
162
+
163
+ DateTime: {
164
+ ref: 'https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value',
165
+ expects: [
166
+ {
167
+ type: 'format',
168
+ value: 'date time',
169
+ },
170
+ ],
171
+ is: checkDateTime(),
172
+ },
173
+
174
+ /**
175
+ * It doesn't check the meaningless number less than -1
176
+ * that is the same as -1.
177
+ * It is another rule.
178
+ */
179
+ TabIndex: {
180
+ expects: [
181
+ {
182
+ type: 'common',
183
+ value: '-1',
184
+ },
185
+ {
186
+ type: 'common',
187
+ value: '0',
188
+ },
189
+ {
190
+ type: 'common',
191
+ value: 'non-negative integer',
192
+ },
193
+ ],
194
+ ref: 'https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex',
195
+ is: matches(value => isInt(value)),
196
+ },
197
+
198
+ BCP47: {
199
+ expects: [
200
+ {
201
+ type: 'format',
202
+ value: 'BCP47',
203
+ },
204
+ ],
205
+ ref: 'https://tools.ietf.org/rfc/bcp/bcp47.html',
206
+ is: matches(isBCP47(), { reason: 'unexpected-token' }),
207
+ },
208
+
209
+ /**
210
+ * **NO IMPLEMENT NEVER**
211
+ *
212
+ * We can evaluate the absolute URL through WHATWG API,
213
+ * but it isn't easy to check the relative URL.
214
+ * And the relative URL expects almost all of the characters.
215
+ * In short, this checking is meaningless.
216
+ *
217
+ * So it always returns the matched object.
218
+ *
219
+ * If you want to expect the URL without multi-byte characters,
220
+ * it should use another rule.
221
+ */
222
+ URL: {
223
+ ref: 'https://html.spec.whatwg.org/multipage/urls-and-fetching.html#valid-url-potentially-surrounded-by-spaces',
224
+ is: () => matched(),
225
+ },
226
+
227
+ AbsoluteURL: {
228
+ ref: 'https://url.spec.whatwg.org/#syntax-url-absolute',
229
+ is: matches(isAbsURL()),
230
+ },
231
+
232
+ HashName: {
233
+ ref: 'https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-hash-name-reference',
234
+ expects: [
235
+ {
236
+ type: 'format',
237
+ value: 'hash name',
238
+ },
239
+ ],
240
+ is: value => (value[0] === '#' ? matched() : unmatched(value, 'unexpected-token')),
241
+ },
242
+
243
+ OneCodePointChar: {
244
+ ref: 'https://html.spec.whatwg.org/multipage/interaction.html#the-accesskey-attribute',
245
+ expects: [
246
+ {
247
+ type: 'common',
248
+ value: 'one code point character',
249
+ },
250
+ ],
251
+ is: value => (value.length === 1 ? matched() : unmatched(value, 'unexpected-token')),
252
+ },
253
+
254
+ CustomElementName: {
255
+ ref: 'https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name',
256
+ expects: [
257
+ {
258
+ type: 'format',
259
+ value: 'custom element name',
260
+ },
261
+ ],
262
+ is: matches(isCustomElementName()),
263
+ },
264
+
265
+ BrowsingContextName: {
266
+ ref: 'https://html.spec.whatwg.org/multipage/browsers.html#browsing-context-names',
267
+ expects: [
268
+ {
269
+ type: 'common',
270
+ value: 'browsing context name',
271
+ },
272
+ ],
273
+ // <iframe name="[HERE]">
274
+ is: matches(isBrowserContextName()),
275
+ },
276
+
277
+ BrowsingContextNameOrKeyword: {
278
+ ref: 'https://html.spec.whatwg.org/multipage/browsers.html#valid-browsing-context-name-or-keyword',
279
+ expects: [
280
+ { type: 'const', value: '_blank' },
281
+ { type: 'const', value: '_self' },
282
+ { type: 'const', value: '_parent' },
283
+ { type: 'const', value: '_top' },
284
+ {
285
+ type: 'common',
286
+ value: 'browsing context name',
287
+ },
288
+ ],
289
+ // <a target="[HERE]">
290
+ is(value) {
291
+ value = value.toLowerCase();
292
+ const keywords = ['_blank', '_self', '_parent', '_top'];
293
+ if (keywords.includes(value)) {
294
+ return matched();
295
+ }
296
+ if (value[0] === '_') {
297
+ const candicate = getCandicate(value, keywords);
298
+ return unmatched(value, 'unexpected-token', { candicate });
299
+ }
300
+ return matches(isBrowserContextName())(value);
301
+ },
302
+ },
303
+
304
+ HTTPSchemaURL: {
305
+ ref: 'https://html.spec.whatwg.org/multipage/links.html#ping',
306
+ expects: [
307
+ {
308
+ type: 'format',
309
+ value: 'URL who schema is an HTTP(S) schema',
310
+ },
311
+ ],
312
+ is(value) {
313
+ if (isAbsURL()(value)) {
314
+ return unmatched(value, 'unexpected-token');
315
+ }
316
+ if (/^https?/i.test(value)) {
317
+ return matched();
318
+ }
319
+ return unmatched(value, 'unexpected-token', {
320
+ expects: [
321
+ {
322
+ type: 'format',
323
+ value: 'HTTP(S) schema',
324
+ },
325
+ ],
326
+ });
327
+ },
328
+ },
329
+
330
+ MIMEType: {
331
+ ref: 'https://mimesniff.spec.whatwg.org/#valid-mime-type',
332
+ expects: [
333
+ {
334
+ type: 'format',
335
+ value: 'MIME Type',
336
+ },
337
+ ],
338
+ is: checkMIMEType(),
339
+ },
340
+
341
+ ItemProp: {
342
+ ref: 'https://html.spec.whatwg.org/multipage/microdata.html#names:-the-itemprop-attribute',
343
+ expects: [
344
+ {
345
+ type: 'common',
346
+ value: 'absolute URL',
347
+ },
348
+ {
349
+ type: 'format',
350
+ value: 'property name',
351
+ },
352
+ ],
353
+ is(value) {
354
+ if (!isAbsURL()(value)) {
355
+ return unmatched(value, 'unexpected-token');
356
+ }
357
+ if (!isItempropName()(value)) {
358
+ return unmatched(value, 'unexpected-token');
359
+ }
360
+ return matched();
361
+ },
362
+ },
363
+
364
+ Srcset: {
365
+ ref: 'https://html.spec.whatwg.org/multipage/images.html#srcset-attributes',
366
+ syntax: {
367
+ apply: '<srcset>',
368
+ def: {
369
+ srcset: '<image-candidate-strings> [, <image-candidate-strings>]*',
370
+ 'image-candidate-strings': '<valid-non-empty-url> [ <width-descriptor> | <pixel-density-descriptor> ]?',
371
+ 'valid-non-empty-url'(token, getNextToken) {
372
+ if (!token) {
373
+ return 0;
374
+ }
375
+ let willAdoptTokenLength = 0;
376
+ do {
377
+ if (token.type === 13) {
378
+ break;
379
+ }
380
+ willAdoptTokenLength++;
381
+ } while ((token = getNextToken(willAdoptTokenLength)));
382
+ return willAdoptTokenLength;
383
+ },
384
+ 'width-descriptor'(token) {
385
+ if (!token) {
386
+ return 0;
387
+ }
388
+ const { num, unit } = splitUnit(token.value);
389
+ if (unit !== 'w') {
390
+ return 0;
391
+ }
392
+ if (!isUint(num)) {
393
+ return 0;
394
+ }
395
+ return 1;
396
+ },
397
+ 'pixel-density-descriptor'(token) {
398
+ if (!token) {
399
+ return 0;
400
+ }
401
+ const { num, unit } = splitUnit(token.value);
402
+ if (unit !== 'x') {
403
+ return 0;
404
+ }
405
+ if (!isFloat(num)) {
406
+ return 0;
407
+ }
408
+ return 1;
409
+ },
410
+ },
411
+ },
412
+ },
413
+
414
+ SourceSizeList: {
415
+ ref: 'https://html.spec.whatwg.org/multipage/images.html#sizes-attributes',
416
+ expects: [
417
+ {
418
+ type: 'syntax',
419
+ value: '<source-size-list>',
420
+ },
421
+ ],
422
+ syntax: {
423
+ apply: '<source-size-list>',
424
+ def: {
425
+ 'source-size-list': '[ <source-size># , ]? <source-size-value>',
426
+ 'source-size': '<media-condition> <source-size-value>',
427
+ 'source-size-value': '<length>',
428
+ },
429
+ },
430
+ },
431
+
432
+ IconSize: {
433
+ ref: 'https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes',
434
+ expects: [
435
+ {
436
+ type: 'const',
437
+ value: 'any',
438
+ },
439
+ {
440
+ type: 'syntax',
441
+ value: '[WIDTH]x[HEIGHT]',
442
+ },
443
+ ],
444
+ is(value) {
445
+ value = value.toLowerCase();
446
+ if (value === 'any') {
447
+ return matched();
448
+ }
449
+ const tokens = new TokenCollection(value, { speificSeparator: 'x' });
450
+ const [width, sep, height, ...tail] = tokens;
451
+ if (!width) {
452
+ return unmatched(value, 'unexpected-token');
453
+ }
454
+ if (!sep) {
455
+ return width.unmatched({ reason: 'unexpected-token' });
456
+ }
457
+ if (!height) {
458
+ return sep.unmatched({ reason: 'unexpected-token' });
459
+ }
460
+ if (tail && tail.length) {
461
+ return tail[0].unmatched({ reason: 'extra-token' });
462
+ }
463
+ if (!isUint(width.value)) {
464
+ return width.unmatched({ reason: 'unexpected-token' });
465
+ }
466
+ if (width.value === '0') {
467
+ return width.unmatched({ reason: 'out-of-range' });
468
+ }
469
+ if (sep.value !== 'x') {
470
+ return sep.unmatched({ reason: 'out-of-range' });
471
+ }
472
+ if (!isUint(height.value)) {
473
+ return height.unmatched({ reason: 'unexpected-token' });
474
+ }
475
+ if (height.value === '0') {
476
+ return height.unmatched({ reason: 'out-of-range' });
477
+ }
478
+ return matched();
479
+ },
480
+ },
481
+
482
+ AutoComplete: {
483
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete',
484
+ is: checkAutoComplete(),
485
+ },
486
+
487
+ Accept: {
488
+ ref: 'https://html.spec.whatwg.org/multipage/input.html#attr-input-accept',
489
+ expects: [
490
+ {
491
+ type: 'const',
492
+ value: 'audio/*',
493
+ },
494
+ {
495
+ type: 'const',
496
+ value: 'video/*',
497
+ },
498
+ {
499
+ type: 'const',
500
+ value: 'image/*',
501
+ },
502
+ {
503
+ type: 'format',
504
+ value: 'MIME Type',
505
+ },
506
+ {
507
+ type: 'format',
508
+ value: 'Extension',
509
+ },
510
+ ],
511
+ // input[type=file] accept: { type: { token: "Accept", "separator": "comma" } }
512
+ is(value) {
513
+ const extMap = ['audio/*', 'video/*', 'image/*'];
514
+ if (extMap.includes(value)) return matched();
515
+ // A valid MIME type string with no parameters
516
+ const mimeMatched = checkMIMEType({ withoutParameters: true })(value);
517
+ if (mimeMatched.matched) return matched();
518
+ // A string whose first character is a U+002E FULL STOP character (.)
519
+ return value[0] === '.' && value[1] ? matched() : mimeMatched;
520
+ },
521
+ },
522
+
523
+ SerializedPermissionsPolicy: {
524
+ ref: 'https://w3c.github.io/webappsec-permissions-policy/#serialized-permissions-policy',
525
+ is: checkSerializedPermissionsPolicy(),
526
+ },
527
+
528
+ '<css-declaration-list>': {
529
+ ref: 'https://drafts.csswg.org/css-style-attr/#syntax',
530
+ syntax: {
531
+ apply: '<css-declaration-list>',
532
+ def: {
533
+ 'css-declaration-list': '<declaration-list>',
534
+ },
535
+ },
536
+ },
537
+
538
+ '<class-list>': {
539
+ ref: 'https://www.w3.org/TR/SVG/styling.html#ClassAttribute',
540
+ syntax: {
541
+ apply: '<class-list>',
542
+ def: {
543
+ 'class-list': '<ident-token>*',
544
+ },
545
+ },
546
+ },
547
+
548
+ '<svg-font-size>': {
549
+ ref: 'https://drafts.csswg.org/css-fonts-5/#descdef-font-face-font-size',
550
+ // TODO:
551
+ is: () => matched(),
552
+ },
553
+
554
+ '<svg-font-size-adjust>': {
555
+ ref: 'https://drafts.csswg.org/css-fonts-5/#propdef-font-size-adjust',
556
+ // TODO:
557
+ is: () => matched(),
558
+ },
559
+
560
+ "<'color-profile'>": {
561
+ ref: 'https://www.w3.org/TR/SVG11/color.html#ColorProfileProperty',
562
+ // TODO:
563
+ is: () => matched(),
564
+ },
565
+
566
+ "<'color-rendering'>": {
567
+ ref: 'https://www.w3.org/TR/SVG11/painting.html#ColorRenderingProperty',
568
+ // TODO:
569
+ is: () => matched(),
570
+ },
571
+
572
+ "<'enable-background'>": {
573
+ ref: 'https://www.w3.org/TR/SVG11/filters.html#EnableBackgroundProperty',
574
+ // TODO:
575
+ is: () => matched(),
576
+ },
577
+
578
+ '<list-of-svg-feature-string>': {
579
+ ref: 'https://www.w3.org/TR/SVG11/feature.html',
580
+ // TODO:
581
+ is: () => matched(),
582
+ },
583
+
584
+ '<animatable-value>': {
585
+ ref: 'https://svgwg.org/specs/animations/#FromAttribute',
586
+ // TODO:
587
+ is: () => matched(),
588
+ },
589
+
590
+ '<begin-value-list>': {
591
+ ref: 'https://svgwg.org/specs/animations/#BeginValueListSyntax',
592
+ // TODO:
593
+ is: () => matched(),
594
+ },
595
+
596
+ '<end-value-list>': {
597
+ ref: 'https://svgwg.org/specs/animations/#EndValueListSyntax',
598
+ // TODO:
599
+ is: () => matched(),
600
+ },
601
+
602
+ '<list-of-value>': {
603
+ ref: 'https://svgwg.org/specs/animations/#ValuesAttribute',
604
+ // TODO:
605
+ is: () => matched(),
606
+ },
607
+
608
+ '<clock-value>': {
609
+ ref: 'https://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-ClockValueSyntax',
610
+ syntax: {
611
+ // TODO:
612
+ apply: '<clock-value>',
613
+ def: {
614
+ 'clock-value': '<any-value>',
615
+ },
616
+ },
617
+ },
618
+
619
+ '<color-matrix>': {
620
+ ref: 'https://drafts.fxtf.org/filter-effects/#element-attrdef-fecolormatrix-values',
621
+ syntax: {
622
+ apply: '<color-matrix>',
623
+ def: {
624
+ 'color-matrix': '[ <number-zero-one> [,]? ]{19} <number-zero-one>',
625
+ },
626
+ },
627
+ },
628
+
629
+ '<dasharray>': {
630
+ ref: 'https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty',
631
+ syntax: {
632
+ apply: '<dasharray>',
633
+ def: {
634
+ dasharray: '[ [ <svg-length> | <percentage> | <number> ]+ ]#',
635
+ },
636
+ },
637
+ },
638
+
639
+ '<key-points>': {
640
+ ref: 'https://svgwg.org/specs/animations/#KeyPointsAttribute',
641
+ syntax: {
642
+ apply: '<key-points>',
643
+ def: {
644
+ 'key-points': '<number> [; <number>]* [;]?',
645
+ },
646
+ },
647
+ },
648
+
649
+ '<key-splines>': {
650
+ ref: 'https://svgwg.org/specs/animations/#KeyTimesAttribute',
651
+ syntax: {
652
+ apply: '<key-splines>',
653
+ def: {
654
+ 'key-splines': '<control-point> [; <control-point>]* [;]?',
655
+ 'control-point': '<number> [,]? <number> [,]? <number> [,]? <number>',
656
+ },
657
+ },
658
+ },
659
+
660
+ '<key-times>': {
661
+ ref: 'https://svgwg.org/specs/animations/#KeyTimesAttribute',
662
+ syntax: {
663
+ apply: '<key-times>',
664
+ def: {
665
+ 'key-times': '<number> [; <number>]* [;]?',
666
+ },
667
+ },
668
+ },
669
+
670
+ '<system-language>': {
671
+ ref: 'https://svgwg.org/svg2-draft/struct.html#SystemLanguageAttribute',
672
+ syntax: {
673
+ apply: '<system-language>',
674
+ def: {
675
+ 'system-language': '<bcp-47>#',
676
+ },
677
+ },
678
+ },
679
+
680
+ '<origin>': {
681
+ ref: 'https://www.w3.org/TR/2001/REC-smil-animation-20010904/#MotionOriginAttribute',
682
+ syntax: {
683
+ apply: '<origin>',
684
+ def: {
685
+ origin: 'default',
686
+ },
687
+ },
688
+ },
689
+
690
+ '<svg-path>': {
691
+ ref: 'https://svgwg.org/svg2-draft/paths.html#PathDataBNF',
692
+ syntax: {
693
+ apply: '<svg-path>',
694
+ // TODO:
695
+ def: {
696
+ 'svg-path': '<any-value>',
697
+ },
698
+ },
699
+ },
700
+
701
+ '<points>': {
702
+ ref: 'https://svgwg.org/svg2-draft/shapes.html#DataTypePoints',
703
+ syntax: {
704
+ apply: '<points>',
705
+ def: {
706
+ points: '[ <number>+ ]#',
707
+ },
708
+ },
709
+ },
710
+
711
+ '<preserve-aspect-ratio>': {
712
+ ref: 'https://svgwg.org/svg2-draft/coords.html#PreserveAspectRatioAttribute',
713
+ syntax: {
714
+ apply: '<preserve-aspect-ratio>',
715
+ def: {
716
+ 'preserve-aspect-ratio': '<align> <meet-or-slice>?',
717
+ align: 'none | xMinYMin | xMidYMin | xMaxYMin | xMinYMid | xMidYMid | xMaxYMid| xMinYMax | xMidYMax | xMaxYMax',
718
+ 'meet-or-slice': 'meet | slice',
719
+ },
720
+ // A new spec
721
+ // @see https://drafts.fxtf.org/filter-effects/#element-attrdef-feimage-preserveaspectratio
722
+ // > preserveAspectRatio = "[defer] <align> [<meetOrSlice>]"
723
+ },
724
+ },
725
+
726
+ '<view-box>': {
727
+ ref: 'https://svgwg.org/svg2-draft/coords.html#ViewBoxAttribute',
728
+ syntax: {
729
+ apply: '<view-box>',
730
+ def: {
731
+ 'view-box': '<min-x> [,]? <min-y> [,]? <width> [,]? <height>', // As '[<min-x>,? <min-y>,? <width>,? <height>]',
732
+ 'min-x': '<number>',
733
+ 'min-y': '<number>',
734
+ width: '<number>',
735
+ height: '<number>',
736
+ },
737
+ },
738
+ },
739
+
740
+ '<rotate>': {
741
+ ref: 'https://svgwg.org/specs/animations/#RotateAttribute',
742
+ syntax: {
743
+ apply: '<rotate>',
744
+ def: {
745
+ rotate: '<number> | auto | auto-reverse',
746
+ },
747
+ },
748
+ },
749
+
750
+ '<text-coordinate>': {
751
+ ref: 'https://svgwg.org/svg2-draft/text.html#TSpanAttributes',
752
+ syntax: {
753
+ apply: '<text-coordinate>',
754
+ def: {
755
+ 'text-coordinate': '[ [ <svg-length> | <percentage> | <number> ]+ ]#',
756
+ },
757
+ },
758
+ },
759
+
760
+ '<list-of-lengths>': {
761
+ ref: 'https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#list-of-ts',
762
+ syntax: {
763
+ apply: '<list-of-lengths>',
764
+ def: {
765
+ 'list-of-lengths': '[ <svg-length> [,]? ]* <svg-length>',
766
+ },
767
+ },
768
+ },
769
+
770
+ '<list-of-numbers>': {
771
+ ref: 'https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#list-of-ts',
772
+ syntax: {
773
+ apply: '<list-of-numbers>',
774
+ def: {
775
+ 'list-of-numbers': '[ <number> [,]? ]* <number>',
776
+ },
777
+ },
778
+ },
779
+
780
+ '<list-of-percentages>': {
781
+ ref: 'https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#percentage',
782
+ syntax: {
783
+ apply: '<list-of-percentages>',
784
+ def: {
785
+ 'list-of-percentages': '[ <percentage> [,]? ]* <percentage>',
786
+ },
787
+ },
788
+ },
789
+
790
+ '<number-optional-number>': {
791
+ ref: 'https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#number-optional-number',
792
+ syntax: {
793
+ apply: '<number-optional-number>',
794
+ def: {
795
+ 'number-optional-number': '<number> | <number> , <number>',
796
+ },
797
+ },
798
+ },
799
+ };
800
+
801
+ export const tokenizers: Record<string, CssSyntaxTokenizer> = {
802
+ // RFC
803
+ // https://tools.ietf.org/rfc/bcp/bcp47.html
804
+ 'bcp-47'(token) {
805
+ if (!token) {
806
+ return 0;
807
+ }
808
+ return isBCP47()(token.value) ? 1 : 0;
809
+ },
810
+ };