@tscircuit/eval 0.0.311 → 0.0.312

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/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.311",
4
+ "version": "0.0.312",
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",
@@ -0,0 +1,42 @@
1
+ import { test, expect } from "bun:test"
2
+ import { runTscircuitCode } from "lib/runner"
3
+
4
+ test(
5
+ "should support importing various npm packages",
6
+ async () => {
7
+ const circuitJson = await runTscircuitCode(
8
+ `
9
+ import _ from "lodash"
10
+ import { v4 as uuidv4 } from "uuid"
11
+ import dayjs from "dayjs"
12
+
13
+ export default () => {
14
+ // Test lodash
15
+ if (!_.isEqual({ a: 1 }, { a: 1 })) {
16
+ throw new Error("_.isEqual failed")
17
+ }
18
+
19
+ // Test uuid
20
+ const uuid = uuidv4()
21
+ if (typeof uuid !== "string" || uuid.length < 36) {
22
+ throw new Error("uuid.v4 failed to generate a valid uuid")
23
+ }
24
+
25
+ // Test dayjs
26
+ if (!dayjs().isValid()) {
27
+ throw new Error("dayjs().isValid() failed")
28
+ }
29
+
30
+ return <resistor name="R1" resistance="1k" />
31
+ }
32
+ `,
33
+ )
34
+
35
+ const resistor = circuitJson.find(
36
+ (element) => element.type === "source_component" && element.name === "R1",
37
+ )
38
+
39
+ expect(resistor).toBeDefined()
40
+ },
41
+ { timeout: 15000 },
42
+ )
@@ -6,6 +6,7 @@ import { importSnippet } from "./import-snippet"
6
6
  import { resolveFilePath } from "lib/runner/resolveFilePath"
7
7
  import { resolveNodeModule } from "lib/utils/resolve-node-module"
8
8
  import { importNodeModule } from "./import-node-module"
9
+ import { importNpmPackage } from "./import-npm-package"
9
10
  import Debug from "debug"
10
11
 
11
12
  const debug = Debug("tsci:eval:import-eval-path")
@@ -59,6 +60,10 @@ export async function importEvalPath(
59
60
  return importSnippet(importName, ctx, depth)
60
61
  }
61
62
 
63
+ if (!importName.startsWith(".") && !importName.startsWith("/")) {
64
+ return importNpmPackage(importName, ctx)
65
+ }
66
+
62
67
  throw new Error(
63
68
  `Unresolved import "${importName}" ${opts.cwd ? `from directory "${opts.cwd}"` : ""}`,
64
69
  )
@@ -0,0 +1,69 @@
1
+ import { evalCompiledJs } from "./eval-compiled-js"
2
+ import type { ExecutionContext } from "./execution-context"
3
+ import * as Babel from "@babel/standalone"
4
+ import { dirname } from "lib/utils/dirname"
5
+ import Debug from "debug"
6
+
7
+ const debug = Debug("tsci:eval:import-npm-package")
8
+
9
+ function extractPackagePathFromJSDelivr(url: string) {
10
+ const prefix = "https://cdn.jsdelivr.net/npm/"
11
+ if (url.startsWith(prefix)) {
12
+ return url.substring(prefix.length).replace(/\/\+esm$/, "")
13
+ }
14
+ return url
15
+ }
16
+
17
+ export async function importNpmPackage(
18
+ importName: string,
19
+ ctx: ExecutionContext,
20
+ ) {
21
+ debug(`importing npm package: ${importName}`)
22
+ const { preSuppliedImports } = ctx
23
+
24
+ if (preSuppliedImports[importName]) return
25
+
26
+ const npmCdnUrl = `https://cdn.jsdelivr.net/npm/${importName}/+esm`
27
+
28
+ let finalUrl: string | undefined
29
+ const { content, error } = await globalThis
30
+ .fetch(npmCdnUrl)
31
+ .then(async (res) => {
32
+ finalUrl = res.url
33
+ if (!res.ok)
34
+ throw new Error(
35
+ `Could not fetch "${importName}" from jsdelivr: ${res.statusText}`,
36
+ )
37
+ return { content: await res.text(), error: null }
38
+ })
39
+ .catch((e) => ({ error: e, content: null }))
40
+
41
+ if (error) {
42
+ console.error("Error fetching npm import", importName, error)
43
+ throw error
44
+ }
45
+
46
+ const transpiled = Babel.transform(content!, {
47
+ presets: ["react", "env"],
48
+ plugins: ["transform-modules-commonjs"],
49
+ filename: importName,
50
+ })
51
+
52
+ if (!transpiled.code) {
53
+ throw new Error(`Babel transpilation failed for ${importName}`)
54
+ }
55
+ try {
56
+ const finalImportName = extractPackagePathFromJSDelivr(finalUrl!)
57
+ const cwd = dirname(finalImportName)
58
+ const exports = evalCompiledJs(
59
+ transpiled.code!,
60
+ preSuppliedImports,
61
+ cwd,
62
+ ).exports
63
+ preSuppliedImports[importName] = exports
64
+ preSuppliedImports[finalImportName] = exports
65
+ preSuppliedImports[finalUrl!] = exports
66
+ } catch (e: any) {
67
+ throw new Error(`Eval npm package error for "${importName}": ${e.message}`)
68
+ }
69
+ }