-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
182 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import type { AnyCircuitElement } from "circuit-json" | ||
import type { | ||
CircuitRunnerApi, | ||
CircuitRunnerConfiguration, | ||
} from "lib/shared/types" | ||
import { createExecutionContext } from "../../webworker/execution-context" | ||
import { normalizeFsMap } from "../../webworker/normalize-fs-map" | ||
import type { RootCircuit } from "@tscircuit/core" | ||
import * as React from "react" | ||
import { importEvalPath } from "webworker/import-eval-path" | ||
|
||
export class CircuitRunner implements CircuitRunnerApi { | ||
_executionContext: ReturnType<typeof createExecutionContext> | null = null | ||
_circuitRunnerConfiguration: CircuitRunnerConfiguration = { | ||
snippetsApiBaseUrl: "https://registry-api.tscircuit.com", | ||
cjsRegistryUrl: "https://cjs.tscircuit.com", | ||
verbose: false, | ||
} | ||
_eventListeners: Record<string, ((...args: any[]) => void)[]> = {} | ||
|
||
async executeWithFsMap(opts: { | ||
entrypoint: string | ||
fsMap: Record<string, string> | ||
name?: string | ||
}): Promise<void> { | ||
if (this._circuitRunnerConfiguration.verbose) { | ||
console.log("[CircuitRunner] executeWithFsMap called with:", { | ||
entrypoint: opts.entrypoint, | ||
fsMapKeys: Object.keys(opts.fsMap), | ||
name: opts.name, | ||
}) | ||
} | ||
|
||
this._executionContext = createExecutionContext( | ||
this._circuitRunnerConfiguration, | ||
{ | ||
name: opts.name, | ||
}, | ||
) | ||
this._bindEventListeners(this._executionContext.circuit) | ||
|
||
this._executionContext.fsMap = normalizeFsMap(opts.fsMap) | ||
if (!this._executionContext.fsMap[opts.entrypoint]) { | ||
throw new Error(`Entrypoint "${opts.entrypoint}" not found`) | ||
} | ||
;(globalThis as any).__tscircuit_circuit = this._executionContext.circuit | ||
|
||
const entrypoint = opts.entrypoint.startsWith("./") | ||
? opts.entrypoint | ||
: `./${opts.entrypoint}` | ||
|
||
await importEvalPath(entrypoint, this._executionContext) | ||
} | ||
|
||
async execute(code: string, opts: { name?: string } = {}) { | ||
if (this._circuitRunnerConfiguration.verbose) { | ||
console.log( | ||
"[CircuitRunner] execute called with code length:", | ||
code.length, | ||
) | ||
} | ||
|
||
this._executionContext = createExecutionContext( | ||
this._circuitRunnerConfiguration, | ||
opts, | ||
) | ||
this._bindEventListeners(this._executionContext.circuit) | ||
this._executionContext.fsMap["entrypoint.tsx"] = code | ||
;(globalThis as any).__tscircuit_circuit = this._executionContext.circuit | ||
|
||
await importEvalPath("./entrypoint.tsx", this._executionContext) | ||
} | ||
|
||
on(event: string, callback: (...args: any[]) => void) { | ||
this._eventListeners[event] ??= [] | ||
this._eventListeners[event].push(callback) | ||
this._executionContext?.circuit.on(event as any, callback) | ||
} | ||
|
||
async renderUntilSettled(): Promise<void> { | ||
if (!this._executionContext) { | ||
throw new Error("No circuit has been created") | ||
} | ||
await this._executionContext.circuit.renderUntilSettled() | ||
} | ||
|
||
async getCircuitJson(): Promise<AnyCircuitElement[]> { | ||
if (!this._executionContext) { | ||
throw new Error("No circuit has been created") | ||
} | ||
return this._executionContext.circuit.getCircuitJson() | ||
} | ||
|
||
clearEventListeners() { | ||
if (this._executionContext?.circuit) { | ||
for (const event in this._eventListeners) { | ||
for (const listener of this._eventListeners[event]) { | ||
const circuit = this._executionContext.circuit as unknown as { | ||
// biome-ignore lint/complexity/noBannedTypes: <explanation> | ||
removeListener?: (event: string, listener: Function) => void | ||
} | ||
circuit.removeListener?.(event, listener) | ||
} | ||
} | ||
} | ||
|
||
for (const event in this._eventListeners) { | ||
delete this._eventListeners[event] | ||
} | ||
} | ||
|
||
async kill() { | ||
// Cleanup resources | ||
this._executionContext = null | ||
} | ||
|
||
async setSnippetsApiBaseUrl(baseUrl: string) { | ||
this._circuitRunnerConfiguration.snippetsApiBaseUrl = baseUrl | ||
} | ||
|
||
private _bindEventListeners(circuit: RootCircuit) { | ||
for (const event in this._eventListeners) { | ||
for (const listener of this._eventListeners[event]) { | ||
circuit.on(event as any, listener as any) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./CircuitRunner" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
tests/circuit-runner/circuitrunner1-readme-example.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { createCircuitWebWorker } from "lib" | ||
import { expect, test } from "bun:test" | ||
import { CircuitRunner } from "lib/eval/CircuitRunner" | ||
|
||
test("circuitrunner1-readme-example", async () => { | ||
const circuitRunner = new CircuitRunner() | ||
|
||
await circuitRunner.execute(` | ||
import { RedLed } from "@tsci/seveibar.red-led" | ||
circuit.add( | ||
<board width="10mm" height="10mm"> | ||
<RedLed name="LED1" /> | ||
</board> | ||
) | ||
`) | ||
|
||
await circuitRunner.renderUntilSettled() | ||
|
||
const circuitJson = await circuitRunner.getCircuitJson() | ||
|
||
expect(circuitJson).toBeDefined() | ||
|
||
const led = circuitJson.find((el: any) => el.name === "LED1") | ||
expect(led).toBeDefined() | ||
expect(led?.type).toBe("source_component") | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters