Skip to content

Commit

Permalink
fix(issue:3777) operation on invalid type resolved
Browse files Browse the repository at this point in the history
* Fixes issue less#3777 where using CSS custom property in an operation
  resulted in a parsing error.
  • Loading branch information
puckowski committed Dec 7, 2024
1 parent a963f11 commit dac5bfd
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 4 deletions.
16 changes: 14 additions & 2 deletions packages/less/src/less/parser/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,18 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; }
},

//
// The custom property part of a variable definition.
//
// --fink:
//
customProperty: function () {
var name;
if (parserInput.currentChar() === '-' && (name = parserInput.$re(/^(--[\w-]+)\s*:/))) {
return name[1];
}
},

//
// Call a variable value to retrieve a detached ruleset
// or a value from a detached ruleset's rules.
Expand Down Expand Up @@ -1578,7 +1590,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {

parserInput.save();

name = this.variable() || this.ruleProperty();
name = this.variable() || this.customProperty() || this.ruleProperty();
if (name) {
isVariable = typeof name === 'string';

Expand All @@ -1597,7 +1609,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
merge = !isVariable && name.length > 1 && name.pop().value;

// Custom property values get permissive parsing
if (name[0].value && name[0].value.slice(0, 2) === '--') {
if (isVariable && name.startsWith('--')) {
if (parserInput.$char(';')) {
value = new Anonymous('');
} else {
Expand Down
59 changes: 58 additions & 1 deletion packages/less/src/less/tree/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Node from './node';
import Color from './color';
import Dimension from './dimension';
import * as Constants from '../constants';
import Variable from './variable';
import Call from './call';
const MATH = Constants.Math;


Expand All @@ -18,8 +20,51 @@ Operation.prototype = Object.assign(new Node(), {
this.operands = visitor.visitArray(this.operands);
},

find: function (obj, fun) {
for (var i_2 = 0, r = void 0; i_2 < obj.length; i_2++) {
r = fun.call(obj, obj[i_2]);
if (r) {
return r;
}
}
return null;
},

evalVariable: function (context, operand) {
if (operand.name === 'var' && operand.args.length === 1) {
var varName = operand.args[0].toCSS();
var variable = this.find(context.frames, function (frame) {
var v = frame.variable(varName);
if (v) {
if (v.important) {
var importantScope = context.importantScope[context.importantScope.length - 1];
importantScope.important = v.important;
}
// If in calc, wrap vars in a function call to cascade evaluate args first
if (context.inCalc) {
return (new Call('_SELF', [v.value])).eval(context);
}
else {
return v.value.eval(context);
}
}
});
if (variable) {
return variable;
}
}
},

eval(context) {
let a = this.operands[0].eval(context), b = this.operands[1].eval(context), op;
var a = this.evalVariable(context, this.operands[0])
if (!a) {
a = this.operands[0].eval(context)
}
var b = this.evalVariable(context, this.operands[1]);
if (!b) {
b = this.operands[1].eval(context);
}
var op;

if (context.isMathOn(this.op)) {
op = this.op === './' ? '/' : this.op;
Expand All @@ -29,6 +74,18 @@ Operation.prototype = Object.assign(new Node(), {
if (b instanceof Dimension && a instanceof Color) {
b = b.toColor();
}
if (a instanceof Dimension && b instanceof Call && b.name === 'var') {
if (b.args && b.args.length === 1) {
b = new Variable(b.args[0].toCSS(), 0, {});
return a.operate(context, op, b);
}
}
if (b instanceof Dimension && a instanceof Call && a.name === 'var') {
if (a.args && a.args.length === 1) {
a = new Variable(a.args[0].toCSS(), 0, {});
return b.operate(context, op, a);
}
}
if (!a.operate || !b.operate) {
if (
(a instanceof Operation || b instanceof Operation)
Expand Down
2 changes: 1 addition & 1 deletion packages/less/src/less/tree/ruleset.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ Ruleset.prototype = Object.assign(new Node(), {
variables() {
if (!this._variables) {
this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) {
if (r instanceof Declaration && r.variable === true) {
if (r instanceof Declaration && (r.variable === true || (typeof r.name ==='string' && r.name.startsWith('--')))) {
hash[r.name] = r;
}
// when evaluating variables in an import statement, imports have not been eval'd
Expand Down
4 changes: 4 additions & 0 deletions packages/test-data/css/_main/custom-property.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
--basic-deg: 20deg;
--basic-deg-tan: tan(var(--basic-deg));
}
.test2 {
--some-var: 5px;
prop: min(100% - var(--some-var), 10px);
}
5 changes: 5 additions & 0 deletions packages/test-data/less/_main/custom-property.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@
--basic-deg: 20deg;
--basic-deg-tan: tan(var(--basic-deg));
}

.test2 {
--some-var: 5px;
prop: min(100% - var(--some-var), 10px);
}

0 comments on commit dac5bfd

Please sign in to comment.