less 4.8.1 → 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 (129) hide show
  1. package/README.md +19 -5
  2. package/bin/lessc +190 -630
  3. package/dist/less-node.cjs +398 -14282
  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 +33 -40
  13. package/dist/less.cjs +0 -14929
  14. package/dist/less.js +0 -14929
  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 -36
  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/parser-input.js +0 -400
  52. package/lib/less/parser/parser.js +0 -2894
  53. package/lib/less/plugin-manager.js +0 -168
  54. package/lib/less/render.js +0 -41
  55. package/lib/less/source-map-builder.js +0 -82
  56. package/lib/less/source-map-output.js +0 -151
  57. package/lib/less/transform-tree.js +0 -102
  58. package/lib/less/tree/anonymous.js +0 -57
  59. package/lib/less/tree/assignment.js +0 -48
  60. package/lib/less/tree/atrule-syntax.js +0 -8
  61. package/lib/less/tree/atrule.js +0 -340
  62. package/lib/less/tree/attribute.js +0 -63
  63. package/lib/less/tree/call.js +0 -132
  64. package/lib/less/tree/color.js +0 -285
  65. package/lib/less/tree/combinator.js +0 -38
  66. package/lib/less/tree/comment.js +0 -48
  67. package/lib/less/tree/condition.js +0 -65
  68. package/lib/less/tree/container.js +0 -104
  69. package/lib/less/tree/debug-info.js +0 -80
  70. package/lib/less/tree/declaration.js +0 -139
  71. package/lib/less/tree/detached-ruleset.js +0 -45
  72. package/lib/less/tree/dimension.js +0 -215
  73. package/lib/less/tree/element.js +0 -93
  74. package/lib/less/tree/expression.js +0 -100
  75. package/lib/less/tree/extend.js +0 -88
  76. package/lib/less/tree/import.js +0 -299
  77. package/lib/less/tree/index.js +0 -56
  78. package/lib/less/tree/javascript.js +0 -45
  79. package/lib/less/tree/js-eval-node.js +0 -74
  80. package/lib/less/tree/keyword.js +0 -28
  81. package/lib/less/tree/media.js +0 -90
  82. package/lib/less/tree/merge-rules.js +0 -47
  83. package/lib/less/tree/mixin-call.js +0 -283
  84. package/lib/less/tree/mixin-definition.js +0 -319
  85. package/lib/less/tree/namespace-value.js +0 -95
  86. package/lib/less/tree/negative.js +0 -37
  87. package/lib/less/tree/nested-at-rule.js +0 -198
  88. package/lib/less/tree/node.js +0 -310
  89. package/lib/less/tree/operation.js +0 -81
  90. package/lib/less/tree/paren.js +0 -41
  91. package/lib/less/tree/property.js +0 -96
  92. package/lib/less/tree/query-in-parens.js +0 -64
  93. package/lib/less/tree/quoted.js +0 -114
  94. package/lib/less/tree/ruleset.js +0 -1066
  95. package/lib/less/tree/selector.js +0 -201
  96. package/lib/less/tree/unicode-descriptor.js +0 -14
  97. package/lib/less/tree/unit.js +0 -170
  98. package/lib/less/tree/url.js +0 -83
  99. package/lib/less/tree/value.js +0 -60
  100. package/lib/less/tree/variable-call.js +0 -60
  101. package/lib/less/tree/variable.js +0 -85
  102. package/lib/less/utils.js +0 -126
  103. package/lib/less/visitors/extend-visitor.js +0 -505
  104. package/lib/less/visitors/import-sequencer.js +0 -56
  105. package/lib/less/visitors/import-visitor.js +0 -203
  106. package/lib/less/visitors/index.js +0 -15
  107. package/lib/less/visitors/join-selector-visitor.js +0 -65
  108. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  109. package/lib/less/visitors/to-css-visitor.js +0 -332
  110. package/lib/less/visitors/visitor.js +0 -165
  111. package/lib/less-browser/add-default-options.js +0 -53
  112. package/lib/less-browser/bootstrap.js +0 -67
  113. package/lib/less-browser/browser.js +0 -65
  114. package/lib/less-browser/cache.js +0 -43
  115. package/lib/less-browser/error-reporting.js +0 -170
  116. package/lib/less-browser/file-manager.js +0 -112
  117. package/lib/less-browser/image-size.js +0 -28
  118. package/lib/less-browser/index.js +0 -284
  119. package/lib/less-browser/log-listener.js +0 -42
  120. package/lib/less-browser/plugin-loader.js +0 -24
  121. package/lib/less-browser/utils.js +0 -30
  122. package/lib/less-node/environment.js +0 -43
  123. package/lib/less-node/file-manager.js +0 -156
  124. package/lib/less-node/fs.js +0 -14
  125. package/lib/less-node/image-size.js +0 -78
  126. package/lib/less-node/index.js +0 -31
  127. package/lib/less-node/lessc-helper.js +0 -95
  128. package/lib/less-node/plugin-loader.js +0 -62
  129. package/lib/less-node/url-file-manager.js +0 -60
