@tbela99/css-parser 0.9.1 → 1.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +265 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +29 -17
  4. package/dist/index-umd-web.js +7461 -4360
  5. package/dist/index.cjs +8608 -5507
  6. package/dist/index.d.ts +203 -61
  7. package/dist/lib/ast/expand.js +2 -1
  8. package/dist/lib/ast/features/calc.js +19 -11
  9. package/dist/lib/ast/features/index.js +1 -0
  10. package/dist/lib/ast/features/inlinecssvariables.js +47 -29
  11. package/dist/lib/ast/features/prefix.js +117 -91
  12. package/dist/lib/ast/features/shorthand.js +34 -14
  13. package/dist/lib/ast/features/transform.js +67 -0
  14. package/dist/lib/ast/features/type.js +7 -0
  15. package/dist/lib/ast/math/expression.js +20 -10
  16. package/dist/lib/ast/math/math.js +20 -2
  17. package/dist/lib/ast/minify.js +209 -80
  18. package/dist/lib/ast/transform/compute.js +337 -0
  19. package/dist/lib/ast/transform/convert.js +33 -0
  20. package/dist/lib/ast/transform/matrix.js +112 -0
  21. package/dist/lib/ast/transform/minify.js +296 -0
  22. package/dist/lib/ast/transform/perspective.js +10 -0
  23. package/dist/lib/ast/transform/rotate.js +40 -0
  24. package/dist/lib/ast/transform/scale.js +32 -0
  25. package/dist/lib/ast/transform/skew.js +23 -0
  26. package/dist/lib/ast/transform/translate.js +32 -0
  27. package/dist/lib/ast/transform/utils.js +198 -0
  28. package/dist/lib/ast/types.js +18 -15
  29. package/dist/lib/ast/walk.js +54 -22
  30. package/dist/lib/fs/resolve.js +10 -0
  31. package/dist/lib/parser/declaration/list.js +48 -45
  32. package/dist/lib/parser/declaration/map.js +1 -0
  33. package/dist/lib/parser/declaration/set.js +2 -1
  34. package/dist/lib/parser/parse.js +449 -340
  35. package/dist/lib/parser/tokenize.js +147 -72
  36. package/dist/lib/parser/utils/declaration.js +5 -4
  37. package/dist/lib/parser/utils/type.js +2 -1
  38. package/dist/lib/renderer/color/a98rgb.js +2 -1
  39. package/dist/lib/renderer/color/{colormix.js → color-mix.js} +16 -7
  40. package/dist/lib/renderer/color/color.js +264 -170
  41. package/dist/lib/renderer/color/hex.js +19 -8
  42. package/dist/lib/renderer/color/hsl.js +9 -3
  43. package/dist/lib/renderer/color/hwb.js +2 -1
  44. package/dist/lib/renderer/color/lab.js +10 -1
  45. package/dist/lib/renderer/color/lch.js +10 -1
  46. package/dist/lib/renderer/color/oklab.js +10 -1
  47. package/dist/lib/renderer/color/oklch.js +10 -1
  48. package/dist/lib/renderer/color/p3.js +2 -1
  49. package/dist/lib/renderer/color/rec2020.js +2 -1
  50. package/dist/lib/renderer/color/relativecolor.js +27 -32
  51. package/dist/lib/renderer/color/rgb.js +14 -10
  52. package/dist/lib/renderer/color/srgb.js +48 -23
  53. package/dist/lib/renderer/color/utils/components.js +18 -6
  54. package/dist/lib/renderer/color/utils/constants.js +47 -3
  55. package/dist/lib/renderer/color/xyz.js +2 -1
  56. package/dist/lib/renderer/color/xyzd50.js +2 -1
  57. package/dist/lib/renderer/render.js +108 -43
  58. package/dist/lib/syntax/syntax.js +267 -136
  59. package/dist/lib/validation/at-rules/container.js +81 -103
  60. package/dist/lib/validation/at-rules/counter-style.js +9 -8
  61. package/dist/lib/validation/at-rules/custom-media.js +13 -15
  62. package/dist/lib/validation/at-rules/document.js +22 -27
  63. package/dist/lib/validation/at-rules/font-feature-values.js +8 -8
  64. package/dist/lib/validation/at-rules/import.js +30 -81
  65. package/dist/lib/validation/at-rules/keyframes.js +19 -23
  66. package/dist/lib/validation/at-rules/layer.js +5 -5
  67. package/dist/lib/validation/at-rules/media.js +42 -53
  68. package/dist/lib/validation/at-rules/namespace.js +19 -23
  69. package/dist/lib/validation/at-rules/page-margin-box.js +15 -18
  70. package/dist/lib/validation/at-rules/page.js +8 -7
  71. package/dist/lib/validation/at-rules/supports.js +73 -82
  72. package/dist/lib/validation/at-rules/when.js +32 -36
  73. package/dist/lib/validation/atrule.js +15 -18
  74. package/dist/lib/validation/config.js +24 -1
  75. package/dist/lib/validation/config.json.js +563 -63
  76. package/dist/lib/validation/parser/parse.js +196 -185
  77. package/dist/lib/validation/parser/types.js +1 -1
  78. package/dist/lib/validation/selector.js +8 -5
  79. package/dist/lib/validation/syntax.js +724 -1405
  80. package/dist/lib/validation/syntaxes/complex-selector-list.js +10 -11
  81. package/dist/lib/validation/syntaxes/complex-selector.js +10 -11
  82. package/dist/lib/validation/syntaxes/compound-selector.js +40 -50
  83. package/dist/lib/validation/syntaxes/family-name.js +9 -8
  84. package/dist/lib/validation/syntaxes/keyframe-block-list.js +6 -5
  85. package/dist/lib/validation/syntaxes/keyframe-selector.js +23 -105
  86. package/dist/lib/validation/syntaxes/layer-name.js +6 -5
  87. package/dist/lib/validation/syntaxes/relative-selector-list.js +7 -6
  88. package/dist/lib/validation/syntaxes/relative-selector.js +17 -15
  89. package/dist/lib/validation/syntaxes/url.js +18 -22
  90. package/dist/lib/validation/utils/list.js +20 -2
  91. package/dist/lib/validation/utils/whitespace.js +2 -1
  92. package/dist/node/index.js +4 -2
  93. package/dist/node/load.js +6 -1
  94. package/dist/web/index.js +4 -2
  95. package/dist/web/load.js +5 -0
  96. package/package.json +16 -15
  97. package/dist/lib/renderer/color/prophotoRgb.js +0 -56
  98. package/dist/lib/validation/declaration.js +0 -94
  99. package/dist/lib/validation/syntaxes/image.js +0 -29
