@tscircuit/eval 0.0.320 → 0.0.322
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.
- package/.github/workflows/bun-test.yml +15 -1
- package/dist/blob-url.js +1 -1
- package/dist/eval/index.d.ts +4 -1
- package/dist/eval/index.js +21 -60
- package/dist/lib/index.d.ts +4 -1
- package/dist/lib/index.js +21 -60
- package/dist/webworker/entrypoint.js +248 -248
- package/lib/index.ts +1 -0
- package/lib/runner/index.ts +1 -0
- package/lib/shared/static-asset-extensions.ts +10 -0
- package/package.json +2 -2
- package/tests/features/static-file-imports/static-file-import.test.ts +50 -0
- package/webworker/import-local-file.ts +8 -68
- package/tests/features/import-glb-file.test.tsx +0 -54
- package/tests/features/import-gltf-file.test.tsx +0 -78
- package/tests/features/import-obj-file.test.tsx +0 -49
package/lib/index.ts
CHANGED
package/lib/runner/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/eval",
|
|
3
3
|
"main": "dist/lib/index.js",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.322",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "bun run build:lib && bun run build:webworker && bun run build:blob-url && bun run build:runner && bun run build:worker-wrapper",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@tscircuit/math-utils": "^0.0.21",
|
|
68
68
|
"@tscircuit/miniflex": "^0.0.4",
|
|
69
69
|
"@tscircuit/parts-engine": "^0.0.8",
|
|
70
|
-
"@tscircuit/props": "0.0.
|
|
70
|
+
"@tscircuit/props": "0.0.320",
|
|
71
71
|
"@tscircuit/schematic-autolayout": "^0.0.6",
|
|
72
72
|
"@tscircuit/schematic-match-adapt": "^0.0.16",
|
|
73
73
|
"@tscircuit/schematic-trace-solver": "^0.0.36",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { createCircuitWebWorker } from "lib"
|
|
3
|
+
import { repoFileUrl } from "tests/fixtures/resourcePaths"
|
|
4
|
+
|
|
5
|
+
test("should import .glb file as string URL when projectBaseUrl is configured", async () => {
|
|
6
|
+
const circuitWebWorker = createCircuitWebWorker({
|
|
7
|
+
webWorkerUrl: repoFileUrl("dist/webworker/entrypoint.js").href,
|
|
8
|
+
platform: {
|
|
9
|
+
projectBaseUrl: "https://example.com/assets",
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const worker = await circuitWebWorker
|
|
14
|
+
|
|
15
|
+
await worker.executeWithFsMap({
|
|
16
|
+
fsMap: {
|
|
17
|
+
"index.tsx": `
|
|
18
|
+
import glbUrl from "./model.glb";
|
|
19
|
+
import kicadMod from "./footprint.kicad_mod";
|
|
20
|
+
|
|
21
|
+
export default () => {
|
|
22
|
+
return (
|
|
23
|
+
<board width="10mm" height="10mm">
|
|
24
|
+
<resistor resistance="1k" footprint="0402" name="R1" cadModel={{
|
|
25
|
+
glbUrl
|
|
26
|
+
}} />
|
|
27
|
+
</board>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
`,
|
|
31
|
+
"model.glb": "__STATIC_ASSET__",
|
|
32
|
+
"footprint.kicad_mod": "__STATIC_ASSET__",
|
|
33
|
+
},
|
|
34
|
+
mainComponentPath: "index.tsx",
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
await worker.renderUntilSettled()
|
|
38
|
+
|
|
39
|
+
// Verify the circuit rendered successfully (imports worked)
|
|
40
|
+
const circuitJson = await worker.getCircuitJson()
|
|
41
|
+
expect(circuitJson).toBeDefined()
|
|
42
|
+
|
|
43
|
+
const cadComponent = circuitJson.find((e) => e.type === "cad_component")!
|
|
44
|
+
|
|
45
|
+
expect(cadComponent.model_glb_url).toBe(
|
|
46
|
+
"https://example.com/assets/model.glb",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
await worker.kill()
|
|
50
|
+
})
|
|
@@ -9,6 +9,7 @@ import { evalCompiledJs } from "./eval-compiled-js"
|
|
|
9
9
|
import type { ExecutionContext } from "./execution-context"
|
|
10
10
|
import { importEvalPath } from "./import-eval-path"
|
|
11
11
|
import Debug from "debug"
|
|
12
|
+
import { isStaticAssetPath } from "lib/shared/static-asset-extensions"
|
|
12
13
|
|
|
13
14
|
const debug = Debug("tsci:eval:import-local-file")
|
|
14
15
|
|
|
@@ -24,8 +25,9 @@ export const importLocalFile = async (
|
|
|
24
25
|
const { fsMap, preSuppliedImports } = ctx
|
|
25
26
|
|
|
26
27
|
const fsPath = resolveFilePathOrThrow(importName, fsMap)
|
|
28
|
+
const isStaticAsset = isStaticAssetPath(fsPath)
|
|
27
29
|
debug("fsPath:", fsPath)
|
|
28
|
-
if (!ctx.fsMap[fsPath]) {
|
|
30
|
+
if (!ctx.fsMap[fsPath] && !isStaticAsset) {
|
|
29
31
|
debug("fsPath not found in fsMap:", fsPath)
|
|
30
32
|
throw new Error(`File "${fsPath}" not found`)
|
|
31
33
|
}
|
|
@@ -37,75 +39,13 @@ export const importLocalFile = async (
|
|
|
37
39
|
__esModule: true,
|
|
38
40
|
default: jsonData,
|
|
39
41
|
}
|
|
40
|
-
} else if (
|
|
41
|
-
const
|
|
42
|
-
|
|
42
|
+
} else if (isStaticAsset) {
|
|
43
|
+
const platformConfig = ctx.circuit.platform
|
|
44
|
+
// Use projectBaseUrl for static file imports
|
|
45
|
+
const staticUrl = `${platformConfig?.projectBaseUrl ?? ""}/${fsPath.startsWith("./") ? fsPath.slice(2) : fsPath}`
|
|
43
46
|
preSuppliedImports[fsPath] = {
|
|
44
47
|
__esModule: true,
|
|
45
|
-
default:
|
|
46
|
-
}
|
|
47
|
-
} else if (fsPath.endsWith(".glb")) {
|
|
48
|
-
const glbArray = Uint8Array.from(fileContent, (c) => c.charCodeAt(0))
|
|
49
|
-
const glbBlob = new Blob([glbArray], { type: "model/gltf-binary" })
|
|
50
|
-
const glbUrl = URL.createObjectURL(glbBlob)
|
|
51
|
-
preSuppliedImports[fsPath] = {
|
|
52
|
-
__esModule: true,
|
|
53
|
-
default: glbUrl,
|
|
54
|
-
}
|
|
55
|
-
} else if (fsPath.endsWith(".gltf")) {
|
|
56
|
-
const gltfJson = JSON.parse(fileContent)
|
|
57
|
-
const fileDir = dirname(fsPath)
|
|
58
|
-
|
|
59
|
-
const inlineUri = (uri: string) => {
|
|
60
|
-
if (uri && !uri.startsWith("data:") && !uri.startsWith("http")) {
|
|
61
|
-
const assetPath = resolveFilePath(uri, fsMap, fileDir)
|
|
62
|
-
if (!assetPath) {
|
|
63
|
-
console.warn(`Asset not found for URI: ${uri} in ${fsPath}`)
|
|
64
|
-
return uri
|
|
65
|
-
}
|
|
66
|
-
const assetContentStr = fsMap[assetPath]
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
const base64Content = btoa(assetContentStr)
|
|
70
|
-
|
|
71
|
-
let mimeType = "application/octet-stream"
|
|
72
|
-
if (assetPath.endsWith(".bin")) {
|
|
73
|
-
mimeType = "application/octet-stream"
|
|
74
|
-
} else if (assetPath.endsWith(".png")) {
|
|
75
|
-
mimeType = "image/png"
|
|
76
|
-
} else if (
|
|
77
|
-
assetPath.endsWith(".jpeg") ||
|
|
78
|
-
assetPath.endsWith(".jpg")
|
|
79
|
-
) {
|
|
80
|
-
mimeType = "image/jpeg"
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return `data:${mimeType};base64,${base64Content}`
|
|
84
|
-
} catch (e) {
|
|
85
|
-
console.error(`Failed to encode asset to base64: ${assetPath}`, e)
|
|
86
|
-
return uri
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return uri
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (gltfJson.buffers) {
|
|
93
|
-
for (const buffer of gltfJson.buffers) {
|
|
94
|
-
if (buffer.uri) buffer.uri = inlineUri(buffer.uri)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (gltfJson.images) {
|
|
98
|
-
for (const image of gltfJson.images) {
|
|
99
|
-
if (image.uri) image.uri = inlineUri(image.uri)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const gltfContent = JSON.stringify(gltfJson)
|
|
104
|
-
const gltfBlob = new Blob([gltfContent], { type: "model/gltf+json" })
|
|
105
|
-
const gltfUrl = URL.createObjectURL(gltfBlob)
|
|
106
|
-
preSuppliedImports[fsPath] = {
|
|
107
|
-
__esModule: true,
|
|
108
|
-
default: gltfUrl,
|
|
48
|
+
default: staticUrl,
|
|
109
49
|
}
|
|
110
50
|
} else if (fsPath.endsWith(".tsx") || fsPath.endsWith(".ts")) {
|
|
111
51
|
const importNames = getImportsFromCode(fileContent)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "bun:test"
|
|
2
|
-
import type { AnyCircuitElement, CadComponent } from "circuit-json"
|
|
3
|
-
import { CircuitRunner } from "lib/runner/CircuitRunner"
|
|
4
|
-
|
|
5
|
-
test("should support importing .glb files", async () => {
|
|
6
|
-
const runner = new CircuitRunner()
|
|
7
|
-
|
|
8
|
-
const glbContent = "This is a dummy glb file"
|
|
9
|
-
|
|
10
|
-
const fsMap = {
|
|
11
|
-
"my-model.glb": glbContent,
|
|
12
|
-
"user-code.tsx": `
|
|
13
|
-
import myGlbUrl from "./my-model.glb"
|
|
14
|
-
|
|
15
|
-
export default () => (
|
|
16
|
-
<chip
|
|
17
|
-
name="C1"
|
|
18
|
-
cadModel={{
|
|
19
|
-
gltfUrl: myGlbUrl,
|
|
20
|
-
}}
|
|
21
|
-
/>
|
|
22
|
-
)
|
|
23
|
-
`,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
await runner.executeWithFsMap({
|
|
27
|
-
fsMap,
|
|
28
|
-
mainComponentPath: "user-code.tsx",
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
await runner.renderUntilSettled()
|
|
32
|
-
const circuitJson = await runner.getCircuitJson()
|
|
33
|
-
|
|
34
|
-
const chip =
|
|
35
|
-
(circuitJson.find(
|
|
36
|
-
(elm) => elm.type === "source_component" && elm.name === "C1",
|
|
37
|
-
) as AnyCircuitElement) || undefined
|
|
38
|
-
const cadModel =
|
|
39
|
-
(circuitJson.find((elm) => elm.type === "cad_component") as CadComponent) ||
|
|
40
|
-
undefined
|
|
41
|
-
|
|
42
|
-
expect(chip).toBeDefined()
|
|
43
|
-
expect(cadModel?.model_gltf_url).toBeString()
|
|
44
|
-
expect(cadModel?.model_gltf_url).toStartWith("blob:")
|
|
45
|
-
|
|
46
|
-
if (cadModel?.model_gltf_url) {
|
|
47
|
-
const response = await fetch(cadModel.model_gltf_url)
|
|
48
|
-
const arrayBuffer = await response.arrayBuffer()
|
|
49
|
-
const text = new TextDecoder().decode(arrayBuffer)
|
|
50
|
-
expect(text).toBe(glbContent)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await runner.kill()
|
|
54
|
-
})
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "bun:test"
|
|
2
|
-
import type { AnyCircuitElement, CadComponent } from "circuit-json"
|
|
3
|
-
import { CircuitRunner } from "lib/runner/CircuitRunner"
|
|
4
|
-
|
|
5
|
-
test("should support importing .gltf files with binary", async () => {
|
|
6
|
-
const runner = new CircuitRunner()
|
|
7
|
-
|
|
8
|
-
const gltfContent = {
|
|
9
|
-
asset: { version: "2.0" },
|
|
10
|
-
scenes: [{ nodes: [0] }],
|
|
11
|
-
nodes: [{ mesh: 0 }],
|
|
12
|
-
meshes: [
|
|
13
|
-
{
|
|
14
|
-
primitives: [{ attributes: { POSITION: 0 } }],
|
|
15
|
-
},
|
|
16
|
-
],
|
|
17
|
-
buffers: [{ uri: "model.bin", byteLength: 36 }],
|
|
18
|
-
bufferViews: [{ buffer: 0, byteOffset: 0, byteLength: 36 }],
|
|
19
|
-
accessors: [
|
|
20
|
-
{
|
|
21
|
-
bufferView: 0,
|
|
22
|
-
componentType: 5126, // FLOAT
|
|
23
|
-
count: 3,
|
|
24
|
-
type: "VEC3",
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const binContent = "This is a dummy binary file content.".padEnd(36, "\0")
|
|
30
|
-
|
|
31
|
-
const fsMap = {
|
|
32
|
-
"my-model.gltf": JSON.stringify(gltfContent),
|
|
33
|
-
"model.bin": binContent,
|
|
34
|
-
"user-code.tsx": `
|
|
35
|
-
import myGltfUrl from "./my-model.gltf"
|
|
36
|
-
|
|
37
|
-
export default () => (
|
|
38
|
-
<chip
|
|
39
|
-
name="C1"
|
|
40
|
-
cadModel={{
|
|
41
|
-
gltfUrl: myGltfUrl,
|
|
42
|
-
}}
|
|
43
|
-
/>
|
|
44
|
-
)
|
|
45
|
-
`,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
await runner.executeWithFsMap({
|
|
49
|
-
fsMap,
|
|
50
|
-
mainComponentPath: "user-code.tsx",
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
await runner.renderUntilSettled()
|
|
54
|
-
const circuitJson = await runner.getCircuitJson()
|
|
55
|
-
|
|
56
|
-
const chip =
|
|
57
|
-
(circuitJson.find(
|
|
58
|
-
(elm) => elm.type === "source_component" && elm.name === "C1",
|
|
59
|
-
) as AnyCircuitElement) || undefined
|
|
60
|
-
const cadModel =
|
|
61
|
-
(circuitJson.find((elm) => elm.type === "cad_component") as CadComponent) ||
|
|
62
|
-
undefined
|
|
63
|
-
|
|
64
|
-
expect(chip).toBeDefined()
|
|
65
|
-
expect(cadModel?.model_gltf_url).toBeString()
|
|
66
|
-
expect(cadModel?.model_gltf_url).toStartWith("blob:")
|
|
67
|
-
|
|
68
|
-
if (cadModel?.model_gltf_url) {
|
|
69
|
-
const response = await fetch(cadModel.model_gltf_url)
|
|
70
|
-
const text = await response.text()
|
|
71
|
-
const json = JSON.parse(text)
|
|
72
|
-
expect(json.buffers[0].uri).toStartWith(
|
|
73
|
-
"data:application/octet-stream;base64,",
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await runner.kill()
|
|
78
|
-
})
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "bun:test"
|
|
2
|
-
import type {
|
|
3
|
-
AnyCircuitElement,
|
|
4
|
-
AnySourceComponent,
|
|
5
|
-
CadComponent,
|
|
6
|
-
} from "circuit-json"
|
|
7
|
-
import { CircuitRunner } from "lib/runner/CircuitRunner"
|
|
8
|
-
|
|
9
|
-
test("should support importing .obj files", async () => {
|
|
10
|
-
const runner = new CircuitRunner()
|
|
11
|
-
|
|
12
|
-
const fsMap = {
|
|
13
|
-
"my-model.obj": `v 1.0 1.0 0.0`, // some dummy obj content
|
|
14
|
-
"user-code.tsx": `
|
|
15
|
-
import myObjUrl from "./my-model.obj"
|
|
16
|
-
|
|
17
|
-
export default () => (
|
|
18
|
-
<chip
|
|
19
|
-
name="C1"
|
|
20
|
-
cadModel={{
|
|
21
|
-
objUrl: myObjUrl,
|
|
22
|
-
}}
|
|
23
|
-
/>
|
|
24
|
-
)
|
|
25
|
-
`,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
await runner.executeWithFsMap({
|
|
29
|
-
fsMap,
|
|
30
|
-
mainComponentPath: "user-code.tsx",
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
await runner.renderUntilSettled()
|
|
34
|
-
const circuitJson = await runner.getCircuitJson()
|
|
35
|
-
|
|
36
|
-
const chip =
|
|
37
|
-
(circuitJson.find(
|
|
38
|
-
(elm) => elm.type === "source_component" && elm.name === "C1",
|
|
39
|
-
) as AnyCircuitElement) || undefined
|
|
40
|
-
const cadModel =
|
|
41
|
-
(circuitJson.find((elm) => elm.type === "cad_component") as CadComponent) ||
|
|
42
|
-
undefined
|
|
43
|
-
|
|
44
|
-
expect(chip).toBeDefined()
|
|
45
|
-
expect(cadModel?.model_obj_url).toBeString()
|
|
46
|
-
expect(cadModel?.model_obj_url).toStartWith("blob:")
|
|
47
|
-
|
|
48
|
-
await runner.kill()
|
|
49
|
-
})
|