convert-ast.js 2.77 KB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertAst = void 0;
const ts = require("typescript");
const util_1 = require("./util");
/**
 * Takes a `ts.SourceFile` and creates data structures that are easier (or more performant) to traverse.
 * Note that there is only a performance gain if you can reuse these structures. It's not recommended for one-time AST walks.
 */
function convertAst(sourceFile) {
    const wrapped = {
        node: sourceFile,
        parent: undefined,
        kind: ts.SyntaxKind.SourceFile,
        children: [],
        next: undefined,
        skip: undefined,
    };
    const flat = [];
    let current = wrapped;
    function collectChildren(node) {
        current.children.push({
            node,
            parent: current,
            kind: node.kind,
            children: [],
            next: undefined,
            skip: undefined,
        });
    }
    const stack = [];
    while (true) {
        if (current.children.length === 0) {
            ts.forEachChild(current.node, collectChildren);
            if (current.children.length === 0) {
                current = current.parent; // nothing to do here, go back to parent
            }
            else {
                // recurse into first child
                const firstChild = current.children[0];
                current.next = firstChild;
                flat.push(firstChild.node);
                if (util_1.isNodeKind(firstChild.kind))
                    current = firstChild;
                stack.push(1); // set index in stack so we know where to continue processing children
            }
        }
        else {
            const index = stack[stack.length - 1];
            if (index < current.children.length) { // handles 2nd child to the last
                const currentChild = current.children[index];
                flat.push(currentChild.node);
                let previous = current.children[index - 1];
                while (previous.children.length !== 0) {
                    previous.skip = currentChild;
                    previous = previous.children[previous.children.length - 1];
                }
                previous.skip = previous.next = currentChild;
                ++stack[stack.length - 1];
                if (util_1.isNodeKind(currentChild.kind))
                    current = currentChild; // recurse into child
            }
            else {
                // done on this node
                if (stack.length === 1)
                    break;
                // remove index from stack and go back to parent
                stack.pop();
                current = current.parent;
            }
        }
    }
    return {
        wrapped,
        flat,
    };
}
exports.convertAst = convertAst;
//# sourceMappingURL=convert-ast.js.map