circuit-json-to-tscircuit 0.0.1 → 0.0.3

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.
@@ -0,0 +1,26 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Format Check
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ jobs:
11
+ format-check:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+
17
+ - name: Setup bun
18
+ uses: oven-sh/setup-bun@v1
19
+ with:
20
+ bun-version: latest
21
+
22
+ - name: Install dependencies
23
+ run: bun install
24
+
25
+ - name: Run format check
26
+ run: bun run format:check
@@ -0,0 +1,25 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Publish to npm
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v3
12
+ - name: Setup bun
13
+ uses: oven-sh/setup-bun@v1
14
+ with:
15
+ bun-version: latest
16
+ - uses: actions/setup-node@v3
17
+ with:
18
+ node-version: 20
19
+ registry-url: https://registry.npmjs.org/
20
+ - run: npm install -g pver
21
+ - run: bun install --frozen-lockfile
22
+ - run: bun run build
23
+ - run: pver release
24
+ env:
25
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,25 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Bun Test
3
+
4
+ on:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ timeout-minutes: 5
11
+
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Setup bun
17
+ uses: oven-sh/setup-bun@v1
18
+ with:
19
+ bun-version: latest
20
+
21
+ - name: Install dependencies
22
+ run: bun install
23
+
24
+ - name: Run tests
25
+ run: bun test
@@ -0,0 +1,26 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Type Check
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ jobs:
11
+ type-check:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+
17
+ - name: Setup bun
18
+ uses: oven-sh/setup-bun@v1
19
+ with:
20
+ bun-version: latest
21
+
22
+ - name: Install dependencies
23
+ run: bun i
24
+
25
+ - name: Run type check
26
+ run: bunx tsc --noEmit
package/README.md CHANGED
@@ -3,3 +3,20 @@
3
3
  Convert [circuit json](https://github.com/tscircuit/circuit-json) code to [tscircuit](https://github.com/tscircuit/tscircuit) code.
4
4
 
5
5
  ## Usage
6
+
7
+ ```bash
8
+ bun add circuit-json-to-tscircuit
9
+ ```
10
+
11
+ ```tsx
12
+ import { convertCircuitJsonToTscircuit } from "circuit-json-to-tscircuit"
13
+
14
+ const circuitJson = await fetch("https://tscircuit.com/circuit.json")
15
+
16
+ const tscircuit = convertCircuitJsonToTscircuit(circuitJson)
17
+ console.log(tscircuit)
18
+
19
+ /**
20
+
21
+ */
22
+ ```
package/bun.lockb CHANGED
Binary file
package/dist/index.d.ts CHANGED
@@ -1,5 +1,14 @@
1
- import { CircuitJson } from 'circuit-json';
1
+ import { AnyCircuitElement, CircuitJson } from 'circuit-json';
2
2
 
3
- declare const convertCircuitJsonToTscircuit: (circuitJson: CircuitJson) => string;
3
+ interface ComponentTemplateParams {
4
+ pinLabels?: Record<string, string[]> | Record<string, string>;
5
+ componentName: string;
6
+ objUrl?: string;
7
+ circuitJson: AnyCircuitElement[];
8
+ supplierPartNumbers?: Record<string, string[]>;
9
+ manufacturerPartNumber?: string;
10
+ }
11
+
12
+ declare const convertCircuitJsonToTscircuit: (circuitJson: CircuitJson, opts: Omit<ComponentTemplateParams, "circuitJson">) => string;
4
13
 
5
14
  export { convertCircuitJsonToTscircuit };
package/dist/index.js CHANGED
@@ -1,6 +1,103 @@
1
+ // lib/generate-footprint-tsx.tsx
2
+ import { mmStr } from "@tscircuit/mm";
3
+ import { su } from "@tscircuit/soup-util";
4
+ var generateFootprintTsx = (circuitJson) => {
5
+ const holes = su(circuitJson).pcb_hole.list();
6
+ const platedHoles = su(circuitJson).pcb_plated_hole.list();
7
+ const smtPads = su(circuitJson).pcb_smtpad.list();
8
+ const silkscreenPaths = su(circuitJson).pcb_silkscreen_path.list();
9
+ const elementStrings = [];
10
+ for (const hole of holes) {
11
+ if (hole.hole_shape === "circle") {
12
+ elementStrings.push(
13
+ `<hole pcbX="${mmStr(hole.x)}" pcbY="${mmStr(hole.y)}" diameter="${mmStr(hole.hole_diameter)}" />`
14
+ );
15
+ } else if (hole.hole_shape === "oval") {
16
+ console.warn("Unhandled oval hole in conversion (needs implementation)");
17
+ }
18
+ }
19
+ for (const platedHole of platedHoles) {
20
+ if (platedHole.shape === "oval" || platedHole.shape === "pill") {
21
+ elementStrings.push(
22
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerHeight="${mmStr(platedHole.outer_height)}" outerWidth="${mmStr(platedHole.outer_width)}" holeHeight="${mmStr(platedHole.hole_height)}" holeWidth="${mmStr(platedHole.hole_width)}" height="${mmStr(platedHole.hole_height)}" shape="${platedHole.shape}" />`
23
+ );
24
+ } else if (platedHole.shape === "circle") {
25
+ elementStrings.push(
26
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerDiameter="${mmStr(platedHole.outer_diameter)}" holeDiameter="${mmStr(platedHole.hole_diameter)}" shape="circle" />`
27
+ );
28
+ }
29
+ }
30
+ for (const smtPad of smtPads) {
31
+ if (smtPad.shape === "circle") {
32
+ elementStrings.push(
33
+ `<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" radius="${mmStr(smtPad.radius)}" shape="circle" />`
34
+ );
35
+ } else if (smtPad.shape === "rect") {
36
+ elementStrings.push(
37
+ `<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" width="${mmStr(smtPad.width)}" height="${mmStr(smtPad.height)}" shape="rect" />`
38
+ );
39
+ }
40
+ }
41
+ for (const silkscreenPath of silkscreenPaths) {
42
+ elementStrings.push(
43
+ `<silkscreenpath route={${JSON.stringify(silkscreenPath.route)}} />`
44
+ );
45
+ }
46
+ return `
47
+ <footprint>
48
+ ${elementStrings.join("\n")}
49
+ </footprint>
50
+ `.trim();
51
+ };
52
+
53
+ // lib/get-component-using-template.ts
54
+ var getComponentUsingTemplate = ({
55
+ pinLabels,
56
+ componentName,
57
+ objUrl,
58
+ circuitJson,
59
+ supplierPartNumbers,
60
+ manufacturerPartNumber
61
+ }) => {
62
+ const footprintTsx = generateFootprintTsx(circuitJson);
63
+ return `
64
+ import { createUseComponent } from "@tscircuit/core"
65
+ import type { CommonLayoutProps } from "@tscircuit/props"
66
+
67
+ const pinLabels = ${JSON.stringify(pinLabels, null, " ")} as const
68
+
69
+ interface Props extends CommonLayoutProps {
70
+ name: string
71
+ }
72
+
73
+ export const ${componentName} = (props: Props) => {
74
+ return (
75
+ <chip
76
+ {...props}
77
+ ${objUrl ? `cadModel={{
78
+ objUrl: "${objUrl}",
79
+ rotationOffset: { x: 0, y: 0, z: 0 },
80
+ positionOffset: { x: 0, y: 0, z: 0 },
81
+ }}` : ""}
82
+ ${pinLabels ? `pinLabels={${JSON.stringify(pinLabels, null, " ")}}` : ""}
83
+ ${supplierPartNumbers ? `supplierPartNumbers={${JSON.stringify(supplierPartNumbers, null, " ")}}` : ""}
84
+ ${manufacturerPartNumber ? `manufacturerPartNumber="${manufacturerPartNumber}"` : ""}
85
+ footprint={${footprintTsx}}
86
+ />
87
+ )
88
+ }
89
+
90
+ export const use${componentName} = createUseComponent(${componentName}, pinLabels)
91
+
92
+ `.trim();
93
+ };
94
+
1
95
  // lib/index.ts
2
- var convertCircuitJsonToTscircuit = (circuitJson) => {
3
- return "";
96
+ var convertCircuitJsonToTscircuit = (circuitJson, opts) => {
97
+ return getComponentUsingTemplate({
98
+ circuitJson,
99
+ ...opts
100
+ });
4
101
  };
5
102
  export {
6
103
  convertCircuitJsonToTscircuit
@@ -0,0 +1,60 @@
1
+ import { mmStr } from "@tscircuit/mm"
2
+ import type { AnyCircuitElement } from "circuit-json"
3
+ import { su } from "@tscircuit/soup-util"
4
+
5
+ export const generateFootprintTsx = (
6
+ circuitJson: AnyCircuitElement[],
7
+ ): string => {
8
+ const holes = su(circuitJson).pcb_hole.list()
9
+ const platedHoles = su(circuitJson).pcb_plated_hole.list()
10
+ const smtPads = su(circuitJson).pcb_smtpad.list()
11
+ const silkscreenPaths = su(circuitJson).pcb_silkscreen_path.list()
12
+
13
+ const elementStrings: string[] = []
14
+
15
+ for (const hole of holes) {
16
+ if (hole.hole_shape === "circle") {
17
+ elementStrings.push(
18
+ `<hole pcbX="${mmStr(hole.x)}" pcbY="${mmStr(hole.y)}" diameter="${mmStr(hole.hole_diameter)}" />`,
19
+ )
20
+ } else if (hole.hole_shape === "oval") {
21
+ console.warn("Unhandled oval hole in conversion (needs implementation)")
22
+ }
23
+ }
24
+
25
+ for (const platedHole of platedHoles) {
26
+ if (platedHole.shape === "oval" || platedHole.shape === "pill") {
27
+ elementStrings.push(
28
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerHeight="${mmStr(platedHole.outer_height)}" outerWidth="${mmStr(platedHole.outer_width)}" holeHeight="${mmStr(platedHole.hole_height)}" holeWidth="${mmStr(platedHole.hole_width)}" height="${mmStr(platedHole.hole_height)}" shape="${platedHole.shape}" />`,
29
+ )
30
+ } else if (platedHole.shape === "circle") {
31
+ elementStrings.push(
32
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerDiameter="${mmStr(platedHole.outer_diameter)}" holeDiameter="${mmStr(platedHole.hole_diameter)}" shape="circle" />`,
33
+ )
34
+ }
35
+ }
36
+
37
+ for (const smtPad of smtPads) {
38
+ if (smtPad.shape === "circle") {
39
+ elementStrings.push(
40
+ `<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" radius="${mmStr(smtPad.radius)}" shape="circle" />`,
41
+ )
42
+ } else if (smtPad.shape === "rect") {
43
+ elementStrings.push(
44
+ `<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" width="${mmStr(smtPad.width)}" height="${mmStr(smtPad.height)}" shape="rect" />`,
45
+ )
46
+ }
47
+ }
48
+
49
+ for (const silkscreenPath of silkscreenPaths) {
50
+ elementStrings.push(
51
+ `<silkscreenpath route={${JSON.stringify(silkscreenPath.route)}} />`,
52
+ )
53
+ }
54
+
55
+ return `
56
+ <footprint>
57
+ ${elementStrings.join("\n")}
58
+ </footprint>
59
+ `.trim()
60
+ }
@@ -0,0 +1,56 @@
1
+ import type { AnyCircuitElement } from "circuit-json"
2
+ import { generateFootprintTsx } from "./generate-footprint-tsx"
3
+
4
+ export interface ComponentTemplateParams {
5
+ pinLabels?: Record<string, string[]> | Record<string, string> // ChipProps["pinLabels"]
6
+ componentName: string
7
+ objUrl?: string
8
+ circuitJson: AnyCircuitElement[]
9
+ supplierPartNumbers?: Record<string, string[]>
10
+ manufacturerPartNumber?: string
11
+ }
12
+
13
+ export const getComponentUsingTemplate = ({
14
+ pinLabels,
15
+ componentName,
16
+ objUrl,
17
+ circuitJson,
18
+ supplierPartNumbers,
19
+ manufacturerPartNumber,
20
+ }: ComponentTemplateParams) => {
21
+ const footprintTsx = generateFootprintTsx(circuitJson)
22
+ return `
23
+ import { createUseComponent } from "@tscircuit/core"
24
+ import type { CommonLayoutProps } from "@tscircuit/props"
25
+
26
+ const pinLabels = ${JSON.stringify(pinLabels, null, " ")} as const
27
+
28
+ interface Props extends CommonLayoutProps {
29
+ name: string
30
+ }
31
+
32
+ export const ${componentName} = (props: Props) => {
33
+ return (
34
+ <chip
35
+ {...props}
36
+ ${
37
+ objUrl
38
+ ? `cadModel={{
39
+ objUrl: "${objUrl}",
40
+ rotationOffset: { x: 0, y: 0, z: 0 },
41
+ positionOffset: { x: 0, y: 0, z: 0 },
42
+ }}`
43
+ : ""
44
+ }
45
+ ${pinLabels ? `pinLabels={${JSON.stringify(pinLabels, null, " ")}}` : ""}
46
+ ${supplierPartNumbers ? `supplierPartNumbers={${JSON.stringify(supplierPartNumbers, null, " ")}}` : ""}
47
+ ${manufacturerPartNumber ? `manufacturerPartNumber="${manufacturerPartNumber}"` : ""}
48
+ footprint={${footprintTsx}}
49
+ />
50
+ )
51
+ }
52
+
53
+ export const use${componentName} = createUseComponent(${componentName}, pinLabels)
54
+
55
+ `.trim()
56
+ }
package/lib/index.ts CHANGED
@@ -1,5 +1,15 @@
1
1
  import type { CircuitJson } from "circuit-json"
2
+ import {
3
+ getComponentUsingTemplate,
4
+ type ComponentTemplateParams,
5
+ } from "./get-component-using-template"
2
6
 
3
- export const convertCircuitJsonToTscircuit = (circuitJson: CircuitJson) => {
4
- return ""
7
+ export const convertCircuitJsonToTscircuit = (
8
+ circuitJson: CircuitJson,
9
+ opts: Omit<ComponentTemplateParams, "circuitJson">,
10
+ ) => {
11
+ return getComponentUsingTemplate({
12
+ circuitJson,
13
+ ...opts,
14
+ })
5
15
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "circuit-json-to-tscircuit",
3
3
  "main": "dist/index.js",
4
4
  "type": "module",
5
- "version": "0.0.1",
5
+ "version": "0.0.3",
6
6
  "scripts": {
7
7
  "build": "tsup-node lib/index.ts --format esm --dts",
8
8
  "test": "bun test",
@@ -10,7 +10,13 @@
10
10
  "format:check": "biome format ."
11
11
  },
12
12
  "devDependencies": {
13
+ "@biomejs/biome": "^1.9.4",
14
+ "@tscircuit/core": "^0.0.251",
15
+ "@tscircuit/mm": "^0.0.8",
16
+ "@tscircuit/soup-util": "^0.0.41",
13
17
  "@types/bun": "latest",
18
+ "@types/react": "18",
19
+ "@types/react-dom": "18",
14
20
  "circuit-json": "^0.0.126",
15
21
  "tsup": "^8.3.5"
16
22
  },
@@ -0,0 +1,54 @@
1
+ import { test, expect } from "bun:test"
2
+ import { convertCircuitJsonToTscircuit } from "lib/index"
3
+ import { Circuit } from "@tscircuit/core"
4
+
5
+ declare module "bun:test" {
6
+ interface Matchers<T = unknown> {
7
+ toMatchInlineSnapshot(snapshot?: string | null): Promise<MatcherResult>
8
+ }
9
+ }
10
+
11
+ test("test1 basic circuit", async () => {
12
+ const circuit = new Circuit()
13
+
14
+ circuit.add(
15
+ <group subcircuit>
16
+ <resistor name="R1" resistance="1k" footprint="0402" />
17
+ </group>,
18
+ )
19
+
20
+ const circuitJson = circuit.getCircuitJson()
21
+
22
+ const tscircuit = convertCircuitJsonToTscircuit(circuitJson, {
23
+ componentName: "MyResistor",
24
+ })
25
+
26
+ expect(tscircuit).toMatchInlineSnapshot(`
27
+ "import { createUseComponent } from "@tscircuit/core"
28
+ import type { CommonLayoutProps } from "@tscircuit/props"
29
+
30
+ const pinLabels = undefined as const
31
+
32
+ interface Props extends CommonLayoutProps {
33
+ name: string
34
+ }
35
+
36
+ export const MyResistor = (props: Props) => {
37
+ return (
38
+ <chip
39
+ {...props}
40
+
41
+
42
+
43
+
44
+ footprint={<footprint>
45
+ <smtpad portHints={["1","left"]} pcbX="-0.5mm" pcbY="0mm" width="0.6000000000000001mm" height="0.6000000000000001mm" shape="rect" />
46
+ <smtpad portHints={["2","right"]} pcbX="0.5mm" pcbY="0mm" width="0.6000000000000001mm" height="0.6000000000000001mm" shape="rect" />
47
+ </footprint>}
48
+ />
49
+ )
50
+ }
51
+
52
+ export const useMyResistor = createUseComponent(MyResistor, pinLabels)"
53
+ `)
54
+ })
@@ -0,0 +1,77 @@
1
+ import { test, expect } from "bun:test"
2
+ import { convertCircuitJsonToTscircuit } from "lib/index"
3
+ import { Circuit } from "@tscircuit/core"
4
+ import { getComponentUsingTemplate } from "lib/get-component-using-template"
5
+
6
+ test("test2 getComponentUsingTemplate", async () => {
7
+ const circuit = new Circuit()
8
+
9
+ circuit.add(
10
+ <board width="10mm" height="10mm">
11
+ <resistor name="R1" resistance="1k" footprint="0402" />
12
+ </board>,
13
+ )
14
+
15
+ const tscircuitCode = getComponentUsingTemplate({
16
+ circuitJson: circuit.getCircuitJson(),
17
+ componentName: "MyResistor",
18
+ pinLabels: {
19
+ pin1: ["pin1"],
20
+ pin2: ["pin2"],
21
+ },
22
+ objUrl: "...",
23
+ supplierPartNumbers: { jlcpcb: ["123456"] },
24
+ manufacturerPartNumber: "123456",
25
+ })
26
+
27
+ expect(tscircuitCode).toMatchInlineSnapshot(`
28
+ "import { createUseComponent } from "@tscircuit/core"
29
+ import type { CommonLayoutProps } from "@tscircuit/props"
30
+
31
+ const pinLabels = {
32
+ "pin1": [
33
+ "pin1"
34
+ ],
35
+ "pin2": [
36
+ "pin2"
37
+ ]
38
+ } as const
39
+
40
+ interface Props extends CommonLayoutProps {
41
+ name: string
42
+ }
43
+
44
+ export const MyResistor = (props: Props) => {
45
+ return (
46
+ <chip
47
+ {...props}
48
+ cadModel={{
49
+ objUrl: "...",
50
+ rotationOffset: { x: 0, y: 0, z: 0 },
51
+ positionOffset: { x: 0, y: 0, z: 0 },
52
+ }}
53
+ pinLabels={{
54
+ "pin1": [
55
+ "pin1"
56
+ ],
57
+ "pin2": [
58
+ "pin2"
59
+ ]
60
+ }}
61
+ supplierPartNumbers={{
62
+ "jlcpcb": [
63
+ "123456"
64
+ ]
65
+ }}
66
+ manufacturerPartNumber="123456"
67
+ footprint={<footprint>
68
+ <smtpad portHints={["1","left"]} pcbX="-0.5mm" pcbY="0mm" width="0.6000000000000001mm" height="0.6000000000000001mm" shape="rect" />
69
+ <smtpad portHints={["2","right"]} pcbX="0.5mm" pcbY="0mm" width="0.6000000000000001mm" height="0.6000000000000001mm" shape="rect" />
70
+ </footprint>}
71
+ />
72
+ )
73
+ }
74
+
75
+ export const useMyResistor = createUseComponent(MyResistor, pinLabels)"
76
+ `)
77
+ })
package/tsconfig.json CHANGED
@@ -7,6 +7,10 @@
7
7
  "moduleDetection": "force",
8
8
  "jsx": "react-jsx",
9
9
  "allowJs": true,
10
+ "baseUrl": ".",
11
+ "paths": {
12
+ "lib/*": ["lib/*"]
13
+ },
10
14
 
11
15
  // Bundler mode
12
16
  "moduleResolution": "bundler",