less 4.6.6 → 4.7.0
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/dist/less-node.cjs +168 -32
- package/dist/less.cjs +143 -26
- package/dist/less.js +143 -26
- package/dist/less.min.js +2 -2
- package/dist/less.min.js.map +1 -1
- package/lib/less/deprecation.js +5 -2
- package/lib/less/parser/parser-input.js +21 -1
- package/lib/less/parser/parser.js +112 -15
- package/lib/less/tree/nested-at-rule.js +6 -6
- package/lib/less-node/environment.js +3 -3
- package/lib/less-node/image-size.js +25 -6
- package/package.json +2 -2
package/dist/less.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Less - Leaner CSS v4.
|
|
2
|
+
* Less - Leaner CSS v4.7.0
|
|
3
3
|
* http://lesscss.org
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) 2009-2026, Alexis Sellier <self@cloudhead.net>
|
|
@@ -4100,12 +4100,23 @@
|
|
|
4100
4100
|
/**
|
|
4101
4101
|
* Permissive parsing. Ignores everything except matching {} [] () and quotes
|
|
4102
4102
|
* until matching token (outside of blocks)
|
|
4103
|
-
|
|
4104
|
-
|
|
4103
|
+
*
|
|
4104
|
+
* @param {string|RegExp} tok - stop token
|
|
4105
|
+
* @param {boolean} [detectBareVar] - when set, also record the position of the
|
|
4106
|
+
* first bare `@variable` reference (not `@{interpolation}`) that appears at
|
|
4107
|
+
* PAREN depth 0 — i.e. a structural reference, not a declaration value inside
|
|
4108
|
+
* `(...)`. Reuses this single pass (which already skips strings/comments) so
|
|
4109
|
+
* callers don't re-scan the text. Exposed as `.bareVarIndex` on the returned
|
|
4110
|
+
* group array (or null). `[...]`/`{...}` do NOT shield a reference — only
|
|
4111
|
+
* `(...)` (a declaration-value group) does.
|
|
4112
|
+
*/
|
|
4113
|
+
parserInput.$parseUntil = (tok, detectBareVar) => {
|
|
4105
4114
|
let quote = '';
|
|
4106
4115
|
let returnVal = null;
|
|
4107
4116
|
let inComment = false;
|
|
4108
4117
|
let blockDepth = 0;
|
|
4118
|
+
let parenDepth = 0;
|
|
4119
|
+
let bareVarIndex = null;
|
|
4109
4120
|
const blockStack = [];
|
|
4110
4121
|
const parseGroups = [];
|
|
4111
4122
|
const length = input.length;
|
|
@@ -4145,6 +4156,12 @@
|
|
|
4145
4156
|
i++;
|
|
4146
4157
|
continue;
|
|
4147
4158
|
}
|
|
4159
|
+
if (detectBareVar && bareVarIndex === null && nextChar === '@' && parenDepth === 0) {
|
|
4160
|
+
// A bare `@ident` (not `@{interpolation}`) outside any `(...)` —
|
|
4161
|
+
// a structural reference. Strings/comments are already skipped above.
|
|
4162
|
+
const after = input.charAt(i + 1);
|
|
4163
|
+
if (after && /[-\w]/.test(after)) { bareVarIndex = i; }
|
|
4164
|
+
}
|
|
4148
4165
|
switch (nextChar) {
|
|
4149
4166
|
case '\\':
|
|
4150
4167
|
i++;
|
|
@@ -4180,6 +4197,7 @@
|
|
|
4180
4197
|
case '(':
|
|
4181
4198
|
blockStack.push(')');
|
|
4182
4199
|
blockDepth++;
|
|
4200
|
+
parenDepth++;
|
|
4183
4201
|
break;
|
|
4184
4202
|
case '[':
|
|
4185
4203
|
blockStack.push(']');
|
|
@@ -4191,6 +4209,7 @@
|
|
|
4191
4209
|
const expected = blockStack.pop();
|
|
4192
4210
|
if (nextChar === expected) {
|
|
4193
4211
|
blockDepth--;
|
|
4212
|
+
if (nextChar === ')' && parenDepth > 0) { parenDepth--; }
|
|
4194
4213
|
} else {
|
|
4195
4214
|
// move the parser to the error and return expected
|
|
4196
4215
|
skipWhitespace(i - startPos);
|
|
@@ -4206,6 +4225,7 @@
|
|
|
4206
4225
|
}
|
|
4207
4226
|
} while (loop);
|
|
4208
4227
|
|
|
4228
|
+
if (Array.isArray(returnVal)) { returnVal.bareVarIndex = bareVarIndex; }
|
|
4209
4229
|
return returnVal ? returnVal : null;
|
|
4210
4230
|
};
|
|
4211
4231
|
|
|
@@ -4406,6 +4426,10 @@
|
|
|
4406
4426
|
|
|
4407
4427
|
const deprecationHandler = new DeprecationHandler();
|
|
4408
4428
|
|
|
4429
|
+
// Tracks `${deprecationId}@${index}` pairs already warned about, so a source
|
|
4430
|
+
// position that gets re-parsed via parser backtracking only warns once.
|
|
4431
|
+
const warnedDeprecations = new Set();
|
|
4432
|
+
|
|
4409
4433
|
/**
|
|
4410
4434
|
* @param {string} msg
|
|
4411
4435
|
* @param {number} index
|
|
@@ -4415,6 +4439,11 @@
|
|
|
4415
4439
|
function warn(msg, index, type, deprecationId) {
|
|
4416
4440
|
if (context.quiet) { return; }
|
|
4417
4441
|
if (deprecationId && context.quietDeprecations) { return; }
|
|
4442
|
+
if (deprecationId) {
|
|
4443
|
+
const key = `${deprecationId}@${index ?? parserInput.i}`;
|
|
4444
|
+
if (warnedDeprecations.has(key)) { return; }
|
|
4445
|
+
warnedDeprecations.add(key);
|
|
4446
|
+
}
|
|
4418
4447
|
if (deprecationId && !deprecationHandler.shouldWarn(deprecationId)) { return; }
|
|
4419
4448
|
|
|
4420
4449
|
logger$1.warn(
|
|
@@ -4430,6 +4459,17 @@
|
|
|
4430
4459
|
);
|
|
4431
4460
|
}
|
|
4432
4461
|
|
|
4462
|
+
/**
|
|
4463
|
+
* Warn that a bare `@variable` reference is being used in a non-value
|
|
4464
|
+
* position (an at-rule prelude, name, or identifier), where it still
|
|
4465
|
+
* resolves today but is deprecated in favour of `@{variable}` interpolation.
|
|
4466
|
+
*
|
|
4467
|
+
* @param {number} index - source position of the bare reference
|
|
4468
|
+
*/
|
|
4469
|
+
function warnBareAtRuleVariable(index) {
|
|
4470
|
+
warn('A bare @variable in an at-rule prelude is deprecated. Use @{variable} interpolation instead.', index, 'DEPRECATED', 'variable-in-at-rule-prelude');
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4433
4473
|
function expect(arg, msg) {
|
|
4434
4474
|
// some older browsers return typeof 'function' for RegExp
|
|
4435
4475
|
const result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);
|
|
@@ -5980,7 +6020,7 @@
|
|
|
5980
6020
|
if (parserInput.$char(';')) {
|
|
5981
6021
|
value = new Anonymous('');
|
|
5982
6022
|
} else {
|
|
5983
|
-
value = this.permissiveValue(/[;}]
|
|
6023
|
+
value = this.permissiveValue(/[;}]/);
|
|
5984
6024
|
}
|
|
5985
6025
|
}
|
|
5986
6026
|
// Try to store values as anonymous
|
|
@@ -6039,8 +6079,12 @@
|
|
|
6039
6079
|
* math is allowed.
|
|
6040
6080
|
*
|
|
6041
6081
|
* @param {RexExp} untilTokens - Characters to stop parsing at
|
|
6082
|
+
* @param {boolean} [deprecateVariables] - when set, this is an at-rule
|
|
6083
|
+
* prelude (non-value position); accept `@{var}` interpolation and warn
|
|
6084
|
+
* on a bare `@var` reference (which resolves today but is deprecated).
|
|
6042
6085
|
*/
|
|
6043
|
-
permissiveValue: function (untilTokens) {
|
|
6086
|
+
permissiveValue: function (untilTokens, deprecateVariables) {
|
|
6087
|
+
const entities = this.entities;
|
|
6044
6088
|
let i;
|
|
6045
6089
|
let e;
|
|
6046
6090
|
let done;
|
|
@@ -6067,7 +6111,20 @@
|
|
|
6067
6111
|
value.push(e);
|
|
6068
6112
|
continue;
|
|
6069
6113
|
}
|
|
6070
|
-
|
|
6114
|
+
if (deprecateVariables) {
|
|
6115
|
+
// In an at-rule prelude, `@{var}` interpolation is the supported
|
|
6116
|
+
// form; consume it here so its `{` is not mistaken for a block.
|
|
6117
|
+
e = entities.variableCurly();
|
|
6118
|
+
if (!e) {
|
|
6119
|
+
const varIndex = parserInput.i;
|
|
6120
|
+
e = this.entity();
|
|
6121
|
+
if (e && e.type === 'Variable') {
|
|
6122
|
+
warnBareAtRuleVariable(varIndex);
|
|
6123
|
+
}
|
|
6124
|
+
}
|
|
6125
|
+
} else {
|
|
6126
|
+
e = this.entity();
|
|
6127
|
+
}
|
|
6071
6128
|
if (e) {
|
|
6072
6129
|
value.push(e);
|
|
6073
6130
|
}
|
|
@@ -6094,7 +6151,7 @@
|
|
|
6094
6151
|
}
|
|
6095
6152
|
parserInput.save();
|
|
6096
6153
|
|
|
6097
|
-
value = parserInput.$parseUntil(tok);
|
|
6154
|
+
value = parserInput.$parseUntil(tok, deprecateVariables);
|
|
6098
6155
|
|
|
6099
6156
|
if (value) {
|
|
6100
6157
|
if (typeof value === 'string') {
|
|
@@ -6104,6 +6161,14 @@
|
|
|
6104
6161
|
parserInput.forget();
|
|
6105
6162
|
return new tree.Anonymous('', index);
|
|
6106
6163
|
}
|
|
6164
|
+
// At-rule prelude: `$parseUntil` (deprecateVariables) records the
|
|
6165
|
+
// first bare `@var` it saw outside any `(...)` in its single pass —
|
|
6166
|
+
// a structural reference (`[...]`/`{...}` don't shield it, only a
|
|
6167
|
+
// declaration-value `(...)` does). Warn once here rather than
|
|
6168
|
+
// re-scanning the text.
|
|
6169
|
+
if (deprecateVariables && value.bareVarIndex !== null && value.bareVarIndex !== undefined) {
|
|
6170
|
+
warnBareAtRuleVariable(value.bareVarIndex);
|
|
6171
|
+
}
|
|
6107
6172
|
/** @type {string} */
|
|
6108
6173
|
let item;
|
|
6109
6174
|
for (i = 0; i < value.length; i++) {
|
|
@@ -6120,11 +6185,14 @@
|
|
|
6120
6185
|
const quote = new tree.Quoted('\'', item, true, index, fileInfo);
|
|
6121
6186
|
const variableRegex = /@([\w-]+)/g;
|
|
6122
6187
|
const propRegex = /\$([\w-]+)/g;
|
|
6123
|
-
|
|
6124
|
-
|
|
6188
|
+
// At-rule preludes are handled once above via
|
|
6189
|
+
// `value.bareVarIndex`; the `variable-in-unknown-value`
|
|
6190
|
+
// notice is for unknown declaration values only.
|
|
6191
|
+
if (!deprecateVariables && variableRegex.test(item)) {
|
|
6192
|
+
warn('@variable in unknown values will not be evaluated as variables in the future. Use @{variable}', index, 'DEPRECATED', 'variable-in-unknown-value');
|
|
6125
6193
|
}
|
|
6126
6194
|
if (propRegex.test(item)) {
|
|
6127
|
-
warn('$
|
|
6195
|
+
warn('$property in unknown values will not be evaluated as property references in the future. Use ${property}', index, 'DEPRECATED', 'property-in-unknown-value');
|
|
6128
6196
|
}
|
|
6129
6197
|
quote.variableRegex = /@([\w-]+)|@{([\w-]+)}/g;
|
|
6130
6198
|
quote.propRegex = /\$([\w-]+)|\${([\w-]+)}/g;
|
|
@@ -6233,7 +6301,17 @@
|
|
|
6233
6301
|
}
|
|
6234
6302
|
parserInput.restore();
|
|
6235
6303
|
|
|
6236
|
-
e = entities.declarationCall.bind(this)() || cssKeyword() || entities.keyword() || entities.
|
|
6304
|
+
e = entities.declarationCall.bind(this)() || cssKeyword() || entities.keyword() || entities.variableCurly();
|
|
6305
|
+
if (!e) {
|
|
6306
|
+
const varIndex = parserInput.i;
|
|
6307
|
+
const bareVariable = entities.variable();
|
|
6308
|
+
if (bareVariable) {
|
|
6309
|
+
warnBareAtRuleVariable(varIndex);
|
|
6310
|
+
e = bareVariable;
|
|
6311
|
+
} else {
|
|
6312
|
+
e = entities.mixinLookup();
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6237
6315
|
if (e) {
|
|
6238
6316
|
nodes.push(e);
|
|
6239
6317
|
if (e.type === 'Variable' ||
|
|
@@ -6244,7 +6322,7 @@
|
|
|
6244
6322
|
let closed = false;
|
|
6245
6323
|
p = this.property();
|
|
6246
6324
|
parserInput.save();
|
|
6247
|
-
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^[
|
|
6325
|
+
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^(?:[^()]|\([^()]*\))*\s*([<>]=|<=|>=|[<>]|=)/)) {
|
|
6248
6326
|
parserInput.restore();
|
|
6249
6327
|
p = this.condition();
|
|
6250
6328
|
|
|
@@ -6324,7 +6402,17 @@
|
|
|
6324
6402
|
features[features.length - 1].noSpacing = false;
|
|
6325
6403
|
}
|
|
6326
6404
|
} else {
|
|
6327
|
-
e = entities.
|
|
6405
|
+
e = entities.variableCurly();
|
|
6406
|
+
if (!e) {
|
|
6407
|
+
const varIndex = parserInput.i;
|
|
6408
|
+
const bareVariable = entities.variable();
|
|
6409
|
+
if (bareVariable) {
|
|
6410
|
+
warnBareAtRuleVariable(varIndex);
|
|
6411
|
+
e = bareVariable;
|
|
6412
|
+
} else {
|
|
6413
|
+
e = entities.mixinLookup();
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6328
6416
|
if (e) {
|
|
6329
6417
|
features.push(e);
|
|
6330
6418
|
if (!parserInput.$char(',')) { break; }
|
|
@@ -6438,8 +6526,24 @@
|
|
|
6438
6526
|
return null;
|
|
6439
6527
|
}
|
|
6440
6528
|
},
|
|
6529
|
+
/**
|
|
6530
|
+
* An entity in a non-value at-rule position (an at-rule identifier,
|
|
6531
|
+
* name, or keyword-list item — e.g. the name in `@keyframes @foo`).
|
|
6532
|
+
* `@{foo}` interpolation is the supported form; a bare `@foo` still
|
|
6533
|
+
* resolves but is deprecated.
|
|
6534
|
+
*/
|
|
6535
|
+
atRuleEntity: function () {
|
|
6536
|
+
const curly = this.entities.variableCurly();
|
|
6537
|
+
if (curly) { return curly; }
|
|
6538
|
+
const index = parserInput.i;
|
|
6539
|
+
const e = this.entity();
|
|
6540
|
+
if (e && e.type === 'Variable') {
|
|
6541
|
+
warnBareAtRuleVariable(index);
|
|
6542
|
+
}
|
|
6543
|
+
return e;
|
|
6544
|
+
},
|
|
6441
6545
|
atruleUnknown: function (value, name, hasBlock) {
|
|
6442
|
-
value = this.permissiveValue(/^[{;]
|
|
6546
|
+
value = this.permissiveValue(/^[{;]/, true);
|
|
6443
6547
|
hasBlock = (parserInput.currentChar() === '{');
|
|
6444
6548
|
if (!value) {
|
|
6445
6549
|
if (!hasBlock && parserInput.currentChar() !== ';') {
|
|
@@ -6455,16 +6559,16 @@
|
|
|
6455
6559
|
rules = this.blockRuleset();
|
|
6456
6560
|
parserInput.save();
|
|
6457
6561
|
if (!rules && !isRooted) {
|
|
6458
|
-
value = this.
|
|
6562
|
+
value = this.atRuleEntity();
|
|
6459
6563
|
rules = this.blockRuleset();
|
|
6460
6564
|
}
|
|
6461
6565
|
if (!rules && !isRooted) {
|
|
6462
6566
|
parserInput.restore();
|
|
6463
6567
|
var e = [];
|
|
6464
|
-
value = this.
|
|
6568
|
+
value = this.atRuleEntity();
|
|
6465
6569
|
while (parserInput.$char(',')) {
|
|
6466
6570
|
e.push(value);
|
|
6467
|
-
value = this.
|
|
6571
|
+
value = this.atRuleEntity();
|
|
6468
6572
|
}
|
|
6469
6573
|
if (value && e.length > 0) {
|
|
6470
6574
|
e.push(value);
|
|
@@ -6549,12 +6653,25 @@
|
|
|
6549
6653
|
parserInput.commentStore.length = 0;
|
|
6550
6654
|
|
|
6551
6655
|
if (hasIdentifier) {
|
|
6552
|
-
value = this.
|
|
6656
|
+
value = this.atRuleEntity();
|
|
6553
6657
|
if (!value) {
|
|
6554
6658
|
error(`expected ${name} identifier`);
|
|
6555
6659
|
}
|
|
6556
6660
|
} else if (hasExpression) {
|
|
6661
|
+
// `@namespace` may carry an interpolated `@{ns}` prefix (or a
|
|
6662
|
+
// deprecated bare `@ns`). Parse that prefix directly so `@{ns}`
|
|
6663
|
+
// is accepted here without treating value positions as
|
|
6664
|
+
// interpolation contexts, then read the namespace URL.
|
|
6665
|
+
let prefix = this.entities.variableCurly();
|
|
6666
|
+
if (!prefix && parserInput.peek(/^@@?[\w-]/)) {
|
|
6667
|
+
const prefixIndex = parserInput.i;
|
|
6668
|
+
prefix = this.entities.variable();
|
|
6669
|
+
if (prefix) { warnBareAtRuleVariable(prefixIndex); }
|
|
6670
|
+
}
|
|
6557
6671
|
value = this.expression();
|
|
6672
|
+
if (prefix) {
|
|
6673
|
+
value = value ? new(tree.Expression)([prefix, ...value.value]) : prefix;
|
|
6674
|
+
}
|
|
6558
6675
|
if (!value) {
|
|
6559
6676
|
error(`expected ${name} expression`);
|
|
6560
6677
|
}
|
|
@@ -8617,16 +8734,16 @@
|
|
|
8617
8734
|
self.features = new Value(self.permute(/** @type {Node[][]} */ (/** @type {unknown} */ (path))).map(
|
|
8618
8735
|
/** @param {Node | Node[]} path */
|
|
8619
8736
|
path => {
|
|
8620
|
-
|
|
8737
|
+
path = /** @type {Node[]} */ (path).map(
|
|
8621
8738
|
/** @param {Node & { toCSS?: Function }} fragment */
|
|
8622
|
-
|
|
8739
|
+
fragment => fragment.toCSS ? fragment : new Anonymous(/** @type {string} */ (/** @type {unknown} */ (fragment))));
|
|
8623
8740
|
|
|
8624
|
-
|
|
8741
|
+
for (i = /** @type {Node[]} */ (path).length - 1; i > 0; i--) {
|
|
8625
8742
|
/** @type {Node[]} */ (path).splice(i, 0, new Anonymous('and'));
|
|
8626
|
-
|
|
8743
|
+
}
|
|
8627
8744
|
|
|
8628
|
-
|
|
8629
|
-
|
|
8745
|
+
return new Expression(/** @type {Node[]} */ (path));
|
|
8746
|
+
}));
|
|
8630
8747
|
self.setParent(self.features, self);
|
|
8631
8748
|
|
|
8632
8749
|
// Fake a tree-node that doesn't output anything.
|
|
@@ -14175,7 +14292,7 @@
|
|
|
14175
14292
|
};
|
|
14176
14293
|
|
|
14177
14294
|
var name = "less";
|
|
14178
|
-
var version = "4.
|
|
14295
|
+
var version = "4.7.0";
|
|
14179
14296
|
var description = "Leaner CSS";
|
|
14180
14297
|
var homepage = "http://lesscss.org";
|
|
14181
14298
|
var author = {
|
|
@@ -14245,7 +14362,7 @@
|
|
|
14245
14362
|
var optionalDependencies = {
|
|
14246
14363
|
errno: "^0.1.1",
|
|
14247
14364
|
"graceful-fs": "^4.1.2",
|
|
14248
|
-
"image-size": "
|
|
14365
|
+
"probe-image-size": "^7.2.3",
|
|
14249
14366
|
"make-dir": "^5.1.0",
|
|
14250
14367
|
mime: "^1.4.1",
|
|
14251
14368
|
needle: "^3.1.0",
|