@tscircuit/cli 0.1.31 → 0.1.33

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,35 @@
1
+ import { writeFileIfNotExists } from "./write-file-if-not-exists"
2
+ import path from "node:path"
3
+
4
+ export const generateGitIgnoreFile = (dir: string) => {
5
+ const gitignorePath = path.join(dir, ".gitignore")
6
+ const gitignoreContent = `# Dependencies
7
+ node_modules/
8
+
9
+ # Build output
10
+ dist/
11
+ build/
12
+
13
+ # Environment variables
14
+ .env
15
+ .env.local
16
+ .env.*.local
17
+
18
+ # IDE files
19
+ .vscode/
20
+ .idea/
21
+ *.swp
22
+ *.swo
23
+
24
+ # OS files
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # Debug logs
29
+ npm-debug.log*
30
+ yarn-debug.log*
31
+ yarn-error.log*
32
+ `
33
+
34
+ writeFileIfNotExists(gitignorePath, gitignoreContent)
35
+ }
@@ -1,5 +1,5 @@
1
- import path from "path"
2
- import fs from "fs"
1
+ import path from "node:path"
2
+ import { writeFileIfNotExists } from "./write-file-if-not-exists"
3
3
 
4
4
  // Generate a React-compatible tsconfig.json
5
5
  export const generateTsConfig = (dir: string) => {
@@ -25,10 +25,5 @@ export const generateTsConfig = (dir: string) => {
25
25
  null,
26
26
  2,
27
27
  )
28
- if (!fs.existsSync(tsconfigPath)) {
29
- fs.writeFileSync(tsconfigPath, tsconfigContent.trimStart())
30
- console.log(`Created: ${tsconfigPath}`)
31
- } else {
32
- console.log(`Skipped: ${tsconfigPath} already exists`)
33
- }
28
+ writeFileIfNotExists(tsconfigPath, tsconfigContent)
34
29
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/cli",
3
3
  "main": "dist/main.js",
4
4
  "type": "module",
5
- "version": "0.1.31",
5
+ "version": "0.1.33",
6
6
  "bin": {
7
7
  "tsci": "./dist/main.js"
8
8
  },
@@ -34,7 +34,9 @@
34
34
  "@tscircuit/eval": "^0.0.96",
35
35
  "@tscircuit/file-server": "^0.0.13",
36
36
  "@tscircuit/runframe": "^0.0.167",
37
+ "bun-match-svg": "^0.0.9",
37
38
  "chokidar": "4.0.1",
39
+ "circuit-to-svg": "^0.0.101",
38
40
  "commander": "^12.1.0",
39
41
  "configstore": "^7.0.0",
40
42
  "cosmiconfig": "^9.0.0",
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600"><style>
2
+ .boundary { fill: #000; }
3
+ .pcb-board { fill: none; }
4
+ .pcb-trace { fill: none; }
5
+ .pcb-hole-outer { fill: rgb(200, 52, 52); }
6
+ .pcb-hole-inner { fill: rgb(255, 38, 226); }
7
+ .pcb-pad { }
8
+ .pcb-boundary { fill: none; stroke: #fff; stroke-width: 0.3; }
9
+ .pcb-silkscreen { fill: none; }
10
+ .pcb-silkscreen-top { stroke: #f2eda1; }
11
+ .pcb-silkscreen-bottom { stroke: #f2eda1; }
12
+ .pcb-silkscreen-text { fill: #f2eda1; }
13
+ </style><rect class="boundary" x="0" y="0" width="800" height="600"/><rect class="pcb-boundary" x="150" y="50" width="500" height="500"/><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5"/><g transform="translate(550, 300) rotate(0) scale(1, -1)"><rect class="pcb-component" x="-39.99999999999999" y="-15.000000000000002" width="79.99999999999999" height="30.000000000000004"/><rect class="pcb-component-outline" x="-39.99999999999999" y="-15.000000000000002" width="79.99999999999999" height="30.000000000000004"/></g><g transform="translate(250, 300) rotate(0) scale(1, -1)"><rect class="pcb-component" x="-39.99999999999999" y="-15.000000000000002" width="79.99999999999999" height="30.000000000000004"/><rect class="pcb-component-outline" x="-39.99999999999999" y="-15.000000000000002" width="79.99999999999999" height="30.000000000000004"/></g><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="510" y="285" width="30.000000000000004" height="30.000000000000004"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="560" y="285" width="30.000000000000004" height="30.000000000000004"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="210" y="285" width="30.000000000000004" height="30.000000000000004"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="260" y="285" width="30.000000000000004" height="30.000000000000004"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" d="M 525 300 L 340 300" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" d="M 340 300 L 340 235" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" d="M 340 235 L 225 235" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" d="M 225 235 L 225 300" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges"/></svg>
@@ -0,0 +1,17 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" style="background-color: rgb(245, 241, 237)" data-real-to-screen-transform="matrix(144.84007242,0,0,-144.84007242,601.2614556427,338.9300573808)"><style>
2
+ .boundary { fill: rgb(245, 241, 237); }
3
+ .schematic-boundary { fill: none; stroke: #fff; }
4
+ .component { fill: none; stroke: rgb(132, 0, 0); }
5
+ .chip { fill: rgb(255, 255, 194); stroke: rgb(132, 0, 0); }
6
+ .component-pin { fill: none; stroke: rgb(132, 0, 0); }
7
+ .trace:hover {
8
+ filter: invert(1);
9
+ }
10
+ .trace:hover .trace-crossing-outline {
11
+ opacity: 0;
12
+ }
13
+ .text { font-family: sans-serif; fill: rgb(0, 150, 0); }
14
+ .pin-number { fill: rgb(169, 0, 0); }
15
+ .port-label { fill: rgb(0, 100, 100); }
16
+ .component-name { fill: rgb(0, 100, 100); }
17
+ </style><rect class="boundary" x="0" y="0" width="1200" height="600"/><g data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_0"><rect class="component-overlay" x="961.6451659624652" y="313.0828974532263" width="153.28907181649743" height="38.32227881712976" fill="transparent"/><path d="M 961.6451659624652 332.2440368617912 L 999.9674302955876 332.2440368617912" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><path d="M 1076.611958961833 332.2440368617912 L 1114.9342377789626 332.2440368617912" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><path d="M 1038.289680144703 313.0828974532263 L 1076.6119444778255 313.0828974532263 L 1076.6119444778255 351.40517627035604 L 999.967401327573 351.40517627035604 L 999.967401327573 313.0828974532263 L 1038.2896801447027 313.0828974532263" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><text x="1035.7816729027" y="305.7221862096437" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="auto" font-size="26.0712130356px">R1</text><text x="1035.7816729027" y="361.9991234825565" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="hanging" font-size="26.0712130356px">1kΩ</text><circle cx="958.4673892575775" cy="332.2956288955875" r="2.8968014484px" stroke-width="2.8968014484px" fill="none" stroke="rgb(132, 0, 0)"/><circle cx="1113.0959565478224" cy="332.3747839951648" r="2.8968014484px" stroke-width="2.8968014484px" fill="none" stroke="rgb(132, 0, 0)"/></g><g data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_1"><rect class="component-overlay" x="89.19451538935782" y="298.10451483403904" width="153.2890718164976" height="76.64452866624515" fill="transparent"/><path d="M 242.48358720585543 336.4267791671613 L 177.33573928794772 336.4267791671613" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><path d="M 154.34237779127272 336.4267791671613 L 89.19451538935782 336.4267791671613" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><path d="M 177.33573928794766 298.10451483403904 L 177.33573928794772 374.7490435002842" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><path d="M 154.34237779127272 298.10451483403904 L 154.34237779127272 374.7490435002842" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.8968014484px"/><text x="164.87794327105283" y="278.14889075777336" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="auto" font-size="26.0712130356px">C1</text><text x="166.18353168384664" y="399.7112240038267" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="middle" dominant-baseline="hanging" font-size="26.0712130356px">1nF</text><circle cx="86.90404345212234" cy="336.5575407845422" r="2.8968014484px" stroke-width="2.8968014484px" fill="none" stroke="rgb(132, 0, 0)"/><circle cx="246.57843331327743" cy="336.47835671695026" r="2.8968014484px" stroke-width="2.8968014484px" fill="none" stroke="rgb(132, 0, 0)"/></g><g class="trace" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0"><path d="M 958.4673892575775 332.2956288955875 L 398.66050935427745 332.2956288955875 L 398.66050935427745 184.39628067595024 L 86.90404345212232 184.39628067595024 L 86.90404345212232 314.83152992154214 L 86.90404345212232 336.55754078454214" class="trace-invisible-hover-outline" stroke="rgb(0, 150, 0)" fill="none" stroke-width="23.1744115872px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path d="M 958.4673892575775 332.2956288955875 L 398.66050935427745 332.2956288955875 L 398.66050935427745 184.39628067595024 L 86.90404345212232 184.39628067595024 L 86.90404345212232 314.83152992154214 L 86.90404345212232 336.55754078454214" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.8968014484px" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
@@ -0,0 +1,62 @@
1
+ import { getCliTestFixture } from "../../fixtures/get-cli-test-fixture"
2
+ import { test, expect } from "bun:test"
3
+ import { readFile } from "node:fs/promises"
4
+ import path from "node:path"
5
+ import "bun-match-svg"
6
+
7
+ const circuitCode = `
8
+ export default () => (
9
+ <board width="10mm" height="10mm">
10
+ <resistor
11
+ resistance="1k"
12
+ footprint="0402"
13
+ name="R1"
14
+ schX={3}
15
+ pcbX={3}
16
+ />
17
+ <capacitor
18
+ capacitance="1000pF"
19
+ footprint="0402"
20
+ name="C1"
21
+ schX={-3}
22
+ pcbX={-3}
23
+ />
24
+ <trace from=".R1 > .pin1" to=".C1 > .pin1" />
25
+ </board>
26
+ )`
27
+
28
+ async function setupTestCircuit(tmpDir: string) {
29
+ await Bun.write(path.join(tmpDir, "test-circuit.tsx"), circuitCode)
30
+ }
31
+
32
+ test("export pcb-svg", async () => {
33
+ const { tmpDir, runCommand } = await getCliTestFixture()
34
+ await setupTestCircuit(tmpDir)
35
+
36
+ const { stdout, stderr } = await runCommand(
37
+ `tsci export ${path.join(tmpDir, "test-circuit.tsx")} -f pcb-svg`,
38
+ )
39
+ expect(stderr).toBe("")
40
+
41
+ const pcbSvg = await readFile(
42
+ path.join(tmpDir, "test-circuit-pcb.svg"),
43
+ "utf-8",
44
+ )
45
+ expect(pcbSvg).toMatchSvgSnapshot(import.meta.path, "pcb")
46
+ })
47
+
48
+ test("export schematic-svg", async () => {
49
+ const { tmpDir, runCommand } = await getCliTestFixture()
50
+ await setupTestCircuit(tmpDir)
51
+
52
+ const { stdout, stderr } = await runCommand(
53
+ `tsci export ${path.join(tmpDir, "test-circuit.tsx")} -f schematic-svg`,
54
+ )
55
+ expect(stderr).toBe("")
56
+
57
+ const schematicSvg = await readFile(
58
+ path.join(tmpDir, "test-circuit-schematic.svg"),
59
+ "utf-8",
60
+ )
61
+ expect(schematicSvg).toMatchSvgSnapshot(import.meta.path, "schematic")
62
+ })