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,1068 +0,0 @@
1
- // @ts-check
2
- /** @import { EvalContext, CSSOutput, TreeVisitor, FileInfo, VisibilityInfo } from './node.js' */
3
- /** @import { FunctionRegistry } from './nested-at-rule.js' */
4
- import Node from './node.js';
5
- import Declaration from './declaration.js';
6
- import Keyword from './keyword.js';
7
- import Comment from './comment.js';
8
- import Paren from './paren.js';
9
- import Selector from './selector.js';
10
- import Element from './element.js';
11
- import Anonymous from './anonymous.js';
12
- import contexts from '../contexts.js';
13
- import globalFunctionRegistry from '../functions/function-registry.js';
14
- import defaultFunc from '../functions/default.js';
15
- import getDebugInfo from './debug-info.js';
16
- import * as utils from '../utils.js';
17
- import Parser from '../parser/parser.js';
18
-
19
- /**
20
- * @typedef {Node & {
21
- * rules?: Node[],
22
- * selectors?: Selector[],
23
- * root?: boolean,
24
- * firstRoot?: boolean,
25
- * allowImports?: boolean,
26
- * functionRegistry?: FunctionRegistry,
27
- * originalRuleset?: Node,
28
- * debugInfo?: { lineNumber: number, fileName: string },
29
- * evalFirst?: boolean,
30
- * isRuleset?: boolean,
31
- * isCharset?: () => boolean,
32
- * merge?: boolean | string,
33
- * multiMedia?: boolean,
34
- * parse?: { context: EvalContext, importManager: object },
35
- * bubbleSelectors?: (selectors: Selector[]) => void
36
- * }} RuleNode
37
- */
38
-
39
- class Ruleset extends Node {
40
- get type() { return 'Ruleset'; }
41
-
42
- /**
43
- * @param {Selector[] | null} selectors
44
- * @param {Node[] | null} rules
45
- * @param {boolean} [strictImports]
46
- * @param {VisibilityInfo} [visibilityInfo]
47
- */
48
- constructor(selectors, rules, strictImports, visibilityInfo) {
49
- super();
50
- /** @type {Selector[] | null} */
51
- this.selectors = selectors;
52
- /** @type {Node[] | null} */
53
- this.rules = rules;
54
- /** @type {Object<string, { rule: Node, path: Node[] }[]>} */
55
- this._lookups = {};
56
- /** @type {Object<string, Declaration> | null} */
57
- this._variables = null;
58
- /** @type {Object<string, Declaration[]> | null} */
59
- this._properties = null;
60
- /** @type {boolean | undefined} */
61
- this.strictImports = strictImports;
62
- this.copyVisibilityInfo(visibilityInfo);
63
- this.allowRoot = true;
64
- /** @type {boolean} */
65
- this.isRuleset = true;
66
-
67
- /** @type {boolean | undefined} */
68
- this.root = undefined;
69
- /** @type {boolean | undefined} */
70
- this.firstRoot = undefined;
71
- /** @type {boolean | undefined} */
72
- this.allowImports = undefined;
73
- /** @type {FunctionRegistry | undefined} */
74
- this.functionRegistry = undefined;
75
- /** @type {Node | undefined} */
76
- this.originalRuleset = undefined;
77
- /** @type {{ lineNumber: number, fileName: string } | undefined} */
78
- this.debugInfo = undefined;
79
- /** @type {Selector[][] | undefined} */
80
- this.paths = undefined;
81
- /** @type {Ruleset[] | null | undefined} */
82
- this._rulesets = undefined;
83
- /** @type {boolean | undefined} */
84
- this.evalFirst = undefined;
85
- this.setParent(this.selectors, this);
86
- this.setParent(this.rules, this);
87
- }
88
-
89
- isRulesetLike() { return true; }
90
-
91
- /** @param {TreeVisitor} visitor */
92
- accept(visitor) {
93
- if (this.paths) {
94
- this.paths = /** @type {Selector[][]} */ (/** @type {unknown} */ (visitor.visitArray(/** @type {Node[]} */ (/** @type {unknown} */ (this.paths)), true)));
95
- } else if (this.selectors) {
96
- this.selectors = /** @type {Selector[]} */ (visitor.visitArray(this.selectors));
97
- }
98
- if (this.rules && this.rules.length) {
99
- this.rules = visitor.visitArray(this.rules);
100
- }
101
- }
102
-
103
- /** @param {EvalContext} context */
104
- eval(context) {
105
- /** @type {Selector[] | undefined} */
106
- let selectors;
107
- /** @type {number} */
108
- let selCnt;
109
- /** @type {Selector} */
110
- let selector;
111
- /** @type {number} */
112
- let i;
113
- /** @type {boolean | undefined} */
114
- let hasVariable;
115
- let hasOnePassingSelector = false;
116
-
117
- if (this.selectors && (selCnt = this.selectors.length)) {
118
- selectors = new Array(selCnt);
119
- defaultFunc.error({
120
- type: 'Syntax',
121
- message: 'it is currently only allowed in parametric mixin guards,'
122
- });
123
-
124
- for (i = 0; i < selCnt; i++) {
125
- selector = /** @type {Selector} */ (this.selectors[i].eval(context));
126
- for (let j = 0; j < selector.elements.length; j++) {
127
- if (selector.elements[j].isVariable) {
128
- hasVariable = true;
129
- break;
130
- }
131
- }
132
- selectors[i] = selector;
133
- if (selector.evaldCondition) {
134
- hasOnePassingSelector = true;
135
- }
136
- }
137
-
138
- if (hasVariable) {
139
- const toParseSelectors = new Array(selCnt);
140
- for (i = 0; i < selCnt; i++) {
141
- selector = selectors[i];
142
- toParseSelectors[i] = selector.toCSS(context);
143
- }
144
- const startingIndex = selectors[0].getIndex();
145
- const selectorFileInfo = selectors[0].fileInfo();
146
- new (/** @type {new (...args: [EvalContext, object, FileInfo, number]) => { parseNode: Function }} */ (/** @type {unknown} */ (Parser)))(context, /** @type {{ context: EvalContext, importManager: object }} */ (this.parse).importManager, selectorFileInfo, startingIndex).parseNode(
147
- toParseSelectors.join(','),
148
- ['selectors'],
149
- function(/** @type {Error | null} */ err, /** @type {Node[]} */ result) {
150
- if (result) {
151
- selectors = /** @type {Selector[]} */ (utils.flattenArray(result));
152
- }
153
- });
154
- }
155
-
156
- defaultFunc.reset();
157
- } else {
158
- hasOnePassingSelector = true;
159
- }
160
-
161
- let rules = this.rules ? utils.copyArray(this.rules) : null;
162
- const ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo());
163
- /** @type {Node} */
164
- let rule;
165
- /** @type {Node} */
166
- let subRule;
167
-
168
- ruleset.originalRuleset = this;
169
- ruleset.root = this.root;
170
- ruleset.firstRoot = this.firstRoot;
171
- ruleset.allowImports = this.allowImports;
172
-
173
- if (this.debugInfo) {
174
- ruleset.debugInfo = this.debugInfo;
175
- }
176
-
177
- if (!hasOnePassingSelector) {
178
- /** @type {Node[]} */ (rules).length = 0;
179
- }
180
-
181
- // push the current ruleset to the frames stack
182
- const ctxFrames = context.frames;
183
-
184
- // inherit a function registry from the frames stack when possible;
185
- // otherwise from the global registry
186
- /** @type {FunctionRegistry | undefined} */
187
- let foundRegistry;
188
- for (let fi = 0, fn = ctxFrames.length; fi !== fn; ++fi) {
189
- foundRegistry = /** @type {RuleNode} */ (ctxFrames[fi]).functionRegistry;
190
- if (foundRegistry) { break; }
191
- }
192
- ruleset.functionRegistry = (foundRegistry || globalFunctionRegistry).inherit();
193
- ctxFrames.unshift(ruleset);
194
-
195
- // currrent selectors
196
- /** @type {Selector[][] | undefined} */
197
- let ctxSelectors = /** @type {EvalContext & { selectors?: Selector[][] }} */ (context).selectors;
198
- if (!ctxSelectors) {
199
- /** @type {EvalContext & { selectors?: Selector[][] }} */ (context).selectors = ctxSelectors = [];
200
- }
201
- ctxSelectors.unshift(this.selectors);
202
-
203
- // Evaluate imports
204
- if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
205
- ruleset.evalImports(context);
206
- }
207
-
208
- // Store the frames around mixin definitions,
209
- // so they can be evaluated like closures when the time comes.
210
- const rsRules = /** @type {Node[]} */ (ruleset.rules);
211
- for (i = 0; (rule = rsRules[i]); i++) {
212
- if (/** @type {RuleNode} */ (rule).evalFirst) {
213
- rsRules[i] = rule.eval(context);
214
- }
215
- }
216
-
217
- const mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0;
218
-
219
- // Evaluate mixin calls.
220
- for (i = 0; (rule = rsRules[i]); i++) {
221
- if (rule.type === 'MixinCall') {
222
- /* jshint loopfunc:true */
223
- rules = /** @type {Node[]} */ (/** @type {unknown} */ (rule.eval(context))).filter(function(/** @type {Node & { variable?: boolean }} */ r) {
224
- if ((r instanceof Declaration) && r.variable) {
225
- // do not pollute the scope if the variable is
226
- // already there. consider returning false here
227
- // but we need a way to "return" variable from mixins
228
- return !(ruleset.variable(/** @type {string} */ (r.name)));
229
- }
230
- return true;
231
- });
232
- rsRules.splice.apply(rsRules, /** @type {[number, number, ...Node[]]} */ ([i, 1].concat(rules)));
233
- i += rules.length - 1;
234
- ruleset.resetCache();
235
- } else if (rule.type === 'VariableCall') {
236
- /* jshint loopfunc:true */
237
- rules = /** @type {Node[]} */ (/** @type {RuleNode} */ (rule.eval(context)).rules).filter(function(/** @type {Node & { variable?: boolean }} */ r) {
238
- if ((r instanceof Declaration) && r.variable) {
239
- // do not pollute the scope at all
240
- return false;
241
- }
242
- return true;
243
- });
244
- rsRules.splice.apply(rsRules, /** @type {[number, number, ...Node[]]} */ ([i, 1].concat(rules)));
245
- i += rules.length - 1;
246
- ruleset.resetCache();
247
- }
248
- }
249
-
250
- // Evaluate everything else
251
- for (i = 0; (rule = rsRules[i]); i++) {
252
- if (!/** @type {RuleNode} */ (rule).evalFirst) {
253
- rsRules[i] = rule = rule.eval ? rule.eval(context) : rule;
254
- }
255
- }
256
-
257
- // Evaluate everything else
258
- for (i = 0; (rule = rsRules[i]); i++) {
259
- // for rulesets, check if it is a css guard and can be removed
260
- if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) {
261
- // check if it can be folded in (e.g. & where)
262
- if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) {
263
- rsRules.splice(i--, 1);
264
-
265
- for (let j = 0; (subRule = rule.rules[j]); j++) {
266
- if (subRule instanceof Node) {
267
- subRule.copyVisibilityInfo(rule.visibilityInfo());
268
- if (!(subRule instanceof Declaration) || !subRule.variable) {
269
- rsRules.splice(++i, 0, subRule);
270
- }
271
- }
272
- }
273
- }
274
- }
275
- }
276
-
277
- // Pop the stack
278
- ctxFrames.shift();
279
- ctxSelectors.shift();
280
-
281
- if (context.mediaBlocks) {
282
- for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) {
283
- /** @type {RuleNode} */ (context.mediaBlocks[i]).bubbleSelectors(selectors);
284
- }
285
- }
286
-
287
- return ruleset;
288
- }
289
-
290
- /** @param {EvalContext} context */
291
- evalImports(context) {
292
- const rules = this.rules;
293
- /** @type {number} */
294
- let i;
295
- /** @type {Node | Node[]} */
296
- let importRules;
297
- if (!rules) { return; }
298
-
299
- for (i = 0; i < rules.length; i++) {
300
- if (rules[i].type === 'Import') {
301
- importRules = rules[i].eval(context);
302
- if (importRules && (/** @type {Node[]} */ (/** @type {unknown} */ (importRules)).length || /** @type {Node[]} */ (/** @type {unknown} */ (importRules)).length === 0)) {
303
- const importArr = /** @type {Node[]} */ (/** @type {unknown} */ (importRules));
304
- rules.splice(i, 1, ...importArr);
305
- i += importArr.length - 1;
306
- } else {
307
- rules.splice(i, 1, importRules);
308
- }
309
- this.resetCache();
310
- }
311
- }
312
- }
313
-
314
- makeImportant() {
315
- const result = new Ruleset(this.selectors, /** @type {Node[]} */ (this.rules).map(function (/** @type {Node & { makeImportant?: () => Node }} */ r) {
316
- if (r.makeImportant) {
317
- return r.makeImportant();
318
- } else {
319
- return r;
320
- }
321
- }), this.strictImports, this.visibilityInfo());
322
-
323
- return result;
324
- }
325
-
326
- /** @param {Node[] | object[] | null} [args] */
327
- matchArgs(args) {
328
- return !args || args.length === 0;
329
- }
330
-
331
- /**
332
- * @param {Node[] | object[] | null} args
333
- * @param {EvalContext} context
334
- */
335
- matchCondition(args, context) {
336
- const lastSelector = /** @type {Selector[]} */ (this.selectors)[/** @type {Selector[]} */ (this.selectors).length - 1];
337
- if (!lastSelector.evaldCondition) {
338
- return false;
339
- }
340
- if (lastSelector.condition &&
341
- !lastSelector.condition.eval(
342
- new contexts.Eval(context,
343
- context.frames))) {
344
- return false;
345
- }
346
- return true;
347
- }
348
-
349
- resetCache() {
350
- this._rulesets = null;
351
- this._variables = null;
352
- this._properties = null;
353
- this._lookups = {};
354
- }
355
-
356
- variables() {
357
- if (!this._variables) {
358
- this._variables = !this.rules ? {} : this.rules.reduce(function (/** @type {Object<string, Declaration>} */ hash, /** @type {Node} */ r) {
359
- if (r instanceof Declaration && r.variable === true) {
360
- hash[/** @type {string} */ (r.name)] = r;
361
- }
362
- // when evaluating variables in an import statement, imports have not been eval'd
363
- // so we need to go inside import statements.
364
- // guard against root being a string (in the case of inlined less)
365
- if (r.type === 'Import' && /** @type {RuleNode} */ (r).root && /** @type {RuleNode & { root: Ruleset }} */ (r).root.variables) {
366
- const vars = /** @type {RuleNode & { root: Ruleset }} */ (r).root.variables();
367
- for (const name in vars) {
368
- if (Object.prototype.hasOwnProperty.call(vars, name)) {
369
- hash[name] = /** @type {Declaration} */ (/** @type {RuleNode & { root: Ruleset }} */ (r).root.variable(name));
370
- }
371
- }
372
- }
373
- return hash;
374
- }, {});
375
- }
376
- return this._variables;
377
- }
378
-
379
- properties() {
380
- if (!this._properties) {
381
- this._properties = !this.rules ? {} : this.rules.reduce(function (/** @type {Object<string, Declaration[]>} */ hash, /** @type {Node} */ r) {
382
- if (r instanceof Declaration && r.variable !== true) {
383
- const name = (/** @type {Node[]} */ (r.name).length === 1) && (/** @type {Node[]} */ (r.name)[0] instanceof Keyword) ?
384
- /** @type {string} */ (/** @type {Node[]} */ (r.name)[0].value) : /** @type {string} */ (r.name);
385
- // Properties don't overwrite as they can merge
386
- if (!hash[`$${name}`]) {
387
- hash[`$${name}`] = [ r ];
388
- }
389
- else {
390
- hash[`$${name}`].push(r);
391
- }
392
- }
393
- return hash;
394
- }, {});
395
- }
396
- return this._properties;
397
- }
398
-
399
- /** @param {string} name */
400
- variable(name) {
401
- const decl = this.variables()[name];
402
- if (decl) {
403
- return this.parseValue(decl);
404
- }
405
- }
406
-
407
- /** @param {string} name */
408
- property(name) {
409
- const decl = this.properties()[name];
410
- if (decl) {
411
- return this.parseValue(decl);
412
- }
413
- }
414
-
415
- lastDeclaration() {
416
- for (let i = /** @type {Node[]} */ (this.rules).length; i > 0; i--) {
417
- const decl = /** @type {Node[]} */ (this.rules)[i - 1];
418
- if (decl instanceof Declaration) {
419
- return this.parseValue(decl);
420
- }
421
- }
422
- }
423
-
424
- /** @param {Declaration | Declaration[]} toParse */
425
- parseValue(toParse) {
426
- const self = this;
427
- /** @param {Declaration} decl */
428
- function transformDeclaration(decl) {
429
- if (decl.value instanceof Anonymous &&
430
- !decl.value._preventReparse &&
431
- !/** @type {Declaration & { parsed?: boolean }} */ (decl).parsed) {
432
- if (typeof decl.value.value === 'string') {
433
- new (/** @type {new (...args: [EvalContext, object, FileInfo, number]) => { parseNode: Function }} */ (/** @type {unknown} */ (Parser)))(/** @type {{ context: EvalContext, importManager: object }} */ (/** @type {Ruleset} */ (this).parse).context, /** @type {{ context: EvalContext, importManager: object }} */ (/** @type {Ruleset} */ (this).parse).importManager, decl.fileInfo(), decl.value.getIndex()).parseNode(
434
- decl.value.value,
435
- ['value', 'important'],
436
- function(/** @type {Error | null} */ err, /** @type {Node[]} */ result) {
437
- if (err) {
438
- decl.parsed = /** @type {Node} */ (/** @type {unknown} */ (true));
439
- }
440
- if (result) {
441
- decl.value = result[0];
442
- /** @type {Declaration & { important?: string }} */ (decl).important = /** @type {string} */ (/** @type {unknown} */ (result[1])) || '';
443
- decl.parsed = /** @type {Node} */ (/** @type {unknown} */ (true));
444
- }
445
- });
446
- } else {
447
- decl.parsed = /** @type {Node} */ (/** @type {unknown} */ (true));
448
- }
449
-
450
- return decl;
451
- }
452
- else {
453
- return decl;
454
- }
455
- }
456
- if (!Array.isArray(toParse)) {
457
- return transformDeclaration.call(self, toParse);
458
- }
459
- else {
460
- /** @type {Declaration[]} */
461
- const nodes = [];
462
- for (let ti = 0; ti < toParse.length; ti++) {
463
- nodes.push(transformDeclaration.call(self, toParse[ti]));
464
- }
465
- return nodes;
466
- }
467
- }
468
-
469
- rulesets() {
470
- if (!this.rules) { return []; }
471
-
472
- /** @type {Node[]} */
473
- const filtRules = [];
474
- const rules = this.rules;
475
- /** @type {number} */
476
- let i;
477
- /** @type {Node} */
478
- let rule;
479
-
480
- for (i = 0; (rule = rules[i]); i++) {
481
- if (/** @type {RuleNode} */ (rule).isRuleset) {
482
- filtRules.push(rule);
483
- }
484
- }
485
-
486
- return filtRules;
487
- }
488
-
489
- /** @param {Node} rule */
490
- prependRule(rule) {
491
- const rules = this.rules;
492
- if (rules) {
493
- rules.unshift(rule);
494
- } else {
495
- this.rules = [ rule ];
496
- }
497
- this.setParent(rule, this);
498
- }
499
-
500
- /**
501
- * @param {Selector} selector
502
- * @param {Ruleset | null} [self]
503
- * @param {((rule: Node) => boolean)} [filter]
504
- * @returns {{ rule: Node, path: Node[] }[]}
505
- */
506
- find(selector, self, filter) {
507
- self = self || this;
508
- /** @type {{ rule: Node, path: Node[] }[]} */
509
- const rules = [];
510
- /** @type {number | undefined} */
511
- let match;
512
- /** @type {{ rule: Node, path: Node[] }[]} */
513
- let foundMixins;
514
- const key = selector.toCSS(/** @type {EvalContext} */ ({}));
515
-
516
- if (key in this._lookups) { return /** @type {{ rule: Node, path: Node[] }[]} */ (this._lookups[key]); }
517
-
518
- this.rulesets().forEach(function (rule) {
519
- if (rule !== self) {
520
- for (let j = 0; j < /** @type {RuleNode} */ (rule).selectors.length; j++) {
521
- match = selector.match(/** @type {RuleNode} */ (rule).selectors[j]);
522
- if (match) {
523
- if (selector.elements.length > match) {
524
- if (!filter || filter(rule)) {
525
- foundMixins = /** @type {Ruleset} */ (/** @type {unknown} */ (rule)).find(new Selector(selector.elements.slice(match)), self, filter);
526
- for (let i = 0; i < foundMixins.length; ++i) {
527
- foundMixins[i].path.push(rule);
528
- }
529
- Array.prototype.push.apply(rules, foundMixins);
530
- }
531
- } else {
532
- rules.push({ rule, path: []});
533
- }
534
- break;
535
- }
536
- }
537
- }
538
- });
539
- this._lookups[key] = rules;
540
- return rules;
541
- }
542
-
543
- /**
544
- * @param {EvalContext} context
545
- * @param {CSSOutput} output
546
- */
547
- genCSS(context, output) {
548
- /** @type {number} */
549
- let i;
550
- /** @type {number} */
551
- let j;
552
- /** @type {Node[]} */
553
- const charsetRuleNodes = [];
554
- /** @type {Node[]} */
555
- let ruleNodes = [];
556
-
557
- let // Line number debugging
558
- debugInfo;
559
-
560
- /** @type {Node} */
561
- let rule;
562
- /** @type {Selector[]} */
563
- let path;
564
-
565
- context.tabLevel = (context.tabLevel || 0);
566
-
567
- if (!this.root) {
568
- context.tabLevel++;
569
- }
570
-
571
- const tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' ');
572
- const tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' ');
573
- /** @type {string} */
574
- let sep;
575
-
576
- let charsetNodeIndex = 0;
577
- let importNodeIndex = 0;
578
- for (i = 0; (rule = /** @type {Node[]} */ (this.rules)[i]); i++) {
579
- if (rule instanceof Comment) {
580
- if (importNodeIndex === i) {
581
- importNodeIndex++;
582
- }
583
- ruleNodes.push(rule);
584
- } else if (/** @type {RuleNode} */ (rule).isCharset && /** @type {RuleNode} */ (rule).isCharset()) {
585
- ruleNodes.splice(charsetNodeIndex, 0, rule);
586
- charsetNodeIndex++;
587
- importNodeIndex++;
588
- } else if (rule.type === 'Import') {
589
- ruleNodes.splice(importNodeIndex, 0, rule);
590
- importNodeIndex++;
591
- } else {
592
- ruleNodes.push(rule);
593
- }
594
- }
595
- ruleNodes = charsetRuleNodes.concat(ruleNodes);
596
-
597
- // If this is the root node, we don't render
598
- // a selector, or {}.
599
- if (!this.root) {
600
- debugInfo = getDebugInfo(context, /** @type {{ debugInfo: { lineNumber: number, fileName: string } }} */ (/** @type {unknown} */ (this)), tabSetStr);
601
-
602
- if (debugInfo) {
603
- output.add(debugInfo);
604
- output.add(tabSetStr);
605
- }
606
-
607
- const paths = /** @type {Selector[][]} */ (this.paths);
608
- const pathCnt = paths.length;
609
- /** @type {number} */
610
- let pathSubCnt;
611
-
612
- sep = context.compress ? ',' : (`,\n${tabSetStr}`);
613
-
614
- for (i = 0; i < pathCnt; i++) {
615
- path = paths[i];
616
- if (!(pathSubCnt = path.length)) { continue; }
617
- if (i > 0) { output.add(sep); }
618
-
619
- /** @type {EvalContext & { firstSelector?: boolean }} */ (context).firstSelector = true;
620
- path[0].genCSS(context, output);
621
-
622
- /** @type {EvalContext & { firstSelector?: boolean }} */ (context).firstSelector = false;
623
- for (j = 1; j < pathSubCnt; j++) {
624
- path[j].genCSS(context, output);
625
- }
626
- }
627
-
628
- output.add((context.compress ? '{' : ' {\n') + tabRuleStr);
629
- }
630
-
631
- // Compile rules and rulesets
632
- for (i = 0; (rule = ruleNodes[i]); i++) {
633
-
634
- if (i + 1 === ruleNodes.length) {
635
- context.lastRule = true;
636
- }
637
-
638
- const currentLastRule = context.lastRule;
639
- if (rule.isRulesetLike()) {
640
- context.lastRule = false;
641
- }
642
-
643
- if (rule.genCSS) {
644
- rule.genCSS(context, output);
645
- } else if (rule.value) {
646
- output.add(/** @type {string} */ (rule.value).toString());
647
- }
648
-
649
- context.lastRule = currentLastRule;
650
-
651
- if (!context.lastRule && rule.isVisible()) {
652
- output.add(context.compress ? '' : (`\n${tabRuleStr}`));
653
- } else {
654
- context.lastRule = false;
655
- }
656
- }
657
-
658
- if (!this.root) {
659
- output.add((context.compress ? '}' : `\n${tabSetStr}}`));
660
- context.tabLevel--;
661
- }
662
-
663
- if (!output.isEmpty() && !context.compress && this.firstRoot) {
664
- output.add('\n');
665
- }
666
- }
667
-
668
- /**
669
- * @param {Selector[][]} paths
670
- * @param {Selector[][]} context
671
- * @param {Selector[]} selectors
672
- */
673
- joinSelectors(paths, context, selectors) {
674
- for (let s = 0; s < selectors.length; s++) {
675
- this.joinSelector(paths, context, selectors[s]);
676
- }
677
- }
678
-
679
- /**
680
- * @param {Selector[][]} paths
681
- * @param {Selector[][]} context
682
- * @param {Selector} selector
683
- */
684
- joinSelector(paths, context, selector) {
685
-
686
- /**
687
- * @param {Selector[]} elementsToPak
688
- * @param {Element} originalElement
689
- * @returns {Paren}
690
- */
691
- function createParenthesis(elementsToPak, originalElement) {
692
- /** @type {Paren} */
693
- let replacementParen;
694
- /** @type {number} */
695
- let j;
696
- if (elementsToPak.length === 0) {
697
- replacementParen = new Paren(elementsToPak[0]);
698
- } else {
699
- const insideParent = new Array(elementsToPak.length);
700
- for (j = 0; j < elementsToPak.length; j++) {
701
- insideParent[j] = new Element(
702
- null,
703
- elementsToPak[j],
704
- originalElement.isVariable,
705
- originalElement._index,
706
- originalElement._fileInfo
707
- );
708
- }
709
- replacementParen = new Paren(new Selector(insideParent));
710
- }
711
- return replacementParen;
712
- }
713
-
714
- /**
715
- * @param {Paren | Selector} containedElement
716
- * @param {Element} originalElement
717
- * @returns {Selector}
718
- */
719
- function createSelector(containedElement, originalElement) {
720
- /** @type {Element} */
721
- let element;
722
- /** @type {Selector} */
723
- let selector;
724
- element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo);
725
- selector = new Selector([element]);
726
- return selector;
727
- }
728
-
729
- /**
730
- * @param {Selector[]} beginningPath
731
- * @param {Selector[]} addPath
732
- * @param {Element} replacedElement
733
- * @param {Selector} originalSelector
734
- * @returns {Selector[]}
735
- */
736
- function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
737
- /** @type {Selector[]} */
738
- let newSelectorPath;
739
- /** @type {Selector} */
740
- let lastSelector;
741
- /** @type {Selector} */
742
- let newJoinedSelector;
743
- // our new selector path
744
- newSelectorPath = [];
745
-
746
- // construct the joined selector - if & is the first thing this will be empty,
747
- // if not newJoinedSelector will be the last set of elements in the selector
748
- if (beginningPath.length > 0) {
749
- newSelectorPath = utils.copyArray(beginningPath);
750
- lastSelector = newSelectorPath.pop();
751
- newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements));
752
- }
753
- else {
754
- newJoinedSelector = originalSelector.createDerived([]);
755
- }
756
-
757
- if (addPath.length > 0) {
758
- // /deep/ is a CSS4 selector - (removed, so should deprecate)
759
- // that is valid without anything in front of it
760
- // so if the & does not have a combinator that is "" or " " then
761
- // and there is a combinator on the parent, then grab that.
762
- // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
763
- let combinator = replacedElement.combinator;
764
-
765
- const parentEl = addPath[0].elements[0];
766
- if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
767
- combinator = parentEl.combinator;
768
- }
769
- // join the elements so far with the first part of the parent
770
- newJoinedSelector.elements.push(new Element(
771
- combinator,
772
- parentEl.value,
773
- replacedElement.isVariable,
774
- replacedElement._index,
775
- replacedElement._fileInfo
776
- ));
777
- newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
778
- }
779
-
780
- // now add the joined selector - but only if it is not empty
781
- if (newJoinedSelector.elements.length !== 0) {
782
- newSelectorPath.push(newJoinedSelector);
783
- }
784
-
785
- // put together the parent selectors after the join (e.g. the rest of the parent)
786
- if (addPath.length > 1) {
787
- let restOfPath = addPath.slice(1);
788
- restOfPath = restOfPath.map(function (/** @type {Selector} */ selector) {
789
- return selector.createDerived(selector.elements, []);
790
- });
791
- newSelectorPath = newSelectorPath.concat(restOfPath);
792
- }
793
- return newSelectorPath;
794
- }
795
-
796
- /**
797
- * @param {Selector[][]} beginningPath
798
- * @param {Selector[]} addPaths
799
- * @param {Element} replacedElement
800
- * @param {Selector} originalSelector
801
- * @param {Selector[][]} result
802
- * @returns {Selector[][]}
803
- */
804
- function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
805
- /** @type {number} */
806
- let j;
807
- for (j = 0; j < beginningPath.length; j++) {
808
- const newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
809
- result.push(newSelectorPath);
810
- }
811
- return result;
812
- }
813
-
814
- /**
815
- * @param {Element[]} elements
816
- * @param {Selector[][]} selectors
817
- */
818
- function mergeElementsOnToSelectors(elements, selectors) {
819
- /** @type {number} */
820
- let i;
821
- /** @type {Selector[]} */
822
- let sel;
823
-
824
- if (elements.length === 0) {
825
- return ;
826
- }
827
- if (selectors.length === 0) {
828
- selectors.push([ new Selector(elements) ]);
829
- return;
830
- }
831
-
832
- for (i = 0; (sel = selectors[i]); i++) {
833
- // if the previous thing in sel is a parent this needs to join on to it
834
- if (sel.length > 0) {
835
- sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
836
- }
837
- else {
838
- sel.push(new Selector(elements));
839
- }
840
- }
841
- }
842
-
843
- /**
844
- * @param {Selector[][]} paths
845
- * @param {Selector[][]} context
846
- * @param {Selector} inSelector
847
- * @returns {boolean}
848
- */
849
- function replaceParentSelector(paths, context, inSelector) {
850
- // The paths are [[Selector]]
851
- // The first list is a list of comma separated selectors
852
- // The inner list is a list of inheritance separated selectors
853
- // e.g.
854
- // .a, .b {
855
- // .c {
856
- // }
857
- // }
858
- // == [[.a] [.c]] [[.b] [.c]]
859
- //
860
- /** @type {number} */
861
- let i;
862
- /** @type {number} */
863
- let j;
864
- /** @type {number} */
865
- let k;
866
- /** @type {Element[]} */
867
- let currentElements;
868
- /** @type {Selector[][]} */
869
- let newSelectors;
870
- /** @type {Selector[][]} */
871
- let selectorsMultiplied;
872
- /** @type {Selector[]} */
873
- let sel;
874
- /** @type {Element} */
875
- let el;
876
- let hadParentSelector = false;
877
- /** @type {number} */
878
- let length;
879
- /** @type {Selector} */
880
- let lastSelector;
881
-
882
- /**
883
- * @param {Element} element
884
- * @returns {Selector | null}
885
- */
886
- function findNestedSelector(element) {
887
- /** @type {Node} */
888
- let maybeSelector;
889
- if (!(element.value instanceof Paren)) {
890
- return null;
891
- }
892
-
893
- maybeSelector = /** @type {Node} */ (element.value.value);
894
- if (!(maybeSelector instanceof Selector)) {
895
- return null;
896
- }
897
-
898
- return maybeSelector;
899
- }
900
-
901
- // the elements from the current selector so far
902
- currentElements = [];
903
- // the current list of new selectors to add to the path.
904
- // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
905
- // by the parents
906
- newSelectors = [
907
- []
908
- ];
909
-
910
- for (i = 0; (el = inSelector.elements[i]); i++) {
911
- // non parent reference elements just get added
912
- if (el.value !== '&') {
913
- const nestedSelector = findNestedSelector(el);
914
- if (nestedSelector !== null) {
915
- // merge the current list of non parent selector elements
916
- // on to the current list of selectors to add
917
- mergeElementsOnToSelectors(currentElements, newSelectors);
918
-
919
- /** @type {Selector[][]} */
920
- const nestedPaths = [];
921
- /** @type {boolean | undefined} */
922
- let replaced;
923
- /** @type {Selector[][]} */
924
- const replacedNewSelectors = [];
925
-
926
- // Check if this is a comma-separated selector list inside the paren
927
- // e.g. :not(&.a, &.b) produces Selector([Selector, Anonymous(','), Selector])
928
- const hasSubSelectors = nestedSelector.elements.some(e => e instanceof Selector);
929
-
930
- if (hasSubSelectors) {
931
- // Process each sub-selector individually
932
- /** @type {(Element | Selector)[]} */
933
- const resolvedElements = [];
934
- for (const subEl of nestedSelector.elements) {
935
- if (subEl instanceof Selector) {
936
- /** @type {Selector[][]} */
937
- const subPaths = [];
938
- const subReplaced = replaceParentSelector(subPaths, context, subEl);
939
- replaced = replaced || subReplaced;
940
- if (subPaths.length > 0 && subPaths[0].length > 0) {
941
- resolvedElements.push(subPaths[0][0]);
942
- } else {
943
- resolvedElements.push(subEl);
944
- }
945
- } else {
946
- resolvedElements.push(subEl);
947
- }
948
- }
949
- hadParentSelector = hadParentSelector || /** @type {boolean} */ (replaced);
950
- const resolvedNestedSelector = new Selector(resolvedElements);
951
- const replacementSelector = createSelector(createParenthesis([resolvedNestedSelector], el), el);
952
- addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
953
- } else {
954
- replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
955
- hadParentSelector = hadParentSelector || replaced;
956
- // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
957
- for (k = 0; k < nestedPaths.length; k++) {
958
- const replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
959
- addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
960
- }
961
- }
962
- newSelectors = replacedNewSelectors;
963
- currentElements = [];
964
- } else {
965
- currentElements.push(el);
966
- }
967
-
968
- } else {
969
- hadParentSelector = true;
970
- // the new list of selectors to add
971
- selectorsMultiplied = [];
972
-
973
- // merge the current list of non parent selector elements
974
- // on to the current list of selectors to add
975
- mergeElementsOnToSelectors(currentElements, newSelectors);
976
-
977
- // loop through our current selectors
978
- for (j = 0; j < newSelectors.length; j++) {
979
- sel = newSelectors[j];
980
- // if we don't have any parent paths, the & might be in a mixin so that it can be used
981
- // whether there are parents or not
982
- if (context.length === 0) {
983
- // the combinator used on el should now be applied to the next element instead so that
984
- // it is not lost
985
- if (sel.length > 0) {
986
- sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo));
987
- }
988
- selectorsMultiplied.push(sel);
989
- }
990
- else {
991
- // and the parent selectors
992
- for (k = 0; k < context.length; k++) {
993
- // We need to put the current selectors
994
- // then join the last selector's elements on to the parents selectors
995
- const newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);
996
- // add that to our new set of selectors
997
- selectorsMultiplied.push(newSelectorPath);
998
- }
999
- }
1000
- }
1001
-
1002
- // our new selectors has been multiplied, so reset the state
1003
- newSelectors = selectorsMultiplied;
1004
- currentElements = [];
1005
- }
1006
- }
1007
-
1008
- // if we have any elements left over (e.g. .a& .b == .b)
1009
- // add them on to all the current selectors
1010
- mergeElementsOnToSelectors(currentElements, newSelectors);
1011
-
1012
- for (i = 0; i < newSelectors.length; i++) {
1013
- length = newSelectors[i].length;
1014
- if (length > 0) {
1015
- paths.push(newSelectors[i]);
1016
- lastSelector = newSelectors[i][length - 1];
1017
- newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList);
1018
- }
1019
- }
1020
-
1021
- return hadParentSelector;
1022
- }
1023
-
1024
- /**
1025
- * @param {VisibilityInfo} visibilityInfo
1026
- * @param {Selector} deriveFrom
1027
- */
1028
- function deriveSelector(visibilityInfo, deriveFrom) {
1029
- const newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition);
1030
- newSelector.copyVisibilityInfo(visibilityInfo);
1031
- return newSelector;
1032
- }
1033
-
1034
- // joinSelector code follows
1035
- /** @type {number} */
1036
- let i;
1037
- /** @type {Selector[][]} */
1038
- let newPaths;
1039
- /** @type {boolean} */
1040
- let hadParentSelector;
1041
-
1042
- newPaths = [];
1043
- hadParentSelector = replaceParentSelector(newPaths, context, selector);
1044
-
1045
- if (!hadParentSelector) {
1046
- if (context.length > 0) {
1047
- newPaths = [];
1048
- for (i = 0; i < context.length; i++) {
1049
-
1050
- const concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo()));
1051
-
1052
- concatenated.push(selector);
1053
- newPaths.push(concatenated);
1054
- }
1055
- }
1056
- else {
1057
- newPaths = [[selector]];
1058
- }
1059
- }
1060
-
1061
- for (i = 0; i < newPaths.length; i++) {
1062
- paths.push(newPaths[i]);
1063
- }
1064
-
1065
- }
1066
- }
1067
-
1068
- export default Ruleset;