@tbela99/css-parser 0.6.0 → 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 +106 -3
- package/dist/config.json.js +3 -1
- package/dist/index-umd-web.js +53876 -50
- package/dist/index.cjs +53876 -50
- package/dist/index.d.ts +113 -18
- 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 +239 -11
- 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 +1 -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 +1 -0
- package/dist/lib/renderer/color/xyz.js +1 -0
- package/dist/lib/renderer/color/xyzd50.js +1 -0
- package/dist/lib/renderer/render.js +25 -5
- 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 +1 -0
- package/dist/web/index.js +1 -0
- package/package.json +1 -1
- package/jsr.json +0 -29
|
@@ -8,8 +8,7 @@ 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
13
|
const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark'];
|
|
15
14
|
function reduceNumber(val) {
|
|
@@ -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,6 +277,7 @@ 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:
|
|
@@ -406,7 +410,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
406
410
|
renderToken(token.r, options, cache, reducer, errors) +
|
|
407
411
|
(token.attr ? ' ' + token.attr : '');
|
|
408
412
|
case EnumToken.NameSpaceAttributeTokenType:
|
|
409
|
-
return (token.l == null ? '' : renderToken(token.l, options, cache, reducer, errors) + '|'
|
|
413
|
+
return (token.l == null ? '' : renderToken(token.l, options, cache, reducer, errors)) + '|' +
|
|
410
414
|
renderToken(token.r, options, cache, reducer, errors);
|
|
411
415
|
case EnumToken.BlockStartTokenType:
|
|
412
416
|
return '{';
|
|
@@ -414,6 +418,8 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
414
418
|
return '}';
|
|
415
419
|
case EnumToken.StartParensTokenType:
|
|
416
420
|
return '(';
|
|
421
|
+
case EnumToken.DelimTokenType:
|
|
422
|
+
return '=';
|
|
417
423
|
case EnumToken.IncludeMatchTokenType:
|
|
418
424
|
return '~=';
|
|
419
425
|
case EnumToken.DashMatchTokenType:
|
|
@@ -428,7 +434,12 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
428
434
|
return '<';
|
|
429
435
|
case EnumToken.LteTokenType:
|
|
430
436
|
return '<=';
|
|
437
|
+
case EnumToken.SubsequentSiblingCombinatorTokenType:
|
|
438
|
+
return '~';
|
|
439
|
+
case EnumToken.NextSiblingCombinatorTokenType:
|
|
440
|
+
return '+';
|
|
431
441
|
case EnumToken.GtTokenType:
|
|
442
|
+
case EnumToken.ChildCombinatorTokenType:
|
|
432
443
|
return '>';
|
|
433
444
|
case EnumToken.GteTokenType:
|
|
434
445
|
return '>=';
|
|
@@ -440,6 +451,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
440
451
|
return '[';
|
|
441
452
|
case EnumToken.AttrEndTokenType:
|
|
442
453
|
return ']';
|
|
454
|
+
case EnumToken.DescendantCombinatorTokenType:
|
|
443
455
|
case EnumToken.WhitespaceTokenType:
|
|
444
456
|
return ' ';
|
|
445
457
|
case EnumToken.ColonTokenType:
|
|
@@ -571,12 +583,20 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
571
583
|
}
|
|
572
584
|
case EnumToken.HashTokenType:
|
|
573
585
|
case EnumToken.IdenTokenType:
|
|
574
|
-
case EnumToken.DelimTokenType:
|
|
575
586
|
case EnumToken.AtRuleTokenType:
|
|
576
587
|
case EnumToken.StringTokenType:
|
|
577
588
|
case EnumToken.LiteralTokenType:
|
|
578
589
|
case EnumToken.DashedIdenTokenType:
|
|
590
|
+
case EnumToken.ClassSelectorTokenType:
|
|
579
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)}`);
|
|
580
600
|
}
|
|
581
601
|
errors?.push({ action: 'ignore', message: `render: unexpected token ${JSON.stringify(token, null, 1)}` });
|
|
582
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 };
|