ai-evaluate 2.1.8 → 2.2.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.
Files changed (61) hide show
  1. package/dist/evaluate.d.ts.map +1 -1
  2. package/dist/evaluate.js.map +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/miniflare-pool.d.ts.map +1 -1
  6. package/dist/miniflare-pool.js.map +1 -1
  7. package/dist/node.d.ts.map +1 -1
  8. package/dist/node.js.map +1 -1
  9. package/dist/static/index.d.ts +111 -0
  10. package/dist/static/index.d.ts.map +1 -0
  11. package/dist/static/index.js +347 -0
  12. package/dist/static/index.js.map +1 -0
  13. package/dist/type-guards.d.ts.map +1 -1
  14. package/dist/type-guards.js.map +1 -1
  15. package/dist/worker-template/core.d.ts.map +1 -1
  16. package/dist/worker-template/core.js +1 -1
  17. package/dist/worker-template/core.js.map +1 -1
  18. package/package.json +17 -4
  19. package/public/capnweb.mjs +220 -0
  20. package/public/index.mjs +426 -0
  21. package/public/scaffold.mjs +198 -0
  22. package/.turbo/turbo-build.log +0 -4
  23. package/.turbo/turbo-test.log +0 -54
  24. package/.turbo/turbo-typecheck.log +0 -4
  25. package/CHANGELOG.md +0 -48
  26. package/example/package.json +0 -20
  27. package/example/src/index.ts +0 -221
  28. package/example/wrangler.jsonc +0 -25
  29. package/src/capnweb-bundle.ts +0 -2596
  30. package/src/evaluate.ts +0 -329
  31. package/src/index.ts +0 -23
  32. package/src/miniflare-pool.ts +0 -395
  33. package/src/node.ts +0 -245
  34. package/src/repl.ts +0 -228
  35. package/src/shared.ts +0 -186
  36. package/src/type-guards.ts +0 -323
  37. package/src/types.ts +0 -196
  38. package/src/validation.ts +0 -120
  39. package/src/worker-template/code-transforms.ts +0 -32
  40. package/src/worker-template/core.ts +0 -557
  41. package/src/worker-template/helpers.ts +0 -90
  42. package/src/worker-template/index.ts +0 -23
  43. package/src/worker-template/sdk-generator.ts +0 -2515
  44. package/src/worker-template/test-generator.ts +0 -358
  45. package/test/evaluate-extended.test.js +0 -429
  46. package/test/evaluate-extended.test.ts +0 -469
  47. package/test/evaluate.test.js +0 -235
  48. package/test/evaluate.test.ts +0 -253
  49. package/test/index.test.js +0 -77
  50. package/test/index.test.ts +0 -95
  51. package/test/miniflare-pool.test.ts +0 -246
  52. package/test/node.test.ts +0 -467
  53. package/test/security.test.ts +0 -1009
  54. package/test/shared.test.ts +0 -105
  55. package/test/type-guards.test.ts +0 -303
  56. package/test/validation.test.ts +0 -240
  57. package/test/worker-template.test.js +0 -365
  58. package/test/worker-template.test.ts +0 -432
  59. package/tsconfig.json +0 -22
  60. package/vitest.config.js +0 -21
  61. package/vitest.config.ts +0 -28