@@ -1,10 +1,35 @@
1
1
  import { EnumToken } from '../types.js';
2
2
  import { walkValues } from '../walk.js';
3
3
  import { renderToken } from '../../renderer/render.js';
4
+ import '../../renderer/color/utils/constants.js';
5
+ import { splitRule } from '../minify.js';
6
+ import '../../parser/parse.js';
7
+ import '../../parser/tokenize.js';
8
+ import '../../parser/utils/config.js';
9
+ import { mathFuncs } from '../../syntax/syntax.js';
4
10
 
11
+ function inlineExpression(token) {
12
+ const result = [];
13
+ if (token.typ == EnumToken.BinaryExpressionTokenType) {
14
+ result.push({
15
+ typ: EnumToken.ParensTokenType,
16
+ chi: [...inlineExpression(token.l), { typ: token.op }, ...inlineExpression(token.r)]
17
+ });
18
+ }
19
+ else {
20
+ result.push(token);
21
+ }
22
+ return result;
23
+ }
5
24
  function replace(node, variableScope) {
6
25
  for (const { value, parent: parentValue } of walkValues(node.val)) {
7
- if (value?.typ == EnumToken.FunctionTokenType && value.val == 'var') {
26
+ if (value.typ == EnumToken.BinaryExpressionTokenType && parentValue != null && 'chi' in parentValue) {
27
+ // @ts-ignore
28
+ parentValue.chi.splice(parentValue.chi.indexOf(value), 1, ...inlineExpression(value));
29
+ }
30
+ }
31
+ for (const { value, parent: parentValue } of walkValues(node.val)) {
32
+ if (value.typ == EnumToken.FunctionTokenType && value.val == 'var') {
8
33
  if (value.chi.length == 1 && value.chi[0].typ == EnumToken.DashedIdenTokenType) {
9
34
  const info = variableScope.get(value.chi[0].val);
10
35
  if (info?.replaceable) {
@@ -26,33 +51,35 @@ function replace(node, variableScope) {
26
51
  }
27
52
  }
28
53
  class InlineCssVariablesFeature {
29
- static get ordering() {
54
+ get ordering() {
30
55
  return 0;
31
56
  }
57
+ get preProcess() {
58
+ return true;
59
+ }
60
+ get postProcess() {
61
+ return false;
62
+ }
32
63
  static register(options) {
33
64
  if (options.inlineCssVariables) {
34
- for (const feature of options.features) {
35
- if (feature instanceof InlineCssVariablesFeature) {
36
- return;
37
- }
38
- }
39
65
  // @ts-ignore
40
66
  options.features.push(new InlineCssVariablesFeature());
41
67
  }
42
68
  }
43
69
  run(ast, options = {}, parent, context) {
70
+ if (!('chi' in ast)) {
71
+ return;
72
+ }
44
73
  if (!('variableScope' in context)) {
45
74
  context.variableScope = new Map;
46
75
  }
47
- const isRoot = parent.typ == EnumToken.StyleSheetNodeType && ast.typ == EnumToken.RuleNodeType && [':root', 'html'].includes(ast.sel);
76
+ // [':root', 'html']
77
+ const isRoot = parent.typ == EnumToken.StyleSheetNodeType && ast.typ == EnumToken.RuleNodeType && (ast.raw ?? splitRule(ast.sel)).some(segment => segment.some(s => s == ':root' || s == 'html'));
48
78
  const variableScope = context.variableScope;
49
79
  // @ts-ignore
50
80
  for (const node of ast.chi) {
51
- if (node.typ == EnumToken.CDOCOMMNodeType || node.typ == EnumToken.CommentNodeType) {
52
- continue;
53
- }
54
81
  if (node.typ != EnumToken.DeclarationNodeType) {
55
- break;
82
+ continue;
56
83
  }
57
84
  // css variable
58
85
  if (node.nam.startsWith('--')) {
@@ -63,13 +90,14 @@ class InlineCssVariablesFeature {
63
90
  parent: new Set(),
64
91
  declarationCount: 1,
65
92
  replaceable: isRoot,
66
- node: node
93
+ node: node,
94
+ values: structuredClone(node.val)
67
95
  };
68
96
  info.parent.add(ast);
69
97
  variableScope.set(node.nam, info);
70
98
  let recursive = false;
71
- for (const { value, parent: parentValue } of walkValues(node.val)) {
72
- if (value?.typ == EnumToken.FunctionTokenType && value.val == 'var') {
99
+ for (const { value } of walkValues(node.val)) {
100
+ if (value?.typ == EnumToken.FunctionTokenType && (mathFuncs.includes(value.val) || value.val == 'var')) {
73
101
  recursive = true;
74
102
  break;
75
103
  }
@@ -108,23 +136,13 @@ class InlineCssVariablesFeature {
108
136
  for (const parent of info.parent) {
109
137
  i = parent.chi?.length ?? 0;
110
138
  while (i--) {
111
- if (parent.chi[i].typ == EnumToken.DeclarationNodeType && parent.chi[i].nam == info.node.nam) {
139
+ if (parent.chi[i] == info.node) {
112
140
  // @ts-ignore
113
- parent.chi.splice(i++, 1, {
141
+ parent.chi.splice(i, 1, {
114
142
  typ: EnumToken.CommentTokenType,
115
- val: `/* ${info.node.nam}: ${info.node.val.reduce((acc, curr) => acc + renderToken(curr), '')} */`
143
+ val: `/* ${info.node.nam}: ${info.values.reduce((acc, curr) => acc + renderToken(curr), '')} */`
116
144
  });
117
- }
118
- }
119
- if (parent.chi?.length == 0 && 'parent' in parent) {
120
- // @ts-ignore
121
- for (i = 0; i < parent.parent.chi?.length; i++) {
122
- // @ts-ignore
123
- if (parent.parent.chi[i] == parent) {
124
- // @ts-ignore
125
- parent.parent.chi.splice(i, 1);
126
- break;
127
- }
145
+ break;
128
146
  }
129
147
  }
130
148
  }
@@ -1,126 +1,152 @@
1
- import { EnumToken } from '../types.js';
1
+ import { EnumToken, SyntaxValidationResult } from '../types.js';
2
2
  import { getSyntaxConfig } from '../../validation/config.js';
3
- import { ValidationTokenEnum } from '../../validation/parser/types.js';
3
+ import '../../validation/parser/types.js';
4
4
  import '../../validation/parser/parse.js';
5
- import '../minify.js';
5
+ import { splitRule, definedPropertySettings } from '../minify.js';
6
6
  import { walkValues } from '../walk.js';
7
- import '../../parser/parse.js';
8
- import '../../renderer/color/utils/constants.js';
9
- import '../../renderer/sourcemap/lib/encode.js';
7
+ import { parseAtRulePrelude, parseString } from '../../parser/parse.js';
8
+ import '../../parser/tokenize.js';
10
9
  import '../../parser/utils/config.js';
10
+ import { pseudoAliasMap } from '../../syntax/syntax.js';
11
+ import { renderToken } from '../../renderer/render.js';
12
+ import { funcLike } from '../../renderer/color/utils/constants.js';
11
13
  import '../../validation/syntaxes/complex-selector.js';
14
+ import { evaluateSyntax } from '../../validation/syntax.js';
12
15
 
13
16
  const config = getSyntaxConfig();
17
+ function replacePseudo(tokens) {
18
+ return tokens.map((raw) => raw.map(r => {
19
+ if (r.includes('(')) {
20
+ const index = r.indexOf('(');
21
+ const name = r.slice(0, index) + '()';
22
+ if (name in pseudoAliasMap) {
23
+ return pseudoAliasMap[name] + r.slice(index);
24
+ }
25
+ return r;
26
+ }
27
+ return r in pseudoAliasMap && pseudoAliasMap[r] in config["selectors" /* ValidationSyntaxGroupEnum.Selectors */] ? pseudoAliasMap[r] : r;
28
+ }));
29
+ }
30
+ function replaceAstNodes(tokens, root) {
31
+ let result = false;
32
+ for (const { value, parent } of walkValues(tokens, root)) {
33
+ if (value.typ == EnumToken.IdenTokenType || value.typ == EnumToken.PseudoClassFuncTokenType || value.typ == EnumToken.PseudoClassTokenType || value.typ == EnumToken.PseudoElementTokenType) {
34
+ let key = value.val + (value.typ == EnumToken.PseudoClassFuncTokenType ? '()' : '');
35
+ if (key in pseudoAliasMap) {
36
+ const isPseudClass = pseudoAliasMap[key].startsWith('::');
37
+ value.val = pseudoAliasMap[key];
38
+ if (value.typ == EnumToken.IdenTokenType &&
39
+ ['min-resolution', 'max-resolution'].includes(value.val) &&
40
+ parent?.typ == EnumToken.MediaQueryConditionTokenType &&
41
+ parent.r?.[0]?.typ == EnumToken.NumberTokenType) {
42
+ Object.assign(parent.r?.[0], {
43
+ typ: EnumToken.ResolutionTokenType,
44
+ unit: 'x',
45
+ });
46
+ }
47
+ else if (isPseudClass && value.typ == EnumToken.PseudoElementTokenType) {
48
+ // @ts-ignore
49
+ value.typ = EnumToken.PseudoClassTokenType;
50
+ }
51
+ result = true;
52
+ }
53
+ }
54
+ }
55
+ return result;
56
+ }
14
57
  class ComputePrefixFeature {
15
- static get ordering() {
58
+ get ordering() {
16
59
  return 2;
17
60
  }
61
+ get preProcess() {
62
+ return true;
63
+ }
64
+ get postProcess() {
65
+ return false;
66
+ }
18
67
  static register(options) {
19
68
  if (options.removePrefix) {
20
- for (const feature of options.features) {
21
- if (feature instanceof ComputePrefixFeature) {
22
- return;
23
- }
24
- }
25
69
  // @ts-ignore
26
70
  options.features.push(new ComputePrefixFeature(options));
27
71
  }
28
72
  }
29
- run(ast) {
30
- // @ts-ignore
31
- const j = ast.chi.length;
32
- let k = 0;
33
- // @ts-ignore
34
- for (; k < j; k++) {
35
- // @ts-ignore
36
- const node = ast.chi[k];
37
- if (node.typ == EnumToken.DeclarationNodeType) {
38
- if (node.nam.charAt(0) == '-') {
39
- const match = node.nam.match(/^-([^-]+)-(.+)$/);
40
- if (match != null) {
41
- const nam = match[2];
42
- if (nam.toLowerCase() in config.declarations) {
43
- node.nam = nam;
73
+ run(node) {
74
+ if (node.typ == EnumToken.RuleNodeType) {
75
+ node.sel = replacePseudo(splitRule(node.sel)).reduce((acc, curr, index) => acc + (index > 0 ? ',' : '') + curr.join(''), '');
76
+ if (node.raw != null) {
77
+ node.raw = replacePseudo(node.raw);
78
+ }
79
+ if (node.optimized != null) {
80
+ node.optimized.selector = replacePseudo(node.optimized.selector);
81
+ }
82
+ if (node.tokens != null) {
83
+ replaceAstNodes(node.tokens);
84
+ }
85
+ }
86
+ else if (node.typ == EnumToken.DeclarationNodeType) {
87
+ if (node.nam.charAt(0) == '-') {
88
+ const match = node.nam.match(/^-([^-]+)-(.+)$/);
89
+ if (match != null) {
90
+ let nam = match[2];
91
+ if (!(nam in config.declarations)) {
92
+ if (node.nam in pseudoAliasMap) {
93
+ nam = pseudoAliasMap[node.nam];
44
94
  }
45
95
  }
46
- }
47
- if (node.nam.toLowerCase() in config.declarations) {
48
- for (const { value } of walkValues(node.val)) {
49
- if (value.typ == EnumToken.IdenTokenType && value.val.charAt(0) == '-' && value.val.charAt(1) != '-') {
50
- // @ts-ignore
51
- const values = config.declarations[node.nam].ast.slice();
52
- const match = value.val.match(/^-(.*?)-(.*)$/);
53
- if (match != null) {
54
- const val = matchToken({ ...value, val: match[2] }, values);
55
- if (val != null) {
56
- // @ts-ignore
57
- value.val = val.val;
58
- }
59
- }
60
- }
96
+ if (nam in config.declarations) {
97
+ node.nam = nam;
61
98
  }
62
99
  }
63
100
  }
64
- }
65
- return ast;
66
- }
67
- }
68
- function matchToken(token, matches) {
69
- let result;
70
- for (let i = 0; i < matches.length; i++) {
71
- switch (matches[i].typ) {
72
- case ValidationTokenEnum.Whitespace:
73
- case ValidationTokenEnum.Comma:
74
- break;
75
- case ValidationTokenEnum.Keyword:
76
- if (token.typ == EnumToken.IdenTokenType && token.val == matches[i].val) {
77
- return token;
78
- }
79
- break;
80
- case ValidationTokenEnum.PropertyType:
81
- if (['ident', 'custom-ident'].includes(matches[i].val)) {
82
- if (token.typ == EnumToken.IdenTokenType && token.val == matches[i].val) {
83
- return token;
101
+ let hasPrefix = false;
102
+ for (const { value } of walkValues(node.val)) {
103
+ if ((value.typ == EnumToken.IdenTokenType || (value.typ != EnumToken.ParensTokenType && funcLike.includes(value.typ))) && value.val.match(/^-([^-]+)-(.+)$/) != null) {
104
+ if (value.val.endsWith('-gradient')) {
105
+ // not supported yet
106
+ break;
84
107
  }
108
+ hasPrefix = true;
109
+ break;
85
110
  }
86
- else {
87
- const val = matches[i].val;
88
- if (val in config.declarations || val in config.syntaxes) {
89
- // @ts-ignore
90
- result = matchToken(token, (config.syntaxes[val] ?? config.declarations[val]).ast.slice());
91
- if (result != null) {
92
- return result;
111
+ }
112
+ if (hasPrefix) {
113
+ const nodes = structuredClone(node.val);
114
+ for (const { value } of walkValues(nodes)) {
115
+ if ((value.typ == EnumToken.IdenTokenType || funcLike.includes(value.typ))) {
116
+ const match = value.val.match(/^-([^-]+)-(.+)$/);
117
+ if (match == null) {
118
+ continue;
93
119
  }
120
+ value.val = match[2];
94
121
  }
95
122
  }
96
- break;
97
- case ValidationTokenEnum.PipeToken:
98
- for (let j = 0; j < matches[i].chi.length; j++) {
99
- result = matchToken(token, matches[i].chi[j]);
100
- if (result != null) {
101
- return result;
102
- }
123
+ if (SyntaxValidationResult.Valid == evaluateSyntax({ ...node, val: nodes }, {}).valid) {
124
+ node.val = nodes;
103
125
  }
104
- break;
105
- case ValidationTokenEnum.ColumnToken:
106
- case ValidationTokenEnum.AmpersandToken:
107
- result = matchToken(token, matches[i].l);
108
- if (result == null) {
109
- result = matchToken(token, matches[i].r);
126
+ }
127
+ }
128
+ else if (node.typ == EnumToken.AtRuleNodeType || node.typ == EnumToken.KeyframeAtRuleNodeType) {
129
+ if (node.nam.startsWith('-')) {
130
+ const match = node.nam.match(/^-([^-]+)-(.+)$/);
131
+ if (match != null && '@' + match[2] in config.atRules) {
132
+ node.nam = match[2];
110
133
  }
111
- if (result != null) {
112
- return result;
134
+ }
135
+ if (node.typ == EnumToken.AtRuleNodeType && node.val !== '') {
136
+ if (node.tokens == null) {
137
+ Object.defineProperty(node, 'tokens', {
138
+ // @ts-ignore
139
+ ...definedPropertySettings,
140
+ value: parseAtRulePrelude(parseString(node.val), node),
141
+ });
113
142
  }
114
- break;
115
- case ValidationTokenEnum.Bracket:
116
- result = matchToken(token, matches[i].chi);
117
- if (result != null) {
118
- return result;
143
+ if (replaceAstNodes(node.tokens)) {
144
+ node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr), '');
119
145
  }
120
- break;
146
+ }
121
147
  }
148
+ return node;
122
149
  }
123
- return null;
124
150
  }
125
151
 
126
152
  export { ComputePrefixFeature };
@@ -3,42 +3,62 @@ import { EnumToken } from '../types.js';
3
3
  import '../minify.js';
4
4
  import '../walk.js';
5
5
  import '../../parser/parse.js';
6
+ import '../../parser/tokenize.js';
7
+ import '../../parser/utils/config.js';
6
8
  import '../../renderer/color/utils/constants.js';
7
9
  import '../../renderer/sourcemap/lib/encode.js';
8
- import '../../parser/utils/config.js';
9
10
 
10
11
  class ComputeShorthandFeature {
11
- static get ordering() {
12
- return 2;
12
+ get ordering() {
13
+ return 3;
14
+ }
15
+ get preProcess() {
16
+ return false;
17
+ }
18
+ get postProcess() {
19
+ return true;
13
20
  }
14
21
  static register(options) {
15
22
  if (options.computeShorthand) {
16
- for (const feature of options.features) {
17
- if (feature instanceof ComputeShorthandFeature) {
18
- return;
19
- }
20
- }
21
23
  // @ts-ignore
22
24
  options.features.push(new ComputeShorthandFeature(options));
23
25
  }
24
26
  }
25
27
  run(ast, options = {}, parent, context) {
28
+ if (!('chi' in ast)) {
29
+ return ast;
30
+ }
26
31
  // @ts-ignore
27
32
  const j = ast.chi.length;
28
33
  let k = 0;
34
+ let l;
29
35
  let properties = new PropertyList(options);
36
+ const rules = [];
30
37
  // @ts-ignore
31
38
  for (; k < j; k++) {
39
+ l = k;
40
+ // capture comments with the next token
41
+ while (l + 1 < j) {
42
+ // @ts-ignore
43
+ const node = ast.chi[l];
44
+ if (node.typ == EnumToken.CommentNodeType) {
45
+ l++;
46
+ continue;
47
+ }
48
+ break;
49
+ }
32
50
  // @ts-ignore
33
- const node = ast.chi[k];
34
- if (node.typ == EnumToken.CommentNodeType || node.typ == EnumToken.DeclarationNodeType) {
35
- properties.add(node);
36
- continue;
51
+ const node = ast.chi[l];
52
+ if (node.typ == EnumToken.DeclarationNodeType) {
53
+ properties.add(...ast.chi.slice(k, l + 1));
54
+ }
55
+ else {
56
+ rules.push(...ast.chi.slice(k, l + 1));
37
57
  }
38
- break;
58
+ k = l;
39
59
  }
40
60
  // @ts-ignore
41
- ast.chi = [...properties].concat(ast.chi.slice(k));
61
+ ast.chi = [...properties, ...rules];
42
62
  return ast;
43
63
  }
44
64
  }
@@ -0,0 +1,67 @@
1
+ import { EnumToken } from '../types.js';
2
+ import { consumeWhitespace } from '../../validation/utils/whitespace.js';
3
+ import '../minify.js';
4
+ import '../walk.js';
5
+ import '../../parser/parse.js';
6
+ import '../../parser/tokenize.js';
7
+ import '../../parser/utils/config.js';
8
+ import { filterValues, renderToken } from '../../renderer/render.js';
9
+ import '../../renderer/color/utils/constants.js';
10
+ import { compute } from '../transform/compute.js';
11
+ import { eqMatrix } from '../transform/minify.js';
12
+
13
+ class TransformCssFeature {
14
+ get ordering() {
15
+ return 4;
16
+ }
17
+ get preProcess() {
18
+ return false;
19
+ }
20
+ get postProcess() {
21
+ return true;
22
+ }
23
+ static register(options) {
24
+ // @ts-ignore
25
+ if (options.computeTransform) {
26
+ // @ts-ignore
27
+ options.features.push(new TransformCssFeature());
28
+ }
29
+ }
30
+ run(ast) {
31
+ if (!('chi' in ast)) {
32
+ return;
33
+ }
34
+ let i = 0;
35
+ let node;
36
+ // @ts-ignore
37
+ for (; i < ast.chi.length; i++) {
38
+ // @ts-ignore
39
+ node = ast.chi[i];
40
+ if (node.typ != EnumToken.DeclarationNodeType || !node.nam.match(/^(-[a-z]+-)?transform$/)) {
41
+ continue;
42
+ }
43
+ const children = node.val.slice();
44
+ consumeWhitespace(children);
45
+ let { matrix, cumulative, minified } = compute(children) ?? {};
46
+ if (matrix == null || cumulative == null || minified == null) {
47
+ continue;
48
+ }
49
+ let r = [filterValues(node.val.slice())];
50
+ if (eqMatrix(matrix, cumulative)) {
51
+ r.push(cumulative);
52
+ }
53
+ if (eqMatrix(matrix, minified)) {
54
+ r.push(minified);
55
+ }
56
+ const l = renderToken(matrix).length;
57
+ node.val = r.reduce((acc, curr) => {
58
+ if (curr.reduce((acc, t) => acc + renderToken(t), '').length < l) {
59
+ return curr;
60
+ }
61
+ return acc;
62
+ }, [matrix]);
63
+ }
64
+ }
65
+ }
66
+
67
+ export { TransformCssFeature };
@@ -0,0 +1,7 @@
1
+ var FeatureWalkMode;
2
+ (function (FeatureWalkMode) {
3
+ FeatureWalkMode[FeatureWalkMode["Pre"] = 0] = "Pre";
4
+ FeatureWalkMode[FeatureWalkMode["Post"] = 1] = "Post";
5
+ })(FeatureWalkMode || (FeatureWalkMode = {}));
6
+
7
+ export { FeatureWalkMode };
@@ -1,6 +1,12 @@
1
1
  import { EnumToken } from '../types.js';
2
2
  import { rem, compute } from './math.js';
3
3
  import { reduceNumber } from '../../renderer/render.js';
4
+ import '../../renderer/color/utils/constants.js';
5
+ import '../minify.js';
6
+ import '../walk.js';
7
+ import '../../parser/parse.js';
8
+ import '../../parser/tokenize.js';
9
+ import '../../parser/utils/config.js';
4
10
  import { mathFuncs } from '../../syntax/syntax.js';
5
11
 
6
12
  /**
@@ -39,14 +45,19 @@ function evaluate(tokens) {
39
45
  return tokens;
40
46
  }
41
47
  if (nodes.length <= 1) {
42
- // @ts-ignore
43
- if (nodes.length == 1 && nodes[0].typ == EnumToken.IdenTokenType && typeof Math[nodes[0].val.toUpperCase()] == 'number') {
44
- return [{
45
- ...nodes[0],
46
- // @ts-ignore
47
- val: '' + Math[nodes[0].val.toUpperCase()],
48
- typ: EnumToken.NumberTokenType
49
- }];
48
+ if (nodes.length == 1) {
49
+ if (nodes[0].typ == EnumToken.BinaryExpressionTokenType) {
50
+ return inlineExpression(nodes[0]);
51
+ }
52
+ // @ts-ignore
53
+ if (nodes[0].typ == EnumToken.IdenTokenType && typeof Math[nodes[0].val.toUpperCase()] == 'number') {
54
+ return [{
55
+ ...nodes[0],
56
+ // @ts-ignore
57
+ val: '' + Math[nodes[0].val.toUpperCase()],
58
+ typ: EnumToken.NumberTokenType
59
+ }];
60
+ }
50
61
  }
51
62
  return nodes;
52
63
  }
@@ -167,7 +178,6 @@ function doEvaluate(l, r, op) {
167
178
  }
168
179
  // @ts-ignore
169
180
  const val = compute(v1, v2, op);
170
- // typ = typeof val == 'number' ? EnumToken.NumberTokenType : EnumToken.FractionTokenType;
171
181
  const token = {
172
182
  ...(l.typ == EnumToken.NumberTokenType ? r : l),
173
183
  typ,
@@ -513,4 +523,4 @@ function factor(tokens, ops) {
513
523
  return tokens;
514
524
  }
515
525
 
516
- export { evaluate, evaluateFunc };
526
+ export { buildExpression, evaluate, evaluateFunc, inlineExpression };
@@ -1,12 +1,29 @@
1
1
  import { EnumToken } from '../types.js';
2
2
  import { reduceNumber } from '../../renderer/render.js';
3
+ import '../../renderer/color/utils/constants.js';
4
+ import '../minify.js';
5
+ import '../walk.js';
6
+ import '../../parser/parse.js';
7
+ import '../../parser/tokenize.js';
8
+ import '../../parser/utils/config.js';
3
9
 
4
10
  function gcd(x, y) {
5
11
  x = Math.abs(x);
6
12
  y = Math.abs(y);
13
+ if (x == y) {
14
+ return x;
15
+ }
7
16
  let t;
8
- if (x == 0 || y == 0) {
9
- return 1;
17
+ if (x == 0) {
18
+ return y;
19
+ }
20
+ if (y == 0) {
21
+ return x;
22
+ }
23
+ if (y > x) {
24
+ t = x;
25
+ x = y;
26
+ y = t;
10
27
  }
11
28
  while (y) {
12
29
  t = y;
@@ -76,6 +93,7 @@ function compute(a, b, op) {
76
93
  r2 = l1.r.val * r1.l.val;
77
94
  break;
78
95
  }
96
+ // @ts-ignore
79
97
  const a2 = simplify(l2, r2);
80
98
  if (a2[1] == 1) {
81
99
  return a2[0];