@tscircuit/eval 0.0.288 → 0.0.290

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 (47) hide show
  1. package/.github/workflows/bun-test.yml +20 -2
  2. package/dist/blob-url.js +1 -1
  3. package/dist/eval/index.d.ts +56 -8
  4. package/dist/eval/index.js +17 -1
  5. package/dist/lib/index.d.ts +57 -8
  6. package/dist/lib/index.js +66 -1
  7. package/dist/webworker/entrypoint.js +352 -349
  8. package/dist/worker.d.ts +1 -0
  9. package/dist/worker.js +50 -1
  10. package/lib/runner/CircuitRunner.ts +19 -0
  11. package/lib/shared/types.ts +2 -0
  12. package/lib/worker.ts +61 -0
  13. package/package.json +9 -7
  14. package/scripts/validate-test-matrix.js +148 -0
  15. package/tests/{example1-readme-example.test.tsx → examples/example01-readme-example.test.tsx} +1 -1
  16. package/tests/{example2-multiple-files.test.tsx → examples/example02-multiple-files.test.tsx} +1 -1
  17. package/tests/{example3-encoded-url.test.tsx → examples/example03-encoded-url.test.tsx} +1 -1
  18. package/tests/{example4-root-child-issue.test.tsx → examples/example04-root-child-issue.test.tsx} +1 -1
  19. package/tests/{example5-event-recording.test.tsx → examples/example05-event-recording.test.tsx} +1 -1
  20. package/tests/{example7-import-default-and-namespace.test.tsx → examples/example07-import-default-and-namespace.test.tsx} +2 -2
  21. package/tests/{example8-footprinter-to220.test.tsx → examples/example08-footprinter-to220.test.tsx} +1 -1
  22. package/tests/{example9-not-defined-component.test.tsx → examples/example09-not-defined-component.test.tsx} +1 -1
  23. package/tests/{example13-webworker-without-entrypoint.test.tsx → examples/example13-webworker-without-entrypoint.test.tsx} +1 -1
  24. package/tests/{example16-parts-engine.test.tsx → examples/example16-parts-engine.test.tsx} +1 -1
  25. package/tests/{example17-parse-tscircuit-config.test.tsx → examples/example17-parse-tscircuit-config.test.tsx} +1 -1
  26. package/tests/{circuit-event-forwarding.test.tsx → features/circuit-event-forwarding.test.tsx} +1 -1
  27. package/tests/features/execute-component-runner.test.tsx +47 -0
  28. package/tests/features/execute-component-worker.test.tsx +25 -0
  29. package/tests/{fetch-override.test.ts → features/fetch-proxy/fetch-override.test.ts} +3 -3
  30. package/tests/{fetch-proxy-validation.test.ts → features/fetch-proxy/fetch-proxy-validation.test.ts} +5 -7
  31. package/tests/{kill.test.ts → features/kill.test.ts} +5 -3
  32. package/tests/{manual-edits.test.tsx → features/manual-edits.test.tsx} +2 -2
  33. package/tests/fixtures/resourcePaths.ts +3 -0
  34. package/webworker/entrypoint.ts +58 -2
  35. /package/tests/{example6-dynamic-load-blob-url.test.tsx → examples/example06-dynamic-load-blob-url.test.tsx} +0 -0
  36. /package/tests/{example10-run-tscircuit-code.test.tsx → examples/example10-run-tscircuit-code.test.tsx} +0 -0
  37. /package/tests/{example11-flexible-import-extensions.test.tsx → examples/example11-flexible-import-extensions.test.tsx} +0 -0
  38. /package/tests/{example12-import-from-subdirectory.test.tsx → examples/example12-import-from-subdirectory.test.tsx} +0 -0
  39. /package/tests/{example14-run-tscircuit-module.test.tsx → examples/example14-run-tscircuit-module.test.tsx} +0 -0
  40. /package/tests/{example15-run-tscircuit-module-with-props.test.tsx → examples/example15-run-tscircuit-module-with-props.test.tsx} +0 -0
  41. /package/tests/{parent-directory-import.test.tsx → features/parent-directory-import.test.tsx} +0 -0
  42. /package/tests/{platform-config.test.tsx → features/platform-config.test.tsx} +0 -0
  43. /package/tests/{prioritize-default-export.test.tsx → features/prioritize-default-export.test.tsx} +0 -0
  44. /package/tests/{group-wrapper.test.tsx → repros/group-wrapper.test.tsx} +0 -0
  45. /package/tests/{nine-keyboard-default-export.test.tsx → repros/nine-keyboard-default-export.test.tsx} +0 -0
  46. /package/tests/{get-imports-from-code.test.tsx → util-fns/get-imports-from-code.test.tsx} +0 -0
  47. /package/tests/{getPossibleEntrypointComponentPaths.test.ts → util-fns/getPossibleEntrypointComponentPaths.test.ts} +0 -0
