@tbela99/css-parser 0.8.0 → 0.9.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/.editorconfig +484 -0
- package/README.md +5 -3
- package/dist/index-umd-web.js +3272 -1898
- package/dist/index.cjs +3272 -1898
- package/dist/index.d.ts +48 -11
- package/dist/lib/ast/expand.js +14 -2
- package/dist/lib/ast/math/expression.js +1 -1
- package/dist/lib/ast/minify.js +30 -16
- package/dist/lib/ast/types.js +1 -0
- package/dist/lib/ast/walk.js +12 -0
- package/dist/lib/parser/declaration/map.js +59 -52
- package/dist/lib/parser/declaration/set.js +0 -12
- package/dist/lib/parser/parse.js +140 -101
- package/dist/lib/parser/tokenize.js +15 -3
- package/dist/lib/renderer/color/hex.js +1 -1
- package/dist/lib/renderer/color/hsl.js +1 -1
- package/dist/lib/renderer/color/hwb.js +2 -2
- package/dist/lib/renderer/color/lab.js +1 -1
- package/dist/lib/renderer/color/lch.js +1 -1
- package/dist/lib/renderer/color/oklab.js +2 -2
- package/dist/lib/renderer/color/oklch.js +1 -1
- package/dist/lib/renderer/color/p3.js +1 -1
- package/dist/lib/renderer/color/prophotoRgb.js +1 -1
- package/dist/lib/renderer/color/prophotorgb.js +1 -1
- package/dist/lib/renderer/color/rgb.js +1 -1
- package/dist/lib/renderer/color/srgb.js +2 -2
- package/dist/lib/renderer/color/utils/constants.js +1 -1
- package/dist/lib/renderer/color/xyz.js +1 -1
- package/dist/lib/renderer/render.js +34 -6
- package/dist/lib/syntax/syntax.js +336 -1
- package/dist/lib/validation/at-rules/container.js +353 -0
- package/dist/lib/validation/at-rules/counter-style.js +2 -2
- package/dist/lib/validation/at-rules/custom-media.js +52 -0
- package/dist/lib/validation/at-rules/else.js +5 -0
- package/dist/lib/validation/at-rules/font-feature-values.js +3 -0
- package/dist/lib/validation/at-rules/import.js +3 -0
- package/dist/lib/validation/at-rules/layer.js +3 -0
- package/dist/lib/validation/at-rules/media.js +117 -29
- package/dist/lib/validation/at-rules/supports.js +11 -11
- package/dist/lib/validation/at-rules/when.js +178 -0
- package/dist/lib/validation/atrule.js +25 -10
- package/dist/lib/validation/config.js +20 -15
- package/dist/lib/validation/config.json.js +162 -42
- package/dist/lib/validation/declaration.js +39 -9
- package/dist/lib/validation/parser/parse.js +91 -13
- package/dist/lib/validation/parser/types.js +1 -0
- package/dist/lib/validation/selector.js +6 -3
- package/dist/lib/validation/syntax.js +50 -4
- package/dist/lib/validation/syntaxes/complex-selector-list.js +16 -12
- package/dist/lib/validation/syntaxes/complex-selector.js +17 -247
- package/dist/lib/validation/syntaxes/compound-selector.js +226 -0
- package/dist/lib/validation/syntaxes/image.js +29 -0
- package/dist/lib/validation/syntaxes/keyframe-block-list.js +1 -1
- package/dist/lib/validation/syntaxes/keyframe-selector.js +1 -1
- package/dist/lib/validation/syntaxes/relative-selector-list.js +43 -13
- package/dist/lib/validation/utils/list.js +2 -2
- package/dist/node/index.js +1 -1
- package/dist/web/index.js +1 -1
- package/package.json +7 -7
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { ValidationTokenEnum } from './types.js';
|
|
2
2
|
import { isIdent, isPseudo } from '../../syntax/syntax.js';
|
|
3
3
|
|
|
4
|
+
var WalkValidationTokenEnum;
|
|
5
|
+
(function (WalkValidationTokenEnum) {
|
|
6
|
+
WalkValidationTokenEnum[WalkValidationTokenEnum["IgnoreChildren"] = 0] = "IgnoreChildren";
|
|
7
|
+
WalkValidationTokenEnum[WalkValidationTokenEnum["IgnoreNode"] = 1] = "IgnoreNode";
|
|
8
|
+
WalkValidationTokenEnum[WalkValidationTokenEnum["IgnoreAll"] = 2] = "IgnoreAll";
|
|
9
|
+
})(WalkValidationTokenEnum || (WalkValidationTokenEnum = {}));
|
|
10
|
+
var WalkValidationTokenKeyTypeEnum;
|
|
11
|
+
(function (WalkValidationTokenKeyTypeEnum) {
|
|
12
|
+
WalkValidationTokenKeyTypeEnum["Array"] = "array";
|
|
13
|
+
WalkValidationTokenKeyTypeEnum["Children"] = "chi";
|
|
14
|
+
WalkValidationTokenKeyTypeEnum["Left"] = "l";
|
|
15
|
+
WalkValidationTokenKeyTypeEnum["Right"] = "r";
|
|
16
|
+
WalkValidationTokenKeyTypeEnum["Prelude"] = "prelude";
|
|
17
|
+
})(WalkValidationTokenKeyTypeEnum || (WalkValidationTokenKeyTypeEnum = {}));
|
|
4
18
|
const skipped = [
|
|
5
19
|
ValidationTokenEnum.Star,
|
|
6
20
|
ValidationTokenEnum.HashMark,
|
|
@@ -167,13 +181,66 @@ function* tokenize(syntax, position = { ind: 0, lin: 1, col: 0 }, currentPositio
|
|
|
167
181
|
yield getTokenType(buffer, position, currentPosition);
|
|
168
182
|
}
|
|
169
183
|
}
|
|
184
|
+
function columnCallback(token, parent, key) {
|
|
185
|
+
if (key == WalkValidationTokenKeyTypeEnum.Prelude) {
|
|
186
|
+
return WalkValidationTokenEnum.IgnoreAll;
|
|
187
|
+
}
|
|
188
|
+
if (token.typ == ValidationTokenEnum.ColumnToken || token.typ == ValidationTokenEnum.Whitespace) {
|
|
189
|
+
return WalkValidationTokenEnum.IgnoreNode;
|
|
190
|
+
}
|
|
191
|
+
return WalkValidationTokenEnum.IgnoreChildren;
|
|
192
|
+
}
|
|
193
|
+
function toColumnArray(ast, parent) {
|
|
194
|
+
const result = new Map;
|
|
195
|
+
// @ts-ignore
|
|
196
|
+
for (const { token } of walkValidationToken(ast, null, columnCallback)) {
|
|
197
|
+
result.set(JSON.stringify(token), token);
|
|
198
|
+
}
|
|
199
|
+
const node = {
|
|
200
|
+
typ: ValidationTokenEnum.ColumnArrayToken,
|
|
201
|
+
chi: [...result.values()]
|
|
202
|
+
};
|
|
203
|
+
if (parent != null) {
|
|
204
|
+
replaceNode(parent, ast, node);
|
|
205
|
+
}
|
|
206
|
+
return node;
|
|
207
|
+
}
|
|
208
|
+
function replaceNode(parent, target, node) {
|
|
209
|
+
if ('l' in parent && parent.l == target) {
|
|
210
|
+
parent.l = node;
|
|
211
|
+
}
|
|
212
|
+
if ('r' in parent && parent.r == target) {
|
|
213
|
+
parent.r = node;
|
|
214
|
+
}
|
|
215
|
+
if ('chi' in parent) {
|
|
216
|
+
// @ts-ignore
|
|
217
|
+
for (let i = 0; i < parent.chi.length; i++) {
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
if (parent.chi[i] == target) {
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
parent.chi[i] = node;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function transform(context) {
|
|
228
|
+
for (const { token, parent } of walkValidationToken(context)) {
|
|
229
|
+
switch (token.typ) {
|
|
230
|
+
case ValidationTokenEnum.ColumnToken:
|
|
231
|
+
toColumnArray(token, parent);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return context;
|
|
236
|
+
}
|
|
170
237
|
function parseSyntax(syntax) {
|
|
171
238
|
const root = Object.defineProperty({
|
|
172
239
|
typ: ValidationTokenEnum.Root,
|
|
173
240
|
chi: []
|
|
174
241
|
}, 'pos', { ...objectProperties, value: { ind: 0, lin: 1, col: 0 } });
|
|
175
242
|
// return minify(doParseSyntax(syntaxes, tokenize(syntaxes), root)) as ValidationRootToken;
|
|
176
|
-
return minify(doParseSyntax(syntax, tokenize(syntax), root));
|
|
243
|
+
return minify(transform(doParseSyntax(syntax, tokenize(syntax), root)));
|
|
177
244
|
}
|
|
178
245
|
function matchParens(syntax, iterator) {
|
|
179
246
|
let item;
|
|
@@ -941,6 +1008,10 @@ function renderSyntax(token, parent) {
|
|
|
941
1008
|
(token.chi == null ? '' : ' {\n' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '')).slice(1, -1) + '\n}';
|
|
942
1009
|
case ValidationTokenEnum.Block:
|
|
943
1010
|
return '{' + token.chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}';
|
|
1011
|
+
case ValidationTokenEnum.DeclarationDefinitionToken:
|
|
1012
|
+
return token.nam + ': ' + renderSyntax(token.val);
|
|
1013
|
+
case ValidationTokenEnum.ColumnArrayToken:
|
|
1014
|
+
return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '||' : '') + renderSyntax(curr), '');
|
|
944
1015
|
default:
|
|
945
1016
|
throw new Error('Unhandled token: ' + JSON.stringify({ token }));
|
|
946
1017
|
}
|
|
@@ -1032,37 +1103,44 @@ function minify(ast) {
|
|
|
1032
1103
|
}
|
|
1033
1104
|
return ast;
|
|
1034
1105
|
}
|
|
1035
|
-
function* walkValidationToken(token, parent, callback) {
|
|
1106
|
+
function* walkValidationToken(token, parent, callback, key) {
|
|
1036
1107
|
if (Array.isArray(token)) {
|
|
1037
1108
|
for (const child of token) {
|
|
1038
|
-
yield* walkValidationToken(child, parent);
|
|
1109
|
+
yield* walkValidationToken(child, parent, callback, WalkValidationTokenKeyTypeEnum.Array);
|
|
1039
1110
|
}
|
|
1040
1111
|
return;
|
|
1041
1112
|
}
|
|
1042
|
-
|
|
1043
|
-
if (
|
|
1113
|
+
let action = null;
|
|
1114
|
+
if (callback != null) {
|
|
1115
|
+
// @ts-ignore
|
|
1116
|
+
action = callback(token, parent, key);
|
|
1117
|
+
}
|
|
1118
|
+
if (action != WalkValidationTokenEnum.IgnoreNode && action != WalkValidationTokenEnum.IgnoreAll) {
|
|
1119
|
+
yield { token, parent };
|
|
1120
|
+
}
|
|
1121
|
+
if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'prelude' in token) {
|
|
1044
1122
|
for (const child of token.prelude) {
|
|
1045
|
-
yield* walkValidationToken(child, token);
|
|
1123
|
+
yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Prelude);
|
|
1046
1124
|
}
|
|
1047
1125
|
}
|
|
1048
|
-
if ('chi' in token) {
|
|
1126
|
+
if (action != WalkValidationTokenEnum.IgnoreChildren && 'chi' in token) {
|
|
1049
1127
|
// @ts-ignore
|
|
1050
1128
|
for (const child of token.chi) {
|
|
1051
|
-
yield* walkValidationToken(child, token);
|
|
1129
|
+
yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Children);
|
|
1052
1130
|
}
|
|
1053
1131
|
}
|
|
1054
|
-
if ('l' in token) {
|
|
1132
|
+
if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'l' in token) {
|
|
1055
1133
|
// @ts-ignore
|
|
1056
1134
|
for (const child of token.l) {
|
|
1057
|
-
yield* walkValidationToken(child, token);
|
|
1135
|
+
yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Left);
|
|
1058
1136
|
}
|
|
1059
1137
|
}
|
|
1060
|
-
if ('r' in token) {
|
|
1138
|
+
if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'r' in token) {
|
|
1061
1139
|
// @ts-ignore
|
|
1062
1140
|
for (const child of token.r) {
|
|
1063
|
-
yield* walkValidationToken(child, token);
|
|
1141
|
+
yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Right);
|
|
1064
1142
|
}
|
|
1065
1143
|
}
|
|
1066
1144
|
}
|
|
1067
1145
|
|
|
1068
|
-
export { parseSyntax, renderSyntax, walkValidationToken };
|
|
1146
|
+
export { WalkValidationTokenEnum, WalkValidationTokenKeyTypeEnum, parseSyntax, renderSyntax, walkValidationToken };
|
|
@@ -41,6 +41,7 @@ var ValidationTokenEnum;
|
|
|
41
41
|
ValidationTokenEnum[ValidationTokenEnum["DeclarationDefinitionToken"] = 37] = "DeclarationDefinitionToken";
|
|
42
42
|
ValidationTokenEnum[ValidationTokenEnum["SemiColon"] = 38] = "SemiColon";
|
|
43
43
|
ValidationTokenEnum[ValidationTokenEnum["Character"] = 39] = "Character";
|
|
44
|
+
ValidationTokenEnum[ValidationTokenEnum["ColumnArrayToken"] = 40] = "ColumnArrayToken";
|
|
44
45
|
})(ValidationTokenEnum || (ValidationTokenEnum = {}));
|
|
45
46
|
var ValidationSyntaxGroupEnum;
|
|
46
47
|
(function (ValidationSyntaxGroupEnum) {
|
|
@@ -8,11 +8,14 @@ import '../parser/utils/config.js';
|
|
|
8
8
|
import { validateRelativeSelectorList } from './syntaxes/relative-selector-list.js';
|
|
9
9
|
import './syntaxes/complex-selector.js';
|
|
10
10
|
import { validateKeyframeBlockList } from './syntaxes/keyframe-block-list.js';
|
|
11
|
+
import './parser/types.js';
|
|
12
|
+
import './parser/parse.js';
|
|
13
|
+
import './config.js';
|
|
11
14
|
import { validateSelectorList } from './syntaxes/selector-list.js';
|
|
12
15
|
|
|
13
16
|
function validateSelector(selector, options, root) {
|
|
14
17
|
if (root == null) {
|
|
15
|
-
return
|
|
18
|
+
return validateSelectorList(selector, root, options);
|
|
16
19
|
}
|
|
17
20
|
// @ts-ignore
|
|
18
21
|
if (root.typ == EnumToken.AtRuleNodeType && root.nam.match(/^(-[a-z]+-)?keyframes$/)) {
|
|
@@ -25,14 +28,14 @@ function validateSelector(selector, options, root) {
|
|
|
25
28
|
isNested++;
|
|
26
29
|
if (isNested > 0) {
|
|
27
30
|
// @ts-ignore
|
|
28
|
-
return validateRelativeSelectorList(selector, root, { nestedSelector: true });
|
|
31
|
+
return validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector: true });
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
currentRoot = currentRoot.parent;
|
|
32
35
|
}
|
|
33
36
|
const nestedSelector = isNested > 0;
|
|
34
37
|
// @ts-ignore
|
|
35
|
-
return nestedSelector ? validateRelativeSelectorList(selector, root, { nestedSelector }) : validateSelectorList(selector, root, { nestedSelector });
|
|
38
|
+
return nestedSelector ? validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector }) : validateSelectorList(selector, root, { ...(options ?? {}), nestedSelector });
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
export { validateSelector };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ValidationTokenEnum, specialValues } from './parser/types.js';
|
|
2
|
-
import './parser/parse.js';
|
|
2
|
+
import { renderSyntax } from './parser/parse.js';
|
|
3
3
|
import { ValidationLevel, EnumToken, funcLike } from '../ast/types.js';
|
|
4
4
|
import '../ast/minify.js';
|
|
5
5
|
import '../ast/walk.js';
|
|
@@ -8,8 +8,10 @@ import { isLength } from '../syntax/syntax.js';
|
|
|
8
8
|
import '../parser/utils/config.js';
|
|
9
9
|
import '../renderer/color/utils/constants.js';
|
|
10
10
|
import '../renderer/sourcemap/lib/encode.js';
|
|
11
|
-
import {
|
|
11
|
+
import { getSyntaxConfig, getParsedSyntax } from './config.js';
|
|
12
12
|
import { validateSelector } from './selector.js';
|
|
13
|
+
import './syntaxes/complex-selector.js';
|
|
14
|
+
import { validateImage } from './syntaxes/image.js';
|
|
13
15
|
|
|
14
16
|
const config = getSyntaxConfig();
|
|
15
17
|
function consumeToken(tokens) {
|
|
@@ -30,6 +32,12 @@ function splice(tokens, matches) {
|
|
|
30
32
|
return tokens;
|
|
31
33
|
}
|
|
32
34
|
function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 }) {
|
|
35
|
+
console.error(JSON.stringify({
|
|
36
|
+
syntax: syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), ''),
|
|
37
|
+
syntaxes,
|
|
38
|
+
tokens,
|
|
39
|
+
s: new Error('bar').stack
|
|
40
|
+
}, null, 1));
|
|
33
41
|
if (syntaxes == null) {
|
|
34
42
|
// @ts-ignore
|
|
35
43
|
return {
|
|
@@ -485,7 +493,7 @@ function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 })
|
|
|
485
493
|
return result;
|
|
486
494
|
}
|
|
487
495
|
function isOptionalSyntax(syntaxes) {
|
|
488
|
-
return syntaxes.every(t => t.typ == ValidationTokenEnum.Whitespace || t.isOptional || t.isRepeatable || (t.typ == ValidationTokenEnum.PropertyType && isOptionalSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, t.val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, t.val))));
|
|
496
|
+
return syntaxes.length > 0 && syntaxes.every(t => t.typ == ValidationTokenEnum.Whitespace || t.isOptional || t.isRepeatable || (t.typ == ValidationTokenEnum.PropertyType && isOptionalSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, t.val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, t.val) ?? [])));
|
|
489
497
|
}
|
|
490
498
|
function doValidateSyntax(syntax, token, tokens, root, options, context) {
|
|
491
499
|
let valid = false;
|
|
@@ -706,7 +714,21 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
|
|
|
706
714
|
break;
|
|
707
715
|
case ValidationTokenEnum.PropertyType:
|
|
708
716
|
//
|
|
709
|
-
if (
|
|
717
|
+
if ('image' == syntax.val) {
|
|
718
|
+
valid = token.typ == EnumToken.UrlFunctionTokenType || token.typ == EnumToken.ImageFunctionTokenType;
|
|
719
|
+
if (!valid) {
|
|
720
|
+
return {
|
|
721
|
+
valid: ValidationLevel.Drop,
|
|
722
|
+
matches: [],
|
|
723
|
+
node: token,
|
|
724
|
+
syntax,
|
|
725
|
+
error: 'unexpected <image>',
|
|
726
|
+
tokens
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
result = validateImage(token);
|
|
730
|
+
}
|
|
731
|
+
else if (['media-feature', 'mf-plain'].includes(syntax.val)) {
|
|
710
732
|
valid = token.typ == EnumToken.DeclarationNodeType;
|
|
711
733
|
result = {
|
|
712
734
|
valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
|
|
@@ -751,6 +773,18 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
|
|
|
751
773
|
}
|
|
752
774
|
else if (syntax.val == 'group-rule-body') {
|
|
753
775
|
valid = [EnumToken.AtRuleNodeType, EnumToken.RuleNodeType].includes(token.typ);
|
|
776
|
+
if (!valid && token.typ == EnumToken.DeclarationNodeType && root?.typ == EnumToken.AtRuleNodeType && root.nam == 'media') {
|
|
777
|
+
// allowed only if nested rule
|
|
778
|
+
let parent = root;
|
|
779
|
+
while (parent != null) {
|
|
780
|
+
if (parent.typ == EnumToken.RuleNodeType) {
|
|
781
|
+
valid = true;
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
// @ts-ignore
|
|
785
|
+
parent = parent.parent;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
754
788
|
// @ts-ignore
|
|
755
789
|
result = {
|
|
756
790
|
valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
|
|
@@ -1419,6 +1453,18 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
|
|
|
1419
1453
|
tokens
|
|
1420
1454
|
};
|
|
1421
1455
|
break;
|
|
1456
|
+
case ValidationTokenEnum.DeclarationDefinitionToken:
|
|
1457
|
+
if (token.typ != EnumToken.DeclarationNodeType || token.nam != syntax.nam) {
|
|
1458
|
+
return {
|
|
1459
|
+
valid: ValidationLevel.Drop,
|
|
1460
|
+
matches: [],
|
|
1461
|
+
node: token,
|
|
1462
|
+
syntax,
|
|
1463
|
+
error: '',
|
|
1464
|
+
tokens
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
return validateSyntax([syntax.val], token.val, root, options, context);
|
|
1422
1468
|
default:
|
|
1423
1469
|
throw new Error('not implemented: ' + JSON.stringify({ syntax, token, tokens }, null, 1));
|
|
1424
1470
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ValidationLevel
|
|
1
|
+
import { ValidationLevel } from '../../ast/types.js';
|
|
2
2
|
import '../../ast/minify.js';
|
|
3
3
|
import '../../ast/walk.js';
|
|
4
4
|
import '../../parser/parse.js';
|
|
@@ -7,6 +7,7 @@ import '../../renderer/sourcemap/lib/encode.js';
|
|
|
7
7
|
import '../../parser/utils/config.js';
|
|
8
8
|
import { validateSelector } from './selector.js';
|
|
9
9
|
import { consumeWhitespace } from '../utils/whitespace.js';
|
|
10
|
+
import { splitTokenList } from '../utils/list.js';
|
|
10
11
|
|
|
11
12
|
function validateComplexSelectorList(tokens, root, options) {
|
|
12
13
|
tokens = tokens.slice();
|
|
@@ -22,20 +23,23 @@ function validateComplexSelectorList(tokens, root, options) {
|
|
|
22
23
|
tokens
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
|
-
let i = -1;
|
|
26
|
-
let j = 0;
|
|
27
26
|
let result = null;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
j = i + 1;
|
|
35
|
-
i = j;
|
|
27
|
+
for (const t of splitTokenList(tokens)) {
|
|
28
|
+
result = validateSelector(t, root, options);
|
|
29
|
+
if (result.valid == ValidationLevel.Drop) {
|
|
30
|
+
return result;
|
|
36
31
|
}
|
|
37
32
|
}
|
|
38
|
-
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
return result ?? {
|
|
35
|
+
valid: ValidationLevel.Drop,
|
|
36
|
+
matches: [],
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
node: root,
|
|
39
|
+
syntax: null,
|
|
40
|
+
error: 'expecting complex selector list',
|
|
41
|
+
tokens
|
|
42
|
+
};
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
export { validateComplexSelectorList };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { consumeWhitespace } from '../utils/whitespace.js';
|
|
2
|
+
import { splitTokenList } from '../utils/list.js';
|
|
2
3
|
import { EnumToken, ValidationLevel } from '../../ast/types.js';
|
|
3
4
|
import '../../ast/minify.js';
|
|
4
5
|
import '../../ast/walk.js';
|
|
@@ -6,9 +7,11 @@ import '../../parser/parse.js';
|
|
|
6
7
|
import '../../renderer/color/utils/constants.js';
|
|
7
8
|
import '../../renderer/sourcemap/lib/encode.js';
|
|
8
9
|
import '../../parser/utils/config.js';
|
|
10
|
+
import { validateCompoundSelector } from './compound-selector.js';
|
|
9
11
|
|
|
10
12
|
const combinatorsTokens = [EnumToken.ChildCombinatorTokenType, EnumToken.ColumnCombinatorTokenType,
|
|
11
|
-
EnumToken.DescendantCombinatorTokenType,
|
|
13
|
+
// EnumToken.DescendantCombinatorTokenType,
|
|
14
|
+
EnumToken.NextSiblingCombinatorTokenType, EnumToken.SubsequentSiblingCombinatorTokenType];
|
|
12
15
|
// <compound-selector> [ <combinator>? <compound-selector> ]*
|
|
13
16
|
function validateComplexSelector(tokens, root, options) {
|
|
14
17
|
// [ <type-selector>? <subclass-selector>* [ <pseudo-element-selector> <pseudo-class-selector>* ]* ]!
|
|
@@ -25,257 +28,24 @@ function validateComplexSelector(tokens, root, options) {
|
|
|
25
28
|
tokens
|
|
26
29
|
};
|
|
27
30
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
error: 'unexpected combinator',
|
|
38
|
-
tokens
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
if (tokens[0].typ == EnumToken.NestingSelectorTokenType) {
|
|
42
|
-
if (!options?.nestedSelector) {
|
|
43
|
-
// @ts-ignore
|
|
44
|
-
return {
|
|
45
|
-
valid: ValidationLevel.Drop,
|
|
46
|
-
matches: [],
|
|
47
|
-
// @ts-ignore
|
|
48
|
-
node: tokens[0],
|
|
49
|
-
syntax: null,
|
|
50
|
-
error: 'nested selector not allowed',
|
|
51
|
-
tokens
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
while (tokens.length > 0 && tokens[0].typ == EnumToken.NestingSelectorTokenType) {
|
|
55
|
-
tokens.shift();
|
|
56
|
-
consumeWhitespace(tokens);
|
|
57
|
-
}
|
|
58
|
-
if (tokens.length == 0) {
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (EnumToken.IdenTokenType == tokens[0].typ) {
|
|
63
|
-
tokens.shift();
|
|
64
|
-
consumeWhitespace(tokens);
|
|
65
|
-
if (tokens.length == 0) {
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (EnumToken.UniversalSelectorTokenType == tokens[0].typ) {
|
|
70
|
-
tokens.shift();
|
|
71
|
-
consumeWhitespace(tokens);
|
|
72
|
-
}
|
|
73
|
-
while (tokens.length > 0) {
|
|
74
|
-
if (tokens[0].typ == EnumToken.PseudoClassFuncTokenType) {
|
|
75
|
-
if (tokens[0].val.startsWith(':-webkit-')) {
|
|
76
|
-
// @ts-ignore
|
|
77
|
-
return {
|
|
78
|
-
valid: ValidationLevel.Drop,
|
|
79
|
-
matches: [],
|
|
80
|
-
// @ts-ignore
|
|
81
|
-
node: tokens[0],
|
|
82
|
-
syntax: null,
|
|
83
|
-
error: 'invalid pseudo-class',
|
|
84
|
-
tokens
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if ([
|
|
89
|
-
EnumToken.ClassSelectorTokenType,
|
|
90
|
-
EnumToken.HashTokenType,
|
|
91
|
-
EnumToken.PseudoClassTokenType,
|
|
92
|
-
EnumToken.PseudoClassFuncTokenType
|
|
93
|
-
].includes(tokens[0].typ)) {
|
|
94
|
-
tokens.shift();
|
|
95
|
-
consumeWhitespace(tokens);
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
if (tokens[0].typ == EnumToken.NestingSelectorTokenType) {
|
|
99
|
-
if (!options?.nestedSelector) {
|
|
100
|
-
// @ts-ignore
|
|
101
|
-
return {
|
|
102
|
-
valid: ValidationLevel.Drop,
|
|
103
|
-
matches: [],
|
|
104
|
-
// @ts-ignore
|
|
105
|
-
node: tokens[0],
|
|
106
|
-
syntax: null,
|
|
107
|
-
error: 'nested selector not allowed',
|
|
108
|
-
tokens
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
tokens.shift();
|
|
112
|
-
consumeWhitespace(tokens);
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
// validate namespace
|
|
116
|
-
if (tokens[0].typ == EnumToken.NameSpaceAttributeTokenType) {
|
|
117
|
-
if (!((tokens[0].l == null || tokens[0].l.typ == EnumToken.IdenTokenType || (tokens[0].l.typ == EnumToken.LiteralTokenType && tokens[0].l.val == '*')) &&
|
|
118
|
-
tokens[0].r.typ == EnumToken.IdenTokenType)) {
|
|
119
|
-
// @ts-ignore
|
|
120
|
-
return {
|
|
121
|
-
valid: ValidationLevel.Drop,
|
|
122
|
-
matches: [],
|
|
123
|
-
node: tokens[0],
|
|
124
|
-
syntax: null,
|
|
125
|
-
error: 'expecting wq-name',
|
|
126
|
-
tokens
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
tokens.shift();
|
|
130
|
-
consumeWhitespace(tokens);
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
// validate attribute
|
|
134
|
-
else if (tokens[0].typ == EnumToken.AttrTokenType) {
|
|
135
|
-
const children = tokens[0].chi.slice();
|
|
136
|
-
consumeWhitespace(children);
|
|
137
|
-
if (children.length == 0) {
|
|
138
|
-
// @ts-ignore
|
|
139
|
-
return {
|
|
140
|
-
valid: ValidationLevel.Drop,
|
|
141
|
-
matches: [],
|
|
142
|
-
node: tokens[0],
|
|
143
|
-
syntax: null,
|
|
144
|
-
error: 'invalid attribute selector',
|
|
145
|
-
tokens
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
if (![
|
|
149
|
-
EnumToken.IdenTokenType,
|
|
150
|
-
EnumToken.NameSpaceAttributeTokenType,
|
|
151
|
-
EnumToken.MatchExpressionTokenType
|
|
152
|
-
].includes(children[0].typ)) {
|
|
153
|
-
// @ts-ignore
|
|
154
|
-
return {
|
|
155
|
-
valid: ValidationLevel.Drop,
|
|
156
|
-
matches: [],
|
|
157
|
-
node: tokens[0],
|
|
158
|
-
syntax: null,
|
|
159
|
-
error: 'invalid attribute selector',
|
|
160
|
-
tokens
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
if (children[0].typ == EnumToken.MatchExpressionTokenType) {
|
|
164
|
-
if (![EnumToken.IdenTokenType,
|
|
165
|
-
EnumToken.NameSpaceAttributeTokenType].includes(children[0].l.typ) ||
|
|
166
|
-
![
|
|
167
|
-
EnumToken.EqualMatchTokenType, EnumToken.DashMatchTokenType,
|
|
168
|
-
EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType,
|
|
169
|
-
EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType
|
|
170
|
-
].includes(children[0].op.typ) ||
|
|
171
|
-
![EnumToken.StringTokenType,
|
|
172
|
-
EnumToken.IdenTokenType].includes(children[0].r.typ)) {
|
|
173
|
-
// @ts-ignore
|
|
174
|
-
return {
|
|
175
|
-
valid: ValidationLevel.Drop,
|
|
176
|
-
matches: [],
|
|
177
|
-
node: tokens[0],
|
|
178
|
-
syntax: null,
|
|
179
|
-
error: 'invalid attribute selector',
|
|
180
|
-
tokens
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
if (children[0].attr != null && !['i', 's'].includes(children[0].attr)) {
|
|
184
|
-
// @ts-ignore
|
|
185
|
-
return {
|
|
186
|
-
valid: ValidationLevel.Drop,
|
|
187
|
-
matches: [],
|
|
188
|
-
node: tokens[0],
|
|
189
|
-
syntax: null,
|
|
190
|
-
error: 'invalid attribute selector',
|
|
191
|
-
tokens
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
children.shift();
|
|
196
|
-
consumeWhitespace(children);
|
|
197
|
-
if (children.length > 0) {
|
|
198
|
-
// @ts-ignore
|
|
199
|
-
return {
|
|
200
|
-
valid: ValidationLevel.Drop,
|
|
201
|
-
matches: [],
|
|
202
|
-
node: children[0],
|
|
203
|
-
syntax: null,
|
|
204
|
-
error: 'unexpected token',
|
|
205
|
-
tokens
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
tokens.shift();
|
|
209
|
-
consumeWhitespace(tokens);
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
if (tokens.length == 0) {
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
// combinator
|
|
218
|
-
if (!combinatorsTokens.includes(tokens[0].typ)) {
|
|
219
|
-
if (tokens[0].typ == EnumToken.NestingSelectorTokenType) {
|
|
220
|
-
if (!options?.nestedSelector) {
|
|
221
|
-
// @ts-ignore
|
|
222
|
-
return {
|
|
223
|
-
valid: ValidationLevel.Drop,
|
|
224
|
-
matches: [],
|
|
225
|
-
// @ts-ignore
|
|
226
|
-
node: tokens[0],
|
|
227
|
-
syntax: null,
|
|
228
|
-
error: 'nested selector not allowed',
|
|
229
|
-
tokens
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
tokens.shift();
|
|
233
|
-
consumeWhitespace(tokens);
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
if (tokens.length > 0 &&
|
|
237
|
-
[
|
|
238
|
-
EnumToken.IdenTokenType,
|
|
239
|
-
EnumToken.AttrTokenType,
|
|
240
|
-
EnumToken.NameSpaceAttributeTokenType,
|
|
241
|
-
EnumToken.ClassSelectorTokenType,
|
|
242
|
-
EnumToken.HashTokenType,
|
|
243
|
-
EnumToken.PseudoClassTokenType,
|
|
244
|
-
EnumToken.PseudoClassFuncTokenType
|
|
245
|
-
].includes(tokens[0].typ)) {
|
|
246
|
-
continue;
|
|
247
|
-
}
|
|
248
|
-
// @ts-ignore
|
|
249
|
-
return {
|
|
250
|
-
valid: ValidationLevel.Drop,
|
|
251
|
-
matches: [],
|
|
252
|
-
node: tokens[0],
|
|
253
|
-
syntax: null,
|
|
254
|
-
error: 'expecting combinator or subclass-selector',
|
|
255
|
-
tokens
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
const token = tokens.shift();
|
|
259
|
-
consumeWhitespace(tokens);
|
|
260
|
-
if (tokens.length == 0) {
|
|
261
|
-
// @ts-ignore
|
|
262
|
-
return {
|
|
263
|
-
valid: ValidationLevel.Drop,
|
|
264
|
-
matches: [],
|
|
265
|
-
node: token,
|
|
266
|
-
syntax: null,
|
|
267
|
-
error: 'expected compound-selector',
|
|
268
|
-
tokens
|
|
269
|
-
};
|
|
31
|
+
// const config = getSyntaxConfig();
|
|
32
|
+
//
|
|
33
|
+
// let match: number = 0;
|
|
34
|
+
let result = null;
|
|
35
|
+
// const combinators: EnumToken[] = combinatorsTokens.filter((t: EnumToken) => t != EnumToken.DescendantCombinatorTokenType);
|
|
36
|
+
for (const t of splitTokenList(tokens, combinatorsTokens)) {
|
|
37
|
+
result = validateCompoundSelector(t, root, options);
|
|
38
|
+
if (result.valid == ValidationLevel.Drop) {
|
|
39
|
+
return result;
|
|
270
40
|
}
|
|
271
41
|
}
|
|
272
42
|
// @ts-ignore
|
|
273
|
-
return {
|
|
274
|
-
valid: ValidationLevel.
|
|
43
|
+
return result ?? {
|
|
44
|
+
valid: ValidationLevel.Drop,
|
|
275
45
|
matches: [],
|
|
276
|
-
node:
|
|
46
|
+
node: root,
|
|
277
47
|
syntax: null,
|
|
278
|
-
error: '',
|
|
48
|
+
error: 'expecting compound-selector',
|
|
279
49
|
tokens
|
|
280
50
|
};
|
|
281
51
|
}
|