Skip to content

Instantly share code, notes, and snippets.

@bebraw bebraw/mixin.css
Created Dec 27, 2011

Embed
What would you like to do?
more.js blog post examples part 2
#header {
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
}
#footer {
border-radius: 10px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
}
#content {
border-radius: 20px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
}
var replaceVariables = function(line, vars) {
for(var k in vars) {
var v = vars[k];
line = line.replace(k, v);
}
return line;
};
var findMixins = function(tree) {
var ret = {};
var parseParams = function(line) {
var ret = {};
var parts;
line = line.trim();
line = line.substr(1, line.length - 2);
parts = line.split(',');
parts.forEach(function(k) {
var segments = k.split(':');
ret[segments[0]] = segments[1];
});
return ret;
};
tree.forEach(function(child) {
if (child.name.search('mixin ') == 0) {
var parts = child.name.split(' ');
var name = parts[1];
var params = parseParams(parts.slice(2).join(''));
ret[child.name.split(' ')[1].trim()] = {
children: child.children,
params: params
};
// mark as deleted so we can avoid this later
child.deleted = true;
}
});
return ret;
};
mixins = findMixins(tree);
var setParams = function(params, values) {
values = values || [];
var ret = {};
var i = 0;
for(var k in params) {
ret[k] = values[i] || params[k];
i++;
};
return ret;
};
var recursion = function(tree, i, vars) {
return tree.map(function(child) {
if (child.deleted) {
return '';
}
var ret = '';
var parts = child.name.split(':');
var begin = parts[0];
if (begin in mixins) {
var values = parts[1] || '';
values = values.trim().split(' ');
var mixin = mixins[begin];
var mixinParams = setParams(mixin.params, values);
ret += recursion(mixin.children, i, mixinParams).join('\n');
return ret;
}
var prefix = chars(' ', i * 4);
var name = replaceVariables(replaceVariables(child.name, vars), variables);
ret = prefix + name;
...
mixin roundedCorners (@radius: 5px)
border-radius: @radius
-webkit-border-radius: @radius
-moz-border-radius: @radius
#header
roundedCorners
#footer
roundedCorners: 10px
@a: 20px
#content
roundedCorners: @a
#!/usr/bin/env node
var fs = require('fs');
var source = process.argv.splice(2)[0];
var target = source.substring(0, source.lastIndexOf('.')) + '.css';
fs.readFile(source, 'utf-8', function(err, data) {
if (err) throw err;
var analyze = function(input) {
return input.map(function(line) {
var rPart = line.trimLeft();
return {l: line.replace(rPart, ''), r: rPart};
});
};
var treeify = function(input) {
var parents = [];
return input.filter(function(elem) {return elem.l || elem.r;}).
map(function(line) {
elem = {name: line.r, children: [], ind: line.l.length};
parent = parents[parents.length - 1] || {ind: 0};
if (parent.ind == elem.ind) {
parents.pop();
parent = parents[parents.length -1] || {ind: 0};
}
elem.parent = parent;
if (elem.ind == 0) {
parents = [elem];
elem.parent = null;
return elem;
}
else if (parent.ind < elem.ind) {
parents.push(elem);
parent.children.push(elem);
}
}).filter(function(elem) {return elem;});
};
var printTree = function(tree, i) {
i = i || 0;
tree.forEach(function(k) {
console.log('depth: ' + i);
console.log('name: ' + k.name);
console.log('parent: ' + k.parent);
printTree(k.children, i + 1);
});
};
var chars = function(c, n) {
var ret = '';
for(var i = 0; i < n; i++) {
ret += c;
}
return ret;
};
var transform = function(tree) {
var variables;
var mixins;
var nested = [];
var findVariables = function(tree) {
var ret = {};
tree.forEach(function(child) {
if (child.name[0] == '@') {
var parts = child.name.split(':');
ret[parts[0]] = parts[1].trim();
}
});
return ret;
};
variables = findVariables(tree);
var replaceVariables = function(line, vars) {
for(var k in vars) {
var v = vars[k];
line = line.replace(k, v);
}
return line;
};
var findMixins = function(tree) {
var ret = {};
var parseParams = function(line) {
var ret = {};
var parts;
line = line.trim();
line = line.substr(1, line.length - 2);
parts = line.split(',');
parts.forEach(function(k) {
var segments = k.split(':');
ret[segments[0]] = segments[1];
});
return ret;
};
tree.forEach(function(child) {
if (child.name.search('mixin ') == 0) {
var parts = child.name.split(' ');
var name = parts[1];
var params = parseParams(parts.slice(2).join(''));
ret[child.name.split(' ')[1].trim()] = {
children: child.children,
params: params
};
// mark as deleted so we can avoid this later
child.deleted = true;
}
});
return ret;
};
mixins = findMixins(tree);
var setParams = function(params, values) {
values = values || [];
var ret = {};
var i = 0;
for(var k in params) {
ret[k] = values[i] || params[k];
i++;
};
return ret;
};
var recursion = function(tree, i, vars) {
return tree.map(function(child) {
if (child.deleted) {
return '';
}
var ret = '';
var parts = child.name.split(':');
var begin = parts[0];
if (begin in mixins) {
var values = parts[1] || '';
values = values.trim().split(' ');
var mixin = mixins[begin];
var mixinParams = setParams(mixin.params, values);
ret += recursion(mixin.children, i, mixinParams).join('\n');
return ret;
}
var prefix = chars(' ', i * 4);
var name = replaceVariables(replaceVariables(child.name, vars), variables);
ret = prefix + name;
if (child.children.length) {
if (child.parent) {
// going to handle these later separately
// we'll lose positional data but it's
// a bit easier this way
// alternatively could try to sort attributes
// within blocks and then render nesting here
nested.push(child);
ret = '';
}
else {
ret += ' {\n' + recursion(child.children, i + 1).join('\n') + '\n}\n';
}
}
else {
ret += ';';
}
return ret;
});
};
var ret = recursion(tree, 0);
var getFullName = function(child) {
return child.parent? getFullName(child.parent) + ' ' + child.name: child.name;
};
if (nested.length) {
nested = nested.map(function(child) {
child.name = getFullName(child);
child.parent = null;
return child;
});
ret.push(transform(nested));
}
return ret.filter(function(o) {return o;});
};
var parts = analyze(data.split('\n'));
var tree = treeify(parts);
var output = transform(tree).join('\n');
console.log(output);
fs.writeFile(target, output, function(err) {
if (err) throw err;
console.log('Wrote ' + target + '!');
});
});
#header {
color: #4D926F;
}
h2 {
color: #4D926F;
}
var transform = function(tree) {
var variables;
var nested = [];
var findVariables = function(tree) {
var ret = {};
tree.forEach(function(child) {
if (child.name[0] == '@') {
var parts = child.name.split(':');
ret[parts[0]] = parts[1].trim();
}
});
return ret;
};
variables = findVariables(tree);
var replaceVariables = function(line) {
for(var k in variables) {
var v = variables[k];
line = line.replace(k, v);
}
return line;
};
var recursion = function(tree, i) {
return tree.map(function(child) {
var prefix = chars(' ', i * 4);
var ret = prefix + replaceVariables(child.name);
...
/* idea borrowed from LESS http://lesscss.org/ */
@color: #4D926F
#header
color: @color
h2
color: @color
@lukewatts

This comment has been minimized.

Copy link

lukewatts commented May 31, 2017

Add the following after the first if (err) throw err in more.js to account for Windows OS \r\n and Mac \r newlines:

data = data.replace(/\r\n|\r/gm, '\n');

Otherwise you end up with this:

div
 {
    color: white
;
    border: 1px solid black
;

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.