@markuplint/types 3.0.0-dev.25 → 3.0.0-dev.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/gen/specific-schema.json +0 -98
- package/gen/types.ts +0 -66
- package/src/check-multi-types.ts +0 -35
- package/src/check.spec.ts +0 -83
- package/src/check.ts +0 -48
- package/src/css-syntax.spec.ts +0 -167
- package/src/css-syntax.ts +0 -188
- package/src/debug.ts +0 -3
- package/src/defs.ts +0 -811
- package/src/enum.ts +0 -25
- package/src/get-candidate.ts +0 -24
- package/src/index.ts +0 -3
- package/src/keyword-type.ts +0 -64
- package/src/list.spec.ts +0 -133
- package/src/list.ts +0 -34
- package/src/match-result.ts +0 -49
- package/src/number.ts +0 -46
- package/src/primitive/index.spec.ts +0 -65
- package/src/primitive/index.ts +0 -7
- package/src/primitive/is-float.ts +0 -8
- package/src/primitive/is-int.ts +0 -8
- package/src/primitive/is-non-zero-uint.ts +0 -8
- package/src/primitive/is-quantity.ts +0 -38
- package/src/primitive/is-uint.ts +0 -15
- package/src/primitive/range.ts +0 -14
- package/src/primitive/split-unit.ts +0 -20
- package/src/rfc/is-bcp-47.spec.ts +0 -23
- package/src/rfc/is-bcp-47.ts +0 -13
- package/src/token/index.ts +0 -2
- package/src/token/token-collection.spec.ts +0 -147
- package/src/token/token-collection.ts +0 -444
- package/src/token/token.ts +0 -144
- package/src/types.schema.ts +0 -1113
- package/src/types.ts +0 -118
- package/src/w3c/check-serialized-permissions-policy.spec.ts +0 -38
- package/src/w3c/check-serialized-permissions-policy.ts +0 -303
- package/src/whatwg/check-autocomplete.spec.ts +0 -387
- package/src/whatwg/check-autocomplete.ts +0 -380
- package/src/whatwg/check-datetime/date-string.ts +0 -44
- package/src/whatwg/check-datetime/datetime-tokens.ts +0 -600
- package/src/whatwg/check-datetime/duration-string.ts +0 -399
- package/src/whatwg/check-datetime/global-date-and-time-string.ts +0 -96
- package/src/whatwg/check-datetime/index.spec.ts +0 -333
- package/src/whatwg/check-datetime/index.ts +0 -36
- package/src/whatwg/check-datetime/local-date-and-time-string.ts +0 -163
- package/src/whatwg/check-datetime/month-string.ts +0 -31
- package/src/whatwg/check-datetime/time-string.ts +0 -49
- package/src/whatwg/check-datetime/time-zone-offset-string.ts +0 -93
- package/src/whatwg/check-datetime/week-string.ts +0 -41
- package/src/whatwg/check-datetime/year-string.ts +0 -26
- package/src/whatwg/check-datetime/yearless-date-string.ts +0 -38
- package/src/whatwg/check-mime-type.spec.ts +0 -59
- package/src/whatwg/check-mime-type.ts +0 -46
- package/src/whatwg/is-abs-url.spec.ts +0 -8
- package/src/whatwg/is-abs-url.ts +0 -31
- package/src/whatwg/is-browser-context-name.ts +0 -16
- package/src/whatwg/is-custom-element-name.ts +0 -76
- package/src/whatwg/is-itemprop-name.ts +0 -17
- package/tsconfig.test.json +0 -3
- package/tsconfig.tsbuildinfo +0 -1
package/src/types.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
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
|
-
candidate?: 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' | 'regexp' | '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;
|
|
@@ -1,38 +0,0 @@
|
|
|
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').matched).toBe(true); // Current supported
|
|
12
|
-
expect(check('a:').reason).toBe('unexpected-token');
|
|
13
|
-
// expect(check('a ').reason).toBe('missing-token'); // Current supported
|
|
14
|
-
expect(check('a ').matched).toBe(true);
|
|
15
|
-
expect(check('a a').reason).toBe('unexpected-token');
|
|
16
|
-
expect(check('a *').matched).toBe(true);
|
|
17
|
-
expect(check('a *a').reason).toBe('unexpected-token');
|
|
18
|
-
expect(check('a none').reason).toBe('missing-token');
|
|
19
|
-
expect(check("a 'none'").matched).toBe(true);
|
|
20
|
-
expect(check('a https://markuplint.dev').matched).toBe(true);
|
|
21
|
-
expect(check('a https://markuplint.dev/path/to').reason).toBe('extra-token');
|
|
22
|
-
expect(check('a https://マルチバイト.abc.xyz').reason).toBe('must-be-serialized');
|
|
23
|
-
expect(check('a * https://markuplint.dev').matched).toBe(true);
|
|
24
|
-
expect(check("a * https://markuplint.dev 'none'").matched).toBe(true);
|
|
25
|
-
// expect(check("a * https://markuplint.dev 'none';b").reason).toBe('missing-token');
|
|
26
|
-
expect(check("a * https://markuplint.dev 'none';b").matched).toBe(true); // Current supported
|
|
27
|
-
// expect(check("a * https://markuplint.dev 'none';b ").reason).toBe('missing-token');
|
|
28
|
-
expect(check("a * https://markuplint.dev 'none';b ").matched).toBe(true); // Current supported
|
|
29
|
-
expect(check("a * https://markuplint.dev 'none';b *").matched).toBe(true);
|
|
30
|
-
expect(check("a * https://markuplint.dev 'none';b *;c 'none'").matched).toBe(true);
|
|
31
|
-
expect(check("a * https://markuplint.dev 'none'; b *; c 'none'").matched).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('YouTube embed', () => {
|
|
35
|
-
expect(
|
|
36
|
-
check('accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture').matched,
|
|
37
|
-
).toBe(true);
|
|
38
|
-
});
|
|
@@ -1,303 +0,0 @@
|
|
|
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
|
-
* But change below according to current supported:
|
|
22
|
-
*
|
|
23
|
-
* ```abnf
|
|
24
|
-
* serialized-policy-directive = feature-identifier [RWS allow-list]
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* `allow-list` is optional.
|
|
28
|
-
*/
|
|
29
|
-
export const checkSerializedPermissionsPolicy: CustomSyntaxChecker = () => value => {
|
|
30
|
-
const res = _checkSerializedPermissionsPolicy(value);
|
|
31
|
-
|
|
32
|
-
if (!res.matched) {
|
|
33
|
-
log('Failed: %O', res);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return res;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
function _checkSerializedPermissionsPolicy(value: string) {
|
|
40
|
-
/**
|
|
41
|
-
* The list of serialized-policy-directive
|
|
42
|
-
*
|
|
43
|
-
* > ```abnf
|
|
44
|
-
* > serialized-policy-directive *(";" serialized-policy-directive)
|
|
45
|
-
* > ```
|
|
46
|
-
*/
|
|
47
|
-
const patterns = [
|
|
48
|
-
/**
|
|
49
|
-
* serialized-policy-directive
|
|
50
|
-
*/
|
|
51
|
-
/[^;]*/,
|
|
52
|
-
/**
|
|
53
|
-
* separator
|
|
54
|
-
*/
|
|
55
|
-
/;?/,
|
|
56
|
-
];
|
|
57
|
-
const tokens = TokenCollection.fromPatterns(value, patterns, { repeat: true });
|
|
58
|
-
const serializedPolicyDirectives = tokens.chunk(patterns.length);
|
|
59
|
-
|
|
60
|
-
log('Serialized Permissions Policy: %s => %O', value, serializedPolicyDirectives);
|
|
61
|
-
|
|
62
|
-
for (const [serializedPolicyDirective] of serializedPolicyDirectives) {
|
|
63
|
-
if (!serializedPolicyDirective || !serializedPolicyDirective.value) {
|
|
64
|
-
return unmatched('', 'empty-token');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const [aw, featureIdentifier, rws, allowListValue] = TokenCollection.fromPatterns(serializedPolicyDirective, [
|
|
68
|
-
/**
|
|
69
|
-
* Any whitespace
|
|
70
|
-
*/
|
|
71
|
-
/\s*/,
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* feature-identifier
|
|
75
|
-
*
|
|
76
|
-
* > ```abnf
|
|
77
|
-
* > feature-identifier = 1*( ALPHA / DIGIT / "-")
|
|
78
|
-
* > ```
|
|
79
|
-
*/
|
|
80
|
-
/[^\s]*/,
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* RWS (Required whitespace)
|
|
84
|
-
*
|
|
85
|
-
* @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3
|
|
86
|
-
*/
|
|
87
|
-
/\s*/,
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* allow-list-value
|
|
91
|
-
*/
|
|
92
|
-
/.*/,
|
|
93
|
-
]);
|
|
94
|
-
|
|
95
|
-
log('Serialized Policy Directive: %s => %O', serializedPolicyDirective.value, {
|
|
96
|
-
aw,
|
|
97
|
-
featureIdentifier,
|
|
98
|
-
rws,
|
|
99
|
-
allowListValue,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* > ```abnf
|
|
104
|
-
* > feature-identifier = 1*( ALPHA / DIGIT / "-")
|
|
105
|
-
* > ```
|
|
106
|
-
*/
|
|
107
|
-
if (!featureIdentifier || !featureIdentifier.match(/^[a-z0-9-]+$/i)) {
|
|
108
|
-
return featureIdentifier.unmatched({
|
|
109
|
-
reason: 'unexpected-token',
|
|
110
|
-
expects: [{ type: 'common', value: 'feature-identifier' }],
|
|
111
|
-
partName: 'feature-identifier',
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (!rws || !rws.value) {
|
|
116
|
-
// return unmatched('', 'missing-token', {
|
|
117
|
-
// expects: [{ type: 'common', value: 'whitespace' }],
|
|
118
|
-
// partName: 'directive',
|
|
119
|
-
// });
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!allowListValue || !allowListValue.value) {
|
|
124
|
-
// return unmatched('', 'missing-token', {
|
|
125
|
-
// expects: [{ type: 'common', value: 'allow-list' }],
|
|
126
|
-
// partName: 'allow-list',
|
|
127
|
-
// });
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const allowListPatterns = [
|
|
132
|
-
// Value
|
|
133
|
-
/[^\s]*/,
|
|
134
|
-
// Separator
|
|
135
|
-
/\s*/,
|
|
136
|
-
];
|
|
137
|
-
const allowListTokens = TokenCollection.fromPatterns(allowListValue, allowListPatterns, { repeat: true });
|
|
138
|
-
const allowList = allowListTokens.chunk(allowListPatterns.length);
|
|
139
|
-
|
|
140
|
-
log('Allow List: %s => %O', allowListTokens.value, allowList);
|
|
141
|
-
|
|
142
|
-
for (const [allow] of allowList) {
|
|
143
|
-
if (!allow || !allow.value) {
|
|
144
|
-
return unmatched('', 'missing-token', {
|
|
145
|
-
expects: [
|
|
146
|
-
{ type: 'const', value: '*' },
|
|
147
|
-
{ type: 'const', value: "'self'" },
|
|
148
|
-
{ type: 'const', value: "'src'" },
|
|
149
|
-
{ type: 'const', value: "'none'" },
|
|
150
|
-
{ type: 'common', value: 'serialized-origin' },
|
|
151
|
-
],
|
|
152
|
-
partName: 'allow-list',
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const origin = checkSerializedOrigin(allow);
|
|
157
|
-
|
|
158
|
-
if (origin.matched) {
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (origin.reason !== 'syntax-error') {
|
|
163
|
-
return origin;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (allow.match(['*', "'self'", "'src'", "'none'"], true)) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (allow.match(['self', 'src', 'none'], true)) {
|
|
171
|
-
return allow.unmatched({
|
|
172
|
-
reason: 'missing-token',
|
|
173
|
-
expects: [{ type: 'common', value: 'single-quote' }],
|
|
174
|
-
partName: 'keyword',
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return allow.unmatched({
|
|
179
|
-
reason: 'unexpected-token',
|
|
180
|
-
expects: [
|
|
181
|
-
{ type: 'const', value: '*' },
|
|
182
|
-
{ type: 'const', value: "'self'" },
|
|
183
|
-
{ type: 'const', value: "'src'" },
|
|
184
|
-
{ type: 'const', value: "'none'" },
|
|
185
|
-
{ type: 'common', value: 'serialized-origin' },
|
|
186
|
-
],
|
|
187
|
-
partName: 'allow-list',
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return matched();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* serialized-origin
|
|
197
|
-
*
|
|
198
|
-
* > serialized-origin is the serialization of an origin.
|
|
199
|
-
* > However, the code points U+0027 ('), U+0021 (*), U+002C (,)
|
|
200
|
-
* > and U+003B (;) MUST NOT appear in the serialization.
|
|
201
|
-
* > If they are required, they must be percent-encoded
|
|
202
|
-
* > as "%27", "%2A", "%2C" or "%3B", respectively.
|
|
203
|
-
*/
|
|
204
|
-
function checkSerializedOrigin(token: Token) {
|
|
205
|
-
const url = parseUrl(token.value);
|
|
206
|
-
|
|
207
|
-
log('Parse URL: "%s" => %O', token.value, url);
|
|
208
|
-
|
|
209
|
-
if (!url) {
|
|
210
|
-
return token.unmatched({
|
|
211
|
-
expects: [{ type: 'common', value: 'serialized-origin' }],
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (url.pathname && url.pathname !== '/') {
|
|
216
|
-
return token.unmatched({
|
|
217
|
-
reason: 'extra-token',
|
|
218
|
-
extra: { type: 'common', value: 'pathname' },
|
|
219
|
-
partName: 'serialized-origin',
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (url.search) {
|
|
224
|
-
return token.unmatched({
|
|
225
|
-
reason: 'extra-token',
|
|
226
|
-
extra: { type: 'common', value: 'query' },
|
|
227
|
-
partName: 'serialized-origin',
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (url.hash) {
|
|
232
|
-
return token.unmatched({
|
|
233
|
-
reason: 'extra-token',
|
|
234
|
-
extra: { type: 'common', value: 'hash' },
|
|
235
|
-
partName: 'serialized-origin',
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (url.username) {
|
|
240
|
-
return token.unmatched({
|
|
241
|
-
reason: 'extra-token',
|
|
242
|
-
extra: { type: 'common', value: 'username' },
|
|
243
|
-
partName: 'serialized-origin',
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (url.password) {
|
|
248
|
-
return token.unmatched({
|
|
249
|
-
reason: 'extra-token',
|
|
250
|
-
extra: { type: 'common', value: 'password' },
|
|
251
|
-
partName: 'serialized-origin',
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (!token.value.includes(url.host)) {
|
|
256
|
-
return token.unmatched({
|
|
257
|
-
reason: 'must-be-serialized',
|
|
258
|
-
partName: 'serialized-origin',
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (token.includes("'")) {
|
|
263
|
-
return token.unmatched({
|
|
264
|
-
expects: [{ type: 'const', value: '%27' }],
|
|
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: '%2A' }],
|
|
273
|
-
reason: 'must-be-percent-encoded',
|
|
274
|
-
partName: 'serialized-origin',
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (token.includes(',')) {
|
|
279
|
-
return token.unmatched({
|
|
280
|
-
expects: [{ type: 'const', value: '%2C' }],
|
|
281
|
-
reason: 'must-be-percent-encoded',
|
|
282
|
-
partName: 'serialized-origin',
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (token.includes(';')) {
|
|
287
|
-
return token.unmatched({
|
|
288
|
-
expects: [{ type: 'const', value: '%3B' }],
|
|
289
|
-
reason: 'must-be-percent-encoded',
|
|
290
|
-
partName: 'serialized-origin',
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return matched();
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function parseUrl(value: string) {
|
|
298
|
-
try {
|
|
299
|
-
return new URL(value);
|
|
300
|
-
} catch {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
}
|