@tbela99/css-parser 0.0.1 → 0.1.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.
@@ -2,37 +2,38 @@ import { splitRule, combinators } from './minify.js';
2
2
  import { parseString } from '../parser/parse.js';
3
3
  import { renderToken } from '../renderer/render.js';
4
4
  import '../renderer/utils/color.js';
5
+ import { EnumToken } from './types.js';
5
6
  import { walkValues } from './walk.js';
6
7
 
7
8
  function expand(ast) {
8
9
  //
9
- if (!['Rule', 'StyleSheet', 'AtRule'].includes(ast.typ)) {
10
+ if (![4 /* NodeType.RuleNodeType */, 2 /* NodeType.StyleSheetNodeType */, 3 /* NodeType.AtRuleNodeType */].includes(ast.typ)) {
10
11
  return ast;
11
12
  }
12
- if ('Rule' == ast.typ) {
13
+ if (4 /* NodeType.RuleNodeType */ == ast.typ) {
13
14
  return {
14
- typ: 'StyleSheet',
15
+ typ: 2 /* NodeType.StyleSheetNodeType */,
15
16
  chi: expandRule(ast)
16
17
  };
17
18
  }
18
19
  if (!('chi' in ast)) {
19
- return { ...ast };
20
+ return ast;
20
21
  }
21
22
  const result = { ...ast, chi: [] };
22
23
  // @ts-ignore
23
24
  for (let i = 0; i < ast.chi.length; i++) {
24
25
  // @ts-ignore
25
26
  const node = ast.chi[i];
26
- if (node.typ == 'Rule') {
27
+ if (node.typ == 4 /* NodeType.RuleNodeType */) {
27
28
  // @ts-ignore
28
29
  result.chi.push(...expandRule(node));
29
30
  // i += expanded.length - 1;
30
31
  }
31
- else if (node.typ == 'AtRule' && 'chi' in node) {
32
+ else if (node.typ == 3 /* NodeType.AtRuleNodeType */ && 'chi' in node) {
32
33
  let hasRule = false;
33
34
  let j = node.chi.length;
34
35
  while (j--) {
35
- if (node.chi[j].typ == 'Rule' || node.chi[j].typ == 'AtRule') {
36
+ if (node.chi[j].typ == 4 /* NodeType.RuleNodeType */ || node.chi[j].typ == 3 /* NodeType.AtRuleNodeType */) {
36
37
  hasRule = true;
37
38
  break;
38
39
  }
@@ -50,10 +51,10 @@ function expand(ast) {
50
51
  function expandRule(node) {
51
52
  const ast = { ...node, chi: node.chi.slice() };
52
53
  const result = [];
53
- if (ast.typ == 'Rule') {
54
+ if (ast.typ == 4 /* NodeType.RuleNodeType */) {
54
55
  let i = 0;
55
56
  for (; i < ast.chi.length; i++) {
56
- if (ast.chi[i].typ == 'Rule') {
57
+ if (ast.chi[i].typ == 4 /* NodeType.RuleNodeType */) {
57
58
  const rule = ast.chi[i];
58
59
  if (!rule.sel.includes('&')) {
59
60
  const selRule = splitRule(rule.sel);
@@ -69,14 +70,13 @@ function expandRule(node) {
69
70
  ast.chi.splice(i--, 1);
70
71
  result.push(...expandRule(rule));
71
72
  }
72
- else if (ast.chi[i].typ == 'AtRule') {
73
+ else if (ast.chi[i].typ == 3 /* NodeType.AtRuleNodeType */) {
73
74
  let astAtRule = ast.chi[i];
74
75
  const values = [];
75
76
  if (astAtRule.nam == 'scope') {
76
77
  if (astAtRule.val.includes('&')) {
77
78
  astAtRule.val = replaceCompound(astAtRule.val, ast.sel);
78
79
  }
79
- // @ts-ignore
80
80
  astAtRule = expand(astAtRule);
81
81
  }
82
82
  else {
@@ -85,7 +85,7 @@ function expandRule(node) {
85
85
  // @ts-ignore
86
86
  astAtRule.chi.length = 0;
87
87
  for (const r of expandRule(clone)) {
88
- if (r.typ == 'AtRule' && 'chi' in r) {
88
+ if (r.typ == 3 /* NodeType.AtRuleNodeType */ && 'chi' in r) {
89
89
  if (astAtRule.val !== '' && r.val !== '') {
90
90
  if (astAtRule.nam == 'media' && r.nam == 'media') {
91
91
  r.val = astAtRule.val + ' and ' + r.val;
@@ -97,7 +97,7 @@ function expandRule(node) {
97
97
  // @ts-ignore
98
98
  values.push(r);
99
99
  }
100
- else if (r.typ == 'Rule') {
100
+ else if (r.typ == 4 /* NodeType.RuleNodeType */) {
101
101
  // @ts-ignore
102
102
  astAtRule.chi.push(...expandRule(r));
103
103
  }
@@ -119,7 +119,7 @@ function expandRule(node) {
119
119
  function replaceCompound(input, replace) {
120
120
  const tokens = parseString(input);
121
121
  for (const t of walkValues(tokens)) {
122
- if (t.value.typ == 'Literal') {
122
+ if (t.value.typ == EnumToken.LiteralTokenType) {
123
123
  if (t.value.val == '&') {
124
124
  t.value.val = replace;
125
125
  }
@@ -0,0 +1,256 @@
1
+ import { EnumToken } from '../types.js';
2
+ import { reduceNumber, renderToken } from '../../renderer/render.js';
3
+ import { walkValues } from '../walk.js';
4
+ import { MinifyFeature } from '../utiles/minifyfeature.js';
5
+
6
+ class ComputeCalcExpression extends MinifyFeature {
7
+ static get ordering() {
8
+ return 1;
9
+ }
10
+ static register(options) {
11
+ if (options.computeCalcExpression) {
12
+ for (const feature of options.features) {
13
+ if (feature instanceof ComputeCalcExpression) {
14
+ return;
15
+ }
16
+ }
17
+ // @ts-ignore
18
+ options.features.push(new ComputeCalcExpression());
19
+ }
20
+ }
21
+ run(ast) {
22
+ if (!('chi' in ast)) {
23
+ return ast;
24
+ }
25
+ // @ts-ignore
26
+ for (const node of ast.chi) {
27
+ if (node.typ != 5 /* NodeType.DeclarationNodeType */) {
28
+ continue;
29
+ }
30
+ const set = new Set;
31
+ for (const { parent } of walkValues(node.val)) {
32
+ if (parent != null && parent.typ == EnumToken.FunctionTokenType && parent.val == 'calc') {
33
+ if (!set.has(parent)) {
34
+ set.add(parent);
35
+ parent.chi = evaluate(parent.chi);
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return ast;
41
+ }
42
+ }
43
+ /**
44
+ * evaluate arithmetic operation
45
+ * @param l
46
+ * @param r
47
+ * @param op
48
+ */
49
+ function doEvaluate(l, r, op) {
50
+ const defaultReturn = {
51
+ typ: EnumToken.BinaryExpressionTokenType,
52
+ op,
53
+ l,
54
+ r
55
+ };
56
+ if (!isScalarToken(l) || !isScalarToken(r)) {
57
+ return defaultReturn;
58
+ }
59
+ if ((op == EnumToken.Add || op == EnumToken.Sub)) {
60
+ // @ts-ignore
61
+ if (l.typ != r.typ || Number.isNaN(+l.val) || Number.isNaN(r.val)) {
62
+ return defaultReturn;
63
+ }
64
+ // @ts-ignore
65
+ return { ...l, val: reduceNumber(+l.val + (op == EnumToken.Add ? +r.val : -1 * r.val)) };
66
+ }
67
+ else {
68
+ // @ts-ignore
69
+ let val;
70
+ if (op == EnumToken.Div) {
71
+ if (r.typ != EnumToken.NumberTokenType || r.val == '0') {
72
+ return defaultReturn;
73
+ }
74
+ // @ts-ignore
75
+ val = reduceNumber(l.val / r.val);
76
+ }
77
+ else {
78
+ // @ts-ignore
79
+ val = reduceNumber(r.val * l.val);
80
+ }
81
+ let result;
82
+ if (r.typ == EnumToken.NumberTokenType || op == EnumToken.Div) {
83
+ result = { ...l, val };
84
+ }
85
+ else {
86
+ // @ts-ignore
87
+ result = { ...r, val };
88
+ }
89
+ if (renderToken(result).length <= renderToken(defaultReturn).length) {
90
+ return result;
91
+ }
92
+ }
93
+ return defaultReturn;
94
+ }
95
+ /**
96
+ * evaluate an array of tokens
97
+ * @param tokens
98
+ */
99
+ function evaluate(tokens) {
100
+ const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
101
+ if (nodes.length <= 1) {
102
+ return nodes;
103
+ }
104
+ const map = new Map;
105
+ let token;
106
+ let i;
107
+ for (i = 0; i < nodes.length; i++) {
108
+ token = nodes[i];
109
+ if (token.typ == EnumToken.Add) {
110
+ continue;
111
+ }
112
+ if (token.typ == EnumToken.Sub) {
113
+ if (!isScalarToken(nodes[i + 1])) {
114
+ token = { typ: EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]] };
115
+ }
116
+ else {
117
+ token = doEvaluate(nodes[i + 1], { typ: EnumToken.NumberTokenType, val: '-1' }, EnumToken.Mul);
118
+ }
119
+ i++;
120
+ }
121
+ if (!map.has(token.typ)) {
122
+ map.set(token.typ, [token]);
123
+ }
124
+ else {
125
+ map.get(token.typ).push(token);
126
+ }
127
+ }
128
+ return [...map].reduce((acc, curr) => {
129
+ const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, EnumToken.Add));
130
+ if (token.typ != EnumToken.BinaryExpressionTokenType) {
131
+ if ('val' in token && +token.val < 0) {
132
+ acc.push({ typ: EnumToken.Sub }, { ...token, val: String(-token.val) });
133
+ return acc;
134
+ }
135
+ }
136
+ if (acc.length > 0 && curr[0] != EnumToken.ListToken) {
137
+ acc.push({ typ: EnumToken.Add });
138
+ }
139
+ acc.push(token);
140
+ return acc;
141
+ }, []);
142
+ }
143
+ /**
144
+ * convert BinaryExpression into an array
145
+ * @param token
146
+ */
147
+ function inlineExpression(token) {
148
+ const result = [];
149
+ if (token.typ == EnumToken.BinaryExpressionTokenType) {
150
+ if ([EnumToken.Mul, EnumToken.Div].includes(token.op)) {
151
+ result.push(token);
152
+ }
153
+ else {
154
+ result.push(...inlineExpression(token.l), { typ: token.op }, ...inlineExpression(token.r));
155
+ }
156
+ }
157
+ else {
158
+ result.push(token);
159
+ }
160
+ return result;
161
+ }
162
+ /**
163
+ * evaluate expression
164
+ * @param token
165
+ */
166
+ function evaluateExpression(token) {
167
+ if (token.typ != EnumToken.BinaryExpressionTokenType) {
168
+ return token;
169
+ }
170
+ if (token.r.typ == EnumToken.BinaryExpressionTokenType) {
171
+ token.r = evaluateExpression(token.r);
172
+ }
173
+ if (token.l.typ == EnumToken.BinaryExpressionTokenType) {
174
+ token.l = evaluateExpression(token.l);
175
+ }
176
+ const result = doEvaluate(token.l, token.r, token.op);
177
+ if (result.typ == EnumToken.BinaryExpressionTokenType &&
178
+ [EnumToken.Mul, EnumToken.Div].includes(result.op)) {
179
+ // wrap expression
180
+ if (result.l.typ == EnumToken.BinaryExpressionTokenType && [EnumToken.Sub, EnumToken.Add].includes(result.l.op)) {
181
+ result.l = { typ: EnumToken.ParensTokenType, chi: [result.l] };
182
+ }
183
+ else if (result.r.typ == EnumToken.BinaryExpressionTokenType && [EnumToken.Sub, EnumToken.Add].includes(result.r.op)) {
184
+ result.r = { typ: EnumToken.ParensTokenType, chi: [result.r] };
185
+ }
186
+ }
187
+ return result;
188
+ }
189
+ function isScalarToken(token) {
190
+ return token.typ != EnumToken.BinaryExpressionTokenType && token.typ != EnumToken.ParensTokenType && token.typ != EnumToken.FunctionTokenType;
191
+ }
192
+ /**
193
+ *
194
+ * generate binary expression tree
195
+ * @param tokens
196
+ */
197
+ function buildExpression(tokens) {
198
+ return factor(factor(tokens.filter(t => t.typ != EnumToken.WhitespaceTokenType), ['/', '*']), ['+', '-'])[0];
199
+ }
200
+ function getArithmeticOperation(op) {
201
+ if (op == '+') {
202
+ return EnumToken.Add;
203
+ }
204
+ if (op == '-') {
205
+ return EnumToken.Sub;
206
+ }
207
+ if (op == '/') {
208
+ return EnumToken.Div;
209
+ }
210
+ return EnumToken.Mul;
211
+ }
212
+ /**
213
+ *
214
+ * generate binary expression tree
215
+ * @param token
216
+ */
217
+ function factorToken(token) {
218
+ if (token.typ == EnumToken.ParensTokenType || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc')) {
219
+ if (token.typ == EnumToken.FunctionTokenType && token.val == 'calc') {
220
+ token = { ...token, typ: EnumToken.ParensTokenType };
221
+ // @ts-ignore
222
+ delete token.val;
223
+ }
224
+ return buildExpression(token.chi);
225
+ }
226
+ return token;
227
+ }
228
+ /**
229
+ * generate binary expression tree
230
+ * @param tokens
231
+ * @param ops
232
+ */
233
+ function factor(tokens, ops) {
234
+ let isOp;
235
+ const opList = [EnumToken.Add, EnumToken.Sub, EnumToken.Div, EnumToken.Mul];
236
+ if (tokens.length == 1) {
237
+ return [factorToken(tokens[0])];
238
+ }
239
+ for (let i = 0; i < tokens.length; i++) {
240
+ isOp = opList.includes(tokens[i].typ);
241
+ if (isOp ||
242
+ // @ts-ignore
243
+ (tokens[i].typ == EnumToken.LiteralTokenType && ops.includes(tokens[i].val))) {
244
+ tokens.splice(i - 1, 3, {
245
+ typ: EnumToken.BinaryExpressionTokenType,
246
+ op: isOp ? tokens[i].typ : getArithmeticOperation(tokens[i].val),
247
+ l: factorToken(tokens[i - 1]),
248
+ r: factorToken(tokens[i + 1])
249
+ });
250
+ i--;
251
+ }
252
+ }
253
+ return tokens;
254
+ }
255
+
256
+ export { ComputeCalcExpression };
@@ -0,0 +1,3 @@
1
+ export { InlineCssVariables } from './inlinecssvariables.js';
2
+ export { ComputeShorthand } from './shorthand.js';
3
+ export { ComputeCalcExpression } from './calc.js';
@@ -0,0 +1,115 @@
1
+ import { EnumToken } from '../types.js';
2
+ import { walkValues } from '../walk.js';
3
+ import { MinifyFeature } from '../utiles/minifyfeature.js';
4
+
5
+ class InlineCssVariables extends MinifyFeature {
6
+ static get ordering() {
7
+ return 0;
8
+ }
9
+ static register(options) {
10
+ if (options.inlineCssVariables) {
11
+ for (const feature of options.features) {
12
+ if (feature instanceof InlineCssVariables) {
13
+ return;
14
+ }
15
+ }
16
+ // @ts-ignore
17
+ options.features.push(new InlineCssVariables());
18
+ }
19
+ }
20
+ run(ast, options = {}, parent, context) {
21
+ if (!('variableScope' in context)) {
22
+ context.variableScope = new Map;
23
+ }
24
+ const isRoot = parent.typ == 2 /* NodeType.StyleSheetNodeType */ && ast.typ == 4 /* NodeType.RuleNodeType */ && ast.sel == ':root';
25
+ const variableScope = context.variableScope;
26
+ // @ts-ignore
27
+ for (const node of ast.chi) {
28
+ if (node.typ == 1 /* NodeType.CDOCOMMNodeType */ || node.typ == 0 /* NodeType.CommentNodeType */) {
29
+ continue;
30
+ }
31
+ if (node.typ != 5 /* NodeType.DeclarationNodeType */) {
32
+ break;
33
+ }
34
+ // css variable
35
+ if (node.nam.startsWith('--')) {
36
+ if (!variableScope.has(node.nam)) {
37
+ const info = {
38
+ globalScope: isRoot,
39
+ // @ts-ignore
40
+ parent: new Set(),
41
+ declarationCount: 1,
42
+ replaceable: isRoot,
43
+ node: node
44
+ };
45
+ info.parent.add(ast);
46
+ variableScope.set(node.nam, info);
47
+ }
48
+ else {
49
+ const info = variableScope.get(node.nam);
50
+ info.globalScope = isRoot;
51
+ if (!isRoot) {
52
+ ++info.declarationCount;
53
+ }
54
+ if (info.replaceable) {
55
+ info.replaceable = isRoot && info.declarationCount == 1;
56
+ }
57
+ info.parent.add(ast);
58
+ info.node = node;
59
+ }
60
+ }
61
+ else {
62
+ for (const { value, parent: parentValue } of walkValues(node.val)) {
63
+ if (value?.typ == EnumToken.FunctionTokenType && value.val == 'var') {
64
+ if (value.chi.length == 1 && value.chi[0].typ == EnumToken.IdenTokenType) {
65
+ const info = variableScope.get(value.chi[0].val);
66
+ if (info?.replaceable) {
67
+ if (parentValue != null) {
68
+ let i = 0;
69
+ for (; i < parentValue.chi.length; i++) {
70
+ if (parentValue.chi[i] == value) {
71
+ parentValue.chi.splice(i, 1, ...info.node.val);
72
+ break;
73
+ }
74
+ }
75
+ }
76
+ else {
77
+ node.val = info.node.val.slice();
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ cleanup(ast, options = {}, context) {
87
+ const variableScope = context.variableScope;
88
+ for (const info of variableScope.values()) {
89
+ if (info.replaceable) {
90
+ let i;
91
+ for (const parent of info.parent) {
92
+ i = parent.chi?.length ?? 0;
93
+ while (i--) {
94
+ if (parent.chi[i].typ == 5 /* NodeType.DeclarationNodeType */ && parent.chi[i].nam == info.node.nam) {
95
+ parent.chi.splice(i, 1);
96
+ }
97
+ }
98
+ if (parent.chi?.length == 0 && 'parent' in parent) {
99
+ // @ts-ignore
100
+ for (i = 0; i < parent.parent.chi?.length; i++) {
101
+ // @ts-ignore
102
+ if (parent.parent.chi[i] == parent) {
103
+ // @ts-ignore
104
+ parent.parent.chi.splice(i, 1);
105
+ break;
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
114
+
115
+ export { InlineCssVariables };
@@ -0,0 +1,45 @@
1
+ import { PropertyList } from '../../parser/declaration/list.js';
2
+ import '../../renderer/utils/color.js';
3
+ import '../types.js';
4
+ import '../minify.js';
5
+ import '../../parser/parse.js';
6
+ import '../../renderer/sourcemap/lib/encode.js';
7
+ import { MinifyFeature } from '../utiles/minifyfeature.js';
8
+
9
+ class ComputeShorthand extends MinifyFeature {
10
+ static get ordering() {
11
+ return 2;
12
+ }
13
+ static register(options) {
14
+ if (options.computeShorthand) {
15
+ for (const feature of options.features) {
16
+ if (feature instanceof ComputeShorthand) {
17
+ return;
18
+ }
19
+ }
20
+ // @ts-ignore
21
+ options.features.push(new ComputeShorthand());
22
+ }
23
+ }
24
+ run(ast, options = {}, parent, context) {
25
+ // @ts-ignore
26
+ const j = ast.chi.length;
27
+ let k = 0;
28
+ let properties = new PropertyList(options);
29
+ // @ts-ignore
30
+ for (; k < j; k++) {
31
+ // @ts-ignore
32
+ const node = ast.chi[k];
33
+ if (node.typ == 0 /* NodeType.CommentNodeType */ || node.typ == 5 /* NodeType.DeclarationNodeType */) {
34
+ properties.add(node);
35
+ continue;
36
+ }
37
+ break;
38
+ }
39
+ // @ts-ignore
40
+ ast.chi = [...properties].concat(ast.chi.slice(k));
41
+ return ast;
42
+ }
43
+ }
44
+
45
+ export { ComputeShorthand };