Skip to content

Commit

Permalink
Fixes less#3205, partial 3.0 math regression less#1880
Browse files Browse the repository at this point in the history
  • Loading branch information
matthew-dean committed Jun 24, 2018
1 parent 66cd402 commit 983fa99
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 77 deletions.
4 changes: 4 additions & 0 deletions lib/less/parser/parser-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ module.exports = function() {
return input.charAt(parserInput.i);
};

parserInput.prevChar = function() {
return input.charAt(parserInput.i - 1);
};

parserInput.getInput = function() {
return input;
};
Expand Down
105 changes: 68 additions & 37 deletions lib/less/parser/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ var Parser = function Parser(context, imports, fileInfo) {

// Custom property values get permissive parsing
if (name[0].value && name[0].value.slice(0, 2) === '--') {
value = this.permissiveValue(';');
value = this.permissiveValue();
}
// Try to store values as anonymous
// If we need the value later we'll re-parse it in ruleset.parseValue
Expand All @@ -1309,13 +1309,12 @@ var Parser = function Parser(context, imports, fileInfo) {
if (!value) {
value = this.value();
}

important = this.important();

// As a last resort, let a variable try to be parsed as a permissive value
// As a last resort, try permissiveValue
if (!value && isVariable) {
value = this.permissiveValue(';');
value = this.permissiveValue();
}

important = this.important();
}

if (value && this.end()) {
Expand All @@ -1337,13 +1336,31 @@ var Parser = function Parser(context, imports, fileInfo) {
}
},
/**
* Used for custom properties and custom at-rules
* Used for custom properties, at-rules, and variables (as fallback)
* Parses almost anything inside of {} [] () "" blocks
* until it reaches outer-most tokens.
*
* First, it will try to parse comments and entities to reach
* the end. This is mostly like the Expression parser except no
* math is allowed.
*/
permissiveValue: function (untilTokens) {
var i, e, index = parserInput.i, value = [];

var i, e, done, value,
tok = untilTokens || ';',
index = parserInput.i, result = [];

function testCurrentChar() {
var char = parserInput.currentChar();
if (typeof tok === 'string') {
return char === tok;
} else {
return tok.test(char);
}
}
if (testCurrentChar()) {
return;
}
value = [];
do {
e = this.comment();
if (e) {
Expand All @@ -1356,41 +1373,55 @@ var Parser = function Parser(context, imports, fileInfo) {
}
} while (e);

done = testCurrentChar();

if (value.length > 0) {
return new(tree.Expression)(value);
value = new(tree.Expression)(value);
if (done) {
return value;
}
else {
result.push(value);
}
// Preserve space before $parseUntil as it will not
if (parserInput.prevChar() === ' ') {
result.push(new tree.Anonymous(' ', index));
}
}
else {
value = parserInput.$parseUntil(untilTokens);
parserInput.save();

value = parserInput.$parseUntil(tok);

if (value) {
if (typeof value === 'string') {
error("Expected '" + value + "'", "Parse");
}
if (value.length === 1 && value[0] === ' ') {
return new tree.Anonymous('', index);
if (value) {
if (typeof value === 'string') {
error("Expected '" + value + "'", "Parse");
}
if (value.length === 1 && value[0] === ' ') {
parserInput.forget();
return new tree.Anonymous('', index);
}
var item;
for (i = 0; i < value.length; i++) {
item = value[i];
if (Array.isArray(item)) {
// Treat actual quotes as normal quoted values
result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo));
}
var item, args = [];
for (i = 0; i < value.length; i++) {
item = value[i];
if (Array.isArray(item)) {
// Treat actual quotes as normal quoted values
args.push(new tree.Quoted(item[0], item[1], true, index, fileInfo));
}
else {
if (i === value.length - 1) {
item = item.trim();
}
// Treat like quoted values, but replace vars like unquoted expressions
var quote = new tree.Quoted("'", item, true, index, fileInfo);
quote.variableRegex = /@([\w-]+)/g;
quote.propRegex = /\$([\w-]+)/g;
quote.reparse = true;
args.push(quote);
else {
if (i === value.length - 1) {
item = item.trim();
}
// Treat like quoted values, but replace vars like unquoted expressions
var quote = new tree.Quoted("'", item, true, index, fileInfo);
quote.variableRegex = /@([\w-]+)/g;
quote.propRegex = /\$([\w-]+)/g;
result.push(quote);
}
return new tree.Expression(args, true);
}
parserInput.forget();
return new tree.Expression(result, true);
}
parserInput.restore();
},

//
Expand Down Expand Up @@ -1472,7 +1503,7 @@ var Parser = function Parser(context, imports, fileInfo) {
nodes.push(e);
} else if (parserInput.$char('(')) {
p = this.property();
e = this.value();
e = this.permissiveValue(')');
if (parserInput.$char(')')) {
if (p && e) {
nodes.push(new(tree.Paren)(new(tree.Declaration)(p, e, null, null, parserInput.i, fileInfo, true)));
Expand Down
3 changes: 3 additions & 0 deletions lib/less/tree/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Expression.prototype.eval = function (context) {
}
if (this.value.length > 1) {
returnValue = new Expression(this.value.map(function (e) {
if (!e.eval) {
return e;
}
return e.eval(context);
}), this.noSpacing);
} else if (this.value.length === 1) {
Expand Down
7 changes: 3 additions & 4 deletions test/css/permissive-parse.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
basically anything until final semi-colon;
even other stuff; // i\'m serious;
};
--custom-color: #ff3333;
custom-color: #ff3333;
--custom-color: #ff3333 #ff3333;
custom-color: #ff3333 #ff3333;
}
.var {
--fortran: read (*, *, iostat=1) radius, height;
Expand All @@ -30,7 +30,6 @@
}
}
.test-comment {
--value: ;
--value: a /* { ; } */;
--comment-within: ( /* okay?; comment; */ );
--empty: ;
}
4 changes: 2 additions & 2 deletions test/css/plugin-preeval.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.foo {
prop: val;
:root.two .one {
--foo: bar !important;
}
7 changes: 3 additions & 4 deletions test/less/errors/at-rules-unmatching-block.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
SyntaxError: @unknown rule is missing block or ending semi-colon in {path}at-rules-unmatching-block.less on line 2, column 10:
1
2 @unknown url( {
3 50% {width: 20px;}
SyntaxError: expected ')' got '' in {path}at-rules-unmatching-block.less on line 5, column 1:
4 }
5
2 changes: 1 addition & 1 deletion test/less/media.less
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@ratio_large: 16;
@ratio_small: 9;

@media all and (device-aspect-ratio: ~"@{ratio_large} / @{ratio_small}") {
@media all and (device-aspect-ratio: @ratio_large / @ratio_small) {
body { max-width: 800px; }
}

Expand Down
5 changes: 2 additions & 3 deletions test/less/permissive-parse.less
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
};
--that: @this;
@red: lighten(red, 10%);
--custom-color: @red;
--custom-color: @red lighten(red, 10%);
custom-color: $--custom-color;
}

Expand Down Expand Up @@ -45,7 +45,6 @@
}
// @todo - fix comment absorption after property
.test-comment {
--value: /* { ; } */;
--value: a/* { ; } */;
--comment-within: ( /* okay?; comment; */ );
--empty: ;
}
2 changes: 1 addition & 1 deletion test/less/plugin-preeval.less
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

.one {
.two({
--foo: foo;
--foo: @replace !important;
});
}

Expand Down
26 changes: 1 addition & 25 deletions test/less/plugin/plugin-preeval.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = {
install({ tree: { Quoted }, visitors }, manager) {
global.TRACK = false
class Visitor {
constructor() {
this.native = new visitors.Visitor(this);
Expand All @@ -13,31 +12,8 @@ module.exports = {
return this.native.visit(root);
}

visitDeclaration(node) {
if (node.name === '@stop') {
global.TRACK = false;
}
console.log(node.name, node.value.type);
return node;
}

visitRuleset(node) {
if (global.TRACK) {
// console.log(node.rules[0]);
}
return node;
}

visitMixinCall(node) {
console.log('mixin call'); // , node.arguments[0].value.ruleset.rules[0].value.value[0]
global.TRACK = true;
return node;
}

visitVariable(node) {
// console.log(node.name);
if (node.name === '@foo') {
console.log('visited var');
if (node.name === '@replace') {
return new Quoted(`'`, 'bar', true);
}
return node;
Expand Down

0 comments on commit 983fa99

Please sign in to comment.