less 4.9.0 → 5.0.0-alpha.1

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 (131) hide show
  1. package/README.md +19 -5
  2. package/bin/lessc +190 -630
  3. package/dist/less-node.cjs +399 -14570
  4. package/index.cjs +5 -2
  5. package/lib/index.js +164 -0
  6. package/lib/lessc-helper.js +52 -0
  7. package/lib/logger.js +76 -0
  8. package/lib/options.d.ts +46 -0
  9. package/lib/options.js +145 -0
  10. package/lib/types.js +20 -0
  11. package/lib/version.js +19 -0
  12. package/package.json +34 -40
  13. package/dist/less.cjs +0 -15215
  14. package/dist/less.js +0 -15215
  15. package/dist/less.min.js +0 -11
  16. package/dist/less.min.js.map +0 -1
  17. package/lib/less/constants.js +0 -13
  18. package/lib/less/contexts.js +0 -165
  19. package/lib/less/data/colors.js +0 -150
  20. package/lib/less/data/index.js +0 -4
  21. package/lib/less/data/unit-conversions.js +0 -21
  22. package/lib/less/default-options.js +0 -89
  23. package/lib/less/deprecation.js +0 -82
  24. package/lib/less/environment/abstract-file-manager.js +0 -140
  25. package/lib/less/environment/abstract-plugin-loader.js +0 -185
  26. package/lib/less/environment/environment-api.ts +0 -21
  27. package/lib/less/environment/environment.js +0 -59
  28. package/lib/less/environment/file-manager-api.ts +0 -77
  29. package/lib/less/functions/boolean.js +0 -29
  30. package/lib/less/functions/color-blending.js +0 -85
  31. package/lib/less/functions/color.js +0 -452
  32. package/lib/less/functions/data-uri.js +0 -74
  33. package/lib/less/functions/default.js +0 -26
  34. package/lib/less/functions/function-caller.js +0 -55
  35. package/lib/less/functions/function-registry.js +0 -36
  36. package/lib/less/functions/index.js +0 -35
  37. package/lib/less/functions/list.js +0 -158
  38. package/lib/less/functions/math-helper.js +0 -22
  39. package/lib/less/functions/math.js +0 -30
  40. package/lib/less/functions/number.js +0 -95
  41. package/lib/less/functions/string.js +0 -39
  42. package/lib/less/functions/style.js +0 -29
  43. package/lib/less/functions/svg.js +0 -87
  44. package/lib/less/functions/types.js +0 -70
  45. package/lib/less/import-manager.js +0 -183
  46. package/lib/less/index.js +0 -95
  47. package/lib/less/less-error.js +0 -166
  48. package/lib/less/logger.js +0 -34
  49. package/lib/less/parse-tree.js +0 -124
  50. package/lib/less/parse.js +0 -87
  51. package/lib/less/parser/lookup-pattern.js +0 -26
  52. package/lib/less/parser/parser-input.js +0 -400
  53. package/lib/less/parser/parser.js +0 -2998
  54. package/lib/less/plugin-manager.js +0 -168
  55. package/lib/less/render.js +0 -41
  56. package/lib/less/source-map-builder.js +0 -82
  57. package/lib/less/source-map-output.js +0 -151
  58. package/lib/less/transform-tree.js +0 -102
  59. package/lib/less/tree/anonymous.js +0 -61
  60. package/lib/less/tree/assignment.js +0 -48
  61. package/lib/less/tree/atrule-syntax.js +0 -8
  62. package/lib/less/tree/atrule.js +0 -340
  63. package/lib/less/tree/attribute.js +0 -63
  64. package/lib/less/tree/call.js +0 -132
  65. package/lib/less/tree/color.js +0 -285
  66. package/lib/less/tree/combinator.js +0 -38
  67. package/lib/less/tree/comment.js +0 -48
  68. package/lib/less/tree/condition.js +0 -65
  69. package/lib/less/tree/container.js +0 -104
  70. package/lib/less/tree/debug-info.js +0 -80
  71. package/lib/less/tree/declaration.js +0 -139
  72. package/lib/less/tree/detached-ruleset.js +0 -45
  73. package/lib/less/tree/dimension.js +0 -215
  74. package/lib/less/tree/element.js +0 -93
  75. package/lib/less/tree/expression.js +0 -100
  76. package/lib/less/tree/extend.js +0 -88
  77. package/lib/less/tree/import.js +0 -299
  78. package/lib/less/tree/index.js +0 -56
  79. package/lib/less/tree/interpolated-variable.js +0 -106
  80. package/lib/less/tree/javascript.js +0 -45
  81. package/lib/less/tree/js-eval-node.js +0 -80
  82. package/lib/less/tree/keyword.js +0 -28
  83. package/lib/less/tree/media.js +0 -90
  84. package/lib/less/tree/merge-rules.js +0 -47
  85. package/lib/less/tree/mixin-call.js +0 -283
  86. package/lib/less/tree/mixin-definition.js +0 -319
  87. package/lib/less/tree/namespace-value.js +0 -95
  88. package/lib/less/tree/negative.js +0 -37
  89. package/lib/less/tree/nested-at-rule.js +0 -239
  90. package/lib/less/tree/node.js +0 -310
  91. package/lib/less/tree/operation.js +0 -81
  92. package/lib/less/tree/paren.js +0 -41
  93. package/lib/less/tree/property.js +0 -96
  94. package/lib/less/tree/query-in-parens.js +0 -64
  95. package/lib/less/tree/quoted.js +0 -131
  96. package/lib/less/tree/ruleset.js +0 -1068
  97. package/lib/less/tree/selector.js +0 -201
  98. package/lib/less/tree/unicode-descriptor.js +0 -14
  99. package/lib/less/tree/unit.js +0 -170
  100. package/lib/less/tree/url.js +0 -83
  101. package/lib/less/tree/value.js +0 -60
  102. package/lib/less/tree/variable-call.js +0 -60
  103. package/lib/less/tree/variable.js +0 -85
  104. package/lib/less/utils.js +0 -126
  105. package/lib/less/visitors/extend-visitor.js +0 -505
  106. package/lib/less/visitors/import-sequencer.js +0 -56
  107. package/lib/less/visitors/import-visitor.js +0 -203
  108. package/lib/less/visitors/index.js +0 -15
  109. package/lib/less/visitors/join-selector-visitor.js +0 -65
  110. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  111. package/lib/less/visitors/to-css-visitor.js +0 -332
  112. package/lib/less/visitors/visitor.js +0 -165
  113. package/lib/less-browser/add-default-options.js +0 -53
  114. package/lib/less-browser/bootstrap.js +0 -67
  115. package/lib/less-browser/browser.js +0 -65
  116. package/lib/less-browser/cache.js +0 -43
  117. package/lib/less-browser/error-reporting.js +0 -170
  118. package/lib/less-browser/file-manager.js +0 -112
  119. package/lib/less-browser/image-size.js +0 -28
  120. package/lib/less-browser/index.js +0 -284
  121. package/lib/less-browser/log-listener.js +0 -42
  122. package/lib/less-browser/plugin-loader.js +0 -24
  123. package/lib/less-browser/utils.js +0 -30
  124. package/lib/less-node/environment.js +0 -43
  125. package/lib/less-node/file-manager.js +0 -156
  126. package/lib/less-node/fs.js +0 -14
  127. package/lib/less-node/image-size.js +0 -78
  128. package/lib/less-node/index.js +0 -31
  129. package/lib/less-node/lessc-helper.js +0 -95
  130. package/lib/less-node/plugin-loader.js +0 -62
  131. package/lib/less-node/url-file-manager.js +0 -60
