mirror of
https://github.com/less/less.js.git
synced 2026-02-05 20:44:58 -05:00
146 lines
3.9 KiB
JavaScript
146 lines
3.9 KiB
JavaScript
(function (tree) {
|
|
|
|
var _visitArgs = { visitDeeper: true },
|
|
_hasIndexed = false;
|
|
|
|
function _noop(node) {
|
|
return node;
|
|
}
|
|
|
|
function indexNodeTypes(parent, ticker) {
|
|
// add .typeIndex to tree node types for lookup table
|
|
var key, child;
|
|
for (key in parent) {
|
|
child = parent[key];
|
|
switch (typeof child) {
|
|
case "function":
|
|
if (child.prototype.type) {
|
|
child.prototype.typeIndex = ticker++;
|
|
}
|
|
break;
|
|
case "object":
|
|
ticker = indexNodeTypes(child, ticker);
|
|
break;
|
|
}
|
|
}
|
|
return ticker;
|
|
}
|
|
|
|
tree.visitor = function(implementation) {
|
|
this._implementation = implementation;
|
|
this._visitFnCache = [];
|
|
|
|
if (!_hasIndexed) {
|
|
indexNodeTypes(tree, 1);
|
|
_hasIndexed = true;
|
|
}
|
|
};
|
|
|
|
tree.visitor.prototype = {
|
|
visit: function(node) {
|
|
|
|
if (!node) {
|
|
return node;
|
|
}
|
|
|
|
if (node.splice) {
|
|
return this.visitArray(node);
|
|
}
|
|
|
|
var nodeTypeIndex = node.typeIndex;
|
|
if (!nodeTypeIndex) {
|
|
return node;
|
|
}
|
|
|
|
var visitFnCache = this._visitFnCache,
|
|
impl = this._implementation,
|
|
aryIndx = nodeTypeIndex << 1,
|
|
func = visitFnCache[aryIndx],
|
|
funcOut = visitFnCache[aryIndx | 1],
|
|
visitArgs = _visitArgs, noop = _noop,
|
|
fnName;
|
|
|
|
visitArgs.visitDeeper = true;
|
|
|
|
if (!func) {
|
|
fnName = "visit" + node.type;
|
|
func = impl[fnName] || noop;
|
|
funcOut = impl[fnName + "Out"] || noop;
|
|
visitFnCache[aryIndx] = func;
|
|
visitFnCache[aryIndx | 1] = funcOut;
|
|
}
|
|
|
|
if (func != noop) {
|
|
var newNode = func.call(impl, node, visitArgs);
|
|
if (impl.isReplacing) {
|
|
node = newNode;
|
|
}
|
|
}
|
|
|
|
if (visitArgs.visitDeeper && node && node.accept) {
|
|
node.accept(this);
|
|
}
|
|
|
|
if (funcOut != noop) {
|
|
funcOut.call(impl, node);
|
|
}
|
|
|
|
return node;
|
|
},
|
|
visitArray: function(nodes) {
|
|
if (!nodes) {
|
|
return nodes;
|
|
}
|
|
|
|
var cnt = nodes.length, i;
|
|
|
|
// Non-replacing
|
|
if (!this._implementation.isReplacing) {
|
|
for (i = 0; i < cnt; i++) {
|
|
this.visit(nodes[i]);
|
|
}
|
|
return nodes;
|
|
}
|
|
|
|
// Replacing
|
|
var out = [];
|
|
for (i = 0; i < cnt; i++) {
|
|
var evald = this.visit(nodes[i]);
|
|
if (evald.splice) {
|
|
this.flatten(evald, out);
|
|
} else {
|
|
out.push(evald);
|
|
}
|
|
}
|
|
return out;
|
|
},
|
|
flatten: function(arr, out) {
|
|
if (!out)
|
|
out = [];
|
|
|
|
var cnt = arr.length, i, item,
|
|
nestedCnt, j, nestedItem;
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
item = arr[i];
|
|
if (!item.splice) {
|
|
out.push(item);
|
|
continue;
|
|
}
|
|
|
|
nestedCnt = item.length;
|
|
for (j = 0; j < nestedCnt; j++) {
|
|
nestedItem = item[j];
|
|
if (!nestedItem.splice) {
|
|
out.push(nestedItem);
|
|
} else {
|
|
this.flatten(nestedItem, out);
|
|
}
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
};
|
|
|
|
})(require('./tree')); |