@tbela99/css-parser 0.5.4 → 0.7.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.
- package/README.md +108 -5
- package/dist/config.json.js +3 -1
- package/dist/index-umd-web.js +53911 -50
- package/dist/index.cjs +53911 -50
- package/dist/index.d.ts +118 -23
- package/dist/lib/ast/expand.js +8 -2
- package/dist/lib/ast/features/index.js +1 -0
- package/dist/lib/ast/features/prefix.js +118 -0
- package/dist/lib/ast/features/shorthand.js +1 -0
- package/dist/lib/ast/minify.js +44 -10
- package/dist/lib/ast/types.js +16 -1
- package/dist/lib/ast/walk.js +3 -1
- package/dist/lib/parser/declaration/list.js +1 -1
- package/dist/lib/parser/declaration/map.js +9 -4
- package/dist/lib/parser/declaration/set.js +2 -1
- package/dist/lib/parser/parse.js +262 -16
- package/dist/lib/parser/tokenize.js +19 -5
- package/dist/lib/parser/utils/config.js +1 -0
- package/dist/lib/parser/utils/declaration.js +2 -1
- package/dist/lib/parser/utils/syntax.js +10 -0
- package/dist/lib/parser/utils/type.js +1 -0
- package/dist/lib/renderer/color/a98rgb.js +1 -0
- package/dist/lib/renderer/color/color.js +1 -0
- package/dist/lib/renderer/color/colormix.js +3 -2
- package/dist/lib/renderer/color/hex.js +1 -0
- package/dist/lib/renderer/color/hsl.js +1 -0
- package/dist/lib/renderer/color/hwb.js +1 -0
- package/dist/lib/renderer/color/lab.js +1 -0
- package/dist/lib/renderer/color/lch.js +1 -0
- package/dist/lib/renderer/color/oklab.js +1 -0
- package/dist/lib/renderer/color/oklch.js +1 -0
- package/dist/lib/renderer/color/p3.js +1 -0
- package/dist/lib/renderer/color/rec2020.js +1 -0
- package/dist/lib/renderer/color/relativecolor.js +1 -0
- package/dist/lib/renderer/color/rgb.js +1 -0
- package/dist/lib/renderer/color/srgb.js +1 -0
- package/dist/lib/renderer/color/utils/components.js +1 -0
- package/dist/lib/renderer/color/utils/constants.js +6 -1
- package/dist/lib/renderer/color/xyz.js +1 -0
- package/dist/lib/renderer/color/xyzd50.js +1 -0
- package/dist/lib/renderer/render.js +30 -7
- package/dist/lib/syntax/syntax.js +456 -0
- package/dist/lib/validation/config.js +9 -0
- package/dist/lib/validation/config.json.js +52883 -0
- package/dist/lib/validation/parser/parse.js +16 -0
- package/dist/lib/validation/parser/types.js +39 -0
- package/dist/lib/validation/selector.js +459 -0
- package/dist/node/index.js +2 -0
- package/dist/web/index.js +1 -0
- package/dist/web/load.js +1 -0
- package/package.json +4 -3
|
@@ -2,6 +2,7 @@ import { EnumToken } from '../../../ast/types.js';
|
|
|
2
2
|
import '../../../ast/minify.js';
|
|
3
3
|
import '../../../parser/parse.js';
|
|
4
4
|
import '../../sourcemap/lib/encode.js';
|
|
5
|
+
import '../../../parser/utils/config.js';
|
|
5
6
|
|
|
6
7
|
const colorRange = {
|
|
7
8
|
lab: {
|
|
@@ -30,6 +31,10 @@ const colorFuncColorSpace = ['srgb', 'srgb-linear', 'display-p3', 'prophoto-rgb'
|
|
|
30
31
|
const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
|
|
31
32
|
const k = Math.pow(29, 3) / Math.pow(3, 3);
|
|
32
33
|
const e = Math.pow(6, 3) / Math.pow(29, 3);
|
|
34
|
+
// color module v4
|
|
35
|
+
const systemColors = new Set(['ActiveText', 'ButtonBorder', 'ButtonFace', 'ButtonText', 'Canvas', 'CanvasText', 'Field', 'FieldText', 'GrayText', 'Highlight', 'HighlightText', 'LinkText', 'Mark', 'MarkText', 'VisitedText'].map(m => m.toLowerCase()));
|
|
36
|
+
// deprecated
|
|
37
|
+
const deprecatedSystemColors = new Set(['ActiveBorder', 'ActiveCaption', 'AppWorkspace', 'Background', 'ButtonFace', 'ButtonHighlight', 'ButtonShadow', 'ButtonText', 'CaptionText', 'GrayText', 'Highlight', 'HighlightText', 'InactiveBorder', 'InactiveCaption', 'InactiveCaptionText', 'InfoBackground', 'InfoText', 'Menu', 'MenuText', 'Scrollbar', 'ThreeDDarkShadow', 'ThreeDFace', 'ThreeDHighlight', 'ThreeDLightShadow', 'ThreeDShadow', 'Window', 'WindowFrame', 'WindowText'].map(t => t.toLowerCase()));
|
|
33
38
|
// name to color
|
|
34
39
|
const COLORS_NAMES = Object.seal({
|
|
35
40
|
'aliceblue': '#f0f8ff',
|
|
@@ -188,4 +193,4 @@ const NAMES_COLORS = Object.seal(Object.entries(COLORS_NAMES).reduce((acc, [key,
|
|
|
188
193
|
return acc;
|
|
189
194
|
}, Object.create(null)));
|
|
190
195
|
|
|
191
|
-
export { COLORS_NAMES, D50, NAMES_COLORS, colorFuncColorSpace, colorRange, e, k };
|
|
196
|
+
export { COLORS_NAMES, D50, NAMES_COLORS, colorFuncColorSpace, colorRange, deprecatedSystemColors, e, k, systemColors };
|
|
@@ -8,10 +8,9 @@ import { expand } from '../ast/expand.js';
|
|
|
8
8
|
import { colorMix } from './color/colormix.js';
|
|
9
9
|
import { parseRelativeColor } from './color/relativecolor.js';
|
|
10
10
|
import { SourceMap } from './sourcemap/sourcemap.js';
|
|
11
|
-
import '../
|
|
12
|
-
import { isColor, isNewLine } from '../parser/utils/syntax.js';
|
|
11
|
+
import { isColor, isNewLine } from '../syntax/syntax.js';
|
|
13
12
|
|
|
14
|
-
const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch'];
|
|
13
|
+
const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark'];
|
|
15
14
|
function reduceNumber(val) {
|
|
16
15
|
val = String(+val);
|
|
17
16
|
if (val === '0') {
|
|
@@ -93,7 +92,7 @@ function doRender(data, options = {}) {
|
|
|
93
92
|
options.output = options.resolve(options.output, options.cwd).absolute;
|
|
94
93
|
}
|
|
95
94
|
if (sourcemap != null) {
|
|
96
|
-
result.map = sourcemap
|
|
95
|
+
result.map = sourcemap;
|
|
97
96
|
}
|
|
98
97
|
return result;
|
|
99
98
|
}
|
|
@@ -201,6 +200,10 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
|
|
|
201
200
|
return `@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val}${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
|
|
202
201
|
}
|
|
203
202
|
return data.sel + `${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
|
|
203
|
+
case EnumToken.InvalidRuleTokenType:
|
|
204
|
+
return '';
|
|
205
|
+
default:
|
|
206
|
+
throw new Error(`render: unexpected token ${JSON.stringify(data, null, 1)}`);
|
|
204
207
|
}
|
|
205
208
|
return '';
|
|
206
209
|
}
|
|
@@ -274,11 +277,15 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
274
277
|
return ' + ';
|
|
275
278
|
case EnumToken.Sub:
|
|
276
279
|
return ' - ';
|
|
280
|
+
case EnumToken.UniversalSelectorTokenType:
|
|
277
281
|
case EnumToken.Mul:
|
|
278
282
|
return '*';
|
|
279
283
|
case EnumToken.Div:
|
|
280
284
|
return '/';
|
|
281
285
|
case EnumToken.ColorTokenType:
|
|
286
|
+
if (token.kin == 'light-dark') {
|
|
287
|
+
return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderToken(curr, options, cache), '') + ')';
|
|
288
|
+
}
|
|
282
289
|
if (options.convertColor) {
|
|
283
290
|
if (token.cal == 'mix' && token.val == 'color-mix') {
|
|
284
291
|
const children = token.chi.reduce((acc, t) => {
|
|
@@ -372,7 +379,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
372
379
|
return reduceHexValue(value);
|
|
373
380
|
}
|
|
374
381
|
}
|
|
375
|
-
if (
|
|
382
|
+
if (['hex', 'lit', 'sys', 'dpsys'].includes(token.kin)) {
|
|
376
383
|
return token.val;
|
|
377
384
|
}
|
|
378
385
|
if (Array.isArray(token.chi)) {
|
|
@@ -403,7 +410,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
403
410
|
renderToken(token.r, options, cache, reducer, errors) +
|
|
404
411
|
(token.attr ? ' ' + token.attr : '');
|
|
405
412
|
case EnumToken.NameSpaceAttributeTokenType:
|
|
406
|
-
return (token.l == null ? '' : renderToken(token.l, options, cache, reducer, errors) + '|'
|
|
413
|
+
return (token.l == null ? '' : renderToken(token.l, options, cache, reducer, errors)) + '|' +
|
|
407
414
|
renderToken(token.r, options, cache, reducer, errors);
|
|
408
415
|
case EnumToken.BlockStartTokenType:
|
|
409
416
|
return '{';
|
|
@@ -411,6 +418,8 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
411
418
|
return '}';
|
|
412
419
|
case EnumToken.StartParensTokenType:
|
|
413
420
|
return '(';
|
|
421
|
+
case EnumToken.DelimTokenType:
|
|
422
|
+
return '=';
|
|
414
423
|
case EnumToken.IncludeMatchTokenType:
|
|
415
424
|
return '~=';
|
|
416
425
|
case EnumToken.DashMatchTokenType:
|
|
@@ -425,7 +434,12 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
425
434
|
return '<';
|
|
426
435
|
case EnumToken.LteTokenType:
|
|
427
436
|
return '<=';
|
|
437
|
+
case EnumToken.SubsequentSiblingCombinatorTokenType:
|
|
438
|
+
return '~';
|
|
439
|
+
case EnumToken.NextSiblingCombinatorTokenType:
|
|
440
|
+
return '+';
|
|
428
441
|
case EnumToken.GtTokenType:
|
|
442
|
+
case EnumToken.ChildCombinatorTokenType:
|
|
429
443
|
return '>';
|
|
430
444
|
case EnumToken.GteTokenType:
|
|
431
445
|
return '>=';
|
|
@@ -437,6 +451,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
437
451
|
return '[';
|
|
438
452
|
case EnumToken.AttrEndTokenType:
|
|
439
453
|
return ']';
|
|
454
|
+
case EnumToken.DescendantCombinatorTokenType:
|
|
440
455
|
case EnumToken.WhitespaceTokenType:
|
|
441
456
|
return ' ';
|
|
442
457
|
case EnumToken.ColonTokenType:
|
|
@@ -568,12 +583,20 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
568
583
|
}
|
|
569
584
|
case EnumToken.HashTokenType:
|
|
570
585
|
case EnumToken.IdenTokenType:
|
|
571
|
-
case EnumToken.DelimTokenType:
|
|
572
586
|
case EnumToken.AtRuleTokenType:
|
|
573
587
|
case EnumToken.StringTokenType:
|
|
574
588
|
case EnumToken.LiteralTokenType:
|
|
575
589
|
case EnumToken.DashedIdenTokenType:
|
|
590
|
+
case EnumToken.ClassSelectorTokenType:
|
|
576
591
|
return /* options.minify && 'Pseudo-class' == token.typ && '::' == token.val.slice(0, 2) ? token.val.slice(1) : */ token.val;
|
|
592
|
+
case EnumToken.NestingSelectorTokenType:
|
|
593
|
+
return '&';
|
|
594
|
+
case EnumToken.InvalidAttrTokenType:
|
|
595
|
+
return '[' + token.chi.reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
|
|
596
|
+
case EnumToken.InvalidClassSelectorTokenType:
|
|
597
|
+
return token.val;
|
|
598
|
+
default:
|
|
599
|
+
throw new Error(`render: unexpected token ${JSON.stringify(token, null, 1)}`);
|
|
577
600
|
}
|
|
578
601
|
errors?.push({ action: 'ignore', message: `render: unexpected token ${JSON.stringify(token, null, 1)}` });
|
|
579
602
|
return '';
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { colorsFunc } from '../renderer/render.js';
|
|
2
|
+
import { EnumToken } from '../ast/types.js';
|
|
3
|
+
import '../ast/minify.js';
|
|
4
|
+
import '../parser/parse.js';
|
|
5
|
+
import '../parser/utils/config.js';
|
|
6
|
+
import { COLORS_NAMES } from '../renderer/color/utils/constants.js';
|
|
7
|
+
|
|
8
|
+
// https://www.w3.org/TR/CSS21/syndata.html#syntax
|
|
9
|
+
// https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token
|
|
10
|
+
// '\\'
|
|
11
|
+
const REVERSE_SOLIDUS = 0x5c;
|
|
12
|
+
const dimensionUnits = new Set([
|
|
13
|
+
'q', 'cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb',
|
|
14
|
+
'dvh', 'dvi', 'dvmax', 'dvmin', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb',
|
|
15
|
+
'lvh', 'lvi', 'lvmax', 'lvw', 'mm', 'pc', 'pt', 'px', 'rem', 'rlh', 'svb',
|
|
16
|
+
'svh', 'svi', 'svmin', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'
|
|
17
|
+
]);
|
|
18
|
+
function isLength(dimension) {
|
|
19
|
+
return 'unit' in dimension && dimensionUnits.has(dimension.unit.toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
function isResolution(dimension) {
|
|
22
|
+
return 'unit' in dimension && ['dpi', 'dpcm', 'dppx', 'x'].includes(dimension.unit.toLowerCase());
|
|
23
|
+
}
|
|
24
|
+
function isAngle(dimension) {
|
|
25
|
+
return 'unit' in dimension && ['rad', 'turn', 'deg', 'grad'].includes(dimension.unit.toLowerCase());
|
|
26
|
+
}
|
|
27
|
+
function isTime(dimension) {
|
|
28
|
+
return 'unit' in dimension && ['ms', 's'].includes(dimension.unit.toLowerCase());
|
|
29
|
+
}
|
|
30
|
+
function isFrequency(dimension) {
|
|
31
|
+
return 'unit' in dimension && ['hz', 'khz'].includes(dimension.unit.toLowerCase());
|
|
32
|
+
}
|
|
33
|
+
function isColorspace(token) {
|
|
34
|
+
if (token.typ != EnumToken.IdenTokenType) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return ['srgb', 'srgb-linear', 'lab', 'oklab', 'lch', 'oklch', 'xyz', 'xyz-d50', 'xyz-d65', 'display-p3', 'a98-rgb', 'prophoto-rgb', 'rec2020', 'rgb', 'hsl', 'hwb'].includes(token.val.toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
function isRectangularOrthogonalColorspace(token) {
|
|
40
|
+
if (token.typ != EnumToken.IdenTokenType) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return ['srgb', 'srgb-linear', 'display-p3', 'a98-rgb', 'prophoto-rgb', 'rec2020', 'lab', 'oklab', 'xyz', 'xyz-d50', 'xyz-d65'].includes(token.val.toLowerCase());
|
|
44
|
+
}
|
|
45
|
+
function isPolarColorspace(token) {
|
|
46
|
+
if (token.typ != EnumToken.IdenTokenType) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return ['hsl', 'hwb', 'lch', 'oklch'].includes(token.val);
|
|
50
|
+
}
|
|
51
|
+
function isHueInterpolationMethod(token) {
|
|
52
|
+
if (token.typ != EnumToken.IdenTokenType) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return ['shorter', 'longer', 'increasing', 'decreasing'].includes(token.val);
|
|
56
|
+
}
|
|
57
|
+
function isColor(token) {
|
|
58
|
+
if (token.typ == EnumToken.ColorTokenType) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
if (token.typ == EnumToken.IdenTokenType) {
|
|
62
|
+
// named color
|
|
63
|
+
return token.val.toLowerCase() in COLORS_NAMES;
|
|
64
|
+
}
|
|
65
|
+
let isLegacySyntax = false;
|
|
66
|
+
if (token.typ == EnumToken.FunctionTokenType && token.chi.length > 0 && colorsFunc.includes(token.val)) {
|
|
67
|
+
if (token.val == 'light-dark') {
|
|
68
|
+
const children = token.chi.filter((t) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.LiteralTokenType, EnumToken.ColorTokenType, EnumToken.FunctionTokenType, EnumToken.PercentageTokenType].includes(t.typ));
|
|
69
|
+
if (children.length != 2) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (isColor(children[0]) && isColor(children[1])) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (token.val == 'color') {
|
|
77
|
+
const children = token.chi.filter((t) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.LiteralTokenType, EnumToken.ColorTokenType, EnumToken.FunctionTokenType, EnumToken.PercentageTokenType].includes(t.typ));
|
|
78
|
+
const isRelative = children[0].typ == EnumToken.IdenTokenType && children[0].val == 'from';
|
|
79
|
+
if (children.length < 4 || children.length > 8) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (!isRelative && !isColorspace(children[0])) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
for (let i = 1; i < children.length - 2; i++) {
|
|
86
|
+
if (children[i].typ == EnumToken.IdenTokenType) {
|
|
87
|
+
if (children[i].val != 'none' &&
|
|
88
|
+
!(isRelative && ['alpha', 'r', 'g', 'b', 'x', 'y', 'z'].includes(children[i].val) || isColorspace(children[i]))) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (children[i].typ == EnumToken.FunctionTokenType && !['calc'].includes(children[i].val)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (children.length == 4 || (isRelative && children.length == 6)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
if (children.length == 8 || children.length == 6) {
|
|
100
|
+
const sep = children.at(-2);
|
|
101
|
+
const alpha = children.at(-1);
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
if ((children.length > 6 || !isRelative) && sep.typ != EnumToken.LiteralTokenType || sep.val != '/') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (alpha.typ == EnumToken.IdenTokenType && alpha.val != 'none') {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// @ts-ignore
|
|
111
|
+
if (alpha.typ == EnumToken.PercentageTokenType) {
|
|
112
|
+
if (+alpha.val < 0 || +alpha.val > 100) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (alpha.typ == EnumToken.NumberTokenType) {
|
|
117
|
+
if (+alpha.val < 0 || +alpha.val > 1) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
else if (token.val == 'color-mix') {
|
|
126
|
+
const children = token.chi.reduce((acc, t) => {
|
|
127
|
+
if (t.typ == EnumToken.CommaTokenType) {
|
|
128
|
+
acc.push([]);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)) {
|
|
132
|
+
acc[acc.length - 1].push(t);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return acc;
|
|
136
|
+
}, [[]]);
|
|
137
|
+
if (children.length == 3) {
|
|
138
|
+
if (children[0].length > 3 ||
|
|
139
|
+
children[0][0].typ != EnumToken.IdenTokenType ||
|
|
140
|
+
children[0][0].val != 'in' ||
|
|
141
|
+
!isColorspace(children[0][1]) ||
|
|
142
|
+
(children[0].length == 3 && !isHueInterpolationMethod(children[0][2])) ||
|
|
143
|
+
children[1].length > 2 ||
|
|
144
|
+
children[1][0].typ != EnumToken.ColorTokenType ||
|
|
145
|
+
children[2].length > 2 ||
|
|
146
|
+
children[2][0].typ != EnumToken.ColorTokenType) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (children[1].length == 2) {
|
|
150
|
+
if (!(children[1][1].typ == EnumToken.PercentageTokenType || (children[1][1].typ == EnumToken.NumberTokenType && children[1][1].val == '0'))) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (children[2].length == 2) {
|
|
155
|
+
if (!(children[2][1].typ == EnumToken.PercentageTokenType || (children[2][1].typ == EnumToken.NumberTokenType && children[2][1].val == '0'))) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const keywords = ['from', 'none'];
|
|
165
|
+
if (['rgb', 'hsl', 'hwb', 'lab', 'lch', 'oklab', 'oklch'].includes(token.val)) {
|
|
166
|
+
keywords.push('alpha', ...token.val.slice(-3).split(''));
|
|
167
|
+
}
|
|
168
|
+
// @ts-ignore
|
|
169
|
+
for (const v of token.chi) {
|
|
170
|
+
if (v.typ == EnumToken.CommaTokenType) {
|
|
171
|
+
isLegacySyntax = true;
|
|
172
|
+
}
|
|
173
|
+
if (v.typ == EnumToken.IdenTokenType) {
|
|
174
|
+
if (!(keywords.includes(v.val) || v.val.toLowerCase() in COLORS_NAMES)) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
if (keywords.includes(v.val)) {
|
|
178
|
+
if (isLegacySyntax) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if (v.val == 'from' && ['rgba', 'hsla'].includes(token.val)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (v.typ == EnumToken.FunctionTokenType && (v.val == 'calc' || v.val == 'var' || colorsFunc.includes(v.val))) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (![EnumToken.ColorTokenType, EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.LiteralTokenType].includes(v.typ)) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
function isLetter(codepoint) {
|
|
200
|
+
// lowercase
|
|
201
|
+
return (codepoint >= 0x61 && codepoint <= 0x7a) ||
|
|
202
|
+
// uppercase
|
|
203
|
+
(codepoint >= 0x41 && codepoint <= 0x5a);
|
|
204
|
+
}
|
|
205
|
+
function isNonAscii(codepoint) {
|
|
206
|
+
return codepoint >= 0x80;
|
|
207
|
+
}
|
|
208
|
+
function isIdentStart(codepoint) {
|
|
209
|
+
// _
|
|
210
|
+
return codepoint == 0x5f || isLetter(codepoint) || isNonAscii(codepoint);
|
|
211
|
+
}
|
|
212
|
+
function isDigit(codepoint) {
|
|
213
|
+
return codepoint >= 0x30 && codepoint <= 0x39;
|
|
214
|
+
}
|
|
215
|
+
function isIdentCodepoint(codepoint) {
|
|
216
|
+
// -
|
|
217
|
+
return codepoint == 0x2d || isDigit(codepoint) || isIdentStart(codepoint);
|
|
218
|
+
}
|
|
219
|
+
function isIdent(name) {
|
|
220
|
+
const j = name.length - 1;
|
|
221
|
+
let i = 0;
|
|
222
|
+
let codepoint = name.charCodeAt(0);
|
|
223
|
+
// -
|
|
224
|
+
if (codepoint == 0x2d) {
|
|
225
|
+
const nextCodepoint = name.charCodeAt(1);
|
|
226
|
+
if (Number.isNaN(nextCodepoint)) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
// -
|
|
230
|
+
if (nextCodepoint == 0x2d) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
if (nextCodepoint == REVERSE_SOLIDUS) {
|
|
234
|
+
return name.length > 2 && !isNewLine(name.charCodeAt(2));
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
if (!isIdentStart(codepoint)) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
while (i < j) {
|
|
242
|
+
i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length;
|
|
243
|
+
codepoint = name.charCodeAt(i);
|
|
244
|
+
if (codepoint == REVERSE_SOLIDUS) {
|
|
245
|
+
i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length;
|
|
246
|
+
codepoint = name.charCodeAt(i);
|
|
247
|
+
i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (!isIdentCodepoint(codepoint)) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
function isNonPrintable(codepoint) {
|
|
257
|
+
// null -> backspace
|
|
258
|
+
return (codepoint >= 0 && codepoint <= 0x8) ||
|
|
259
|
+
// tab
|
|
260
|
+
codepoint == 0xb ||
|
|
261
|
+
// delete
|
|
262
|
+
codepoint == 0x7f ||
|
|
263
|
+
(codepoint >= 0xe && codepoint <= 0x1f);
|
|
264
|
+
}
|
|
265
|
+
function isPseudo(name) {
|
|
266
|
+
return name.charAt(0) == ':' &&
|
|
267
|
+
((name.endsWith('(') && isIdent(name.charAt(1) == ':' ? name.slice(2, -1) : name.slice(1, -1))) ||
|
|
268
|
+
isIdent(name.charAt(1) == ':' ? name.slice(2) : name.slice(1)));
|
|
269
|
+
}
|
|
270
|
+
function isHash(name) {
|
|
271
|
+
return name.charAt(0) == '#' && isIdent(name.charAt(1));
|
|
272
|
+
}
|
|
273
|
+
function isNumber(name) {
|
|
274
|
+
if (name.length == 0) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
let codepoint = name.charCodeAt(0);
|
|
278
|
+
let i = 0;
|
|
279
|
+
const j = name.length;
|
|
280
|
+
if (j == 1 && !isDigit(codepoint)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
// '+' '-'
|
|
284
|
+
if ([0x2b, 0x2d].includes(codepoint)) {
|
|
285
|
+
i++;
|
|
286
|
+
}
|
|
287
|
+
// consume digits
|
|
288
|
+
while (i < j) {
|
|
289
|
+
codepoint = name.charCodeAt(i);
|
|
290
|
+
if (isDigit(codepoint)) {
|
|
291
|
+
i++;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
// '.' 'E' 'e'
|
|
295
|
+
if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) {
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
// '.'
|
|
301
|
+
if (codepoint == 0x2e) {
|
|
302
|
+
if (!isDigit(name.charCodeAt(++i))) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
while (i < j) {
|
|
307
|
+
codepoint = name.charCodeAt(i);
|
|
308
|
+
if (isDigit(codepoint)) {
|
|
309
|
+
i++;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
// 'E' 'e'
|
|
313
|
+
if (codepoint == 0x45 || codepoint == 0x65) {
|
|
314
|
+
i++;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
// 'E' 'e'
|
|
320
|
+
if (codepoint == 0x45 || codepoint == 0x65) {
|
|
321
|
+
if (i == j) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
codepoint = name.charCodeAt(i + 1);
|
|
325
|
+
// '+' '-'
|
|
326
|
+
if ([0x2b, 0x2d].includes(codepoint)) {
|
|
327
|
+
i++;
|
|
328
|
+
}
|
|
329
|
+
codepoint = name.charCodeAt(i + 1);
|
|
330
|
+
if (!isDigit(codepoint)) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
while (++i < j) {
|
|
335
|
+
codepoint = name.charCodeAt(i);
|
|
336
|
+
if (!isDigit(codepoint)) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
function isDimension(name) {
|
|
343
|
+
let index = name.length;
|
|
344
|
+
while (index--) {
|
|
345
|
+
if (isLetter(name.charCodeAt(index))) {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
index++;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
const number = name.slice(0, index);
|
|
352
|
+
return number.length > 0 && isIdentStart(name.charCodeAt(index)) && isNumber(number);
|
|
353
|
+
}
|
|
354
|
+
function isPercentage(name) {
|
|
355
|
+
return name.endsWith('%') && isNumber(name.slice(0, -1));
|
|
356
|
+
}
|
|
357
|
+
function isFlex(name) {
|
|
358
|
+
return name.endsWith('fr') && isNumber(name.slice(0, -2));
|
|
359
|
+
}
|
|
360
|
+
function parseDimension(name) {
|
|
361
|
+
let index = name.length;
|
|
362
|
+
while (index--) {
|
|
363
|
+
if (isLetter(name.charCodeAt(index))) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
index++;
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
const dimension = {
|
|
370
|
+
typ: EnumToken.DimensionTokenType,
|
|
371
|
+
val: name.slice(0, index),
|
|
372
|
+
unit: name.slice(index)
|
|
373
|
+
};
|
|
374
|
+
if (isAngle(dimension)) {
|
|
375
|
+
// @ts-ignore
|
|
376
|
+
dimension.typ = EnumToken.AngleTokenType;
|
|
377
|
+
}
|
|
378
|
+
else if (isLength(dimension)) {
|
|
379
|
+
// @ts-ignore
|
|
380
|
+
dimension.typ = EnumToken.LengthTokenType;
|
|
381
|
+
}
|
|
382
|
+
else if (isTime(dimension)) {
|
|
383
|
+
// @ts-ignore
|
|
384
|
+
dimension.typ = EnumToken.TimeTokenType;
|
|
385
|
+
}
|
|
386
|
+
else if (isResolution(dimension)) {
|
|
387
|
+
// @ts-ignore
|
|
388
|
+
dimension.typ = EnumToken.ResolutionTokenType;
|
|
389
|
+
if (dimension.unit == 'dppx') {
|
|
390
|
+
dimension.unit = 'x';
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else if (isFrequency(dimension)) {
|
|
394
|
+
// @ts-ignore
|
|
395
|
+
dimension.typ = EnumToken.FrequencyTokenType;
|
|
396
|
+
}
|
|
397
|
+
return dimension;
|
|
398
|
+
}
|
|
399
|
+
function isHexColor(name) {
|
|
400
|
+
if (name.charAt(0) != '#' || ![4, 5, 7, 9].includes(name.length)) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
for (let chr of name.slice(1)) {
|
|
404
|
+
let codepoint = chr.charCodeAt(0);
|
|
405
|
+
if (!isDigit(codepoint) &&
|
|
406
|
+
// A-F
|
|
407
|
+
!(codepoint >= 0x41 && codepoint <= 0x46) &&
|
|
408
|
+
// a-f
|
|
409
|
+
!(codepoint >= 0x61 && codepoint <= 0x66)) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
/*
|
|
416
|
+
export function isHexDigit(name: string): boolean {
|
|
417
|
+
|
|
418
|
+
if (name.length || name.length > 6) {
|
|
419
|
+
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
for (let chr of name) {
|
|
424
|
+
|
|
425
|
+
let codepoint = <number>chr.charCodeAt(0);
|
|
426
|
+
|
|
427
|
+
if (!isDigit(codepoint) &&
|
|
428
|
+
// A F
|
|
429
|
+
!(codepoint >= 0x41 && codepoint <= 0x46) &&
|
|
430
|
+
// a f
|
|
431
|
+
!(codepoint >= 0x61 && codepoint <= 0x66)) {
|
|
432
|
+
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
*/
|
|
440
|
+
function isFunction(name) {
|
|
441
|
+
return name.endsWith('(') && isIdent(name.slice(0, -1));
|
|
442
|
+
}
|
|
443
|
+
function isAtKeyword(name) {
|
|
444
|
+
return name.charCodeAt(0) == 0x40 && isIdent(name.slice(1));
|
|
445
|
+
}
|
|
446
|
+
function isNewLine(codepoint) {
|
|
447
|
+
// \n \r \f
|
|
448
|
+
return codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
|
|
449
|
+
}
|
|
450
|
+
function isWhiteSpace(codepoint) {
|
|
451
|
+
return codepoint == 0x9 || codepoint == 0x20 ||
|
|
452
|
+
// isNewLine
|
|
453
|
+
codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export { isAngle, isAtKeyword, isColor, isColorspace, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, parseDimension };
|