@@ -1,299 +0,0 @@
1
- // @ts-check
2
- /** @import { EvalContext, CSSOutput, TreeVisitor, FileInfo, VisibilityInfo } from './node.js' */
3
- import Node from './node.js';
4
- import Media from './media.js';
5
- import URL from './url.js';
6
- import Quoted from './quoted.js';
7
- import Ruleset from './ruleset.js';
8
- import Anonymous from './anonymous.js';
9
- import Expression from './expression.js';
10
- import * as utils from '../utils.js';
11
- import LessError from '../less-error.js';
12
-
13
- /**
14
- * @typedef {object} ImportOptions
15
- * @property {boolean} [less]
16
- * @property {boolean} [inline]
17
- * @property {boolean} [isPlugin]
18
- * @property {boolean} [reference]
19
- */
20
-
21
- //
22
- // CSS @import node
23
- //
24
- // The general strategy here is that we don't want to wait
25
- // for the parsing to be completed, before we start importing
26
- // the file. That's because in the context of a browser,
27
- // most of the time will be spent waiting for the server to respond.
28
- //
29
- // On creation, we push the import path to our import queue, though
30
- // `import,push`, we also pass it a callback, which it'll call once
31
- // the file has been fetched, and parsed.
32
- //
33
- class Import extends Node {
34
- get type() { return 'Import'; }
35
-
36
- /**
37
- * @param {Node} path
38
- * @param {Node | null} features
39
- * @param {ImportOptions} options
40
- * @param {number} index
41
- * @param {FileInfo} [currentFileInfo]
42
- * @param {VisibilityInfo} [visibilityInfo]
43
- */
44
- constructor(path, features, options, index, currentFileInfo, visibilityInfo) {
45
- super();
46
- /** @type {ImportOptions} */
47
- this.options = options;
48
- this._index = index;
49
- this._fileInfo = currentFileInfo;
50
- this.path = path;
51
- /** @type {Node | null} */
52
- this.features = features;
53
- /** @type {boolean} */
54
- this.allowRoot = true;
55
-
56
- /** @type {boolean | undefined} */
57
- this.css = undefined;
58
- /** @type {boolean | undefined} */
59
- this.layerCss = undefined;
60
- /** @type {(Ruleset & { imports?: object, filename?: string, functions?: object, functionRegistry?: { addMultiple: (fns: object) => void } }) | undefined} */
61
- this.root = undefined;
62
- /** @type {string | undefined} */
63
- this.importedFilename = undefined;
64
- /** @type {boolean | (() => boolean) | undefined} */
65
- this.skip = undefined;
66
- /** @type {{ message: string, index: number, filename: string } | undefined} */
67
- this.error = undefined;
68
-
69
- if (this.options.less !== undefined || this.options.inline) {
70
- this.css = !this.options.less || this.options.inline;
71
- } else {
72
- const pathValue = this.getPath();
73
- if (pathValue && /[#.&?]css([?;].*)?$/.test(pathValue)) {
74
- this.css = true;
75
- }
76
- }
77
- this.copyVisibilityInfo(visibilityInfo);
78
- if (this.features) {
79
- this.setParent(this.features, /** @type {Node} */ (this));
80
- }
81
- this.setParent(this.path, /** @type {Node} */ (this));
82
- }
83
-
84
- /** @param {TreeVisitor} visitor */
85
- accept(visitor) {
86
- if (this.features) {
87
- this.features = visitor.visit(this.features);
88
- }
89
- this.path = visitor.visit(this.path);
90
- if (!this.options.isPlugin && !this.options.inline && this.root) {
91
- this.root = /** @type {Ruleset} */ (visitor.visit(this.root));
92
- }
93
- }
94
-
95
- /**
96
- * @param {EvalContext} context
97
- * @param {CSSOutput} output
98
- */
99
- genCSS(context, output) {
100
- if (this.css && this.path._fileInfo.reference === undefined) {
101
- output.add('@import ', this._fileInfo, this._index);
102
- this.path.genCSS(context, output);
103
- if (this.features) {
104
- output.add(' ');
105
- this.features.genCSS(context, output);
106
- }
107
- output.add(';');
108
- }
109
- }
110
-
111
- /** @returns {string | undefined} */
112
- getPath() {
113
- return (this.path instanceof URL) ?
114
- /** @type {string} */ (/** @type {Node} */ (this.path.value).value) :
115
- /** @type {string | undefined} */ (this.path.value);
116
- }
117
-
118
- /** @returns {boolean | RegExpMatchArray | null} */
119
- isVariableImport() {
120
- let path = this.path;
121
- if (path instanceof URL) {
122
- path = /** @type {Node} */ (path.value);
123
- }
124
- if (path instanceof Quoted) {
125
- return path.containsVariables();
126
- }
127
-
128
- return true;
129
- }
130
-
131
- /** @param {EvalContext} context */
132
- evalForImport(context) {
133
- let path = this.path;
134
-
135
- if (path instanceof URL) {
136
- path = /** @type {Node} */ (path.value);
137
- }
138
-
139
- return new Import(path.eval(context), this.features, this.options, this._index || 0, this._fileInfo, this.visibilityInfo());
140
- }
141
-
142
- /** @param {EvalContext} context */
143
- evalPath(context) {
144
- const path = this.path.eval(context);
145
- const fileInfo = this._fileInfo;
146
-
147
- if (!(path instanceof URL)) {
148
- // Add the rootpath if the URL requires a rewrite
149
- const pathValue = /** @type {string} */ (path.value);
150
- if (fileInfo &&
151
- pathValue &&
152
- context.pathRequiresRewrite(pathValue)) {
153
- path.value = context.rewritePath(pathValue, fileInfo.rootpath);
154
- } else {
155
- path.value = context.normalizePath(/** @type {string} */ (path.value));
156
- }
157
- }
158
-
159
- return path;
160
- }
161
-
162
- /** @param {EvalContext} context */
163
- // @ts-ignore - Import.eval returns Node | Node[] | Import (wider than Node.eval's Node return)
164
- eval(context) {
165
- const result = this.doEval(context);
166
- if (this.options.reference || this.blocksVisibility()) {
167
- if (Array.isArray(result)) {
168
- result.forEach(function (node) {
169
- node.addVisibilityBlock();
170
- });
171
- } else {
172
- /** @type {Node} */ (result).addVisibilityBlock();
173
- }
174
- }
175
- return result;
176
- }
177
-
178
- /** @param {EvalContext} context */
179
- doEval(context) {
180
- /** @type {Ruleset | undefined} */
181
- let ruleset;
182
- const features = this.features && this.features.eval(context);
183
-
184
- if (this.options.isPlugin) {
185
- if (this.root && this.root.eval) {
186
- try {
187
- this.root.eval(context);
188
- }
189
- catch (e) {
190
- const err = /** @type {{ message: string }} */ (e);
191
- err.message = 'Plugin error during evaluation';
192
- throw new LessError(
193
- /** @type {{ message: string, index?: number, filename?: string }} */ (e),
194
- /** @type {{ imports: object }} */ (/** @type {unknown} */ (this.root)).imports,
195
- /** @type {{ filename: string }} */ (/** @type {unknown} */ (this.root)).filename
196
- );
197
- }
198
- }
199
- const frame0 = /** @type {Ruleset & { functionRegistry?: { addMultiple: (fns: object) => void } }} */ (context.frames[0]);
200
- const registry = frame0 && frame0.functionRegistry;
201
- if (registry && this.root && this.root.functions) {
202
- registry.addMultiple(this.root.functions);
203
- }
204
-
205
- return [];
206
- }
207
-
208
- if (this.skip) {
209
- if (typeof this.skip === 'function') {
210
- this.skip = this.skip();
211
- }
212
- if (this.skip) {
213
- return [];
214
- }
215
- }
216
- if (this.features) {
217
- let featureValue = /** @type {Node[]} */ (this.features.value);
218
- if (Array.isArray(featureValue) && featureValue.length >= 1) {
219
- const expr = featureValue[0];
220
- if (expr.type === 'Expression' && Array.isArray(expr.value) && /** @type {Node[]} */ (expr.value).length >= 2) {
221
- featureValue = /** @type {Node[]} */ (expr.value);
222
- const isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
223
- && featureValue[1].type === 'Paren';
224
- if (isLayer) {
225
- this.css = false;
226
- }
227
- }
228
- }
229
- }
230
- if (this.options.inline) {
231
- const contents = new Anonymous(
232
- /** @type {string} */ (/** @type {unknown} */ (this.root)),
233
- 0,
234
- {
235
- filename: this.importedFilename,
236
- reference: this.path._fileInfo && this.path._fileInfo.reference
237
- },
238
- true,
239
- true
240
- );
241
-
242
- return this.features ? new Media([contents], /** @type {Node[]} */ (this.features.value)) : [contents];
243
- } else if (this.css || this.layerCss) {
244
- const newImport = new Import(this.evalPath(context), features, this.options, this._index || 0);
245
- if (this.layerCss) {
246
- newImport.css = this.layerCss;
247
- newImport.path._fileInfo = this._fileInfo;
248
- }
249
- if (!newImport.css && this.error) {
250
- throw this.error;
251
- }
252
- return newImport;
253
- } else if (this.root) {
254
- if (this.features) {
255
- let featureValue = /** @type {Node[]} */ (this.features.value);
256
- if (Array.isArray(featureValue) && featureValue.length === 1) {
257
- const expr = featureValue[0];
258
- if (expr.type === 'Expression' && Array.isArray(expr.value) && /** @type {Node[]} */ (expr.value).length >= 2) {
259
- featureValue = /** @type {Node[]} */ (expr.value);
260
- const isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
261
- && featureValue[1].type === 'Paren';
262
- if (isLayer) {
263
- this.layerCss = true;
264
- featureValue[0] = new Expression(/** @type {Node[]} */ (featureValue.slice(0, 2)));
265
- featureValue.splice(1, 1);
266
- /** @type {Expression} */ (featureValue[0]).noSpacing = true;
267
- return this;
268
- }
269
- }
270
- }
271
- }
272
- ruleset = new Ruleset(null, utils.copyArray(this.root.rules));
273
- ruleset.evalImports(context);
274
-
275
- return this.features ? new Media(ruleset.rules, /** @type {Node[]} */ (this.features.value)) : ruleset.rules;
276
- } else {
277
- if (this.features) {
278
- let featureValue = /** @type {Node[]} */ (this.features.value);
279
- if (Array.isArray(featureValue) && featureValue.length >= 1) {
280
- featureValue = /** @type {Node[]} */ (featureValue[0].value);
281
- if (Array.isArray(featureValue) && featureValue.length >= 2) {
282
- const isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
283
- && featureValue[1].type === 'Paren';
284
- if (isLayer) {
285
- this.css = true;
286
- featureValue[0] = new Expression(/** @type {Node[]} */ (featureValue.slice(0, 2)));
287
- featureValue.splice(1, 1);
288
- /** @type {Expression} */ (featureValue[0]).noSpacing = true;
289
- return this;
290
- }
291
- }
292
- }
293
- }
294
- return [];
295
- }
296
- }
297
- }
298
-
299
- export default Import;
@@ -1,56 +0,0 @@
1
- // @ts-check
2
- import Node from './node.js';
3
- import Color from './color.js';
4
- import AtRule from './atrule.js';
5
- import DetachedRuleset from './detached-ruleset.js';
6
- import Operation from './operation.js';
7
- import Dimension from './dimension.js';
8
- import Unit from './unit.js';
9
- import Keyword from './keyword.js';
10
- import Variable from './variable.js';
11
- import Property from './property.js';
12
- import Ruleset from './ruleset.js';
13
- import Element from './element.js';
14
- import Attribute from './attribute.js';
15
- import Combinator from './combinator.js';
16
- import Selector from './selector.js';
17
- import Quoted from './quoted.js';
18
- import Expression from './expression.js';
19
- import Declaration from './declaration.js';
20
- import Call from './call.js';
21
- import URL from './url.js';
22
- import Import from './import.js';
23
- import Comment from './comment.js';
24
- import Anonymous from './anonymous.js';
25
- import Value from './value.js';
26
- import JavaScript from './javascript.js';
27
- import Assignment from './assignment.js';
28
- import Condition from './condition.js';
29
- import QueryInParens from './query-in-parens.js';
30
- import Paren from './paren.js';
31
- import Media from './media.js';
32
- import Container from './container.js';
33
- import UnicodeDescriptor from './unicode-descriptor.js';
34
- import Negative from './negative.js';
35
- import Extend from './extend.js';
36
- import VariableCall from './variable-call.js';
37
- import NamespaceValue from './namespace-value.js';
38
-
39
- // mixins
40
- import MixinCall from './mixin-call.js';
41
- import MixinDefinition from './mixin-definition.js';
42
-
43
- export default {
44
- Node, Color, AtRule, DetachedRuleset, Operation,
45
- Dimension, Unit, Keyword, Variable, Property,
46
- Ruleset, Element, Attribute, Combinator, Selector,
47
- Quoted, Expression, Declaration, Call, URL, Import,
48
- Comment, Anonymous, Value, JavaScript, Assignment,
49
- Condition, Paren, Media, Container, QueryInParens,
50
- UnicodeDescriptor, Negative, Extend, VariableCall,
51
- NamespaceValue,
52
- mixin: {
53
- Call: MixinCall,
54
- Definition: MixinDefinition
55
- }
56
- };
@@ -1,106 +0,0 @@
1
- // @ts-check
2
- /** @import { FileInfo } from './node.js' */
3
- /** @import Node from './node.js' */
4
- import Variable from './variable.js';
5
- import Property from './property.js';
6
- import VariableCall from './variable-call.js';
7
- import NamespaceValue from './namespace-value.js';
8
- import { LOOKUP_KEY, VARIABLE_WITH_LOOKUPS } from '../parser/lookup-pattern.js';
9
-
10
- /**
11
- * Interpolation resolved by string replacement at eval time.
12
- *
13
- * The parser consumes `@{name[key]}` structurally via `entities.variableCurly`,
14
- * but `Quoted` and inline JavaScript hold their contents as raw text and can only
15
- * substitute at eval time. Both share this module so the two evaluation paths build
16
- * identical nodes from identical patterns.
17
- */
18
-
19
- /** Matches `@{name}` and `@{name[a][b]}`, capturing the reference. */
20
- export const VARIABLE_INTERPOLATION = new RegExp(`@\\{(${VARIABLE_WITH_LOOKUPS})\\}`, 'g');
21
-
22
- /**
23
- * Matches `${name}`, capturing the reference.
24
- *
25
- * Deliberately narrower than {@link VARIABLE_INTERPOLATION}: a lookup chain is not
26
- * part of the property grammar. `entities.property` parses `$name` with no lookup
27
- * handling, so `$map[key]` is a property reference followed by the literal text
28
- * `[key]`, and a property cannot hold a ruleset to look into in the first place
29
- * (`prop: { … }` is a parse error in every scope). Accepting `${map[key]}` here
30
- * would invent syntax the language does not have.
31
- */
32
- export const PROPERTY_INTERPOLATION = /\$\{([\w-]+)\}/g;
33
-
34
- const LOOKUP_SEGMENT = new RegExp(`\\[(${LOOKUP_KEY})\\]`, 'g');
35
-
36
- // Non-global twins for membership tests. `RegExp.test` on a /g regex advances
37
- // `lastIndex` and so returns alternating results across calls on shared instances.
38
- const HAS_VARIABLE_INTERPOLATION = new RegExp(VARIABLE_INTERPOLATION.source);
39
- const HAS_PROPERTY_INTERPOLATION = new RegExp(PROPERTY_INTERPOLATION.source);
40
-
41
- /**
42
- * Whether text contains an `@{...}` or `${...}` interpolation.
43
- *
44
- * @param {string} text
45
- * @returns {boolean}
46
- */
47
- export function hasInterpolation(text) {
48
- return HAS_VARIABLE_INTERPOLATION.test(text) || HAS_PROPERTY_INTERPOLATION.test(text);
49
- }
50
-
51
- /**
52
- * Split a `name[a][b]` reference into its name and lookup keys.
53
- *
54
- * `lookups` is null for a plain reference, so callers keep using the cheaper
55
- * `Variable`/`Property` node when there is no lookup to resolve.
56
- *
57
- * @param {string} raw
58
- * @returns {{ name: string, lookups: string[] | null }}
59
- */
60
- export function splitLookups(raw) {
61
- const open = raw.indexOf('[');
62
- if (open === -1) {
63
- return { name: raw, lookups: null };
64
- }
65
- /** @type {string[]} */
66
- const lookups = [];
67
- const re = new RegExp(LOOKUP_SEGMENT.source, 'g');
68
- let match;
69
- while ((match = re.exec(raw)) !== null) {
70
- lookups.push(match[1]);
71
- }
72
- return { name: raw.slice(0, open), lookups };
73
- }
74
-
75
- /**
76
- * Build the node for an interpolated `@variable` reference, with or without lookups.
77
- *
78
- * @param {string} raw - the reference text inside `@{...}`
79
- * @param {number} index
80
- * @param {FileInfo} fileInfo
81
- * @returns {Node}
82
- */
83
- export function resolveInterpolatedVariable(raw, index, fileInfo) {
84
- const { name, lookups } = splitLookups(raw);
85
- if (!lookups) {
86
- return new Variable(`@${name}`, index, fileInfo);
87
- }
88
- return new NamespaceValue(
89
- new VariableCall(`@${name}`, index, fileInfo), lookups, index, fileInfo
90
- );
91
- }
92
-
93
- /**
94
- * Build the node for an interpolated `$property` reference.
95
- *
96
- * No lookup handling: see {@link PROPERTY_INTERPOLATION}. Properties have no lookup
97
- * grammar, so `raw` is always a bare name here.
98
- *
99
- * @param {string} raw - the reference text inside `${...}`
100
- * @param {number} index
101
- * @param {FileInfo} fileInfo
102
- * @returns {Node}
103
- */
104
- export function resolveInterpolatedProperty(raw, index, fileInfo) {
105
- return new Property(`$${raw}`, index, fileInfo);
106
- }
@@ -1,45 +0,0 @@
1
- // @ts-check
2
- /** @import { EvalContext, FileInfo } from './node.js' */
3
- import JsEvalNode from './js-eval-node.js';
4
- import Dimension from './dimension.js';
5
- import Quoted from './quoted.js';
6
- import Anonymous from './anonymous.js';
7
-
8
- class JavaScript extends JsEvalNode {
9
- get type() { return 'JavaScript'; }
10
-
11
- /**
12
- * @param {string} string
13
- * @param {boolean} escaped
14
- * @param {number} index
15
- * @param {FileInfo} currentFileInfo
16
- */
17
- constructor(string, escaped, index, currentFileInfo) {
18
- super();
19
- this.escaped = escaped;
20
- this.expression = string;
21
- this._index = index;
22
- this._fileInfo = currentFileInfo;
23
- }
24
-
25
- /**
26
- * @param {EvalContext} context
27
- * @returns {Dimension | Quoted | Anonymous}
28
- */
29
- eval(context) {
30
- const result = this.evaluateJavaScript(this.expression, context);
31
- const type = typeof result;
32
-
33
- if (type === 'number' && !isNaN(/** @type {number} */ (result))) {
34
- return new Dimension(/** @type {number} */ (result));
35
- } else if (type === 'string') {
36
- return new Quoted(`"${result}"`, /** @type {string} */ (result), this.escaped, this._index);
37
- } else if (Array.isArray(result)) {
38
- return new Anonymous(/** @type {string[]} */ (result).join(', '));
39
- } else {
40
- return new Anonymous(/** @type {string} */ (result));
41
- }
42
- }
43
- }
44
-
45
- export default JavaScript;
@@ -1,80 +0,0 @@
1
- // @ts-check
2
- /** @import { EvalContext } from './node.js' */
3
- import Node from './node.js';
4
- import Variable from './variable.js';
5
- import {
6
- VARIABLE_INTERPOLATION,
7
- resolveInterpolatedVariable
8
- } from './interpolated-variable.js';
9
-
10
- class JsEvalNode extends Node {
11
- /**
12
- * @param {string} expression
13
- * @param {EvalContext} context
14
- * @returns {string | number | boolean}
15
- */
16
- evaluateJavaScript(expression, context) {
17
- let result;
18
- const that = this;
19
- /** @type {Record<string, { value: Node, toJS: () => string }>} */
20
- const evalContext = {};
21
-
22
- if (!context.javascriptEnabled) {
23
- throw { message: 'Inline JavaScript is not enabled. Is it set in your options?',
24
- filename: this.fileInfo().filename,
25
- index: this.getIndex() };
26
- }
27
-
28
- expression = expression.replace(VARIABLE_INTERPOLATION, function (_, raw) {
29
- return that.jsify(resolveInterpolatedVariable(
30
- raw, that.getIndex(), that.fileInfo()
31
- ).eval(context));
32
- });
33
-
34
- /** @type {Function} */
35
- let expressionFunc;
36
- try {
37
- expressionFunc = new Function(`return (${expression})`);
38
- } catch (e) {
39
- throw { message: `JavaScript evaluation error: ${/** @type {Error} */ (e).message} from \`${expression}\`` ,
40
- filename: this.fileInfo().filename,
41
- index: this.getIndex() };
42
- }
43
-
44
- const variables = /** @type {Node & { variables: () => Record<string, { value: Node }> }} */ (context.frames[0]).variables();
45
- for (const k in variables) {
46
- // eslint-disable-next-line no-prototype-builtins
47
- if (variables.hasOwnProperty(k)) {
48
- evalContext[k.slice(1)] = {
49
- value: variables[k].value,
50
- toJS: function () {
51
- return this.value.eval(context).toCSS(context);
52
- }
53
- };
54
- }
55
- }
56
-
57
- try {
58
- result = expressionFunc.call(evalContext);
59
- } catch (e) {
60
- throw { message: `JavaScript evaluation error: '${/** @type {Error} */ (e).name}: ${/** @type {Error} */ (e).message.replace(/["]/g, '\'')}'` ,
61
- filename: this.fileInfo().filename,
62
- index: this.getIndex() };
63
- }
64
- return result;
65
- }
66
-
67
- /**
68
- * @param {Node} obj
69
- * @returns {string}
70
- */
71
- jsify(obj) {
72
- if (Array.isArray(obj.value) && (obj.value.length > 1)) {
73
- return `[${obj.value.map(function (v) { return v.toCSS(/** @type {EvalContext} */ (undefined)); }).join(', ')}]`;
74
- } else {
75
- return obj.toCSS(/** @type {EvalContext} */ (undefined));
76
- }
77
- }
78
- }
79
-
80
- export default JsEvalNode;
@@ -1,28 +0,0 @@
1
- // @ts-check
2
- import Node from './node.js';
3
-
4
- /** @import { EvalContext, CSSOutput } from './node.js' */
5
-
6
- class Keyword extends Node {
7
- get type() { return 'Keyword'; }
8
-
9
- /** @param {string} value */
10
- constructor(value) {
11
- super();
12
- this.value = value;
13
- }
14
-
15
- /**
16
- * @param {EvalContext} context
17
- * @param {CSSOutput} output
18
- */
19
- genCSS(context, output) {
20
- if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; }
21
- output.add(/** @type {string} */ (this.value));
22
- }
23
- }
24
-
25
- Keyword.True = new Keyword('true');
26
- Keyword.False = new Keyword('false');
27
-
28
- export default Keyword;