@tscircuit/core 0.0.1043 → 0.0.1045

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/dist/index.d.ts CHANGED
@@ -296,6 +296,11 @@ declare class IsolatedCircuit {
296
296
  * for subcircuit rendering.
297
297
  */
298
298
  cachedSubcircuits?: Map<string, AnyCircuitElement[]>;
299
+ /**
300
+ * Map to track pending renders by prop hash. This allows multiple subcircuits
301
+ * with the same props to wait for a single render instead of each doing their own.
302
+ */
303
+ pendingSubcircuitRenders?: Map<string, Promise<AnyCircuitElement[]>>;
299
304
  private _schematicDisabledOverride;
300
305
  get schematicDisabled(): boolean;
301
306
  set schematicDisabled(value: boolean);
@@ -318,10 +323,11 @@ declare class IsolatedCircuit {
318
323
  _hasRenderedAtleastOnce: boolean;
319
324
  private _asyncEffectIdsByPhase;
320
325
  private _asyncEffectPhaseById;
321
- constructor({ platform, projectUrl, cachedSubcircuits, }?: {
326
+ constructor({ platform, projectUrl, cachedSubcircuits, pendingSubcircuitRenders, }?: {
322
327
  platform?: PlatformConfig;
323
328
  projectUrl?: string;
324
329
  cachedSubcircuits?: Map<string, AnyCircuitElement[]>;
330
+ pendingSubcircuitRenders?: Map<string, Promise<AnyCircuitElement[]>>;
325
331
  });
326
332
  add(componentOrElm: PrimitiveComponent | ReactElement): void;
327
333
  setPlatform(platform: Partial<PlatformConfig>): void;
package/dist/index.js CHANGED
@@ -580,6 +580,9 @@ ${error.stack}`
580
580
  }
581
581
  runRenderPhaseForChildren(phase) {
582
582
  for (const child of this.children) {
583
+ if ("_isIsolatedSubcircuit" in this && this._isIsolatedSubcircuit && phase === "RenderIsolatedSubcircuits") {
584
+ continue;
585
+ }
583
586
  child.runRenderPhaseForChildren(phase);
584
587
  child.runRenderPhase(phase);
585
588
  }
@@ -9421,7 +9424,8 @@ var NormalComponent3 = class extends PrimitiveComponent2 {
9421
9424
  source_component_id: this.source_component_id,
9422
9425
  subcircuit_id: subcircuit.subcircuit_id ?? void 0,
9423
9426
  do_not_place: props.doNotPlace ?? false,
9424
- obstructs_within_bounds: props.obstructsWithinBounds ?? true
9427
+ obstructs_within_bounds: props.obstructsWithinBounds ?? true,
9428
+ metadata: props.kicadFootprintMetadata ? { kicad_footprint: props.kicadFootprintMetadata } : void 0
9425
9429
  });
9426
9430
  const footprint = props.footprint ?? this._getImpliedFootprintString();
9427
9431
  if (!footprint && !this.isGroup) {
@@ -16345,7 +16349,8 @@ var Chip = class extends NormalComponent3 {
16345
16349
  subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
16346
16350
  do_not_place: props.doNotPlace ?? false,
16347
16351
  obstructs_within_bounds: props.obstructsWithinBounds ?? true,
16348
- is_allowed_to_be_off_board: props.allowOffBoard ?? false
16352
+ is_allowed_to_be_off_board: props.allowOffBoard ?? false,
16353
+ metadata: props.kicadFootprintMetadata ? { kicad_footprint: props.kicadFootprintMetadata } : void 0
16349
16354
  });
16350
16355
  this.pcb_component_id = pcb_component.pcb_component_id;
16351
16356
  }
@@ -16915,7 +16920,6 @@ function inflateSourceTrace(sourceTrace, inflatorContext) {
16915
16920
  traceProps2.pcbStraightLine = true;
16916
16921
  }
16917
16922
  const trace = new Trace3(traceProps2);
16918
- trace.source_trace_id = sourceTrace.source_trace_id;
16919
16923
  subcircuit.add(trace);
16920
16924
  }
16921
16925
 
@@ -17012,8 +17016,22 @@ var inflateCircuitJson = (target, circuitJson, children) => {
17012
17016
  groupsMap
17013
17017
  };
17014
17018
  const sourceGroups = injectionDb.source_group.list();
17015
- for (const sourceGroup of sourceGroups) {
17016
- inflateSourceGroup(sourceGroup, inflationCtx);
17019
+ const renderedGroupIds = /* @__PURE__ */ new Set();
17020
+ const groupsToRender = [...sourceGroups];
17021
+ while (groupsToRender.length > 0) {
17022
+ const groupIndex = groupsToRender.findIndex(
17023
+ (g) => !g.parent_source_group_id || renderedGroupIds.has(g.parent_source_group_id)
17024
+ );
17025
+ if (groupIndex === -1) {
17026
+ const remainingIds = groupsToRender.map((g) => g.source_group_id).join(", ");
17027
+ throw new Error(
17028
+ `Cannot inflate source_groups: cyclic dependency or missing parent detected. Remaining groups: ${remainingIds}`
17029
+ );
17030
+ }
17031
+ const groupToRender = groupsToRender[groupIndex];
17032
+ inflateSourceGroup(groupToRender, inflationCtx);
17033
+ renderedGroupIds.add(groupToRender.source_group_id);
17034
+ groupsToRender.splice(groupIndex, 1);
17017
17035
  }
17018
17036
  const pcbBoards = injectionDb.pcb_board.list();
17019
17037
  for (const pcbBoard of pcbBoards) {
@@ -17531,7 +17549,7 @@ import { identity as identity4 } from "transformation-matrix";
17531
17549
  var package_default = {
17532
17550
  name: "@tscircuit/core",
17533
17551
  type: "module",
17534
- version: "0.0.1042",
17552
+ version: "0.0.1044",
17535
17553
  types: "dist/index.d.ts",
17536
17554
  main: "dist/index.js",
17537
17555
  module: "dist/index.js",
@@ -17589,7 +17607,7 @@ var package_default = {
17589
17607
  "bun-match-svg": "0.0.12",
17590
17608
  "calculate-elbow": "^0.0.12",
17591
17609
  "chokidar-cli": "^3.0.0",
17592
- "circuit-json": "^0.0.379",
17610
+ "circuit-json": "^0.0.383",
17593
17611
  "circuit-json-to-bpc": "^0.0.13",
17594
17612
  "circuit-json-to-connectivity-map": "^0.0.23",
17595
17613
  "circuit-json-to-gltf": "^0.0.68",
@@ -17660,6 +17678,11 @@ var IsolatedCircuit = class {
17660
17678
  * for subcircuit rendering.
17661
17679
  */
17662
17680
  cachedSubcircuits;
17681
+ /**
17682
+ * Map to track pending renders by prop hash. This allows multiple subcircuits
17683
+ * with the same props to wait for a single render instead of each doing their own.
17684
+ */
17685
+ pendingSubcircuitRenders;
17663
17686
  _schematicDisabledOverride;
17664
17687
  get schematicDisabled() {
17665
17688
  if (this._schematicDisabledOverride !== void 0) {
@@ -17696,7 +17719,8 @@ var IsolatedCircuit = class {
17696
17719
  constructor({
17697
17720
  platform,
17698
17721
  projectUrl,
17699
- cachedSubcircuits
17722
+ cachedSubcircuits,
17723
+ pendingSubcircuitRenders
17700
17724
  } = {}) {
17701
17725
  this.children = [];
17702
17726
  this.db = su5([]);
@@ -17704,6 +17728,7 @@ var IsolatedCircuit = class {
17704
17728
  this.projectUrl = projectUrl;
17705
17729
  this.pcbDisabled = platform?.pcbDisabled ?? false;
17706
17730
  this.cachedSubcircuits = cachedSubcircuits;
17731
+ this.pendingSubcircuitRenders = pendingSubcircuitRenders;
17707
17732
  this.root = this;
17708
17733
  }
17709
17734
  add(componentOrElm) {
@@ -17914,6 +17939,7 @@ function Subcircuit_doInitialRenderIsolatedSubcircuits(subcircuit) {
17914
17939
  if (subcircuit._isolatedCircuitJson) return;
17915
17940
  const propHash = subcircuit.getSubcircuitPropHash();
17916
17941
  const cachedSubcircuits = subcircuit.root?.cachedSubcircuits;
17942
+ const pendingSubcircuitRenders = subcircuit.root?.pendingSubcircuitRenders;
17917
17943
  const cached = cachedSubcircuits?.get(propHash);
17918
17944
  if (cached) {
17919
17945
  subcircuit._isolatedCircuitJson = cached;
@@ -17921,26 +17947,54 @@ function Subcircuit_doInitialRenderIsolatedSubcircuits(subcircuit) {
17921
17947
  subcircuit._normalComponentNameMap = null;
17922
17948
  return;
17923
17949
  }
17924
- const parentRoot = subcircuit.root;
17925
17950
  const childrenToRender = [...subcircuit.children];
17926
17951
  subcircuit.children = [];
17927
17952
  subcircuit._normalComponentNameMap = null;
17953
+ const parentRoot = subcircuit.root;
17928
17954
  subcircuit._queueAsyncEffect("render-isolated-subcircuit", async () => {
17929
- const isolatedCircuit = new IsolatedCircuit({
17930
- platform: {
17931
- ...parentRoot.platform,
17932
- pcbDisabled: parentRoot.pcbDisabled,
17933
- schematicDisabled: parentRoot.schematicDisabled
17934
- },
17935
- cachedSubcircuits
17936
- });
17937
- for (const child of childrenToRender) {
17938
- isolatedCircuit.add(child);
17955
+ const cachedResult = cachedSubcircuits?.get(propHash);
17956
+ if (cachedResult) {
17957
+ subcircuit._isolatedCircuitJson = cachedResult;
17958
+ return;
17959
+ }
17960
+ const pendingRenderPromise = pendingSubcircuitRenders?.get(propHash);
17961
+ if (pendingRenderPromise) {
17962
+ subcircuit._isolatedCircuitJson = await pendingRenderPromise;
17963
+ return;
17964
+ }
17965
+ let resolveRender;
17966
+ let rejectRender;
17967
+ const renderPromise = new Promise(
17968
+ (resolve, reject) => {
17969
+ resolveRender = resolve;
17970
+ rejectRender = reject;
17971
+ }
17972
+ );
17973
+ pendingSubcircuitRenders?.set(propHash, renderPromise);
17974
+ try {
17975
+ const isolatedCircuit = new IsolatedCircuit({
17976
+ platform: {
17977
+ ...parentRoot.platform,
17978
+ pcbDisabled: parentRoot.pcbDisabled,
17979
+ schematicDisabled: parentRoot.schematicDisabled
17980
+ },
17981
+ cachedSubcircuits,
17982
+ pendingSubcircuitRenders
17983
+ });
17984
+ for (const child of childrenToRender) {
17985
+ isolatedCircuit.add(child);
17986
+ }
17987
+ await isolatedCircuit.renderUntilSettled();
17988
+ const circuitJson = isolatedCircuit.getCircuitJson();
17989
+ cachedSubcircuits?.set(propHash, circuitJson);
17990
+ subcircuit._isolatedCircuitJson = circuitJson;
17991
+ resolveRender(circuitJson);
17992
+ } catch (error) {
17993
+ rejectRender(error instanceof Error ? error : new Error(String(error)));
17994
+ throw error;
17995
+ } finally {
17996
+ pendingSubcircuitRenders?.delete(propHash);
17939
17997
  }
17940
- await isolatedCircuit.renderUntilSettled();
17941
- const circuitJson = isolatedCircuit.getCircuitJson();
17942
- cachedSubcircuits?.set(propHash, circuitJson);
17943
- subcircuit._isolatedCircuitJson = circuitJson;
17944
17998
  });
17945
17999
  }
17946
18000
 
@@ -17959,6 +18013,32 @@ var EXCLUDED_PROPS = /* @__PURE__ */ new Set([
17959
18013
  "pcbRotation",
17960
18014
  "schRotation"
17961
18015
  ]);
18016
+ function safeSerialize(value, seen = /* @__PURE__ */ new WeakSet()) {
18017
+ if (value === null) return "null";
18018
+ if (value === void 0) return "undefined";
18019
+ const type = typeof value;
18020
+ if (type === "string") return `"${value}"`;
18021
+ if (type === "number" || type === "boolean") return String(value);
18022
+ if (type === "function") return "[function]";
18023
+ if (type === "symbol") return "[symbol]";
18024
+ if (type === "object") {
18025
+ if (seen.has(value)) return "[circular]";
18026
+ seen.add(value);
18027
+ if (value.$$typeof !== void 0) {
18028
+ const elementType = typeof value.type === "string" ? value.type : value.type?.name || "[component]";
18029
+ const propsStr = value.props ? safeSerialize(value.props, seen) : "{}";
18030
+ return `ReactElement(${elementType},${propsStr})`;
18031
+ }
18032
+ if (Array.isArray(value)) {
18033
+ const items = value.map((v) => safeSerialize(v, seen)).join(",");
18034
+ return `[${items}]`;
18035
+ }
18036
+ const keys = Object.keys(value).sort();
18037
+ const pairs3 = keys.map((k) => `${k}:${safeSerialize(value[k], seen)}`);
18038
+ return `{${pairs3.join(",")}}`;
18039
+ }
18040
+ return String(value);
18041
+ }
17962
18042
  function getHashableProps(props) {
17963
18043
  const result = {};
17964
18044
  const keys = Object.keys(props).sort();
@@ -17985,9 +18065,9 @@ function fnv1aHash(str) {
17985
18065
  return hash >>> 0;
17986
18066
  }
17987
18067
  function computeHash(data) {
17988
- const jsonString = JSON.stringify(data);
17989
- const hash1 = fnv1aHash(jsonString);
17990
- const hash2 = fnv1aHash(jsonString + hash1.toString());
18068
+ const serialized = safeSerialize(data);
18069
+ const hash1 = fnv1aHash(serialized);
18070
+ const hash2 = fnv1aHash(serialized + hash1.toString());
17991
18071
  return hash1.toString(16).padStart(8, "0") + hash2.toString(16).padStart(8, "0");
17992
18072
  }
17993
18073
  function Subcircuit_getSubcircuitPropHash(subcircuit) {
@@ -18976,7 +19056,8 @@ var Jumper = class extends NormalComponent3 {
18976
19056
  source_component_id: this.source_component_id,
18977
19057
  subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
18978
19058
  do_not_place: props.doNotPlace ?? false,
18979
- obstructs_within_bounds: props.obstructsWithinBounds ?? true
19059
+ obstructs_within_bounds: props.obstructsWithinBounds ?? true,
19060
+ metadata: props.kicadFootprintMetadata ? { kicad_footprint: props.kicadFootprintMetadata } : void 0
18980
19061
  });
18981
19062
  this.pcb_component_id = pcb_component.pcb_component_id;
18982
19063
  }
@@ -19199,7 +19280,8 @@ var SolderJumper = class extends NormalComponent3 {
19199
19280
  source_component_id: this.source_component_id,
19200
19281
  subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
19201
19282
  do_not_place: props.doNotPlace ?? false,
19202
- obstructs_within_bounds: props.obstructsWithinBounds ?? true
19283
+ obstructs_within_bounds: props.obstructsWithinBounds ?? true,
19284
+ metadata: props.kicadFootprintMetadata ? { kicad_footprint: props.kicadFootprintMetadata } : void 0
19203
19285
  });
19204
19286
  this.pcb_component_id = pcb_component.pcb_component_id;
19205
19287
  }
@@ -22923,8 +23005,11 @@ var SymbolComponent = class extends PrimitiveComponent2 {
22923
23005
  if (this.root?.schematicDisabled) return;
22924
23006
  const { db } = this.root;
22925
23007
  const { _parsedProps: props } = this;
23008
+ const parentNormal = this.getParentNormalComponent();
23009
+ const kicadSymbolMetadata = parentNormal?._parsedProps?.kicadSymbolMetadata;
22926
23010
  const schematic_symbol = db.schematic_symbol.insert({
22927
- name: props.name
23011
+ name: props.name,
23012
+ metadata: kicadSymbolMetadata ? { kicad_symbol: kicadSymbolMetadata } : void 0
22928
23013
  });
22929
23014
  this.schematic_symbol_id = schematic_symbol.schematic_symbol_id;
22930
23015
  }
@@ -23310,7 +23395,8 @@ var RootCircuit = class extends IsolatedCircuit {
23310
23395
  super({
23311
23396
  platform,
23312
23397
  projectUrl,
23313
- cachedSubcircuits: /* @__PURE__ */ new Map()
23398
+ cachedSubcircuits: /* @__PURE__ */ new Map(),
23399
+ pendingSubcircuitRenders: /* @__PURE__ */ new Map()
23314
23400
  });
23315
23401
  this.root = this;
23316
23402
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1043",
4
+ "version": "0.0.1045",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -59,7 +59,7 @@
59
59
  "bun-match-svg": "0.0.12",
60
60
  "calculate-elbow": "^0.0.12",
61
61
  "chokidar-cli": "^3.0.0",
62
- "circuit-json": "^0.0.379",
62
+ "circuit-json": "^0.0.383",
63
63
  "circuit-json-to-bpc": "^0.0.13",
64
64
  "circuit-json-to-connectivity-map": "^0.0.23",
65
65
  "circuit-json-to-gltf": "^0.0.68",