Reputation: 47
I want to traverse some of the string literals in one traversal and generate the ouput. and the string literals that are not visited in the first traversal should be traversed in the second traversal. the rule that which string literals should be visited in the first traversal and which should be visited in the second traversal is not important. the important note is that I want to traverse unvisited nodes in the second traversal. to know which of the nodes are visited in the first traversal I used a weakset and put the visited nodes in the weakset. and in the second traversal I check the weakset for the existence of the node and if it doesn't exist I change it. but this approach doesn't work. I understand that the when I put some nodes in the weakset and in the second traversal check for the existence of that nodes the result is false (the node exist in the weakset but it says that it doesn't exist). see the below code:
const babel = require('@babel/core');
const code = `
function greet(name) {
return 'Hello ' + name;
}
console.log(greet('tanhauhau'));
`;
var visited_past = new WeakSet();
const output = babel.transformSync(code, {
plugins: [
function myCustomPlugin() {
return {
visitor: {
StringLiteral(path) {
console.log("first traversal :");
console.log(path.node);
visited_past.add(path.node);
},
},
};
},
],
});
const output2 = babel.transformSync(code, {
plugins: [
function myCustomPlugin() {
return {
visitor: {
StringLiteral(path) {
console.log("second traversal :");
console.log(path.node);
console.log(visited_past.has(path.node));
},
},
};
},
],
});
the output is:
first traversal :
Node {
type: 'StringLiteral',
start: 33,
end: 41,
loc: SourceLocation {
start: Position { line: 3, column: 9, index: 33 },
end: Position { line: 3, column: 17, index: 41 },
filename: undefined,
identifierName: undefined
},
extra: { rawValue: 'Hello ', raw: "'Hello '" },
value: 'Hello ',
leadingComments: undefined,
innerComments: undefined,
trailingComments: undefined
}
first traversal :
Node {
type: 'StringLiteral',
start: 70,
end: 81,
loc: SourceLocation {
start: Position { line: 5, column: 18, index: 70 },
end: Position { line: 5, column: 29, index: 81 },
filename: undefined,
identifierName: undefined
},
extra: { rawValue: 'tanhauhau', raw: "'tanhauhau'" },
value: 'tanhauhau',
leadingComments: undefined,
innerComments: undefined,
trailingComments: undefined
}
second traversal :
Node {
type: 'StringLiteral',
start: 33,
end: 41,
loc: SourceLocation {
start: Position { line: 3, column: 9, index: 33 },
end: Position { line: 3, column: 17, index: 41 },
filename: undefined,
identifierName: undefined
},
extra: { rawValue: 'Hello ', raw: "'Hello '" },
value: 'Hello ',
leadingComments: undefined,
innerComments: undefined,
trailingComments: undefined
}
false
second traversal :
Node {
type: 'StringLiteral',
start: 70,
end: 81,
loc: SourceLocation {
start: Position { line: 5, column: 18, index: 70 },
end: Position { line: 5, column: 29, index: 81 },
filename: undefined,
identifierName: undefined
},
extra: { rawValue: 'tanhauhau', raw: "'tanhauhau'" },
value: 'tanhauhau',
leadingComments: undefined,
innerComments: undefined,
trailingComments: undefined
}
false
what should I do?
Upvotes: 1
Views: 251
Reputation: 3241
Depending on your use case, you could do a few things:
If you aren't changing anything in the file, you could just store the path.node.start
of visited nodes and then skip those on the second traversal.
If things could change length, but not order, you could use
path.scope.generateUidIdentifier("uid")
as a key for each node as you visit them.
Otherwise you'll have to get clever with something like following the node parentPath
chain to build a key, or using the text value itself.
Upvotes: 0