tsquery
tsquery copied to clipboard
Duplicate nodes getting added to ancestors array in traverse
When I run the following sample code
const content = `export const ComponentName = () => {}`;
// this is just calling ts.createSourceFile
const ast = parseContents(content, "/test");
traverse(ast, (node, ancestors) => {
const ancestorTypes = ancestors.map((a) => SyntaxKind[a.kind]);
console.log({
node: SyntaxKind[node.kind],
ancestors: ancestorTypes,
});
});
When processing the VariableDeclaration node, I get the following console log
{ node: 'VariableDeclaration', ancestors: [ 'VariableDeclarationList', 'VariableDeclarationList', 'FirstStatement', 'SourceFile', 'SourceFile' ] }
The issue seems to be related to the handling of nodes that have SyntaxList children. I think the issue is this code in traverse in particular
if (node.parent != null) {
ancestors.unshift(node.parent);
}
It seems like SyntaxList's parent isn't being assigned correctly, so that step allows the same node to get added twice. This in turn, makes a query like SourceFile > VariableStatement > VariableDeclarationList > VariableDeclaration impossible, where as, for some reason, VariableDeclarationList > VariableDeclaration does work.
I fixed this locally just by adding a duplicate check to traverse, but I am concerned this might introduce issues else where.
if (node.parent != null && ancestors[0] !== node.parent) {
ancestors.unshift(node.parent);
}
Has a quick look - would you mind checking if changing:
if (node.parent != null) {
ancestors.unshift(node.parent);
}
iterator(node, ancestors);
let children: Array<Node> = [];
to:
iterator(node, ancestors);
let children: Array<Node> = [];
ancestors.unshift(node.parent);
Fixes your issue as well? Seems like if there are multiple children for one node, then it can add the item to ancestors multiple times which doesn't really make sense!
Ah yep, that also fixes it, good call