@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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/lib/css-syntax.spec.js +1 -1
  3. package/lib/defs.js +4 -4
  4. package/lib/get-candidate.d.ts +3 -0
  5. package/lib/{get-candicate.js → get-candidate.js} +8 -8
  6. package/lib/list.spec.js +4 -4
  7. package/lib/number.js +4 -4
  8. package/lib/primitive/is-uint.d.ts +1 -1
  9. package/lib/primitive/is-uint.js +4 -4
  10. package/lib/token/token-collection.d.ts +21 -21
  11. package/lib/token/token-collection.js +101 -101
  12. package/lib/token/token-collection.spec.js +2 -2
  13. package/lib/token/token.d.ts +22 -22
  14. package/lib/token/token.js +36 -36
  15. package/lib/types.d.ts +2 -2
  16. package/lib/types.schema.d.ts +3 -0
  17. package/lib/whatwg/check-autocomplete.js +55 -15
  18. package/lib/whatwg/check-autocomplete.spec.js +19 -10
  19. package/lib/whatwg/check-datetime/datetime-tokens.d.ts +1 -1
  20. package/lib/whatwg/check-datetime/datetime-tokens.js +16 -16
  21. package/lib/whatwg/check-datetime/global-date-and-time-string.js +3 -3
  22. package/lib/whatwg/check-datetime/local-date-and-time-string.js +2 -2
  23. package/lib/whatwg/check-datetime/time-string.js +1 -1
  24. package/lib/whatwg/check-datetime/time-zone-offset-string.js +4 -4
  25. package/lib/whatwg/check-mime-type.js +1 -1
  26. package/lib/whatwg/check-mime-type.spec.js +3 -3
  27. package/package.json +4 -4
  28. package/src/css-syntax.spec.ts +1 -1
  29. package/src/defs.ts +4 -4
  30. package/src/{get-candicate.ts → get-candidate.ts} +6 -6
  31. package/src/list.spec.ts +4 -4
  32. package/src/number.ts +4 -4
  33. package/src/primitive/is-uint.ts +4 -4
  34. package/src/token/token-collection.spec.ts +2 -2
  35. package/src/token/token-collection.ts +113 -113
  36. package/src/token/token.ts +58 -58
  37. package/src/types.schema.ts +3 -0
  38. package/src/types.ts +2 -2
  39. package/src/whatwg/check-autocomplete.spec.ts +19 -10
  40. package/src/whatwg/check-autocomplete.ts +71 -15
  41. package/src/whatwg/check-datetime/datetime-tokens.ts +18 -18
  42. package/src/whatwg/check-datetime/global-date-and-time-string.ts +3 -3
  43. package/src/whatwg/check-datetime/local-date-and-time-string.ts +4 -4
  44. package/src/whatwg/check-datetime/time-string.ts +2 -2
  45. package/src/whatwg/check-datetime/time-zone-offset-string.ts +4 -4
  46. package/src/whatwg/check-mime-type.spec.ts +3 -3
  47. package/src/whatwg/check-mime-type.ts +1 -1
  48. package/tsconfig.tsbuildinfo +1 -1
  49. package/lib/get-candicate.d.ts +0 -3
@@ -116,7 +116,7 @@ test('custom-type-checking', () => {
116
116
  expect(cssSyntaxMatch('0', custom).matched).toBe(false);
117
117
  });
118
118
 
