@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/types.ts ADDED
@@ -0,0 +1,118 @@
1
+ import type { cssSyntaxMatch } from './css-syntax';
2
+
3
+ export type { Type, List, Enum, CssSyntax, KeywordDefinedType, Number } from './types.schema';
4
+
5
+ export type Result = UnmatchedResult | MatchedResult;
6
+
7
+ export type UnmatchedResult = {
8
+ matched: false;
9
+ ref: string | null;
10
+ raw: string;
11
+ length: number;
12
+ offset: number;
13
+ line: number;
14
+ column: number;
15
+ reason: UnmatchedResultReason;
16
+ passCount?: number;
17
+ } & UnmatchedResultOptions;
18
+
19
+ export type UnmatchedResultOptions = {
20
+ partName?: string;
21
+ expects?: Expect[];
22
+ extra?: Expect;
23
+ candicate?: string;
24
+ };
25
+
26
+ export type UnmatchedResultReason =
27
+ | 'syntax-error'
28
+ | 'typo'
29
+ | 'missing-token'
30
+ | 'missing-comma'
31
+ | 'unexpected-token'
32
+ | 'unexpected-space'
33
+ | 'unexpected-newline'
34
+ | 'unexpected-comma'
35
+ | 'empty-token'
36
+ | 'out-of-range'
37
+ | 'doesnt-exist-in-enum'
38
+ | 'duplicated'
39
+ | 'illegal-combination'
40
+ | 'illegal-order'
41
+ | 'extra-token'
42
+ | 'must-be-percent-encoded'
43
+ | 'must-be-serialized'
44
+ | {
45
+ type: 'out-of-range';
46
+ gt?: number;
47
+ gte?: number;
48
+ lt?: number;
49
+ lte?: number;
50
+ }
51
+ | {
52
+ type: 'out-of-range-length-char';
53
+ gte: number;
54
+ lte?: number;
55
+ }
56
+ | {
57
+ type: 'out-of-range-length-digit';
58
+ gte: number;
59
+ lte?: number;
60
+ };
61
+
62
+ export type MatchedResult = {
63
+ matched: true;
64
+ };
65
+
66
+ export type Expect = {
67
+ type: 'const' | 'format' | 'syntax' | 'regxp' | 'common';
68
+ value: string;
69
+ };
70
+
71
+ export type FormattedPrimitiveTypeCheck = (value: string) => boolean;
72
+
73
+ export type FormattedPrimitiveTypeCreator<O = never> = (options?: O) => FormattedPrimitiveTypeCheck;
74
+
75
+ export type Defs = Record<string, CustomCssSyntax | CustomSyntax>;
76
+
77
+ export type CustomSyntax = {
78
+ ref: string;
79
+ expects?: Expect[];
80
+ is: CustomSyntaxCheck;
81
+ };
82
+
83
+ export type CustomSyntaxCheck = (value: string) => Result;
84
+ export type CustomSyntaxChecker<O = {}> = (options?: O) => CustomSyntaxCheck;
85
+
86
+ export type CustomCssSyntax = {
87
+ ref: string;
88
+ caseSensitive?: boolean;
89
+ expects?: Expect[];
90
+ syntax: {
91
+ apply: `<${string}>`;
92
+ def: Record<string, string | CssSyntaxTokenizer>;
93
+ /**
94
+ * @deprecated
95
+ */
96
+ ebnf?: Record<string, string | string[]>;
97
+ /**
98
+ * @deprecated
99
+ */
100
+ properties?: Record<string, string>;
101
+ };
102
+ };
103
+
104
+ export type CSSSyntaxToken = {
105
+ type: number;
106
+ value: string;
107
+ index: number;
108
+ balance: number;
109
+ node?: any;
110
+ };
111
+
112
+ export type CssSyntaxTokenizer = (
113
+ token: CSSSyntaxToken | null,
114
+ getNextToken: GetNextToken,
115
+ match: typeof cssSyntaxMatch,
116
+ ) => number;
117
+
118
+ export type GetNextToken = (length: number) => CSSSyntaxToken | null;
@@ -0,0 +1,27 @@
1
+ // @ts-nocheck
2
+
3
+ import { checkSerializedPermissionsPolicy } from './check-serialized-permissions-policy';
4
+
5
+ const check = checkSerializedPermissionsPolicy();
6
+
7
+ test('checkSerializedPermissionsPolicy', () => {
8
+ expect(check('').reason).toBe('empty-token');
9
+ expect(check(' ').reason).toBe('unexpected-token');
10
+ expect(check('a').reason).toBe('missing-token');
11
+ expect(check('a:').reason).toBe('unexpected-token');
12
+ expect(check('a ').reason).toBe('missing-token');
13
+ expect(check('a a').reason).toBe('unexpected-token');
14
+ expect(check('a *').matched).toBe(true);
15
+ expect(check('a *a').reason).toBe('unexpected-token');
16
+ expect(check('a none').reason).toBe('missing-token');
17
+ expect(check("a 'none'").matched).toBe(true);
18
+ expect(check('a https://markuplint.dev').matched).toBe(true);
19
+ expect(check('a https://markuplint.dev/path/to').reason).toBe('extra-token');
20
+ expect(check('a https://マルチバイト.abc.xyz').reason).toBe('must-be-serialized');
21
+ expect(check('a * https://markuplint.dev').matched).toBe(true);
22
+ expect(check("a * https://markuplint.dev 'none'").matched).toBe(true);
23
+ expect(check("a * https://markuplint.dev 'none';b").reason).toBe('missing-token');
24
+ expect(check("a * https://markuplint.dev 'none';b ").reason).toBe('missing-token');
25
+ expect(check("a * https://markuplint.dev 'none';b *").matched).toBe(true);
26
+ expect(check("a * https://markuplint.dev 'none';b *;c 'none'").matched).toBe(true);
27
+ });
@@ -0,0 +1,287 @@
1
+ import type { Token } from '../token';
2
+ import type { CustomSyntaxChecker } from '../types';
3
+
4
+ import { log } from '../debug';
5
+ import { matched, unmatched } from '../match-result';
6
+ import { TokenCollection } from '../token';
7
+
8
+ /**
9
+ * @see https://w3c.github.io/webappsec-permissions-policy/#serialized-permissions-policy
10
+ *
11
+ * > Policy Directives in HTML attributes are represented as their
12
+ * > ASCII serialization, with the following ABNF:
13
+ * > ```abnf
14
+ * > serialized-permissions-policy = serialized-policy-directive *(";" serialized-policy-directive)
15
+ * > serialized-policy-directive = feature-identifier RWS allow-list
16
+ * > feature-identifier = 1*( ALPHA / DIGIT / "-")
17
+ * > allow-list = allow-list-value *(RWS allow-list-value)
18
+ * > allow-list-value = serialized-origin / "*" / "'self'" / "'src'" / "'none'"
19
+ * > ```
20
+ */
21
+ export const checkSerializedPermissionsPolicy: CustomSyntaxChecker = () => value => {
22
+ const res = _checkSerializedPermissionsPolicy(value);
23
+
24
+ if (!res.matched) {
25
+ log('Failed: %O', res);
26
+ }
27
+
28
+ return res;
29
+ };
30
+
31
+ function _checkSerializedPermissionsPolicy(value: string) {
32
+ /**
33
+ * The list of serialized-policy-directive
34
+ *
35
+ * > ```abnf
36
+ * > serialized-policy-directive *(";" serialized-policy-directive)
37
+ * > ```
38
+ */
39
+ const patterns = [
40
+ /**
41
+ * serialized-policy-directive
42
+ */
43
+ /[^;]*/,
44
+ /**
45
+ * separator
46
+ */
47
+ /;?/,
48
+ ];
49
+ const tokens = TokenCollection.fromPatterns(value, patterns, { repeat: true });
50
+ const serializedPolicyDirectives = tokens.chunk(patterns.length);
51
+
52
+ log('Serialized Permissions Policy: %s => %O', value, serializedPolicyDirectives);
53
+
54
+ for (const [serializedPolicyDirective] of serializedPolicyDirectives) {
55
+ if (!serializedPolicyDirective || !serializedPolicyDirective.value) {
56
+ return unmatched('', 'empty-token');
57
+ }
58
+
59
+ const [featureIdentifier, rws, allowListValue] = TokenCollection.fromPatterns(serializedPolicyDirective, [
60
+ /**
61
+ * feature-identifier
62
+ *
63
+ * > ```abnf
64
+ * > feature-identifier = 1*( ALPHA / DIGIT / "-")
65
+ * > ```
66
+ */
67
+ /[^\s]*/,
68
+
69
+ /**
70
+ * RWS (Required whitespace)
71
+ *
72
+ * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3
73
+ */
74
+ /\s*/,
75
+
76
+ /**
77
+ * allow-list-value
78
+ */
79
+ /.*/,
80
+ ]);
81
+
82
+ log('Serialized Policy Directive: %s => %O', serializedPolicyDirective.value, {
83
+ featureIdentifier,
84
+ rws,
85
+ allowListValue,
86
+ });
87
+
88
+ /**
89
+ * > ```abnf
90
+ * > feature-identifier = 1*( ALPHA / DIGIT / "-")
91
+ * > ```
92
+ */
93
+ if (!featureIdentifier || !featureIdentifier.match(/^[a-z0-9-]+$/i)) {
94
+ return featureIdentifier.unmatched({
95
+ reason: 'unexpected-token',
96
+ expects: [{ type: 'common', value: 'feature-identifier' }],
97
+ partName: 'feature-identifier',
98
+ });
99
+ }
100
+
101
+ if (!rws || !rws.value) {
102
+ return unmatched('', 'missing-token', {
103
+ expects: [{ type: 'common', value: 'whitespace' }],
104
+ partName: 'directive',
105
+ });
106
+ }
107
+
108
+ if (!allowListValue || !allowListValue.value) {
109
+ return unmatched('', 'missing-token', {
110
+ expects: [{ type: 'common', value: 'allow-list' }],
111
+ partName: 'allow-list',
112
+ });
113
+ }
114
+
115
+ const allowListPatterns = [
116
+ // Value
117
+ /[^\s]*/,
118
+ // Separator
119
+ /\s*/,
120
+ ];
121
+ const allowListTokens = TokenCollection.fromPatterns(allowListValue, allowListPatterns, { repeat: true });
122
+ const allowList = allowListTokens.chunk(allowListPatterns.length);
123
+
124
+ log('Allow List: %s => %O', allowListTokens.value, allowList);
125
+
126
+ for (const [allow] of allowList) {
127
+ if (!allow || !allow.value) {
128
+ return unmatched('', 'missing-token', {
129
+ expects: [
130
+ { type: 'const', value: '*' },
131
+ { type: 'const', value: "'self'" },
132
+ { type: 'const', value: "'src'" },
133
+ { type: 'const', value: "'none'" },
134
+ { type: 'common', value: 'serialized-origin' },
135
+ ],
136
+ partName: 'allow-list',
137
+ });
138
+ }
139
+
140
+ const origin = checkSerializedOrigin(allow);
141
+
142
+ if (origin.matched) {
143
+ continue;
144
+ }
145
+
146
+ if (origin.reason !== 'syntax-error') {
147
+ return origin;
148
+ }
149
+
150
+ if (allow.match(['*', "'self'", "'src'", "'none'"], true)) {
151
+ continue;
152
+ }
153
+
154
+ if (allow.match(['self', 'src', 'none'], true)) {
155
+ return allow.unmatched({
156
+ reason: 'missing-token',
157
+ expects: [{ type: 'common', value: 'single-quote' }],
158
+ partName: 'keyword',
159
+ });
160
+ }
161
+
162
+ return allow.unmatched({
163
+ reason: 'unexpected-token',
164
+ expects: [
165
+ { type: 'const', value: '*' },
166
+ { type: 'const', value: "'self'" },
167
+ { type: 'const', value: "'src'" },
168
+ { type: 'const', value: "'none'" },
169
+ { type: 'common', value: 'serialized-origin' },
170
+ ],
171
+ partName: 'allow-list',
172
+ });
173
+ }
174
+ }
175
+
176
+ return matched();
177
+ }
178
+
179
+ /**
180
+ * serialized-origin
181
+ *
182
+ * > serialized-origin is the serialization of an origin.
183
+ * > However, the code points U+0027 ('), U+0021 (*), U+002C (,)
184
+ * > and U+003B (;) MUST NOT appear in the serialization.
185
+ * > If they are required, they must be percent-encoded
186
+ * > as "%27", "%2A", "%2C" or "%3B", respectively.
187
+ */
188
+ function checkSerializedOrigin(token: Token) {
189
+ const url = parseUrl(token.value);
190
+
191
+ log('Parse URL: "%s" => %O', token.value, url);
192
+
193
+ if (!url) {
194
+ return token.unmatched({
195
+ expects: [{ type: 'common', value: 'serialized-origin' }],
196
+ });
197
+ }
198
+
199
+ if (url.pathname && url.pathname !== '/') {
200
+ return token.unmatched({
201
+ reason: 'extra-token',
202
+ extra: { type: 'common', value: 'pathname' },
203
+ partName: 'serialized-origin',
204
+ });
205
+ }
206
+
207
+ if (url.search) {
208
+ return token.unmatched({
209
+ reason: 'extra-token',
210
+ extra: { type: 'common', value: 'query' },
211
+ partName: 'serialized-origin',
212
+ });
213
+ }
214
+
215
+ if (url.hash) {
216
+ return token.unmatched({
217
+ reason: 'extra-token',
218
+ extra: { type: 'common', value: 'hash' },
219
+ partName: 'serialized-origin',
220
+ });
221
+ }
222
+
223
+ if (url.username) {
224
+ return token.unmatched({
225
+ reason: 'extra-token',
226
+ extra: { type: 'common', value: 'username' },
227
+ partName: 'serialized-origin',
228
+ });
229
+ }
230
+
231
+ if (url.password) {
232
+ return token.unmatched({
233
+ reason: 'extra-token',
234
+ extra: { type: 'common', value: 'password' },
235
+ partName: 'serialized-origin',
236
+ });
237
+ }
238
+
239
+ if (!token.value.includes(url.host)) {
240
+ return token.unmatched({
241
+ reason: 'must-be-serialized',
242
+ partName: 'serialized-origin',
243
+ });
244
+ }
245
+
246
+ if (token.includes("'")) {
247
+ return token.unmatched({
248
+ expects: [{ type: 'const', value: '%27' }],
249
+ reason: 'must-be-percent-encoded',
250
+ partName: 'serialized-origin',
251
+ });
252
+ }
253
+
254
+ if (token.includes('*')) {
255
+ return token.unmatched({
256
+ expects: [{ type: 'const', value: '%2A' }],
257
+ reason: 'must-be-percent-encoded',
258
+ partName: 'serialized-origin',
259
+ });
260
+ }
261
+
262
+ if (token.includes(',')) {
263
+ return token.unmatched({
264
+ expects: [{ type: 'const', value: '%2C' }],
265
+ reason: 'must-be-percent-encoded',
266
+ partName: 'serialized-origin',
267
+ });
268
+ }
269
+
270
+ if (token.includes(';')) {
271
+ return token.unmatched({
272
+ expects: [{ type: 'const', value: '%3B' }],
273
+ reason: 'must-be-percent-encoded',
274
+ partName: 'serialized-origin',
275
+ });
276
+ }
277
+
278
+ return matched();
279
+ }
280
+
281
+ function parseUrl(value: string) {
282
+ try {
283
+ return new URL(value);
284
+ } catch {
285
+ return null;
286
+ }
287
+ }