@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,251 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkSerializedPermissionsPolicy = void 0;
4
+ const debug_1 = require("../debug");
5
+ const match_result_1 = require("../match-result");
6
+ const token_1 = require("../token");
7
+ /**
8
+ * @see https://w3c.github.io/webappsec-permissions-policy/#serialized-permissions-policy
9
+ *
10
+ * > Policy Directives in HTML attributes are represented as their
11
+ * > ASCII serialization, with the following ABNF:
12
+ * > ```abnf
13
+ * > serialized-permissions-policy = serialized-policy-directive *(";" serialized-policy-directive)
14
+ * > serialized-policy-directive = feature-identifier RWS allow-list
15
+ * > feature-identifier = 1*( ALPHA / DIGIT / "-")
16
+ * > allow-list = allow-list-value *(RWS allow-list-value)
17
+ * > allow-list-value = serialized-origin / "*" / "'self'" / "'src'" / "'none'"
18
+ * > ```
19
+ */
20
+ const checkSerializedPermissionsPolicy = () => value => {
21
+ const res = _checkSerializedPermissionsPolicy(value);
22
+ if (!res.matched) {
23
+ (0, debug_1.log)('Failed: %O', res);
24
+ }
25
+ return res;
26
+ };
27
+ exports.checkSerializedPermissionsPolicy = checkSerializedPermissionsPolicy;
28
+ function _checkSerializedPermissionsPolicy(value) {
29
+ /**
30
+ * The list of serialized-policy-directive
31
+ *
32
+ * > ```abnf
33
+ * > serialized-policy-directive *(";" serialized-policy-directive)
34
+ * > ```
35
+ */
36
+ const patterns = [
37
+ /**
38
+ * serialized-policy-directive
39
+ */
40
+ /[^;]*/,
41
+ /**
42
+ * separator
43
+ */
44
+ /;?/,
45
+ ];
46
+ const tokens = token_1.TokenCollection.fromPatterns(value, patterns, { repeat: true });
47
+ const serializedPolicyDirectives = tokens.chunk(patterns.length);
48
+ (0, debug_1.log)('Serialized Permissions Policy: %s => %O', value, serializedPolicyDirectives);
49
+ for (const [serializedPolicyDirective] of serializedPolicyDirectives) {
50
+ if (!serializedPolicyDirective || !serializedPolicyDirective.value) {
51
+ return (0, match_result_1.unmatched)('', 'empty-token');
52
+ }
53
+ const [featureIdentifier, rws, allowListValue] = token_1.TokenCollection.fromPatterns(serializedPolicyDirective, [
54
+ /**
55
+ * feature-identifier
56
+ *
57
+ * > ```abnf
58
+ * > feature-identifier = 1*( ALPHA / DIGIT / "-")
59
+ * > ```
60
+ */
61
+ /[^\s]*/,
62
+ /**
63
+ * RWS (Required whitespace)
64
+ *
65
+ * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3
66
+ */
67
+ /\s*/,
68
+ /**
69
+ * allow-list-value
70
+ */
71
+ /.*/,
72
+ ]);
73
+ (0, debug_1.log)('Serialized Policy Directive: %s => %O', serializedPolicyDirective.value, {
74
+ featureIdentifier,
75
+ rws,
76
+ allowListValue,
77
+ });
78
+ /**
79
+ * > ```abnf
80
+ * > feature-identifier = 1*( ALPHA / DIGIT / "-")
81
+ * > ```
82
+ */
83
+ if (!featureIdentifier || !featureIdentifier.match(/^[a-z0-9-]+$/i)) {
84
+ return featureIdentifier.unmatched({
85
+ reason: 'unexpected-token',
86
+ expects: [{ type: 'common', value: 'feature-identifier' }],
87
+ partName: 'feature-identifier',
88
+ });
89
+ }
90
+ if (!rws || !rws.value) {
91
+ return (0, match_result_1.unmatched)('', 'missing-token', {
92
+ expects: [{ type: 'common', value: 'whitespace' }],
93
+ partName: 'directive',
94
+ });
95
+ }
96
+ if (!allowListValue || !allowListValue.value) {
97
+ return (0, match_result_1.unmatched)('', 'missing-token', {
98
+ expects: [{ type: 'common', value: 'allow-list' }],
99
+ partName: 'allow-list',
100
+ });
101
+ }
102
+ const allowListPatterns = [
103
+ // Value
104
+ /[^\s]*/,
105
+ // Separator
106
+ /\s*/,
107
+ ];
108
+ const allowListTokens = token_1.TokenCollection.fromPatterns(allowListValue, allowListPatterns, { repeat: true });
109
+ const allowList = allowListTokens.chunk(allowListPatterns.length);
110
+ (0, debug_1.log)('Allow List: %s => %O', allowListTokens.value, allowList);
111
+ for (const [allow] of allowList) {
112
+ if (!allow || !allow.value) {
113
+ return (0, match_result_1.unmatched)('', 'missing-token', {
114
+ expects: [
115
+ { type: 'const', value: '*' },
116
+ { type: 'const', value: "'self'" },
117
+ { type: 'const', value: "'src'" },
118
+ { type: 'const', value: "'none'" },
119
+ { type: 'common', value: 'serialized-origin' },
120
+ ],
121
+ partName: 'allow-list',
122
+ });
123
+ }
124
+ const origin = checkSerializedOrigin(allow);
125
+ if (origin.matched) {
126
+ continue;
127
+ }
128
+ if (origin.reason !== 'syntax-error') {
129
+ return origin;
130
+ }
131
+ if (allow.match(['*', "'self'", "'src'", "'none'"], true)) {
132
+ continue;
133
+ }
134
+ if (allow.match(['self', 'src', 'none'], true)) {
135
+ return allow.unmatched({
136
+ reason: 'missing-token',
137
+ expects: [{ type: 'common', value: 'single-quote' }],
138
+ partName: 'keyword',
139
+ });
140
+ }
141
+ return allow.unmatched({
142
+ reason: 'unexpected-token',
143
+ expects: [
144
+ { type: 'const', value: '*' },
145
+ { type: 'const', value: "'self'" },
146
+ { type: 'const', value: "'src'" },
147
+ { type: 'const', value: "'none'" },
148
+ { type: 'common', value: 'serialized-origin' },
149
+ ],
150
+ partName: 'allow-list',
151
+ });
152
+ }
153
+ }
154
+ return (0, match_result_1.matched)();
155
+ }
156
+ /**
157
+ * serialized-origin
158
+ *
159
+ * > serialized-origin is the serialization of an origin.
160
+ * > However, the code points U+0027 ('), U+0021 (*), U+002C (,)
161
+ * > and U+003B (;) MUST NOT appear in the serialization.
162
+ * > If they are required, they must be percent-encoded
163
+ * > as "%27", "%2A", "%2C" or "%3B", respectively.
164
+ */
165
+ function checkSerializedOrigin(token) {
166
+ const url = parseUrl(token.value);
167
+ (0, debug_1.log)('Parse URL: "%s" => %O', token.value, url);
168
+ if (!url) {
169
+ return token.unmatched({
170
+ expects: [{ type: 'common', value: 'serialized-origin' }],
171
+ });
172
+ }
173
+ if (url.pathname && url.pathname !== '/') {
174
+ return token.unmatched({
175
+ reason: 'extra-token',
176
+ extra: { type: 'common', value: 'pathname' },
177
+ partName: 'serialized-origin',
178
+ });
179
+ }
180
+ if (url.search) {
181
+ return token.unmatched({
182
+ reason: 'extra-token',
183
+ extra: { type: 'common', value: 'query' },
184
+ partName: 'serialized-origin',
185
+ });
186
+ }
187
+ if (url.hash) {
188
+ return token.unmatched({
189
+ reason: 'extra-token',
190
+ extra: { type: 'common', value: 'hash' },
191
+ partName: 'serialized-origin',
192
+ });
193
+ }
194
+ if (url.username) {
195
+ return token.unmatched({
196
+ reason: 'extra-token',
197
+ extra: { type: 'common', value: 'username' },
198
+ partName: 'serialized-origin',
199
+ });
200
+ }
201
+ if (url.password) {
202
+ return token.unmatched({
203
+ reason: 'extra-token',
204
+ extra: { type: 'common', value: 'password' },
205
+ partName: 'serialized-origin',
206
+ });
207
+ }
208
+ if (!token.value.includes(url.host)) {
209
+ return token.unmatched({
210
+ reason: 'must-be-serialized',
211
+ partName: 'serialized-origin',
212
+ });
213
+ }
214
+ if (token.includes("'")) {
215
+ return token.unmatched({
216
+ expects: [{ type: 'const', value: '%27' }],
217
+ reason: 'must-be-percent-encoded',
218
+ partName: 'serialized-origin',
219
+ });
220
+ }
221
+ if (token.includes('*')) {
222
+ return token.unmatched({
223
+ expects: [{ type: 'const', value: '%2A' }],
224
+ reason: 'must-be-percent-encoded',
225
+ partName: 'serialized-origin',
226
+ });
227
+ }
228
+ if (token.includes(',')) {
229
+ return token.unmatched({
230
+ expects: [{ type: 'const', value: '%2C' }],
231
+ reason: 'must-be-percent-encoded',
232
+ partName: 'serialized-origin',
233
+ });
234
+ }
235
+ if (token.includes(';')) {
236
+ return token.unmatched({
237
+ expects: [{ type: 'const', value: '%3B' }],
238
+ reason: 'must-be-percent-encoded',
239
+ partName: 'serialized-origin',
240
+ });
241
+ }
242
+ return (0, match_result_1.matched)();
243
+ }
244
+ function parseUrl(value) {
245
+ try {
246
+ return new URL(value);
247
+ }
248
+ catch {
249
+ return null;
250
+ }
251
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ // @ts-nocheck
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const check_serialized_permissions_policy_1 = require("./check-serialized-permissions-policy");
5
+ const check = (0, check_serialized_permissions_policy_1.checkSerializedPermissionsPolicy)();
6
+ test('checkSerializedPermissionsPolicy', () => {
7
+ expect(check('').reason).toBe('empty-token');
8
+ expect(check(' ').reason).toBe('unexpected-token');
9
+ expect(check('a').reason).toBe('missing-token');
10
+ expect(check('a:').reason).toBe('unexpected-token');
11
+ expect(check('a ').reason).toBe('missing-token');
12
+ expect(check('a a').reason).toBe('unexpected-token');
13
+ expect(check('a *').matched).toBe(true);
14
+ expect(check('a *a').reason).toBe('unexpected-token');
15
+ expect(check('a none').reason).toBe('missing-token');
16
+ expect(check("a 'none'").matched).toBe(true);
17
+ expect(check('a https://markuplint.dev').matched).toBe(true);
18
+ expect(check('a https://markuplint.dev/path/to').reason).toBe('extra-token');
19
+ expect(check('a https://マルチバイト.abc.xyz').reason).toBe('must-be-serialized');
20
+ expect(check('a * https://markuplint.dev').matched).toBe(true);
21
+ expect(check("a * https://markuplint.dev 'none'").matched).toBe(true);
22
+ expect(check("a * https://markuplint.dev 'none';b").reason).toBe('missing-token');
23
+ expect(check("a * https://markuplint.dev 'none';b ").reason).toBe('missing-token');
24
+ expect(check("a * https://markuplint.dev 'none';b *").matched).toBe(true);
25
+ expect(check("a * https://markuplint.dev 'none';b *;c 'none'").matched).toBe(true);
26
+ });
@@ -0,0 +1,5 @@
1
+ import type { CustomSyntaxChecker } from '../types';
2
+ /**
3
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete
4
+ */
5
+ export declare const checkAutoComplete: CustomSyntaxChecker;
@@ -0,0 +1,282 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkAutoComplete = void 0;
4
+ const get_candicate_1 = require("../get-candicate");
5
+ const match_result_1 = require("../match-result");
6
+ const token_1 = require("../token");
7
+ /**
8
+ * https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section
9
+ */
10
+ const namedGroup = /^section-/i;
11
+ /**
12
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-shipping
13
+ */
14
+ const partOfAddress = ['shipping', 'billing'];
15
+ /**
16
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field
17
+ */
18
+ const autofillFieldNames = [
19
+ 'name',
20
+ 'honorific-prefix',
21
+ 'given-name',
22
+ 'additional-name',
23
+ 'family-name',
24
+ 'honorific-suffix',
25
+ 'nickname',
26
+ 'username',
27
+ 'new-password',
28
+ 'current-password',
29
+ 'one-time-code',
30
+ 'organization-title',
31
+ 'organization',
32
+ 'street-address',
33
+ 'address-line1',
34
+ 'address-line2',
35
+ 'address-line3',
36
+ 'address-level4',
37
+ 'address-level3',
38
+ 'address-level2',
39
+ 'address-level1',
40
+ 'country',
41
+ 'country-name',
42
+ 'postal-code',
43
+ 'cc-name',
44
+ 'cc-given-name',
45
+ 'cc-additional-name',
46
+ 'cc-family-name',
47
+ 'cc-number',
48
+ 'cc-exp',
49
+ 'cc-exp-month',
50
+ 'cc-exp-year',
51
+ 'cc-csc',
52
+ 'cc-type',
53
+ 'transaction-currency',
54
+ 'transaction-amount',
55
+ 'language',
56
+ 'bday',
57
+ 'bday-day',
58
+ 'bday-month',
59
+ 'bday-year',
60
+ 'sex',
61
+ 'url',
62
+ 'photo',
63
+ ];
64
+ /**
65
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-home
66
+ */
67
+ const contactingTokens = ['home', 'work', 'mobile', 'fax', 'pager'];
68
+ /**
69
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:ascii-case-insensitive-7
70
+ */
71
+ const contactableFieldNames = [
72
+ 'tel',
73
+ 'tel-country-code',
74
+ 'tel-national',
75
+ 'tel-area-code',
76
+ 'tel-local',
77
+ 'tel-local-prefix',
78
+ 'tel-local-suffix',
79
+ 'tel-extension',
80
+ 'email',
81
+ 'impp',
82
+ ];
83
+ const URL_AUTOCOMPLET = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete';
84
+ const URL_ON_OFF = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-on-2';
85
+ const URL_NAMED_GROUP = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section';
86
+ const URL_PART_OF_ADDRESS = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-shipping';
87
+ const URL_AUTOFILL_FIELD = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field';
88
+ const URL_CONTACTABLE_FIELD = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-tel';
89
+ /**
90
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete
91
+ */
92
+ const checkAutoComplete = () => value => {
93
+ let hasNamedGroup = false;
94
+ let hasPartOfAddress = false;
95
+ let hasContactingToken = false;
96
+ const tokens = new token_1.TokenCollection(value, {
97
+ disallowToSurroundBySpaces: false,
98
+ allowEmpty: false,
99
+ ordered: true,
100
+ unique: true,
101
+ caseInsensitive: true,
102
+ });
103
+ const listingChecked = tokens.check({
104
+ expects: [
105
+ {
106
+ type: 'format',
107
+ value: 'autocomplete',
108
+ },
109
+ ],
110
+ ref: URL_AUTOCOMPLET,
111
+ });
112
+ if (!listingChecked.matched) {
113
+ return listingChecked;
114
+ }
115
+ const idents = tokens.getIdentTokens();
116
+ const headAndTail1 = idents.headAndTail();
117
+ let { head, tail } = headAndTail1;
118
+ if (!head) {
119
+ // Never
120
+ throw new Error('TokenCollection is empty');
121
+ }
122
+ // > When wearing the autofill anchor mantle, the autocomplete attribute,
123
+ // > if specified, must have a value that is
124
+ // > an ordered set of space-separated tokens consisting of
125
+ // > just autofill detail tokens
126
+ // > (i.e. the "on" and "off" keywords are not allowed).
127
+ if (head.match(['on', 'off'], true)) {
128
+ if (tail.length) {
129
+ return tail[0].unmatched({
130
+ reason: 'extra-token',
131
+ expects: [
132
+ {
133
+ type: 'format',
134
+ value: 'autocomplete',
135
+ },
136
+ ],
137
+ ref: URL_ON_OFF,
138
+ });
139
+ }
140
+ return (0, match_result_1.matched)();
141
+ }
142
+ // > Optionally, a token whose first eight characters are
143
+ // > an ASCII case-insensitive match for the string "section-",
144
+ // > meaning that the field belongs to the named group.
145
+ if (head.match(namedGroup, true)) {
146
+ hasNamedGroup = true;
147
+ const sectionToken = tail.search(namedGroup);
148
+ if (sectionToken) {
149
+ return sectionToken.unmatched({
150
+ partName: 'autofill named group',
151
+ reason: 'duplicated',
152
+ ref: URL_NAMED_GROUP,
153
+ });
154
+ }
155
+ const headAndTail2 = tail.headAndTail();
156
+ head = headAndTail2.head;
157
+ tail = headAndTail2.tail;
158
+ if (!head) {
159
+ // Missing autofill field name but it is valid
160
+ return (0, match_result_1.matched)();
161
+ }
162
+ }
163
+ // > Optionally, a token that is an ASCII case-insensitive match for
164
+ // > one of the following strings:
165
+ // > - "shipping", meaning the field is part of the shipping address or contact information
166
+ // > - "billing", meaning the field is part of the billing address or contact information
167
+ if (head.match(partOfAddress, true)) {
168
+ hasPartOfAddress = true;
169
+ const partToken = tail.search(partOfAddress);
170
+ if (partToken) {
171
+ return partToken.unmatched({
172
+ reason: 'duplicated',
173
+ expects: [
174
+ {
175
+ type: 'format',
176
+ value: 'autocomplete',
177
+ },
178
+ ],
179
+ ref: URL_PART_OF_ADDRESS,
180
+ });
181
+ }
182
+ const headAndTail3 = tail.headAndTail();
183
+ head = headAndTail3.head;
184
+ tail = headAndTail3.tail;
185
+ if (!head) {
186
+ // Missing autofill field name but it is valid
187
+ return (0, match_result_1.matched)();
188
+ }
189
+ }
190
+ if (head.match(contactingTokens, true)) {
191
+ hasContactingToken = true;
192
+ const contactableFiledToken = tail[0];
193
+ if (!contactableFiledToken) {
194
+ // Missing autofill field name but it is valid
195
+ return (0, match_result_1.matched)();
196
+ }
197
+ if (!contactableFiledToken.match(contactableFieldNames, true)) {
198
+ const candicate = (0, get_candicate_1.getCandicate)(contactableFiledToken.value, contactableFieldNames);
199
+ return contactableFiledToken.unmatched({
200
+ reason: 'unexpected-token',
201
+ expects: contactableFieldNames.slice().map(token => ({
202
+ type: 'const',
203
+ value: token,
204
+ })),
205
+ candicate,
206
+ ref: URL_CONTACTABLE_FIELD,
207
+ });
208
+ }
209
+ if (tail[1]) {
210
+ return tail[1].unmatched({
211
+ reason: 'extra-token',
212
+ expects: [
213
+ {
214
+ type: 'format',
215
+ value: 'autocomplete',
216
+ },
217
+ ],
218
+ ref: URL_AUTOFILL_FIELD,
219
+ });
220
+ }
221
+ return (0, match_result_1.matched)();
222
+ }
223
+ if (head.match([...autofillFieldNames, ...contactableFieldNames], true)) {
224
+ if (tail.length) {
225
+ return tail[0].unmatched({
226
+ reason: 'extra-token',
227
+ expects: [
228
+ {
229
+ type: 'format',
230
+ value: 'autocomplete',
231
+ },
232
+ ],
233
+ ref: URL_AUTOFILL_FIELD,
234
+ });
235
+ }
236
+ return (0, match_result_1.matched)();
237
+ }
238
+ const expects = [
239
+ {
240
+ type: 'common',
241
+ value: 'autofill field name',
242
+ },
243
+ ];
244
+ let candicate;
245
+ if (!hasNamedGroup) {
246
+ expects.unshift({
247
+ type: 'common',
248
+ value: 'autofill named group',
249
+ });
250
+ // Potentially typo a named group
251
+ const [prefix, namedGroupStr] = head.value.split('-');
252
+ const candicatePrefix = (0, get_candicate_1.getCandicate)(prefix, 'section');
253
+ if (candicatePrefix) {
254
+ candicate = `${candicatePrefix}-${namedGroupStr || ''}`;
255
+ }
256
+ }
257
+ else if (!hasPartOfAddress) {
258
+ expects.unshift(...partOfAddress
259
+ .slice()
260
+ .reverse()
261
+ .map(token => ({
262
+ type: 'const',
263
+ value: token,
264
+ })));
265
+ candicate = (0, get_candicate_1.getCandicate)(head.value, partOfAddress, autofillFieldNames, contactingTokens, contactableFieldNames);
266
+ }
267
+ else if (!hasContactingToken) {
268
+ expects.push(...contactingTokens.slice().map(token => ({
269
+ type: 'const',
270
+ value: token,
271
+ })));
272
+ candicate = (0, get_candicate_1.getCandicate)(head.value, autofillFieldNames, contactingTokens, contactableFieldNames);
273
+ }
274
+ candicate = candicate || (0, get_candicate_1.getCandicate)(head.value, autofillFieldNames);
275
+ return head.unmatched({
276
+ reason: 'unexpected-token',
277
+ expects,
278
+ candicate,
279
+ ref: URL_AUTOFILL_FIELD,
280
+ });
281
+ };
282
+ exports.checkAutoComplete = checkAutoComplete;
@@ -0,0 +1 @@
1
+ export {};