UNPKG

idyll-ast

Version:
306 lines (269 loc) 7.04 kB
'use strict'; /** * * 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 };