@markuplint/types 3.0.0-alpha.0 → 3.0.0-alpha.2
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/README.md +1 -1
- package/lib/css-syntax.spec.js +1 -1
- package/lib/defs.js +4 -4
- package/lib/get-candidate.d.ts +3 -0
- package/lib/{get-candicate.js → get-candidate.js} +8 -8
- package/lib/list.spec.js +4 -4
- package/lib/number.js +4 -4
- package/lib/primitive/is-uint.d.ts +1 -1
- package/lib/primitive/is-uint.js +4 -4
- package/lib/token/token-collection.d.ts +21 -21
- package/lib/token/token-collection.js +101 -101
- package/lib/token/token-collection.spec.js +2 -2
- package/lib/token/token.d.ts +22 -22
- package/lib/token/token.js +36 -36
- package/lib/types.d.ts +2 -2
- package/lib/types.schema.d.ts +3 -0
- package/lib/whatwg/check-autocomplete.js +55 -15
- package/lib/whatwg/check-autocomplete.spec.js +19 -10
- package/lib/whatwg/check-datetime/datetime-tokens.d.ts +1 -1
- package/lib/whatwg/check-datetime/datetime-tokens.js +16 -16
- package/lib/whatwg/check-datetime/global-date-and-time-string.js +3 -3
- package/lib/whatwg/check-datetime/local-date-and-time-string.js +2 -2
- package/lib/whatwg/check-datetime/time-string.js +1 -1
- package/lib/whatwg/check-datetime/time-zone-offset-string.js +4 -4
- package/lib/whatwg/check-mime-type.js +1 -1
- package/lib/whatwg/check-mime-type.spec.js +3 -3
- package/package.json +4 -4
- package/src/css-syntax.spec.ts +1 -1
- package/src/defs.ts +4 -4
- package/src/{get-candicate.ts → get-candidate.ts} +6 -6
- package/src/list.spec.ts +4 -4
- package/src/number.ts +4 -4
- package/src/primitive/is-uint.ts +4 -4
- package/src/token/token-collection.spec.ts +2 -2
- package/src/token/token-collection.ts +113 -113
- package/src/token/token.ts +58 -58
- package/src/types.schema.ts +3 -0
- package/src/types.ts +2 -2
- package/src/whatwg/check-autocomplete.spec.ts +19 -10
- package/src/whatwg/check-autocomplete.ts +71 -15
- package/src/whatwg/check-datetime/datetime-tokens.ts +18 -18
- package/src/whatwg/check-datetime/global-date-and-time-string.ts +3 -3
- package/src/whatwg/check-datetime/local-date-and-time-string.ts +4 -4
- package/src/whatwg/check-datetime/time-string.ts +2 -2
- package/src/whatwg/check-datetime/time-zone-offset-string.ts +4 -4
- package/src/whatwg/check-mime-type.spec.ts +3 -3
- package/src/whatwg/check-mime-type.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/get-candicate.d.ts +0 -3
package/lib/token/token.js
CHANGED
|
@@ -11,6 +11,13 @@ class Token {
|
|
|
11
11
|
this.offset = offset;
|
|
12
12
|
tslib_1.__classPrivateFieldSet(this, _Token_originalValue, originalValue, "f");
|
|
13
13
|
}
|
|
14
|
+
static getCol(value, offset) {
|
|
15
|
+
const lines = value.slice(0, offset).split(/\n/g);
|
|
16
|
+
return lines[lines.length - 1].length + 1;
|
|
17
|
+
}
|
|
18
|
+
static getLine(value, offset) {
|
|
19
|
+
return value.slice(0, offset).split(/\n/g).length;
|
|
20
|
+
}
|
|
14
21
|
static getType(value, separators) {
|
|
15
22
|
if (Token.whitespace.includes(value[0])) {
|
|
16
23
|
return Token.WhiteSpace;
|
|
@@ -23,13 +30,6 @@ class Token {
|
|
|
23
30
|
}
|
|
24
31
|
return Token.Ident;
|
|
25
32
|
}
|
|
26
|
-
static getLine(value, offset) {
|
|
27
|
-
return value.slice(0, offset).split(/\n/g).length;
|
|
28
|
-
}
|
|
29
|
-
static getCol(value, offset) {
|
|
30
|
-
const lines = value.slice(0, offset).split(/\n/g);
|
|
31
|
-
return lines[lines.length - 1].length + 1;
|
|
32
|
-
}
|
|
33
33
|
static shiftLocation(token, offset) {
|
|
34
34
|
const shifted = token.offset + offset;
|
|
35
35
|
return {
|
|
@@ -44,32 +44,18 @@ class Token {
|
|
|
44
44
|
get origin() {
|
|
45
45
|
return tslib_1.__classPrivateFieldGet(this, _Token_originalValue, "f");
|
|
46
46
|
}
|
|
47
|
-
unmatched(options) {
|
|
48
|
-
var _a;
|
|
49
|
-
return {
|
|
50
|
-
...options,
|
|
51
|
-
matched: false,
|
|
52
|
-
ref: (options === null || options === void 0 ? void 0 : options.ref) || null,
|
|
53
|
-
raw: this.value,
|
|
54
|
-
offset: this.offset,
|
|
55
|
-
length: this.value.length,
|
|
56
|
-
line: Token.getLine(tslib_1.__classPrivateFieldGet(this, _Token_originalValue, "f"), this.offset),
|
|
57
|
-
column: Token.getCol(tslib_1.__classPrivateFieldGet(this, _Token_originalValue, "f"), this.offset),
|
|
58
|
-
reason: (_a = options === null || options === void 0 ? void 0 : options.reason) !== null && _a !== void 0 ? _a : 'syntax-error',
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
47
|
/**
|
|
62
48
|
*
|
|
63
49
|
* @param value The token value or the token type or its list
|
|
64
50
|
*/
|
|
65
|
-
|
|
51
|
+
includes(value, caseInsensitive) {
|
|
66
52
|
if (Array.isArray(value)) {
|
|
67
|
-
return value.some(v => this.
|
|
53
|
+
return value.some(v => this.includes(v));
|
|
68
54
|
}
|
|
69
55
|
if (typeof value === 'string') {
|
|
70
56
|
const a = caseInsensitive ? this.value.toLowerCase() : this.value;
|
|
71
57
|
const b = caseInsensitive ? value.toLowerCase() : value;
|
|
72
|
-
return a
|
|
58
|
+
return a.indexOf(b) !== -1;
|
|
73
59
|
}
|
|
74
60
|
if (value instanceof RegExp) {
|
|
75
61
|
const pattern = new RegExp(value, caseInsensitive ? 'i' : '');
|
|
@@ -81,14 +67,14 @@ class Token {
|
|
|
81
67
|
*
|
|
82
68
|
* @param value The token value or the token type or its list
|
|
83
69
|
*/
|
|
84
|
-
|
|
70
|
+
match(value, caseInsensitive) {
|
|
85
71
|
if (Array.isArray(value)) {
|
|
86
|
-
return value.some(v => this.
|
|
72
|
+
return value.some(v => this.match(v));
|
|
87
73
|
}
|
|
88
74
|
if (typeof value === 'string') {
|
|
89
75
|
const a = caseInsensitive ? this.value.toLowerCase() : this.value;
|
|
90
76
|
const b = caseInsensitive ? value.toLowerCase() : value;
|
|
91
|
-
return a
|
|
77
|
+
return a === b;
|
|
92
78
|
}
|
|
93
79
|
if (value instanceof RegExp) {
|
|
94
80
|
const pattern = new RegExp(value, caseInsensitive ? 'i' : '');
|
|
@@ -96,9 +82,6 @@ class Token {
|
|
|
96
82
|
}
|
|
97
83
|
return this.type === value;
|
|
98
84
|
}
|
|
99
|
-
toNumber() {
|
|
100
|
-
return parseFloat(this.value);
|
|
101
|
-
}
|
|
102
85
|
toJSON() {
|
|
103
86
|
return {
|
|
104
87
|
type: this.type,
|
|
@@ -106,9 +89,32 @@ class Token {
|
|
|
106
89
|
offset: this.offset,
|
|
107
90
|
};
|
|
108
91
|
}
|
|
92
|
+
toNumber() {
|
|
93
|
+
return parseFloat(this.value);
|
|
94
|
+
}
|
|
95
|
+
unmatched(options) {
|
|
96
|
+
var _a;
|
|
97
|
+
return {
|
|
98
|
+
...options,
|
|
99
|
+
matched: false,
|
|
100
|
+
ref: (options === null || options === void 0 ? void 0 : options.ref) || null,
|
|
101
|
+
raw: this.value,
|
|
102
|
+
offset: this.offset,
|
|
103
|
+
length: this.value.length,
|
|
104
|
+
line: Token.getLine(tslib_1.__classPrivateFieldGet(this, _Token_originalValue, "f"), this.offset),
|
|
105
|
+
column: Token.getCol(tslib_1.__classPrivateFieldGet(this, _Token_originalValue, "f"), this.offset),
|
|
106
|
+
reason: (_a = options === null || options === void 0 ? void 0 : options.reason) !== null && _a !== void 0 ? _a : 'syntax-error',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
109
|
}
|
|
110
110
|
exports.Token = Token;
|
|
111
111
|
_Token_originalValue = new WeakMap();
|
|
112
|
+
/**
|
|
113
|
+
* @see https://github.com/csstree/csstree/blob/master/lib/tokenizer/types.js
|
|
114
|
+
*/
|
|
115
|
+
Token.Comma = 18;
|
|
116
|
+
Token.Ident = 1;
|
|
117
|
+
Token.WhiteSpace = 13;
|
|
112
118
|
/**
|
|
113
119
|
* ASCII whitespace is
|
|
114
120
|
* - U+0009 TAB
|
|
@@ -120,9 +126,3 @@ _Token_originalValue = new WeakMap();
|
|
|
120
126
|
* @see https://infra.spec.whatwg.org/#ascii-whitespace
|
|
121
127
|
*/
|
|
122
128
|
Token.whitespace = ['\u0009', '\u000A', '\u000C', '\u000D', '\u0020'];
|
|
123
|
-
/**
|
|
124
|
-
* @see https://github.com/csstree/csstree/blob/master/lib/tokenizer/types.js
|
|
125
|
-
*/
|
|
126
|
-
Token.Ident = 1;
|
|
127
|
-
Token.WhiteSpace = 13;
|
|
128
|
-
Token.Comma = 18;
|
package/lib/types.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare type UnmatchedResultOptions = {
|
|
|
16
16
|
partName?: string;
|
|
17
17
|
expects?: Expect[];
|
|
18
18
|
extra?: Expect;
|
|
19
|
-
|
|
19
|
+
candidate?: string;
|
|
20
20
|
};
|
|
21
21
|
export declare type UnmatchedResultReason = 'syntax-error' | 'typo' | 'missing-token' | 'missing-comma' | 'unexpected-token' | 'unexpected-space' | 'unexpected-newline' | 'unexpected-comma' | 'empty-token' | 'out-of-range' | 'doesnt-exist-in-enum' | 'duplicated' | 'illegal-combination' | 'illegal-order' | 'extra-token' | 'must-be-percent-encoded' | 'must-be-serialized' | {
|
|
22
22
|
type: 'out-of-range';
|
|
@@ -37,7 +37,7 @@ export declare type MatchedResult = {
|
|
|
37
37
|
matched: true;
|
|
38
38
|
};
|
|
39
39
|
export declare type Expect = {
|
|
40
|
-
type: 'const' | 'format' | 'syntax' | '
|
|
40
|
+
type: 'const' | 'format' | 'syntax' | 'regexp' | 'common';
|
|
41
41
|
value: string;
|
|
42
42
|
};
|
|
43
43
|
export declare type FormattedPrimitiveTypeCheck = (value: string) => boolean;
|
package/lib/types.schema.d.ts
CHANGED
|
@@ -32,6 +32,9 @@ export interface List {
|
|
|
32
32
|
* [Enumerated attributes](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#enumerated-attribute)
|
|
33
33
|
*/
|
|
34
34
|
export interface Enum {
|
|
35
|
+
/**
|
|
36
|
+
* @minItems 1
|
|
37
|
+
*/
|
|
35
38
|
enum: [string, ...string[]];
|
|
36
39
|
disallowToSurroundBySpaces?: boolean;
|
|
37
40
|
caseInsensitive?: boolean;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkAutoComplete = void 0;
|
|
4
|
-
const
|
|
4
|
+
const debug_1 = require("../debug");
|
|
5
|
+
const get_candidate_1 = require("../get-candidate");
|
|
5
6
|
const match_result_1 = require("../match-result");
|
|
6
7
|
const token_1 = require("../token");
|
|
8
|
+
const acLog = debug_1.log.extend('autocomplete');
|
|
7
9
|
/**
|
|
8
10
|
* https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section
|
|
9
11
|
*/
|
|
@@ -80,7 +82,11 @@ const contactableFieldNames = [
|
|
|
80
82
|
'email',
|
|
81
83
|
'impp',
|
|
82
84
|
];
|
|
83
|
-
|
|
85
|
+
/**
|
|
86
|
+
* @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-webauthn
|
|
87
|
+
*/
|
|
88
|
+
const webauthnFieldNames = ['webauthn'];
|
|
89
|
+
const URL_AUTOCOMPLETE = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete';
|
|
84
90
|
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
91
|
const URL_NAMED_GROUP = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-section';
|
|
86
92
|
const URL_PART_OF_ADDRESS = 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-shipping';
|
|
@@ -107,13 +113,14 @@ const checkAutoComplete = () => value => {
|
|
|
107
113
|
value: 'autocomplete',
|
|
108
114
|
},
|
|
109
115
|
],
|
|
110
|
-
ref:
|
|
116
|
+
ref: URL_AUTOCOMPLETE,
|
|
111
117
|
});
|
|
112
118
|
if (!listingChecked.matched) {
|
|
119
|
+
acLog('Unmatch: %s', listingChecked.reason);
|
|
113
120
|
return listingChecked;
|
|
114
121
|
}
|
|
115
|
-
const
|
|
116
|
-
const headAndTail1 =
|
|
122
|
+
const identTokens = tokens.getIdentTokens();
|
|
123
|
+
const headAndTail1 = identTokens.headAndTail();
|
|
117
124
|
let { head, tail } = headAndTail1;
|
|
118
125
|
if (!head) {
|
|
119
126
|
// Never
|
|
@@ -126,6 +133,7 @@ const checkAutoComplete = () => value => {
|
|
|
126
133
|
// > (i.e. the "on" and "off" keywords are not allowed).
|
|
127
134
|
if (head.match(['on', 'off'], true)) {
|
|
128
135
|
if (tail.length) {
|
|
136
|
+
acLog('[Unmatched ("%s")] Unexpected pair with "on" or "off": "%s"', value, tail.value);
|
|
129
137
|
return tail[0].unmatched({
|
|
130
138
|
reason: 'extra-token',
|
|
131
139
|
expects: [
|
|
@@ -146,6 +154,7 @@ const checkAutoComplete = () => value => {
|
|
|
146
154
|
hasNamedGroup = true;
|
|
147
155
|
const sectionToken = tail.search(namedGroup);
|
|
148
156
|
if (sectionToken) {
|
|
157
|
+
acLog('[Unmatched ("%s")] Deprecated in autofill named group: "%s"', value, sectionToken.value);
|
|
149
158
|
return sectionToken.unmatched({
|
|
150
159
|
partName: 'autofill named group',
|
|
151
160
|
reason: 'duplicated',
|
|
@@ -168,6 +177,7 @@ const checkAutoComplete = () => value => {
|
|
|
168
177
|
hasPartOfAddress = true;
|
|
169
178
|
const partToken = tail.search(partOfAddress);
|
|
170
179
|
if (partToken) {
|
|
180
|
+
acLog('[Unmatched ("%s")] Duplicated values: "%s"', value, partToken.value);
|
|
171
181
|
return partToken.unmatched({
|
|
172
182
|
reason: 'duplicated',
|
|
173
183
|
expects: [
|
|
@@ -195,18 +205,29 @@ const checkAutoComplete = () => value => {
|
|
|
195
205
|
return (0, match_result_1.matched)();
|
|
196
206
|
}
|
|
197
207
|
if (!contactableFiledToken.match(contactableFieldNames, true)) {
|
|
198
|
-
const
|
|
208
|
+
const candidate = (0, get_candidate_1.getCandidate)(contactableFiledToken.value, contactableFieldNames);
|
|
209
|
+
acLog('[Unmatched ("%s")] Unexpected token: "%s"', value, contactableFiledToken.value);
|
|
199
210
|
return contactableFiledToken.unmatched({
|
|
200
211
|
reason: 'unexpected-token',
|
|
201
212
|
expects: contactableFieldNames.slice().map(token => ({
|
|
202
213
|
type: 'const',
|
|
203
214
|
value: token,
|
|
204
215
|
})),
|
|
205
|
-
|
|
216
|
+
candidate,
|
|
206
217
|
ref: URL_CONTACTABLE_FIELD,
|
|
207
218
|
});
|
|
208
219
|
}
|
|
209
220
|
if (tail[1]) {
|
|
221
|
+
if (tail[1].match(webauthnFieldNames)) {
|
|
222
|
+
return (0, match_result_1.matched)();
|
|
223
|
+
}
|
|
224
|
+
const candidate = (0, get_candidate_1.getCandidate)(tail[1].value, webauthnFieldNames);
|
|
225
|
+
if (candidate) {
|
|
226
|
+
acLog('[Unmatched ("%s")] Unnecessarily token: "%s", Do you mean "%s"? ', value, tail[1].value, candidate);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
acLog('[Unmatched ("%s")] Unnecessarily token: "%s"', value, tail[1].value);
|
|
230
|
+
}
|
|
210
231
|
return tail[1].unmatched({
|
|
211
232
|
reason: 'extra-token',
|
|
212
233
|
expects: [
|
|
@@ -222,6 +243,16 @@ const checkAutoComplete = () => value => {
|
|
|
222
243
|
}
|
|
223
244
|
if (head.match([...autofillFieldNames, ...contactableFieldNames], true)) {
|
|
224
245
|
if (tail.length) {
|
|
246
|
+
if (tail[0].match(webauthnFieldNames)) {
|
|
247
|
+
return (0, match_result_1.matched)();
|
|
248
|
+
}
|
|
249
|
+
const candidate = (0, get_candidate_1.getCandidate)(tail[0].value, webauthnFieldNames);
|
|
250
|
+
if (candidate) {
|
|
251
|
+
acLog('[Unmatched ("%s")] Unnecessarily token: "%s", Do you mean "%s"? ', value, tail[0].value, candidate);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
acLog('[Unmatched ("%s")] Unnecessarily token: "%s"', value, tail[0].value);
|
|
255
|
+
}
|
|
225
256
|
return tail[0].unmatched({
|
|
226
257
|
reason: 'extra-token',
|
|
227
258
|
expects: [
|
|
@@ -235,13 +266,16 @@ const checkAutoComplete = () => value => {
|
|
|
235
266
|
}
|
|
236
267
|
return (0, match_result_1.matched)();
|
|
237
268
|
}
|
|
269
|
+
if (head.match(webauthnFieldNames)) {
|
|
270
|
+
return (0, match_result_1.matched)();
|
|
271
|
+
}
|
|
238
272
|
const expects = [
|
|
239
273
|
{
|
|
240
274
|
type: 'common',
|
|
241
275
|
value: 'autofill field name',
|
|
242
276
|
},
|
|
243
277
|
];
|
|
244
|
-
let
|
|
278
|
+
let candidate;
|
|
245
279
|
if (!hasNamedGroup) {
|
|
246
280
|
expects.unshift({
|
|
247
281
|
type: 'common',
|
|
@@ -249,9 +283,9 @@ const checkAutoComplete = () => value => {
|
|
|
249
283
|
});
|
|
250
284
|
// Potentially typo a named group
|
|
251
285
|
const [prefix, namedGroupStr] = head.value.split('-');
|
|
252
|
-
const
|
|
253
|
-
if (
|
|
254
|
-
|
|
286
|
+
const candidatePrefix = (0, get_candidate_1.getCandidate)(prefix, 'section');
|
|
287
|
+
if (candidatePrefix) {
|
|
288
|
+
candidate = `${candidatePrefix}-${namedGroupStr || ''}`;
|
|
255
289
|
}
|
|
256
290
|
}
|
|
257
291
|
else if (!hasPartOfAddress) {
|
|
@@ -262,20 +296,26 @@ const checkAutoComplete = () => value => {
|
|
|
262
296
|
type: 'const',
|
|
263
297
|
value: token,
|
|
264
298
|
})));
|
|
265
|
-
|
|
299
|
+
candidate = (0, get_candidate_1.getCandidate)(head.value, partOfAddress, autofillFieldNames, contactingTokens, contactableFieldNames);
|
|
266
300
|
}
|
|
267
301
|
else if (!hasContactingToken) {
|
|
268
302
|
expects.push(...contactingTokens.slice().map(token => ({
|
|
269
303
|
type: 'const',
|
|
270
304
|
value: token,
|
|
271
305
|
})));
|
|
272
|
-
|
|
306
|
+
candidate = (0, get_candidate_1.getCandidate)(head.value, autofillFieldNames, contactingTokens, contactableFieldNames);
|
|
307
|
+
}
|
|
308
|
+
candidate = candidate || (0, get_candidate_1.getCandidate)(head.value, autofillFieldNames);
|
|
309
|
+
if (candidate) {
|
|
310
|
+
acLog('[Unmatched ("%s")] Unexpected token: "%s", Do you mean "%s"? ', value, head.value, candidate);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
acLog('[Unmatched ("%s")] Unexpected token: "%s"', value, head.value);
|
|
273
314
|
}
|
|
274
|
-
candicate = candicate || (0, get_candicate_1.getCandicate)(head.value, autofillFieldNames);
|
|
275
315
|
return head.unmatched({
|
|
276
316
|
reason: 'unexpected-token',
|
|
277
317
|
expects,
|
|
278
|
-
|
|
318
|
+
candidate,
|
|
279
319
|
ref: URL_AUTOFILL_FIELD,
|
|
280
320
|
});
|
|
281
321
|
};
|
|
@@ -2,28 +2,37 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const check_autocomplete_1 = require("./check-autocomplete");
|
|
4
4
|
const check = (0, check_autocomplete_1.checkAutoComplete)();
|
|
5
|
-
test('
|
|
5
|
+
test('basic', () => {
|
|
6
6
|
expect(check('on').matched).toBe(true);
|
|
7
|
+
expect(check('on webauthn').matched).toBe(false);
|
|
7
8
|
expect(check('off').matched).toBe(true);
|
|
9
|
+
expect(check('off webauthn').matched).toBe(false);
|
|
8
10
|
expect(check('name').matched).toBe(true);
|
|
9
11
|
expect(check('given-name').matched).toBe(true);
|
|
12
|
+
expect(check('given-name webauthn').matched).toBe(true);
|
|
13
|
+
expect(check('given-name webauthun').matched).toBe(false);
|
|
10
14
|
expect(check('section-').matched).toBe(true);
|
|
11
15
|
expect(check('section-foo').matched).toBe(true);
|
|
16
|
+
expect(check('section-foo webauthn').matched).toBe(true);
|
|
12
17
|
expect(check('section-foo name').matched).toBe(true);
|
|
18
|
+
expect(check('section-foo name webauthn').matched).toBe(true);
|
|
13
19
|
expect(check('section-foo shipping name').matched).toBe(true);
|
|
14
20
|
expect(check('section-foo billing name').matched).toBe(true);
|
|
15
21
|
expect(check('section-foo billing home').matched).toBe(true);
|
|
16
22
|
expect(check('section-foo billing work').matched).toBe(true);
|
|
17
23
|
expect(check('section-foo billing home tel').matched).toBe(true);
|
|
18
24
|
expect(check('section-foo billing work email').matched).toBe(true);
|
|
25
|
+
expect(check('section-foo billing work email webauthn').matched).toBe(true);
|
|
19
26
|
expect(check('shipping name').matched).toBe(true);
|
|
20
27
|
expect(check('billing name').matched).toBe(true);
|
|
21
28
|
expect(check('billing home').matched).toBe(true);
|
|
22
29
|
expect(check('billing work').matched).toBe(true);
|
|
23
30
|
expect(check('billing home tel').matched).toBe(true);
|
|
24
31
|
expect(check('billing work email').matched).toBe(true);
|
|
32
|
+
expect(check('billing work email webauthn').matched).toBe(true);
|
|
25
33
|
expect(check('home tel').matched).toBe(true);
|
|
26
34
|
expect(check('work email').matched).toBe(true);
|
|
35
|
+
expect(check('work email webauthn').matched).toBe(true);
|
|
27
36
|
});
|
|
28
37
|
test('unexpected-token', () => {
|
|
29
38
|
expect(check('section-foo , name')).toStrictEqual({
|
|
@@ -39,7 +48,7 @@ test('unexpected-token', () => {
|
|
|
39
48
|
{ type: 'const', value: 'shipping' },
|
|
40
49
|
{ type: 'common', value: 'autofill field name' },
|
|
41
50
|
],
|
|
42
|
-
|
|
51
|
+
candidate: undefined,
|
|
43
52
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
|
|
44
53
|
});
|
|
45
54
|
});
|
|
@@ -56,7 +65,7 @@ test('unexpected-token', () => {
|
|
|
56
65
|
{ type: 'common', value: 'autofill named group' },
|
|
57
66
|
{ type: 'common', value: 'autofill field name' },
|
|
58
67
|
],
|
|
59
|
-
|
|
68
|
+
candidate: undefined,
|
|
60
69
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
|
|
61
70
|
});
|
|
62
71
|
});
|
|
@@ -74,7 +83,7 @@ test('unexpected-token', () => {
|
|
|
74
83
|
{ type: 'const', value: 'shipping' },
|
|
75
84
|
{ type: 'common', value: 'autofill field name' },
|
|
76
85
|
],
|
|
77
|
-
|
|
86
|
+
candidate: 'name',
|
|
78
87
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
|
|
79
88
|
});
|
|
80
89
|
expect(check('section-foo shipping neme')).toStrictEqual({
|
|
@@ -93,12 +102,12 @@ test('unexpected-token', () => {
|
|
|
93
102
|
{ type: 'const', value: 'fax' },
|
|
94
103
|
{ type: 'const', value: 'pager' },
|
|
95
104
|
],
|
|
96
|
-
|
|
105
|
+
candidate: 'name',
|
|
97
106
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
|
|
98
107
|
});
|
|
99
|
-
expect(check('section-foo shipping home
|
|
108
|
+
expect(check('section-foo shipping home name')).toStrictEqual({
|
|
100
109
|
matched: false,
|
|
101
|
-
raw: '
|
|
110
|
+
raw: 'name',
|
|
102
111
|
offset: 26,
|
|
103
112
|
length: 4,
|
|
104
113
|
line: 1,
|
|
@@ -116,7 +125,7 @@ test('unexpected-token', () => {
|
|
|
116
125
|
{ type: 'const', value: 'email' },
|
|
117
126
|
{ type: 'const', value: 'impp' },
|
|
118
127
|
],
|
|
119
|
-
|
|
128
|
+
candidate: undefined,
|
|
120
129
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-tel',
|
|
121
130
|
});
|
|
122
131
|
expect(check('section-foo shipping home emall')).toStrictEqual({
|
|
@@ -139,7 +148,7 @@ test('unexpected-token', () => {
|
|
|
139
148
|
{ type: 'const', value: 'email' },
|
|
140
149
|
{ type: 'const', value: 'impp' },
|
|
141
150
|
],
|
|
142
|
-
|
|
151
|
+
candidate: 'email',
|
|
143
152
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute:attr-fe-autocomplete-tel',
|
|
144
153
|
});
|
|
145
154
|
});
|
|
@@ -364,7 +373,7 @@ test('typo', () => {
|
|
|
364
373
|
{ type: 'common', value: 'autofill named group' },
|
|
365
374
|
{ type: 'common', value: 'autofill field name' },
|
|
366
375
|
],
|
|
367
|
-
|
|
376
|
+
candidate: 'section-foo',
|
|
368
377
|
ref: 'https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field',
|
|
369
378
|
});
|
|
370
379
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { TokenEachCheck } from '../../token/token-collection';
|
|
2
|
-
export declare const datetimeTokenCheck: Record<'year' | 'month' | 'date' | 'hour' | 'minute' | 'second' | 'secondFractionalPart' | 'week' | 'hyphen' | '
|
|
2
|
+
export declare const datetimeTokenCheck: Record<'year' | 'month' | 'date' | 'hour' | 'minute' | 'second' | 'secondFractionalPart' | 'week' | 'hyphen' | 'colon' | 'extra' | 'colonOrEnd' | 'decimalPointOrEnd' | 'localDateTimeSeparator' | 'normalizedlocalDateTimeSeparator' | 'plusOrMinusSign' | 'weekSign', TokenEachCheck> & Record<'_year' | '_month', number | null>;
|
|
3
3
|
export declare function getMaxWeekNum(year: number): number;
|
|
@@ -317,18 +317,18 @@ exports.datetimeTokenCheck = {
|
|
|
317
317
|
/**
|
|
318
318
|
* > A U+003A COLON character (:)
|
|
319
319
|
*/
|
|
320
|
-
|
|
321
|
-
(0, debug_1.log)('Parsing Datetime
|
|
322
|
-
if (!
|
|
320
|
+
colon(colon) {
|
|
321
|
+
(0, debug_1.log)('Parsing Datetime colon: "%s"', colon === null || colon === void 0 ? void 0 : colon.value);
|
|
322
|
+
if (!colon || !colon.value) {
|
|
323
323
|
return (0, match_result_1.unmatched)('', 'missing-token', {
|
|
324
|
-
expects: [{ type: 'common', value: '
|
|
324
|
+
expects: [{ type: 'common', value: 'colon' }],
|
|
325
325
|
partName: 'time',
|
|
326
326
|
});
|
|
327
327
|
}
|
|
328
|
-
if (!
|
|
329
|
-
return
|
|
328
|
+
if (!colon.match(':')) {
|
|
329
|
+
return colon.unmatched({
|
|
330
330
|
reason: 'unexpected-token',
|
|
331
|
-
expects: [{ type: 'common', value: '
|
|
331
|
+
expects: [{ type: 'common', value: 'colon' }],
|
|
332
332
|
partName: 'time',
|
|
333
333
|
});
|
|
334
334
|
}
|
|
@@ -338,14 +338,14 @@ exports.datetimeTokenCheck = {
|
|
|
338
338
|
* or
|
|
339
339
|
* End of token
|
|
340
340
|
*/
|
|
341
|
-
|
|
342
|
-
if (!
|
|
341
|
+
colonOrEnd(colon) {
|
|
342
|
+
if (!colon || !colon.value) {
|
|
343
343
|
return (0, match_result_1.matched)();
|
|
344
344
|
}
|
|
345
|
-
if (!
|
|
346
|
-
return
|
|
345
|
+
if (!colon.match(':')) {
|
|
346
|
+
return colon.unmatched({
|
|
347
347
|
reason: 'unexpected-token',
|
|
348
|
-
expects: [{ type: 'common', value: '
|
|
348
|
+
expects: [{ type: 'common', value: 'colon' }],
|
|
349
349
|
partName: 'time',
|
|
350
350
|
});
|
|
351
351
|
}
|
|
@@ -413,8 +413,8 @@ exports.datetimeTokenCheck = {
|
|
|
413
413
|
* > a U+002D HYPHEN-MINUS character (-),
|
|
414
414
|
* > representing the sign of the time-zone offset
|
|
415
415
|
*/
|
|
416
|
-
plusOrMinusSign(
|
|
417
|
-
if (!
|
|
416
|
+
plusOrMinusSign(colon) {
|
|
417
|
+
if (!colon) {
|
|
418
418
|
return (0, match_result_1.unmatched)('', 'missing-token', {
|
|
419
419
|
expects: [
|
|
420
420
|
{ type: 'const', value: '+' },
|
|
@@ -423,8 +423,8 @@ exports.datetimeTokenCheck = {
|
|
|
423
423
|
partName: 'time-zone',
|
|
424
424
|
});
|
|
425
425
|
}
|
|
426
|
-
if (!
|
|
427
|
-
return
|
|
426
|
+
if (!colon.match(['+', '-'])) {
|
|
427
|
+
return colon.unmatched({
|
|
428
428
|
reason: 'unexpected-token',
|
|
429
429
|
expects: [
|
|
430
430
|
{ type: 'const', value: '+' },
|
|
@@ -36,13 +36,13 @@ const checkGlobalDateAndTimeString = () => function checkGlobalDateAndTimeString
|
|
|
36
36
|
/.*/,
|
|
37
37
|
]);
|
|
38
38
|
(0, debug_1.log)('Global Date and Time "%s" => %O', tokens.value, tokens);
|
|
39
|
-
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.year, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.month, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.date, datetime_tokens_1.datetimeTokenCheck.localDateTimeSeparator, datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.
|
|
39
|
+
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.year, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.month, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.date, datetime_tokens_1.datetimeTokenCheck.localDateTimeSeparator, datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.colon, datetime_tokens_1.datetimeTokenCheck.minute, second => {
|
|
40
40
|
if (!second || !second.value) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
const secondTokens = token_1.TokenCollection.fromPatterns(second, [/:?/, /[0-9]*/, /\.?/, /[0-9]*/]);
|
|
44
|
-
(0, debug_1.log)('
|
|
45
|
-
const res = secondTokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.
|
|
44
|
+
(0, debug_1.log)('Second Part: "%s" => %O', secondTokens.value, secondTokens);
|
|
45
|
+
const res = secondTokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.colon, datetime_tokens_1.datetimeTokenCheck.second, datetime_tokens_1.datetimeTokenCheck.decimalPointOrEnd, datetime_tokens_1.datetimeTokenCheck.secondFractionalPart);
|
|
46
46
|
if (!res.matched) {
|
|
47
47
|
return res;
|
|
48
48
|
}
|
|
@@ -38,7 +38,7 @@ const checkLocalDateAndTimeString = () => function checkLocalDateAndTimeString(v
|
|
|
38
38
|
/.[0-9]*/,
|
|
39
39
|
]);
|
|
40
40
|
(0, debug_1.log)('Local Date and Time: "%s" => %O', tokens.value, tokens);
|
|
41
|
-
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.year, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.month, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.date, datetime_tokens_1.datetimeTokenCheck.localDateTimeSeparator, datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.
|
|
41
|
+
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.year, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.month, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.date, datetime_tokens_1.datetimeTokenCheck.localDateTimeSeparator, datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.colon, datetime_tokens_1.datetimeTokenCheck.minute, datetime_tokens_1.datetimeTokenCheck.colonOrEnd, datetime_tokens_1.datetimeTokenCheck.second, datetime_tokens_1.datetimeTokenCheck.decimalPointOrEnd, datetime_tokens_1.datetimeTokenCheck.secondFractionalPart, datetime_tokens_1.datetimeTokenCheck.extra);
|
|
42
42
|
if (!res.matched) {
|
|
43
43
|
(0, debug_1.log)('Failed: %O', res);
|
|
44
44
|
}
|
|
@@ -79,7 +79,7 @@ const checkNormalizedLocalDateAndTimeString = () => function checkNormalizedLoca
|
|
|
79
79
|
/.[0-9]*/,
|
|
80
80
|
]);
|
|
81
81
|
(0, debug_1.log)('Normalized Local Date and Time: "%s" => %O', tokens.value, tokens);
|
|
82
|
-
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.year, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.month, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.date, datetime_tokens_1.datetimeTokenCheck.normalizedlocalDateTimeSeparator, datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.
|
|
82
|
+
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.year, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.month, datetime_tokens_1.datetimeTokenCheck.hyphen, datetime_tokens_1.datetimeTokenCheck.date, datetime_tokens_1.datetimeTokenCheck.normalizedlocalDateTimeSeparator, datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.colon, datetime_tokens_1.datetimeTokenCheck.minute, datetime_tokens_1.datetimeTokenCheck.colonOrEnd, datetime_tokens_1.datetimeTokenCheck.second, datetime_tokens_1.datetimeTokenCheck.decimalPointOrEnd, datetime_tokens_1.datetimeTokenCheck.secondFractionalPart, datetime_tokens_1.datetimeTokenCheck.extra);
|
|
83
83
|
if (!res.matched) {
|
|
84
84
|
(0, debug_1.log)('Failed: %O', res);
|
|
85
85
|
return res;
|
|
@@ -26,7 +26,7 @@ const checkTimeString = () => function checkTimeString(value) {
|
|
|
26
26
|
/.[0-9]*/,
|
|
27
27
|
]);
|
|
28
28
|
(0, debug_1.log)('Time: "%s" => %O', tokens.value, tokens);
|
|
29
|
-
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.
|
|
29
|
+
const res = tokens.eachCheck(datetime_tokens_1.datetimeTokenCheck.hour, datetime_tokens_1.datetimeTokenCheck.colon, datetime_tokens_1.datetimeTokenCheck.minute, datetime_tokens_1.datetimeTokenCheck.colonOrEnd, datetime_tokens_1.datetimeTokenCheck.second, datetime_tokens_1.datetimeTokenCheck.decimalPointOrEnd, datetime_tokens_1.datetimeTokenCheck.secondFractionalPart);
|
|
30
30
|
if (!res.matched) {
|
|
31
31
|
(0, debug_1.log)('Failed: %O', res);
|
|
32
32
|
}
|
|
@@ -55,12 +55,12 @@ function parseTimeZone(zone) {
|
|
|
55
55
|
partName: 'time-zone',
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
}, datetime_tokens_1.datetimeTokenCheck.hour,
|
|
59
|
-
if (!
|
|
58
|
+
}, datetime_tokens_1.datetimeTokenCheck.hour, colon => {
|
|
59
|
+
if (!colon || !colon.value) {
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
|
-
if (!
|
|
63
|
-
return
|
|
62
|
+
if (!colon.match(':')) {
|
|
63
|
+
return colon.unmatched({
|
|
64
64
|
reason: 'unexpected-token',
|
|
65
65
|
expects: [{ type: 'const', value: ':' }],
|
|
66
66
|
partName: 'time-zone',
|
|
@@ -34,7 +34,7 @@ const checkMIMEType = options => value => {
|
|
|
34
34
|
return new token_1.Token(extraToken, mimeType.essence.length, value).unmatched({
|
|
35
35
|
reason: 'extra-token',
|
|
36
36
|
expects: expects(withoutParameters),
|
|
37
|
-
|
|
37
|
+
candidate: mimeType.essence,
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
return (0, match_result_1.unmatched)(value, 'syntax-error', { expects: expects(withoutParameters) });
|
|
@@ -20,7 +20,7 @@ test('excrescence-token', () => {
|
|
|
20
20
|
ref: null,
|
|
21
21
|
});
|
|
22
22
|
expect(check('x/y;')).toStrictEqual({
|
|
23
|
-
|
|
23
|
+
candidate: 'x/y',
|
|
24
24
|
column: 4,
|
|
25
25
|
expects: [{ type: 'format', value: 'MIME Type' }],
|
|
26
26
|
length: 1,
|
|
@@ -32,7 +32,7 @@ test('excrescence-token', () => {
|
|
|
32
32
|
ref: null,
|
|
33
33
|
});
|
|
34
34
|
expect(checkNoParam('x/y;')).toStrictEqual({
|
|
35
|
-
|
|
35
|
+
candidate: 'x/y',
|
|
36
36
|
column: 4,
|
|
37
37
|
expects: [{ type: 'format', value: 'MIME Type with no parameters' }],
|
|
38
38
|
length: 1,
|
|
@@ -44,7 +44,7 @@ test('excrescence-token', () => {
|
|
|
44
44
|
ref: null,
|
|
45
45
|
});
|
|
46
46
|
expect(checkNoParam('x/y;a=b;c=D;E="F"')).toStrictEqual({
|
|
47
|
-
|
|
47
|
+
candidate: 'x/y',
|
|
48
48
|
column: 4,
|
|
49
49
|
expects: [{ type: 'format', value: 'MIME Type with no parameters' }],
|
|
50
50
|
length: 14,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/types",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.2",
|
|
4
4
|
"description": "Types of attributes and properties and more",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/bcp-47": "1",
|
|
28
|
-
"@types/css-tree": "
|
|
28
|
+
"@types/css-tree": "1",
|
|
29
29
|
"@types/debug": "^4.1.7",
|
|
30
|
-
"@types/whatwg-mimetype": "
|
|
30
|
+
"@types/whatwg-mimetype": "2"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "830bf8187b81bf5ca2f5f09b6f85a98395a58bdb"
|
|
33
33
|
}
|