Skip to content

Commit da6b0bd

Browse files
authored
Merge pull request #4 from bendtherules/return-multiple-nodes
Add section "return multiple nodes"
2 parents 0233b49 + d11d0d4 commit da6b0bd

File tree

5 files changed

+93
-2
lines changed

5 files changed

+93
-2
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
let a = 1;
2+
{
3+
const a = 'abcd';
4+
}
5+
a = 2;
6+
console.log(a);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
let a = 1;
2+
{
3+
const a = 'abcd';
4+
}
5+
a = 2;
6+
a = 2;
7+
console.log(a);
8+
console.log(a);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as ts from 'typescript';
2+
3+
const transformer: ts.TransformerFactory<ts.SourceFile> = context => {
4+
return sourceFile => {
5+
const visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
6+
// If it is a expression statement,
7+
if (ts.isExpressionStatement(node)) {
8+
// Return it twice.
9+
// Effectively duplicating the statement
10+
return [node, node];
11+
}
12+
13+
return ts.visitEachChild(node, visitor, context);
14+
};
15+
16+
return ts.visitNode(sourceFile, visitor);
17+
};
18+
};
19+
20+
export default transformer;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "transformed",
5+
"plugins": [{ "transform": "./transformer.ts", "type": "raw" }]
6+
},
7+
"files": ["source.ts"]
8+
}

translations/en/transformer-handbook.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,11 +1086,60 @@ if (ts.isFunctionDeclaration(node)) {
10861086
10871087
#### Replacing a node with multiple nodes
10881088

1089-
> **TODO** - Is this possible?
1089+
Interestingly, a visitor function can also return a array of nodes instead of just one node.
1090+
That means, even though it gets one node as input, it can return multiple nodes which replaces that input node.
1091+
1092+
```ts
1093+
export type Visitor = (node: Node) => VisitResult<Node>;
1094+
export type VisitResult<T extends Node> = T | T[] | undefined;
1095+
```
1096+
1097+
Let's just replace every expression statement with two copies of the same statement (duplicating it) -
1098+
1099+
```ts
1100+
const transformer: ts.TransformerFactory<ts.SourceFile> = context => {
1101+
return sourceFile => {
1102+
const visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
1103+
// If it is a expression statement,
1104+
if (ts.isExpressionStatement(node)) {
1105+
// Return it twice.
1106+
// Effectively duplicating the statement
1107+
return [node, node];
1108+
}
1109+
1110+
return ts.visitEachChild(node, visitor, context);
1111+
};
1112+
1113+
return ts.visitNode(sourceFile, visitor);
1114+
};
1115+
};
1116+
```
1117+
So,
1118+
1119+
```ts
1120+
let a = 1;
1121+
a = 2;
1122+
```
1123+
1124+
becomes
1125+
1126+
```js
1127+
let a = 1;
1128+
a = 2;
1129+
a = 2;
1130+
```
1131+
> **Tip** - You can see the source for this at [/example-transformers/return-multiple-node](/example-transformers/return-multiple-node)
1132+
1133+
The declaration statement (first line) is ignored as it's not a `ExpressionStatement`.
1134+
1135+
*Note* - Make sure that what you are trying to do actually makes sense in the AST. For ex., returning two expressions instead of one is often just invalid.
1136+
1137+
Say there is a assignment expression (BinaryExpression with with EqualToken operator), `a = b = 2`. Now returning two nodes instead of `b = 2` expression is invalid (because right hand side can not be multiple nodes). So, TS will throw an error - `Debug Failure. False expression: Too many nodes written to output.`
1138+
10901139

10911140
#### Inserting a sibling node
10921141

1093-
> **TODO** - Is this possible?
1142+
This is effectively same as the [previous section](#replacing-a-node-with-multiple-nodes). Just return a array of nodes including itself and other sibling nodes.
10941143

10951144
#### Removing a node
10961145

0 commit comments

Comments
 (0)