less 4.9.1 → 5.0.0-alpha.10

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 (134) hide show
  1. package/README.md +23 -5
  2. package/V5-STATUS.md +71 -0
  3. package/bin/lessc +302 -626
  4. package/dist/less-browser-dev.js +2550 -0
  5. package/dist/less-node.cjs +480 -14561
  6. package/index.cjs +5 -2
  7. package/lib/browser-dev.js +86 -0
  8. package/lib/index.js +164 -0
  9. package/lib/lessc-helper.js +64 -0
  10. package/lib/logger.js +76 -0
  11. package/lib/options.d.ts +82 -0
  12. package/lib/options.js +227 -0
  13. package/lib/types.js +20 -0
  14. package/lib/version.js +19 -0
  15. package/package.json +36 -40
  16. package/dist/less.cjs +0 -15218
  17. package/dist/less.js +0 -15218
  18. package/dist/less.min.js +0 -11
  19. package/dist/less.min.js.map +0 -1
  20. package/lib/less/constants.js +0 -13
  21. package/lib/less/contexts.js +0 -165
  22. package/lib/less/data/colors.js +0 -150
  23. package/lib/less/data/index.js +0 -4
  24. package/lib/less/data/unit-conversions.js +0 -21
  25. package/lib/less/default-options.js +0 -89
  26. package/lib/less/deprecation.js +0 -82
  27. package/lib/less/environment/abstract-file-manager.js +0 -140
  28. package/lib/less/environment/abstract-plugin-loader.js +0 -185
  29. package/lib/less/environment/environment-api.ts +0 -21
  30. package/lib/less/environment/environment.js +0 -59
  31. package/lib/less/environment/file-manager-api.ts +0 -77
  32. package/lib/less/functions/boolean.js +0 -29
  33. package/lib/less/functions/color-blending.js +0 -85
  34. package/lib/less/functions/color.js +0 -452
  35. package/lib/less/functions/data-uri.js +0 -74
  36. package/lib/less/functions/default.js +0 -26
  37. package/lib/less/functions/function-caller.js +0 -55
  38. package/lib/less/functions/function-registry.js +0 -36
  39. package/lib/less/functions/index.js +0 -35
  40. package/lib/less/functions/list.js +0 -158
  41. package/lib/less/functions/math-helper.js +0 -22
  42. package/lib/less/functions/math.js +0 -30
  43. package/lib/less/functions/number.js +0 -95
  44. package/lib/less/functions/string.js +0 -39
  45. package/lib/less/functions/style.js +0 -29
  46. package/lib/less/functions/svg.js +0 -87
  47. package/lib/less/functions/types.js +0 -70
  48. package/lib/less/import-manager.js +0 -183
  49. package/lib/less/index.js +0 -95
  50. package/lib/less/less-error.js +0 -166
  51. package/lib/less/logger.js +0 -34
  52. package/lib/less/parse-tree.js +0 -124
  53. package/lib/less/parse.js +0 -87
  54. package/lib/less/parser/lookup-pattern.js +0 -26
  55. package/lib/less/parser/parser-input.js +0 -400
  56. package/lib/less/parser/parser.js +0 -2998
  57. package/lib/less/plugin-manager.js +0 -168
  58. package/lib/less/render.js +0 -41
  59. package/lib/less/source-map-builder.js +0 -82
  60. package/lib/less/source-map-output.js +0 -151
  61. package/lib/less/transform-tree.js +0 -102
  62. package/lib/less/tree/anonymous.js +0 -61
  63. package/lib/less/tree/assignment.js +0 -48
  64. package/lib/less/tree/atrule-syntax.js +0 -8
  65. package/lib/less/tree/atrule.js +0 -340
  66. package/lib/less/tree/attribute.js +0 -63
  67. package/lib/less/tree/call.js +0 -132
  68. package/lib/less/tree/color.js +0 -285
  69. package/lib/less/tree/combinator.js +0 -38
  70. package/lib/less/tree/comment.js +0 -48
  71. package/lib/less/tree/condition.js +0 -65
  72. package/lib/less/tree/container.js +0 -104
  73. package/lib/less/tree/debug-info.js +0 -80
  74. package/lib/less/tree/declaration.js +0 -142
  75. package/lib/less/tree/detached-ruleset.js +0 -45
  76. package/lib/less/tree/dimension.js +0 -215
  77. package/lib/less/tree/element.js +0 -93
  78. package/lib/less/tree/expression.js +0 -100
  79. package/lib/less/tree/extend.js +0 -88
  80. package/lib/less/tree/import.js +0 -299
  81. package/lib/less/tree/index.js +0 -56
  82. package/lib/less/tree/interpolated-variable.js +0 -106
  83. package/lib/less/tree/javascript.js +0 -45
  84. package/lib/less/tree/js-eval-node.js +0 -80
  85. package/lib/less/tree/keyword.js +0 -28
  86. package/lib/less/tree/media.js +0 -90
  87. package/lib/less/tree/merge-rules.js +0 -47
  88. package/lib/less/tree/mixin-call.js +0 -283
  89. package/lib/less/tree/mixin-definition.js +0 -319
  90. package/lib/less/tree/namespace-value.js +0 -95
  91. package/lib/less/tree/negative.js +0 -37
  92. package/lib/less/tree/nested-at-rule.js +0 -239
  93. package/lib/less/tree/node.js +0 -310
  94. package/lib/less/tree/operation.js +0 -81
  95. package/lib/less/tree/paren.js +0 -41
  96. package/lib/less/tree/property.js +0 -96
  97. package/lib/less/tree/query-in-parens.js +0 -64
  98. package/lib/less/tree/quoted.js +0 -131
  99. package/lib/less/tree/ruleset.js +0 -1068
  100. package/lib/less/tree/selector.js +0 -201
  101. package/lib/less/tree/unicode-descriptor.js +0 -14
  102. package/lib/less/tree/unit.js +0 -170
  103. package/lib/less/tree/url.js +0 -83
  104. package/lib/less/tree/value.js +0 -60
  105. package/lib/less/tree/variable-call.js +0 -60
  106. package/lib/less/tree/variable.js +0 -85
  107. package/lib/less/utils.js +0 -126
  108. package/lib/less/visitors/extend-visitor.js +0 -505
  109. package/lib/less/visitors/import-sequencer.js +0 -56
  110. package/lib/less/visitors/import-visitor.js +0 -203
  111. package/lib/less/visitors/index.js +0 -15
  112. package/lib/less/visitors/join-selector-visitor.js +0 -65
  113. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  114. package/lib/less/visitors/to-css-visitor.js +0 -332
  115. package/lib/less/visitors/visitor.js +0 -165
  116. package/lib/less-browser/add-default-options.js +0 -53
  117. package/lib/less-browser/bootstrap.js +0 -67
  118. package/lib/less-browser/browser.js +0 -65
  119. package/lib/less-browser/cache.js +0 -43
  120. package/lib/less-browser/error-reporting.js +0 -170
  121. package/lib/less-browser/file-manager.js +0 -112
  122. package/lib/less-browser/image-size.js +0 -28
  123. package/lib/less-browser/index.js +0 -284
  124. package/lib/less-browser/log-listener.js +0 -42
  125. package/lib/less-browser/plugin-loader.js +0 -24
  126. package/lib/less-browser/utils.js +0 -30
  127. package/lib/less-node/environment.js +0 -43
  128. package/lib/less-node/file-manager.js +0 -156
  129. package/lib/less-node/fs.js +0 -14
  130. package/lib/less-node/image-size.js +0 -78
  131. package/lib/less-node/index.js +0 -31
  132. package/lib/less-node/lessc-helper.js +0 -95
  133. package/lib/less-node/plugin-loader.js +0 -62
  134. 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;