119
- test('case-sensivite', () => {
119
+ test('case-sensitive', () => {
120
120
  const custom: CustomCssSyntax = {
121
121
  ref: 'n/a',
122
122
  caseSensitive: true,
package/src/defs.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Defs, CssSyntaxTokenizer } from './types';
2
2
 
3
3
  import { checkMultiTypes } from './check-multi-types';
4
- import { getCandicate } from './get-candicate';
4
+ import { getCandidate } from './get-candidate';
5
5
  import { matched, matches, unmatched } from './match-result';
6
6
  import { splitUnit, isFloat, isUint, isInt } from './primitive';
7
7
  import { isBCP47 } from './rfc/is-bcp-47';
@@ -295,8 +295,8 @@ export const types: Defs = {
295
295
  return matched();
296
296
  }
297
297
  if (value[0] === '_') {
298
- const candicate = getCandicate(value, keywords);
299
- return unmatched(value, 'unexpected-token', { candicate });
298
+ const candidate = getCandidate(value, keywords);
299
+ return unmatched(value, 'unexpected-token', { candidate });
300
300
  }
301
301
  return matches(isBrowserContextName())(value);
302
302
  },
@@ -446,7 +446,7 @@ export const types: Defs = {
446
446
  if (value === 'any') {
447
447
  return matched();
448
448
  }
449
- const tokens = new TokenCollection(value, { speificSeparator: 'x' });
449
+ const tokens = new TokenCollection(value, { specificSeparator: 'x' });
450
450
  const [width, sep, height, ...tail] = tokens;
451
451
  if (!width) {
452
452
  return unmatched(value, 'unexpected-token');
@@ -2,23 +2,23 @@ import leven from 'leven';
2
2
 
3
3
  type NullableString = string | null | undefined;
4
4
 
5
- export function getCandicate(value: NullableString, ...candicates: (NullableString | NullableString[])[]) {
5
+ export function getCandidate(value: NullableString, ...candidates: (NullableString | NullableString[])[]) {
6
6
  if (!value) {
7
7
  return;
8
8
  }
9
- const list = candicates.flat(2).filter((s): s is string => !!s);
10
- let candicate: string | undefined;
9
+ const list = candidates.flat(2).filter((s): s is string => !!s);
10
+ let candidate: string | undefined;
11
11
  let maxRatio = 0;
12
12
  list.forEach(word => {
13
13
  const dist = leven(value.trim().toLowerCase(), word.trim().toLowerCase());
14
14
  const ratio = 1 - dist / word.length;
15
15
  if (0.5 <= ratio && maxRatio < ratio) {
16
- candicate = word;
16
+ candidate = word;
17
17
  }
18
18
  maxRatio = Math.max(ratio, maxRatio);
19
19
  });
20
- if (value === candicate) {
20
+ if (value === candidate) {
21
21
  return;
22
22
  }
23
- return candicate;
23
+ return candidate;
24
24
  }
package/src/list.spec.ts CHANGED
@@ -50,7 +50,7 @@ test('Zero comma (disallowToSurroundBySpaces)', () => {
50
50
  test('Location of the token', () => {
51
51
  const type = { token: 'Accept', separator: 'comma' } as const;
52
52
  expect(checkList('x/y;a=b', type)).toStrictEqual({
53
- candicate: 'x/y',
53
+ candidate: 'x/y',
54
54
  column: 4,
55
55
  expects: [{ type: 'format', value: 'MIME Type with no parameters' }],
56
56
  length: 4,
@@ -63,7 +63,7 @@ test('Location of the token', () => {
63
63
  ref: 'https://html.spec.whatwg.org/multipage/input.html#attr-input-accept',
64
64
  });
65
65
  expect(checkList('x/y,x/y;a=b', type)).toStrictEqual({
66
- candicate: 'x/y',
66
+ candidate: 'x/y',
67
67
  column: 8,
68
68
  expects: [{ type: 'format', value: 'MIME Type with no parameters' }],
69
69
  length: 4,
@@ -76,7 +76,7 @@ test('Location of the token', () => {
76
76
  ref: 'https://html.spec.whatwg.org/multipage/input.html#attr-input-accept',
77
77
  });
78
78
  expect(checkList('x/y\n,\nx/y;a=b', type)).toStrictEqual({
79
- candicate: 'x/y',
79
+ candidate: 'x/y',
80
80
  column: 4,
81
81
  expects: [{ type: 'format', value: 'MIME Type with no parameters' }],
82
82
  length: 4,
@@ -120,7 +120,7 @@ test('Missing comma', () => {
120
120
  const type = { token: 'Accept', separator: 'comma' } as const;
121
121
  expect(checkList('a/b,x/y a/z', type)).toStrictEqual({
122
122
  column: 9,
123
- candicate: ',a/z',
123
+ candidate: ',a/z',
124
124
  expects: undefined,
125
125
  length: 3,
126
126
  line: 1,
package/src/number.ts CHANGED
@@ -20,25 +20,25 @@ export function checkNumber(value: string, type: Number, ref?: string): Result {
20
20
 
21
21
  if (type.gt != null && n <= type.gt) {
22
22
  return unmatched(value, 'out-of-range', {
23
- candicate: clampable && isInt ? `${type.gt + 1}` : undefined,
23
+ candidate: clampable && isInt ? `${type.gt + 1}` : undefined,
24
24
  });
25
25
  }
26
26
 
27
27
  if (type.gte != null && n < type.gte) {
28
28
  return unmatched(value, 'out-of-range', {
29
- candicate: clampable ? `${type.gte}` : undefined,
29
+ candidate: clampable ? `${type.gte}` : undefined,
30
30
  });
31
31
  }
32
32
 
33
33
  if (type.lt != null && type.lt <= n) {
34
34
  return unmatched(value, 'out-of-range', {
35
- candicate: clampable && isInt ? `${type.lt - 1}` : undefined,
35
+ candidate: clampable && isInt ? `${type.lt - 1}` : undefined,
36
36
  });
37
37
  }
38
38
 
39
39
  if (type.lte != null && type.lte < n) {
40
40
  return unmatched(value, 'out-of-range', {
41
- candicate: clampable ? `${type.lte}` : undefined,
41
+ candidate: clampable ? `${type.lte}` : undefined,
42
42
  });
43
43
  }
44
44
  }
@@ -3,12 +3,12 @@
3
3
  *
4
4
  * @param value
5
5
  */
6
- export function isUint(value: string, opions?: { gt?: number }) {
6
+ export function isUint(value: string, options?: { gt?: number }) {
7
7
  const matched = /^[0-9]+$/.test(value);
8
- if (matched && opions) {
8
+ if (matched && options) {
9
9
  const n = parseInt(value, 10);
10
- if (opions.gt != null) {
11
- return isFinite(n) && opions.gt < n;
10
+ if (options.gt != null) {
11
+ return isFinite(n) && options.gt < n;
12
12
  }
13
13
  }
14
14
  return matched;
@@ -42,7 +42,7 @@ test('parse', () => {
42
42
  ]);
43
43
  });
44
44
 
45
- test('parse camma separator', () => {
45
+ test('parse comma separator', () => {
46
46
  expect(new TokenCollection('a,, ,b,cde', { separator: 'comma' }).toJSON()).toStrictEqual([
47
47
  {
48
48
  offset: 0,
@@ -87,7 +87,7 @@ test('parse camma separator', () => {
87
87
  ]);
88
88
  });
89
89
 
90
- test('A camma is an ident if the comma is not a separator', () => {
90
+ test('A comma is an ident if the comma is not a separator', () => {
91
91
  expect(new TokenCollection('a ,cde , f').toJSON()).toStrictEqual([
92
92
  {
93
93
  offset: 0,
@@ -7,23 +7,17 @@ import { Token } from './token';
7
7
 
8
8
  type TokenCollectionOptions = Partial<
9
9
  Omit<List, 'token'> & {
10
- speificSeparator: string | string[];
10
+ specificSeparator: string | string[];
11
11
  }
12
12
  >;
13
13
 
14
14
  export type TokenEachCheck = (head: Token | null, tail: TokenCollection) => Result | void;
15
15
 
16
16
  export class TokenCollection extends Array<Token> {
17
- private static _new(tokens: Token[], old?: TokenCollection) {
18
- const newCollection = new TokenCollection('', old);
19
- newCollection.push(...tokens);
20
- return newCollection;
21
- }
22
-
23
17
  static fromPatterns(
24
18
  value: Token | string,
25
19
  patterns: RegExp[],
26
- typeOptions?: Omit<TokenCollectionOptions, 'speificSeparator'> & { repeat?: boolean },
20
+ typeOptions?: Omit<TokenCollectionOptions, 'specificSeparator'> & { repeat?: boolean },
27
21
  ) {
28
22
  const origin = typeof value === 'string' ? value : value.origin;
29
23
  let strings = typeof value === 'string' ? value : value.value;
@@ -40,15 +34,15 @@ export class TokenCollection extends Array<Token> {
40
34
  return token;
41
35
  }
42
36
 
43
- let isBreaked = false;
37
+ let isBroken = false;
44
38
  do {
45
- isBreaked = false;
39
+ isBroken = false;
46
40
  for (const pattern of patterns) {
47
41
  const res = pattern.exec(strings);
48
42
  let value: string;
49
43
 
50
44
  if (!res) {
51
- isBreaked = true;
45
+ isBroken = true;
52
46
  value = '';
53
47
  } else {
54
48
  if (res.index !== 0) {
@@ -63,7 +57,7 @@ export class TokenCollection extends Array<Token> {
63
57
  // @ts-ignore
64
58
  token._ = pattern;
65
59
  }
66
- if (isBreaked) {
60
+ if (isBroken) {
67
61
  addToken(strings);
68
62
  }
69
63
  } while (typeOptions?.repeat && strings);
@@ -79,13 +73,13 @@ export class TokenCollection extends Array<Token> {
79
73
  return Array;
80
74
  }
81
75
 
82
- readonly disallowToSurroundBySpaces: NonNullable<List['disallowToSurroundBySpaces']>;
83
76
  readonly allowEmpty: NonNullable<List['allowEmpty']>;
84
- readonly ordered: NonNullable<List['ordered']>;
85
- readonly unique: NonNullable<List['unique']>;
86
77
  readonly caseInsensitive: NonNullable<List['caseInsensitive']>;
78
+ readonly disallowToSurroundBySpaces: NonNullable<List['disallowToSurroundBySpaces']>;
87
79
  readonly number: List['number'];
80
+ readonly ordered: NonNullable<List['ordered']>;
88
81
  readonly separator: NonNullable<List['separator']>;
82
+ readonly unique: NonNullable<List['unique']>;
89
83
 
90
84
  constructor(value?: string, typeOptions?: TokenCollectionOptions);
91
85
  constructor(value?: number); // for map method etc.
@@ -114,11 +108,11 @@ export class TokenCollection extends Array<Token> {
114
108
  separators.push(',');
115
109
  }
116
110
 
117
- if (typeOptions?.speificSeparator) {
118
- if (Array.isArray(typeOptions.speificSeparator)) {
119
- separators.push(...typeOptions.speificSeparator);
111
+ if (typeOptions?.specificSeparator) {
112
+ if (Array.isArray(typeOptions.specificSeparator)) {
113
+ separators.push(...typeOptions.specificSeparator);
120
114
  } else {
121
- separators.push(typeOptions.speificSeparator);
115
+ separators.push(typeOptions.specificSeparator);
122
116
  }
123
117
  }
124
118
 
@@ -158,62 +152,6 @@ export class TokenCollection extends Array<Token> {
158
152
  return value;
159
153
  }
160
154
 
161
- filter(callback: (value: Token, index: number, array: Token[]) => boolean) {
162
- return TokenCollection._new(super.filter(callback), this);
163
- }
164
-
165
- headAndTail(): { head: Token | null; tail: TokenCollection } {
166
- const copy = this.slice();
167
- const head = copy.shift();
168
- if (!head) {
169
- return { head: head || null, tail: TokenCollection._new([], this) };
170
- }
171
- const tail = TokenCollection._new(copy, this);
172
- return { head, tail };
173
- }
174
-
175
- getIdentTokens() {
176
- return this.filter(token => token.type === Token.Ident);
177
- }
178
-
179
- compareTokens(callback: (prev: Token, current: Token) => Token | null | void) {
180
- const _tokens = this.slice();
181
- let prev = _tokens.shift();
182
- while (prev) {
183
- const current = _tokens.shift();
184
- if (!current) {
185
- return;
186
- }
187
- const result = callback(prev, current);
188
- if (result) {
189
- return result;
190
- }
191
- prev = current;
192
- }
193
- return null;
194
- }
195
-
196
- /**
197
- *
198
- * @param value The token value or the token type or its list
199
- */
200
- has(value: string | RegExp | number | (string | RegExp | number)[]) {
201
- return this.some(t => t.match(value));
202
- }
203
-
204
- /**
205
- *
206
- * @param value The token value or the token type or its list
207
- */
208
- search(value: string | RegExp | number | (string | RegExp | number)[]) {
209
- for (const token of this) {
210
- if (token.includes(value)) {
211
- return token;
212
- }
213
- }
214
- return null;
215
- }
216
-
217
155
  check(options: { expects?: Expect[]; ref?: string; cache?: boolean } = {}) {
218
156
  const { expects, ref } = options;
219
157
 
@@ -268,7 +206,7 @@ export class TokenCollection extends Array<Token> {
268
206
  reason: 'missing-comma',
269
207
  ref,
270
208
  expects,
271
- candicate: `,${takeTurnsError.token.value}`,
209
+ candidate: `,${takeTurnsError.token.value}`,
272
210
  });
273
211
  }
274
212
  }
@@ -298,38 +236,42 @@ export class TokenCollection extends Array<Token> {
298
236
  return matched();
299
237
  }
300
238
 
301
- getConsecutiveToken(tokenType: number) {
302
- const resultToken = this.compareTokens((prev, current) => {
303
- if (prev.type === tokenType && current.type === tokenType) {
304
- return current;
305
- }
306
- });
307
- return resultToken || null;
239
+ chunk(split: number) {
240
+ const chunks: TokenCollection[] = [];
241
+ const tokens = this.slice();
242
+ while (tokens.length) {
243
+ const chunkTokens = tokens.splice(0, split);
244
+ const chunk = TokenCollection._new(chunkTokens, this);
245
+ chunks.push(chunk);
246
+ }
247
+ return chunks;
308
248
  }
309
249
 
310
- takeTurns(tokenNumbers: ReadonlyArray<number>, lastTokenNumber?: number) {
311
- const tokens = this.slice();
312
- for (let i = 0; i < tokens.length; i++) {
313
- const token = tokens[i];
314
- const expectedTokenNumber = tokenNumbers[i % tokenNumbers.length];
315
- if (token.type !== expectedTokenNumber) {
316
- return {
317
- unexpectedLastToken: false,
318
- expectedTokenNumber,
319
- token,
320
- };
250
+ compareTokens(callback: (prev: Token, current: Token) => Token | null | void) {
251
+ const _tokens = this.slice();
252
+ let prev = _tokens.shift();
253
+ while (prev) {
254
+ const current = _tokens.shift();
255
+ if (!current) {
256
+ return;
321
257
  }
322
- if (lastTokenNumber != null && i === tokens.length - 1 && token.type !== lastTokenNumber) {
323
- return {
324
- unexpectedLastToken: true,
325
- expectedTokenNumber,
326
- token,
327
- };
258
+ const result = callback(prev, current);
259
+ if (result) {
260
+ return result;
328
261
  }
262
+ prev = current;
329
263
  }
330
264
  return null;
331
265
  }
332
266
 
267
+ divide(position: number) {
268
+ const _a = this.slice(0, position);
269
+ const _b = this.slice(position);
270
+ const a = TokenCollection._new(_a, this);
271
+ const b = TokenCollection._new(_b, this);
272
+ return [a, b] as const;
273
+ }
274
+
333
275
  eachCheck(...callbacks: TokenEachCheck[]): Result {
334
276
  let headAndTail = this.headAndTail();
335
277
  let head = headAndTail.head;
@@ -397,6 +339,19 @@ export class TokenCollection extends Array<Token> {
397
339
  return matched();
398
340
  }
399
341
 
342
+ filter(callback: (value: Token, index: number, array: Token[]) => boolean) {
343
+ return TokenCollection._new(super.filter(callback), this);
344
+ }
345
+
346
+ getConsecutiveToken(tokenType: number) {
347
+ const resultToken = this.compareTokens((prev, current) => {
348
+ if (prev.type === tokenType && current.type === tokenType) {
349
+ return current;
350
+ }
351
+ });
352
+ return resultToken || null;
353
+ }
354
+
400
355
  getDuplicated() {
401
356
  const aList = this.slice();
402
357
  const bList = this.slice();
@@ -419,26 +374,71 @@ export class TokenCollection extends Array<Token> {
419
374
  return null;
420
375
  }
421
376
 
422
- divide(position: number) {
423
- const _a = this.slice(0, position);
424
- const _b = this.slice(position);
425
- const a = TokenCollection._new(_a, this);
426
- const b = TokenCollection._new(_b, this);
427
- return [a, b] as const;
377
+ getIdentTokens() {
378
+ return this.filter(token => token.type === Token.Ident);
428
379
  }
429
380
 
430
- chunk(split: number) {
431
- const chunks: TokenCollection[] = [];
381
+ /**
382
+ *
383
+ * @param value The token value or the token type or its list
384
+ */
385
+ has(value: string | RegExp | number | (string | RegExp | number)[]) {
386
+ return this.some(t => t.match(value));
387
+ }
388
+
389
+ headAndTail(): { head: Token | null; tail: TokenCollection } {
390
+ const copy = this.slice();
391
+ const head = copy.shift();
392
+ if (!head) {
393
+ return { head: head || null, tail: TokenCollection._new([], this) };
394
+ }
395
+ const tail = TokenCollection._new(copy, this);
396
+ return { head, tail };
397
+ }
398
+
399
+ /**
400
+ *
401
+ * @param value The token value or the token type or its list
402
+ */
403
+ search(value: string | RegExp | number | (string | RegExp | number)[]) {
404
+ for (const token of this) {
405
+ if (token.includes(value)) {
406
+ return token;
407
+ }
408
+ }
409
+ return null;
410
+ }
411
+
412
+ takeTurns(tokenNumbers: ReadonlyArray<number>, lastTokenNumber?: number) {
432
413
  const tokens = this.slice();
433
- while (tokens.length) {
434
- const chunkTokens = tokens.splice(0, split);
435
- const chunk = TokenCollection._new(chunkTokens, this);
436
- chunks.push(chunk);
414
+ for (let i = 0; i < tokens.length; i++) {
415
+ const token = tokens[i];
416
+ const expectedTokenNumber = tokenNumbers[i % tokenNumbers.length];
417
+ if (token.type !== expectedTokenNumber) {
418
+ return {
419
+ unexpectedLastToken: false,
420
+ expectedTokenNumber,
421
+ token,
422
+ };
423
+ }
424
+ if (lastTokenNumber != null && i === tokens.length - 1 && token.type !== lastTokenNumber) {
425
+ return {
426
+ unexpectedLastToken: true,
427
+ expectedTokenNumber,
428
+ token,
429
+ };
430
+ }
437
431
  }
438
- return chunks;
432
+ return null;
439
433
  }
440
434
 
441
435
  toJSON() {
442
436
  return this.map(t => t.toJSON());
443
437
  }
438
+
439
+ private static _new(tokens: Token[], old?: TokenCollection) {
440
+ const newCollection = new TokenCollection('', old);
441
+ newCollection.push(...tokens);
442
+ return newCollection;
443
+ }
444
444
  }
@@ -1,6 +1,34 @@
1
1
  import type { UnmatchedResult, UnmatchedResultOptions, UnmatchedResultReason } from '../types';
2
2
 
3
3
  export class Token {
4
+ /**
5
+ * @see https://github.com/csstree/csstree/blob/master/lib/tokenizer/types.js
6
+ */
7
+ static readonly Comma = 18;
8
+ static readonly Ident = 1;
9
+ static readonly WhiteSpace = 13;
10
+
11
+ /**
12
+ * ASCII whitespace is
13
+ * - U+0009 TAB
14
+ * - U+000A LF
15
+ * - U+000C FF
16
+ * - U+000D CR
17
+ * - U+0020 SPACE.
18
+ *
19
+ * @see https://infra.spec.whatwg.org/#ascii-whitespace
20
+ */
21
+ static readonly whitespace: ReadonlyArray<string> = ['\u0009', '\u000A', '\u000C', '\u000D', '\u0020'];
22
+
23
+ static getCol(value: string, offset: number) {
24
+ const lines = value.slice(0, offset).split(/\n/g);
25
+ return lines[lines.length - 1].length + 1;
26
+ }
27
+
28
+ static getLine(value: string, offset: number) {
29
+ return value.slice(0, offset).split(/\n/g).length;
30
+ }
31
+
4
32
  static getType(value: string, separators?: string[]) {
5
33
  if (Token.whitespace.includes(value[0])) {
6
34
  return Token.WhiteSpace;
@@ -14,15 +42,6 @@ export class Token {
14
42
  return Token.Ident;
15
43
  }
16
44
 
17
- static getLine(value: string, offset: number) {
18
- return value.slice(0, offset).split(/\n/g).length;
19
- }
20
-
21
- static getCol(value: string, offset: number) {
22
- const lines = value.slice(0, offset).split(/\n/g);
23
- return lines[lines.length - 1].length + 1;
24
- }
25
-
26
45
  static shiftLocation(token: Token, offset: number) {
27
46
  const shifted = token.offset + offset;
28
47
  return {
@@ -32,29 +51,10 @@ export class Token {
32
51
  };
33
52
  }
34
53
 
35
- /**
36
- * ASCII whitespace is
37
- * - U+0009 TAB
38
- * - U+000A LF
39
- * - U+000C FF
40
- * - U+000D CR
41
- * - U+0020 SPACE.
42
- *
43
- * @see https://infra.spec.whatwg.org/#ascii-whitespace
44
- */
45
- static readonly whitespace: ReadonlyArray<string> = ['\u0009', '\u000A', '\u000C', '\u000D', '\u0020'];
46
-
47
- /**
48
- * @see https://github.com/csstree/csstree/blob/master/lib/tokenizer/types.js
49
- */
50
- static readonly Ident = 1;
51
- static readonly WhiteSpace = 13;
52
- static readonly Comma = 18;
53
-
54
- readonly type: number;
55
- readonly value: string;
56
54
  readonly offset: number;
57
55
  #originalValue: string;
56
+ readonly type: number;
57
+ readonly value: string;
58
58
 
59
59
  constructor(value: string, offset: number, originalValue: string, separators?: string[]) {
60
60
  this.type = Token.getType(value, separators);
@@ -71,37 +71,18 @@ export class Token {
71
71
  return this.#originalValue;
72
72
  }
73
73
 
74
- unmatched(
75
- options?: UnmatchedResultOptions & {
76
- ref?: string;
77
- reason?: UnmatchedResultReason;
78
- },
79
- ): UnmatchedResult {
80
- return {
81
- ...options,
82
- matched: false,
83
- ref: options?.ref || null,
84
- raw: this.value,
85
- offset: this.offset,
86
- length: this.value.length,
87
- line: Token.getLine(this.#originalValue, this.offset),
88
- column: Token.getCol(this.#originalValue, this.offset),
89
- reason: options?.reason ?? 'syntax-error',
90
- };
91
- }
92
-
93
74
  /**
94
75
  *
95
76
  * @param value The token value or the token type or its list
96
77
  */
97
- match(value: string | RegExp | number | (string | RegExp | number)[], caseInsensitive?: boolean): boolean {
78
+ includes(value: string | RegExp | number | (string | RegExp | number)[], caseInsensitive?: boolean): boolean {
98
79
  if (Array.isArray(value)) {
99
- return value.some(v => this.match(v));
80
+ return value.some(v => this.includes(v));
100
81
  }
101
82
  if (typeof value === 'string') {
102
83
  const a = caseInsensitive ? this.value.toLowerCase() : this.value;
103
84
  const b = caseInsensitive ? value.toLowerCase() : value;
104
- return a === b;
85
+ return a.indexOf(b) !== -1;
105
86
  }
106
87
  if (value instanceof RegExp) {
107
88
  const pattern = new RegExp(value, caseInsensitive ? 'i' : '');
@@ -114,14 +95,14 @@ export class Token {
114
95
  *
115
96
  * @param value The token value or the token type or its list
116
97
  */
117
- includes(value: string | RegExp | number | (string | RegExp | number)[], caseInsensitive?: boolean): boolean {
98
+ match(value: string | RegExp | number | (string | RegExp | number)[], caseInsensitive?: boolean): boolean {
118
99
  if (Array.isArray(value)) {
119
- return value.some(v => this.includes(v));
100
+ return value.some(v => this.match(v));
120
101
  }
121
102
  if (typeof value === 'string') {
122
103
  const a = caseInsensitive ? this.value.toLowerCase() : this.value;
123
104
  const b = caseInsensitive ? value.toLowerCase() : value;
124
- return a.indexOf(b) !== -1;
105
+ return a === b;
125
106
  }
126
107
  if (value instanceof RegExp) {
127
108
  const pattern = new RegExp(value, caseInsensitive ? 'i' : '');
@@ -130,15 +111,34 @@ export class Token {
130
111
  return this.type === value;
131
112
  }
132
113
 
114
+ toJSON() {
115
+ return {
116
+ type: this.type,
117
+ value: this.value,
118
+ offset: this.offset,
119
+ };
120
+ }
121
+
133
122
  toNumber() {
134
123
  return parseFloat(this.value);
135
124
  }
136
125
 
137
- toJSON() {
126
+ unmatched(
127
+ options?: UnmatchedResultOptions & {
128
+ ref?: string;
129
+ reason?: UnmatchedResultReason;
130
+ },
131
+ ): UnmatchedResult {
138
132
  return {
139
- type: this.type,
140
- value: this.value,
133
+ ...options,
134
+ matched: false,
135
+ ref: options?.ref || null,
136
+ raw: this.value,
141
137
  offset: this.offset,
138
+ length: this.value.length,
139
+ line: Token.getLine(this.#originalValue, this.offset),
140
+ column: Token.getCol(this.#originalValue, this.offset),
141
+ reason: options?.reason ?? 'syntax-error',
142
142
  };
143
143
  }
144
144
  }
@@ -1037,6 +1037,9 @@ export interface List {
1037
1037
  * [Enumerated attributes](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#enumerated-attribute)
1038
1038
  */
1039
1039
  export interface Enum {
1040
+ /**
1041
+ * @minItems 1
1042
+ */
1040
1043
  enum: [string, ...string[]];
1041
1044
  disallowToSurroundBySpaces?: boolean;
1042
1045
  caseInsensitive?: boolean;