less 4.6.7 → 4.8.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 +296 -64
- package/dist/less.cjs +271 -58
- package/dist/less.js +271 -58
- package/dist/less.min.js +2 -2
- package/dist/less.min.js.map +1 -1
- package/lib/less/deprecation.js +17 -2
- package/lib/less/parser/parser-input.js +21 -1
- package/lib/less/parser/parser.js +210 -29
- package/lib/less/tree/mixin-definition.js +30 -18
- 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-node.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Less - Leaner CSS v4.
|
|
2
|
+
* Less - Leaner CSS v4.8.0
|
|
3
3
|
* http://lesscss.org
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) 2009-2026, Alexis Sellier <self@cloudhead.net>
|
|
@@ -31,6 +31,7 @@ class SourceMapGeneratorFallback {
|
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
|
|
34
35
|
var environment = {
|
|
35
36
|
encodeBase64: function encodeBase64(str) {
|
|
36
37
|
// Avoid Buffer constructor on newer versions of Node.js.
|
|
@@ -40,9 +41,9 @@ var environment = {
|
|
|
40
41
|
mimeLookup: function (filename) {
|
|
41
42
|
try {
|
|
42
43
|
const mimeModule = require$6('mime');
|
|
43
|
-
return mimeModule ? mimeModule.lookup(filename) :
|
|
44
|
+
return mimeModule ? mimeModule.lookup(filename) : 'application/octet-stream';
|
|
44
45
|
} catch (e) {
|
|
45
|
-
return
|
|
46
|
+
return 'application/octet-stream';
|
|
46
47
|
}
|
|
47
48
|
},
|
|
48
49
|
charsetLookup: function (mime) {
|
|
@@ -4267,12 +4268,23 @@ var getParserInput = () => {
|
|
|
4267
4268
|
/**
|
|
4268
4269
|
* Permissive parsing. Ignores everything except matching {} [] () and quotes
|
|
4269
4270
|
* until matching token (outside of blocks)
|
|
4270
|
-
|
|
4271
|
-
|
|
4271
|
+
*
|
|
4272
|
+
* @param {string|RegExp} tok - stop token
|
|
4273
|
+
* @param {boolean} [detectBareVar] - when set, also record the position of the
|
|
4274
|
+
* first bare `@variable` reference (not `@{interpolation}`) that appears at
|
|
4275
|
+
* PAREN depth 0 — i.e. a structural reference, not a declaration value inside
|
|
4276
|
+
* `(...)`. Reuses this single pass (which already skips strings/comments) so
|
|
4277
|
+
* callers don't re-scan the text. Exposed as `.bareVarIndex` on the returned
|
|
4278
|
+
* group array (or null). `[...]`/`{...}` do NOT shield a reference — only
|
|
4279
|
+
* `(...)` (a declaration-value group) does.
|
|
4280
|
+
*/
|
|
4281
|
+
parserInput.$parseUntil = (tok, detectBareVar) => {
|
|
4272
4282
|
let quote = '';
|
|
4273
4283
|
let returnVal = null;
|
|
4274
4284
|
let inComment = false;
|
|
4275
4285
|
let blockDepth = 0;
|
|
4286
|
+
let parenDepth = 0;
|
|
4287
|
+
let bareVarIndex = null;
|
|
4276
4288
|
const blockStack = [];
|
|
4277
4289
|
const parseGroups = [];
|
|
4278
4290
|
const length = input.length;
|
|
@@ -4312,6 +4324,12 @@ var getParserInput = () => {
|
|
|
4312
4324
|
i++;
|
|
4313
4325
|
continue;
|
|
4314
4326
|
}
|
|
4327
|
+
if (detectBareVar && bareVarIndex === null && nextChar === '@' && parenDepth === 0) {
|
|
4328
|
+
// A bare `@ident` (not `@{interpolation}`) outside any `(...)` —
|
|
4329
|
+
// a structural reference. Strings/comments are already skipped above.
|
|
4330
|
+
const after = input.charAt(i + 1);
|
|
4331
|
+
if (after && /[-\w]/.test(after)) { bareVarIndex = i; }
|
|
4332
|
+
}
|
|
4315
4333
|
switch (nextChar) {
|
|
4316
4334
|
case '\\':
|
|
4317
4335
|
i++;
|
|
@@ -4347,6 +4365,7 @@ var getParserInput = () => {
|
|
|
4347
4365
|
case '(':
|
|
4348
4366
|
blockStack.push(')');
|
|
4349
4367
|
blockDepth++;
|
|
4368
|
+
parenDepth++;
|
|
4350
4369
|
break;
|
|
4351
4370
|
case '[':
|
|
4352
4371
|
blockStack.push(']');
|
|
@@ -4358,6 +4377,7 @@ var getParserInput = () => {
|
|
|
4358
4377
|
const expected = blockStack.pop();
|
|
4359
4378
|
if (nextChar === expected) {
|
|
4360
4379
|
blockDepth--;
|
|
4380
|
+
if (nextChar === ')' && parenDepth > 0) { parenDepth--; }
|
|
4361
4381
|
} else {
|
|
4362
4382
|
// move the parser to the error and return expected
|
|
4363
4383
|
skipWhitespace(i - startPos);
|
|
@@ -4373,6 +4393,7 @@ var getParserInput = () => {
|
|
|
4373
4393
|
}
|
|
4374
4394
|
} while (loop);
|
|
4375
4395
|
|
|
4396
|
+
if (Array.isArray(returnVal)) { returnVal.bareVarIndex = bareVarIndex; }
|
|
4376
4397
|
return returnVal ? returnVal : null;
|
|
4377
4398
|
};
|
|
4378
4399
|
|
|
@@ -4573,6 +4594,10 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
4573
4594
|
|
|
4574
4595
|
const deprecationHandler = new DeprecationHandler();
|
|
4575
4596
|
|
|
4597
|
+
// Tracks `${deprecationId}@${index}` pairs already warned about, so a source
|
|
4598
|
+
// position that gets re-parsed via parser backtracking only warns once.
|
|
4599
|
+
const warnedDeprecations = new Set();
|
|
4600
|
+
|
|
4576
4601
|
/**
|
|
4577
4602
|
* @param {string} msg
|
|
4578
4603
|
* @param {number} index
|
|
@@ -4582,6 +4607,11 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
4582
4607
|
function warn(msg, index, type, deprecationId) {
|
|
4583
4608
|
if (context.quiet) { return; }
|
|
4584
4609
|
if (deprecationId && context.quietDeprecations) { return; }
|
|
4610
|
+
if (deprecationId) {
|
|
4611
|
+
const key = `${deprecationId}@${index ?? parserInput.i}`;
|
|
4612
|
+
if (warnedDeprecations.has(key)) { return; }
|
|
4613
|
+
warnedDeprecations.add(key);
|
|
4614
|
+
}
|
|
4585
4615
|
if (deprecationId && !deprecationHandler.shouldWarn(deprecationId)) { return; }
|
|
4586
4616
|
|
|
4587
4617
|
logger.warn(
|
|
@@ -4597,6 +4627,75 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
4597
4627
|
);
|
|
4598
4628
|
}
|
|
4599
4629
|
|
|
4630
|
+
/**
|
|
4631
|
+
* Warn that a bare `@variable` reference is being used in a non-value
|
|
4632
|
+
* position (an at-rule prelude, name, or identifier), where it still
|
|
4633
|
+
* resolves today but is deprecated in favour of `@{variable}` interpolation.
|
|
4634
|
+
*
|
|
4635
|
+
* @param {number} index - source position of the bare reference
|
|
4636
|
+
*/
|
|
4637
|
+
function warnBareAtRuleVariable(index) {
|
|
4638
|
+
warn('A bare @variable in an at-rule prelude is deprecated. Use @{variable} interpolation instead.', index, 'DEPRECATED', 'variable-in-at-rule-prelude');
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4641
|
+
/**
|
|
4642
|
+
* Numeric-leading variable names are a Less extension rather than valid CSS
|
|
4643
|
+
* identifier syntax. Keep accepting them through Less 4, but make the Less 5
|
|
4644
|
+
* migration visible at every actual variable reference or definition.
|
|
4645
|
+
*
|
|
4646
|
+
* @param {string} name - either an @-prefixed name or the name inside @{...}
|
|
4647
|
+
* @param {number} index - source position of the variable token
|
|
4648
|
+
*/
|
|
4649
|
+
function warnNumericVariableName(name, index) {
|
|
4650
|
+
if (/^(?:@@?)?[0-9]/.test(name)) {
|
|
4651
|
+
warn('Variable names beginning with a number are deprecated and will be removed in Less 5.x. Rename the variable to start with a valid identifier character.', index, 'DEPRECATED', 'numeric-variable-name');
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
|
|
4655
|
+
/**
|
|
4656
|
+
* A lone '-' is not a CSS identifier. Less historically accepts it as a
|
|
4657
|
+
* variable name; retain that in Less 4 only and warn on definitions,
|
|
4658
|
+
* ordinary references, and interpolation references.
|
|
4659
|
+
*
|
|
4660
|
+
* @param {string} name - either @-/@@-, or the name inside @{...}
|
|
4661
|
+
* @param {number} index - source position of the variable token
|
|
4662
|
+
*/
|
|
4663
|
+
function warnDashOnlyVariableName(name, index) {
|
|
4664
|
+
const bareName = name.replace(/^@@?/, '');
|
|
4665
|
+
if (bareName === '-') {
|
|
4666
|
+
warn('The dash-only variable names @- and @{-} are deprecated and will be removed in Less 5.x. Rename the variable to use a valid identifier.', index, 'DEPRECATED', 'dash-only-variable-name');
|
|
4667
|
+
}
|
|
4668
|
+
}
|
|
4669
|
+
|
|
4670
|
+
/**
|
|
4671
|
+
* A lone '-' is not a CSS identifier. Less historically accepts it as a mixin
|
|
4672
|
+
* name after '.' or '#'; retain that in Less 4 only.
|
|
4673
|
+
*
|
|
4674
|
+
* @param {string} name
|
|
4675
|
+
* @param {number} index
|
|
4676
|
+
*/
|
|
4677
|
+
function warnDashOnlyMixinName(name, index) {
|
|
4678
|
+
if (name === '.-' || name === '#-') {
|
|
4679
|
+
warn('The dash-only mixin names .-() and #-() are deprecated and will be removed in Less 5.x. Rename the mixin to use a valid CSS identifier.', index, 'DEPRECATED', 'dash-only-mixin-name');
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4682
|
+
|
|
4683
|
+
/**
|
|
4684
|
+
* CSS @charset is a source-header declaration, not a general dynamic at-rule.
|
|
4685
|
+
* Less 4 keeps its historical interpolation behavior for compatibility, but
|
|
4686
|
+
* makes each dynamic spelling visible before Less 5 rejects it.
|
|
4687
|
+
*
|
|
4688
|
+
* @param {import('../tree/node.js').default} value
|
|
4689
|
+
* @param {number} index - source position of the @charset token
|
|
4690
|
+
*/
|
|
4691
|
+
function warnDynamicCharset(value, index) {
|
|
4692
|
+
if (value instanceof tree.Variable ||
|
|
4693
|
+
(value instanceof tree.Quoted &&
|
|
4694
|
+
(value.containsVariables() || value.value.match(value.propRegex)))) {
|
|
4695
|
+
warn('Dynamic @charset interpolation is deprecated and will be removed in Less 5.x. Use a static quoted encoding declaration instead.', index, 'DEPRECATED', 'dynamic-charset');
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
|
|
4600
4699
|
function expect(arg, msg) {
|
|
4601
4700
|
// some older browsers return typeof 'function' for RegExp
|
|
4602
4701
|
const result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);
|
|
@@ -5050,7 +5149,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5050
5149
|
}
|
|
5051
5150
|
|
|
5052
5151
|
function condition() {
|
|
5053
|
-
return [expect(parsers.condition, 'expected condition')];
|
|
5152
|
+
return [expect(() => parsers.condition(false, true), 'expected condition')];
|
|
5054
5153
|
}
|
|
5055
5154
|
},
|
|
5056
5155
|
|
|
@@ -5175,6 +5274,8 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5175
5274
|
|
|
5176
5275
|
parserInput.save();
|
|
5177
5276
|
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) {
|
|
5277
|
+
warnNumericVariableName(name, index);
|
|
5278
|
+
warnDashOnlyVariableName(name, index);
|
|
5178
5279
|
ch = parserInput.currentChar();
|
|
5179
5280
|
if ((ch === '(' && !parserInput.prevChar().match(/^\s/))
|
|
5180
5281
|
|| (ch === '[' && !parserInput.prevChar().match(/^\s/))) {
|
|
@@ -5197,6 +5298,8 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5197
5298
|
const index = parserInput.i;
|
|
5198
5299
|
|
|
5199
5300
|
if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) {
|
|
5301
|
+
warnNumericVariableName(curly[1], index);
|
|
5302
|
+
warnDashOnlyVariableName(curly[1], index);
|
|
5200
5303
|
return new(tree.Variable)(`@${curly[1]}`, index + currentIndex, fileInfo);
|
|
5201
5304
|
}
|
|
5202
5305
|
},
|
|
@@ -5319,7 +5422,11 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5319
5422
|
variable: function () {
|
|
5320
5423
|
let name;
|
|
5321
5424
|
|
|
5322
|
-
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) {
|
|
5425
|
+
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) {
|
|
5426
|
+
warnNumericVariableName(name[1], parserInput.i - name[0].length);
|
|
5427
|
+
warnDashOnlyVariableName(name[1], parserInput.i - name[0].length);
|
|
5428
|
+
return name[1];
|
|
5429
|
+
}
|
|
5323
5430
|
},
|
|
5324
5431
|
|
|
5325
5432
|
//
|
|
@@ -5349,6 +5456,8 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5349
5456
|
}
|
|
5350
5457
|
|
|
5351
5458
|
if (!inValue) {
|
|
5459
|
+
warnNumericVariableName(name[1], i);
|
|
5460
|
+
warnDashOnlyVariableName(name[1], i);
|
|
5352
5461
|
name = name[1];
|
|
5353
5462
|
}
|
|
5354
5463
|
|
|
@@ -5505,6 +5614,9 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5505
5614
|
if (inValue || parsers.end()) {
|
|
5506
5615
|
parserInput.forget();
|
|
5507
5616
|
const mixin = new(tree.mixin.Call)(elements, args, index + currentIndex, fileInfo, !lookups && important);
|
|
5617
|
+
for (const element of elements) {
|
|
5618
|
+
warnDashOnlyMixinName(element.value, element._index - currentIndex);
|
|
5619
|
+
}
|
|
5508
5620
|
if (lookups) {
|
|
5509
5621
|
return new tree.NamespaceValue(mixin, lookups);
|
|
5510
5622
|
}
|
|
@@ -5701,6 +5813,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5701
5813
|
let ruleset;
|
|
5702
5814
|
let cond;
|
|
5703
5815
|
let variadic = false;
|
|
5816
|
+
const index = parserInput.i;
|
|
5704
5817
|
if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') ||
|
|
5705
5818
|
parserInput.peek(/^[^{]*\}/)) {
|
|
5706
5819
|
return;
|
|
@@ -5736,6 +5849,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
5736
5849
|
|
|
5737
5850
|
if (ruleset) {
|
|
5738
5851
|
parserInput.forget();
|
|
5852
|
+
warnDashOnlyMixinName(name, index);
|
|
5739
5853
|
return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
|
|
5740
5854
|
} else {
|
|
5741
5855
|
parserInput.restore();
|
|
@@ -6147,7 +6261,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6147
6261
|
if (parserInput.$char(';')) {
|
|
6148
6262
|
value = new Anonymous('');
|
|
6149
6263
|
} else {
|
|
6150
|
-
value = this.permissiveValue(/[;}]
|
|
6264
|
+
value = this.permissiveValue(/[;}]/);
|
|
6151
6265
|
}
|
|
6152
6266
|
}
|
|
6153
6267
|
// Try to store values as anonymous
|
|
@@ -6206,8 +6320,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6206
6320
|
* math is allowed.
|
|
6207
6321
|
*
|
|
6208
6322
|
* @param {RexExp} untilTokens - Characters to stop parsing at
|
|
6323
|
+
* @param {boolean} [deprecateVariables] - when set, this is an at-rule
|
|
6324
|
+
* prelude (non-value position); accept `@{var}` interpolation and warn
|
|
6325
|
+
* on a bare `@var` reference (which resolves today but is deprecated).
|
|
6209
6326
|
*/
|
|
6210
|
-
permissiveValue: function (untilTokens) {
|
|
6327
|
+
permissiveValue: function (untilTokens, deprecateVariables) {
|
|
6328
|
+
const entities = this.entities;
|
|
6211
6329
|
let i;
|
|
6212
6330
|
let e;
|
|
6213
6331
|
let done;
|
|
@@ -6234,7 +6352,20 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6234
6352
|
value.push(e);
|
|
6235
6353
|
continue;
|
|
6236
6354
|
}
|
|
6237
|
-
|
|
6355
|
+
if (deprecateVariables) {
|
|
6356
|
+
// In an at-rule prelude, `@{var}` interpolation is the supported
|
|
6357
|
+
// form; consume it here so its `{` is not mistaken for a block.
|
|
6358
|
+
e = entities.variableCurly();
|
|
6359
|
+
if (!e) {
|
|
6360
|
+
const varIndex = parserInput.i;
|
|
6361
|
+
e = this.entity();
|
|
6362
|
+
if (e && e.type === 'Variable') {
|
|
6363
|
+
warnBareAtRuleVariable(varIndex);
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
} else {
|
|
6367
|
+
e = this.entity();
|
|
6368
|
+
}
|
|
6238
6369
|
if (e) {
|
|
6239
6370
|
value.push(e);
|
|
6240
6371
|
}
|
|
@@ -6261,7 +6392,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6261
6392
|
}
|
|
6262
6393
|
parserInput.save();
|
|
6263
6394
|
|
|
6264
|
-
value = parserInput.$parseUntil(tok);
|
|
6395
|
+
value = parserInput.$parseUntil(tok, deprecateVariables);
|
|
6265
6396
|
|
|
6266
6397
|
if (value) {
|
|
6267
6398
|
if (typeof value === 'string') {
|
|
@@ -6271,6 +6402,14 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6271
6402
|
parserInput.forget();
|
|
6272
6403
|
return new tree.Anonymous('', index);
|
|
6273
6404
|
}
|
|
6405
|
+
// At-rule prelude: `$parseUntil` (deprecateVariables) records the
|
|
6406
|
+
// first bare `@var` it saw outside any `(...)` in its single pass —
|
|
6407
|
+
// a structural reference (`[...]`/`{...}` don't shield it, only a
|
|
6408
|
+
// declaration-value `(...)` does). Warn once here rather than
|
|
6409
|
+
// re-scanning the text.
|
|
6410
|
+
if (deprecateVariables && value.bareVarIndex !== null && value.bareVarIndex !== undefined) {
|
|
6411
|
+
warnBareAtRuleVariable(value.bareVarIndex);
|
|
6412
|
+
}
|
|
6274
6413
|
/** @type {string} */
|
|
6275
6414
|
let item;
|
|
6276
6415
|
for (i = 0; i < value.length; i++) {
|
|
@@ -6287,11 +6426,14 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6287
6426
|
const quote = new tree.Quoted('\'', item, true, index, fileInfo);
|
|
6288
6427
|
const variableRegex = /@([\w-]+)/g;
|
|
6289
6428
|
const propRegex = /\$([\w-]+)/g;
|
|
6290
|
-
|
|
6291
|
-
|
|
6429
|
+
// At-rule preludes are handled once above via
|
|
6430
|
+
// `value.bareVarIndex`; the `variable-in-unknown-value`
|
|
6431
|
+
// notice is for unknown declaration values only.
|
|
6432
|
+
if (!deprecateVariables && variableRegex.test(item)) {
|
|
6433
|
+
warn('@variable in unknown values will not be evaluated as variables in the future. Use @{variable}', index, 'DEPRECATED', 'variable-in-unknown-value');
|
|
6292
6434
|
}
|
|
6293
6435
|
if (propRegex.test(item)) {
|
|
6294
|
-
warn('$
|
|
6436
|
+
warn('$property in unknown values will not be evaluated as property references in the future. Use ${property}', index, 'DEPRECATED', 'property-in-unknown-value');
|
|
6295
6437
|
}
|
|
6296
6438
|
quote.variableRegex = /@([\w-]+)|@{([\w-]+)}/g;
|
|
6297
6439
|
quote.propRegex = /\$([\w-]+)|\${([\w-]+)}/g;
|
|
@@ -6400,7 +6542,17 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6400
6542
|
}
|
|
6401
6543
|
parserInput.restore();
|
|
6402
6544
|
|
|
6403
|
-
e = entities.declarationCall.bind(this)() || cssKeyword() || entities.keyword() || entities.
|
|
6545
|
+
e = entities.declarationCall.bind(this)() || cssKeyword() || entities.keyword() || entities.variableCurly();
|
|
6546
|
+
if (!e) {
|
|
6547
|
+
const varIndex = parserInput.i;
|
|
6548
|
+
const bareVariable = entities.variable();
|
|
6549
|
+
if (bareVariable) {
|
|
6550
|
+
warnBareAtRuleVariable(varIndex);
|
|
6551
|
+
e = bareVariable;
|
|
6552
|
+
} else {
|
|
6553
|
+
e = entities.mixinLookup();
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6404
6556
|
if (e) {
|
|
6405
6557
|
nodes.push(e);
|
|
6406
6558
|
if (e.type === 'Variable' ||
|
|
@@ -6411,7 +6563,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6411
6563
|
let closed = false;
|
|
6412
6564
|
p = this.property();
|
|
6413
6565
|
parserInput.save();
|
|
6414
|
-
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^[
|
|
6566
|
+
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^(?:[^()]|\([^()]*\))*\s*([<>]=|<=|>=|[<>]|=)/)) {
|
|
6415
6567
|
parserInput.restore();
|
|
6416
6568
|
p = this.condition();
|
|
6417
6569
|
|
|
@@ -6491,7 +6643,17 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6491
6643
|
features[features.length - 1].noSpacing = false;
|
|
6492
6644
|
}
|
|
6493
6645
|
} else {
|
|
6494
|
-
e = entities.
|
|
6646
|
+
e = entities.variableCurly();
|
|
6647
|
+
if (!e) {
|
|
6648
|
+
const varIndex = parserInput.i;
|
|
6649
|
+
const bareVariable = entities.variable();
|
|
6650
|
+
if (bareVariable) {
|
|
6651
|
+
warnBareAtRuleVariable(varIndex);
|
|
6652
|
+
e = bareVariable;
|
|
6653
|
+
} else {
|
|
6654
|
+
e = entities.mixinLookup();
|
|
6655
|
+
}
|
|
6656
|
+
}
|
|
6495
6657
|
if (e) {
|
|
6496
6658
|
features.push(e);
|
|
6497
6659
|
if (!parserInput.$char(',')) { break; }
|
|
@@ -6605,8 +6767,24 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6605
6767
|
return null;
|
|
6606
6768
|
}
|
|
6607
6769
|
},
|
|
6770
|
+
/**
|
|
6771
|
+
* An entity in a non-value at-rule position (an at-rule identifier,
|
|
6772
|
+
* name, or keyword-list item — e.g. the name in `@keyframes @foo`).
|
|
6773
|
+
* `@{foo}` interpolation is the supported form; a bare `@foo` still
|
|
6774
|
+
* resolves but is deprecated.
|
|
6775
|
+
*/
|
|
6776
|
+
atRuleEntity: function () {
|
|
6777
|
+
const curly = this.entities.variableCurly();
|
|
6778
|
+
if (curly) { return curly; }
|
|
6779
|
+
const index = parserInput.i;
|
|
6780
|
+
const e = this.entity();
|
|
6781
|
+
if (e && e.type === 'Variable') {
|
|
6782
|
+
warnBareAtRuleVariable(index);
|
|
6783
|
+
}
|
|
6784
|
+
return e;
|
|
6785
|
+
},
|
|
6608
6786
|
atruleUnknown: function (value, name, hasBlock) {
|
|
6609
|
-
value = this.permissiveValue(/^[{;]
|
|
6787
|
+
value = this.permissiveValue(/^[{;]/, true);
|
|
6610
6788
|
hasBlock = (parserInput.currentChar() === '{');
|
|
6611
6789
|
if (!value) {
|
|
6612
6790
|
if (!hasBlock && parserInput.currentChar() !== ';') {
|
|
@@ -6622,16 +6800,16 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6622
6800
|
rules = this.blockRuleset();
|
|
6623
6801
|
parserInput.save();
|
|
6624
6802
|
if (!rules && !isRooted) {
|
|
6625
|
-
value = this.
|
|
6803
|
+
value = this.atRuleEntity();
|
|
6626
6804
|
rules = this.blockRuleset();
|
|
6627
6805
|
}
|
|
6628
6806
|
if (!rules && !isRooted) {
|
|
6629
6807
|
parserInput.restore();
|
|
6630
6808
|
var e = [];
|
|
6631
|
-
value = this.
|
|
6809
|
+
value = this.atRuleEntity();
|
|
6632
6810
|
while (parserInput.$char(',')) {
|
|
6633
6811
|
e.push(value);
|
|
6634
|
-
value = this.
|
|
6812
|
+
value = this.atRuleEntity();
|
|
6635
6813
|
}
|
|
6636
6814
|
if (value && e.length > 0) {
|
|
6637
6815
|
e.push(value);
|
|
@@ -6716,12 +6894,28 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6716
6894
|
parserInput.commentStore.length = 0;
|
|
6717
6895
|
|
|
6718
6896
|
if (hasIdentifier) {
|
|
6719
|
-
value = this.
|
|
6897
|
+
value = this.atRuleEntity();
|
|
6720
6898
|
if (!value) {
|
|
6721
6899
|
error(`expected ${name} identifier`);
|
|
6722
6900
|
}
|
|
6901
|
+
if (nonVendorSpecificName === '@charset') {
|
|
6902
|
+
warnDynamicCharset(value, index);
|
|
6903
|
+
}
|
|
6723
6904
|
} else if (hasExpression) {
|
|
6905
|
+
// `@namespace` may carry an interpolated `@{ns}` prefix (or a
|
|
6906
|
+
// deprecated bare `@ns`). Parse that prefix directly so `@{ns}`
|
|
6907
|
+
// is accepted here without treating value positions as
|
|
6908
|
+
// interpolation contexts, then read the namespace URL.
|
|
6909
|
+
let prefix = this.entities.variableCurly();
|
|
6910
|
+
if (!prefix && parserInput.peek(/^@@?[\w-]/)) {
|
|
6911
|
+
const prefixIndex = parserInput.i;
|
|
6912
|
+
prefix = this.entities.variable();
|
|
6913
|
+
if (prefix) { warnBareAtRuleVariable(prefixIndex); }
|
|
6914
|
+
}
|
|
6724
6915
|
value = this.expression();
|
|
6916
|
+
if (prefix) {
|
|
6917
|
+
value = value ? new(tree.Expression)([prefix, ...value.value]) : prefix;
|
|
6918
|
+
}
|
|
6725
6919
|
if (!value) {
|
|
6726
6920
|
error(`expected ${name} expression`);
|
|
6727
6921
|
}
|
|
@@ -6911,7 +7105,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6911
7105
|
return condition || a;
|
|
6912
7106
|
}
|
|
6913
7107
|
},
|
|
6914
|
-
condition: function (needsParens) {
|
|
7108
|
+
condition: function (needsParens, allowConditionOperands) {
|
|
6915
7109
|
let result;
|
|
6916
7110
|
let logical;
|
|
6917
7111
|
let next;
|
|
@@ -6919,13 +7113,13 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6919
7113
|
return parserInput.$str('or');
|
|
6920
7114
|
}
|
|
6921
7115
|
|
|
6922
|
-
result = this.conditionAnd(needsParens);
|
|
7116
|
+
result = this.conditionAnd(needsParens, allowConditionOperands);
|
|
6923
7117
|
if (!result) {
|
|
6924
7118
|
return ;
|
|
6925
7119
|
}
|
|
6926
7120
|
logical = or();
|
|
6927
7121
|
if (logical) {
|
|
6928
|
-
next = this.condition(needsParens);
|
|
7122
|
+
next = this.condition(needsParens, allowConditionOperands);
|
|
6929
7123
|
if (next) {
|
|
6930
7124
|
result = new(tree.Condition)(logical, result, next);
|
|
6931
7125
|
} else {
|
|
@@ -6934,13 +7128,13 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6934
7128
|
}
|
|
6935
7129
|
return result;
|
|
6936
7130
|
},
|
|
6937
|
-
conditionAnd: function (needsParens) {
|
|
7131
|
+
conditionAnd: function (needsParens, allowConditionOperands) {
|
|
6938
7132
|
let result;
|
|
6939
7133
|
let logical;
|
|
6940
7134
|
let next;
|
|
6941
7135
|
const self = this;
|
|
6942
7136
|
function insideCondition() {
|
|
6943
|
-
const cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens);
|
|
7137
|
+
const cond = self.negatedCondition(needsParens, allowConditionOperands) || self.parenthesisCondition(needsParens, allowConditionOperands);
|
|
6944
7138
|
if (!cond && !needsParens) {
|
|
6945
7139
|
return self.atomicCondition(needsParens);
|
|
6946
7140
|
}
|
|
@@ -6954,9 +7148,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6954
7148
|
if (!result) {
|
|
6955
7149
|
return ;
|
|
6956
7150
|
}
|
|
7151
|
+
if (allowConditionOperands) {
|
|
7152
|
+
result = this.atomicCondition(needsParens, result, allowConditionOperands) || result;
|
|
7153
|
+
}
|
|
6957
7154
|
logical = and();
|
|
6958
7155
|
if (logical) {
|
|
6959
|
-
next = this.conditionAnd(needsParens);
|
|
7156
|
+
next = this.conditionAnd(needsParens, allowConditionOperands);
|
|
6960
7157
|
if (next) {
|
|
6961
7158
|
result = new(tree.Condition)(logical, result, next);
|
|
6962
7159
|
} else {
|
|
@@ -6965,9 +7162,9 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6965
7162
|
}
|
|
6966
7163
|
return result;
|
|
6967
7164
|
},
|
|
6968
|
-
negatedCondition: function (needsParens) {
|
|
7165
|
+
negatedCondition: function (needsParens, allowConditionOperands) {
|
|
6969
7166
|
if (parserInput.$str('not')) {
|
|
6970
|
-
const result = this.parenthesisCondition(needsParens);
|
|
7167
|
+
const result = this.parenthesisCondition(needsParens, allowConditionOperands);
|
|
6971
7168
|
if (result) {
|
|
6972
7169
|
result.negate = !result.negate;
|
|
6973
7170
|
return result;
|
|
@@ -6984,11 +7181,11 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
6984
7181
|
}
|
|
6985
7182
|
}
|
|
6986
7183
|
},
|
|
6987
|
-
parenthesisCondition: function (needsParens) {
|
|
7184
|
+
parenthesisCondition: function (needsParens, allowConditionOperands) {
|
|
6988
7185
|
function tryConditionFollowedByParenthesis(me) {
|
|
6989
7186
|
let body;
|
|
6990
7187
|
parserInput.save();
|
|
6991
|
-
body = me.condition(needsParens);
|
|
7188
|
+
body = me.condition(needsParens, allowConditionOperands);
|
|
6992
7189
|
if (!body) {
|
|
6993
7190
|
parserInput.restore();
|
|
6994
7191
|
return ;
|
|
@@ -7025,7 +7222,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
7025
7222
|
parserInput.forget();
|
|
7026
7223
|
return body;
|
|
7027
7224
|
},
|
|
7028
|
-
atomicCondition: function (needsParens, preparsedCond) {
|
|
7225
|
+
atomicCondition: function (needsParens, preparsedCond, allowConditionOperands) {
|
|
7029
7226
|
const entities = this.entities;
|
|
7030
7227
|
const index = parserInput.i;
|
|
7031
7228
|
let a;
|
|
@@ -7034,7 +7231,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
7034
7231
|
let op;
|
|
7035
7232
|
|
|
7036
7233
|
const cond = (function() {
|
|
7037
|
-
return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup();
|
|
7234
|
+
return (allowConditionOperands && this.parenthesisCondition(needsParens)) || this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup();
|
|
7038
7235
|
}).bind(this);
|
|
7039
7236
|
|
|
7040
7237
|
if (preparsedCond) {
|
|
@@ -7195,6 +7392,11 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
7195
7392
|
}
|
|
7196
7393
|
for (k = 0; k < name.length; k++) {
|
|
7197
7394
|
s = name[k];
|
|
7395
|
+
if (s.charAt(0) === '@') {
|
|
7396
|
+
const variableName = s.slice(2, -1);
|
|
7397
|
+
warnNumericVariableName(variableName, index[k]);
|
|
7398
|
+
warnDashOnlyVariableName(variableName, index[k]);
|
|
7399
|
+
}
|
|
7198
7400
|
name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ?
|
|
7199
7401
|
new(tree.Keyword)(s) :
|
|
7200
7402
|
(s.charAt(0) === '@' ?
|
|
@@ -8784,16 +8986,16 @@ const NestableAtRulePrototype = {
|
|
|
8784
8986
|
self.features = new Value(self.permute(/** @type {Node[][]} */ (/** @type {unknown} */ (path))).map(
|
|
8785
8987
|
/** @param {Node | Node[]} path */
|
|
8786
8988
|
path => {
|
|
8787
|
-
|
|
8989
|
+
path = /** @type {Node[]} */ (path).map(
|
|
8788
8990
|
/** @param {Node & { toCSS?: Function }} fragment */
|
|
8789
|
-
|
|
8991
|
+
fragment => fragment.toCSS ? fragment : new Anonymous(/** @type {string} */ (/** @type {unknown} */ (fragment))));
|
|
8790
8992
|
|
|
8791
|
-
|
|
8993
|
+
for (i = /** @type {Node[]} */ (path).length - 1; i > 0; i--) {
|
|
8792
8994
|
/** @type {Node[]} */ (path).splice(i, 0, new Anonymous('and'));
|
|
8793
|
-
|
|
8995
|
+
}
|
|
8794
8996
|
|
|
8795
|
-
|
|
8796
|
-
|
|
8997
|
+
return new Expression(/** @type {Node[]} */ (path));
|
|
8998
|
+
}));
|
|
8797
8999
|
self.setParent(self.features, self);
|
|
8798
9000
|
|
|
8799
9001
|
// Fake a tree-node that doesn't output anything.
|
|
@@ -11147,35 +11349,47 @@ class Definition extends Ruleset {
|
|
|
11147
11349
|
*/
|
|
11148
11350
|
matchArgs(args, context) {
|
|
11149
11351
|
const allArgsCnt = (args && args.length) || 0;
|
|
11150
|
-
|
|
11151
|
-
const
|
|
11152
|
-
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
}
|
|
11156
|
-
|
|
11352
|
+
const evaldArguments = new Array(this.params.length);
|
|
11353
|
+
const positionalArgs = [];
|
|
11354
|
+
let positionalIndex = 0;
|
|
11355
|
+
|
|
11356
|
+
for (let i = 0; i < allArgsCnt; i++) {
|
|
11357
|
+
const arg = /** @type {MixinArg[]} */ (args)[i];
|
|
11358
|
+
if (!arg.name) {
|
|
11359
|
+
positionalArgs.push(arg);
|
|
11360
|
+
continue;
|
|
11157
11361
|
}
|
|
11158
|
-
}, 0);
|
|
11159
11362
|
|
|
11160
|
-
|
|
11161
|
-
if (
|
|
11363
|
+
const paramIndex = this.params.findIndex((param, index) => param.name === arg.name && !evaldArguments[index]);
|
|
11364
|
+
if (paramIndex < 0) {
|
|
11162
11365
|
return false;
|
|
11163
11366
|
}
|
|
11164
|
-
|
|
11165
|
-
|
|
11367
|
+
evaldArguments[paramIndex] = arg;
|
|
11368
|
+
}
|
|
11369
|
+
|
|
11370
|
+
for (let i = 0; i < this.params.length; i++) {
|
|
11371
|
+
if (evaldArguments[i]) {
|
|
11372
|
+
continue;
|
|
11166
11373
|
}
|
|
11167
|
-
|
|
11168
|
-
|
|
11374
|
+
if (this.params[i].variadic) {
|
|
11375
|
+
positionalIndex = positionalArgs.length;
|
|
11376
|
+
continue;
|
|
11377
|
+
}
|
|
11378
|
+
if (positionalIndex < positionalArgs.length) {
|
|
11379
|
+
evaldArguments[i] = positionalArgs[positionalIndex++];
|
|
11380
|
+
} else if (!this.params[i].name || !this.params[i].value) {
|
|
11169
11381
|
return false;
|
|
11170
11382
|
}
|
|
11171
11383
|
}
|
|
11172
11384
|
|
|
11173
|
-
|
|
11174
|
-
|
|
11385
|
+
if (positionalIndex < positionalArgs.length) {
|
|
11386
|
+
return false;
|
|
11387
|
+
}
|
|
11175
11388
|
|
|
11176
|
-
|
|
11389
|
+
// check patterns
|
|
11390
|
+
for (let i = 0; i < this.arity; i++) {
|
|
11177
11391
|
if (!this.params[i].name && !this.params[i].variadic) {
|
|
11178
|
-
if (
|
|
11392
|
+
if (evaldArguments[i].value.eval(context).toCSS(/** @type {EvalContext} */ ({})) != /** @type {Node} */ (this.params[i].value).eval(context).toCSS(/** @type {EvalContext} */ ({}))) {
|
|
11179
11393
|
return false;
|
|
11180
11394
|
}
|
|
11181
11395
|
}
|
|
@@ -14064,23 +14278,41 @@ var imageSize = environment => {
|
|
|
14064
14278
|
throw fileSync.error;
|
|
14065
14279
|
}
|
|
14066
14280
|
|
|
14067
|
-
|
|
14068
|
-
|
|
14281
|
+
let probe;
|
|
14282
|
+
try {
|
|
14283
|
+
probe = require$1('probe-image-size/sync');
|
|
14284
|
+
} catch (_) {
|
|
14285
|
+
return { width: 0, height: 0 };
|
|
14286
|
+
}
|
|
14287
|
+
|
|
14288
|
+
const size = probe(nodeFs.readFileSync(fileSync.filename));
|
|
14289
|
+
|
|
14290
|
+
if (!size) {
|
|
14291
|
+
throw {
|
|
14292
|
+
type: 'File',
|
|
14293
|
+
message: `Unrecognised image format for '${filePath}'`
|
|
14294
|
+
};
|
|
14295
|
+
}
|
|
14296
|
+
|
|
14297
|
+
return {
|
|
14298
|
+
width: size.width,
|
|
14299
|
+
height: size.height
|
|
14300
|
+
};
|
|
14069
14301
|
}
|
|
14070
14302
|
|
|
14071
14303
|
const imageFunctions = {
|
|
14072
|
-
'image-size': function(filePathNode) {
|
|
14304
|
+
'image-size': function (filePathNode) {
|
|
14073
14305
|
const size = imageSize(this, filePathNode);
|
|
14074
14306
|
return new Expression([
|
|
14075
14307
|
new Dimension(size.width, 'px'),
|
|
14076
14308
|
new Dimension(size.height, 'px')
|
|
14077
14309
|
]);
|
|
14078
14310
|
},
|
|
14079
|
-
'image-width': function(filePathNode) {
|
|
14311
|
+
'image-width': function (filePathNode) {
|
|
14080
14312
|
const size = imageSize(this, filePathNode);
|
|
14081
14313
|
return new Dimension(size.width, 'px');
|
|
14082
14314
|
},
|
|
14083
|
-
'image-height': function(filePathNode) {
|
|
14315
|
+
'image-height': function (filePathNode) {
|
|
14084
14316
|
const size = imageSize(this, filePathNode);
|
|
14085
14317
|
return new Dimension(size.height, 'px');
|
|
14086
14318
|
}
|
|
@@ -14090,7 +14322,7 @@ var imageSize = environment => {
|
|
|
14090
14322
|
};
|
|
14091
14323
|
|
|
14092
14324
|
createRequire();
|
|
14093
|
-
const version = "4.
|
|
14325
|
+
const version = "4.8.0";
|
|
14094
14326
|
|
|
14095
14327
|
const less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()], version);
|
|
14096
14328
|
|