@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
@@ -0,0 +1,378 @@
1
+ import { checkAutoComplete } from './check-autocomplete';
2
+
3
+ const check = checkAutoComplete();
4
+
5
+ test('valid', () => {
6
+ expect(check('on').matched).toBe(true);
7
+ expect(check('off').matched).toBe(true);
8
+ expect(check('name').matched).toBe(true);
9
+ expect(check('given-name').matched).toBe(true);
10
+ expect(check('section-').matched).toBe(true);
11
+ expect(check('section-foo').matched).toBe(true);
12
+ expect(check('section-foo name').matched).toBe(true);
13
+ expect(check('section-foo shipping name').matched).toBe(true);
14
+ expect(check('section-foo billing name').matched).toBe(true);
15
+ expect(check('section-foo billing home').matched).toBe(true);
16
+ expect(check('section-foo billing work').matched).toBe(true);
17
+ expect(check('section-foo billing home tel').matched).toBe(true);
18
+ expect(check('section-foo billing work email').matched).toBe(true);
19
+ expect(check('shipping name').matched).toBe(true);
20
+ expect(check('billing name').matched).toBe(true);
21
+ expect(check('billing home').matched).toBe(true);
22
+ expect(check('billing work').matched).toBe(true);
23
+ expect(check('billing home tel').matched).toBe(true);
24
+ expect(check('billing work email').matched).toBe(true);
25
+ expect(check('home tel').matched).toBe(true);
26
+ expect(check('work email').matched).toBe(true);
27
+ });
28
+
29
+ test('unexpected-token', () => {
30
+ expect(check('section-foo , name')).toStrictEqual({
31
+ matched: false,
32
+ raw: ',',
33
+ offset: 12,
34
+ length: 1,
35
+ line: 1,
36
+ column: 13,
37
+ reason: 'unexpected-token',
38
+ expects: [
39
+ { type: 'const', value: 'billing' },
40
+ { type: 'const', value: 'shipping' },
41
+ { type: 'common', value: 'autofill field name' },
42
+ ],
43
+ candicate: undefined,
44
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
45
+ });
46
+ });
47
+
48
+ test('unexpected-token', () => {
49
+ expect(check('xxx')).toStrictEqual({
50
+ matched: false,
51
+ raw: 'xxx',
52
+ offset: 0,
53
+ length: 3,
54
+ line: 1,
55
+ column: 1,
56
+ reason: 'unexpected-token',
57
+ expects: [
58
+ { type: 'common', value: 'autofill named group' },
59
+ { type: 'common', value: 'autofill field name' },
60
+ ],
61
+ candicate: undefined,
62
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
63
+ });
64
+ });
65
+
66
+ test('unexpected-token', () => {
67
+ expect(check('section-foo neme')).toStrictEqual({
68
+ matched: false,
69
+ raw: 'neme',
70
+ offset: 12,
71
+ length: 4,
72
+ line: 1,
73
+ column: 13,
74
+ reason: 'unexpected-token',
75
+ expects: [
76
+ { type: 'const', value: 'billing' },
77
+ { type: 'const', value: 'shipping' },
78
+ { type: 'common', value: 'autofill field name' },
79
+ ],
80
+ candicate: 'name',
81
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
82
+ });
83
+ expect(check('section-foo shipping neme')).toStrictEqual({
84
+ matched: false,
85
+ raw: 'neme',
86
+ offset: 21,
87
+ length: 4,
88
+ line: 1,
89
+ column: 22,
90
+ reason: 'unexpected-token',
91
+ expects: [
92
+ { type: 'common', value: 'autofill field name' },
93
+ { type: 'const', value: 'home' },
94
+ { type: 'const', value: 'work' },
95
+ { type: 'const', value: 'mobile' },
96
+ { type: 'const', value: 'fax' },
97
+ { type: 'const', value: 'pager' },
98
+ ],
99
+ candicate: 'name',
100
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
101
+ });
102
+ expect(check('section-foo shipping home neme')).toStrictEqual({
103
+ matched: false,
104
+ raw: 'neme',
105
+ offset: 26,
106
+ length: 4,
107
+ line: 1,
108
+ column: 27,
109
+ reason: 'unexpected-token',
110
+ expects: [
111
+ { type: 'const', value: 'tel' },
112
+ { type: 'const', value: 'tel-country-code' },
113
+ { type: 'const', value: 'tel-national' },
114
+ { type: 'const', value: 'tel-area-code' },
115
+ { type: 'const', value: 'tel-local' },
116
+ { type: 'const', value: 'tel-local-prefix' },
117
+ { type: 'const', value: 'tel-local-suffix' },
118
+ { type: 'const', value: 'tel-extension' },
119
+ { type: 'const', value: 'email' },
120
+ { type: 'const', value: 'impp' },
121
+ ],
122
+ candicate: undefined,
123
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-tel',
124
+ });
125
+ expect(check('section-foo shipping home emall')).toStrictEqual({
126
+ matched: false,
127
+ raw: 'emall',
128
+ offset: 26,
129
+ length: 5,
130
+ line: 1,
131
+ column: 27,
132
+ reason: 'unexpected-token',
133
+ expects: [
134
+ { type: 'const', value: 'tel' },
135
+ { type: 'const', value: 'tel-country-code' },
136
+ { type: 'const', value: 'tel-national' },
137
+ { type: 'const', value: 'tel-area-code' },
138
+ { type: 'const', value: 'tel-local' },
139
+ { type: 'const', value: 'tel-local-prefix' },
140
+ { type: 'const', value: 'tel-local-suffix' },
141
+ { type: 'const', value: 'tel-extension' },
142
+ { type: 'const', value: 'email' },
143
+ { type: 'const', value: 'impp' },
144
+ ],
145
+ candicate: 'email',
146
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-tel',
147
+ });
148
+ });
149
+
150
+ test('duplicated', () => {
151
+ expect(check('name name')).toStrictEqual({
152
+ matched: false,
153
+ raw: 'name',
154
+ offset: 5,
155
+ length: 4,
156
+ line: 1,
157
+ column: 6,
158
+ partName: 'the content of the list',
159
+ reason: 'duplicated',
160
+ expects: [{ type: 'format', value: 'autocomplete' }],
161
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete',
162
+ });
163
+ expect(check('on on')).toStrictEqual({
164
+ matched: false,
165
+ raw: 'on',
166
+ offset: 3,
167
+ length: 2,
168
+ line: 1,
169
+ column: 4,
170
+ partName: 'the content of the list',
171
+ reason: 'duplicated',
172
+ expects: [{ type: 'format', value: 'autocomplete' }],
173
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete',
174
+ });
175
+ });
176
+
177
+ test('extra-token', () => {
178
+ expect(check('on off')).toStrictEqual({
179
+ matched: false,
180
+ raw: 'off',
181
+ offset: 3,
182
+ length: 3,
183
+ line: 1,
184
+ column: 4,
185
+ reason: 'extra-token',
186
+ expects: [{ type: 'format', value: 'autocomplete' }],
187
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-on-2',
188
+ });
189
+ expect(check('off on')).toStrictEqual({
190
+ matched: false,
191
+ raw: 'on',
192
+ offset: 4,
193
+ length: 2,
194
+ line: 1,
195
+ column: 5,
196
+ reason: 'extra-token',
197
+ expects: [{ type: 'format', value: 'autocomplete' }],
198
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-on-2',
199
+ });
200
+ expect(check('on name')).toStrictEqual({
201
+ matched: false,
202
+ raw: 'name',
203
+ offset: 3,
204
+ length: 4,
205
+ line: 1,
206
+ column: 4,
207
+ reason: 'extra-token',
208
+ expects: [{ type: 'format', value: 'autocomplete' }],
209
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-on-2',
210
+ });
211
+ expect(check('name on')).toStrictEqual({
212
+ matched: false,
213
+ raw: 'on',
214
+ offset: 5,
215
+ length: 2,
216
+ line: 1,
217
+ column: 6,
218
+ reason: 'extra-token',
219
+ expects: [{ type: 'format', value: 'autocomplete' }],
220
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
221
+ });
222
+ expect(check('section-foo name on')).toStrictEqual({
223
+ matched: false,
224
+ raw: 'on',
225
+ offset: 17,
226
+ length: 2,
227
+ line: 1,
228
+ column: 18,
229
+ reason: 'extra-token',
230
+ expects: [{ type: 'format', value: 'autocomplete' }],
231
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
232
+ });
233
+ expect(check('section-foo billing name on')).toStrictEqual({
234
+ matched: false,
235
+ raw: 'on',
236
+ offset: 25,
237
+ length: 2,
238
+ line: 1,
239
+ column: 26,
240
+ reason: 'extra-token',
241
+ expects: [{ type: 'format', value: 'autocomplete' }],
242
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
243
+ });
244
+ expect(check('billing name on')).toStrictEqual({
245
+ matched: false,
246
+ raw: 'on',
247
+ offset: 13,
248
+ length: 2,
249
+ line: 1,
250
+ column: 14,
251
+ reason: 'extra-token',
252
+ expects: [{ type: 'format', value: 'autocomplete' }],
253
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
254
+ });
255
+ expect(check('tel on')).toStrictEqual({
256
+ matched: false,
257
+ raw: 'on',
258
+ offset: 4,
259
+ length: 2,
260
+ line: 1,
261
+ column: 5,
262
+ reason: 'extra-token',
263
+ expects: [{ type: 'format', value: 'autocomplete' }],
264
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
265
+ });
266
+ expect(check('home tel on')).toStrictEqual({
267
+ matched: false,
268
+ raw: 'on',
269
+ offset: 9,
270
+ length: 2,
271
+ line: 1,
272
+ column: 10,
273
+ reason: 'extra-token',
274
+ expects: [{ type: 'format', value: 'autocomplete' }],
275
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
276
+ });
277
+ expect(check('billing home tel on')).toStrictEqual({
278
+ matched: false,
279
+ raw: 'on',
280
+ offset: 17,
281
+ length: 2,
282
+ line: 1,
283
+ column: 18,
284
+ reason: 'extra-token',
285
+ expects: [{ type: 'format', value: 'autocomplete' }],
286
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
287
+ });
288
+ expect(check('billing home tel on')).toStrictEqual({
289
+ matched: false,
290
+ raw: 'on',
291
+ offset: 17,
292
+ length: 2,
293
+ line: 1,
294
+ column: 18,
295
+ reason: 'extra-token',
296
+ expects: [{ type: 'format', value: 'autocomplete' }],
297
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
298
+ });
299
+ expect(check('section-foo billing home tel on')).toStrictEqual({
300
+ matched: false,
301
+ raw: 'on',
302
+ offset: 29,
303
+ length: 2,
304
+ line: 1,
305
+ column: 30,
306
+ reason: 'extra-token',
307
+ expects: [{ type: 'format', value: 'autocomplete' }],
308
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
309
+ });
310
+ expect(check('section-foo home tel on')).toStrictEqual({
311
+ matched: false,
312
+ raw: 'on',
313
+ offset: 21,
314
+ length: 2,
315
+ line: 1,
316
+ column: 22,
317
+ reason: 'extra-token',
318
+ expects: [{ type: 'format', value: 'autocomplete' }],
319
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
320
+ });
321
+ expect(check('section-foo tel on')).toStrictEqual({
322
+ matched: false,
323
+ raw: 'on',
324
+ offset: 16,
325
+ length: 2,
326
+ line: 1,
327
+ column: 17,
328
+ reason: 'extra-token',
329
+ expects: [{ type: 'format', value: 'autocomplete' }],
330
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
331
+ });
332
+ });
333
+
334
+ test('duplicated section', () => {
335
+ expect(check('section-foo section-bar')).toStrictEqual({
336
+ matched: false,
337
+ raw: 'section-bar',
338
+ offset: 12,
339
+ length: 11,
340
+ line: 1,
341
+ column: 13,
342
+ partName: 'autofill named group',
343
+ reason: 'duplicated',
344
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section',
345
+ });
346
+ });
347
+
348
+ test('duplicated part', () => {
349
+ expect(check('shipping billing')).toStrictEqual({
350
+ matched: false,
351
+ raw: 'billing',
352
+ offset: 9,
353
+ length: 7,
354
+ line: 1,
355
+ column: 10,
356
+ reason: 'duplicated',
357
+ expects: [{ type: 'format', value: 'autocomplete' }],
358
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-shipping',
359
+ });
360
+ });
361
+
362
+ test('typo', () => {
363
+ expect(check('secsion-foo name')).toStrictEqual({
364
+ matched: false,
365
+ raw: 'secsion-foo',
366
+ offset: 0,
367
+ length: 11,
368
+ line: 1,
369
+ column: 1,
370
+ reason: 'unexpected-token',
371
+ expects: [
372
+ { type: 'common', value: 'autofill named group' },
373
+ { type: 'common', value: 'autofill field name' },
374
+ ],
375
+ candicate: 'section-foo',
376
+ ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
377
+ });
378
+ });
@@ -0,0 +1,324 @@
1
+ import type { Expect } from '..';
2
+ import type { CustomSyntaxChecker } from '../types';
3
+
4
+ import { getCandicate } from '../get-candicate';
5
+ import { matched } from '../match-result';
6
+ import { TokenCollection } from '../token';
7
+
8
+ /**
9
+ * https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section
10
+ */
11
+ const namedGroup = /^section-/i;
12
+
13
+ /**
14
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-shipping
15
+ */
16
+ const partOfAddress = ['shipping', 'billing'];
17
+
18
+ /**
19
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field
20
+ */
21
+ const autofillFieldNames = [
22
+ 'name',
23
+ 'honorific-prefix',
24
+ 'given-name',
25
+ 'additional-name',
26
+ 'family-name',
27
+ 'honorific-suffix',
28
+ 'nickname',
29
+ 'username',
30
+ 'new-password',
31
+ 'current-password',
32
+ 'one-time-code',
33
+ 'organization-title',
34
+ 'organization',
35
+ 'street-address',
36
+ 'address-line1',
37
+ 'address-line2',
38
+ 'address-line3',
39
+ 'address-level4',
40
+ 'address-level3',
41
+ 'address-level2',
42
+ 'address-level1',
43
+ 'country',
44
+ 'country-name',
45
+ 'postal-code',
46
+ 'cc-name',
47
+ 'cc-given-name',
48
+ 'cc-additional-name',
49
+ 'cc-family-name',
50
+ 'cc-number',
51
+ 'cc-exp',
52
+ 'cc-exp-month',
53
+ 'cc-exp-year',
54
+ 'cc-csc',
55
+ 'cc-type',
56
+ 'transaction-currency',
57
+ 'transaction-amount',
58
+ 'language',
59
+ 'bday',
60
+ 'bday-day',
61
+ 'bday-month',
62
+ 'bday-year',
63
+ 'sex',
64
+ 'url',
65
+ 'photo',
66
+ ];
67
+
68
+ /**
69
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-home
70
+ */
71
+ const contactingTokens = ['home', 'work', 'mobile', 'fax', 'pager'];
72
+
73
+ /**
74
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:ascii-case-insensitive-7
75
+ */
76
+ const contactableFieldNames = [
77
+ 'tel',
78
+ 'tel-country-code',
79
+ 'tel-national',
80
+ 'tel-area-code',
81
+ 'tel-local',
82
+ 'tel-local-prefix',
83
+ 'tel-local-suffix',
84
+ 'tel-extension',
85
+ 'email',
86
+ 'impp',
87
+ ];
88
+
89
+ const URL_AUTOCOMPLET = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete';
90
+ const URL_ON_OFF =
91
+ 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-on-2';
92
+ const URL_NAMED_GROUP =
93
+ 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section';
94
+ const URL_PART_OF_ADDRESS =
95
+ 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-shipping';
96
+ const URL_AUTOFILL_FIELD = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field';
97
+ const URL_CONTACTABLE_FIELD =
98
+ 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-tel';
99
+
100
+ /**
101
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete
102
+ */
103
+ export const checkAutoComplete: CustomSyntaxChecker = () => value => {
104
+ let hasNamedGroup = false;
105
+ let hasPartOfAddress = false;
106
+ let hasContactingToken = false;
107
+
108
+ const tokens = new TokenCollection(value, {
109
+ disallowToSurroundBySpaces: false,
110
+ allowEmpty: false,
111
+ ordered: true,
112
+ unique: true,
113
+ caseInsensitive: true,
114
+ });
115
+
116
+ const listingChecked = tokens.check({
117
+ expects: [
118
+ {
119
+ type: 'format',
120
+ value: 'autocomplete',
121
+ },
122
+ ],
123
+ ref: URL_AUTOCOMPLET,
124
+ });
125
+ if (!listingChecked.matched) {
126
+ return listingChecked;
127
+ }
128
+
129
+ const idents = tokens.getIdentTokens();
130
+ const headAndTail1 = idents.headAndTail();
131
+ let { head, tail } = headAndTail1;
132
+ if (!head) {
133
+ // Never
134
+ throw new Error('TokenCollection is empty');
135
+ }
136
+
137
+ // > When wearing the autofill anchor mantle, the autocomplete attribute,
138
+ // > if specified, must have a value that is
139
+ // > an ordered set of space-separated tokens consisting of
140
+ // > just autofill detail tokens
141
+ // > (i.e. the "on" and "off" keywords are not allowed).
142
+ if (head.match(['on', 'off'], true)) {
143
+ if (tail.length) {
144
+ return tail[0].unmatched({
145
+ reason: 'extra-token',
146
+ expects: [
147
+ {
148
+ type: 'format',
149
+ value: 'autocomplete',
150
+ },
151
+ ],
152
+ ref: URL_ON_OFF,
153
+ });
154
+ }
155
+
156
+ return matched();
157
+ }
158
+
159
+ // > Optionally, a token whose first eight characters are
160
+ // > an ASCII case-insensitive match for the string "section-",
161
+ // > meaning that the field belongs to the named group.
162
+ if (head.match(namedGroup, true)) {
163
+ hasNamedGroup = true;
164
+ const sectionToken = tail.search(namedGroup);
165
+ if (sectionToken) {
166
+ return sectionToken.unmatched({
167
+ partName: 'autofill named group',
168
+ reason: 'duplicated',
169
+ ref: URL_NAMED_GROUP,
170
+ });
171
+ }
172
+
173
+ const headAndTail2 = tail.headAndTail();
174
+ head = headAndTail2.head;
175
+ tail = headAndTail2.tail;
176
+
177
+ if (!head) {
178
+ // Missing autofill field name but it is valid
179
+ return matched();
180
+ }
181
+ }
182
+
183
+ // > Optionally, a token that is an ASCII case-insensitive match for
184
+ // > one of the following strings:
185
+ // > - "shipping", meaning the field is part of the shipping address or contact information
186
+ // > - "billing", meaning the field is part of the billing address or contact information
187
+ if (head.match(partOfAddress, true)) {
188
+ hasPartOfAddress = true;
189
+ const partToken = tail.search(partOfAddress);
190
+ if (partToken) {
191
+ return partToken.unmatched({
192
+ reason: 'duplicated',
193
+ expects: [
194
+ {
195
+ type: 'format',
196
+ value: 'autocomplete',
197
+ },
198
+ ],
199
+ ref: URL_PART_OF_ADDRESS,
200
+ });
201
+ }
202
+
203
+ const headAndTail3 = tail.headAndTail();
204
+ head = headAndTail3.head;
205
+ tail = headAndTail3.tail;
206
+
207
+ if (!head) {
208
+ // Missing autofill field name but it is valid
209
+ return matched();
210
+ }
211
+ }
212
+
213
+ if (head.match(contactingTokens, true)) {
214
+ hasContactingToken = true;
215
+ const contactableFiledToken = tail[0];
216
+ if (!contactableFiledToken) {
217
+ // Missing autofill field name but it is valid
218
+ return matched();
219
+ }
220
+
221
+ if (!contactableFiledToken.match(contactableFieldNames, true)) {
222
+ const candicate = getCandicate(contactableFiledToken.value, contactableFieldNames);
223
+ return contactableFiledToken.unmatched({
224
+ reason: 'unexpected-token',
225
+ expects: contactableFieldNames.slice().map(token => ({
226
+ type: 'const' as const,
227
+ value: token,
228
+ })),
229
+ candicate,
230
+ ref: URL_CONTACTABLE_FIELD,
231
+ });
232
+ }
233
+
234
+ if (tail[1]) {
235
+ return tail[1].unmatched({
236
+ reason: 'extra-token',
237
+ expects: [
238
+ {
239
+ type: 'format',
240
+ value: 'autocomplete',
241
+ },
242
+ ],
243
+ ref: URL_AUTOFILL_FIELD,
244
+ });
245
+ }
246
+
247
+ return matched();
248
+ }
249
+
250
+ if (head.match([...autofillFieldNames, ...contactableFieldNames], true)) {
251
+ if (tail.length) {
252
+ return tail[0].unmatched({
253
+ reason: 'extra-token',
254
+ expects: [
255
+ {
256
+ type: 'format',
257
+ value: 'autocomplete',
258
+ },
259
+ ],
260
+ ref: URL_AUTOFILL_FIELD,
261
+ });
262
+ }
263
+
264
+ return matched();
265
+ }
266
+
267
+ const expects: Expect[] = [
268
+ {
269
+ type: 'common',
270
+ value: 'autofill field name',
271
+ },
272
+ ];
273
+ let candicate: string | undefined;
274
+
275
+ if (!hasNamedGroup) {
276
+ expects.unshift({
277
+ type: 'common',
278
+ value: 'autofill named group',
279
+ });
280
+
281
+ // Potentially typo a named group
282
+ const [prefix, namedGroupStr] = head.value.split('-');
283
+ const candicatePrefix = getCandicate(prefix, 'section');
284
+ if (candicatePrefix) {
285
+ candicate = `${candicatePrefix}-${namedGroupStr || ''}`;
286
+ }
287
+ } else if (!hasPartOfAddress) {
288
+ expects.unshift(
289
+ ...partOfAddress
290
+ .slice()
291
+ .reverse()
292
+ .map(token => ({
293
+ type: 'const' as const,
294
+ value: token,
295
+ })),
296
+ );
297
+
298
+ candicate = getCandicate(
299
+ head.value,
300
+ partOfAddress,
301
+ autofillFieldNames,
302
+ contactingTokens,
303
+ contactableFieldNames,
304
+ );
305
+ } else if (!hasContactingToken) {
306
+ expects.push(
307
+ ...contactingTokens.slice().map(token => ({
308
+ type: 'const' as const,
309
+ value: token,
310
+ })),
311
+ );
312
+
313
+ candicate = getCandicate(head.value, autofillFieldNames, contactingTokens, contactableFieldNames);
314
+ }
315
+
316
+ candicate = candicate || getCandicate(head.value, autofillFieldNames);
317
+
318
+ return head.unmatched({
319
+ reason: 'unexpected-token',
320
+ expects,
321
+ candicate,
322
+ ref: URL_AUTOFILL_FIELD,
323
+ });
324
+ };