idyll-ast
Version:
Utilities for manipulating Idyll's AST
306 lines (269 loc) • 7.04 kB
JavaScript
;
/**
*
* module contains utility functions
* for dealing with Idyll's internal representation
* of an AST. The ast object is an array of nodes,
* where each node is defined like:
*
* [ name, [
* [property1, [valueType, value ]],
* [property2, [valueType, value ]]
* ], [
* child1,
* child2,
* ...
* ] ]
*
*/
var appendNode = function appendNode(ast, node) {
return appendNodes(ast, [node]);
};
var appendNodes = function appendNodes(ast, nodes) {
return [].concat(ast, nodes);
};
/**
* function that returns the names of the passed node
* @param {*} node
* @return {String} name of the node
*/
var getNodeName = function getNodeName(node) {
return node[0];
};
var createNode = function createNode(name, props, children) {
var node = [name, [], children || []];
node = setProperties(node, props || {});
return node;
};
/**
* Creates a textnode with the text passed
* @param {*} text the text inside a textnode
*/
var createTextNode = function createTextNode(text) {
if (typeof text === 'string') {
return text;
}
};
var getChildren = function getChildren(node) {
if (typeof node === 'string') {
return [];
}
if (typeof node[2] === 'string') {
return [node[2]];
}
return node[2] || [];
};
var getText = function getText(node) {
var texts = [];
walkNodes(node, function (n) {
if (typeof n === 'string') {
texts.push(n);
}
});
return texts.join(' ');
};
var walkNodes = function walkNodes(ast, f) {
(ast || []).forEach(function (node) {
walkNodes(getChildren(node), f);
f(node);
});
};
/**
* function to do a depth first traversal on the ast tree.
* @param {*} ast Array that forms the tree structure
* @param {*} f call-back function
*/
var walkNodesBreadthFirst = function walkNodesBreadthFirst(ast, f) {
var childAst = [];
(ast || []).forEach(function (node) {
f(node);
childAst = childAst.concat(getChildren(node));
});
if (childAst.length !== 0) {
walkNodesBreadthFirst(childAst, f);
}
};
var findNodes = function findNodes(ast, filter) {
var result = [];
walkNodes(ast, function (node) {
if (filter(node)) result.push(node);
});
return result;
};
var modifyChildren = function modifyChildren(node, modifier) {
if (typeof node === 'string') {
return node;
}
node[2] = getChildren(node).map(function (child) {
return modifier(child);
});
return node;
};
// TODO: wrap string in array so that the reduce doesn't err
var getNodesByName = function getNodesByName(ast, name) {
var handleNode = function handleNode(acc, node) {
if (node[0].toLowerCase() === name.toLowerCase()) {
acc.push(node);
}
var children = getChildren(node);
if (!children || typeof children === 'string') {
return acc;
}
return children.reduce(handleNode, acc);
};
// if (typeof ast === 'string') {
// ast = [ast];
// }
return ast.reduce(handleNode, []);
};
var filterChildren = function filterChildren(node, filter) {
if (typeof node === 'string') {
return node;
}
node[2] = getChildren(node).filter(function (child) {
return filter(child);
});
return node;
};
var filterNodes = function filterNodes(ast, filter) {
return ast.filter(filter).map(function (node) {
if (typeof node === 'string') {
return node;
}
node[2] = filterNodes(node[2] || [], filter);
return node;
});
};
var modifyNodesByName = function modifyNodesByName(ast, name, modifier) {
var handleNode = function handleNode(node) {
if (typeof node === 'string') {
return node;
}
if (node[0].toLowerCase() === name.toLowerCase()) {
node = modifier(node);
}
node = modifyChildren(node, handleNode);
return node;
};
ast = ast.map(function (node) {
return handleNode(node);
});
return ast;
};
var getProperty = function getProperty(node, key) {
if (typeof node === 'string') {
return null;
}
var retProp = void 0;
node[1].forEach(function (element) {
if (element[0] === key) {
retProp = element[1];
}
});
return retProp;
};
var getProperties = function getProperties(node) {
if (typeof node === 'string') {
return [];
}
return node[1] || [];
};
var getPropertiesByType = function getPropertiesByType(node, type) {
if (typeof node === 'string') {
return [];
}
return (node[1] || []).filter(function (_ref) {
var propName = _ref[0],
_ref$ = _ref[1],
propType = _ref$[0],
propValue = _ref$[1];
return propType === type;
});
};
var prependNode = function prependNode(ast, node) {
return prependNodes(ast, [node]);
};
var prependNodes = function prependNodes(ast, nodes) {
return [].concat(nodes, ast);
};
var removeNodesByName = function removeNodesByName(ast, name) {
return filterNodes(ast, function (node) {
if (typeof node === 'string') {
return true;
}
if (node[0].toLowerCase() === name.toLowerCase()) {
return false;
}
return true;
});
};
var setProperty = function setProperty(node, key, value) {
if (typeof node === 'string') {
console.warn('Cannot setPropery on string node.');
return node;
}
var hasSet = false;
var isArr = Array.isArray(value);
node[1] = node[1].map(function (element) {
if (element[0] === key) {
hasSet = true;
return [element[0], isArr ? value : ['value', value]];
}
return element;
});
if (!hasSet) {
node[1] = node[1].concat([[key, isArr ? value : ['value', value]]]);
}
return node;
};
var setProperties = function setProperties(node, properties) {
if (typeof node === 'string') {
console.warn('Cannot setProperties of string node.');
return node;
}
Object.keys(properties).forEach(function (key) {
node = setProperty(node, key, properties[key]);
});
return node;
};
var removeProperty = function removeProperty(node, key) {
if (typeof node === 'string') {
console.warn('Cannot removePropery of string node.');
return node;
}
node[1] = node[1].filter(function (_ref2) {
var propName = _ref2[0],
propVal = _ref2[1];
if (propName === key) {
return false;
}
return true;
});
return node;
};
module.exports = {
appendNode: appendNode,
appendNodes: appendNodes,
createNode: createNode,
createTextNode: createTextNode,
walkNodesBreadthFirst: walkNodesBreadthFirst,
getChildren: getChildren,
getNodesByName: getNodesByName,
filterChildren: filterChildren,
filterNodes: filterNodes,
modifyChildren: modifyChildren,
modifyNodesByName: modifyNodesByName,
getNodeName: getNodeName,
getProperty: getProperty,
getProperties: getProperties,
getPropertiesByType: getPropertiesByType,
getText: getText,
prependNode: prependNode,
prependNodes: prependNodes,
removeNodesByName: removeNodesByName,
setProperties: setProperties,
setProperty: setProperty,
removeProperty: removeProperty,
walkNodes: walkNodes,
findNodes: findNodes
};