@tscircuit/cli 0.1.1649 → 0.1.1650

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.
@@ -2485,8 +2485,8 @@ export default {
2485
2485
  import { parentPort } from "node:worker_threads";
2486
2486
 
2487
2487
  // lib/shared/process-snapshot-file.ts
2488
- import fs7 from "node:fs";
2489
- import path6 from "node:path";
2488
+ import fs8 from "node:fs";
2489
+ import path7 from "node:path";
2490
2490
 
2491
2491
  // node_modules/circuit-json-to-3d-png/dist/index.js
2492
2492
  function normalizeDir(dir) {
@@ -2775,9 +2775,140 @@ function init(open, close) {
2775
2775
  }
2776
2776
  var kleur_default = $;
2777
2777
 
2778
+ // lib/shared/circuit-json-build-cache.ts
2779
+ import fs from "node:fs";
2780
+ import path from "node:path";
2781
+ import { createHash } from "node:crypto";
2782
+ var SOURCE_FILE_EXTENSIONS = new Set([
2783
+ ".tsx",
2784
+ ".ts",
2785
+ ".jsx",
2786
+ ".js",
2787
+ ".json",
2788
+ ".txt",
2789
+ ".md",
2790
+ ".obj",
2791
+ ".kicad_mod",
2792
+ ".kicad_pcb",
2793
+ ".kicad_pro",
2794
+ ".kicad_sch"
2795
+ ]);
2796
+ var IGNORED_DIRECTORY_NAMES = new Set([
2797
+ "node_modules",
2798
+ "dist",
2799
+ "build",
2800
+ ".git"
2801
+ ]);
2802
+ var isPathInside = (childPath, parentPath) => {
2803
+ const relative = path.relative(parentPath, childPath);
2804
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
2805
+ };
2806
+ var findCircuitProjectDir = (filePath) => {
2807
+ const absoluteFilePath = path.resolve(filePath);
2808
+ let currentDir = path.dirname(absoluteFilePath);
2809
+ while (true) {
2810
+ if (fs.existsSync(path.join(currentDir, "package.json"))) {
2811
+ return currentDir;
2812
+ }
2813
+ const parentDir = path.dirname(currentDir);
2814
+ if (parentDir === currentDir)
2815
+ break;
2816
+ currentDir = parentDir;
2817
+ }
2818
+ const cwd = path.resolve(process.cwd());
2819
+ return isPathInside(absoluteFilePath, cwd) ? cwd : path.dirname(absoluteFilePath);
2820
+ };
2821
+ var getCircuitJsonOutputDirName = (relativePath) => {
2822
+ const normalizedRelativePath = relativePath.toLowerCase().replaceAll("\\", "/");
2823
+ if (normalizedRelativePath === "circuit.json" || normalizedRelativePath.endsWith("/circuit.json")) {
2824
+ return path.dirname(relativePath);
2825
+ }
2826
+ return relativePath.replace(/(\.board|\.circuit)?\.tsx$/, "").replace(/\.circuit\.json$/, "");
2827
+ };
2828
+ var getCircuitJsonBuildOutputPath = (filePath) => {
2829
+ const absoluteFilePath = path.resolve(filePath);
2830
+ const projectDir = findCircuitProjectDir(absoluteFilePath);
2831
+ const relativePath = path.relative(projectDir, absoluteFilePath);
2832
+ return path.join(projectDir, "dist", getCircuitJsonOutputDirName(relativePath), "circuit.json");
2833
+ };
2834
+ var getSourceFilePaths = (projectDir) => {
2835
+ const sourceFilePaths = [];
2836
+ const visit = (directoryPath) => {
2837
+ const entries = fs.readdirSync(directoryPath, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
2838
+ for (const entry of entries) {
2839
+ const entryPath = path.join(directoryPath, entry.name);
2840
+ if (entry.isDirectory()) {
2841
+ if (IGNORED_DIRECTORY_NAMES.has(entry.name) || entry.name.startsWith(".")) {
2842
+ continue;
2843
+ }
2844
+ visit(entryPath);
2845
+ continue;
2846
+ }
2847
+ if (!entry.isFile() || entry.name.endsWith(".circuit.json") || !SOURCE_FILE_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {
2848
+ continue;
2849
+ }
2850
+ sourceFilePaths.push(entryPath);
2851
+ }
2852
+ };
2853
+ visit(projectDir);
2854
+ return sourceFilePaths;
2855
+ };
2856
+ var getSourceFilesystemMd5Hash = (filePath) => {
2857
+ const projectDir = findCircuitProjectDir(filePath);
2858
+ const hash = createHash("md5");
2859
+ for (const sourceFilePath of getSourceFilePaths(projectDir)) {
2860
+ const relativePath = path.relative(projectDir, sourceFilePath).split(path.sep).join("/");
2861
+ const content = fs.readFileSync(sourceFilePath);
2862
+ hash.update(`${Buffer.byteLength(relativePath)}:`);
2863
+ hash.update(relativePath);
2864
+ hash.update(`${content.byteLength}:`);
2865
+ hash.update(content);
2866
+ }
2867
+ return hash.digest("hex");
2868
+ };
2869
+ var addSourceFilesystemHash = (circuitJson, sourceFilesystemMd5Hash) => {
2870
+ let foundProjectMetadata = false;
2871
+ const circuitJsonWithHash = circuitJson.map((element) => {
2872
+ if (element.type !== "source_project_metadata")
2873
+ return element;
2874
+ foundProjectMetadata = true;
2875
+ const metadataWithHash = {
2876
+ ...element,
2877
+ source_filesystem_md5_hash: sourceFilesystemMd5Hash
2878
+ };
2879
+ return metadataWithHash;
2880
+ });
2881
+ if (!foundProjectMetadata) {
2882
+ const metadataWithHash = {
2883
+ type: "source_project_metadata",
2884
+ source_filesystem_md5_hash: sourceFilesystemMd5Hash
2885
+ };
2886
+ circuitJsonWithHash.push(metadataWithHash);
2887
+ }
2888
+ return circuitJsonWithHash;
2889
+ };
2890
+ var readCurrentCircuitJsonBuild = ({
2891
+ filePath,
2892
+ sourceFilesystemMd5Hash
2893
+ }) => {
2894
+ const outputPath = getCircuitJsonBuildOutputPath(filePath);
2895
+ try {
2896
+ const parsed = JSON.parse(fs.readFileSync(outputPath, "utf-8"));
2897
+ if (!Array.isArray(parsed))
2898
+ return null;
2899
+ const hasCurrentFilesystemHash = parsed.some((element) => element?.type === "source_project_metadata" && element.source_filesystem_md5_hash === sourceFilesystemMd5Hash);
2900
+ return hasCurrentFilesystemHash ? {
2901
+ circuitJson: parsed,
2902
+ outputPath
2903
+ } : null;
2904
+ } catch {
2905
+ return null;
2906
+ }
2907
+ };
2908
+
2778
2909
  // lib/shared/generate-circuit-json.tsx
2779
- import fs4 from "node:fs";
2780
- import path4 from "node:path";
2910
+ import fs5 from "node:fs";
2911
+ import path5 from "node:path";
2781
2912
  import { pathToFileURL } from "node:url";
2782
2913
  import Debug from "debug";
2783
2914
 
@@ -2799,8 +2930,8 @@ var abbreviateStringifyObject = (obj) => {
2799
2930
  var import_make_vfs = __toESM(require_dist(), 1);
2800
2931
 
2801
2932
  // lib/shared/autorouter-diagnostics.ts
2802
- import fs from "node:fs";
2803
- import path from "node:path";
2933
+ import fs2 from "node:fs";
2934
+ import path2 from "node:path";
2804
2935
  import { convertCircuitJsonToPcbSvg } from "circuit-to-svg";
2805
2936
 
2806
2937
  // lib/shared/convert-svg-to-png.ts
@@ -2815,7 +2946,7 @@ var convertSvgToPngBuffer = (svg) => {
2815
2946
  };
2816
2947
 
2817
2948
  // lib/shared/autorouter-diagnostics.ts
2818
- var DEFAULT_DEBUG_DIR = path.join("dist", "autorouter-debug");
2949
+ var DEFAULT_DEBUG_DIR = path2.join("dist", "autorouter-debug");
2819
2950
  var PROGRESS_LOG_INTERVAL_MS = 1e4;
2820
2951
  var CIRCUIT_JSON_ID_PATTERN = /\b(?:source|pcb|schematic|subcircuit|cad|simulation)_[a-z0-9_]*_\d+\b/gi;
2821
2952
  var parseAutorouterTimeout = (duration) => {
@@ -3160,24 +3291,24 @@ class AutorouterDiagnostics {
3160
3291
  return this.options.dumpSrj === "all" || this.options.dumpSrj === "failed" || this.options.dumpSrj === `phase:${routingPhaseIndex}`;
3161
3292
  }
3162
3293
  writeJson(fileName, value) {
3163
- const debugDir = path.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3164
- fs.mkdirSync(debugDir, { recursive: true });
3165
- const filePath = path.join(debugDir, fileName);
3166
- fs.writeFileSync(filePath, JSON.stringify(value, null, 2));
3294
+ const debugDir = path2.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3295
+ fs2.mkdirSync(debugDir, { recursive: true });
3296
+ const filePath = path2.join(debugDir, fileName);
3297
+ fs2.writeFileSync(filePath, JSON.stringify(value, null, 2));
3167
3298
  this.logArtifact(filePath);
3168
3299
  return filePath;
3169
3300
  }
3170
3301
  writePngSnapshot(fileName, circuitJson) {
3171
3302
  const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
3172
3303
  const png = convertSvgToPngBuffer(pcbSvg);
3173
- const debugDir = path.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3174
- fs.mkdirSync(debugDir, { recursive: true });
3175
- const filePath = path.join(debugDir, fileName);
3176
- fs.writeFileSync(filePath, png);
3304
+ const debugDir = path2.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3305
+ fs2.mkdirSync(debugDir, { recursive: true });
3306
+ const filePath = path2.join(debugDir, fileName);
3307
+ fs2.writeFileSync(filePath, png);
3177
3308
  this.logArtifact(filePath);
3178
3309
  }
3179
3310
  logArtifact(filePath) {
3180
- this.log(`Wrote debug artifact: ${path.relative(process.cwd(), filePath)}`);
3311
+ this.log(`Wrote debug artifact: ${path2.relative(process.cwd(), filePath)}`);
3181
3312
  }
3182
3313
  getCircuitJsonWithCompletedPhaseTraces() {
3183
3314
  const circuitJson = [...this.getCurrentCircuitJson()];
@@ -3323,12 +3454,12 @@ class AutorouterDiagnostics {
3323
3454
 
3324
3455
  // lib/shared/importFromUserLand.ts
3325
3456
  import { createRequire as createRequire2 } from "node:module";
3326
- import fs2 from "node:fs";
3327
- import path2 from "node:path";
3457
+ import fs3 from "node:fs";
3458
+ import path3 from "node:path";
3328
3459
  async function importFromUserLand(moduleName) {
3329
- const userModulePath = path2.join(process.cwd(), "node_modules", moduleName);
3330
- if (fs2.existsSync(userModulePath)) {
3331
- const userRequire = createRequire2(path2.join(process.cwd(), "noop.js"));
3460
+ const userModulePath = path3.join(process.cwd(), "node_modules", moduleName);
3461
+ if (fs3.existsSync(userModulePath)) {
3462
+ const userRequire = createRequire2(path3.join(process.cwd(), "noop.js"));
3332
3463
  try {
3333
3464
  const resolvedUserPath = userRequire.resolve(moduleName);
3334
3465
  return await import(resolvedUserPath);
@@ -3351,8 +3482,8 @@ async function importFromUserLand(moduleName) {
3351
3482
  }
3352
3483
 
3353
3484
  // lib/shared/register-static-asset-loaders.ts
3354
- import fs3 from "node:fs";
3355
- import path3 from "node:path";
3485
+ import fs4 from "node:fs";
3486
+ import path4 from "node:path";
3356
3487
  var STATIC_ASSET_EXTENSIONS = [
3357
3488
  ".glb",
3358
3489
  ".gltf",
@@ -3377,15 +3508,15 @@ var TEXT_STATIC_ASSET_EXTENSIONS = new Set([
3377
3508
  ".kicad_sch"
3378
3509
  ]);
3379
3510
  var readFileContentForStaticLoader = (filePath) => {
3380
- const ext = path3.extname(filePath).toLowerCase();
3511
+ const ext = path4.extname(filePath).toLowerCase();
3381
3512
  if (TEXT_STATIC_ASSET_EXTENSIONS.has(ext)) {
3382
- return fs3.readFileSync(filePath, "utf-8");
3513
+ return fs4.readFileSync(filePath, "utf-8");
3383
3514
  }
3384
- const buffer = fs3.readFileSync(filePath);
3515
+ const buffer = fs4.readFileSync(filePath);
3385
3516
  return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
3386
3517
  };
3387
3518
  var getStaticFileLoader = (filePath) => {
3388
- const extWithDot = path3.extname(filePath).toLowerCase();
3519
+ const extWithDot = path4.extname(filePath).toLowerCase();
3389
3520
  const ext = extWithDot.replace(/^\./, "");
3390
3521
  return activePlatformConfig?.staticFileLoaderMap?.[ext] ?? activePlatformConfig?.staticFileLoaderMap?.[extWithDot];
3391
3522
  };
@@ -3399,12 +3530,12 @@ var normalizeStaticFileLoaderResult = (result) => {
3399
3530
  };
3400
3531
  };
3401
3532
  var getBaseUrlFromTsConfig = () => {
3402
- const tsconfigPath = path3.join(process.cwd(), "tsconfig.json");
3533
+ const tsconfigPath = path4.join(process.cwd(), "tsconfig.json");
3403
3534
  try {
3404
- if (!fs3.existsSync(tsconfigPath)) {
3535
+ if (!fs4.existsSync(tsconfigPath)) {
3405
3536
  return null;
3406
3537
  }
3407
- const tsconfigContent = fs3.readFileSync(tsconfigPath, "utf-8");
3538
+ const tsconfigContent = fs4.readFileSync(tsconfigPath, "utf-8");
3408
3539
  const tsconfig = JSON.parse(tsconfigContent);
3409
3540
  if (tsconfig.compilerOptions?.baseUrl) {
3410
3541
  return tsconfig.compilerOptions.baseUrl;
@@ -3431,8 +3562,8 @@ var registerStaticAssetLoaders = (platformConfig) => {
3431
3562
  loader: "object"
3432
3563
  };
3433
3564
  }
3434
- const baseDir = baseUrl ? path3.resolve(process.cwd(), baseUrl) : process.cwd();
3435
- const relativePath = path3.relative(baseDir, args.path).split(path3.sep).join("/");
3565
+ const baseDir = baseUrl ? path4.resolve(process.cwd(), baseUrl) : process.cwd();
3566
+ const relativePath = path4.relative(baseDir, args.path).split(path4.sep).join("/");
3436
3567
  const pathStr = `./${relativePath}`;
3437
3568
  return {
3438
3569
  exports: {
@@ -3472,9 +3603,11 @@ async function generateCircuitJson({
3472
3603
  platformConfig,
3473
3604
  injectedProps,
3474
3605
  onAsyncEffectStatus,
3475
- autorouterDiagnostics: autorouterDiagnosticsOptions
3606
+ autorouterDiagnostics: autorouterDiagnosticsOptions,
3607
+ sourceFilesystemMd5Hash
3476
3608
  }) {
3477
3609
  debug(`Generating circuit JSON for ${filePath}`);
3610
+ const currentSourceFilesystemMd5Hash = sourceFilesystemMd5Hash ?? getSourceFilesystemMd5Hash(filePath);
3478
3611
  const React = await importFromUserLand("react");
3479
3612
  globalThis.React = React;
3480
3613
  registerStaticAssetLoaders(platformConfig);
@@ -3484,12 +3617,12 @@ async function generateCircuitJson({
3484
3617
  });
3485
3618
  const autorouterDiagnostics = new AutorouterDiagnostics(autorouterDiagnosticsOptions);
3486
3619
  autorouterDiagnostics.attachToRootCircuit(runner);
3487
- const absoluteFilePath = path4.isAbsolute(filePath) ? filePath : path4.resolve(process.cwd(), filePath);
3488
- const projectDir = path4.dirname(absoluteFilePath);
3620
+ const absoluteFilePath = path5.isAbsolute(filePath) ? filePath : path5.resolve(process.cwd(), filePath);
3621
+ const projectDir = path5.dirname(absoluteFilePath);
3489
3622
  const resolvedOutputDir = outputDir ?? projectDir;
3490
- const relativeComponentPath = path4.relative(projectDir, absoluteFilePath);
3491
- const baseFileName = outputFileName || path4.basename(absoluteFilePath).replace(/\.[^.]+$/, "");
3492
- const outputPath = path4.join(resolvedOutputDir, `${baseFileName}.circuit.json`);
3623
+ const relativeComponentPath = path5.relative(projectDir, absoluteFilePath);
3624
+ const baseFileName = outputFileName || path5.basename(absoluteFilePath).replace(/\.[^.]+$/, "");
3625
+ const outputPath = path5.join(resolvedOutputDir, `${baseFileName}.circuit.json`);
3493
3626
  debug(`Project directory: ${projectDir}`);
3494
3627
  debug(`Relative component path: ${relativeComponentPath}`);
3495
3628
  debug(`Output path: ${outputPath}`);
@@ -3509,7 +3642,7 @@ async function generateCircuitJson({
3509
3642
  return false;
3510
3643
  if (normalizedFilePath.match(/^\.[^/]/))
3511
3644
  return false;
3512
- if (!ALLOWED_FILE_EXTENSIONS.includes(path4.extname(normalizedFilePath)))
3645
+ if (!ALLOWED_FILE_EXTENSIONS.includes(path5.extname(normalizedFilePath)))
3513
3646
  return false;
3514
3647
  return true;
3515
3648
  },
@@ -3541,11 +3674,11 @@ async function generateCircuitJson({
3541
3674
  runner.render();
3542
3675
  }
3543
3676
  runner.emit("renderComplete");
3544
- const circuitJson = await runner.getCircuitJson();
3677
+ const circuitJson = addSourceFilesystemHash(await runner.getCircuitJson(), currentSourceFilesystemMd5Hash);
3545
3678
  await autorouterDiagnostics.finalize(circuitJson);
3546
3679
  if (saveToFile) {
3547
3680
  debug(`Saving circuit JSON to ${outputPath}`);
3548
- fs4.writeFileSync(outputPath, JSON.stringify(circuitJson, null, 2));
3681
+ fs5.writeFileSync(outputPath, JSON.stringify(circuitJson, null, 2));
3549
3682
  }
3550
3683
  return {
3551
3684
  circuitJson,
@@ -3554,30 +3687,54 @@ async function generateCircuitJson({
3554
3687
  };
3555
3688
  }
3556
3689
 
3690
+ // lib/shared/get-or-generate-circuit-json.ts
3691
+ var getOrGenerateCircuitJson = async (options) => {
3692
+ const sourceFilesystemMd5Hash = getSourceFilesystemMd5Hash(options.filePath);
3693
+ const cachedBuild = readCurrentCircuitJsonBuild({
3694
+ filePath: options.filePath,
3695
+ sourceFilesystemMd5Hash
3696
+ });
3697
+ if (cachedBuild) {
3698
+ return {
3699
+ ...cachedBuild,
3700
+ rootCircuit: undefined,
3701
+ cacheHit: true
3702
+ };
3703
+ }
3704
+ const generated = await generateCircuitJson({
3705
+ ...options,
3706
+ sourceFilesystemMd5Hash
3707
+ });
3708
+ return {
3709
+ ...generated,
3710
+ cacheHit: false
3711
+ };
3712
+ };
3713
+
3557
3714
  // lib/shared/get-platform-config-with-cli-defaults.ts
3558
- import { createHash } from "node:crypto";
3559
- import fs5 from "node:fs";
3560
- import path5 from "node:path";
3715
+ import { createHash as createHash2 } from "node:crypto";
3716
+ import fs6 from "node:fs";
3717
+ import path6 from "node:path";
3561
3718
  import { getPlatformConfig } from "@tscircuit/eval/platform-config";
3562
- function createLocalCacheEngine(cacheDir = path5.join(process.cwd(), ".tscircuit", "cache")) {
3719
+ function createLocalCacheEngine(cacheDir = path6.join(process.cwd(), ".tscircuit", "cache")) {
3563
3720
  return {
3564
3721
  getItem: (key) => {
3565
3722
  try {
3566
- const hash = createHash("md5").update(key).digest("hex");
3723
+ const hash = createHash2("md5").update(key).digest("hex");
3567
3724
  const keyWithSafeCharacters = key.replace(/[^a-zA-Z0-9]/g, "_");
3568
- const filePath = path5.join(cacheDir, `${keyWithSafeCharacters.slice(keyWithSafeCharacters.length - 10, keyWithSafeCharacters.length)}-${hash}.json`);
3569
- return fs5.readFileSync(filePath, "utf-8");
3725
+ const filePath = path6.join(cacheDir, `${keyWithSafeCharacters.slice(keyWithSafeCharacters.length - 10, keyWithSafeCharacters.length)}-${hash}.json`);
3726
+ return fs6.readFileSync(filePath, "utf-8");
3570
3727
  } catch {
3571
3728
  return null;
3572
3729
  }
3573
3730
  },
3574
3731
  setItem: (key, value) => {
3575
3732
  try {
3576
- fs5.mkdirSync(cacheDir, { recursive: true });
3577
- const hash = createHash("md5").update(key).digest("hex");
3733
+ fs6.mkdirSync(cacheDir, { recursive: true });
3734
+ const hash = createHash2("md5").update(key).digest("hex");
3578
3735
  const keyWithSafeCharacters = key.replace(/[^a-zA-Z0-9]/g, "_");
3579
- const filePath = path5.join(cacheDir, `${keyWithSafeCharacters.slice(keyWithSafeCharacters.length - 10, keyWithSafeCharacters.length)}-${hash}.json`);
3580
- fs5.writeFileSync(filePath, value);
3736
+ const filePath = path6.join(cacheDir, `${keyWithSafeCharacters.slice(keyWithSafeCharacters.length - 10, keyWithSafeCharacters.length)}-${hash}.json`);
3737
+ fs6.writeFileSync(filePath, value);
3581
3738
  } catch {}
3582
3739
  }
3583
3740
  };
@@ -3593,15 +3750,15 @@ function getPlatformConfigWithCliDefaults(userConfig) {
3593
3750
  loadFromUrl: async (url) => {
3594
3751
  let fetchUrl = url;
3595
3752
  if (url.startsWith("./") || url.startsWith("../")) {
3596
- const absolutePath = path5.resolve(process.cwd(), url);
3753
+ const absolutePath = path6.resolve(process.cwd(), url);
3597
3754
  fetchUrl = `file://${absolutePath}`;
3598
3755
  } else if (url.startsWith("/")) {
3599
- if (fs5.existsSync(url)) {
3756
+ if (fs6.existsSync(url)) {
3600
3757
  fetchUrl = `file://${url}`;
3601
3758
  } else {
3602
3759
  const relativePath = `.${url}`;
3603
- const absolutePath = path5.resolve(process.cwd(), relativePath);
3604
- if (fs5.existsSync(absolutePath)) {
3760
+ const absolutePath = path6.resolve(process.cwd(), relativePath);
3761
+ if (fs6.existsSync(absolutePath)) {
3605
3762
  fetchUrl = `file://${absolutePath}`;
3606
3763
  } else {
3607
3764
  fetchUrl = `file://${url}`;
@@ -3674,7 +3831,7 @@ var getSimulationSvgAssetsFromCircuitJson = (circuitJson) => {
3674
3831
 
3675
3832
  // lib/shared/compare-images.ts
3676
3833
  import looksSame from "@tscircuit/image-utils/looks-same";
3677
- import fs6 from "node:fs/promises";
3834
+ import fs7 from "node:fs/promises";
3678
3835
  var compareAndCreateDiff = async (buffer1, buffer2, diffPath, createDiff = true) => {
3679
3836
  const b1 = Buffer.from(buffer1);
3680
3837
  const b2 = Buffer.from(buffer2);
@@ -3690,9 +3847,9 @@ var compareAndCreateDiff = async (buffer1, buffer2, diffPath, createDiff = true)
3690
3847
  highlightColor: "#ff00ff",
3691
3848
  tolerance: 2
3692
3849
  });
3693
- await fs6.writeFile(diffPath, diffBuffer);
3850
+ await fs7.writeFile(diffPath, diffBuffer);
3694
3851
  } else {
3695
- await fs6.writeFile(diffPath, buffer2);
3852
+ await fs7.writeFile(diffPath, buffer2);
3696
3853
  }
3697
3854
  }
3698
3855
  return { equal };
@@ -3721,7 +3878,7 @@ var processSnapshotFile = async ({
3721
3878
  cameraPreset,
3722
3879
  pcbLayer
3723
3880
  }) => {
3724
- const relativeFilePath = path6.relative(projectDir, file);
3881
+ const relativeFilePath = path7.relative(projectDir, file);
3725
3882
  const successPaths = [];
3726
3883
  const warningMessages = [];
3727
3884
  const mismatches = [];
@@ -3732,11 +3889,11 @@ var processSnapshotFile = async ({
3732
3889
  let simulationSvgAssets;
3733
3890
  try {
3734
3891
  if (isCircuitJsonFile(file)) {
3735
- const parsed = JSON.parse(fs7.readFileSync(file, "utf-8"));
3892
+ const parsed = JSON.parse(fs8.readFileSync(file, "utf-8"));
3736
3893
  circuitJson = Array.isArray(parsed) ? parsed : [];
3737
3894
  } else {
3738
3895
  const platformConfigWithCliDefaults = getPlatformConfigWithCliDefaults(platformConfig);
3739
- const result = await generateCircuitJson({
3896
+ const result = await getOrGenerateCircuitJson({
3740
3897
  filePath: file,
3741
3898
  platformConfig: platformConfigWithCliDefaults
3742
3899
  });
@@ -3816,12 +3973,12 @@ var processSnapshotFile = async ({
3816
3973
  } catch (error) {
3817
3974
  const errorMessage = error instanceof Error ? error.message : String(error);
3818
3975
  if (errorMessage.includes("No pcb_board found in circuit JSON")) {
3819
- const fileDir = path6.dirname(file);
3820
- const relativeDir = path6.relative(projectDir, fileDir);
3821
- const snapDir2 = snapshotsDirName ? path6.join(projectDir, snapshotsDirName, relativeDir) : path6.join(fileDir, "__snapshots__");
3822
- const base2 = path6.basename(file).replace(/\.[^.]+$/, "");
3823
- const snap3dPath = path6.join(snapDir2, `${base2}-3d.snap.png`);
3824
- const existing3dSnapshot = fs7.existsSync(snap3dPath);
3976
+ const fileDir = path7.dirname(file);
3977
+ const relativeDir = path7.relative(projectDir, fileDir);
3978
+ const snapDir2 = snapshotsDirName ? path7.join(projectDir, snapshotsDirName, relativeDir) : path7.join(fileDir, "__snapshots__");
3979
+ const base2 = path7.basename(file).replace(/\.[^.]+$/, "");
3980
+ const snap3dPath = path7.join(snapDir2, `${base2}-3d.snap.png`);
3981
+ const existing3dSnapshot = fs8.existsSync(snap3dPath);
3825
3982
  if (existing3dSnapshot) {
3826
3983
  return {
3827
3984
  ok: false,
@@ -3832,7 +3989,7 @@ var processSnapshotFile = async ({
3832
3989
  errorMessage: kleur_default.red(`
3833
3990
  ❌ Failed to generate 3D snapshot for ${relativeFilePath}:
3834
3991
  `) + kleur_default.red(` No pcb_board found in circuit JSON
3835
- `) + kleur_default.red(` Existing snapshot: ${path6.relative(projectDir, snap3dPath)}
3992
+ `) + kleur_default.red(` Existing snapshot: ${path7.relative(projectDir, snap3dPath)}
3836
3993
  `)
3837
3994
  };
3838
3995
  }
@@ -3853,9 +4010,9 @@ var processSnapshotFile = async ({
3853
4010
  }
3854
4011
  }
3855
4012
  }
3856
- const snapDir = snapshotsDirName ? path6.join(projectDir, snapshotsDirName, path6.relative(projectDir, path6.dirname(file))) : path6.join(path6.dirname(file), "__snapshots__");
3857
- fs7.mkdirSync(snapDir, { recursive: true });
3858
- const base = path6.basename(file).replace(/\.[^.]+$/, "");
4013
+ const snapDir = snapshotsDirName ? path7.join(projectDir, snapshotsDirName, path7.relative(projectDir, path7.dirname(file))) : path7.join(path7.dirname(file), "__snapshots__");
4014
+ fs8.mkdirSync(snapDir, { recursive: true });
4015
+ const base = path7.basename(file).replace(/\.[^.]+$/, "");
3859
4016
  const snapshots = [];
3860
4017
  if (!simulationOnly && (pcbOnly || !schematicOnly)) {
3861
4018
  let pcbSnapshotType = "pcb";
@@ -3889,17 +4046,17 @@ var processSnapshotFile = async ({
3889
4046
  for (const snapshot of snapshots) {
3890
4047
  const { type } = snapshot;
3891
4048
  const is3d = type === "3d";
3892
- const snapPath = path6.join(snapDir, `${base}-${type}.snap.${is3d ? "png" : "svg"}`);
3893
- const existing = fs7.existsSync(snapPath);
4049
+ const snapPath = path7.join(snapDir, `${base}-${type}.snap.${is3d ? "png" : "svg"}`);
4050
+ const existing = fs8.existsSync(snapPath);
3894
4051
  const newContentBuffer = snapshot.isBinary ? snapshot.content : Buffer.from(snapshot.content, "utf8");
3895
4052
  const newContentForFile = snapshot.content;
3896
4053
  if (!existing) {
3897
- fs7.writeFileSync(snapPath, newContentForFile);
3898
- successPaths.push(path6.relative(projectDir, snapPath));
4054
+ fs8.writeFileSync(snapPath, newContentForFile);
4055
+ successPaths.push(path7.relative(projectDir, snapPath));
3899
4056
  didUpdate = true;
3900
4057
  continue;
3901
4058
  }
3902
- const oldContentBuffer = fs7.readFileSync(snapPath);
4059
+ const oldContentBuffer = fs8.readFileSync(snapPath);
3903
4060
  let equal;
3904
4061
  let diffPath;
3905
4062
  if (createDiff) {
@@ -3911,16 +4068,16 @@ var processSnapshotFile = async ({
3911
4068
  }
3912
4069
  if (update) {
3913
4070
  if (!forceUpdate && equal) {
3914
- successPaths.push(path6.relative(projectDir, snapPath));
4071
+ successPaths.push(path7.relative(projectDir, snapPath));
3915
4072
  } else {
3916
- fs7.writeFileSync(snapPath, newContentForFile);
3917
- successPaths.push(path6.relative(projectDir, snapPath));
4073
+ fs8.writeFileSync(snapPath, newContentForFile);
4074
+ successPaths.push(path7.relative(projectDir, snapPath));
3918
4075
  didUpdate = true;
3919
4076
  }
3920
4077
  } else if (!equal) {
3921
4078
  mismatches.push(diffPath ? `${snapPath} (diff: ${diffPath})` : snapPath);
3922
4079
  } else {
3923
- successPaths.push(path6.relative(projectDir, snapPath));
4080
+ successPaths.push(path7.relative(projectDir, snapPath));
3924
4081
  }
3925
4082
  }
3926
4083
  return {
@@ -3933,8 +4090,8 @@ var processSnapshotFile = async ({
3933
4090
  };
3934
4091
 
3935
4092
  // lib/project-config/index.ts
3936
- import * as fs8 from "node:fs";
3937
- import * as path7 from "node:path";
4093
+ import * as fs9 from "node:fs";
4094
+ import * as path8 from "node:path";
3938
4095
  import { pathToFileURL as pathToFileURL2 } from "node:url";
3939
4096
 
3940
4097
  // lib/project-config/project-config-schema.ts
@@ -4009,10 +4166,10 @@ var stripWrappingQuotes = (value) => {
4009
4166
  var loadProjectEnv = (projectDir) => {
4010
4167
  const initialEnvKeys = new Set(Object.keys(process.env));
4011
4168
  for (const envFileName of ENV_FILENAMES) {
4012
- const envPath = path7.join(projectDir, envFileName);
4013
- if (!fs8.existsSync(envPath))
4169
+ const envPath = path8.join(projectDir, envFileName);
4170
+ if (!fs9.existsSync(envPath))
4014
4171
  continue;
4015
- const envContent = fs8.readFileSync(envPath, "utf8");
4172
+ const envContent = fs9.readFileSync(envPath, "utf8");
4016
4173
  for (const rawLine of envContent.split(/\r?\n/)) {
4017
4174
  const line = rawLine.trim();
4018
4175
  if (!line || line.startsWith("#"))
@@ -4030,12 +4187,12 @@ var loadProjectEnv = (projectDir) => {
4030
4187
  }
4031
4188
  };
4032
4189
  var loadProjectConfigSync = (projectDir = process.cwd()) => {
4033
- const configPath = path7.join(projectDir, CONFIG_FILENAME);
4034
- if (!fs8.existsSync(configPath)) {
4190
+ const configPath = path8.join(projectDir, CONFIG_FILENAME);
4191
+ if (!fs9.existsSync(configPath)) {
4035
4192
  return null;
4036
4193
  }
4037
4194
  try {
4038
- const configContent = fs8.readFileSync(configPath, "utf8");
4195
+ const configContent = fs9.readFileSync(configPath, "utf8");
4039
4196
  const parsedConfig = JSON.parse(configContent);
4040
4197
  return projectConfigSchema.parse(parsedConfig);
4041
4198
  } catch (error) {
@@ -4046,12 +4203,12 @@ var loadProjectConfigSync = (projectDir = process.cwd()) => {
4046
4203
  var loadProjectConfigModule = async (projectDir) => {
4047
4204
  loadProjectEnv(projectDir);
4048
4205
  for (const configFileName of CONFIG_MODULE_FILENAMES) {
4049
- const configPath = path7.join(projectDir, configFileName);
4050
- if (!fs8.existsSync(configPath))
4206
+ const configPath = path8.join(projectDir, configFileName);
4207
+ if (!fs9.existsSync(configPath))
4051
4208
  continue;
4052
4209
  try {
4053
4210
  const moduleUrl = pathToFileURL2(configPath);
4054
- const stat = fs8.statSync(configPath);
4211
+ const stat = fs9.statSync(configPath);
4055
4212
  moduleUrl.searchParams.set("tsci", String(stat.mtimeMs));
4056
4213
  const importedModule = await import(moduleUrl.href);
4057
4214
  const exportedConfig = importedModule.default ?? importedModule.config ?? importedModule;
@@ -4098,13 +4255,13 @@ var getSnapshotsDir = (projectDir = process.cwd()) => {
4098
4255
  return config?.snapshotsDir;
4099
4256
  };
4100
4257
  var saveProjectConfig = (config, projectDir = process.cwd()) => {
4101
- const configPath = path7.join(projectDir, CONFIG_FILENAME);
4258
+ const configPath = path8.join(projectDir, CONFIG_FILENAME);
4102
4259
  try {
4103
4260
  const configWithSchema = {
4104
4261
  $schema: CONFIG_SCHEMA_URL,
4105
4262
  ...config ?? {}
4106
4263
  };
4107
- fs8.writeFileSync(configPath, JSON.stringify(configWithSchema, null, 2));
4264
+ fs9.writeFileSync(configPath, JSON.stringify(configWithSchema, null, 2));
4108
4265
  return true;
4109
4266
  } catch (error) {
4110
4267
  console.error(`Error saving tscircuit config: ${error}`);
package/dist/lib/index.js CHANGED
@@ -65811,7 +65811,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
65811
65811
  }));
65812
65812
  };
65813
65813
  // package.json
65814
- var version = "0.1.1648";
65814
+ var version = "0.1.1649";
65815
65815
  var package_default = {
65816
65816
  name: "@tscircuit/cli",
65817
65817
  version,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1649",
3
+ "version": "0.1.1650",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",