Skip to content

Commit

Permalink
Implement named parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesfoster committed Apr 30, 2012
1 parent cb78933 commit 1857b7c
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 8 deletions.
30 changes: 27 additions & 3 deletions lib/less/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -752,22 +752,46 @@ less.Parser = function Parser(env) {
// selector for now.
//
call: function () {
var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
var elements = [], e, c, args = [], arg, index = i, s = input.charAt(i), name, value, important = false;

if (s !== '.' && s !== '#') { return }

while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
elements.push(new(tree.Element)(c, e, i));
c = $('>');
}
$('(') && (args = $(this.entities.arguments)) && $(')');
if ($('(')) {
while (arg = $(this.expression)) {
value = arg;
name = null;

// Variable
if (arg.value.length = 1) {
var val = arg.value[0];
if (val instanceof tree.Variable) {
if ($(':')) {
if (value = $(this.expression)) {
name = val.name;
} else {
throw new(Error)("Expected value");
}
}
}
}

args.push({ name: name, value: value });

if (! $(',')) { break }
}
if (! $(')')) throw new(Error)("Expected )");
}

if ($(this.important)) {
important = true;
}

if (elements.length > 0 && ($(';') || peek('}'))) {
return new(tree.mixin.Call)(elements, args || [], index, env.filename, important);
return new(tree.mixin.Call)(elements, args, index, env.filename, important);
}
},

Expand Down
21 changes: 16 additions & 5 deletions lib/less/tree/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ tree.mixin.Call.prototype = {

for (var i = 0; i < env.frames.length; i++) {
if ((mixins = env.frames[i].find(this.selector)).length > 0) {
args = this.arguments && this.arguments.map(function (a) { return a.eval(env) });
args = this.arguments && this.arguments.map(function (a) {
return { name: a.name, value: a.value.eval(env) };
});
for (var m = 0; m < mixins.length; m++) {
if (mixins[m].match(args, env)) {
try {
Expand Down Expand Up @@ -69,17 +71,26 @@ tree.mixin.Definition.prototype = {
rulesets: function () { return this.parent.rulesets.apply(this) },

evalParams: function (env, args) {
var frame = new(tree.Ruleset)(null, []), varargs;
var frame = new(tree.Ruleset)(null, []), varargs, arg;

for (var i = 0, val, name; i < this.params.length; i++) {
arg = args && args[i]

if (arg && arg.name) {
frame.rules.unshift(new(tree.Rule)(arg.name, arg.value.eval(env)));
args.splice(i, 1);
i--;
continue;
}

if (name = this.params[i].name) {
if (this.params[i].variadic && args) {
varargs = [];
for (var j = i; j < args.length; j++) {
varargs.push(args[j].eval(env));

This comment has been minimized.

Copy link
@jreading

jreading May 11, 2012

Contributor

This needs to be:

varargs.push(args[j].value.eval(env));

This comment has been minimized.

Copy link
@jamesfoster

jamesfoster May 11, 2012

Author Contributor

Hi John.

Thanks for catching this. I wasn't able to run the tests because I didn't have node.js. It would be great if someone could implement the tests using qunit or similar so they run in the browser!

}
frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
} else if (val = (args && args[i]) || this.params[i].value) {
} else if (val = (arg && arg.value) || this.params[i].value) {
frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
} else {
throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
Expand All @@ -93,7 +104,7 @@ tree.mixin.Definition.prototype = {
var frame = this.evalParams(env, args), context, _arguments = [], rules, start;

for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
_arguments.push(args[i] || this.params[i].value);
_arguments.push((args[i] && args[i].value) || this.params[i].value);
}
frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));

Expand Down Expand Up @@ -123,7 +134,7 @@ tree.mixin.Definition.prototype = {

for (var i = 0; i < len; i++) {
if (!this.params[i].name) {
if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
return false;
}
}
Expand Down
20 changes: 20 additions & 0 deletions test/css/mixins-named-args.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.named-arg {
color: blue;
width: 5px;
height: 99%;
text-align: center;
}
.class {
width: 5px;
height: 19%;
}
.named-args2 {
width: 15px;
height: 49%;
color: #646464;
}
.named-args3 {
width: 5px;
height: 29%;
color: #123456;
}
31 changes: 31 additions & 0 deletions test/less/mixins-named-args.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.mixin (@a: 1px, @b: 50%) {
width: @a * 5;
height: @b - 1%;
}
.mixin (@a: 1px, @b: 50%) when (@b > 75%){
text-align: center;
}

.named-arg {
color: blue;
.mixin(@b: 100%);
}

.class {
@var: 20%;
.mixin(@b: @var);
}

.mixin2 (@a: 1px, @b: 50%, @c: 50) {
width: @a * 5;
height: @b - 1%;
color: #000000 + @c;
}

.named-args2 {
.mixin2(3px, @c: 100);
}

.named-args3 {
.mixin2(@b: 30%, @c: #123456);
}

2 comments on commit 1857b7c

@matthew-dean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Named parameters? Hooray!

@jreading
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks the mixins-args test. Fix pending

Please sign in to comment.