@tbela99/css-parser 1.3.4 → 1.4.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/CHANGELOG.md +37 -0
- package/README.md +44 -31
- package/dist/config.json.js +3 -0
- package/dist/index-umd-web.js +1247 -72
- package/dist/index.cjs +1258 -72
- package/dist/index.d.ts +282 -17
- package/dist/lib/ast/features/type.js +1 -1
- package/dist/lib/ast/minify.js +1 -1
- package/dist/lib/ast/types.js +62 -3
- package/dist/lib/ast/walk.js +16 -9
- package/dist/lib/fs/resolve.js +63 -7
- package/dist/lib/parser/declaration/list.js +4 -1
- package/dist/lib/parser/parse.js +830 -13
- package/dist/lib/parser/tokenize.js +22 -7
- package/dist/lib/parser/utils/declaration.js +54 -0
- package/dist/lib/parser/utils/hash.js +86 -0
- package/dist/lib/parser/utils/text.js +8 -0
- package/dist/lib/renderer/render.js +25 -6
- package/dist/lib/syntax/color/relativecolor.js +0 -3
- package/dist/lib/validation/config.json.js +15 -3
- package/dist/lib/validation/syntax.js +6 -1
- package/dist/lib/validation/syntaxes/compound-selector.js +1 -2
- package/dist/lib/validation/syntaxes/relative-selector-list.js +2 -5
- package/dist/node.js +48 -11
- package/dist/types.d.ts +17 -0
- package/dist/types.js +20 -0
- package/dist/web.js +35 -9
- package/package.json +16 -16
package/dist/lib/parser/parse.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, parseDimension, isHexColor, isHash, mediaTypes } from '../syntax/syntax.js';
|
|
2
|
-
import { EnumToken, ColorType, ValidationLevel, SyntaxValidationResult } from '../ast/types.js';
|
|
2
|
+
import { EnumToken, ColorType, ValidationLevel, ModuleCaseTransformEnum, ModuleScopeEnumOptions, SyntaxValidationResult } from '../ast/types.js';
|
|
3
3
|
import { definedPropertySettings, minify, combinators } from '../ast/minify.js';
|
|
4
4
|
import { walkValues, WalkerEvent, walk, WalkerOptionEnum } from '../ast/walk.js';
|
|
5
5
|
import { expand } from '../ast/expand.js';
|
|
6
6
|
import './utils/config.js';
|
|
7
7
|
import { parseDeclarationNode } from './utils/declaration.js';
|
|
8
|
+
import { camelize, dasherize } from './utils/text.js';
|
|
8
9
|
import { renderToken } from '../renderer/render.js';
|
|
9
10
|
import '../renderer/sourcemap/lib/encode.js';
|
|
10
11
|
import { funcLike, timingFunc, timelineFunc, COLORS_NAMES, systemColors, deprecatedSystemColors, colorsFunc } from '../syntax/color/utils/constants.js';
|
|
@@ -19,6 +20,7 @@ import '../validation/syntaxes/complex-selector.js';
|
|
|
19
20
|
import { validateKeyframeSelector } from '../validation/syntaxes/keyframe-selector.js';
|
|
20
21
|
import { isNodeAllowedInContext, evaluateSyntax } from '../validation/syntax.js';
|
|
21
22
|
import { validateAtRuleKeyframes } from '../validation/at-rules/keyframes.js';
|
|
23
|
+
import { hashAlgorithms, hash } from './utils/hash.js';
|
|
22
24
|
|
|
23
25
|
const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
|
|
24
26
|
const trimWhiteSpace = [EnumToken.CommentTokenType, EnumToken.GtTokenType, EnumToken.GteTokenType, EnumToken.LtTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType];
|
|
@@ -38,9 +40,12 @@ const enumTokenHints = new Set([
|
|
|
38
40
|
function reject(reason) {
|
|
39
41
|
throw new Error(reason ?? 'Parsing aborted');
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
/**
|
|
44
|
+
* replace token in its parent node
|
|
45
|
+
* @param parent
|
|
46
|
+
* @param value
|
|
47
|
+
* @param replacement
|
|
48
|
+
*/
|
|
44
49
|
function replaceToken(parent, value, replacement) {
|
|
45
50
|
for (const node of (Array.isArray(replacement) ? replacement : [replacement])) {
|
|
46
51
|
if ('parent' in value && value.parent != node.parent) {
|
|
@@ -68,11 +73,129 @@ function replaceToken(parent, value, replacement) {
|
|
|
68
73
|
target.splice(index, 1, ...(Array.isArray(replacement) ? replacement : [replacement]));
|
|
69
74
|
}
|
|
70
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* transform case of key name
|
|
78
|
+
* @param key
|
|
79
|
+
* @param how
|
|
80
|
+
*
|
|
81
|
+
* @throws Error
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
function getKeyName(key, how) {
|
|
85
|
+
switch (how) {
|
|
86
|
+
case ModuleCaseTransformEnum.CamelCase:
|
|
87
|
+
case ModuleCaseTransformEnum.CamelCaseOnly:
|
|
88
|
+
return camelize(key);
|
|
89
|
+
case ModuleCaseTransformEnum.DashCase:
|
|
90
|
+
case ModuleCaseTransformEnum.DashCaseOnly:
|
|
91
|
+
return dasherize(key);
|
|
92
|
+
}
|
|
93
|
+
return key;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* generate scoped name
|
|
97
|
+
* @param localName
|
|
98
|
+
* @param filePath
|
|
99
|
+
* @param pattern
|
|
100
|
+
* @param hashLength
|
|
101
|
+
*
|
|
102
|
+
* @throws Error
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
async function generateScopedName(localName, filePath, pattern, hashLength = 5) {
|
|
106
|
+
if (localName.startsWith('--')) {
|
|
107
|
+
localName = localName.slice(2);
|
|
108
|
+
}
|
|
109
|
+
const matches = /.*?(([^/]+)\/)?([^/\\]*?)(\.([^?/]+))?([?].*)?$/.exec(filePath);
|
|
110
|
+
const folder = matches?.[2]?.replace?.(/[^A-Za-z0-9_-]/g, "_") ?? '';
|
|
111
|
+
const fileBase = matches?.[3] ?? '';
|
|
112
|
+
const ext = matches?.[5] ?? '';
|
|
113
|
+
const path = filePath.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
114
|
+
// sanitize localName for safe char set (replace spaces/illegal chars)
|
|
115
|
+
const safeLocal = localName.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
116
|
+
const hashString = `${localName}::${filePath}`;
|
|
117
|
+
let result = '';
|
|
118
|
+
let inParens = 0;
|
|
119
|
+
let key = '';
|
|
120
|
+
let position = 0;
|
|
121
|
+
// Compose final scoped name. Ensure the entire class doesn't start with digit:
|
|
122
|
+
for (const char of pattern) {
|
|
123
|
+
position += char.length;
|
|
124
|
+
if (char == '[') {
|
|
125
|
+
inParens++;
|
|
126
|
+
if (inParens != 1) {
|
|
127
|
+
throw new Error(`Unexpected character: '${char} at position ${position - 1}' in pattern '${pattern}'`);
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (char == ']') {
|
|
132
|
+
inParens--;
|
|
133
|
+
if (inParens != 0) {
|
|
134
|
+
throw new Error(`Unexpected character: '${char}:${position - 1}'`);
|
|
135
|
+
}
|
|
136
|
+
let hashAlgo = null;
|
|
137
|
+
let length = null;
|
|
138
|
+
if (key.includes(':')) {
|
|
139
|
+
const parts = key.split(':');
|
|
140
|
+
if (parts.length == 2) {
|
|
141
|
+
// @ts-ignore
|
|
142
|
+
[key, length] = parts;
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
if (key == 'hash' && hashAlgorithms.includes(length)) {
|
|
145
|
+
// @ts-ignore
|
|
146
|
+
hashAlgo = length;
|
|
147
|
+
length = null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (parts.length == 3) {
|
|
151
|
+
// @ts-ignore
|
|
152
|
+
[key, hashAlgo, length] = parts;
|
|
153
|
+
}
|
|
154
|
+
if (length != null && !Number.isInteger(+length)) {
|
|
155
|
+
throw new Error(`Unsupported hash length: '${length}'. expecting format [hash:length] or [hash:hash-algo:length]`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
switch (key) {
|
|
159
|
+
case 'hash':
|
|
160
|
+
result += await hash(hashString, length ?? hashLength, hashAlgo);
|
|
161
|
+
break;
|
|
162
|
+
case 'name':
|
|
163
|
+
result += length != null ? fileBase.slice(0, +length) : fileBase;
|
|
164
|
+
break;
|
|
165
|
+
case 'local':
|
|
166
|
+
result += length != null ? safeLocal.slice(0, +length) : localName;
|
|
167
|
+
break;
|
|
168
|
+
case 'ext':
|
|
169
|
+
result += length != null ? ext.slice(0, +length) : ext;
|
|
170
|
+
break;
|
|
171
|
+
case 'path':
|
|
172
|
+
result += length != null ? path.slice(0, +length) : path;
|
|
173
|
+
break;
|
|
174
|
+
case 'folder':
|
|
175
|
+
result += length != null ? folder.slice(0, +length) : folder;
|
|
176
|
+
break;
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(`Unsupported key: '${key}'`);
|
|
179
|
+
}
|
|
180
|
+
key = '';
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (inParens > 0) {
|
|
184
|
+
key += char;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
result += char;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// if leading char is digit, prefix underscore (very rare)
|
|
191
|
+
return (/^[0-9]/.test(result) ? '_' : '') + result;
|
|
192
|
+
}
|
|
71
193
|
/**
|
|
72
194
|
* parse css string
|
|
73
195
|
* @param iter
|
|
74
196
|
* @param options
|
|
75
197
|
*
|
|
198
|
+
* @throws Error
|
|
76
199
|
* @private
|
|
77
200
|
*/
|
|
78
201
|
async function doParse(iter, options = {}) {
|
|
@@ -104,6 +227,9 @@ async function doParse(iter, options = {}) {
|
|
|
104
227
|
if (typeof options.validation == 'boolean') {
|
|
105
228
|
options.validation = options.validation ? ValidationLevel.All : ValidationLevel.None;
|
|
106
229
|
}
|
|
230
|
+
if (options.module) {
|
|
231
|
+
options.expandNestingRules = true;
|
|
232
|
+
}
|
|
107
233
|
if (options.expandNestingRules) {
|
|
108
234
|
options.nestingRules = false;
|
|
109
235
|
}
|
|
@@ -369,6 +495,7 @@ async function doParse(iter, options = {}) {
|
|
|
369
495
|
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
370
496
|
stream,
|
|
371
497
|
buffer: '',
|
|
498
|
+
offset: 0,
|
|
372
499
|
position: { ind: 0, lin: 1, col: 1 },
|
|
373
500
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
374
501
|
}), Object.assign({}, options, {
|
|
@@ -428,7 +555,7 @@ async function doParse(iter, options = {}) {
|
|
|
428
555
|
}
|
|
429
556
|
let node = result.node;
|
|
430
557
|
for (const handler of handlers) {
|
|
431
|
-
callable = typeof handler == 'function' ? handler : handler[
|
|
558
|
+
callable = typeof handler == 'function' ? handler : handler[camelize(node.typ == EnumToken.DeclarationNodeType || node.typ == EnumToken.AtRuleNodeType ? node.nam : node.val)];
|
|
432
559
|
if (callable == null) {
|
|
433
560
|
continue;
|
|
434
561
|
}
|
|
@@ -563,12 +690,9 @@ async function doParse(iter, options = {}) {
|
|
|
563
690
|
}
|
|
564
691
|
}
|
|
565
692
|
}
|
|
566
|
-
const endTime = performance.now();
|
|
567
|
-
if (options.signal != null) {
|
|
568
|
-
options.signal.removeEventListener('abort', reject);
|
|
569
|
-
}
|
|
570
693
|
stats.bytesIn += stats.importedBytesIn;
|
|
571
|
-
|
|
694
|
+
let endTime = performance.now();
|
|
695
|
+
const result = {
|
|
572
696
|
ast,
|
|
573
697
|
errors,
|
|
574
698
|
stats: {
|
|
@@ -578,6 +702,503 @@ async function doParse(iter, options = {}) {
|
|
|
578
702
|
total: `${(endTime - startTime).toFixed(2)}ms`
|
|
579
703
|
}
|
|
580
704
|
};
|
|
705
|
+
if (options.module) {
|
|
706
|
+
const moduleSettings = {
|
|
707
|
+
hashLength: 5,
|
|
708
|
+
filePath: '',
|
|
709
|
+
scoped: ModuleScopeEnumOptions.Local,
|
|
710
|
+
naming: ModuleCaseTransformEnum.IgnoreCase,
|
|
711
|
+
pattern: '',
|
|
712
|
+
generateScopedName,
|
|
713
|
+
...(typeof options.module != 'object' ? {} : options.module)
|
|
714
|
+
};
|
|
715
|
+
const parseModuleTime = performance.now();
|
|
716
|
+
const namesMapping = {};
|
|
717
|
+
const global = new Set;
|
|
718
|
+
const processed = new Set;
|
|
719
|
+
const pattern = typeof options.module == 'boolean' ? null : moduleSettings.pattern;
|
|
720
|
+
const importMapping = {};
|
|
721
|
+
const cssVariablesMap = {};
|
|
722
|
+
const importedCssVariables = {};
|
|
723
|
+
let mapping = {};
|
|
724
|
+
let revMapping = {};
|
|
725
|
+
let filePath = typeof options.module == 'boolean' ? options.src : (moduleSettings.filePath ?? options.src);
|
|
726
|
+
filePath = filePath === '' ? options.src : options.resolve(filePath, options.dirname(options.src), options.cwd).relative;
|
|
727
|
+
if (typeof options.module == 'number') {
|
|
728
|
+
if (options.module & ModuleCaseTransformEnum.CamelCase) {
|
|
729
|
+
moduleSettings.naming = ModuleCaseTransformEnum.CamelCase;
|
|
730
|
+
}
|
|
731
|
+
else if (options.module & ModuleCaseTransformEnum.CamelCaseOnly) {
|
|
732
|
+
moduleSettings.naming = ModuleCaseTransformEnum.CamelCaseOnly;
|
|
733
|
+
}
|
|
734
|
+
else if (options.module & ModuleCaseTransformEnum.DashCase) {
|
|
735
|
+
moduleSettings.naming = ModuleCaseTransformEnum.DashCase;
|
|
736
|
+
}
|
|
737
|
+
else if (options.module & ModuleCaseTransformEnum.DashCaseOnly) {
|
|
738
|
+
moduleSettings.naming = ModuleCaseTransformEnum.DashCaseOnly;
|
|
739
|
+
}
|
|
740
|
+
if (options.module & ModuleScopeEnumOptions.Global) {
|
|
741
|
+
moduleSettings.scoped = ModuleScopeEnumOptions.Global;
|
|
742
|
+
}
|
|
743
|
+
if (options.module & ModuleScopeEnumOptions.Pure) {
|
|
744
|
+
// @ts-ignore
|
|
745
|
+
moduleSettings.scoped |= ModuleScopeEnumOptions.Pure;
|
|
746
|
+
}
|
|
747
|
+
if (options.module & ModuleScopeEnumOptions.ICSS) {
|
|
748
|
+
// @ts-ignore
|
|
749
|
+
moduleSettings.scoped |= ModuleScopeEnumOptions.ICSS;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
if (typeof moduleSettings.scoped == 'boolean') {
|
|
753
|
+
moduleSettings.scoped = moduleSettings.scoped ? ModuleScopeEnumOptions.Local : ModuleScopeEnumOptions.Global;
|
|
754
|
+
}
|
|
755
|
+
moduleSettings.filePath = filePath;
|
|
756
|
+
moduleSettings.pattern = pattern != null && pattern !== '' ? pattern : (filePath === '' ? `[local]_[hash]` : `[local]_[hash]_[name]`);
|
|
757
|
+
for (const { node, parent } of walk(ast)) {
|
|
758
|
+
if (node.typ == EnumToken.CssVariableImportTokenType) {
|
|
759
|
+
const url = node.val.find(t => t.typ == EnumToken.StringTokenType).val.slice(1, -1);
|
|
760
|
+
const src = options.resolve(url, options.dirname(options.src), options.cwd);
|
|
761
|
+
const result = options.load(url, options.src);
|
|
762
|
+
const stream = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction' ? await result : result;
|
|
763
|
+
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
764
|
+
stream,
|
|
765
|
+
buffer: '',
|
|
766
|
+
offset: 0,
|
|
767
|
+
position: { ind: 0, lin: 1, col: 1 },
|
|
768
|
+
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
769
|
+
}), Object.assign({}, options, {
|
|
770
|
+
minify: false,
|
|
771
|
+
setParent: false,
|
|
772
|
+
src: src.relative
|
|
773
|
+
}));
|
|
774
|
+
cssVariablesMap[node.nam] = root.cssModuleVariables;
|
|
775
|
+
parent.chi.splice(parent.chi.indexOf(node), 1);
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
if (node.typ == EnumToken.CssVariableDeclarationMapTokenType) {
|
|
779
|
+
const from = node.from.find(t => t.typ == EnumToken.IdenTokenType || isIdentColor(t));
|
|
780
|
+
if (!(from.val in cssVariablesMap)) {
|
|
781
|
+
errors.push({
|
|
782
|
+
node,
|
|
783
|
+
message: `could not resolve @value import from '${from.val}'`,
|
|
784
|
+
action: 'drop'
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
for (const token of node.vars) {
|
|
789
|
+
if (token.typ == EnumToken.IdenTokenType || isIdentColor(token)) {
|
|
790
|
+
if (!(token.val in cssVariablesMap[from.val])) {
|
|
791
|
+
errors.push({
|
|
792
|
+
node,
|
|
793
|
+
message: `value '${token.val}' is not exported from '${from.val}'`,
|
|
794
|
+
action: 'drop'
|
|
795
|
+
});
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
result.cssModuleVariables ??= {};
|
|
799
|
+
result.cssModuleVariables[token.val] = importedCssVariables[token.val] = cssVariablesMap[from.val][token.val];
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
parent.chi.splice(parent.chi.indexOf(node), 1);
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (node.typ == EnumToken.CssVariableTokenType) {
|
|
807
|
+
if (parent?.typ == EnumToken.StyleSheetNodeType) {
|
|
808
|
+
if (result.cssModuleVariables == null) {
|
|
809
|
+
result.cssModuleVariables = {};
|
|
810
|
+
}
|
|
811
|
+
result.cssModuleVariables[node.nam] = node;
|
|
812
|
+
}
|
|
813
|
+
parent.chi.splice(parent.chi.indexOf(node), 1);
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
if (node.typ == EnumToken.DeclarationNodeType) {
|
|
817
|
+
if (node.nam.startsWith('--')) {
|
|
818
|
+
if (!(node.nam in namesMapping)) {
|
|
819
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? node.nam : moduleSettings.generateScopedName(node.nam, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
820
|
+
let value = result instanceof Promise ? await result : result;
|
|
821
|
+
mapping[node.nam] = '--' + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
822
|
+
revMapping[node.nam] = node.nam;
|
|
823
|
+
}
|
|
824
|
+
node.nam = mapping[node.nam];
|
|
825
|
+
}
|
|
826
|
+
if ('composes' == node.nam.toLowerCase()) {
|
|
827
|
+
const tokens = [];
|
|
828
|
+
let isValid = true;
|
|
829
|
+
for (const token of node.val) {
|
|
830
|
+
if (token.typ == EnumToken.ComposesSelectorNodeType) {
|
|
831
|
+
if (!(token.r == null || token.r.typ == EnumToken.StringTokenType || token.r.typ == EnumToken.IdenTokenType)) {
|
|
832
|
+
errors.push({
|
|
833
|
+
action: 'drop',
|
|
834
|
+
message: `composes '${EnumToken[token.r.typ]}' is not supported`,
|
|
835
|
+
node
|
|
836
|
+
});
|
|
837
|
+
isValid = false;
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
tokens.push(token);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
// find parent rule
|
|
844
|
+
let parentRule = node.parent;
|
|
845
|
+
while (parentRule != null && parentRule.typ != EnumToken.RuleNodeType) {
|
|
846
|
+
parentRule = parentRule.parent;
|
|
847
|
+
}
|
|
848
|
+
if (!isValid || tokens.length == 0) {
|
|
849
|
+
if (tokens.length == 0) {
|
|
850
|
+
errors.push({
|
|
851
|
+
action: 'drop',
|
|
852
|
+
message: `composes is empty`,
|
|
853
|
+
node
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
parentRule.chi.splice(parentRule.chi.indexOf(node), 1);
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
for (const token of tokens) {
|
|
860
|
+
// composes: a b c;
|
|
861
|
+
if (token.r == null) {
|
|
862
|
+
for (const rule of token.l) {
|
|
863
|
+
if (rule.typ == EnumToken.WhitespaceTokenType || rule.typ == EnumToken.CommentTokenType) {
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
if (!(rule.val in mapping)) {
|
|
867
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? rule.val : moduleSettings.generateScopedName(rule.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
868
|
+
let value = result instanceof Promise ? await result : result;
|
|
869
|
+
mapping[rule.val] = (rule.typ == EnumToken.DashedIdenTokenType ? '--' : '') + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
870
|
+
revMapping[mapping[rule.val]] = rule.val;
|
|
871
|
+
}
|
|
872
|
+
if (parentRule != null) {
|
|
873
|
+
for (const tk of parentRule.tokens) {
|
|
874
|
+
if (tk.typ == EnumToken.ClassSelectorTokenType) {
|
|
875
|
+
const val = tk.val.slice(1);
|
|
876
|
+
if (val in revMapping) {
|
|
877
|
+
const key = revMapping[val];
|
|
878
|
+
mapping[key] = [...new Set([...mapping[key].split(' '), mapping[rule.val]])].join(' ');
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
// composes: a b c from 'file.css';
|
|
886
|
+
else if (token.r.typ == EnumToken.String) {
|
|
887
|
+
const url = token.r.val.slice(1, -1);
|
|
888
|
+
const src = options.resolve(url, options.dirname(options.src), options.cwd);
|
|
889
|
+
const result = options.load(url, options.src);
|
|
890
|
+
const stream = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction' ? await result : result;
|
|
891
|
+
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
892
|
+
stream,
|
|
893
|
+
buffer: '',
|
|
894
|
+
offset: 0,
|
|
895
|
+
position: { ind: 0, lin: 1, col: 1 },
|
|
896
|
+
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
897
|
+
}), Object.assign({}, options, {
|
|
898
|
+
minify: false,
|
|
899
|
+
setParent: false,
|
|
900
|
+
src: src.relative
|
|
901
|
+
}));
|
|
902
|
+
const srcIndex = (src.relative.startsWith('/') || src.relative.startsWith('../') ? '' : './') + src.relative;
|
|
903
|
+
if (Object.keys(root.mapping).length > 0) {
|
|
904
|
+
importMapping[srcIndex] = {};
|
|
905
|
+
}
|
|
906
|
+
if (parentRule != null) {
|
|
907
|
+
for (const tk of parentRule.tokens) {
|
|
908
|
+
if (tk.typ == EnumToken.ClassSelectorTokenType) {
|
|
909
|
+
const val = tk.val.slice(1);
|
|
910
|
+
if (val in revMapping) {
|
|
911
|
+
const key = revMapping[val];
|
|
912
|
+
const values = [];
|
|
913
|
+
for (const iden of token.l) {
|
|
914
|
+
if (iden.typ != EnumToken.IdenTokenType && iden.typ != EnumToken.DashedIdenTokenType) {
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (!(iden.val in root.mapping)) {
|
|
918
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? iden.val : moduleSettings.generateScopedName(iden.val, srcIndex, moduleSettings.pattern, moduleSettings.hashLength);
|
|
919
|
+
let value = result instanceof Promise ? await result : result;
|
|
920
|
+
root.mapping[iden.val] = (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
921
|
+
root.revMapping[root.mapping[iden.val]] = iden.val;
|
|
922
|
+
}
|
|
923
|
+
importMapping[srcIndex][iden.val] = root.mapping[iden.val];
|
|
924
|
+
values.push(root.mapping[iden.val]);
|
|
925
|
+
}
|
|
926
|
+
mapping[key] = [...new Set([...mapping[key].split(' '), ...values])].join(' ');
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
// composes: a b c from global;
|
|
933
|
+
else if (token.r.typ == EnumToken.IdenTokenType) {
|
|
934
|
+
// global
|
|
935
|
+
if (parentRule != null) {
|
|
936
|
+
if ('global' == token.r.val.toLowerCase()) {
|
|
937
|
+
for (const tk of parentRule.tokens) {
|
|
938
|
+
if (tk.typ == EnumToken.ClassSelectorTokenType) {
|
|
939
|
+
const val = tk.val.slice(1);
|
|
940
|
+
if (val in revMapping) {
|
|
941
|
+
const key = revMapping[val];
|
|
942
|
+
mapping[key] = [...new Set([...mapping[key].split(' '), ...(token.l.reduce((acc, curr) => {
|
|
943
|
+
if (curr.typ == EnumToken.IdenTokenType) {
|
|
944
|
+
acc.push(curr.val);
|
|
945
|
+
}
|
|
946
|
+
return acc;
|
|
947
|
+
}, []))])].join(' ');
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
errors.push({
|
|
954
|
+
action: 'drop',
|
|
955
|
+
message: `composes '${token.r.val}' is not supported`,
|
|
956
|
+
node
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
parentRule.chi.splice(parentRule.chi.indexOf(node), 1);
|
|
963
|
+
}
|
|
964
|
+
if (node.typ == EnumToken.DeclarationNodeType && ['grid-column', 'grid-column-start', 'grid-column-end', 'grid-row', 'grid-row-start', 'grid-row-end', 'grid-template', 'grid-template-columns', 'grid-template-rows'].includes(node.nam)) {
|
|
965
|
+
for (const { value } of walkValues(node.val, node)) {
|
|
966
|
+
if (value.typ != EnumToken.IdenTokenType) {
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
let idenToken = value.val;
|
|
970
|
+
let suffix = '';
|
|
971
|
+
if (idenToken.endsWith('-start')) {
|
|
972
|
+
suffix = '-start';
|
|
973
|
+
idenToken = idenToken.slice(0, -6);
|
|
974
|
+
}
|
|
975
|
+
else if (idenToken.endsWith('-end')) {
|
|
976
|
+
suffix = '-end';
|
|
977
|
+
idenToken = idenToken.slice(0, -4);
|
|
978
|
+
}
|
|
979
|
+
if (!(idenToken in mapping)) {
|
|
980
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? idenToken : moduleSettings.generateScopedName(idenToken, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
981
|
+
if (result instanceof Promise) {
|
|
982
|
+
result = await result;
|
|
983
|
+
}
|
|
984
|
+
mapping[idenToken] = result;
|
|
985
|
+
revMapping[result] = idenToken;
|
|
986
|
+
if (suffix !== '') {
|
|
987
|
+
idenToken += suffix;
|
|
988
|
+
if (!(idenToken in mapping)) {
|
|
989
|
+
mapping[idenToken] = result + suffix;
|
|
990
|
+
revMapping[result + suffix] = idenToken;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
value.val = mapping[idenToken];
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
else if (node.nam == 'grid-template-areas' || node.nam == 'grid-template') {
|
|
998
|
+
for (let i = 0; i < node.val.length; i++) {
|
|
999
|
+
if (node.val[i].typ == EnumToken.String) {
|
|
1000
|
+
const tokens = parseString(node.val[i].val.slice(1, -1), { location: true });
|
|
1001
|
+
for (const { value } of walkValues(tokens)) {
|
|
1002
|
+
if (value.typ == EnumToken.IdenTokenType || value.typ == EnumToken.DashedIdenTokenType) {
|
|
1003
|
+
if (value.val in mapping) {
|
|
1004
|
+
value.val = mapping[value.val];
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1008
|
+
if (result instanceof Promise) {
|
|
1009
|
+
result = await result;
|
|
1010
|
+
}
|
|
1011
|
+
mapping[value.val] = result;
|
|
1012
|
+
revMapping[result] = value.val;
|
|
1013
|
+
value.val = result;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
node.val[i].val = node.val[i].val.charAt(0) + tokens.reduce((acc, curr) => acc + renderToken(curr), '') + node.val[i].val.charAt(node.val[i].val.length - 1);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
else if (node.nam == 'animation' || node.nam == 'animation-name') {
|
|
1022
|
+
for (const { value } of walkValues(node.val, node)) {
|
|
1023
|
+
if (value.typ == EnumToken.IdenTokenType && ![
|
|
1024
|
+
'none', 'infinite', 'normal', 'reverse', 'alternate',
|
|
1025
|
+
'alternate-reverse', 'forwards', 'backwards', 'both',
|
|
1026
|
+
'running', 'paused', 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out',
|
|
1027
|
+
'step-start', 'step-end', 'jump-start', 'jump-end',
|
|
1028
|
+
'jump-none', 'jump-both', 'start', 'end',
|
|
1029
|
+
'inherit', 'initial', 'unset'
|
|
1030
|
+
].includes(value.val)) {
|
|
1031
|
+
if (!(value.val in mapping)) {
|
|
1032
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1033
|
+
mapping[value.val] = result instanceof Promise ? await result : result;
|
|
1034
|
+
revMapping[mapping[value.val]] = value.val;
|
|
1035
|
+
}
|
|
1036
|
+
value.val = mapping[value.val];
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
for (const { value, parent } of walkValues(node.val, node)) {
|
|
1041
|
+
if (value.typ == EnumToken.DashedIdenTokenType) {
|
|
1042
|
+
if (!(value.val in mapping)) {
|
|
1043
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1044
|
+
let val = result instanceof Promise ? await result : result;
|
|
1045
|
+
mapping[value.val] = '--' + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(val, moduleSettings.naming) : val);
|
|
1046
|
+
revMapping[mapping[value.val]] = value.val;
|
|
1047
|
+
}
|
|
1048
|
+
value.val = mapping[value.val];
|
|
1049
|
+
}
|
|
1050
|
+
else if ((value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && value.val in importedCssVariables) {
|
|
1051
|
+
replaceToken(parent, value, importedCssVariables[value.val].val);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
else if (node.typ == EnumToken.RuleNodeType) {
|
|
1056
|
+
if (node.tokens == null) {
|
|
1057
|
+
Object.defineProperty(node, 'tokens', {
|
|
1058
|
+
...definedPropertySettings,
|
|
1059
|
+
value: parseSelector(parseString(node.sel, { location: true }))
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
let hasIdOrClass = false;
|
|
1063
|
+
for (const { value } of walkValues(node.tokens, node,
|
|
1064
|
+
// @ts-ignore
|
|
1065
|
+
(value, parent) => {
|
|
1066
|
+
if (value.typ == EnumToken.PseudoClassTokenType) {
|
|
1067
|
+
const val = value.val.toLowerCase();
|
|
1068
|
+
switch (val) {
|
|
1069
|
+
case ':local':
|
|
1070
|
+
case ':global':
|
|
1071
|
+
{
|
|
1072
|
+
let index = parent.tokens.indexOf(value);
|
|
1073
|
+
parent.tokens.splice(index, 1);
|
|
1074
|
+
if (parent.tokens[index]?.typ == EnumToken.WhitespaceTokenType || parent.tokens[index]?.typ == EnumToken.DescendantCombinatorTokenType) {
|
|
1075
|
+
parent.tokens.splice(index, 1);
|
|
1076
|
+
}
|
|
1077
|
+
if (val == ':global') {
|
|
1078
|
+
for (; index < parent.tokens.length; index++) {
|
|
1079
|
+
if (parent.tokens[index].typ == EnumToken.CommaTokenType ||
|
|
1080
|
+
([EnumToken.PseudoClassFuncTokenType, EnumToken.PseudoClassTokenType].includes(parent.tokens[index].typ) &&
|
|
1081
|
+
[':global', ':local'].includes(parent.tokens[index].val.toLowerCase()))) {
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
global.add(parent.tokens[index]);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
else if (value.typ == EnumToken.PseudoClassFuncTokenType) {
|
|
1092
|
+
switch (value.val.toLowerCase()) {
|
|
1093
|
+
case ':global':
|
|
1094
|
+
for (const token of value.chi) {
|
|
1095
|
+
global.add(token);
|
|
1096
|
+
}
|
|
1097
|
+
parent.tokens.splice(parent.tokens.indexOf(value), 1, ...value.chi);
|
|
1098
|
+
break;
|
|
1099
|
+
case ':local':
|
|
1100
|
+
parent.tokens.splice(parent.tokens.indexOf(value), 1, ...value.chi);
|
|
1101
|
+
break;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
})) {
|
|
1105
|
+
if (value.typ == EnumToken.HashTokenType || value.typ == EnumToken.ClassSelectorTokenType) {
|
|
1106
|
+
hasIdOrClass = true;
|
|
1107
|
+
}
|
|
1108
|
+
if (processed.has(value)) {
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
processed.add(value);
|
|
1112
|
+
if (value.typ == EnumToken.PseudoClassTokenType) ;
|
|
1113
|
+
else if (value.typ == EnumToken.PseudoClassFuncTokenType) ;
|
|
1114
|
+
else {
|
|
1115
|
+
if (global.has(value)) {
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (value.typ == EnumToken.ClassSelectorTokenType) {
|
|
1119
|
+
const val = value.val.slice(1);
|
|
1120
|
+
if (!(val in mapping)) {
|
|
1121
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? val : moduleSettings.generateScopedName(val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1122
|
+
let value = result instanceof Promise ? await result : result;
|
|
1123
|
+
mapping[val] = (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
1124
|
+
revMapping[mapping[val]] = val;
|
|
1125
|
+
}
|
|
1126
|
+
value.val = '.' + mapping[val];
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
if (moduleSettings.scoped & ModuleScopeEnumOptions.Pure) {
|
|
1131
|
+
if (!hasIdOrClass) {
|
|
1132
|
+
throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${node.loc?.src ?? ''}':${node.loc?.sta?.lin ?? ''}:${node.loc?.sta?.col ?? ''}`);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
node.sel = '';
|
|
1136
|
+
for (const token of node.tokens) {
|
|
1137
|
+
node.sel += renderToken(token);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
else if (node.typ == EnumToken.AtRuleNodeType || node.typ == EnumToken.KeyframesAtRuleNodeType) {
|
|
1141
|
+
const val = node.nam.toLowerCase();
|
|
1142
|
+
if (node.tokens == null) {
|
|
1143
|
+
Object.defineProperty(node, 'tokens', {
|
|
1144
|
+
...definedPropertySettings,
|
|
1145
|
+
// @ts-ignore
|
|
1146
|
+
value: parseAtRulePrelude(parseString(node.val), node)
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
if (val == 'property' || val == 'keyframes') {
|
|
1150
|
+
const prefix = val == 'property' ? '--' : '';
|
|
1151
|
+
for (const value of node.tokens) {
|
|
1152
|
+
if ((prefix == '--' && value.typ == EnumToken.DashedIdenTokenType) || (prefix == '' && value.typ == EnumToken.IdenTokenType)) {
|
|
1153
|
+
if (!(value.val in mapping)) {
|
|
1154
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1155
|
+
let val = result instanceof Promise ? await result : result;
|
|
1156
|
+
mapping[value.val] = prefix + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(val, moduleSettings.naming) : val);
|
|
1157
|
+
revMapping[mapping[value.val]] = value.val;
|
|
1158
|
+
}
|
|
1159
|
+
value.val = mapping[value.val];
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
node.val = node.tokens.reduce((a, b) => a + renderToken(b), '');
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
let isReplaced = false;
|
|
1166
|
+
for (const { value, parent } of walkValues(node.tokens, node)) {
|
|
1167
|
+
if (EnumToken.MediaQueryConditionTokenType == parent.typ && value != parent.l) {
|
|
1168
|
+
if ((value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && value.val in importedCssVariables) {
|
|
1169
|
+
isReplaced = true;
|
|
1170
|
+
parent.r.splice(parent.r.indexOf(value), 1, ...importedCssVariables[value.val].val);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
if (isReplaced) {
|
|
1175
|
+
node.val = node.tokens.reduce((a, b) => a + renderToken(b), '');
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
if (moduleSettings.naming != ModuleCaseTransformEnum.IgnoreCase) {
|
|
1181
|
+
revMapping = {};
|
|
1182
|
+
mapping = Object.entries(mapping).reduce((acc, [key, value]) => {
|
|
1183
|
+
const keyName = getKeyName(key, moduleSettings.naming);
|
|
1184
|
+
acc[keyName] = value;
|
|
1185
|
+
revMapping[value] = keyName;
|
|
1186
|
+
return acc;
|
|
1187
|
+
}, {});
|
|
1188
|
+
}
|
|
1189
|
+
result.mapping = mapping;
|
|
1190
|
+
result.revMapping = revMapping;
|
|
1191
|
+
if ((moduleSettings.scoped & ModuleScopeEnumOptions.ICSS) && Object.keys(importMapping).length > 0) {
|
|
1192
|
+
result.importMapping = importMapping;
|
|
1193
|
+
}
|
|
1194
|
+
endTime = performance.now();
|
|
1195
|
+
result.stats.module = `${(endTime - parseModuleTime).toFixed(2)}ms`;
|
|
1196
|
+
result.stats.total = `${(endTime - startTime).toFixed(2)}ms`;
|
|
1197
|
+
}
|
|
1198
|
+
if (options.signal != null) {
|
|
1199
|
+
options.signal.removeEventListener('abort', reject);
|
|
1200
|
+
}
|
|
1201
|
+
return result;
|
|
581
1202
|
}
|
|
582
1203
|
function getLastNode(context) {
|
|
583
1204
|
let i = context.chi.length;
|
|
@@ -795,6 +1416,147 @@ function parseNode(results, context, options, errors, src, map, rawTokens, stats
|
|
|
795
1416
|
isValid = false;
|
|
796
1417
|
}
|
|
797
1418
|
}
|
|
1419
|
+
if (node.nam == 'value') {
|
|
1420
|
+
let i = 0;
|
|
1421
|
+
while (i < tokens.length) {
|
|
1422
|
+
if (tokens[i].typ == EnumToken.WhitespaceTokenType || tokens[i].typ == EnumToken.CommentTokenType) {
|
|
1423
|
+
i++;
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
break;
|
|
1427
|
+
}
|
|
1428
|
+
if (i < tokens.length) {
|
|
1429
|
+
if (tokens[i].typ == EnumToken.IdenTokenType || isIdentColor(tokens[i])) {
|
|
1430
|
+
let k = i + 1;
|
|
1431
|
+
while (k < tokens.length) {
|
|
1432
|
+
if (tokens[k].typ == EnumToken.WhitespaceTokenType || tokens[k].typ == EnumToken.CommentTokenType) {
|
|
1433
|
+
k++;
|
|
1434
|
+
continue;
|
|
1435
|
+
}
|
|
1436
|
+
// var or import
|
|
1437
|
+
if (tokens[k].typ == EnumToken.ColonTokenType) {
|
|
1438
|
+
let j = k;
|
|
1439
|
+
while (++j < tokens.length) {
|
|
1440
|
+
if (tokens[j].typ != EnumToken.WhitespaceTokenType && tokens[j].typ != EnumToken.CommentTokenType) {
|
|
1441
|
+
break;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
let offset = k + 1;
|
|
1445
|
+
while (offset < tokens.length && tokens[offset].typ == EnumToken.WhitespaceTokenType) {
|
|
1446
|
+
offset++;
|
|
1447
|
+
}
|
|
1448
|
+
if (tokens[j].typ == EnumToken.StringTokenType) {
|
|
1449
|
+
Object.assign(node, {
|
|
1450
|
+
typ: EnumToken.CssVariableImportTokenType,
|
|
1451
|
+
nam: tokens[i].val,
|
|
1452
|
+
val: tokens.slice(offset)
|
|
1453
|
+
});
|
|
1454
|
+
delete node.tokens;
|
|
1455
|
+
// @ts-ignore
|
|
1456
|
+
delete node.raw;
|
|
1457
|
+
context.chi.push(node);
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
Object.assign(node, {
|
|
1461
|
+
typ: EnumToken.CssVariableTokenType,
|
|
1462
|
+
nam: tokens[i].val,
|
|
1463
|
+
val: tokens.slice(offset)
|
|
1464
|
+
});
|
|
1465
|
+
context.chi.push(node);
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
if (tokens[k].typ == EnumToken.PseudoClassTokenType) {
|
|
1469
|
+
Object.assign(tokens[k], {
|
|
1470
|
+
typ: EnumToken.IdenTokenType,
|
|
1471
|
+
val: tokens[k].val.slice(1)
|
|
1472
|
+
});
|
|
1473
|
+
Object.assign(node, {
|
|
1474
|
+
typ: EnumToken.CssVariableTokenType,
|
|
1475
|
+
nam: tokens[i].val,
|
|
1476
|
+
val: tokens.slice(k)
|
|
1477
|
+
});
|
|
1478
|
+
context.chi.push(node);
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
if (tokens[k].typ == EnumToken.CommaTokenType) {
|
|
1482
|
+
let j = i;
|
|
1483
|
+
while (++j < tokens.length) {
|
|
1484
|
+
if (tokens[j].typ == EnumToken.IdenTokenType && tokens[j].val.toLowerCase() == 'from') {
|
|
1485
|
+
const vars = tokens.slice(i, j);
|
|
1486
|
+
const from = tokens.slice(j + 1);
|
|
1487
|
+
let l = 0;
|
|
1488
|
+
let expect = EnumToken.IdenTokenType;
|
|
1489
|
+
for (; l < vars.length; l++) {
|
|
1490
|
+
if (vars[l].typ == EnumToken.WhitespaceTokenType || vars[l].typ == EnumToken.CommentTokenType) {
|
|
1491
|
+
continue;
|
|
1492
|
+
}
|
|
1493
|
+
if (expect == vars[l].typ || (expect == EnumToken.IdenTokenType && isIdentColor(vars[l]))) {
|
|
1494
|
+
expect = expect == EnumToken.CommaTokenType ? EnumToken.IdenTokenType : EnumToken.CommaTokenType;
|
|
1495
|
+
continue;
|
|
1496
|
+
}
|
|
1497
|
+
errors.push({
|
|
1498
|
+
action: 'drop',
|
|
1499
|
+
node: node,
|
|
1500
|
+
location: map.get(vars[l]) ?? location,
|
|
1501
|
+
message: `expecting '${EnumToken[expect]}' but found ${renderToken(vars[l])}`
|
|
1502
|
+
});
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1505
|
+
l = 0;
|
|
1506
|
+
expect = EnumToken.IdenTokenType;
|
|
1507
|
+
for (; l < from.length; l++) {
|
|
1508
|
+
if (from[l].typ == EnumToken.WhitespaceTokenType || from[l].typ == EnumToken.CommentTokenType) {
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1511
|
+
if (expect == from[l].typ || isIdentColor(from[l])) {
|
|
1512
|
+
while (++l < from.length) {
|
|
1513
|
+
if (from[l].typ == EnumToken.WhitespaceTokenType || from[l].typ == EnumToken.CommentTokenType) {
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
errors.push({
|
|
1517
|
+
action: 'drop',
|
|
1518
|
+
node: node,
|
|
1519
|
+
location: map.get(from[l]) ?? location,
|
|
1520
|
+
message: `unexpected '${renderToken(from[l])}'`
|
|
1521
|
+
});
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
break;
|
|
1525
|
+
}
|
|
1526
|
+
errors.push({
|
|
1527
|
+
action: 'drop',
|
|
1528
|
+
node: node,
|
|
1529
|
+
location: map.get(from[l]) ?? location,
|
|
1530
|
+
message: `expecting <string> but found ${renderToken(from[l])}`
|
|
1531
|
+
});
|
|
1532
|
+
return null;
|
|
1533
|
+
}
|
|
1534
|
+
// @ts-ignore
|
|
1535
|
+
delete node.nam;
|
|
1536
|
+
// @ts-ignore
|
|
1537
|
+
delete node.val;
|
|
1538
|
+
Object.assign(node, {
|
|
1539
|
+
typ: EnumToken.CssVariableDeclarationMapTokenType,
|
|
1540
|
+
vars,
|
|
1541
|
+
from
|
|
1542
|
+
});
|
|
1543
|
+
context.chi.push(node);
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
k++;
|
|
1549
|
+
}
|
|
1550
|
+
Object.assign(node, {
|
|
1551
|
+
typ: EnumToken.CssVariableTokenType,
|
|
1552
|
+
nam: tokens[i].val,
|
|
1553
|
+
val: tokens.slice(k)
|
|
1554
|
+
});
|
|
1555
|
+
context.chi.push(node);
|
|
1556
|
+
return null;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
798
1560
|
// @ts-ignore
|
|
799
1561
|
const skipValidate = (options.validation & ValidationLevel.AtRule) == 0;
|
|
800
1562
|
const isAllowed = skipValidate || isNodeAllowedInContext(node, context);
|
|
@@ -1333,6 +2095,7 @@ async function parseDeclarations(declaration) {
|
|
|
1333
2095
|
return doParse(tokenize({
|
|
1334
2096
|
stream: `.x{${declaration}}`,
|
|
1335
2097
|
buffer: '',
|
|
2098
|
+
offset: 0,
|
|
1336
2099
|
position: { ind: 0, lin: 1, col: 1 },
|
|
1337
2100
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
1338
2101
|
}), { setParent: false, minify: false, validation: false }).then(result => {
|
|
@@ -1453,6 +2216,7 @@ function parseString(src, options = { location: false }) {
|
|
|
1453
2216
|
const parseInfo = {
|
|
1454
2217
|
stream: src,
|
|
1455
2218
|
buffer: '',
|
|
2219
|
+
offset: 0,
|
|
1456
2220
|
position: { ind: 0, lin: 1, col: 1 },
|
|
1457
2221
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
1458
2222
|
};
|
|
@@ -1578,12 +2342,10 @@ function getTokenType(val, hint) {
|
|
|
1578
2342
|
val: +val.slice(0, -1)
|
|
1579
2343
|
};
|
|
1580
2344
|
}
|
|
1581
|
-
// if (isDimension(val)) {
|
|
1582
2345
|
const dimension = parseDimension(val);
|
|
1583
2346
|
if (dimension != null) {
|
|
1584
2347
|
return dimension;
|
|
1585
2348
|
}
|
|
1586
|
-
// }
|
|
1587
2349
|
const v = val.toLowerCase();
|
|
1588
2350
|
if (v == 'currentcolor' || v == 'transparent' || v in COLORS_NAMES) {
|
|
1589
2351
|
return {
|
|
@@ -1612,6 +2374,12 @@ function getTokenType(val, hint) {
|
|
|
1612
2374
|
val
|
|
1613
2375
|
};
|
|
1614
2376
|
}
|
|
2377
|
+
if (val.charAt(0) == '.' && isIdent(val.slice(1))) {
|
|
2378
|
+
return {
|
|
2379
|
+
typ: EnumToken.ClassSelectorTokenType,
|
|
2380
|
+
val
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
1615
2383
|
if (val.charAt(0) == '#' && isHexColor(val)) {
|
|
1616
2384
|
return {
|
|
1617
2385
|
typ: EnumToken.ColorTokenType,
|
|
@@ -1659,6 +2427,55 @@ function getTokenType(val, hint) {
|
|
|
1659
2427
|
function parseTokens(tokens, options = {}) {
|
|
1660
2428
|
for (let i = 0; i < tokens.length; i++) {
|
|
1661
2429
|
const t = tokens[i];
|
|
2430
|
+
if (t.typ == EnumToken.IdenTokenType && t.val == 'from' && i > 0) {
|
|
2431
|
+
const left = [];
|
|
2432
|
+
const right = [];
|
|
2433
|
+
let foundLeft = 0;
|
|
2434
|
+
let foundRight = 0;
|
|
2435
|
+
let k = i;
|
|
2436
|
+
let l = i;
|
|
2437
|
+
while (k > 0) {
|
|
2438
|
+
if (tokens[k - 1].typ == EnumToken.CommentTokenType || tokens[k - 1].typ == EnumToken.WhitespaceTokenType) {
|
|
2439
|
+
left.push(tokens[--k]);
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
if (tokens[k - 1].typ == EnumToken.IdenTokenType || tokens[k - 1].typ == EnumToken.DashedIdenTokenType) {
|
|
2443
|
+
foundLeft++;
|
|
2444
|
+
left.push(tokens[--k]);
|
|
2445
|
+
continue;
|
|
2446
|
+
}
|
|
2447
|
+
break;
|
|
2448
|
+
}
|
|
2449
|
+
while (++l < tokens.length) {
|
|
2450
|
+
if (tokens[l].typ == EnumToken.CommentTokenType || tokens[l].typ == EnumToken.WhitespaceTokenType) {
|
|
2451
|
+
right.push(tokens[l]);
|
|
2452
|
+
continue;
|
|
2453
|
+
}
|
|
2454
|
+
if (tokens[l].typ == EnumToken.IdenTokenType || tokens[l].typ == EnumToken.StringTokenType) {
|
|
2455
|
+
foundRight++;
|
|
2456
|
+
right.push(tokens[l]);
|
|
2457
|
+
continue;
|
|
2458
|
+
}
|
|
2459
|
+
break;
|
|
2460
|
+
}
|
|
2461
|
+
if (foundLeft > 0 && foundRight == 1) {
|
|
2462
|
+
while (left?.[0].typ == EnumToken.WhitespaceTokenType) {
|
|
2463
|
+
left.shift();
|
|
2464
|
+
}
|
|
2465
|
+
while (left.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
|
|
2466
|
+
left.pop();
|
|
2467
|
+
}
|
|
2468
|
+
tokens.splice(k, l - k + 1, {
|
|
2469
|
+
typ: EnumToken.ComposesSelectorNodeType,
|
|
2470
|
+
l: left,
|
|
2471
|
+
r: right.reduce((a, b) => {
|
|
2472
|
+
return a == null ? b : b.typ == EnumToken.IdenTokenType || b.typ == EnumToken.StringTokenType ? b : a;
|
|
2473
|
+
}, null)
|
|
2474
|
+
});
|
|
2475
|
+
i = k;
|
|
2476
|
+
continue;
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
1662
2479
|
if (t.typ == EnumToken.WhitespaceTokenType && ((i == 0 ||
|
|
1663
2480
|
i + 1 == tokens.length ||
|
|
1664
2481
|
[EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType].includes(tokens[i + 1].typ)) ||
|
|
@@ -1942,4 +2759,4 @@ function parseTokens(tokens, options = {}) {
|
|
|
1942
2759
|
return tokens;
|
|
1943
2760
|
}
|
|
1944
2761
|
|
|
1945
|
-
export { doParse, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, replaceToken, urlTokenMatcher };
|
|
2762
|
+
export { doParse, generateScopedName, getKeyName, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, replaceToken, urlTokenMatcher };
|