@@ -1,1066 +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 && !/** @type {Declaration & { parsed?: boolean }} */ (decl).parsed) {
430
- if (typeof decl.value.value === 'string') {
431
- 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(
432
- decl.value.value,
433
- ['value', 'important'],
434
- function(/** @type {Error | null} */ err, /** @type {Node[]} */ result) {
435
- if (err) {
436
- decl.parsed = /** @type {Node} */ (/** @type {unknown} */ (true));
437
- }
438
- if (result) {
439
- decl.value = result[0];
440
- /** @type {Declaration & { important?: string }} */ (decl).important = /** @type {string} */ (/** @type {unknown} */ (result[1])) || '';
441
- decl.parsed = /** @type {Node} */ (/** @type {unknown} */ (true));
442
- }
443
- });
444
- } else {
445
- decl.parsed = /** @type {Node} */ (/** @type {unknown} */ (true));
446
- }
447
-
448
- return decl;
449
- }
450
- else {
451
- return decl;
452
- }
453
- }
454
- if (!Array.isArray(toParse)) {
455
- return transformDeclaration.call(self, toParse);
456
- }
457
- else {
458
- /** @type {Declaration[]} */
459
- const nodes = [];
460
- for (let ti = 0; ti < toParse.length; ti++) {
461
- nodes.push(transformDeclaration.call(self, toParse[ti]));
462
- }
463
- return nodes;
464
- }
465
- }
466
-
467
- rulesets() {
468
- if (!this.rules) { return []; }
469
-
470
- /** @type {Node[]} */
471
- const filtRules = [];
472
- const rules = this.rules;
473
- /** @type {number} */
474
- let i;
475
- /** @type {Node} */
476
- let rule;
477
-
478
- for (i = 0; (rule = rules[i]); i++) {
479
- if (/** @type {RuleNode} */ (rule).isRuleset) {
480
- filtRules.push(rule);
481
- }
482
- }
483
-
484
- return filtRules;
485
- }
486
-
487
- /** @param {Node} rule */
488
- prependRule(rule) {
489
- const rules = this.rules;
490
- if (rules) {
491
- rules.unshift(rule);
492
- } else {
493
- this.rules = [ rule ];
494
- }
495
- this.setParent(rule, this);
496
- }
497
-
498
- /**
499
- * @param {Selector} selector
500
- * @param {Ruleset | null} [self]
501
- * @param {((rule: Node) => boolean)} [filter]
502
- * @returns {{ rule: Node, path: Node[] }[]}
503
- */
504
- find(selector, self, filter) {
505
- self = self || this;
506
- /** @type {{ rule: Node, path: Node[] }[]} */
507
- const rules = [];
508
- /** @type {number | undefined} */
509
- let match;
510
- /** @type {{ rule: Node, path: Node[] }[]} */
511
- let foundMixins;
512
- const key = selector.toCSS(/** @type {EvalContext} */ ({}));
513
-
514
- if (key in this._lookups) { return /** @type {{ rule: Node, path: Node[] }[]} */ (this._lookups[key]); }
515
-
516
- this.rulesets().forEach(function (rule) {
517
- if (rule !== self) {
518
- for (let j = 0; j < /** @type {RuleNode} */ (rule).selectors.length; j++) {
519
- match = selector.match(/** @type {RuleNode} */ (rule).selectors[j]);
520
- if (match) {
521
- if (selector.elements.length > match) {
522
- if (!filter || filter(rule)) {
523
- foundMixins = /** @type {Ruleset} */ (/** @type {unknown} */ (rule)).find(new Selector(selector.elements.slice(match)), self, filter);
524
- for (let i = 0; i < foundMixins.length; ++i) {
525
- foundMixins[i].path.push(rule);
526
- }
527
- Array.prototype.push.apply(rules, foundMixins);
528
- }
529
- } else {
530
- rules.push({ rule, path: []});
531
- }
532
- break;
533
- }
534
- }
535
- }
536
- });
537
- this._lookups[key] = rules;
538
- return rules;
539
- }
540
-
541
- /**
542
- * @param {EvalContext} context
543
- * @param {CSSOutput} output
544
- */
545
- genCSS(context, output) {
546
- /** @type {number} */
547
- let i;
548
- /** @type {number} */
549
- let j;
550
- /** @type {Node[]} */
551
- const charsetRuleNodes = [];
552
- /** @type {Node[]} */
553
- let ruleNodes = [];
554
-
555
- let // Line number debugging
556
- debugInfo;
557
-
558
- /** @type {Node} */
559
- let rule;
560
- /** @type {Selector[]} */
561
- let path;
562
-
563
- context.tabLevel = (context.tabLevel || 0);
564
-
565
- if (!this.root) {
566
- context.tabLevel++;
567
- }
568
-
569
- const tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' ');
570
- const tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' ');
571
- /** @type {string} */
572
- let sep;
573
-
574
- let charsetNodeIndex = 0;
575
- let importNodeIndex = 0;
576
- for (i = 0; (rule = /** @type {Node[]} */ (this.rules)[i]); i++) {
577
- if (rule instanceof Comment) {
578
- if (importNodeIndex === i) {
579
- importNodeIndex++;
580
- }
581
- ruleNodes.push(rule);
582
- } else if (/** @type {RuleNode} */ (rule).isCharset && /** @type {RuleNode} */ (rule).isCharset()) {
583
- ruleNodes.splice(charsetNodeIndex, 0, rule);
584
- charsetNodeIndex++;
585
- importNodeIndex++;
586
- } else if (rule.type === 'Import') {
587
- ruleNodes.splice(importNodeIndex, 0, rule);
588
- importNodeIndex++;
589
- } else {
590
- ruleNodes.push(rule);
591
- }
592
- }
593
- ruleNodes = charsetRuleNodes.concat(ruleNodes);
594
-
595
- // If this is the root node, we don't render
596
- // a selector, or {}.
597
- if (!this.root) {
598
- debugInfo = getDebugInfo(context, /** @type {{ debugInfo: { lineNumber: number, fileName: string } }} */ (/** @type {unknown} */ (this)), tabSetStr);
599
-
600
- if (debugInfo) {
601
- output.add(debugInfo);
602
- output.add(tabSetStr);
603
- }
604
-
605
- const paths = /** @type {Selector[][]} */ (this.paths);
606
- const pathCnt = paths.length;
607
- /** @type {number} */
608
- let pathSubCnt;
609
-
610
- sep = context.compress ? ',' : (`,\n${tabSetStr}`);
611
-
612
- for (i = 0; i < pathCnt; i++) {
613
- path = paths[i];
614
- if (!(pathSubCnt = path.length)) { continue; }
615
- if (i > 0) { output.add(sep); }
616
-
617
- /** @type {EvalContext & { firstSelector?: boolean }} */ (context).firstSelector = true;
618
- path[0].genCSS(context, output);
619
-
620
- /** @type {EvalContext & { firstSelector?: boolean }} */ (context).firstSelector = false;
621
- for (j = 1; j < pathSubCnt; j++) {
622
- path[j].genCSS(context, output);
623
- }
624
- }
625
-
626
- output.add((context.compress ? '{' : ' {\n') + tabRuleStr);
627
- }
628
-
629
- // Compile rules and rulesets
630
- for (i = 0; (rule = ruleNodes[i]); i++) {
631
-
632
- if (i + 1 === ruleNodes.length) {
633
- context.lastRule = true;
634
- }
635
-
636
- const currentLastRule = context.lastRule;
637
- if (rule.isRulesetLike()) {
638
- context.lastRule = false;
639
- }
640
-
641
- if (rule.genCSS) {
642
- rule.genCSS(context, output);
643
- } else if (rule.value) {
644
- output.add(/** @type {string} */ (rule.value).toString());
645
- }
646
-
647
- context.lastRule = currentLastRule;
648
-
649
- if (!context.lastRule && rule.isVisible()) {
650
- output.add(context.compress ? '' : (`\n${tabRuleStr}`));
651
- } else {
652
- context.lastRule = false;
653
- }
654
- }
655
-
656
- if (!this.root) {
657
- output.add((context.compress ? '}' : `\n${tabSetStr}}`));
658
- context.tabLevel--;
659
- }
660
-
661
- if (!output.isEmpty() && !context.compress && this.firstRoot) {
662
- output.add('\n');
663
- }
664
- }
665
-
666
- /**
667
- * @param {Selector[][]} paths
668
- * @param {Selector[][]} context
669
- * @param {Selector[]} selectors
670
- */
671
- joinSelectors(paths, context, selectors) {
672
- for (let s = 0; s < selectors.length; s++) {
673
- this.joinSelector(paths, context, selectors[s]);
674
- }
675
- }
676
-
677
- /**
678
- * @param {Selector[][]} paths
679
- * @param {Selector[][]} context
680
- * @param {Selector} selector
681
- */
682
- joinSelector(paths, context, selector) {
683
-
684
- /**
685
- * @param {Selector[]} elementsToPak
686
- * @param {Element} originalElement
687
- * @returns {Paren}
688
- */
689
- function createParenthesis(elementsToPak, originalElement) {
690
- /** @type {Paren} */
691
- let replacementParen;
692
- /** @type {number} */
693
- let j;
694
- if (elementsToPak.length === 0) {
695
- replacementParen = new Paren(elementsToPak[0]);
696
- } else {
697
- const insideParent = new Array(elementsToPak.length);
698
- for (j = 0; j < elementsToPak.length; j++) {
699
- insideParent[j] = new Element(
700
- null,
701
- elementsToPak[j],
702
- originalElement.isVariable,
703
- originalElement._index,
704
- originalElement._fileInfo
705
- );
706
- }
707
- replacementParen = new Paren(new Selector(insideParent));
708
- }
709
- return replacementParen;
710
- }
711
-
712
- /**
713
- * @param {Paren | Selector} containedElement
714
- * @param {Element} originalElement
715
- * @returns {Selector}
716
- */
717
- function createSelector(containedElement, originalElement) {
718
- /** @type {Element} */
719
- let element;
720
- /** @type {Selector} */
721
- let selector;
722
- element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo);
723
- selector = new Selector([element]);
724
- return selector;
725
- }
726
-
727
- /**
728
- * @param {Selector[]} beginningPath
729
- * @param {Selector[]} addPath
730
- * @param {Element} replacedElement
731
- * @param {Selector} originalSelector
732
- * @returns {Selector[]}
733
- */
734
- function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
735
- /** @type {Selector[]} */
736
- let newSelectorPath;
737
- /** @type {Selector} */
738
- let lastSelector;
739
- /** @type {Selector} */
740
- let newJoinedSelector;
741
- // our new selector path
742
- newSelectorPath = [];
743
-
744
- // construct the joined selector - if & is the first thing this will be empty,
745
- // if not newJoinedSelector will be the last set of elements in the selector
746
- if (beginningPath.length > 0) {
747
- newSelectorPath = utils.copyArray(beginningPath);
748
- lastSelector = newSelectorPath.pop();
749
- newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements));
750
- }
751
- else {
752
- newJoinedSelector = originalSelector.createDerived([]);
753
- }
754
-
755
- if (addPath.length > 0) {
756
- // /deep/ is a CSS4 selector - (removed, so should deprecate)
757
- // that is valid without anything in front of it
758
- // so if the & does not have a combinator that is "" or " " then
759
- // and there is a combinator on the parent, then grab that.
760
- // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
761
- let combinator = replacedElement.combinator;
762
-
763
- const parentEl = addPath[0].elements[0];
764
- if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
765
- combinator = parentEl.combinator;
766
- }
767
- // join the elements so far with the first part of the parent
768
- newJoinedSelector.elements.push(new Element(
769
- combinator,
770
- parentEl.value,
771
- replacedElement.isVariable,
772
- replacedElement._index,
773
- replacedElement._fileInfo
774
- ));
775
- newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
776
- }
777
-
778
- // now add the joined selector - but only if it is not empty
779
- if (newJoinedSelector.elements.length !== 0) {
780
- newSelectorPath.push(newJoinedSelector);
781
- }
782
-
783
- // put together the parent selectors after the join (e.g. the rest of the parent)
784
- if (addPath.length > 1) {
785
- let restOfPath = addPath.slice(1);
786
- restOfPath = restOfPath.map(function (/** @type {Selector} */ selector) {
787
- return selector.createDerived(selector.elements, []);
788
- });
789
- newSelectorPath = newSelectorPath.concat(restOfPath);
790
- }
791
- return newSelectorPath;
792
- }
793
-
794
- /**
795
- * @param {Selector[][]} beginningPath
796
- * @param {Selector[]} addPaths
797
- * @param {Element} replacedElement
798
- * @param {Selector} originalSelector
799
- * @param {Selector[][]} result
800
- * @returns {Selector[][]}
801
- */
802
- function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
803
- /** @type {number} */
804
- let j;
805
- for (j = 0; j < beginningPath.length; j++) {
806
- const newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
807
- result.push(newSelectorPath);
808
- }
809
- return result;
810
- }
811
-
812
- /**
813
- * @param {Element[]} elements
814
- * @param {Selector[][]} selectors
815
- */
816
- function mergeElementsOnToSelectors(elements, selectors) {
817
- /** @type {number} */
818
- let i;
819
- /** @type {Selector[]} */
820
- let sel;
821
-
822
- if (elements.length === 0) {
823
- return ;
824
- }
825
- if (selectors.length === 0) {
826
- selectors.push([ new Selector(elements) ]);
827
- return;
828
- }
829
-
830
- for (i = 0; (sel = selectors[i]); i++) {
831
- // if the previous thing in sel is a parent this needs to join on to it
832
- if (sel.length > 0) {
833
- sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
834
- }
835
- else {
836
- sel.push(new Selector(elements));
837
- }
838
- }
839
- }
840
-
841
- /**
842
- * @param {Selector[][]} paths
843
- * @param {Selector[][]} context
844
- * @param {Selector} inSelector
845
- * @returns {boolean}
846
- */
847
- function replaceParentSelector(paths, context, inSelector) {
848
- // The paths are [[Selector]]
849
- // The first list is a list of comma separated selectors
850
- // The inner list is a list of inheritance separated selectors
851
- // e.g.
852
- // .a, .b {
853
- // .c {
854
- // }
855
- // }
856
- // == [[.a] [.c]] [[.b] [.c]]
857
- //
858
- /** @type {number} */
859
- let i;
860
- /** @type {number} */
861
- let j;
862
- /** @type {number} */
863
- let k;
864
- /** @type {Element[]} */
865
- let currentElements;
866
- /** @type {Selector[][]} */
867
- let newSelectors;
868
- /** @type {Selector[][]} */
869
- let selectorsMultiplied;
870
- /** @type {Selector[]} */
871
- let sel;
872
- /** @type {Element} */
873
- let el;
874
- let hadParentSelector = false;
875
- /** @type {number} */
876
- let length;
877
- /** @type {Selector} */
878
- let lastSelector;
879
-
880
- /**
881
- * @param {Element} element
882
- * @returns {Selector | null}
883
- */
884
- function findNestedSelector(element) {
885
- /** @type {Node} */
886
- let maybeSelector;
887
- if (!(element.value instanceof Paren)) {
888
- return null;
889
- }
890
-
891
- maybeSelector = /** @type {Node} */ (element.value.value);
892
- if (!(maybeSelector instanceof Selector)) {
893
- return null;
894
- }
895
-
896
- return maybeSelector;
897
- }
898
-
899
- // the elements from the current selector so far
900
- currentElements = [];
901
- // the current list of new selectors to add to the path.
902
- // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
903
- // by the parents
904
- newSelectors = [
905
- []
906
- ];
907
-
908
- for (i = 0; (el = inSelector.elements[i]); i++) {
909
- // non parent reference elements just get added
910
- if (el.value !== '&') {
911
- const nestedSelector = findNestedSelector(el);
912
- if (nestedSelector !== null) {
913
- // merge the current list of non parent selector elements
914
- // on to the current list of selectors to add
915
- mergeElementsOnToSelectors(currentElements, newSelectors);
916
-
917
- /** @type {Selector[][]} */
918
- const nestedPaths = [];
919
- /** @type {boolean | undefined} */
920
- let replaced;
921
- /** @type {Selector[][]} */
922
- const replacedNewSelectors = [];
923
-
924
- // Check if this is a comma-separated selector list inside the paren
925
- // e.g. :not(&.a, &.b) produces Selector([Selector, Anonymous(','), Selector])
926
- const hasSubSelectors = nestedSelector.elements.some(e => e instanceof Selector);
927
-
928
- if (hasSubSelectors) {
929
- // Process each sub-selector individually
930
- /** @type {(Element | Selector)[]} */
931
- const resolvedElements = [];
932
- for (const subEl of nestedSelector.elements) {
933
- if (subEl instanceof Selector) {
934
- /** @type {Selector[][]} */
935
- const subPaths = [];
936
- const subReplaced = replaceParentSelector(subPaths, context, subEl);
937
- replaced = replaced || subReplaced;
938
- if (subPaths.length > 0 && subPaths[0].length > 0) {
939
- resolvedElements.push(subPaths[0][0]);
940
- } else {
941
- resolvedElements.push(subEl);
942
- }
943
- } else {
944
- resolvedElements.push(subEl);
945
- }
946
- }
947
- hadParentSelector = hadParentSelector || /** @type {boolean} */ (replaced);
948
- const resolvedNestedSelector = new Selector(resolvedElements);
949
- const replacementSelector = createSelector(createParenthesis([resolvedNestedSelector], el), el);
950
- addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
951
- } else {
952
- replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
953
- hadParentSelector = hadParentSelector || replaced;
954
- // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
955
- for (k = 0; k < nestedPaths.length; k++) {
956
- const replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
957
- addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
958
- }
959
- }
960
- newSelectors = replacedNewSelectors;
961
- currentElements = [];
962
- } else {
963
- currentElements.push(el);
964
- }
965
-
966
- } else {
967
- hadParentSelector = true;
968
- // the new list of selectors to add
969
- selectorsMultiplied = [];
970
-
971
- // merge the current list of non parent selector elements
972
- // on to the current list of selectors to add
973
- mergeElementsOnToSelectors(currentElements, newSelectors);
974
-
975
- // loop through our current selectors
976
- for (j = 0; j < newSelectors.length; j++) {
977
- sel = newSelectors[j];
978
- // if we don't have any parent paths, the & might be in a mixin so that it can be used
979
- // whether there are parents or not
980
- if (context.length === 0) {
981
- // the combinator used on el should now be applied to the next element instead so that
982
- // it is not lost
983
- if (sel.length > 0) {
984
- sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo));
985
- }
986
- selectorsMultiplied.push(sel);
987
- }
988
- else {
989
- // and the parent selectors
990
- for (k = 0; k < context.length; k++) {
991
- // We need to put the current selectors
992
- // then join the last selector's elements on to the parents selectors
993
- const newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);
994
- // add that to our new set of selectors
995
- selectorsMultiplied.push(newSelectorPath);
996
- }
997
- }
998
- }
999
-
1000
- // our new selectors has been multiplied, so reset the state
1001
- newSelectors = selectorsMultiplied;
1002
- currentElements = [];
1003
- }
1004
- }
1005
-
1006
- // if we have any elements left over (e.g. .a& .b == .b)
1007
- // add them on to all the current selectors
1008
- mergeElementsOnToSelectors(currentElements, newSelectors);
1009
-
1010
- for (i = 0; i < newSelectors.length; i++) {
1011
- length = newSelectors[i].length;
1012
- if (length > 0) {
1013
- paths.push(newSelectors[i]);
1014
- lastSelector = newSelectors[i][length - 1];
1015
- newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList);
1016
- }
1017
- }
1018
-
1019
- return hadParentSelector;
1020
- }
1021
-
1022
- /**
1023
- * @param {VisibilityInfo} visibilityInfo
1024
- * @param {Selector} deriveFrom
1025
- */
1026
- function deriveSelector(visibilityInfo, deriveFrom) {
1027
- const newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition);
1028
- newSelector.copyVisibilityInfo(visibilityInfo);
1029
- return newSelector;
1030
- }
1031
-
1032
- // joinSelector code follows
1033
- /** @type {number} */
1034
- let i;
1035
- /** @type {Selector[][]} */
1036
- let newPaths;
1037
- /** @type {boolean} */
1038
- let hadParentSelector;
1039
-
1040
- newPaths = [];
1041
- hadParentSelector = replaceParentSelector(newPaths, context, selector);
1042
-
1043
- if (!hadParentSelector) {
1044
- if (context.length > 0) {
1045
- newPaths = [];
1046
- for (i = 0; i < context.length; i++) {
1047
-
1048
- const concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo()));
1049
-
1050
- concatenated.push(selector);
1051
- newPaths.push(concatenated);
1052
- }
1053
- }
1054
- else {
1055
- newPaths = [[selector]];
1056
- }
1057
- }
1058
-
1059
- for (i = 0; i < newPaths.length; i++) {
1060
- paths.push(newPaths[i]);
1061
- }
1062
-
1063
- }
1064
- }
1065
-
1066
- export default Ruleset;