@@ -1,323 +0,0 @@
1
- /**
2
- * Runtime type guards for JSON response validation
3
- */
4
-
5
- import type { EvaluateResult, LogEntry, TestResults, TestResult } from './types.js'
6
-
7
- /**
8
- * Check if a value is a valid LogEntry
9
- */
10
- function isLogEntry(value: unknown): value is LogEntry {
11
- if (typeof value !== 'object' || value === null) {
12
- return false
13
- }
14
-
15
- const obj = value as Record<string, unknown>
16
-
17
- // Check level is one of the allowed values
18
- const validLevels = ['log', 'warn', 'error', 'info', 'debug']
19
- if (typeof obj.level !== 'string' || !validLevels.includes(obj.level)) {
20
- return false
21
- }
22
-
23
- // Check message is a string
24
- if (typeof obj.message !== 'string') {
25
- return false
26
- }
27
-
28
- // Check timestamp is a number
29
- if (typeof obj.timestamp !== 'number') {
30
- return false
31
- }
32
-
33
- return true
34
- }
35
-
36
- /**
37
- * Check if a value is a valid TestResult
38
- */
39
- function isTestResult(value: unknown): value is TestResult {
40
- if (typeof value !== 'object' || value === null) {
41
- return false
42
- }
43
-
44
- const obj = value as Record<string, unknown>
45
-
46
- // Check required fields
47
- if (typeof obj.name !== 'string') {
48
- return false
49
- }
50
-
51
- if (typeof obj.passed !== 'boolean') {
52
- return false
53
- }
54
-
55
- if (typeof obj.duration !== 'number') {
56
- return false
57
- }
58
-
59
- // Check optional error field
60
- if (obj.error !== undefined && typeof obj.error !== 'string') {
61
- return false
62
- }
63
-
64
- return true
65
- }
66
-
67
- /**
68
- * Check if a value is a valid TestResults
69
- */
70
- function isTestResults(value: unknown): value is TestResults {
71
- if (typeof value !== 'object' || value === null) {
72
- return false
73
- }
74
-
75
- const obj = value as Record<string, unknown>
76
-
77
- // Check required numeric fields
78
- if (typeof obj.total !== 'number') {
79
- return false
80
- }
81
-
82
- if (typeof obj.passed !== 'number') {
83
- return false
84
- }
85
-
86
- if (typeof obj.failed !== 'number') {
87
- return false
88
- }
89
-
90
- if (typeof obj.skipped !== 'number') {
91
- return false
92
- }
93
-
94
- if (typeof obj.duration !== 'number') {
95
- return false
96
- }
97
-
98
- // Check tests array
99
- if (!Array.isArray(obj.tests)) {
100
- return false
101
- }
102
-
103
- for (const test of obj.tests) {
104
- if (!isTestResult(test)) {
105
- return false
106
- }
107
- }
108
-
109
- return true
110
- }
111
-
112
- /**
113
- * Type guard to check if a value is a valid EvaluateResult
114
- *
115
- * Validates all required fields: success, duration, logs
116
- *
117
- * @param value - The value to check
118
- * @returns True if the value is a valid EvaluateResult
119
- */
120
- export function isEvaluateResult(value: unknown): value is EvaluateResult {
121
- if (typeof value !== 'object' || value === null) {
122
- return false
123
- }
124
-
125
- const obj = value as Record<string, unknown>
126
-
127
- // Check required fields
128
- if (typeof obj.success !== 'boolean') {
129
- return false
130
- }
131
-
132
- if (typeof obj.duration !== 'number') {
133
- return false
134
- }
135
-
136
- // Check logs is an array of valid LogEntry objects
137
- if (!Array.isArray(obj.logs)) {
138
- return false
139
- }
140
-
141
- for (const log of obj.logs) {
142
- if (!isLogEntry(log)) {
143
- return false
144
- }
145
- }
146
-
147
- // Check optional fields have correct types if present
148
- if (obj.error !== undefined && typeof obj.error !== 'string') {
149
- return false
150
- }
151
-
152
- if (obj.testResults !== undefined && !isTestResults(obj.testResults)) {
153
- return false
154
- }
155
-
156
- // value can be any type, so no validation needed for it
157
-
158
- return true
159
- }
160
-
161
- /**
162
- * Assertion function that throws a descriptive error if the value is not a valid EvaluateResult
163
- *
164
- * @param value - The value to validate
165
- * @throws Error with descriptive message if validation fails
166
- */
167
- export function assertEvaluateResult(value: unknown): asserts value is EvaluateResult {
168
- if (typeof value !== 'object' || value === null) {
169
- throw new Error(
170
- `Invalid EvaluateResult: expected object, got ${value === null ? 'null' : typeof value}`
171
- )
172
- }
173
-
174
- const obj = value as Record<string, unknown>
175
-
176
- // Validate required field: success
177
- if (typeof obj.success !== 'boolean') {
178
- throw new Error(
179
- `Invalid EvaluateResult: 'success' must be a boolean, got ${typeof obj.success}`
180
- )
181
- }
182
-
183
- // Validate required field: duration
184
- if (typeof obj.duration !== 'number') {
185
- throw new Error(
186
- `Invalid EvaluateResult: 'duration' must be a number, got ${typeof obj.duration}`
187
- )
188
- }
189
-
190
- // Validate required field: logs
191
- if (!Array.isArray(obj.logs)) {
192
- throw new Error(`Invalid EvaluateResult: 'logs' must be an array, got ${typeof obj.logs}`)
193
- }
194
-
195
- // Validate each log entry
196
- for (let i = 0; i < obj.logs.length; i++) {
197
- const log = obj.logs[i]
198
- if (typeof log !== 'object' || log === null) {
199
- throw new Error(
200
- `Invalid EvaluateResult: logs[${i}] must be an object, got ${
201
- log === null ? 'null' : typeof log
202
- }`
203
- )
204
- }
205
-
206
- const logObj = log as Record<string, unknown>
207
- const validLevels = ['log', 'warn', 'error', 'info', 'debug']
208
-
209
- if (typeof logObj.level !== 'string' || !validLevels.includes(logObj.level)) {
210
- throw new Error(
211
- `Invalid EvaluateResult: logs[${i}].level must be one of ${validLevels.join(', ')}, got '${
212
- logObj.level
213
- }'`
214
- )
215
- }
216
-
217
- if (typeof logObj.message !== 'string') {
218
- throw new Error(
219
- `Invalid EvaluateResult: logs[${i}].message must be a string, got ${typeof logObj.message}`
220
- )
221
- }
222
-
223
- if (typeof logObj.timestamp !== 'number') {
224
- throw new Error(
225
- `Invalid EvaluateResult: logs[${i}].timestamp must be a number, got ${typeof logObj.timestamp}`
226
- )
227
- }
228
- }
229
-
230
- // Validate optional field: error
231
- if (obj.error !== undefined && typeof obj.error !== 'string') {
232
- throw new Error(
233
- `Invalid EvaluateResult: 'error' must be a string if present, got ${typeof obj.error}`
234
- )
235
- }
236
-
237
- // Validate optional field: testResults
238
- if (obj.testResults !== undefined) {
239
- if (typeof obj.testResults !== 'object' || obj.testResults === null) {
240
- throw new Error(
241
- `Invalid EvaluateResult: 'testResults' must be an object if present, got ${
242
- obj.testResults === null ? 'null' : typeof obj.testResults
243
- }`
244
- )
245
- }
246
-
247
- const testResults = obj.testResults as Record<string, unknown>
248
-
249
- if (typeof testResults.total !== 'number') {
250
- throw new Error(
251
- `Invalid EvaluateResult: testResults.total must be a number, got ${typeof testResults.total}`
252
- )
253
- }
254
-
255
- if (typeof testResults.passed !== 'number') {
256
- throw new Error(
257
- `Invalid EvaluateResult: testResults.passed must be a number, got ${typeof testResults.passed}`
258
- )
259
- }
260
-
261
- if (typeof testResults.failed !== 'number') {
262
- throw new Error(
263
- `Invalid EvaluateResult: testResults.failed must be a number, got ${typeof testResults.failed}`
264
- )
265
- }
266
-
267
- if (typeof testResults.skipped !== 'number') {
268
- throw new Error(
269
- `Invalid EvaluateResult: testResults.skipped must be a number, got ${typeof testResults.skipped}`
270
- )
271
- }
272
-
273
- if (typeof testResults.duration !== 'number') {
274
- throw new Error(
275
- `Invalid EvaluateResult: testResults.duration must be a number, got ${typeof testResults.duration}`
276
- )
277
- }
278
-
279
- if (!Array.isArray(testResults.tests)) {
280
- throw new Error(
281
- `Invalid EvaluateResult: testResults.tests must be an array, got ${typeof testResults.tests}`
282
- )
283
- }
284
-
285
- // Validate each test result
286
- for (let i = 0; i < testResults.tests.length; i++) {
287
- const test = testResults.tests[i]
288
- if (typeof test !== 'object' || test === null) {
289
- throw new Error(
290
- `Invalid EvaluateResult: testResults.tests[${i}] must be an object, got ${
291
- test === null ? 'null' : typeof test
292
- }`
293
- )
294
- }
295
-
296
- const testObj = test as Record<string, unknown>
297
-
298
- if (typeof testObj.name !== 'string') {
299
- throw new Error(
300
- `Invalid EvaluateResult: testResults.tests[${i}].name must be a string, got ${typeof testObj.name}`
301
- )
302
- }
303
-
304
- if (typeof testObj.passed !== 'boolean') {
305
- throw new Error(
306
- `Invalid EvaluateResult: testResults.tests[${i}].passed must be a boolean, got ${typeof testObj.passed}`
307
- )
308
- }
309
-
310
- if (typeof testObj.duration !== 'number') {
311
- throw new Error(
312
- `Invalid EvaluateResult: testResults.tests[${i}].duration must be a number, got ${typeof testObj.duration}`
313
- )
314
- }
315
-
316
- if (testObj.error !== undefined && typeof testObj.error !== 'string') {
317
- throw new Error(
318
- `Invalid EvaluateResult: testResults.tests[${i}].error must be a string if present, got ${typeof testObj.error}`
319
- )
320
- }
321
- }
322
- }
323
- }
package/src/types.ts DELETED
@@ -1,196 +0,0 @@
1
- /**
2
- * Types for ai-sandbox
3
- */
4
-
5
- /**
6
- * SDK configuration for the sandbox environment
7
- */
8
- export interface SDKConfig {
9
- /** Execution context: local (in-memory) or remote (RPC) */
10
- context?: 'local' | 'remote'
11
- /** RPC endpoint URL for all services (default: https://rpc.do) */
12
- rpcUrl?: string
13
- /** Database RPC URL (default: https://db.do/rpc) */
14
- dbUrl?: string
15
- /** AI RPC URL (default: https://ai.do/rpc) */
16
- aiUrl?: string
17
- /** Authentication token */
18
- token?: string
19
- /** Default namespace for database operations */
20
- ns?: string
21
- /** Cloudflare AI Gateway URL (e.g., https://gateway.ai.cloudflare.com/v1/{account}/{gateway}) */
22
- aiGatewayUrl?: string
23
- /** Cloudflare AI Gateway authentication token */
24
- aiGatewayToken?: string
25
- }
26
-
27
- /**
28
- * Network access configuration
29
- *
30
- * @example
31
- * fetch: true // allow all (default)
32
- * fetch: false // block all
33
- * fetch: null // block all (backwards compat)
34
- * fetch: ['api.example.com', '*.trusted.com'] // allowlist with wildcards
35
- */
36
- export type FetchConfig = boolean | null | string[]
37
-
38
- /**
39
- * Options for evaluate()
40
- */
41
- export interface EvaluateOptions {
42
- /** Module code with exports */
43
- module?: string | undefined
44
- /** Test code using vitest (describe, expect, it in global scope) */
45
- tests?: string | undefined
46
- /** Script code to run immediately (module exports in scope) */
47
- script?: string | undefined
48
- /** Timeout in milliseconds (default: 5000) */
49
- timeout?: number | undefined
50
- /** Environment variables to pass to the sandbox */
51
- env?: Record<string, string> | undefined
52
- /**
53
- * Network access control
54
- * - true: allow all (default)
55
- * - false/null: block all
56
- * - string[]: allowlist of domains (wildcards: '*.example.com')
57
- */
58
- fetch?: FetchConfig
59
- /** RPC services to expose via capnweb (URL -> handler) */
60
- rpc?: Record<string, unknown> | undefined
61
- /** Outbound RPC interceptor - intercepts fetch calls to RPC URLs */
62
- outboundRpc?: ((url: string, request: Request) => Promise<Response> | Response | null) | undefined
63
- /** SDK configuration - enables $, db, ai, api, on, send globals */
64
- sdk?: SDKConfig | boolean | undefined
65
- /** Top-level imports to hoist (for MDX test files with external imports) */
66
- imports?: string[] | undefined
67
- }
68
-
69
- /**
70
- * Result from evaluate()
71
- */
72
- export interface EvaluateResult {
73
- /** Whether execution succeeded */
74
- success: boolean
75
- /** Return value from script (if any) */
76
- value?: unknown
77
- /** Console output */
78
- logs: LogEntry[]
79
- /** Test results (if tests were provided) */
80
- testResults?: TestResults
81
- /** Error message if execution failed */
82
- error?: string
83
- /** Execution time in milliseconds */
84
- duration: number
85
- }
86
-
87
- /**
88
- * A log entry from console.log/warn/error
89
- */
90
- export interface LogEntry {
91
- level: 'log' | 'warn' | 'error' | 'info' | 'debug'
92
- message: string
93
- timestamp: number
94
- }
95
-
96
- /**
97
- * Test results from vitest-style tests
98
- */
99
- export interface TestResults {
100
- /** Total number of tests */
101
- total: number
102
- /** Number of passed tests */
103
- passed: number
104
- /** Number of failed tests */
105
- failed: number
106
- /** Number of skipped tests */
107
- skipped: number
108
- /** Individual test results */
109
- tests: TestResult[]
110
- /** Total duration in milliseconds */
111
- duration: number
112
- }
113
-
114
- /**
115
- * Individual test result
116
- */
117
- export interface TestResult {
118
- /** Test name (describe > it) */
119
- name: string
120
- /** Whether the test passed */
121
- passed: boolean
122
- /** Error message if failed */
123
- error?: string
124
- /** Test duration in milliseconds */
125
- duration: number
126
- }
127
-
128
- /**
129
- * Worker loader binding type (Cloudflare)
130
- */
131
- export interface WorkerLoader {
132
- get(id: string, loader: () => Promise<WorkerCode>): WorkerStub
133
- }
134
-
135
- /**
136
- * Worker code configuration
137
- */
138
- export interface WorkerCode {
139
- mainModule: string
140
- modules: Record<string, string | { js?: string; cjs?: string; text?: string; json?: unknown }>
141
- compatibilityDate?: string
142
- env?: Record<string, unknown>
143
- globalOutbound?: null | unknown
144
- }
145
-
146
- /**
147
- * Worker entrypoint with fetch method
148
- */
149
- export interface WorkerEntrypoint {
150
- fetch(request: Request): Promise<Response>
151
- }
152
-
153
- /**
154
- * Worker stub returned by loader
155
- */
156
- export interface WorkerStub {
157
- getEntrypoint(): WorkerEntrypoint
158
- }
159
-
160
- /**
161
- * Test service core - returned by connect() (from ai-tests)
162
- */
163
- export interface TestServiceCore {
164
- expect(value: unknown, message?: string): unknown
165
- should(value: unknown): unknown
166
- assert: unknown
167
- describe(name: string, fn: () => void): void
168
- it(name: string, fn: () => void | Promise<void>): void
169
- test(name: string, fn: () => void | Promise<void>): void
170
- skip(name: string, fn?: () => void | Promise<void>): void
171
- only(name: string, fn: () => void | Promise<void>): void
172
- beforeEach(fn: () => void | Promise<void>): void
173
- afterEach(fn: () => void | Promise<void>): void
174
- beforeAll(fn: () => void | Promise<void>): void
175
- afterAll(fn: () => void | Promise<void>): void
176
- run(): Promise<TestResults>
177
- reset(): void
178
- }
179
-
180
- /**
181
- * Test service binding type - WorkerEntrypoint (from ai-tests)
182
- */
183
- export interface TestServiceBinding {
184
- /** Get a test service instance via RPC */
185
- connect(): Promise<TestServiceCore>
186
- }
187
-
188
- /**
189
- * Environment with worker loader binding
190
- */
191
- export interface SandboxEnv {
192
- loader?: WorkerLoader
193
- LOADER?: WorkerLoader // Legacy - prefer lowercase
194
- test?: TestServiceBinding
195
- TEST?: TestServiceBinding // Legacy - prefer lowercase
196
- }
package/src/validation.ts DELETED
@@ -1,120 +0,0 @@
1
- /**
2
- * Input validation for EvaluateOptions
3
- *
4
- * Validates options to prevent resource exhaustion and provide clear error messages.
5
- */
6
-
7
- import type { EvaluateOptions } from './types.js'
8
-
9
- /**
10
- * Validation limits for EvaluateOptions
11
- */
12
- export const MAX_SCRIPT_SIZE = 1024 * 1024 // 1MB
13
- export const MAX_IMPORTS = 100
14
- export const MAX_TIMEOUT = 60000 // 60 seconds
15
- export const DEFAULT_TIMEOUT = 5000 // 5 seconds
16
-
17
- /**
18
- * Validation error thrown when options fail validation
19
- */
20
- export class ValidationError extends Error {
21
- constructor(message: string) {
22
- super(message)
23
- this.name = 'ValidationError'
24
- }
25
- }
26
-
27
- /**
28
- * Validate a URL string
29
- */
30
- function isValidUrl(urlString: string): boolean {
31
- try {
32
- const url = new URL(urlString)
33
- return url.protocol === 'http:' || url.protocol === 'https:'
34
- } catch {
35
- return false
36
- }
37
- }
38
-
39
- /**
40
- * Validate EvaluateOptions
41
- *
42
- * @throws ValidationError if any validation fails
43
- */
44
- export function validateOptions(options: EvaluateOptions): void {
45
- // Validate timeout
46
- if (options.timeout !== undefined) {
47
- if (typeof options.timeout !== 'number') {
48
- throw new ValidationError('timeout must be a number')
49
- }
50
- if (!Number.isFinite(options.timeout)) {
51
- throw new ValidationError('timeout must be a finite number')
52
- }
53
- if (options.timeout <= 0) {
54
- throw new ValidationError('timeout must be a positive number')
55
- }
56
- if (options.timeout > MAX_TIMEOUT) {
57
- throw new ValidationError(`timeout exceeds maximum allowed value of ${MAX_TIMEOUT}ms`)
58
- }
59
- }
60
-
61
- // Validate script length
62
- if (options.script !== undefined && options.script !== null) {
63
- if (typeof options.script !== 'string') {
64
- throw new ValidationError('script must be a string')
65
- }
66
- const scriptBytes = new TextEncoder().encode(options.script).length
67
- if (scriptBytes > MAX_SCRIPT_SIZE) {
68
- throw new ValidationError(
69
- `script size (${scriptBytes} bytes) exceeds maximum allowed size of ${MAX_SCRIPT_SIZE} bytes (1MB)`
70
- )
71
- }
72
- }
73
-
74
- // Validate module length
75
- if (options.module !== undefined && options.module !== null) {
76
- if (typeof options.module !== 'string') {
77
- throw new ValidationError('module must be a string')
78
- }
79
- const moduleBytes = new TextEncoder().encode(options.module).length
80
- if (moduleBytes > MAX_SCRIPT_SIZE) {
81
- throw new ValidationError(
82
- `module size (${moduleBytes} bytes) exceeds maximum allowed size of ${MAX_SCRIPT_SIZE} bytes (1MB)`
83
- )
84
- }
85
- }
86
-
87
- // Validate tests length
88
- if (options.tests !== undefined && options.tests !== null) {
89
- if (typeof options.tests !== 'string') {
90
- throw new ValidationError('tests must be a string')
91
- }
92
- const testsBytes = new TextEncoder().encode(options.tests).length
93
- if (testsBytes > MAX_SCRIPT_SIZE) {
94
- throw new ValidationError(
95
- `tests size (${testsBytes} bytes) exceeds maximum allowed size of ${MAX_SCRIPT_SIZE} bytes (1MB)`
96
- )
97
- }
98
- }
99
-
100
- // Validate imports
101
- if (options.imports !== undefined && options.imports !== null) {
102
- if (!Array.isArray(options.imports)) {
103
- throw new ValidationError('imports must be an array')
104
- }
105
- if (options.imports.length > MAX_IMPORTS) {
106
- throw new ValidationError(
107
- `imports count (${options.imports.length}) exceeds maximum allowed count of ${MAX_IMPORTS}`
108
- )
109
- }
110
- for (let i = 0; i < options.imports.length; i++) {
111
- const importUrl = options.imports[i]
112
- if (typeof importUrl !== 'string') {
113
- throw new ValidationError(`imports[${i}] must be a string`)
114
- }
115
- if (!isValidUrl(importUrl)) {
116
- throw new ValidationError(`imports[${i}] is not a valid URL: ${importUrl}`)
117
- }
118
- }
119
- }
120
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Module transformation and export detection utilities
3
- */
4
-
5
- /**
6
- * Transform module code to work in sandbox
7
- * Converts ES module exports to CommonJS-style for the sandbox
8
- */
9
- export function transformModuleCode(moduleCode: string): string {
10
- let code = moduleCode
11
-
12
- // Transform: export const foo = ... -> const foo = ...; exports.foo = foo;
13
- code = code.replace(/export\s+(const|let|var)\s+(\w+)\s*=/g, '$1 $2 = exports.$2 =')
14
-
15
- // Transform: export function foo(...) -> function foo(...) exports.foo = foo;
16
- // Also handles async generators: export async function* foo
17
- code = code.replace(/export\s+(async\s+)?function(\*?)\s+(\w+)/g, '$1function$2 $3')
18
- // Add exports for functions after their definition
19
- const funcNames = [...moduleCode.matchAll(/export\s+(?:async\s+)?function\*?\s+(\w+)/g)]
20
- for (const [, name] of funcNames) {
21
- code += `\nexports.${name} = ${name};`
22
- }
23
-
24
- // Transform: export class Foo -> class Foo; exports.Foo = Foo;
25
- code = code.replace(/export\s+class\s+(\w+)/g, 'class $1')
26
- const classNames = [...moduleCode.matchAll(/export\s+class\s+(\w+)/g)]
27
- for (const [, name] of classNames) {
28
- code += `\nexports.${name} = ${name};`
29
- }
30
-
31
- return code
32
- }