less 4.9.0 → 5.0.0-alpha.2
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.
- package/README.md +19 -5
- package/bin/lessc +190 -630
- package/dist/less-node.cjs +399 -14570
- package/index.cjs +5 -2
- package/lib/index.js +164 -0
- package/lib/lessc-helper.js +52 -0
- package/lib/logger.js +76 -0
- package/lib/options.d.ts +46 -0
- package/lib/options.js +145 -0
- package/lib/types.js +20 -0
- package/lib/version.js +19 -0
- package/package.json +32 -39
- package/dist/less.cjs +0 -15215
- package/dist/less.js +0 -15215
- package/dist/less.min.js +0 -11
- package/dist/less.min.js.map +0 -1
- package/lib/less/constants.js +0 -13
- package/lib/less/contexts.js +0 -165
- package/lib/less/data/colors.js +0 -150
- package/lib/less/data/index.js +0 -4
- package/lib/less/data/unit-conversions.js +0 -21
- package/lib/less/default-options.js +0 -89
- package/lib/less/deprecation.js +0 -82
- package/lib/less/environment/abstract-file-manager.js +0 -140
- package/lib/less/environment/abstract-plugin-loader.js +0 -185
- package/lib/less/environment/environment-api.ts +0 -21
- package/lib/less/environment/environment.js +0 -59
- package/lib/less/environment/file-manager-api.ts +0 -77
- package/lib/less/functions/boolean.js +0 -29
- package/lib/less/functions/color-blending.js +0 -85
- package/lib/less/functions/color.js +0 -452
- package/lib/less/functions/data-uri.js +0 -74
- package/lib/less/functions/default.js +0 -26
- package/lib/less/functions/function-caller.js +0 -55
- package/lib/less/functions/function-registry.js +0 -36
- package/lib/less/functions/index.js +0 -35
- package/lib/less/functions/list.js +0 -158
- package/lib/less/functions/math-helper.js +0 -22
- package/lib/less/functions/math.js +0 -30
- package/lib/less/functions/number.js +0 -95
- package/lib/less/functions/string.js +0 -39
- package/lib/less/functions/style.js +0 -29
- package/lib/less/functions/svg.js +0 -87
- package/lib/less/functions/types.js +0 -70
- package/lib/less/import-manager.js +0 -183
- package/lib/less/index.js +0 -95
- package/lib/less/less-error.js +0 -166
- package/lib/less/logger.js +0 -34
- package/lib/less/parse-tree.js +0 -124
- package/lib/less/parse.js +0 -87
- package/lib/less/parser/lookup-pattern.js +0 -26
- package/lib/less/parser/parser-input.js +0 -400
- package/lib/less/parser/parser.js +0 -2998
- package/lib/less/plugin-manager.js +0 -168
- package/lib/less/render.js +0 -41
- package/lib/less/source-map-builder.js +0 -82
- package/lib/less/source-map-output.js +0 -151
- package/lib/less/transform-tree.js +0 -102
- package/lib/less/tree/anonymous.js +0 -61
- package/lib/less/tree/assignment.js +0 -48
- package/lib/less/tree/atrule-syntax.js +0 -8
- package/lib/less/tree/atrule.js +0 -340
- package/lib/less/tree/attribute.js +0 -63
- package/lib/less/tree/call.js +0 -132
- package/lib/less/tree/color.js +0 -285
- package/lib/less/tree/combinator.js +0 -38
- package/lib/less/tree/comment.js +0 -48
- package/lib/less/tree/condition.js +0 -65
- package/lib/less/tree/container.js +0 -104
- package/lib/less/tree/debug-info.js +0 -80
- package/lib/less/tree/declaration.js +0 -139
- package/lib/less/tree/detached-ruleset.js +0 -45
- package/lib/less/tree/dimension.js +0 -215
- package/lib/less/tree/element.js +0 -93
- package/lib/less/tree/expression.js +0 -100
- package/lib/less/tree/extend.js +0 -88
- package/lib/less/tree/import.js +0 -299
- package/lib/less/tree/index.js +0 -56
- package/lib/less/tree/interpolated-variable.js +0 -106
- package/lib/less/tree/javascript.js +0 -45
- package/lib/less/tree/js-eval-node.js +0 -80
- package/lib/less/tree/keyword.js +0 -28
- package/lib/less/tree/media.js +0 -90
- package/lib/less/tree/merge-rules.js +0 -47
- package/lib/less/tree/mixin-call.js +0 -283
- package/lib/less/tree/mixin-definition.js +0 -319
- package/lib/less/tree/namespace-value.js +0 -95
- package/lib/less/tree/negative.js +0 -37
- package/lib/less/tree/nested-at-rule.js +0 -239
- package/lib/less/tree/node.js +0 -310
- package/lib/less/tree/operation.js +0 -81
- package/lib/less/tree/paren.js +0 -41
- package/lib/less/tree/property.js +0 -96
- package/lib/less/tree/query-in-parens.js +0 -64
- package/lib/less/tree/quoted.js +0 -131
- package/lib/less/tree/ruleset.js +0 -1068
- package/lib/less/tree/selector.js +0 -201
- package/lib/less/tree/unicode-descriptor.js +0 -14
- package/lib/less/tree/unit.js +0 -170
- package/lib/less/tree/url.js +0 -83
- package/lib/less/tree/value.js +0 -60
- package/lib/less/tree/variable-call.js +0 -60
- package/lib/less/tree/variable.js +0 -85
- package/lib/less/utils.js +0 -126
- package/lib/less/visitors/extend-visitor.js +0 -505
- package/lib/less/visitors/import-sequencer.js +0 -56
- package/lib/less/visitors/import-visitor.js +0 -203
- package/lib/less/visitors/index.js +0 -15
- package/lib/less/visitors/join-selector-visitor.js +0 -65
- package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
- package/lib/less/visitors/to-css-visitor.js +0 -332
- package/lib/less/visitors/visitor.js +0 -165
- package/lib/less-browser/add-default-options.js +0 -53
- package/lib/less-browser/bootstrap.js +0 -67
- package/lib/less-browser/browser.js +0 -65
- package/lib/less-browser/cache.js +0 -43
- package/lib/less-browser/error-reporting.js +0 -170
- package/lib/less-browser/file-manager.js +0 -112
- package/lib/less-browser/image-size.js +0 -28
- package/lib/less-browser/index.js +0 -284
- package/lib/less-browser/log-listener.js +0 -42
- package/lib/less-browser/plugin-loader.js +0 -24
- package/lib/less-browser/utils.js +0 -30
- package/lib/less-node/environment.js +0 -43
- package/lib/less-node/file-manager.js +0 -156
- package/lib/less-node/fs.js +0 -14
- package/lib/less-node/image-size.js +0 -78
- package/lib/less-node/index.js +0 -31
- package/lib/less-node/lessc-helper.js +0 -95
- package/lib/less-node/plugin-loader.js +0 -62
- package/lib/less-node/url-file-manager.js +0 -60
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/** @import { EvalContext, TreeVisitor, VisibilityInfo } from './node.js' */
|
|
3
|
-
/** @import { FunctionRegistry } from './nested-at-rule.js' */
|
|
4
|
-
/** @import { MixinArg } from './mixin-call.js' */
|
|
5
|
-
import Node from './node.js';
|
|
6
|
-
import Selector from './selector.js';
|
|
7
|
-
import Element from './element.js';
|
|
8
|
-
import Ruleset from './ruleset.js';
|
|
9
|
-
import Declaration from './declaration.js';
|
|
10
|
-
import DetachedRuleset from './detached-ruleset.js';
|
|
11
|
-
import Expression from './expression.js';
|
|
12
|
-
import contexts from '../contexts.js';
|
|
13
|
-
import * as utils from '../utils.js';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {object} MixinParam
|
|
17
|
-
* @property {string} [name]
|
|
18
|
-
* @property {Node} [value]
|
|
19
|
-
* @property {boolean} [variadic]
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @typedef {Ruleset & {
|
|
24
|
-
* functionRegistry?: FunctionRegistry,
|
|
25
|
-
* originalRuleset?: Node
|
|
26
|
-
* }} RulesetWithRegistry
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
class Definition extends Ruleset {
|
|
30
|
-
get type() { return 'MixinDefinition'; }
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @param {string | undefined} name
|
|
34
|
-
* @param {MixinParam[]} params
|
|
35
|
-
* @param {Node[]} rules
|
|
36
|
-
* @param {Node | null} [condition]
|
|
37
|
-
* @param {boolean} [variadic]
|
|
38
|
-
* @param {Node[] | null} [frames]
|
|
39
|
-
* @param {VisibilityInfo} [visibilityInfo]
|
|
40
|
-
*/
|
|
41
|
-
constructor(name, params, rules, condition, variadic, frames, visibilityInfo) {
|
|
42
|
-
super(null, null);
|
|
43
|
-
/** @type {string} */
|
|
44
|
-
this.name = name || 'anonymous mixin';
|
|
45
|
-
this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])];
|
|
46
|
-
/** @type {MixinParam[]} */
|
|
47
|
-
this.params = params;
|
|
48
|
-
/** @type {Node | null | undefined} */
|
|
49
|
-
this.condition = condition;
|
|
50
|
-
/** @type {boolean | undefined} */
|
|
51
|
-
this.variadic = variadic;
|
|
52
|
-
/** @type {number} */
|
|
53
|
-
this.arity = params.length;
|
|
54
|
-
this.rules = rules;
|
|
55
|
-
this._lookups = {};
|
|
56
|
-
/** @type {string[]} */
|
|
57
|
-
const optionalParameters = [];
|
|
58
|
-
/** @type {number} */
|
|
59
|
-
this.required = params.reduce(function (/** @type {number} */ count, /** @type {MixinParam} */ p) {
|
|
60
|
-
if (!p.name || (p.name && !p.value)) {
|
|
61
|
-
return count + 1;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
optionalParameters.push(p.name);
|
|
65
|
-
return count;
|
|
66
|
-
}
|
|
67
|
-
}, 0);
|
|
68
|
-
/** @type {string[]} */
|
|
69
|
-
this.optionalParameters = optionalParameters;
|
|
70
|
-
/** @type {Node[] | null | undefined} */
|
|
71
|
-
this.frames = frames;
|
|
72
|
-
this.copyVisibilityInfo(visibilityInfo);
|
|
73
|
-
this.allowRoot = true;
|
|
74
|
-
/** @type {boolean} */
|
|
75
|
-
this.evalFirst = true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** @param {TreeVisitor} visitor */
|
|
79
|
-
accept(visitor) {
|
|
80
|
-
if (this.params && this.params.length) {
|
|
81
|
-
this.params = /** @type {MixinParam[]} */ (/** @type {unknown} */ (visitor.visitArray(/** @type {Node[]} */ (/** @type {unknown} */ (this.params)))));
|
|
82
|
-
}
|
|
83
|
-
this.rules = visitor.visitArray(this.rules);
|
|
84
|
-
if (this.condition) {
|
|
85
|
-
this.condition = visitor.visit(this.condition);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @param {EvalContext} context
|
|
91
|
-
* @param {EvalContext} mixinEnv
|
|
92
|
-
* @param {MixinArg[] | null} args
|
|
93
|
-
* @param {Node[]} evaldArguments
|
|
94
|
-
* @returns {Ruleset}
|
|
95
|
-
*/
|
|
96
|
-
evalParams(context, mixinEnv, args, evaldArguments) {
|
|
97
|
-
/* jshint boss:true */
|
|
98
|
-
const frame = new Ruleset(null, null);
|
|
99
|
-
|
|
100
|
-
/** @type {Node[] | undefined} */
|
|
101
|
-
let varargs;
|
|
102
|
-
/** @type {MixinArg | undefined} */
|
|
103
|
-
let arg;
|
|
104
|
-
const params = /** @type {MixinParam[]} */ (utils.copyArray(this.params));
|
|
105
|
-
/** @type {number} */
|
|
106
|
-
let i;
|
|
107
|
-
/** @type {number} */
|
|
108
|
-
let j;
|
|
109
|
-
/** @type {Node | undefined} */
|
|
110
|
-
let val;
|
|
111
|
-
/** @type {string | undefined} */
|
|
112
|
-
let name;
|
|
113
|
-
/** @type {boolean} */
|
|
114
|
-
let isNamedFound;
|
|
115
|
-
/** @type {number} */
|
|
116
|
-
let argIndex;
|
|
117
|
-
let argsLength = 0;
|
|
118
|
-
|
|
119
|
-
if (mixinEnv.frames && mixinEnv.frames[0] && /** @type {RulesetWithRegistry} */ (mixinEnv.frames[0]).functionRegistry) {
|
|
120
|
-
/** @type {RulesetWithRegistry} */ (frame).functionRegistry = /** @type {FunctionRegistry} */ (/** @type {RulesetWithRegistry} */ (mixinEnv.frames[0]).functionRegistry).inherit();
|
|
121
|
-
}
|
|
122
|
-
mixinEnv = new contexts.Eval(mixinEnv, /** @type {Node[]} */ ([frame]).concat(/** @type {Node[]} */ (mixinEnv.frames)));
|
|
123
|
-
|
|
124
|
-
if (args) {
|
|
125
|
-
args = /** @type {MixinArg[]} */ (utils.copyArray(args));
|
|
126
|
-
argsLength = args.length;
|
|
127
|
-
|
|
128
|
-
for (i = 0; i < argsLength; i++) {
|
|
129
|
-
arg = args[i];
|
|
130
|
-
if (name = (arg && arg.name)) {
|
|
131
|
-
isNamedFound = false;
|
|
132
|
-
for (j = 0; j < params.length; j++) {
|
|
133
|
-
if (!evaldArguments[j] && name === params[j].name) {
|
|
134
|
-
evaldArguments[j] = arg.value.eval(context);
|
|
135
|
-
frame.prependRule(new Declaration(name, arg.value.eval(context)));
|
|
136
|
-
isNamedFound = true;
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (isNamedFound) {
|
|
141
|
-
args.splice(i, 1);
|
|
142
|
-
i--;
|
|
143
|
-
continue;
|
|
144
|
-
} else {
|
|
145
|
-
throw { type: 'Runtime', message: `Named argument for ${this.name} ${args[i].name} not found` };
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
argIndex = 0;
|
|
151
|
-
for (i = 0; i < params.length; i++) {
|
|
152
|
-
if (evaldArguments[i]) { continue; }
|
|
153
|
-
|
|
154
|
-
arg = args && args[argIndex];
|
|
155
|
-
|
|
156
|
-
if (name = params[i].name) {
|
|
157
|
-
if (params[i].variadic) {
|
|
158
|
-
varargs = [];
|
|
159
|
-
for (j = argIndex; j < argsLength; j++) {
|
|
160
|
-
varargs.push(/** @type {MixinArg[]} */ (args)[j].value.eval(context));
|
|
161
|
-
}
|
|
162
|
-
frame.prependRule(new Declaration(name, new Expression(varargs).eval(context)));
|
|
163
|
-
} else {
|
|
164
|
-
val = arg && arg.value;
|
|
165
|
-
if (val) {
|
|
166
|
-
// This was a mixin call, pass in a detached ruleset of it's eval'd rules
|
|
167
|
-
if (Array.isArray(val)) {
|
|
168
|
-
val = /** @type {Node} */ (/** @type {unknown} */ (new DetachedRuleset(new Ruleset(null, /** @type {Node[]} */ (val)))));
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
val = val.eval(context);
|
|
172
|
-
}
|
|
173
|
-
} else if (params[i].value) {
|
|
174
|
-
val = /** @type {Node} */ (params[i].value).eval(mixinEnv);
|
|
175
|
-
frame.resetCache();
|
|
176
|
-
} else {
|
|
177
|
-
throw { type: 'Runtime', message: `wrong number of arguments for ${this.name} (${argsLength} for ${this.arity})` };
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
frame.prependRule(new Declaration(name, val));
|
|
181
|
-
evaldArguments[i] = val;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (params[i].variadic && args) {
|
|
186
|
-
for (j = argIndex; j < argsLength; j++) {
|
|
187
|
-
evaldArguments[j] = args[j].value.eval(context);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
argIndex++;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return frame;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/** @returns {Ruleset} */
|
|
197
|
-
makeImportant() {
|
|
198
|
-
const rules = !this.rules ? this.rules : this.rules.map(function (/** @type {Node & { makeImportant?: (important?: boolean) => Node }} */ r) {
|
|
199
|
-
if (r.makeImportant) {
|
|
200
|
-
return r.makeImportant(true);
|
|
201
|
-
} else {
|
|
202
|
-
return r;
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
const result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames);
|
|
206
|
-
return /** @type {Ruleset} */ (/** @type {unknown} */ (result));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* @param {EvalContext} context
|
|
211
|
-
* @returns {Definition}
|
|
212
|
-
*/
|
|
213
|
-
eval(context) {
|
|
214
|
-
return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames));
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @param {EvalContext} context
|
|
219
|
-
* @param {MixinArg[]} args
|
|
220
|
-
* @param {string | undefined} important
|
|
221
|
-
* @returns {Ruleset}
|
|
222
|
-
*/
|
|
223
|
-
evalCall(context, args, important) {
|
|
224
|
-
/** @type {Node[]} */
|
|
225
|
-
const _arguments = [];
|
|
226
|
-
const mixinFrames = this.frames ? /** @type {Node[]} */ (this.frames).concat(/** @type {Node[]} */ (context.frames)) : /** @type {Node[]} */ (context.frames);
|
|
227
|
-
const frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments);
|
|
228
|
-
/** @type {Node[]} */
|
|
229
|
-
let rules;
|
|
230
|
-
/** @type {Ruleset} */
|
|
231
|
-
let ruleset;
|
|
232
|
-
|
|
233
|
-
frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context)));
|
|
234
|
-
|
|
235
|
-
rules = utils.copyArray(this.rules);
|
|
236
|
-
|
|
237
|
-
ruleset = new Ruleset(null, rules);
|
|
238
|
-
/** @type {RulesetWithRegistry} */ (ruleset).originalRuleset = this;
|
|
239
|
-
ruleset = /** @type {Ruleset} */ (ruleset.eval(new contexts.Eval(context, /** @type {Node[]} */ ([this, frame]).concat(mixinFrames))));
|
|
240
|
-
if (important) {
|
|
241
|
-
ruleset = /** @type {Ruleset} */ (ruleset.makeImportant());
|
|
242
|
-
}
|
|
243
|
-
return ruleset;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* @param {MixinArg[] | null} args
|
|
248
|
-
* @param {EvalContext} context
|
|
249
|
-
* @returns {boolean}
|
|
250
|
-
*/
|
|
251
|
-
matchCondition(args, context) {
|
|
252
|
-
if (this.condition && !this.condition.eval(
|
|
253
|
-
new contexts.Eval(context,
|
|
254
|
-
/** @type {Node[]} */ ([this.evalParams(context, /* the parameter variables */
|
|
255
|
-
new contexts.Eval(context, this.frames ? /** @type {Node[]} */ (this.frames).concat(/** @type {Node[]} */ (context.frames)) : context.frames), args, [])])
|
|
256
|
-
.concat(/** @type {Node[]} */ (this.frames || [])) // the parent namespace/mixin frames
|
|
257
|
-
.concat(/** @type {Node[]} */ (context.frames))))) { // the current environment frames
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
return true;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* @param {MixinArg[] | null} args
|
|
265
|
-
* @param {EvalContext} [context]
|
|
266
|
-
* @returns {boolean}
|
|
267
|
-
*/
|
|
268
|
-
matchArgs(args, context) {
|
|
269
|
-
const allArgsCnt = (args && args.length) || 0;
|
|
270
|
-
const evaldArguments = new Array(this.params.length);
|
|
271
|
-
const positionalArgs = [];
|
|
272
|
-
let positionalIndex = 0;
|
|
273
|
-
|
|
274
|
-
for (let i = 0; i < allArgsCnt; i++) {
|
|
275
|
-
const arg = /** @type {MixinArg[]} */ (args)[i];
|
|
276
|
-
if (!arg.name) {
|
|
277
|
-
positionalArgs.push(arg);
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const paramIndex = this.params.findIndex((param, index) => param.name === arg.name && !evaldArguments[index]);
|
|
282
|
-
if (paramIndex < 0) {
|
|
283
|
-
return false;
|
|
284
|
-
}
|
|
285
|
-
evaldArguments[paramIndex] = arg;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
for (let i = 0; i < this.params.length; i++) {
|
|
289
|
-
if (evaldArguments[i]) {
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (this.params[i].variadic) {
|
|
293
|
-
positionalIndex = positionalArgs.length;
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
if (positionalIndex < positionalArgs.length) {
|
|
297
|
-
evaldArguments[i] = positionalArgs[positionalIndex++];
|
|
298
|
-
} else if (!this.params[i].name || !this.params[i].value) {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (positionalIndex < positionalArgs.length) {
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// check patterns
|
|
308
|
-
for (let i = 0; i < this.arity; i++) {
|
|
309
|
-
if (!this.params[i].name && !this.params[i].variadic) {
|
|
310
|
-
if (evaldArguments[i].value.eval(context).toCSS(/** @type {EvalContext} */ ({})) != /** @type {Node} */ (this.params[i].value).eval(context).toCSS(/** @type {EvalContext} */ ({}))) {
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
export default Definition;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/** @import { EvalContext, FileInfo } from './node.js' */
|
|
3
|
-
import Node from './node.js';
|
|
4
|
-
import Variable from './variable.js';
|
|
5
|
-
import Ruleset from './ruleset.js';
|
|
6
|
-
import Selector from './selector.js';
|
|
7
|
-
|
|
8
|
-
class NamespaceValue extends Node {
|
|
9
|
-
get type() { return 'NamespaceValue'; }
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @param {Node} ruleCall
|
|
13
|
-
* @param {string[]} lookups
|
|
14
|
-
* @param {number} index
|
|
15
|
-
* @param {FileInfo} fileInfo
|
|
16
|
-
*/
|
|
17
|
-
constructor(ruleCall, lookups, index, fileInfo) {
|
|
18
|
-
super();
|
|
19
|
-
this.value = ruleCall;
|
|
20
|
-
this.lookups = lookups;
|
|
21
|
-
this._index = index;
|
|
22
|
-
this._fileInfo = fileInfo;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @param {EvalContext} context
|
|
27
|
-
* @returns {Node}
|
|
28
|
-
*/
|
|
29
|
-
eval(context) {
|
|
30
|
-
let i, name;
|
|
31
|
-
/** @type {Ruleset | Node | Node[]} */
|
|
32
|
-
let rules = this.value.eval(context);
|
|
33
|
-
|
|
34
|
-
for (i = 0; i < this.lookups.length; i++) {
|
|
35
|
-
name = this.lookups[i];
|
|
36
|
-
|
|
37
|
-
if (Array.isArray(rules)) {
|
|
38
|
-
rules = new Ruleset([new Selector()], rules);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const rs = /** @type {Ruleset} */ (rules);
|
|
42
|
-
|
|
43
|
-
if (name === '') {
|
|
44
|
-
rules = rs.lastDeclaration();
|
|
45
|
-
}
|
|
46
|
-
else if (name.charAt(0) === '@') {
|
|
47
|
-
if (name.charAt(1) === '@') {
|
|
48
|
-
name = `@${new Variable(name.slice(1)).eval(context).value}`;
|
|
49
|
-
}
|
|
50
|
-
if (rs.variables) {
|
|
51
|
-
rules = rs.variable(name);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (!rules) {
|
|
55
|
-
throw { type: 'Name',
|
|
56
|
-
message: `variable ${name} not found`,
|
|
57
|
-
filename: this.fileInfo().filename,
|
|
58
|
-
index: this.getIndex() };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
if (name.substring(0, 2) === '$@') {
|
|
63
|
-
name = `$${new Variable(name.slice(1)).eval(context).value}`;
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
name = name.charAt(0) === '$' ? name : `$${name}`;
|
|
67
|
-
}
|
|
68
|
-
if (rs.properties) {
|
|
69
|
-
rules = rs.property(name);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (!rules) {
|
|
73
|
-
throw { type: 'Name',
|
|
74
|
-
message: `property "${name.slice(1)}" not found`,
|
|
75
|
-
filename: this.fileInfo().filename,
|
|
76
|
-
index: this.getIndex() };
|
|
77
|
-
}
|
|
78
|
-
const rulesArr = /** @type {Node[]} */ (rules);
|
|
79
|
-
rules = rulesArr[rulesArr.length - 1];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const current = /** @type {Node} */ (rules);
|
|
83
|
-
if (current.value) {
|
|
84
|
-
rules = /** @type {Node} */ (current.eval(context).value);
|
|
85
|
-
}
|
|
86
|
-
const currentNode = /** @type {Node & { ruleset?: Node }} */ (rules);
|
|
87
|
-
if (currentNode.ruleset) {
|
|
88
|
-
rules = currentNode.ruleset.eval(context);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return /** @type {Node} */ (rules);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export default NamespaceValue;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/** @import { EvalContext, CSSOutput } from './node.js' */
|
|
3
|
-
import Node from './node.js';
|
|
4
|
-
import Operation from './operation.js';
|
|
5
|
-
import Dimension from './dimension.js';
|
|
6
|
-
|
|
7
|
-
class Negative extends Node {
|
|
8
|
-
get type() { return 'Negative'; }
|
|
9
|
-
|
|
10
|
-
/** @param {Node} node */
|
|
11
|
-
constructor(node) {
|
|
12
|
-
super();
|
|
13
|
-
this.value = node;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @param {EvalContext} context
|
|
18
|
-
* @param {CSSOutput} output
|
|
19
|
-
*/
|
|
20
|
-
genCSS(context, output) {
|
|
21
|
-
output.add('-');
|
|
22
|
-
/** @type {Node} */ (this.value).genCSS(context, output);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @param {EvalContext} context
|
|
27
|
-
* @returns {Node}
|
|
28
|
-
*/
|
|
29
|
-
eval(context) {
|
|
30
|
-
if (context.isMathOn('*')) {
|
|
31
|
-
return (new Operation('*', [new Dimension(-1), /** @type {Node} */ (this.value)], false)).eval(context);
|
|
32
|
-
}
|
|
33
|
-
return new Negative(/** @type {Node} */ (this.value).eval(context));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default Negative;
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/** @import { EvalContext, CSSOutput, TreeVisitor, FileInfo, VisibilityInfo } from './node.js' */
|
|
3
|
-
import Ruleset from './ruleset.js';
|
|
4
|
-
import Value from './value.js';
|
|
5
|
-
import Selector from './selector.js';
|
|
6
|
-
import Anonymous from './anonymous.js';
|
|
7
|
-
import Expression from './expression.js';
|
|
8
|
-
import * as utils from '../utils.js';
|
|
9
|
-
import Node from './node.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {object} FunctionRegistry
|
|
13
|
-
* @property {(name: string, func: Function) => void} add
|
|
14
|
-
* @property {(functions: Object) => void} addMultiple
|
|
15
|
-
* @property {(name: string) => Function} get
|
|
16
|
-
* @property {() => Object} getLocalFunctions
|
|
17
|
-
* @property {() => FunctionRegistry} inherit
|
|
18
|
-
* @property {(base: FunctionRegistry) => FunctionRegistry} create
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef {Node & {
|
|
23
|
-
* features: Value,
|
|
24
|
-
* rules: Ruleset[],
|
|
25
|
-
* type: string,
|
|
26
|
-
* functionRegistry?: FunctionRegistry,
|
|
27
|
-
* multiMedia?: boolean,
|
|
28
|
-
* debugInfo?: { lineNumber: number, fileName: string },
|
|
29
|
-
* allowRoot?: boolean,
|
|
30
|
-
* _evaluated?: boolean,
|
|
31
|
-
* evalFunction: () => void,
|
|
32
|
-
* evalTop: (context: EvalContext) => Node | Ruleset,
|
|
33
|
-
* evalNested: (context: EvalContext) => Node | Ruleset,
|
|
34
|
-
* permute: (arr: Node[][]) => Node[][],
|
|
35
|
-
* bubbleSelectors: (selectors: Selector[] | undefined) => void,
|
|
36
|
-
* outputRuleset: (context: EvalContext, output: CSSOutput, rules: Node[]) => void
|
|
37
|
-
* }} NestableAtRuleThis
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
// A media query may only carry a media type at its front, before any
|
|
41
|
-
// conditions (https://drafts.csswg.org/mediaqueries-5/#typedef-media-query-list).
|
|
42
|
-
// Operators that join media-query parts, so a fragment leading with one is not
|
|
43
|
-
// a media type. Any other bare identifier is treated as a type, since unknown
|
|
44
|
-
// media types are valid non-matches in CSS, not syntax errors.
|
|
45
|
-
const MEDIA_QUERY_OPERATORS = ['and', 'or'];
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Whether a flattened media-query fragment leads with a media type, e.g.
|
|
49
|
-
* `screen`, `only screen`, `print and (color)` or an unknown type like `foo`.
|
|
50
|
-
* @param {Node & { value?: * }} fragment
|
|
51
|
-
*/
|
|
52
|
-
function startsWithMediaType(fragment) {
|
|
53
|
-
let head;
|
|
54
|
-
if (fragment.type === 'Keyword' || fragment.type === 'Anonymous') {
|
|
55
|
-
head = fragment.value;
|
|
56
|
-
} else if (fragment.type === 'Expression' && Array.isArray(fragment.value)) {
|
|
57
|
-
const parts = fragment.value.filter(p => p && p.value !== undefined);
|
|
58
|
-
let idx = 0;
|
|
59
|
-
const first = parts[idx] && String(parts[idx].value).toLowerCase();
|
|
60
|
-
if (first === 'not' || first === 'only') { idx++; }
|
|
61
|
-
head = parts[idx] && parts[idx].value;
|
|
62
|
-
}
|
|
63
|
-
if (typeof head !== 'string' || head === '') {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
// Inspect only the first token. A media type is a bare identifier; a feature
|
|
67
|
-
// condition begins with '(' - e.g. an escaped ~"(max-width: 1px)" is an
|
|
68
|
-
// Anonymous whose whole value is "(max-width: 1px)", which is not a media type.
|
|
69
|
-
const firstToken = head.trim().split(/[\s(]/)[0];
|
|
70
|
-
return firstToken !== ''
|
|
71
|
-
&& MEDIA_QUERY_OPERATORS.indexOf(firstToken.toLowerCase()) < 0;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const NestableAtRulePrototype = {
|
|
75
|
-
|
|
76
|
-
isRulesetLike() {
|
|
77
|
-
return true;
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
/** @param {TreeVisitor} visitor */
|
|
81
|
-
accept(visitor) {
|
|
82
|
-
/** @type {NestableAtRuleThis} */
|
|
83
|
-
const self = /** @type {NestableAtRuleThis} */ (/** @type {unknown} */ (this));
|
|
84
|
-
if (self.features) {
|
|
85
|
-
self.features = /** @type {Value} */ (visitor.visit(self.features));
|
|
86
|
-
}
|
|
87
|
-
if (self.rules) {
|
|
88
|
-
self.rules = /** @type {Ruleset[]} */ (visitor.visitArray(self.rules));
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
evalFunction: function () {
|
|
93
|
-
/** @type {NestableAtRuleThis} */
|
|
94
|
-
const self = /** @type {NestableAtRuleThis} */ (/** @type {unknown} */ (this));
|
|
95
|
-
if (!self.features || !Array.isArray(self.features.value) || self.features.value.length < 1) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const exprValues = /** @type {Node[]} */ (self.features.value);
|
|
100
|
-
/** @type {Node | undefined} */
|
|
101
|
-
let expr;
|
|
102
|
-
/** @type {Node | undefined} */
|
|
103
|
-
let paren;
|
|
104
|
-
|
|
105
|
-
for (let index = 0; index < exprValues.length; ++index) {
|
|
106
|
-
expr = exprValues[index];
|
|
107
|
-
|
|
108
|
-
if ((expr.type === 'Keyword' || expr.type === 'Variable')
|
|
109
|
-
&& index + 1 < exprValues.length
|
|
110
|
-
&& (/** @type {Node & { noSpacing?: boolean }} */ (expr).noSpacing || /** @type {Node & { noSpacing?: boolean }} */ (expr).noSpacing == null)) {
|
|
111
|
-
paren = exprValues[index + 1];
|
|
112
|
-
|
|
113
|
-
if (paren.type === 'Paren' && /** @type {Node & { noSpacing?: boolean }} */ (paren).noSpacing) {
|
|
114
|
-
exprValues[index]= new Expression([expr, paren]);
|
|
115
|
-
exprValues.splice(index + 1, 1);
|
|
116
|
-
/** @type {Node & { noSpacing?: boolean }} */ (exprValues[index]).noSpacing = true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
/** @param {EvalContext} context */
|
|
123
|
-
evalTop(context) {
|
|
124
|
-
/** @type {NestableAtRuleThis} */
|
|
125
|
-
const self = /** @type {NestableAtRuleThis} */ (/** @type {unknown} */ (this));
|
|
126
|
-
self.evalFunction();
|
|
127
|
-
|
|
128
|
-
/** @type {Node | Ruleset} */
|
|
129
|
-
let result = self;
|
|
130
|
-
|
|
131
|
-
// Render all dependent Media blocks.
|
|
132
|
-
if (context.mediaBlocks.length > 1) {
|
|
133
|
-
const selectors = (new Selector([], null, null, self.getIndex(), self.fileInfo())).createEmptySelectors();
|
|
134
|
-
result = new Ruleset(selectors, context.mediaBlocks);
|
|
135
|
-
/** @type {Ruleset & { multiMedia?: boolean }} */ (result).multiMedia = true;
|
|
136
|
-
result.copyVisibilityInfo(self.visibilityInfo());
|
|
137
|
-
self.setParent(result, self);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
delete context.mediaBlocks;
|
|
141
|
-
delete context.mediaPath;
|
|
142
|
-
|
|
143
|
-
return result;
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
/** @param {EvalContext} context */
|
|
147
|
-
evalNested(context) {
|
|
148
|
-
/** @type {NestableAtRuleThis} */
|
|
149
|
-
const self = /** @type {NestableAtRuleThis} */ (/** @type {unknown} */ (this));
|
|
150
|
-
self.evalFunction();
|
|
151
|
-
|
|
152
|
-
let i;
|
|
153
|
-
/** @type {Node | Node[]} */
|
|
154
|
-
let value;
|
|
155
|
-
const path = context.mediaPath.concat([self]);
|
|
156
|
-
|
|
157
|
-
// Extract the media-query conditions separated with `,` (OR).
|
|
158
|
-
for (i = 0; i < path.length; i++) {
|
|
159
|
-
if (path[i].type !== self.type) {
|
|
160
|
-
const blockIndex = context.mediaBlocks.indexOf(self);
|
|
161
|
-
if (blockIndex > -1) {
|
|
162
|
-
context.mediaBlocks.splice(blockIndex, 1);
|
|
163
|
-
}
|
|
164
|
-
return self;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
value = /** @type {NestableAtRuleThis} */ (path[i]).features instanceof Value ?
|
|
168
|
-
/** @type {Node[]} */ (/** @type {NestableAtRuleThis} */ (path[i]).features.value) : /** @type {NestableAtRuleThis} */ (path[i]).features;
|
|
169
|
-
path[i] = /** @type {Node} */ (/** @type {unknown} */ (Array.isArray(value) ? value : [value]));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Trace all permutations to generate the resulting media-query.
|
|
173
|
-
//
|
|
174
|
-
// (a, b and c) with nested (d, e) ->
|
|
175
|
-
// a and d
|
|
176
|
-
// a and e
|
|
177
|
-
// b and c and d
|
|
178
|
-
// b and c and e
|
|
179
|
-
self.features = new Value(self.permute(/** @type {Node[][]} */ (/** @type {unknown} */ (path))).map(
|
|
180
|
-
/** @param {Node | Node[]} path */
|
|
181
|
-
path => {
|
|
182
|
-
path = /** @type {Node[]} */ (path).map(
|
|
183
|
-
/** @param {Node & { toCSS?: Function }} fragment */
|
|
184
|
-
fragment => fragment.toCSS ? fragment : new Anonymous(/** @type {string} */ (/** @type {unknown} */ (fragment))));
|
|
185
|
-
|
|
186
|
-
// A media type nested inside conditions must move ahead of them
|
|
187
|
-
// so the flattened query stays valid (issue #3694, #3764).
|
|
188
|
-
const types = /** @type {Node[]} */ (path).filter(startsWithMediaType);
|
|
189
|
-
if (types.length && types.length < /** @type {Node[]} */ (path).length) {
|
|
190
|
-
path = types.concat(/** @type {Node[]} */ (path).filter(f => !startsWithMediaType(f)));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
for (i = /** @type {Node[]} */ (path).length - 1; i > 0; i--) {
|
|
194
|
-
/** @type {Node[]} */ (path).splice(i, 0, new Anonymous('and'));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return new Expression(/** @type {Node[]} */ (path));
|
|
198
|
-
}));
|
|
199
|
-
self.setParent(self.features, self);
|
|
200
|
-
|
|
201
|
-
// Fake a tree-node that doesn't output anything.
|
|
202
|
-
return new Ruleset([], []);
|
|
203
|
-
},
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* @param {Node[][]} arr
|
|
207
|
-
* @returns {Node[][]}
|
|
208
|
-
*/
|
|
209
|
-
permute(arr) {
|
|
210
|
-
if (arr.length === 0) {
|
|
211
|
-
return [];
|
|
212
|
-
} else if (arr.length === 1) {
|
|
213
|
-
return /** @type {Node[][]} */ (/** @type {unknown} */ (arr[0]));
|
|
214
|
-
} else {
|
|
215
|
-
/** @type {Node[][]} */
|
|
216
|
-
const result = [];
|
|
217
|
-
const rest = this.permute(arr.slice(1));
|
|
218
|
-
for (let i = 0; i < rest.length; i++) {
|
|
219
|
-
for (let j = 0; j < arr[0].length; j++) {
|
|
220
|
-
result.push([arr[0][j]].concat(rest[i]));
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return result;
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
/** @param {Selector[] | undefined} selectors */
|
|
228
|
-
bubbleSelectors(selectors) {
|
|
229
|
-
/** @type {NestableAtRuleThis} */
|
|
230
|
-
const self = /** @type {NestableAtRuleThis} */ (/** @type {unknown} */ (this));
|
|
231
|
-
if (!selectors) {
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
self.rules = [new Ruleset(utils.copyArray(selectors), [self.rules[0]])];
|
|
235
|
-
self.setParent(self.rules, self);
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
export default NestableAtRulePrototype;
|