Skip to content

Commit 6809415

Browse files
committed
Release v4.4.0
* Update files for Revlease/v4.4.0
1 parent 67404cd commit 6809415

File tree

10 files changed

+210
-17
lines changed

10 files changed

+210
-17
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## Change Log
22

3+
### v4.4.0 (2025-05-31)
4+
5+
- [#4337](https://github.com/less/less.js/pull/4337) add support for layer at-rule (@puckowski)
6+
- [#4340](https://github.com/less/less.js/pull/4340) Add support for import at-rule layer functionality (@puckowski)
7+
38
### v4.3.0 (2025-04-04)
49

510
- [#4319](https://github.com/less/less.js/pull/4319) Add deprecation warnings to Less output during parsing and new quiet flag (@matthew-dean)

dist/less.js

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Less - Leaner CSS v4.3.0
2+
* Less - Leaner CSS v4.4.0
33
* http://lesscss.org
44
*
55
* Copyright (c) 2009-2025, Alexis Sellier <[email protected]>
@@ -5179,6 +5179,7 @@
51795179
var hasUnknown;
51805180
var hasBlock = true;
51815181
var isRooted = true;
5182+
var isKeywordList = false;
51825183
if (parserInput.currentChar() !== '@') {
51835184
return;
51845185
}
@@ -5216,6 +5217,9 @@
52165217
case '@starting-style':
52175218
isRooted = false;
52185219
break;
5220+
case '@layer':
5221+
isRooted = false;
5222+
break;
52195223
default:
52205224
hasUnknown = true;
52215225
break;
@@ -5247,8 +5251,33 @@
52475251
}
52485252
if (hasBlock) {
52495253
rules = this.blockRuleset();
5254+
parserInput.save();
5255+
if (!rules && !isRooted) {
5256+
value = this.entity();
5257+
rules = this.blockRuleset();
5258+
}
5259+
if (!rules && !isRooted) {
5260+
parserInput.restore();
5261+
var e = [];
5262+
value = this.entity();
5263+
while (parserInput.$char(',')) {
5264+
e.push(value);
5265+
value = this.entity();
5266+
}
5267+
if (value && e.length > 0) {
5268+
e.push(value);
5269+
value = e;
5270+
isKeywordList = true;
5271+
}
5272+
else {
5273+
rules = this.blockRuleset();
5274+
}
5275+
}
5276+
else {
5277+
parserInput.forget();
5278+
}
52505279
}
5251-
if (rules || (!hasBlock && value && parserInput.$char(';'))) {
5280+
if (rules || isKeywordList || (!hasBlock && value && parserInput.$char(';'))) {
52525281
parserInput.forget();
52535282
return new (tree.AtRule)(name, value, rules, index + currentIndex, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted);
52545283
}
@@ -7016,6 +7045,7 @@
70167045
this.value = visitor.visitArray(this.value);
70177046
},
70187047
eval: function (context) {
7048+
var noSpacing = this.noSpacing;
70197049
var returnValue;
70207050
var mathOn = context.isMathOn();
70217051
var inParenthesis = this.parens;
@@ -7047,6 +7077,7 @@
70477077
&& (!(returnValue instanceof Dimension))) {
70487078
returnValue = new Paren(returnValue);
70497079
}
7080+
returnValue.noSpacing = returnValue.noSpacing || noSpacing;
70507081
return returnValue;
70517082
},
70527083
genCSS: function (context, output) {
@@ -7212,6 +7243,13 @@
72127243
else {
72137244
return rules.filter(function (node) { return (node.type === 'Declaration' || node.type === 'Comment'); }).length === rules.length;
72147245
}
7246+
}, keywordList: function (rules) {
7247+
if (!Array.isArray(rules)) {
7248+
return false;
7249+
}
7250+
else {
7251+
return rules.filter(function (node) { return (node.type === 'Keyword' || node.type === 'Comment'); }).length === rules.length;
7252+
}
72157253
}, accept: function (visitor) {
72167254
var value = this.value, rules = this.rules, declarations = this.declarations;
72177255
if (rules) {
@@ -7254,6 +7292,9 @@
72547292
context.mediaBlocks = [];
72557293
if (value) {
72567294
value = value.eval(context);
7295+
if (value.value && this.keywordList(value.value)) {
7296+
value = new Anonymous(value.value.map(function (keyword) { return keyword.value; }).join(', '), this.getIndex(), this.fileInfo());
7297+
}
72577298
}
72587299
if (rules) {
72597300
rules = this.evalRoot(context, rules);
@@ -8008,26 +8049,79 @@
80088049
return [];
80098050
}
80108051
}
8052+
if (this.features) {
8053+
var featureValue = this.features.value;
8054+
if (Array.isArray(featureValue) && featureValue.length >= 1) {
8055+
var expr = featureValue[0];
8056+
if (expr.type === 'Expression' && Array.isArray(expr.value) && expr.value.length >= 2) {
8057+
featureValue = expr.value;
8058+
var isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
8059+
&& featureValue[1].type === 'Paren';
8060+
if (isLayer) {
8061+
this.css = false;
8062+
}
8063+
}
8064+
}
8065+
}
80118066
if (this.options.inline) {
80128067
var contents = new Anonymous(this.root, 0, {
80138068
filename: this.importedFilename,
80148069
reference: this.path._fileInfo && this.path._fileInfo.reference
80158070
}, true, true);
80168071
return this.features ? new Media([contents], this.features.value) : [contents];
80178072
}
8018-
else if (this.css) {
8073+
else if (this.css || this.layerCss) {
80198074
var newImport = new Import(this.evalPath(context), features, this.options, this._index);
8075+
if (this.layerCss) {
8076+
newImport.css = this.layerCss;
8077+
newImport.path._fileInfo = this._fileInfo;
8078+
}
80208079
if (!newImport.css && this.error) {
80218080
throw this.error;
80228081
}
80238082
return newImport;
80248083
}
80258084
else if (this.root) {
8085+
if (this.features) {
8086+
var featureValue = this.features.value;
8087+
if (Array.isArray(featureValue) && featureValue.length === 1) {
8088+
var expr = featureValue[0];
8089+
if (expr.type === 'Expression' && Array.isArray(expr.value) && expr.value.length >= 2) {
8090+
featureValue = expr.value;
8091+
var isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
8092+
&& featureValue[1].type === 'Paren';
8093+
if (isLayer) {
8094+
this.layerCss = true;
8095+
featureValue[0] = new Expression(featureValue.slice(0, 2));
8096+
featureValue.splice(1, 1);
8097+
featureValue[0].noSpacing = true;
8098+
return this;
8099+
}
8100+
}
8101+
}
8102+
}
80268103
ruleset = new Ruleset(null, copyArray(this.root.rules));
80278104
ruleset.evalImports(context);
80288105
return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;
80298106
}
80308107
else {
8108+
if (this.features) {
8109+
var featureValue = this.features.value;
8110+
if (Array.isArray(featureValue) && featureValue.length >= 1) {
8111+
featureValue = featureValue[0].value;
8112+
if (Array.isArray(featureValue) && featureValue.length >= 2) {
8113+
var isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
8114+
&& featureValue[1].type === 'Paren';
8115+
if (isLayer) {
8116+
this.css = true;
8117+
featureValue[0] = new Expression(featureValue.slice(0, 2));
8118+
featureValue.splice(1, 1);
8119+
featureValue[0].noSpacing = true;
8120+
return this;
8121+
}
8122+
}
8123+
}
8124+
}
80318125
return [];
80328126
}
80338127
}
@@ -11025,7 +11119,7 @@
1102511119
return render;
1102611120
}
1102711121

11028-
var version = "4.3.0";
11122+
var version = "4.4.0";
1102911123

1103011124
function parseNodeVersion(version) {
1103111125
var match = version.match(/^v(\d{1,2})\.(\d{1,2})\.(\d{1,2})(?:-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-.]+))?$/); // eslint-disable-line max-len

