@vxrn/compiler 2.13.4 → 2.13.6

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.
@@ -0,0 +1,238 @@
1
+ import type { WorkletClassCandidate } from './types'
2
+
3
+ export const WORKLET_CLASS_MARKER = '__workletClass'
4
+ export const WORKLET_CLASS_FACTORY_SUFFIX = '__classFactory'
5
+
6
+ const MARKER_FIELD_TYPES = new Set([
7
+ 'PropertyDefinition',
8
+ 'AccessorProperty',
9
+ 'TSAbstractPropertyDefinition',
10
+ ])
11
+
12
+ function isMarkerField(element: any): boolean {
13
+ return (
14
+ MARKER_FIELD_TYPES.has(element?.type) &&
15
+ !element.computed &&
16
+ element.key?.type === 'Identifier' &&
17
+ element.key.name === WORKLET_CLASS_MARKER
18
+ )
19
+ }
20
+
21
+ export function findWorkletClasses(program: any): WorkletClassCandidate[] {
22
+ const candidates: WorkletClassCandidate[] = []
23
+
24
+ function walk(node: any, parent: any) {
25
+ if (!node || typeof node !== 'object') return
26
+
27
+ if (
28
+ node.type === 'ClassDeclaration' &&
29
+ node.id?.type === 'Identifier' &&
30
+ !node.declare &&
31
+ // class-level decorators sit outside the class range upstream's factory
32
+ // shape can carry, so decorated classes keep today's raw capture.
33
+ !(node.decorators?.length > 0)
34
+ ) {
35
+ const marker = node.body?.body?.find(isMarkerField)
36
+ if (marker) {
37
+ candidates.push({ node, name: node.id.name, parent, marker })
38
+ }
39
+ }
40
+
41
+ for (const key of Object.keys(node)) {
42
+ if (key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue
43
+ const child = node[key]
44
+ if (Array.isArray(child)) {
45
+ for (const item of child) walk(item, node)
46
+ } else if (child && typeof child === 'object') {
47
+ walk(child, node)
48
+ }
49
+ }
50
+ }
51
+
52
+ walk(program, null)
53
+ // a marked class nested inside another marked class shares one rewrite
54
+ // range with it, so only the outermost of an overlap is rewritten.
55
+ return candidates.filter(
56
+ (candidate) =>
57
+ !candidates.some(
58
+ (other) =>
59
+ other !== candidate &&
60
+ other.node.start <= candidate.node.start &&
61
+ other.node.end >= candidate.node.end
62
+ )
63
+ )
64
+ }
65
+
66
+ export function classFactoryName(className: string): string {
67
+ return `${className}${WORKLET_CLASS_FACTORY_SUFFIX}`
68
+ }
69
+
70
+ function collectPatternNames(pattern: any, count: (name: string) => void) {
71
+ if (!pattern || typeof pattern !== 'object') return
72
+ switch (pattern.type) {
73
+ case 'Identifier':
74
+ count(pattern.name)
75
+ return
76
+ case 'AssignmentPattern':
77
+ collectPatternNames(pattern.left, count)
78
+ return
79
+ case 'RestElement':
80
+ collectPatternNames(pattern.argument, count)
81
+ return
82
+ case 'ArrayPattern':
83
+ for (const element of pattern.elements ?? []) collectPatternNames(element, count)
84
+ return
85
+ case 'ObjectPattern':
86
+ for (const property of pattern.properties ?? []) {
87
+ if (property?.type === 'Property') collectPatternNames(property.value, count)
88
+ else if (property?.type === 'RestElement')
89
+ collectPatternNames(property.argument, count)
90
+ }
91
+ return
92
+ case 'TSParameterProperty':
93
+ collectPatternNames(pattern.parameter, count)
94
+ return
95
+ }
96
+ }
97
+
98
+ /**
99
+ * marked class names that are the sole value binding of that name in the file.
100
+ * every free reference to one necessarily resolves to the marked class, so a
101
+ * worklet capturing it (a superclass, a static access, an instanceof) carries
102
+ * the factory instead of the raw class. any other binding of the same name
103
+ * keeps the previous capture, since the reference may resolve to that one.
104
+ */
105
+ export function findUnambiguousClassNames(
106
+ program: any,
107
+ candidates: WorkletClassCandidate[]
108
+ ): Set<string> {
109
+ const wanted = new Set(candidates.map((candidate) => candidate.name))
110
+ const counts = new Map<string, number>()
111
+ const count = (name: string) => {
112
+ if (wanted.has(name)) counts.set(name, (counts.get(name) ?? 0) + 1)
113
+ }
114
+
115
+ function walk(node: any) {
116
+ if (!node || typeof node !== 'object') return
117
+ if (Array.isArray(node)) {
118
+ for (const item of node) walk(item)
119
+ return
120
+ }
121
+ switch (node.type) {
122
+ case 'VariableDeclarator':
123
+ collectPatternNames(node.id, count)
124
+ break
125
+ case 'FunctionDeclaration':
126
+ case 'FunctionExpression':
127
+ if (node.id?.type === 'Identifier') count(node.id.name)
128
+ for (const param of node.params ?? []) collectPatternNames(param, count)
129
+ break
130
+ case 'ArrowFunctionExpression':
131
+ for (const param of node.params ?? []) collectPatternNames(param, count)
132
+ break
133
+ case 'ClassDeclaration':
134
+ case 'ClassExpression':
135
+ if (node.id?.type === 'Identifier') count(node.id.name)
136
+ break
137
+ case 'CatchClause':
138
+ collectPatternNames(node.param, count)
139
+ break
140
+ case 'ImportSpecifier':
141
+ case 'ImportDefaultSpecifier':
142
+ case 'ImportNamespaceSpecifier':
143
+ if (node.local?.type === 'Identifier') count(node.local.name)
144
+ break
145
+ case 'TSEnumDeclaration':
146
+ case 'TSModuleDeclaration':
147
+ if (node.id?.type === 'Identifier') count(node.id.name)
148
+ break
149
+ }
150
+ for (const key of Object.keys(node)) {
151
+ if (key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue
152
+ walk(node[key])
153
+ }
154
+ }
155
+
156
+ walk(program)
157
+ return new Set(
158
+ candidates.filter((candidate) => counts.get(candidate.name) === 1).map((c) => c.name)
159
+ )
160
+ }
161
+
162
+ const ABSTRACT_MEMBER_TYPES = new Set([
163
+ 'TSAbstractMethodDefinition',
164
+ 'TSAbstractPropertyDefinition',
165
+ ])
166
+
167
+ export function buildClassFactoryDeclaration(
168
+ candidate: WorkletClassCandidate,
169
+ code: string
170
+ ): string {
171
+ const { node, name, marker } = candidate
172
+ const factory = classFactoryName(name)
173
+
174
+ // the marker plus any bodiless abstract member, which only compiles inside
175
+ // an abstract class declaration and a factory holds a class expression.
176
+ const removals: Array<[number, number]> = [
177
+ [marker.decorators?.[0]?.start ?? marker.start, marker.end],
178
+ ]
179
+ for (const element of node.body?.body ?? []) {
180
+ if (ABSTRACT_MEMBER_TYPES.has(element?.type)) {
181
+ removals.push([element.start, element.end])
182
+ }
183
+ }
184
+ removals.sort((a, b) => a[0] - b[0])
185
+ let classSrc = ''
186
+ let cursor = node.start
187
+ for (const [start, end] of removals) {
188
+ if (start < cursor) continue
189
+ classSrc += code.slice(cursor, start)
190
+ cursor = end
191
+ }
192
+ classSrc += code.slice(cursor, node.end)
193
+ const classExpr = classSrc.replace(/^abstract\s+/, '')
194
+
195
+ return [
196
+ `function ${factory}() {`,
197
+ `'worklet';`,
198
+ `const ${name} = ${classExpr};`,
199
+ `${name}.${factory} = ${factory};`,
200
+ `return ${name};`,
201
+ `}`,
202
+ ].join('\n')
203
+ }
204
+
205
+ /**
206
+ * names constructed with `new Name()` anywhere under the worklet, in traversal
207
+ * order. like upstream's plugin, callers rewrite one whose name is also a
208
+ * captured variable to its class factory, without checking where the class
209
+ * was defined, so imported worklet classes resolve through their own file.
210
+ */
211
+ export function findConstructedNames(fnNode: any): string[] {
212
+ const names: string[] = []
213
+ const seen = new Set<string>()
214
+
215
+ function walk(node: any) {
216
+ if (!node || typeof node !== 'object') return
217
+ if (Array.isArray(node)) {
218
+ for (const item of node) walk(item)
219
+ return
220
+ }
221
+ if (
222
+ node.type === 'NewExpression' &&
223
+ node.callee?.type === 'Identifier' &&
224
+ !seen.has(node.callee.name)
225
+ ) {
226
+ seen.add(node.callee.name)
227
+ names.push(node.callee.name)
228
+ }
229
+ for (const key of Object.keys(node)) {
230
+ if (key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue
231
+ walk(node[key])
232
+ }
233
+ }
234
+
235
+ walk(fnNode.body)
236
+ for (const param of fnNode.params ?? []) walk(param)
237
+ return names
238
+ }
@@ -296,6 +296,9 @@ export function getClosureVariables(fnNode: any, globals: Set<string>): string[]
296
296
  if (node.id && node.id.name) {
297
297
  currentScope.bindings.add(node.id.name)
298
298
  }
299
+ if (node.decorators) {
300
+ for (const decorator of node.decorators) walk(decorator)
301
+ }
299
302
  if (node.superClass) walk(node.superClass)
300
303
  pushScope(false)
301
304
  walk(node.body)
@@ -319,14 +322,37 @@ export function getClosureVariables(fnNode: any, globals: Set<string>): string[]
319
322
  return
320
323
  }
321
324
 
322
- case 'MethodDefinition': {
325
+ case 'MethodDefinition':
326
+ case 'TSAbstractMethodDefinition': {
323
327
  if (node.computed) {
324
328
  walk(node.key)
325
329
  }
330
+ if (node.decorators) {
331
+ for (const decorator of node.decorators) walk(decorator)
332
+ }
326
333
  walk(node.value)
327
334
  return
328
335
  }
329
336
 
337
+ case 'PropertyDefinition':
338
+ case 'AccessorProperty':
339
+ case 'TSAbstractPropertyDefinition': {
340
+ // a plain field name is not a value reference. without this case the
341
+ // default traversal captures every field name as a closure variable.
342
+ if (node.computed) {
343
+ walk(node.key)
344
+ }
345
+ if (node.decorators) {
346
+ for (const decorator of node.decorators) walk(decorator)
347
+ }
348
+ if (node.value) walk(node.value)
349
+ return
350
+ }
351
+
352
+ case 'TSIndexSignature': {
353
+ return
354
+ }
355
+
330
356
  case 'Identifier': {
331
357
  resolveIdentifier(node.name)
332
358
  return
@@ -24,6 +24,11 @@ function assertTransformed(
24
24
  }
25
25
  }
26
26
 
27
+ export type ClassReconstruction = {
28
+ name: string
29
+ factory: string
30
+ }
31
+
27
32
  /**
28
33
  * serializes a worklet function into a string for the hermes ui thread (__initData.code).
29
34
  * includes injected unpacker: `const [var1, var2] = this.__closure;`
@@ -33,7 +38,8 @@ export function serializeWorkletForUI(
33
38
  fnNode: any,
34
39
  code: string,
35
40
  name: string | undefined,
36
- closureVars: string[]
41
+ closureVars: string[],
42
+ reconstructions: ClassReconstruction[] = []
37
43
  ): string {
38
44
  let rawParams = ''
39
45
  if (fnNode.params && fnNode.params.length > 0) {
@@ -53,12 +59,18 @@ export function serializeWorkletForUI(
53
59
 
54
60
  const unpacker =
55
61
  closureVars.length > 0 ? `const [${closureVars.join(', ')}] = this.__closure;\n` : ''
62
+ const rebuilt =
63
+ reconstructions.length > 0
64
+ ? reconstructions
65
+ .map(({ name, factory }) => `const ${name} = ${factory}();\n`)
66
+ .join('')
67
+ : ''
56
68
 
57
69
  const asyncPrefix = fnNode.async ? 'async ' : ''
58
70
  const genPrefix = fnNode.generator ? '*' : ''
59
71
  const fnName = name || '_worklet'
60
72
 
61
- const fullFn = `${asyncPrefix}function${genPrefix} ${fnName}(${rawParams}) {\n${unpacker}${rawBody}\n}`
73
+ const fullFn = `${asyncPrefix}function${genPrefix} ${fnName}(${rawParams}) {\n${unpacker}${rebuilt}${rawBody}\n}`
62
74
 
63
75
  const transformed = transformSync('worklet.ts', fullFn)
64
76
  assertTransformed(transformed, name, 'serialized')
@@ -7,10 +7,21 @@ import {
7
7
  findWorkletCandidates,
8
8
  hasDirective,
9
9
  } from './autoworklet'
10
+ import {
11
+ buildClassFactoryDeclaration,
12
+ classFactoryName,
13
+ findConstructedNames,
14
+ findUnambiguousClassNames,
15
+ findWorkletClasses,
16
+ } from './classes'
10
17
  import { createGlobalsSet } from './globals'
11
18
  import { calculateWorkletHash } from './hash'
12
19
  import { getClosureVariables } from './scope'
13
- import { buildLocalFunction, serializeWorkletForUI } from './serialize'
20
+ import {
21
+ buildLocalFunction,
22
+ serializeWorkletForUI,
23
+ type ClassReconstruction,
24
+ } from './serialize'
14
25
  import type { TransformWorkletsOptions } from './types'
15
26
 
16
27
  const FUNCTION_TYPES = new Set([
@@ -124,7 +135,17 @@ export function executeWorkletTransform(
124
135
  }
125
136
 
126
137
  const initialCandidates = findWorkletCandidates(initialParse.program)
127
- if (initialCandidates.length === 0) {
138
+ // upstream's plugin skips class work under either flag, and this port has
139
+ // no bundle-mode support, so both leave classes and their captures raw.
140
+ const workletClassesEnabled = !options?.disableWorkletClasses && !options?.bundleMode
141
+ const initialClasses = workletClassesEnabled
142
+ ? findWorkletClasses(initialParse.program)
143
+ : []
144
+ const resolvableClassNames =
145
+ initialClasses.length > 0
146
+ ? findUnambiguousClassNames(initialParse.program, initialClasses)
147
+ : new Set<string>()
148
+ if (initialCandidates.length === 0 && initialClasses.length === 0) {
128
149
  let map: any = undefined
129
150
  if (sourceMaps) {
130
151
  const ms = new MagicString(code)
@@ -154,6 +175,48 @@ export function executeWorkletTransform(
154
175
  const initDataDefs = new Map<string, string>()
155
176
  const passMaps: any[] = []
156
177
 
178
+ // marked classes become serializable factories before the worklet passes, so
179
+ // the factories themselves are workletized like any other candidate and a
180
+ // worklet capturing the class reconstructs it from the factory on the ui
181
+ // thread instead of capturing the raw class.
182
+ if (initialClasses.length > 0) {
183
+ const ms = new MagicString(currentCode)
184
+ for (const candidate of initialClasses) {
185
+ const factoryDecl = buildClassFactoryDeclaration(candidate, currentCode)
186
+ const rebound = `const ${candidate.name} = ${classFactoryName(candidate.name)}();`
187
+ if (candidate.parent?.type === 'ExportNamedDeclaration') {
188
+ ms.overwrite(
189
+ candidate.parent.start,
190
+ candidate.parent.end,
191
+ `${factoryDecl}\nexport ${rebound}`
192
+ )
193
+ } else if (candidate.parent?.type === 'ExportDefaultDeclaration') {
194
+ ms.overwrite(
195
+ candidate.parent.start,
196
+ candidate.parent.end,
197
+ `${factoryDecl}\n${rebound}\nexport default ${candidate.name};`
198
+ )
199
+ } else {
200
+ ms.overwrite(
201
+ candidate.node.start,
202
+ candidate.node.end,
203
+ `${factoryDecl}\n${rebound}`
204
+ )
205
+ }
206
+ }
207
+ if (sourceMaps) {
208
+ passMaps.push(
209
+ ms.generateMap({
210
+ source: cleanId,
211
+ file: cleanId,
212
+ hires: true,
213
+ includeContent: true,
214
+ })
215
+ )
216
+ }
217
+ currentCode = ms.toString()
218
+ }
219
+
157
220
  // 3. Iterative bottom-up transformation
158
221
  // In each pass, we transform all innermost candidates (candidates that contain NO other candidates in their body).
159
222
  // All innermost candidates are disjoint, so they can be rewritten simultaneously in a single MagicString.
@@ -202,16 +265,42 @@ export function executeWorkletTransform(
202
265
  // `no-worklet-closure` says the worklet captures nothing, so it gets no
203
266
  // unpacker line and an empty `__closure`. it is what lets the worklets
204
267
  // runtime evaluate the serialized code with no closure to bind.
205
- const closureVars = hasDirective(candidate.fnNode, 'no-worklet-closure')
268
+ let closureVars = hasDirective(candidate.fnNode, 'no-worklet-closure')
206
269
  ? []
207
270
  : getClosureVariables(candidate.fnNode, globals)
271
+ // a capture that is known to be a worklet class travels as its
272
+ // factory and is rebuilt from it on the ui thread, so a factory
273
+ // closing over its superclass stays serializable. anything else that
274
+ // is constructed resolves through its own file like upstream.
275
+ const reconstructions: ClassReconstruction[] = []
276
+ if (workletClassesEnabled && closureVars.length > 0) {
277
+ const captured = new Set(closureVars)
278
+ const rewriteToFactory = (name: string) => {
279
+ if (!captured.has(name)) return
280
+ const factory = classFactoryName(name)
281
+ captured.delete(name)
282
+ captured.add(factory)
283
+ if (!reconstructions.some((r) => r.factory === factory)) {
284
+ reconstructions.push({ name, factory })
285
+ }
286
+ }
287
+ const knownCaptures = [...captured].filter((name) =>
288
+ resolvableClassNames.has(name)
289
+ )
290
+ for (const name of knownCaptures) rewriteToFactory(name)
291
+ for (const constructed of findConstructedNames(candidate.fnNode)) {
292
+ rewriteToFactory(constructed)
293
+ }
294
+ closureVars = [...captured].sort()
295
+ }
208
296
  const fnName = candidate.name
209
297
 
210
298
  const serializedCode = serializeWorkletForUI(
211
299
  candidate.fnNode,
212
300
  currentCode,
213
301
  fnName,
214
- closureVars
302
+ closureVars,
303
+ reconstructions
215
304
  )
216
305
  const workletHash = calculateWorkletHash(serializedCode)
217
306
  const initDataVar = `_worklet_${workletHash}_init_data`
@@ -242,7 +331,12 @@ export function executeWorkletTransform(
242
331
  const localFnCode = buildLocalFunction(candidate.fnNode, currentCode, fnName)
243
332
  const localName = fnName || '_worklet'
244
333
  // worklets 0.13 captures values in the same order the ui function unpacks them.
245
- const closureValues = closureVars.join(', ')
334
+ // a class factory travels as a member of its class, which the defining
335
+ // file attached when it built the factory.
336
+ const factoryOwners = new Map(reconstructions.map((r) => [r.factory, r.name]))
337
+ const closureValues = closureVars
338
+ .map((v) => (factoryOwners.has(v) ? `${factoryOwners.get(v)}.${v}` : v))
339
+ .join(', ')
246
340
 
247
341
  const iife = `(function () {
248
342
  var _e = [new (typeof global !== 'undefined' ? global : globalThis).Error(), 1, -27];
@@ -24,3 +24,10 @@ export interface WorkletCandidate {
24
24
  parent?: any
25
25
  isAutoWorklet: boolean
26
26
  }
27
+
28
+ export interface WorkletClassCandidate {
29
+ node: any
30
+ name: string
31
+ parent?: any
32
+ marker: any
33
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"transformWorklets.d.ts","sourceRoot":"","sources":["../src/transformWorklets.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,sCAAsC,UAiBlD,CAAA;AAiCD,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,WAWjF;AAED,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA8DlF;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAOD,OAAO,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAEtE,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,UAAU,UAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CAqBtC"}
1
+ {"version":3,"file":"transformWorklets.d.ts","sourceRoot":"","sources":["../src/transformWorklets.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,sCAAsC,UAqBlD,CAAA;AAiCD,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,WAWjF;AAED,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA8DlF;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAOD,OAAO,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAEtE,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,UAAU,UAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CAqBtC"}
@@ -0,0 +1,22 @@
1
+ import type { WorkletClassCandidate } from './types';
2
+ export declare const WORKLET_CLASS_MARKER = "__workletClass";
3
+ export declare const WORKLET_CLASS_FACTORY_SUFFIX = "__classFactory";
4
+ export declare function findWorkletClasses(program: any): WorkletClassCandidate[];
5
+ export declare function classFactoryName(className: string): string;
6
+ /**
7
+ * marked class names that are the sole value binding of that name in the file.
8
+ * every free reference to one necessarily resolves to the marked class, so a
9
+ * worklet capturing it (a superclass, a static access, an instanceof) carries
10
+ * the factory instead of the raw class. any other binding of the same name
11
+ * keeps the previous capture, since the reference may resolve to that one.
12
+ */
13
+ export declare function findUnambiguousClassNames(program: any, candidates: WorkletClassCandidate[]): Set<string>;
14
+ export declare function buildClassFactoryDeclaration(candidate: WorkletClassCandidate, code: string): string;
15
+ /**
16
+ * names constructed with `new Name()` anywhere under the worklet, in traversal
17
+ * order. like upstream's plugin, callers rewrite one whose name is also a
18
+ * captured variable to its class factory, without checking where the class
19
+ * was defined, so imported worklet classes resolve through their own file.
20
+ */
21
+ export declare function findConstructedNames(fnNode: any): string[];
22
+ //# sourceMappingURL=classes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classes.d.ts","sourceRoot":"","sources":["../../src/worklets/classes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEpD,eAAO,MAAM,oBAAoB,mBAAmB,CAAA;AACpD,eAAO,MAAM,4BAA4B,mBAAmB,CAAA;AAiB5D,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,GAAG,GAAG,qBAAqB,EAAE,CA2CxE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AA8BD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,GAAG,EACZ,UAAU,EAAE,qBAAqB,EAAE,GAClC,GAAG,CAAC,MAAM,CAAC,CAoDb;AAOD,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE,MAAM,GACX,MAAM,CAiCR;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE,CA2B1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/worklets/scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAoY/E"}
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/worklets/scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CA8Z/E"}
@@ -1,9 +1,13 @@
1
+ export type ClassReconstruction = {
2
+ name: string;
3
+ factory: string;
4
+ };
1
5
  /**
2
6
  * serializes a worklet function into a string for the hermes ui thread (__initData.code).
3
7
  * includes injected unpacker: `const [var1, var2] = this.__closure;`
4
8
  * strips typescript types and formats via oxc-transform.
5
9
  */
6
- export declare function serializeWorkletForUI(fnNode: any, code: string, name: string | undefined, closureVars: string[]): string;
10
+ export declare function serializeWorkletForUI(fnNode: any, code: string, name: string | undefined, closureVars: string[], reconstructions?: ClassReconstruction[]): string;
7
11
  /**
8
12
  * Builds the local JavaScript function to run on the JS thread inside the worklet IIFE.
9
13
  * Strips TypeScript types and the 'worklet' directive.
@@ -1 +1 @@
1
- {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/worklets/serialize.ts"],"names":[],"mappings":"AA0BA;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,WAAW,EAAE,MAAM,EAAE,GACpB,MAAM,CA6BR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,MAAM,CAqCR"}
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/worklets/serialize.ts"],"names":[],"mappings":"AA0BA,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,WAAW,EAAE,MAAM,EAAE,EACrB,eAAe,GAAE,mBAAmB,EAAO,GAC1C,MAAM,CAmCR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,MAAM,CAqCR"}
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/worklets/transform.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAQvD,wBAAgB,+BAA+B,CAC7C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,UAAU,UAAQ,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,CAAA;CAAE,GAAG,IAAI,CAiCpC;AAsCD,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,UAAU,UAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,EAClC,gBAAgB,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GACrE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,CAAA;CAAE,CAoP7B"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/worklets/transform.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAQvD,wBAAgB,+BAA+B,CAC7C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,UAAU,UAAQ,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,CAAA;CAAE,GAAG,IAAI,CAiCpC;AAsCD,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,UAAU,UAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,EAClC,gBAAgB,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GACrE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,GAAG,CAAA;CAAE,CAuU7B"}
@@ -18,4 +18,10 @@ export interface WorkletCandidate {
18
18
  parent?: any;
19
19
  isAutoWorklet: boolean;
20
20
  }
21
+ export interface WorkletClassCandidate {
22
+ node: any;
23
+ name: string;
24
+ parent?: any;
25
+ marker: any;
26
+ }
21
27
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/worklets/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAC5B,sBAAsB,GACtB,qBAAqB,GACrB,gBAAgB,GAChB,eAAe,CAAA;AAEnB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,GAAG,CAAA;IACX,IAAI,EAAE,oBAAoB,CAAA;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,aAAa,EAAE,OAAO,CAAA;CACvB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/worklets/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAC5B,sBAAsB,GACtB,qBAAqB,GACrB,gBAAgB,GAChB,eAAe,CAAA;AAEnB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,GAAG,CAAA;IACX,IAAI,EAAE,oBAAoB,CAAA;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,GAAG,CAAA;IACT,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,MAAM,EAAE,GAAG,CAAA;CACZ"}