@vxrn/compiler 1.25.16 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cache.cjs +4 -2
- package/dist/cjs/configure.cjs +9 -1
- package/dist/cjs/index.cjs +87 -5
- package/dist/cjs/reactNativeCodegen.cjs +140 -0
- package/dist/cjs/reactNativeViewConfig.cjs +489 -0
- package/dist/cjs/transformBabel.cjs +15 -20
- package/dist/cjs/transformBabel.test.cjs +260 -0
- package/dist/cjs/transformHermesAsync.cjs +61 -0
- package/dist/cjs/transformHermesLoops.cjs +319 -0
- package/dist/cjs/transformHermesLoops.test.cjs +257 -0
- package/dist/cjs/transformSWC.cjs +110 -138
- package/dist/cjs/transformSWC.test.cjs +117 -0
- package/dist/cjs/transformWorklets.cjs +123 -0
- package/dist/cjs/transformWorklets.test.cjs +604 -0
- package/dist/cjs/worklets/autoworklet.cjs +265 -0
- package/dist/cjs/worklets/globals.cjs +73 -0
- package/dist/cjs/worklets/hash.cjs +38 -0
- package/dist/cjs/worklets/scope.cjs +370 -0
- package/dist/cjs/worklets/serialize.cjs +101 -0
- package/dist/cjs/worklets/transform.cjs +266 -0
- package/dist/cjs/worklets/types.cjs +18 -0
- package/dist/esm/cache.mjs +5 -3
- package/dist/esm/cache.mjs.map +1 -1
- package/dist/esm/configure.mjs +8 -1
- package/dist/esm/configure.mjs.map +1 -1
- package/dist/esm/index.js +75 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +75 -6
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/reactNativeCodegen.mjs +104 -0
- package/dist/esm/reactNativeCodegen.mjs.map +1 -0
- package/dist/esm/reactNativeViewConfig.mjs +460 -0
- package/dist/esm/reactNativeViewConfig.mjs.map +1 -0
- package/dist/esm/transformBabel.mjs +14 -19
- package/dist/esm/transformBabel.mjs.map +1 -1
- package/dist/esm/transformBabel.test.mjs +261 -1
- package/dist/esm/transformBabel.test.mjs.map +1 -1
- package/dist/esm/transformHermesAsync.mjs +25 -0
- package/dist/esm/transformHermesAsync.mjs.map +1 -0
- package/dist/esm/transformHermesLoops.mjs +283 -0
- package/dist/esm/transformHermesLoops.mjs.map +1 -0
- package/dist/esm/transformHermesLoops.test.mjs +234 -0
- package/dist/esm/transformHermesLoops.test.mjs.map +1 -0
- package/dist/esm/transformSWC.mjs +96 -139
- package/dist/esm/transformSWC.mjs.map +1 -1
- package/dist/esm/transformSWC.test.mjs +118 -0
- package/dist/esm/transformSWC.test.mjs.map +1 -0
- package/dist/esm/transformWorklets.mjs +82 -0
- package/dist/esm/transformWorklets.mjs.map +1 -0
- package/dist/esm/transformWorklets.test.mjs +581 -0
- package/dist/esm/transformWorklets.test.mjs.map +1 -0
- package/dist/esm/worklets/autoworklet.mjs +234 -0
- package/dist/esm/worklets/autoworklet.mjs.map +1 -0
- package/dist/esm/worklets/globals.mjs +46 -0
- package/dist/esm/worklets/globals.mjs.map +1 -0
- package/dist/esm/worklets/hash.mjs +13 -0
- package/dist/esm/worklets/hash.mjs.map +1 -0
- package/dist/esm/worklets/scope.mjs +345 -0
- package/dist/esm/worklets/scope.mjs.map +1 -0
- package/dist/esm/worklets/serialize.mjs +75 -0
- package/dist/esm/worklets/serialize.mjs.map +1 -0
- package/dist/esm/worklets/transform.mjs +229 -0
- package/dist/esm/worklets/transform.mjs.map +1 -0
- package/dist/esm/worklets/types.mjs +2 -0
- package/dist/esm/worklets/types.mjs.map +1 -0
- package/package.json +11 -6
- package/src/cache.ts +10 -3
- package/src/configure.ts +12 -0
- package/src/index.ts +96 -13
- package/src/reactNativeCodegen.ts +181 -0
- package/src/reactNativeViewConfig.ts +593 -0
- package/src/transformBabel.test.ts +268 -1
- package/src/transformBabel.ts +21 -31
- package/src/transformHermesAsync.ts +30 -0
- package/src/transformHermesLoops.test.ts +341 -0
- package/src/transformHermesLoops.ts +435 -0
- package/src/transformSWC.test.ts +132 -0
- package/src/transformSWC.ts +121 -161
- package/src/transformWorklets.test.ts +708 -0
- package/src/transformWorklets.ts +160 -0
- package/src/types.ts +4 -4
- package/src/worklets/autoworklet.ts +391 -0
- package/src/worklets/globals.ts +129 -0
- package/src/worklets/hash.ts +14 -0
- package/src/worklets/scope.ts +401 -0
- package/src/worklets/serialize.ts +114 -0
- package/src/worklets/transform.ts +319 -0
- package/src/worklets/types.ts +26 -0
- package/types/cache.d.ts +1 -0
- package/types/cache.d.ts.map +1 -1
- package/types/configure.d.ts +2 -0
- package/types/configure.d.ts.map +1 -1
- package/types/index.d.ts +6 -0
- package/types/index.d.ts.map +1 -1
- package/types/reactNativeCodegen.d.ts +5 -0
- package/types/reactNativeCodegen.d.ts.map +1 -0
- package/types/reactNativeViewConfig.d.ts +35 -0
- package/types/reactNativeViewConfig.d.ts.map +1 -0
- package/types/transformBabel.d.ts +3 -3
- package/types/transformBabel.d.ts.map +1 -1
- package/types/transformHermesAsync.d.ts +5 -0
- package/types/transformHermesAsync.d.ts.map +1 -0
- package/types/transformHermesLoops.d.ts +5 -0
- package/types/transformHermesLoops.d.ts.map +1 -0
- package/types/transformHermesLoops.test.d.ts +2 -0
- package/types/transformHermesLoops.test.d.ts.map +1 -0
- package/types/transformSWC.d.ts +13 -3
- package/types/transformSWC.d.ts.map +1 -1
- package/types/transformSWC.test.d.ts +2 -0
- package/types/transformSWC.test.d.ts.map +1 -0
- package/types/transformWorklets.d.ts +23 -0
- package/types/transformWorklets.d.ts.map +1 -0
- package/types/transformWorklets.test.d.ts +2 -0
- package/types/transformWorklets.test.d.ts.map +1 -0
- package/types/types.d.ts +4 -4
- package/types/types.d.ts.map +1 -1
- package/types/worklets/autoworklet.d.ts +14 -0
- package/types/worklets/autoworklet.d.ts.map +1 -0
- package/types/worklets/globals.d.ts +4 -0
- package/types/worklets/globals.d.ts.map +1 -0
- package/types/worklets/hash.d.ts +5 -0
- package/types/worklets/hash.d.ts.map +1 -0
- package/types/worklets/scope.d.ts +7 -0
- package/types/worklets/scope.d.ts.map +1 -0
- package/types/worklets/serialize.d.ts +12 -0
- package/types/worklets/serialize.d.ts.map +1 -0
- package/types/worklets/transform.d.ts +10 -0
- package/types/worklets/transform.d.ts.map +1 -0
- package/types/worklets/types.d.ts +21 -0
- package/types/worklets/types.d.ts.map +1 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import * as vm from 'node:vm'
|
|
3
|
+
import { transformHermesLoops } from './transformHermesLoops'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hermes emits one CreateFunctionEnvironment before a loop rather than one per
|
|
7
|
+
* iteration, and that environment covers the loop's head AND everything its
|
|
8
|
+
* body declares, so every lexical binding under a loop behaves there exactly
|
|
9
|
+
* like `var`. Rewriting them all that way reproduces Hermes on a spec-correct
|
|
10
|
+
* runtime, which is what makes these assertions meaningful: every one of them
|
|
11
|
+
* returns the wrong answer against the untransformed source.
|
|
12
|
+
*
|
|
13
|
+
* Verified against `hermesc -dump-bytecode`, which emits a single
|
|
14
|
+
* CreateFunctionEnvironment before the loop and a StoreToEnvironment into the
|
|
15
|
+
* same slot on each iteration.
|
|
16
|
+
*/
|
|
17
|
+
function runAsHermes(code: string) {
|
|
18
|
+
const asHermesWouldSeeIt = code.replace(/\b(?:let|const)\b/g, 'var')
|
|
19
|
+
const sandbox: any = { result: undefined, console }
|
|
20
|
+
vm.runInNewContext(asHermesWouldSeeIt, sandbox)
|
|
21
|
+
return sandbox.result
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function run(source: string) {
|
|
25
|
+
const out = transformHermesLoops(source, 'test.js')
|
|
26
|
+
return runAsHermes(out ? out.code : source)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('transformHermesLoops', () => {
|
|
30
|
+
it.each([
|
|
31
|
+
['if (false)', []],
|
|
32
|
+
['if (true)', [1, 2]],
|
|
33
|
+
['for (var pass = 0; pass < 2; pass++)', [1, 2, 1, 2]],
|
|
34
|
+
['while (passes++ < 2)', [1, 2, 1, 2]],
|
|
35
|
+
])('keeps a captured loop inside a single-statement %s body', (parent, expected) => {
|
|
36
|
+
expect(
|
|
37
|
+
run(`
|
|
38
|
+
var fns = []
|
|
39
|
+
var passes = 0
|
|
40
|
+
${parent} for (const n of [1, 2]) fns.push(() => n)
|
|
41
|
+
result = fns.map((f) => f())
|
|
42
|
+
`)
|
|
43
|
+
).toEqual(expected)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it.each([true, false])(
|
|
47
|
+
'preserves if/else selection when the condition is %s',
|
|
48
|
+
(condition) => {
|
|
49
|
+
expect(
|
|
50
|
+
run(`
|
|
51
|
+
var fns = []
|
|
52
|
+
if (${condition}) for (const n of [1, 2]) fns.push(() => n)
|
|
53
|
+
else for (const n of [3, 4]) fns.push(() => n)
|
|
54
|
+
result = fns.map((f) => f())
|
|
55
|
+
`)
|
|
56
|
+
).toEqual(condition ? [1, 2] : [3, 4])
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
it('preserves a do/while with a single-statement loop body', () => {
|
|
61
|
+
expect(
|
|
62
|
+
run(`
|
|
63
|
+
var fns = []
|
|
64
|
+
var passes = 0
|
|
65
|
+
do for (const n of [1, 2]) fns.push(() => n)
|
|
66
|
+
while (passes++ < 1)
|
|
67
|
+
result = fns.map((f) => f())
|
|
68
|
+
`)
|
|
69
|
+
).toEqual([1, 2, 1, 2])
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('guards optional Zero query patches through nested loop transforms', () => {
|
|
73
|
+
expect(
|
|
74
|
+
run(`
|
|
75
|
+
var fns = []
|
|
76
|
+
var parts = [{}, { desiredQueriesPatches: { a: ['x', 'y'], b: ['z'] } }]
|
|
77
|
+
for (const part of parts) {
|
|
78
|
+
if (part.desiredQueriesPatches)
|
|
79
|
+
for (const [clientID, queriesPatch] of Object.entries(part.desiredQueriesPatches))
|
|
80
|
+
for (const op of queriesPatch) fns.push(() => clientID + ':' + op)
|
|
81
|
+
}
|
|
82
|
+
result = fns.map((f) => f())
|
|
83
|
+
`)
|
|
84
|
+
).toEqual(['a:x', 'a:y', 'b:z'])
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('gives a C-style loop a per-iteration binding', () => {
|
|
88
|
+
expect(
|
|
89
|
+
run(`
|
|
90
|
+
var fns = []
|
|
91
|
+
for (let i = 0; i < 3; i++) fns.push(() => i)
|
|
92
|
+
result = fns.map((f) => f())
|
|
93
|
+
`)
|
|
94
|
+
).toEqual([0, 1, 2])
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('gives for-of and for-in per-iteration bindings', () => {
|
|
98
|
+
expect(
|
|
99
|
+
run(`
|
|
100
|
+
var fns = []
|
|
101
|
+
for (const label of ['a', 'b']) fns.push(() => label)
|
|
102
|
+
for (const key in { x: 1, y: 2 }) fns.push(() => key)
|
|
103
|
+
result = fns.map((f) => f())
|
|
104
|
+
`)
|
|
105
|
+
).toEqual(['a', 'b', 'x', 'y'])
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('preserves break', () => {
|
|
109
|
+
expect(
|
|
110
|
+
run(`
|
|
111
|
+
var fns = []
|
|
112
|
+
for (let i = 0; i < 10; i++) {
|
|
113
|
+
if (i === 3) break
|
|
114
|
+
fns.push(() => i)
|
|
115
|
+
}
|
|
116
|
+
result = fns.map((f) => f())
|
|
117
|
+
`)
|
|
118
|
+
).toEqual([0, 1, 2])
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('preserves continue', () => {
|
|
122
|
+
expect(
|
|
123
|
+
run(`
|
|
124
|
+
var fns = []
|
|
125
|
+
for (let i = 0; i < 5; i++) {
|
|
126
|
+
if (i % 2 === 0) continue
|
|
127
|
+
fns.push(() => i)
|
|
128
|
+
}
|
|
129
|
+
result = fns.map((f) => f())
|
|
130
|
+
`)
|
|
131
|
+
).toEqual([1, 3])
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('preserves return out of the enclosing function', () => {
|
|
135
|
+
expect(
|
|
136
|
+
run(`
|
|
137
|
+
function find() {
|
|
138
|
+
for (const n of [1, 2, 3]) {
|
|
139
|
+
const get = () => n
|
|
140
|
+
if (n === 2) return get()
|
|
141
|
+
}
|
|
142
|
+
return 'none'
|
|
143
|
+
}
|
|
144
|
+
result = find()
|
|
145
|
+
`)
|
|
146
|
+
).toBe(2)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('preserves a bare return', () => {
|
|
150
|
+
expect(
|
|
151
|
+
run(`
|
|
152
|
+
var fns = []
|
|
153
|
+
function go() {
|
|
154
|
+
for (let i = 0; i < 5; i++) {
|
|
155
|
+
if (i === 2) return
|
|
156
|
+
fns.push(() => i)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
go()
|
|
160
|
+
result = fns.map((f) => f())
|
|
161
|
+
`)
|
|
162
|
+
).toEqual([0, 1])
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('leaves break and continue belonging to a nested loop alone', () => {
|
|
166
|
+
expect(
|
|
167
|
+
run(`
|
|
168
|
+
var fns = []
|
|
169
|
+
for (let i = 0; i < 2; i++) {
|
|
170
|
+
for (var j = 0; j < 5; j++) {
|
|
171
|
+
if (j > 0) break
|
|
172
|
+
}
|
|
173
|
+
fns.push(() => i)
|
|
174
|
+
}
|
|
175
|
+
result = fns.map((f) => f())
|
|
176
|
+
`)
|
|
177
|
+
).toEqual([0, 1])
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('handles nested capturing loops', () => {
|
|
181
|
+
expect(
|
|
182
|
+
run(`
|
|
183
|
+
var fns = []
|
|
184
|
+
for (let i = 0; i < 2; i++) {
|
|
185
|
+
for (let j = 0; j < 2; j++) {
|
|
186
|
+
fns.push(() => i + ':' + j)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
result = fns.map((f) => f())
|
|
190
|
+
`)
|
|
191
|
+
).toEqual(['0:0', '0:1', '1:0', '1:1'])
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('handles await in the loop body', async () => {
|
|
195
|
+
const out = transformHermesLoops(
|
|
196
|
+
`
|
|
197
|
+
var fns = []
|
|
198
|
+
async function go() {
|
|
199
|
+
for (const n of [1, 2]) {
|
|
200
|
+
await Promise.resolve()
|
|
201
|
+
fns.push(() => n)
|
|
202
|
+
}
|
|
203
|
+
return fns.map((f) => f())
|
|
204
|
+
}
|
|
205
|
+
result = go()
|
|
206
|
+
`,
|
|
207
|
+
'test.js'
|
|
208
|
+
)
|
|
209
|
+
expect(out).not.toBeNull()
|
|
210
|
+
await expect(runAsHermes(out!.code)).resolves.toEqual([1, 2])
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('destructures a for-of binding per iteration', () => {
|
|
214
|
+
expect(
|
|
215
|
+
run(`
|
|
216
|
+
var fns = []
|
|
217
|
+
for (const { id } of [{ id: 'a' }, { id: 'b' }]) fns.push(() => id)
|
|
218
|
+
result = fns.map((f) => f())
|
|
219
|
+
`)
|
|
220
|
+
).toEqual(['a', 'b'])
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
it('rewrites the esbuild interop helper that broke every multi-export module', () => {
|
|
224
|
+
// this exact shape is what esbuild inlines into every commonjs-interop
|
|
225
|
+
// module, and under Hermes it made each named export resolve to the last one
|
|
226
|
+
expect(
|
|
227
|
+
run(`
|
|
228
|
+
var __defProp = Object.defineProperty
|
|
229
|
+
var __getOwnPropNames = Object.getOwnPropertyNames
|
|
230
|
+
var from = { a: 1, b: 2 }
|
|
231
|
+
var to = {}
|
|
232
|
+
for (let key of __getOwnPropNames(from)) {
|
|
233
|
+
__defProp(to, key, { get: () => from[key], enumerable: true })
|
|
234
|
+
}
|
|
235
|
+
result = [to.a, to.b]
|
|
236
|
+
`)
|
|
237
|
+
).toEqual([1, 2])
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('leaves loops that never capture their binding untouched', () => {
|
|
241
|
+
expect(
|
|
242
|
+
transformHermesLoops('for (let i = 0; i < 3; i++) sum += i', 'test.js')
|
|
243
|
+
).toBeNull()
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('gives a binding declared in the loop body a per-iteration copy', () => {
|
|
247
|
+
// react-native's NativeAnimatedHelper builds one wrapper per method this
|
|
248
|
+
// way; sharing `methodName` made every wrapper resolve the last method.
|
|
249
|
+
expect(
|
|
250
|
+
run(`
|
|
251
|
+
var names = ['createAnimatedNode', 'addListener', 'removeListener']
|
|
252
|
+
var wrappers = {}
|
|
253
|
+
for (var ii = 0; ii < names.length; ii++) {
|
|
254
|
+
const methodName = names[ii]
|
|
255
|
+
wrappers[methodName] = () => methodName
|
|
256
|
+
}
|
|
257
|
+
result = names.map((n) => wrappers[n]())
|
|
258
|
+
`)
|
|
259
|
+
).toEqual(['createAnimatedNode', 'addListener', 'removeListener'])
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('gives a binding declared in a nested block of the loop body a per-iteration copy', () => {
|
|
263
|
+
expect(
|
|
264
|
+
run(`
|
|
265
|
+
var fns = []
|
|
266
|
+
for (var i = 0; i < 3; i++) {
|
|
267
|
+
if (i >= 0) {
|
|
268
|
+
const doubled = i * 2
|
|
269
|
+
fns.push(() => doubled)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
result = fns.map((f) => f())
|
|
273
|
+
`)
|
|
274
|
+
).toEqual([0, 2, 4])
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('keeps `this` and `arguments` meaning what they meant outside the loop', () => {
|
|
278
|
+
// reanimated's PropsFilter reads `this._map` from a closure inside a
|
|
279
|
+
// `for (const key in props)` body, so a lifted body that rebound `this`
|
|
280
|
+
// crashed every animated component.
|
|
281
|
+
expect(
|
|
282
|
+
run(`
|
|
283
|
+
class PropsFilter {
|
|
284
|
+
constructor() { this._map = { a: 'A', b: 'B' } }
|
|
285
|
+
filter(props) {
|
|
286
|
+
var out = []
|
|
287
|
+
for (const key in props) {
|
|
288
|
+
const label = key
|
|
289
|
+
out.push(() => this._map[label] + arguments.length)
|
|
290
|
+
}
|
|
291
|
+
return out
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
result = new PropsFilter().filter({ a: 1, b: 2 }).map((f) => f())
|
|
295
|
+
`)
|
|
296
|
+
).toEqual(['A1', 'B1'])
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it('leaves a loop with no lexical binding untouched', () => {
|
|
300
|
+
expect(
|
|
301
|
+
transformHermesLoops('for (var i = 0; i < 3; i++) fns.push(() => i)', 'test.js')
|
|
302
|
+
).toBeNull()
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('leaves the head declaration alone so it cannot collide with a sibling', () => {
|
|
306
|
+
// react-native-gesture-handler's Pressable declares `const gesture` in the
|
|
307
|
+
// same block as `for (const gesture of gestures)`. hoisting the head to
|
|
308
|
+
// `var` made that a redeclaration and failed the whole bundle to parse.
|
|
309
|
+
const out = transformHermesLoops(
|
|
310
|
+
`function build(gestures) {
|
|
311
|
+
var handlers = []
|
|
312
|
+
for (const gesture of gestures) { handlers.push(() => gesture) }
|
|
313
|
+
const gesture = gestures[0]
|
|
314
|
+
return gesture
|
|
315
|
+
}`,
|
|
316
|
+
'Pressable.js'
|
|
317
|
+
)
|
|
318
|
+
// a redeclaration is a SyntaxError, so compiling is the whole assertion
|
|
319
|
+
expect(() => new vm.Script(out!.code)).not.toThrow()
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
it('rewrites a loop in a .js file that still contains jsx', () => {
|
|
323
|
+
// react-native and its dependencies ship jsx inside plain `.js`, and the
|
|
324
|
+
// rolldown native pipeline keeps jsx unlowered until after this transform.
|
|
325
|
+
const out = transformHermesLoops(
|
|
326
|
+
'for (const c of items) rows.push(() => <Row key={c} />)',
|
|
327
|
+
'Rows.js'
|
|
328
|
+
)
|
|
329
|
+
expect(out?.code).toContain('_hermesLoop0')
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
it('does not rewrite a loop that reassigns its own binding', () => {
|
|
333
|
+
// the update would be stranded inside the lifted function
|
|
334
|
+
expect(
|
|
335
|
+
transformHermesLoops(
|
|
336
|
+
'for (let i = 0; i < 3; i++) { i += 1; fns.push(() => i) }',
|
|
337
|
+
'test.js'
|
|
338
|
+
)
|
|
339
|
+
).toBeNull()
|
|
340
|
+
})
|
|
341
|
+
})
|