@kudzujs/core 0.8.17 → 0.8.19

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,49 @@
1
+ export function createComponentAnalysis(file) {
2
+ return { version: 1, file, owners: [], specializations: [] }
3
+ }
4
+
5
+ export function createComponentAnalysisSession(analysis) {
6
+ const owners = new WeakMap()
7
+
8
+ function registerOwner(identity, descriptor = {}) {
9
+ let owner = owners.get(identity)
10
+ if (!owner) {
11
+ owner = { slot: analysis.owners.length, kind: descriptor.kind ?? "component", name: descriptor.name ?? "anonymous", props: descriptor.props ?? [], states: [], setters: [], refs: [], ids: [], ...(descriptor.source ? { source: descriptor.source } : {}) }
12
+ owners.set(identity, owner)
13
+ analysis.owners.push(owner)
14
+ }
15
+ return owner
16
+ }
17
+
18
+ function registerState(identity, descriptor) {
19
+ const owner = owners.get(identity)
20
+ if (!owner) throw new Error("Component owner must be registered before its state")
21
+ let state = owner.states.find(entry => entry.name === descriptor.name && entry.owner === descriptor.owner)
22
+ if (!state) {
23
+ state = { slot: owner.states.length, name: descriptor.name, kind: descriptor.kind, ...(descriptor.owner ? { owner: descriptor.owner } : {}), ...(descriptor.source ? { source: descriptor.source } : {}) }
24
+ owner.states.push(state)
25
+ }
26
+ if (descriptor.setter && !owner.setters.some(entry => entry.name === descriptor.setter)) owner.setters.push({ name: descriptor.setter, signal: state.slot, kind: descriptor.kind })
27
+ return state
28
+ }
29
+
30
+ function registerRef(identity, descriptor) {
31
+ const owner = owners.get(identity)
32
+ if (!owner) throw new Error("Component owner must be registered before its ref")
33
+ if (!owner.refs.some(entry => entry.name === descriptor.name)) owner.refs.push({ slot: owner.refs.length, ...descriptor })
34
+ }
35
+
36
+ function registerId(identity, descriptor) {
37
+ const owner = owners.get(identity)
38
+ if (!owner) throw new Error("Component owner must be registered before its ID")
39
+ if (!owner.ids.some(entry => entry.name === descriptor.name)) owner.ids.push({ slot: owner.ids.length, ...descriptor })
40
+ }
41
+
42
+ function registerSpecialization(descriptor) {
43
+ const specialization = { slot: analysis.specializations.length, ...descriptor }
44
+ analysis.specializations.push(specialization)
45
+ return specialization
46
+ }
47
+
48
+ return { owner: identity => owners.get(identity), registerId, registerOwner, registerRef, registerSpecialization, registerState }
49
+ }
@@ -1,20 +1,24 @@
1
1
  import ts from "typescript"
2
+ import { createComponentAnalysis } from "./analysis/component-analysis.mjs"
2
3
  import { bindingNames, isFunctionLike, isReferenceIdentifier, isShadowedByParameter, isShadowedIdentifier, unwrapExpression } from "./ast-helpers.mjs"
3
4
  import { generateCommandBehavior } from "./codegen/command-codegen.mjs"
4
- import { createModuleIR, registerCommandHandler } from "./ir/module-ir.mjs"
5
+ import { createModuleIR, registerBinding, registerCommandHandler, registerDerived, registerModuleHandler } from "./ir/module-ir.mjs"
5
6
 
6
7
  export function createSemanticArtifact(file) {
7
- return { moduleIR: createModuleIR(file), nativeHandlers: [], effectHandlers: [], reactiveBindings: [], listExpressions: [], clientImports: new Set() }
8
+ return { componentAnalysis: createComponentAnalysis(file), moduleIR: createModuleIR(file) }
8
9
  }
9
10
 