dist/less.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/less.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@less/root",
33
"private": true,
4-
"version": "4.3.0",
4+
"version": "4.4.0",
55
"description": "Less monorepo",
66
"homepage": "http://lesscss.org",
77
"scripts": {

packages/less/dist/less.js

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Less - Leaner CSS v4.3.0
2+
* Less - Leaner CSS v4.4.0
33
* http://lesscss.org
44
*
55
* Copyright (c) 2009-2025, Alexis Sellier <[email protected]>
@@ -5179,6 +5179,7 @@
51795179
var hasUnknown;
51805180
var hasBlock = true;
51815181
var isRooted = true;
5182+
var isKeywordList = false;
51825183
if (parserInput.currentChar() !== '@') {
51835184
return;
51845185
}
@@ -5216,6 +5217,9 @@
52165217
case '@starting-style':
52175218
isRooted = false;
52185219
break;
5220+
case '@layer':
5221+
isRooted = false;
5222+
break;
52195223
default:
52205224
hasUnknown = true;
52215225
break;
@@ -5247,8 +5251,33 @@
52475251
}
52485252
if (hasBlock) {
52495253
rules = this.blockRuleset();
5254+
parserInput.save();
5255+
if (!rules && !isRooted) {
5256+
value = this.entity();
5257+
rules = this.blockRuleset();
5258+
}
5259+
if (!rules && !isRooted) {
5260+
parserInput.restore();
5261+
var e = [];
5262+
value = this.entity();
5263+
while (parserInput.$char(',')) {
5264+
e.push(value);
5265+
value = this.entity();
5266+
}
5267+
if (value && e.length > 0) {
5268+
e.push(value);
5269+
value = e;
5270+
isKeywordList = true;
5271+
}
5272+
else {
5273+
rules = this.blockRuleset();
5274+
}
5275+
}
5276+
else {
5277+
parserInput.forget();
5278+
}
52505279
}
5251-
if (rules || (!hasBlock && value && parserInput.$char(';'))) {
5280+
if (rules || isKeywordList || (!hasBlock && value && parserInput.$char(';'))) {
52525281
parserInput.forget();
52535282
return new (tree.AtRule)(name, value, rules, index + currentIndex, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted);
52545283
}
@@ -7016,6 +7045,7 @@
70167045
this.value = visitor.visitArray(this.value);
70177046
},
70187047
eval: function (context) {
7048+
var noSpacing = this.noSpacing;
70197049
var returnValue;
70207050
var mathOn = context.isMathOn();
70217051
var inParenthesis = this.parens;
@@ -7047,6 +7077,7 @@
70477077
&& (!(returnValue instanceof Dimension))) {
70487078
returnValue = new Paren(returnValue);
70497079
}
7080+
returnValue.noSpacing = returnValue.noSpacing || noSpacing;
70507081
return returnValue;
70517082
},
70527083
genCSS: function (context, output) {
@@ -7212,6 +7243,13 @@
72127243
else {
72137244
return rules.filter(function (node) { return (node.type === 'Declaration' || node.type === 'Comment'); }).length === rules.length;
72147245
}
7246+
}, keywordList: function (rules) {
7247+
if (!Array.isArray(rules)) {
7248+
return false;
7249+
}
7250+
else {
7251+
return rules.filter(function (node) { return (node.type === 'Keyword' || node.type === 'Comment'); }).length === rules.length;
7252+
}
72157253
}, accept: function (visitor) {
72167254
var value = this.value, rules = this.rules, declarations = this.declarations;
72177255
if (rules) {
@@ -7254,6 +7292,9 @@
72547292
context.mediaBlocks = [];
72557293
if (value) {
72567294
value = value.eval(context);
7295+
if (value.value && this.keywordList(value.value)) {
7296+
value = new Anonymous(value.value.map(function (keyword) { return keyword.value; }).join(', '), this.getIndex(), this.fileInfo());
7297+
}
72577298
}
72587299
if (rules) {
72597300
rules = this.evalRoot(context, rules);
@@ -8008,26 +8049,79 @@
80088049
return [];
80098050
}
80108051
}
8052+
if (this.features) {
8053+
var featureValue = this.features.value;
8054+
if (Array.isArray(featureValue) && featureValue.length >= 1) {
8055+
var expr = featureValue[0];
8056+
if (expr.type === 'Expression' && Array.isArray(expr.value) && expr.value.length >= 2) {
8057+
featureValue = expr.value;
8058+
var isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
8059+
&& featureValue[1].type === 'Paren';
8060+
if (isLayer) {
8061+
this.css = false;
8062+
}
8063+
}
8064+
}
8065+
}
80118066
if (this.options.inline) {
80128067
var contents = new Anonymous(this.root, 0, {
80138068
filename: this.importedFilename,
80148069
reference: this.path._fileInfo && this.path._fileInfo.reference
80158070
}, true, true);
80168071
return this.features ? new Media([contents], this.features.value) : [contents];
80178072
}
8018-
else if (this.css) {
8073+
else if (this.css || this.layerCss) {
80198074
var newImport = new Import(this.evalPath(context), features, this.options, this._index);
8075+
if (this.layerCss) {
8076+
newImport.css = this.layerCss;
8077+
newImport.path._fileInfo = this._fileInfo;
8078+
}
80208079
if (!newImport.css && this.error) {
80218080
throw this.error;
80228081
}
80238082
return newImport;
80248083
}
80258084
else if (this.root) {
8085+
if (this.features) {
8086+
var featureValue = this.features.value;
8087+
if (Array.isArray(featureValue) && featureValue.length === 1) {
8088+
var expr = featureValue[0];
8089+
if (expr.type === 'Expression' && Array.isArray(expr.value) && expr.value.length >= 2) {
8090+
featureValue = expr.value;
8091+
var isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
8092+
&& featureValue[1].type === 'Paren';
8093+
if (isLayer) {
8094+
this.layerCss = true;
8095+
featureValue[0] = new Expression(featureValue.slice(0, 2));
8096+
featureValue.splice(1, 1);
8097+
featureValue[0].noSpacing = true;
8098+
return this;
8099+
}
8100+
}
8101+
}
8102+
}
80268103
ruleset = new Ruleset(null, copyArray(this.root.rules));
80278104
ruleset.evalImports(context);
80288105
return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;
80298106
}
80308107
else {
8108+
if (this.features) {
8109+
var featureValue = this.features.value;
8110+
if (Array.isArray(featureValue) && featureValue.length >= 1) {
8111+
featureValue = featureValue[0].value;
8112+
if (Array.isArray(featureValue) && featureValue.length >= 2) {
8113+
var isLayer = featureValue[0].type === 'Keyword' && featureValue[0].value === 'layer'
8114+
&& featureValue[1].type === 'Paren';
8115+
if (isLayer) {
8116+
this.css = true;
8117+
featureValue[0] = new Expression(featureValue.slice(0, 2));
8118+
featureValue.splice(1, 1);
8119+
featureValue[0].noSpacing = true;
8120+
return this;
8121+
}
8122+
}
8123+
}
8124+
}
80318125
return [];
80328126
}
80338127
}
@@ -11025,7 +11119,7 @@
1102511119
return render;
1102611120
}
1102711121

11028-
var version = "4.3.0";
11122+
var version = "4.4.0";
1102911123

1103011124
function parseNodeVersion(version) {
1103111125
var match = version.match(/^v(\d{1,2})\.(\d{1,2})\.(\d{1,2})(?:-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-.]+))?$/); // eslint-disable-line max-len

0 commit comments

Comments
 (0)