@@ -0,0 +1,25 @@
1
+ import { expect, test } from "bun:test"
2
+ import * as React from "react"
3
+ import { createCircuitWebWorker } from "lib"
4
+ import { repoFileUrl } from "tests/fixtures/resourcePaths"
5
+
6
+ test("CircuitWebWorker.executeComponent with factory function", async () => {
7
+ const worker = await createCircuitWebWorker({
8
+ webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
9
+ })
10
+
11
+ await worker.executeComponent(
12
+ <board>
13
+ <resistor name="R1" resistance="1k" />
14
+ </board>,
15
+ )
16
+
17
+ await worker.renderUntilSettled()
18
+ const circuitJson = await worker.getCircuitJson()
19
+ const R1 = circuitJson.find(
20
+ (el: any) => el.type === "source_component" && el.name === "R1",
21
+ )
22
+ expect(R1).toBeDefined()
23
+
24
+ await worker.kill()
25
+ })
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect } from "bun:test"
2
- import { createCircuitWebWorker } from "../lib"
2
+ import { createCircuitWebWorker } from "lib"
3
+ import { repoFileUrl } from "tests/fixtures/resourcePaths"
3
4
 
4
5
  describe("fetch override", () => {
5
6
  it("allows worker to fetch via parent and propagates errors", async () => {
@@ -15,8 +16,7 @@ describe("fetch override", () => {
15
16
  globalThis.fetch = fakeFetch as any
16
17
 
17
18
  const worker = await createCircuitWebWorker({
18
- webWorkerUrl: new URL("../dist/webworker/entrypoint.js", import.meta.url)
19
- .href,
19
+ webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
20
20
  enableFetchProxy: true,
21
21
  })
22
22
 
@@ -1,11 +1,11 @@
1
1
  import { describe, it, expect } from "bun:test"
2
- import { createCircuitWebWorker } from "../lib"
2
+ import { createCircuitWebWorker } from "lib"
3
+ import { repoFileUrl } from "tests/fixtures/resourcePaths"
3
4
 
4
5
  describe("fetch proxy validation", () => {
5
6
  it("should NOT proxy fetch requests when enableFetchProxy is false (default)", async () => {
6
7
  const worker = await createCircuitWebWorker({
7
- webWorkerUrl: new URL("../dist/webworker/entrypoint.js", import.meta.url)
8
- .href,
8
+ webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
9
9
  // enableFetchProxy not set, should default to false
10
10
  })
11
11
 
@@ -31,8 +31,7 @@ fetch("https://example.com/test")
31
31
 
32
32
  it("should proxy fetch requests when enableFetchProxy is true", async () => {
33
33
  const worker = await createCircuitWebWorker({
34
- webWorkerUrl: new URL("../dist/webworker/entrypoint.js", import.meta.url)
35
- .href,
34
+ webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
36
35
  enableFetchProxy: true,
37
36
  })
38
37
 
@@ -67,8 +66,7 @@ fetch("https://example.com/test")
67
66
  globalThis.fetch = fakeFetch as any
68
67
 
69
68
  const worker = await createCircuitWebWorker({
70
- webWorkerUrl: new URL("../dist/webworker/entrypoint.js", import.meta.url)
71
- .href,
69
+ webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
72
70
  enableFetchProxy: true,
73
71
  })
74
72
 
@@ -1,11 +1,13 @@
1
1
  import { describe, it, expect } from "bun:test"
2
- import { createCircuitWebWorker } from "../lib"
2
+ import { createCircuitWebWorker } from "lib"
3
3
 
4
4
  describe("kill method", () => {
5
5
  it("should immediately terminate the worker", async () => {
6
6
  const worker = await createCircuitWebWorker({
7
- webWorkerUrl: new URL("../dist/webworker/entrypoint.js", import.meta.url)
8
- .href,
7
+ webWorkerUrl: new URL(
8
+ "../../dist/webworker/entrypoint.js",
9
+ import.meta.url,
10
+ ).href,
9
11
  })
10
12
 
11
13
  // Ensure worker is running
@@ -59,7 +59,7 @@ const example2 = {
59
59
 
60
60
  test("example1: Manual edits in entrypoint.tsx file", async () => {
61
61
  const circuitWebWorker = await createCircuitWebWorker({
62
- webWorkerUrl: new URL("../webworker/index.ts", import.meta.url),
62
+ webWorkerUrl: new URL("../../webworker/index.ts", import.meta.url),
63
63
  })
64
64
 
65
65
  await circuitWebWorker.executeWithFsMap({
@@ -89,7 +89,7 @@ test("example1: Manual edits in entrypoint.tsx file", async () => {
89
89
 
90
90
  test("example2: Manual edits in manual-edits.json file", async () => {
91
91
  const circuitWebWorker = await createCircuitWebWorker({
92
- webWorkerUrl: new URL("../webworker/index.ts", import.meta.url),
92
+ webWorkerUrl: new URL("../../webworker/index.ts", import.meta.url),
93
93
  })
94
94
 
95
95
  await circuitWebWorker.executeWithFsMap({
@@ -0,0 +1,3 @@
1
+ export const repoFileUrl = (pathFromRoot: string) => {
2
+ return new URL(`../../${pathFromRoot}`, import.meta.url)
3
+ }
@@ -11,7 +11,7 @@ import {
11
11
  type ExecutionContext,
12
12
  } from "./execution-context"
13
13
  import { importEvalPath } from "./import-eval-path"
14
- import { normalizeFsMap } from "../lib/runner/normalizeFsMap"
14
+ import { normalizeFsMap } from "lib/runner/normalizeFsMap"
15
15
  import type { RootCircuit } from "@tscircuit/core"
16
16
  import { setupDefaultEntrypointIfNeeded } from "lib/runner/setupDefaultEntrypointIfNeeded"
17
17
  import { setupFetchProxy } from "./fetchProxy"
@@ -30,6 +30,40 @@ const circuitRunnerConfiguration: WebWorkerConfiguration = {
30
30
 
31
31
  const eventListeners: Record<string, ((...args: any[]) => void)[]> = {}
32
32
 
33
+ // Helper to deserialize React elements from cross-worker communication
34
+ function deserializeReactElement(serialized: any): any {
35
+ if (!serialized || typeof serialized !== "object") {
36
+ return serialized
37
+ }
38
+
39
+ if (serialized.__isSerializedReactElement) {
40
+ const props = deserializeProps(serialized.props)
41
+ return React.createElement(serialized.type, props)
42
+ }
43
+
44
+ return serialized
45
+ }
46
+
47
+ function deserializeProps(props: any): any {
48
+ if (!props || typeof props !== "object") {
49
+ return props
50
+ }
51
+
52
+ const deserialized: any = {}
53
+ for (const [key, value] of Object.entries(props)) {
54
+ if (key === "children") {
55
+ if (Array.isArray(value)) {
56
+ deserialized.children = value.map(deserializeReactElement)
57
+ } else {
58
+ deserialized.children = deserializeReactElement(value)
59
+ }
60
+ } else {
61
+ deserialized[key] = value
62
+ }
63
+ }
64
+ return deserialized
65
+ }
66
+
33
67
  function bindEventListeners(circuit: RootCircuit) {
34
68
  for (const event in eventListeners) {
35
69
  for (const listener of eventListeners[event]) {
@@ -100,6 +134,28 @@ const webWorkerApi = {
100
134
  await importEvalPath("./entrypoint.tsx", executionContext)
101
135
  },
102
136
 
137
+ async executeComponent(component: any, opts: { name?: string } = {}) {
138
+ if (circuitRunnerConfiguration.verbose) {
139
+ console.log("[Worker] executeComponent called")
140
+ }
141
+ executionContext = createExecutionContext(circuitRunnerConfiguration, {
142
+ ...opts,
143
+ platform: circuitRunnerConfiguration.platform,
144
+ })
145
+ bindEventListeners(executionContext.circuit)
146
+ ;(globalThis as any).__tscircuit_circuit = executionContext.circuit
147
+
148
+ let element: any
149
+ if (typeof component === "function") {
150
+ element = component()
151
+ } else if (component && component.__isSerializedReactElement) {
152
+ element = deserializeReactElement(component)
153
+ } else {
154
+ element = component
155
+ }
156
+ executionContext.circuit.add(element as any)
157
+ },
158
+
103
159
  on: (event: string, callback: (...args: any[]) => void) => {
104
160
  eventListeners[event] ??= []
105
161
  eventListeners[event].push(callback)
@@ -131,7 +187,7 @@ const webWorkerApi = {
131
187
  listener: (...args: any[]) => void,
132
188
  ) => void
133
189
  }
134
- if (typeof circuit.removeListener === "function") {
190
+ if (circuit.removeListener) {
135
191
  circuit.removeListener(event, listener)
136
192
  }
137
193
  }