Skip to content

Commit fd7c2a6

Browse files
committed
fix: make comment workarounds opt-in
BREAKING CHANGE: more comments will get deleted unless you opt into the workaround with . I turned this off by default because it crashes in a few cases.
1 parent c4e1fd0 commit fd7c2a6

File tree

6 files changed

+105
-41
lines changed

6 files changed

+105
-41
lines changed

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,56 @@ npx jscodeshift -t asyncify/index.js path/to/your/project/**/*.js
3535
| All but one nested if/else/switch branch return | 🚫 |
3636
| More than one if/else/switch branch doesn't return | 🚫 |
3737
| Return inside loop | 🚫 |
38+
39+
## Warnings
40+
41+
Comments can sometimes get deleted due to an impedance mismatch between `@babel` and `recast`
42+
ASTs. If you use the `--commentWorkarounds=true` option it will try to prevent more comments
43+
from getting deleted but it sometimes causes an assertion to fail in `recast`.
44+
45+
There are a few edge cases where `asyncify` produces funky output. It's intended to not break
46+
any existing behavior but sometimes the output will be be semantically wrong even if it behaves
47+
correctly. For example, I've seen a case where doing an async operation several times in a row:
48+
49+
```js
50+
it('test', () => {
51+
const doSomething = () => {
52+
// ...
53+
}
54+
55+
return doSomething()
56+
.then(doSomething)
57+
.then(doSomething)
58+
}
59+
```
60+
61+
Gets converted to:
62+
63+
```js
64+
it('test', async () => {
65+
const doSomething = () => {
66+
// ...
67+
}
68+
await doSomething(await doSomething(await doSomething()))
69+
})
70+
```
71+
72+
This works even though it initially seems like it wouldn't and is obviously not what you want:
73+
74+
```js
75+
it('test', async () => {
76+
const doSomething = () => {
77+
// ...
78+
}
79+
await doSomething()
80+
await doSomething()
81+
await doSomething()
82+
})
83+
```
84+
85+
Although I could possibly fix this for cases where it's easy to determine that the function has
86+
no parameters, there could be cases where it's impossible to determine whether the identifier
87+
`doSomething` is even a function or whether it has parameters.
88+
89+
At the moment, `.then(someIdentifier)` when `someIdentifier` is not a function is the only known
90+
case where the output behavior is wrong and will likely throw a `TypeError` (#15).

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module.exports = function index(
1515
})
1616

1717
const ignoreChainsShorterThan = parseInt(options.ignoreChainsShorterThan)
18+
const commentWorkarounds = options.commentWorkarounds
1819

1920
let program: NodePath<t.Program> | undefined
2021
traverse(
@@ -26,7 +27,7 @@ module.exports = function index(
2627
},
2728
},
2829
undefined,
29-
{ ignoreChainsShorterThan }
30+
{ ignoreChainsShorterThan, commentWorkarounds }
3031
)
3132
if (!program) throw new Error('failed to find Program node')
3233
asyncify(program)

src/util/recastBugWorkarounds.ts

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,6 @@ import { NodePath } from '@babel/traverse'
44
export default function recastBugWorkarounds(path: NodePath<any>): void {
55
const visitedComments: Set<t.Comment> = new Set()
66
path.traverse({
7-
exit(path: NodePath<t.Node>) {
8-
const { leadingComments } = path.node
9-
const anyNode = path.node as any
10-
if (leadingComments) {
11-
anyNode.comments = []
12-
if (leadingComments) {
13-
for (const comment of leadingComments) {
14-
if (visitedComments.has(comment)) continue
15-
visitedComments.add(comment)
16-
anyNode.comments.push({
17-
...comment,
18-
leading: true,
19-
trailing: false,
20-
})
21-
}
22-
}
23-
} else {
24-
anyNode.comments = null
25-
}
26-
},
277
AwaitExpression(path: NodePath<t.AwaitExpression>) {
288
const argument = path.get('argument')
299
const { parentPath } = path
@@ -35,22 +15,46 @@ export default function recastBugWorkarounds(path: NodePath<any>): void {
3515
}
3616
},
3717
})
38-
path.traverse({
39-
exit(path: NodePath<t.Node>) {
40-
const { trailingComments } = path.node
41-
const anyNode = path.node as any
42-
if (trailingComments) {
43-
if (!anyNode.comments) anyNode.comments = []
44-
for (const comment of trailingComments) {
45-
if (visitedComments.has(comment)) continue
46-
visitedComments.add(comment)
47-
anyNode.comments.push({
48-
...comment,
49-
leading: false,
50-
trailing: true,
51-
})
18+
if (path.state.commentWorkarounds) {
19+
path.traverse({
20+
exit(path: NodePath<t.Node>) {
21+
const { leadingComments } = path.node
22+
const anyNode = path.node as any
23+
if (leadingComments) {
24+
anyNode.comments = []
25+
if (leadingComments) {
26+
for (const comment of leadingComments) {
27+
if (visitedComments.has(comment)) continue
28+
visitedComments.add(comment)
29+
anyNode.comments.push({
30+
...comment,
31+
leading: true,
32+
trailing: false,
33+
})
34+
}
35+
}
36+
} else {
37+
anyNode.comments = null
5238
}
53-
}
54-
},
55-
})
39+
},
40+
})
41+
path.traverse({
42+
exit(path: NodePath<t.Node>) {
43+
const { trailingComments } = path.node
44+
const anyNode = path.node as any
45+
if (trailingComments) {
46+
if (!anyNode.comments) anyNode.comments = []
47+
for (const comment of trailingComments) {
48+
if (visitedComments.has(comment)) continue
49+
visitedComments.add(comment)
50+
anyNode.comments.push({
51+
...comment,
52+
leading: false,
53+
trailing: true,
54+
})
55+
}
56+
}
57+
},
58+
})
59+
}
5660
}

test/fixtures/bugs_BelongsToMany.create.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ class BelongsToMany {
2727
}
2828
`
2929

30-
export const options = {}
30+
export const options = {
31+
commentWorkarounds: true,
32+
}
3133

3234
export const expected = `
3335
class BelongsToMany {

test/fixtures/bugs_Sequelize.transaction.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ class Sequelize {
2727
}
2828
`
2929

30-
export const options = {}
30+
export const options = {
31+
commentWorkarounds: true,
32+
}
3133

3234
export const expected = `
3335
class Sequelize {

test/fixtures/leadingComment.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ function foo() {
99
}
1010
`
1111

12-
export const options = {}
12+
export const options = {
13+
commentWorkarounds: true,
14+
}
1315

1416
export const expected = `
1517
async function foo() {

0 commit comments

Comments
 (0)