10
- export function createDescriptorSession({ semantic, handlerUrl, factory, context, compileEventCommand, isPrimitiveLiteral, rejectWorkerConstructions, sourceName = source => source.fileName }) {
11
- const { moduleIR, nativeHandlers, effectHandlers, reactiveBindings, listExpressions, clientImports } = semantic
12
- const stateScopes = new WeakMap()
13
- let nextStateScope = 0
11
+ export function createDescriptorSession({ semantic, handlerUrl, factory, context, compileEventCommand, handlerLowering, isPrimitiveLiteral, rejectWorkerConstructions, sourceName = source => source.fileName }) {
12
+ const { moduleIR } = semantic
13
+ const nativeHandlers = []
14
+ const effectHandlers = []
15
+ const reactiveBindings = []
16
+ const listExpressions = []
17
+ const clientModules = new Set()
14
18
 
15
19
  function compileListExpression(read, expression, item, index, states = new Set()) {
16
20
  const exportName = `listExpression${listExpressions.length}`
17
- listExpressions.push({ exportName, expression, item, index, states })
21
+ listExpressions.push({ exportName, expression, item, index, states, role: "list-expression" })
18
22
  const arguments_ = [read, factory.createStringLiteral(handlerUrl), factory.createStringLiteral(exportName)]
19
23
  if (states.size) arguments_.push(factory.createArrayLiteralExpression([...states].map(name => factory.createArrayLiteralExpression([factory.createStringLiteral(name), factory.createIdentifier(name)]))))
20
24
  return factory.createCallExpression(factory.createIdentifier("__kListExpression"), undefined, arguments_)
@@ -22,7 +26,7 @@ export function createDescriptorSession({ semantic, handlerUrl, factory, context
22
26
 
23
27
  function compileListConditional(entry) {
24
28
  const exportName = `listExpression${listExpressions.length}`
25
- listExpressions.push({ exportName, expression: entry.condition, item: entry.item, index: entry.index })
29
+ listExpressions.push({ exportName, expression: entry.condition, item: entry.item, index: entry.index, role: "list-conditional" })
26
30
  const read = factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), entry.condition)
27
31
  const thunk = branch => factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), branch)
28
32
  return factory.createCallExpression(factory.createIdentifier("__kListConditional"), undefined, [
@@ -67,7 +71,7 @@ export function createDescriptorSession({ semantic, handlerUrl, factory, context
67
71
  registerClientImports(imports)
68
72
  const captures = new Set([...captureNames(expression, expression, setters)].filter(name => !importedNames.has(name)))
69
73
  const exportName = `binding${reactiveBindings.length}`
70
- reactiveBindings.push({ exportName, expression, captures, states: usedStates, imports })
74
+ reactiveBindings.push({ exportName, expression, captures, states: usedStates, imports, role: "binding" })
71
75
  const states = [...usedStates].map(name => factory.createArrayLiteralExpression([factory.createStringLiteral(name), factory.createIdentifier(name)]))
72
76
  const scope = [...captures].map(name => factory.createArrayLiteralExpression([factory.createStringLiteral(name), factory.createIdentifier(name)]))
73
77
  const stateNames = new Set(usedStates)
@@ -87,23 +91,23 @@ export function createDescriptorSession({ semantic, handlerUrl, factory, context
87
91
  ]
88
92
  }
89
93
 
90
- function compileEvent(expression, { setters, reducers, functions, listItem, importBindings }) {
94
+ function compileEvent(expression, { owner = "module", stateOwners = new Map(), setters, reducers, functions, listItem, importBindings }) {
91
95
  if (ts.isIdentifier(expression)) expression = functions.get(expression.text)
92
96
  if (!expression || (!ts.isArrowFunction(expression) && !ts.isFunctionExpression(expression) && !ts.isFunctionDeclaration(expression))) return undefined
93
- const optimized = referencedReducerDispatches(expression.body, reducers, expression).size ? undefined : compileOptimizedEvent(expression, setters)
97
+ const optimized = referencedReducerDispatches(expression.body, reducers, expression).size ? undefined : compileOptimizedEvent(expression, setters, stateOwners, owner)
94
98
  if (optimized) return optimized
95
99
  rejectWorkerConstructions(expression)
96
- const descriptor = compileNativeCallback(expression, { setters, reducers, entries: nativeHandlers, importBindings, prefix: "handler", listItem })
100
+ const descriptor = compileNativeCallback(expression, { setters, reducers, entries: nativeHandlers, importBindings, prefix: "handler", role: "native", listItem })
97
101
  return factory.createCallExpression(factory.createIdentifier("__kNativeBehavior"), undefined, [
98
102
  factory.createStringLiteral(handlerUrl), factory.createStringLiteral(descriptor.exportName), descriptor.states, descriptor.scope
99
103
  ])
100
104
  }
101
105
 
102
106
  function compileEffectCallback(expression, options) {
103
- return compileNativeCallback(expression, { ...options, entries: effectHandlers, prefix: "effect" })
107
+ return compileNativeCallback(expression, { ...options, entries: effectHandlers, prefix: "effect", role: "effect" })
104
108
  }
105
109
 
106
- function compileNativeCallback(expression, { setters, reducers, entries, importBindings, prefix, listItem, deferValues = false, snapshotNested = false, liveStates = new Set() }) {
110
+ function compileNativeCallback(expression, { setters, reducers, entries, importBindings, prefix, role, listItem, deferValues = false, snapshotNested = false, liveStates = new Set() }) {
107
111
  const allCaptures = nativeCaptureNames(expression, setters)
108
112
  const usedReducers = referencedReducerDispatches(expression.body, reducers, expression)
109
113
  const imports = [...referencedImportedBindings(expression, importBindings)].map(name => importBindings.get(name))
@@ -116,7 +120,7 @@ export function createDescriptorSession({ semantic, handlerUrl, factory, context
116
120
  if (reducer.contextAction) for (const state of referencedStateNames(reducer.contextAction.body, reducer.states, reducer.contextAction)) usedStates.add(state)
117
121
  }
118
122
  const exportName = `${prefix}${entries.length}`
119
- entries.push({ exportName, expression, captures, imports, liveStates, setters: new Map([...setters].filter(([, state]) => usedStates.has(state))), reducers: new Map([...reducers].filter(([name]) => usedReducers.has(name))), snapshotNested })
123
+ entries.push({ exportName, expression, captures, deferValues, imports, listItem, liveStates, role, setters: new Map([...setters].filter(([, state]) => usedStates.has(state))), reducers: new Map([...reducers].filter(([name]) => usedReducers.has(name))), snapshotNested, usedStates })
120
124
  const value = name => deferValues
121
125
  ? factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factory.createIdentifier(name))
122
126
  : factory.createIdentifier(name)
@@ -132,23 +136,86 @@ export function createDescriptorSession({ semantic, handlerUrl, factory, context
132
136
  }
133
137
  }
134
138
 
135
- function compileOptimizedEvent(expression, setters) {
139
+ function compileOptimizedEvent(expression, setters, stateOwners, owner) {
136
140
  const statements = ts.isBlock(expression.body) ? expression.body.statements : [factory.createExpressionStatement(expression.body)]
137
141
  const commands = statements.map(statement => ts.isExpressionStatement(statement) ? compileEventCommand(statement.expression, setters) : undefined)
138
142
  if (!commands.length || commands.some(command => !command)) return undefined
139
143
  const original = ts.getOriginalNode(expression)
140
144
  const source = original.pos >= 0 && original.end >= 0 ? { file: sourceName(original.getSourceFile()), start: original.getStart(), end: original.end } : undefined
141
- if (!stateScopes.has(setters)) stateScopes.set(setters, `state:${nextStateScope++}`)
142
- const scope = stateScopes.get(setters)
143
- const handler = registerCommandHandler(moduleIR, commands, source, scope)
145
+ const handler = registerCommandHandler(moduleIR, commands.map(command => ({ ...command, owner: stateOwners.get(command.state) ?? owner })), source, owner)
144
146
  return generateCommandBehavior(moduleIR, handler, factory)
145
147
  }
146
148
 
147
149
  function registerClientImports(imports) {
148
- for (const entry of imports) if (!entry.package) clientImports.add(entry.target)
150
+ for (const entry of imports) if (!entry.package) clientModules.add(entry.target)
149
151
  }
150
152
 
151
- return { compileConditional, compileEffectCallback, compileEvent, compileListConditional, compileListValue, compileReactiveBinding }
153
+ function registerDerivedResult(kind, value, states = [], node) {
154
+ const normalized = JSON.parse(JSON.stringify(value))
155
+ return registerDerived(moduleIR, { kind, [kind]: normalized, states: [...states], ...(source(node) ? { source: source(node) } : {}) })
156
+ }
157
+
158
+ function finalize() {
159
+ const callbacks = [...nativeHandlers, ...effectHandlers]
160
+ for (const entry of callbacks) {
161
+ const lowered = handlerLowering.lowerNativeHandler(entry)
162
+ const setters = Map.groupBy(entry.setters, ([, state]) => state)
163
+ registerModuleHandler(moduleIR, {
164
+ role: entry.role,
165
+ exportName: entry.exportName,
166
+ async: Boolean(entry.expression.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.AsyncKeyword)),
167
+ generator: Boolean(entry.expression.asteriskToken),
168
+ signals: [...entry.usedStates].map(name => ({
169
+ name,
170
+ setters: (setters.get(name) ?? []).map(([setter]) => setter),
171
+ value: entry.deferValues ? "deferred" : "direct",
172
+ snapshot: lowered.stateSnapshots.includes(name)
173
+ })),
174
+ captures: [...entry.captures].map(name => ({
175
+ name,
176
+ source: name === (typeof entry.listItem === "string" ? entry.listItem : entry.listItem?.item) ? "list-item" : name === entry.listItem?.index ? "list-index" : "scope",
177
+ value: entry.deferValues ? "deferred" : "direct",
178
+ snapshot: lowered.captureSnapshots.includes(name)
179
+ })),
180
+ imports: entry.imports.map(importRecord),
181
+ code: lowered.code,
182
+ ...(source(entry.expression) ? { source: source(entry.expression) } : {})
183
+ })
184
+ }
185
+ for (const entry of reactiveBindings) registerBinding(moduleIR, {
186
+ role: entry.role,
187
+ exportName: entry.exportName,
188
+ parameters: ["__k"],
189
+ states: [...entry.states],
190
+ captures: [...entry.captures].map(name => ({ name, source: "scope" })),
191
+ imports: entry.imports.map(importRecord),
192
+ code: handlerLowering.lowerReactiveBinding(entry),
193
+ ...(source(entry.expression) ? { source: source(entry.expression) } : {})
194
+ })
195
+ for (const entry of listExpressions) registerBinding(moduleIR, {
196
+ role: entry.role,
197
+ exportName: entry.exportName,
198
+ parameters: [entry.item, entry.index ?? "__kIndex", "__k"],
199
+ states: [...(entry.states ?? [])],
200
+ captures: [],
201
+ imports: [],
202
+ code: handlerLowering.lowerListExpression(entry),
203
+ ...(source(entry.expression) ? { source: source(entry.expression) } : {})
204
+ })
205
+ const imports = [...callbacks, ...reactiveBindings].flatMap(entry => entry.imports ?? []).map(importRecord)
206
+ moduleIR.imports = [...new Map(imports.map(entry => [`${entry.target}:${entry.kind}:${entry.imported ?? ""}:${entry.local}`, entry])).values()]
207
+ moduleIR.clientModules = [...clientModules]
208
+ }
209
+
210
+ function source(node) {
211
+ if (!node) return undefined
212
+ const original = ts.getOriginalNode(node)
213
+ return original.pos >= 0 && original.end >= 0 ? { file: sourceName(original.getSourceFile()), start: original.getStart(), end: original.end } : undefined
214
+ }
215
+
216
+ const importRecord = entry => ({ target: entry.target, kind: entry.kind, local: entry.local, ...(entry.imported ? { imported: entry.imported } : {}), package: Boolean(entry.package) })
217
+
218
+ return { compileConditional, compileEffectCallback, compileEvent, compileListConditional, compileListValue, compileReactiveBinding, finalize, registerDerived: registerDerivedResult }
152
219
  }
153
220
 
154
221
  function directStateIdentifier(expression, setters) {
@@ -1,19 +1,14 @@
1
- import ts from "typescript"
2
- import { isFunctionLike, isReferenceIdentifier, isShadowedByParameter, isShadowedIdentifier, sourceNodeError } from "./ast-helpers.mjs"
3
-
4
- export function createHandlerCodegen({ cloneAst, synthesizeTree, resolveClientImport }) {
5
- return function printHandlerModule({ callbacks, reactiveBindings, listExpressions, handlerPath }) {
1
+ export function createHandlerCodegen({ resolveClientImport }) {
2
+ return function printHandlerModule({ moduleIR, handlerPath }) {
6
3
  return [
7
- printClientImports([...callbacks, ...reactiveBindings].flatMap(handler => handler.imports ?? []), handlerPath),
8
- ...callbacks.map(handler => printNativeHandler(handler)),
9
- ...reactiveBindings.map(entry => printReactiveBinding(entry)),
10
- ...listExpressions.map(entry => printListExpression(entry))
4
+ printClientImports(moduleIR.imports, handlerPath),
5
+ ...moduleIR.handlers.filter(handler => handler.kind === "module-export").map(handler => handler.code),
6
+ ...moduleIR.bindings.map(binding => binding.code)
11
7
  ].join("\n")
12
8
  }
13
9
 
14
10
  function printClientImports(entries, handlerPath) {
15
- const unique = new Map(entries.map(entry => [`${entry.target}:${entry.kind}:${entry.imported ?? ""}:${entry.local}`, entry]))
16
- const groups = Map.groupBy(unique.values(), entry => entry.target)
11
+ const groups = Map.groupBy(entries, entry => entry.target)
17
12
  const imports = []
18
13
  for (const [target, group] of groups) {
19
14
  const specifier = resolveClientImport(group[0], handlerPath)
@@ -25,272 +20,4 @@ export function createHandlerCodegen({ cloneAst, synthesizeTree, resolveClientIm
25
20
  }
26
21
  return imports.join("\n")
27
22
  }
28
-
29
- function printNativeHandler({ exportName, expression, captures, setters, reducers = new Map(), snapshotNested, liveStates = new Set() }) {
30
- const factory = ts.factory
31
- const stateNames = new Set(setters.values())
32
- const snapshotNames = snapshotNested ? nestedStateNames(expression, setters, liveStates) : new Set()
33
- const snapshots = new Map([...snapshotNames].map(name => [name, factory.createUniqueName("__kEffectState")]))
34
- const captureSnapshotNames = snapshotNested ? nestedCaptureNames(expression, captures) : new Set()
35
- const captureSnapshots = new Map([...captureSnapshotNames].map(name => [name, factory.createUniqueName("__kEffectCapture")]))
36
- const transformer = context => root => {
37
- const visitor = node => {
38
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && reducers.has(node.expression.text) && !isShadowedIdentifier(node.expression, expression)) {
39
- const reducer = reducers.get(node.expression.text)
40
- if (reducer.contextAction) {
41
- const action = synthesizeTree(cloneAst(reducer.contextAction, factory, context))
42
- const call = factory.createCallExpression(action, undefined, node.arguments)
43
- ts.setParentRecursive(call, false)
44
- return ts.visitNode(call, visitor)
45
- }
46
- if (reducer.store) return zustandActionDispatch(factory, reducer, node.arguments.map(argument => ts.visitNode(argument, visitor)))
47
- if (node.arguments.length !== 1) throw sourceNodeError(node, expression.getSourceFile(), "Reducer dispatches require exactly one action")
48
- return reducerDispatch(factory, reducer, ts.visitNode(node.arguments[0], visitor))
49
- }
50
- if (ts.isShorthandPropertyAssignment(node) && reducers.has(node.name.text) && !isShadowedIdentifier(node.name, expression)) {
51
- if (reducers.get(node.name.text).contextAction) throw sourceNodeError(node, expression.getSourceFile(), "Context actions must be called directly inside an event handler")
52
- if (reducers.get(node.name.text).store) throw sourceNodeError(node, expression.getSourceFile(), "Zustand actions must be called directly inside an event handler")
53
- return factory.createPropertyAssignment(node.name, reducerReference(factory, reducers.get(node.name.text)))
54
- }
55
- if (ts.isIdentifier(node) && reducers.has(node.text) && isReferenceIdentifier(node) && !isShadowedIdentifier(node, expression)) {
56
- if (reducers.get(node.text).contextAction) throw sourceNodeError(node, expression.getSourceFile(), "Context actions must be called directly inside an event handler")
57
- if (reducers.get(node.text).store) throw sourceNodeError(node, expression.getSourceFile(), "Zustand actions must be called directly inside an event handler")
58
- return reducerReference(factory, reducers.get(node.text))
59
- }
60
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && setters.has(node.expression.text) && !isShadowedIdentifier(node.expression, expression)) {
61
- return factory.createCallExpression(
62
- factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "set"),
63
- undefined,
64
- [factory.createStringLiteral(setters.get(node.expression.text)), ...node.arguments.map(argument => ts.visitNode(argument, visitor))]
65
- )
66
- }
67
- if (ts.isShorthandPropertyAssignment(node) && setters.has(node.name.text) && !isShadowedIdentifier(node.name, expression)) {
68
- return factory.createPropertyAssignment(node.name, setterReference(factory, setters.get(node.name.text)))
69
- }
70
- if (ts.isIdentifier(node) && setters.has(node.text) && isReferenceIdentifier(node) && !isShadowedIdentifier(node, expression)) {
71
- return setterReference(factory, setters.get(node.text))
72
- }
73
- if (ts.isShorthandPropertyAssignment(node) && stateNames.has(node.name.text) && !isShadowedIdentifier(node.name, expression)) {
74
- if (snapshots.has(node.name.text) && insideNestedFunction(node, expression)) return factory.createPropertyAssignment(node.name, snapshots.get(node.name.text))
75
- return factory.createPropertyAssignment(node.name, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"), undefined, [factory.createStringLiteral(node.name.text)]))
76
- }
77
- if (ts.isIdentifier(node) && stateNames.has(node.text) && isReferenceIdentifier(node) && !isShadowedIdentifier(node, expression)) {
78
- if (snapshots.has(node.text) && insideNestedFunction(node, expression)) return snapshots.get(node.text)
79
- return factory.createCallExpression(
80
- factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"),
81
- undefined,
82
- [factory.createStringLiteral(node.text)]
83
- )
84
- }
85
- if (ts.isShorthandPropertyAssignment(node) && captures.has(node.name.text) && !isShadowedIdentifier(node.name, expression)) {
86
- if (captureSnapshots.has(node.name.text) && insideNestedFunction(node, expression)) return factory.createPropertyAssignment(node.name, captureSnapshots.get(node.name.text))
87
- return factory.createPropertyAssignment(node.name, scopeRead(factory, node.name.text))
88
- }
89
- if (ts.isIdentifier(node) && captures.has(node.text) && isReferenceIdentifier(node) && !isShadowedIdentifier(node, expression)) {
90
- if (captureSnapshots.has(node.text) && insideNestedFunction(node, expression)) return captureSnapshots.get(node.text)
91
- return scopeRead(factory, node.text)
92
- }
93
- return ts.visitEachChild(node, visitor, context)
94
- }
95
- return ts.visitNode(root, visitor)
96
- }
97
- const transformed = ts.transform(expression.body, [transformer])
98
- try {
99
- let body = ts.isBlock(expression.body)
100
- ? transformed.transformed[0]
101
- : factory.createBlock([factory.createReturnStatement(transformed.transformed[0])], true)
102
- const snapshotDeclarations = [
103
- ...[...snapshots].map(([name, identifier]) => factory.createVariableDeclaration(identifier, undefined, undefined, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"), undefined, [factory.createStringLiteral(name)]))),
104
- ...[...captureSnapshots].map(([name, identifier]) => factory.createVariableDeclaration(identifier, undefined, undefined, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "scope"), undefined, [factory.createStringLiteral(name)])))
105
- ]
106
- if (snapshotDeclarations.length) body = factory.updateBlock(body, [
107
- factory.createVariableStatement(undefined, factory.createVariableDeclarationList(snapshotDeclarations, ts.NodeFlags.Const)),
108
- ...body.statements
109
- ])
110
- const modifiers = [factory.createModifier(ts.SyntaxKind.ExportKeyword)]
111
- if (expression.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.AsyncKeyword)) modifiers.push(factory.createModifier(ts.SyntaxKind.AsyncKeyword))
112
- const declaration = factory.createFunctionDeclaration(
113
- modifiers,
114
- expression.asteriskToken,
115
- exportName,
116
- undefined,
117
- [factory.createParameterDeclaration(undefined, undefined, "__k"), ...expression.parameters],
118
- undefined,
119
- body
120
- )
121
- return ts.createPrinter().printNode(ts.EmitHint.Unspecified, declaration, expression.getSourceFile())
122
- } finally {
123
- transformed.dispose()
124
- }
125
- }
126
-
127
- function nestedCaptureNames(expression, captures) {
128
- const names = new Set()
129
- const visit = node => {
130
- if (ts.isIdentifier(node) && captures.has(node.text) && isReferenceIdentifier(node) && insideNestedFunction(node, expression) && !isShadowedIdentifier(node, expression)) names.add(node.text)
131
- ts.forEachChild(node, visit)
132
- }
133
- visit(expression.body)
134
- return names
135
- }
136
-
137
- function nestedStateNames(expression, setters, liveStates = new Set()) {
138
- const states = new Set(setters.values())
139
- const names = new Set()
140
- const visit = node => {
141
- if (ts.isIdentifier(node) && states.has(node.text) && !liveStates.has(node.text) && isReferenceIdentifier(node) && insideNestedFunction(node, expression) && !isShadowedIdentifier(node, expression)) names.add(node.text)
142
- ts.forEachChild(node, visit)
143
- }
144
- visit(expression.body)
145
- return names
146
- }
147
-
148
- function insideNestedFunction(node, root) {
149
- for (let current = node.parent; current && current !== root; current = current.parent) {
150
- if (isFunctionLike(current)) return true
151
- }
152
- return false
153
- }
154
-
155
- function setterReference(factory, stateName) {
156
- return factory.createArrowFunction(
157
- undefined,
158
- undefined,
159
- [factory.createParameterDeclaration(undefined, undefined, "value")],
160
- undefined,
161
- factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
162
- factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "set"), undefined, [factory.createStringLiteral(stateName), factory.createIdentifier("value")])
163
- )
164
- }
165
-
166
- function reducerReference(factory, reducer) {
167
- const action = factory.createUniqueName("__kAction")
168
- return factory.createArrowFunction(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, action)], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), reducerDispatch(factory, reducer, action))
169
- }
170
-
171
- function reducerDispatch(factory, reducer, action) {
172
- if (reducer.store) return zustandActionDispatch(factory, reducer, [action])
173
- const previous = factory.createUniqueName("__kPrevious")
174
- const update = factory.createArrowFunction(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, previous)], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factory.createCallExpression(factory.createIdentifier(reducer.reducer), undefined, [previous, action]))
175
- return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "set"), undefined, [factory.createStringLiteral(reducer.state), update])
176
- }
177
-
178
- function zustandActionDispatch(factory, reducer, args) {
179
- const previous = factory.createUniqueName("__kPrevious")
180
- const current = factory.createUniqueName("__kStore")
181
- const updateValue = factory.createUniqueName("__kUpdate")
182
- const partial = factory.createUniqueName("__kPartial")
183
- const action = factory.createUniqueName("__kAction")
184
- const set = factory.createIdentifier(reducer.store.setName)
185
- const merge = factory.createExpressionStatement(factory.createBinaryExpression(current, factory.createToken(ts.SyntaxKind.EqualsToken), factory.createObjectLiteralExpression([
186
- factory.createSpreadAssignment(current),
187
- factory.createSpreadAssignment(partial)
188
- ])))
189
- const setBody = factory.createBlock([
190
- factory.createVariableStatement(undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(partial, undefined, undefined, factory.createConditionalExpression(
191
- factory.createBinaryExpression(factory.createTypeOfExpression(updateValue), factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), factory.createStringLiteral("function")),
192
- undefined,
193
- factory.createCallExpression(updateValue, undefined, [current]),
194
- undefined,
195
- updateValue
196
- ))], ts.NodeFlags.Const)),
197
- merge
198
- ], true)
199
- const body = factory.createBlock([
200
- factory.createVariableStatement(undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(current, undefined, undefined, factory.createObjectLiteralExpression([factory.createPropertyAssignment(reducer.store.field, previous)]))], ts.NodeFlags.Let)),
201
- factory.createVariableStatement(undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(set, undefined, undefined, factory.createArrowFunction(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, updateValue)], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), setBody))], ts.NodeFlags.Const)),
202
- factory.createVariableStatement(undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(action, undefined, undefined, synthesizeTree(reducer.store.actions.get(reducer.action)))], ts.NodeFlags.Const)),
203
- factory.createExpressionStatement(factory.createCallExpression(action, undefined, args)),
204
- factory.createReturnStatement(factory.createPropertyAccessExpression(current, reducer.store.field))
205
- ], true)
206
- const update = factory.createArrowFunction(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, previous)], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), body)
207
- return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "set"), undefined, [factory.createStringLiteral(reducer.state), update])
208
- }
209
-
210
- function printReactiveBinding({ exportName, expression, captures, states }) {
211
- const factory = ts.factory
212
- const transformer = context => root => {
213
- const visitor = node => {
214
- if (ts.isShorthandPropertyAssignment(node) && states.has(node.name.text)) {
215
- return factory.createPropertyAssignment(
216
- node.name,
217
- factory.createCallExpression(
218
- factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"),
219
- undefined,
220
- [factory.createStringLiteral(node.name.text)]
221
- )
222
- )
223
- }
224
- if (ts.isIdentifier(node) && states.has(node.text) && isReferenceIdentifier(node) && !isShadowedByParameter(node, expression)) {
225
- return factory.createCallExpression(
226
- factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"),
227
- undefined,
228
- [factory.createStringLiteral(node.text)]
229
- )
230
- }
231
- if (ts.isShorthandPropertyAssignment(node) && captures.has(node.name.text)) {
232
- return factory.createPropertyAssignment(node.name, scopeRead(factory, node.name.text))
233
- }
234
- if (ts.isIdentifier(node) && captures.has(node.text) && isReferenceIdentifier(node)) {
235
- return scopeRead(factory, node.text)
236
- }
237
- return ts.visitEachChild(node, visitor, context)
238
- }
239
- return ts.visitNode(root, visitor)
240
- }
241
- const transformed = ts.transform(expression, [transformer])
242
- try {
243
- const declaration = factory.createFunctionDeclaration(
244
- [factory.createModifier(ts.SyntaxKind.ExportKeyword)],
245
- undefined,
246
- exportName,
247
- undefined,
248
- [factory.createParameterDeclaration(undefined, undefined, "__k")],
249
- undefined,
250
- factory.createBlock([factory.createReturnStatement(transformed.transformed[0])], true)
251
- )
252
- return ts.createPrinter().printNode(ts.EmitHint.Unspecified, declaration, expression.getSourceFile())
253
- } finally {
254
- transformed.dispose()
255
- }
256
- }
257
-
258
- function printListExpression({ exportName, expression, item, index, states = new Set() }) {
259
- const factory = ts.factory
260
- const transformer = context => root => {
261
- const visitor = node => {
262
- if (ts.isShorthandPropertyAssignment(node) && states.has(node.name.text)) {
263
- return factory.createPropertyAssignment(node.name, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"), undefined, [factory.createStringLiteral(node.name.text)]))
264
- }
265
- if (ts.isIdentifier(node) && states.has(node.text) && isReferenceIdentifier(node) && !isShadowedByParameter(node, expression)) {
266
- return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"), undefined, [factory.createStringLiteral(node.text)])
267
- }
268
- return ts.visitEachChild(node, visitor, context)
269
- }
270
- return ts.visitNode(root, visitor)
271
- }
272
- const transformed = ts.transform(expression, [transformer])
273
- const declaration = ts.factory.createFunctionDeclaration(
274
- [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
275
- undefined,
276
- exportName,
277
- undefined,
278
- [ts.factory.createParameterDeclaration(undefined, undefined, item), ts.factory.createParameterDeclaration(undefined, undefined, index ?? "__kIndex"), ts.factory.createParameterDeclaration(undefined, undefined, "__k")],
279
- undefined,
280
- ts.factory.createBlock([ts.factory.createReturnStatement(transformed.transformed[0])], true)
281
- )
282
- try {
283
- return ts.createPrinter().printNode(ts.EmitHint.Unspecified, declaration, expression.getSourceFile())
284
- } finally {
285
- transformed.dispose()
286
- }
287
- }
288
-
289
- function scopeRead(factory, name) {
290
- return factory.createCallExpression(
291
- factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "scope"),
292
- undefined,
293
- [factory.createStringLiteral(name)]
294
- )
295
- }
296
23
  }