@tscircuit/core 0.0.1043 → 0.0.1044

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
  }
@@ -16915,7 +16918,6 @@ function inflateSourceTrace(sourceTrace, inflatorContext) {
16915
16918
  traceProps2.pcbStraightLine = true;
16916
16919
  }
16917
16920
  const trace = new Trace3(traceProps2);
16918
- trace.source_trace_id = sourceTrace.source_trace_id;
16919
16921
  subcircuit.add(trace);
16920
16922
  }
16921
16923
 
@@ -17012,8 +17014,22 @@ var inflateCircuitJson = (target, circuitJson, children) => {
17012
17014
  groupsMap
17013
17015
  };
17014
17016
  const sourceGroups = injectionDb.source_group.list();
17015
- for (const sourceGroup of sourceGroups) {
17016
- inflateSourceGroup(sourceGroup, inflationCtx);
17017
+ const renderedGroupIds = /* @__PURE__ */ new Set();
17018
+ const groupsToRender = [...sourceGroups];
17019
+ while (groupsToRender.length > 0) {
17020
+ const groupIndex = groupsToRender.findIndex(
17021
+ (g) => !g.parent_source_group_id || renderedGroupIds.has(g.parent_source_group_id)
17022
+ );
17023
+ if (groupIndex === -1) {
17024
+ const remainingIds = groupsToRender.map((g) => g.source_group_id).join(", ");
17025
+ throw new Error(
17026
+ `Cannot inflate source_groups: cyclic dependency or missing parent detected. Remaining groups: ${remainingIds}`
17027
+ );
17028
+ }
17029
+ const groupToRender = groupsToRender[groupIndex];
17030
+ inflateSourceGroup(groupToRender, inflationCtx);
17031
+ renderedGroupIds.add(groupToRender.source_group_id);
17032
+ groupsToRender.splice(groupIndex, 1);
17017
17033
  }
17018
17034
  const pcbBoards = injectionDb.pcb_board.list();
17019
17035
  for (const pcbBoard of pcbBoards) {
@@ -17531,7 +17547,7 @@ import { identity as identity4 } from "transformation-matrix";
17531
17547
  var package_default = {
17532
17548
  name: "@tscircuit/core",
17533
17549
  type: "module",
17534
- version: "0.0.1042",
17550
+ version: "0.0.1043",
17535
17551
  types: "dist/index.d.ts",
17536
17552
  main: "dist/index.js",
17537
17553
  module: "dist/index.js",
@@ -17660,6 +17676,11 @@ var IsolatedCircuit = class {
17660
17676
  * for subcircuit rendering.
17661
17677
  */
17662
17678
  cachedSubcircuits;
17679
+ /**
17680
+ * Map to track pending renders by prop hash. This allows multiple subcircuits
17681
+ * with the same props to wait for a single render instead of each doing their own.
17682
+ */
17683
+ pendingSubcircuitRenders;
17663
17684
  _schematicDisabledOverride;
17664
17685
  get schematicDisabled() {
17665
17686
  if (this._schematicDisabledOverride !== void 0) {
@@ -17696,7 +17717,8 @@ var IsolatedCircuit = class {
17696
17717
  constructor({
17697
17718
  platform,
17698
17719
  projectUrl,
17699
- cachedSubcircuits
17720
+ cachedSubcircuits,
17721
+ pendingSubcircuitRenders
17700
17722
  } = {}) {
17701
17723
  this.children = [];
17702
17724
  this.db = su5([]);
@@ -17704,6 +17726,7 @@ var IsolatedCircuit = class {
17704
17726
  this.projectUrl = projectUrl;
17705
17727
  this.pcbDisabled = platform?.pcbDisabled ?? false;
17706
17728
  this.cachedSubcircuits = cachedSubcircuits;
17729
+ this.pendingSubcircuitRenders = pendingSubcircuitRenders;
17707
17730
  this.root = this;
17708
17731
  }
17709
17732
  add(componentOrElm) {
@@ -17914,6 +17937,7 @@ function Subcircuit_doInitialRenderIsolatedSubcircuits(subcircuit) {
17914
17937
  if (subcircuit._isolatedCircuitJson) return;
17915
17938
  const propHash = subcircuit.getSubcircuitPropHash();
17916
17939
  const cachedSubcircuits = subcircuit.root?.cachedSubcircuits;
17940
+ const pendingSubcircuitRenders = subcircuit.root?.pendingSubcircuitRenders;
17917
17941
  const cached = cachedSubcircuits?.get(propHash);
17918
17942
  if (cached) {
17919
17943
  subcircuit._isolatedCircuitJson = cached;
@@ -17921,26 +17945,54 @@ function Subcircuit_doInitialRenderIsolatedSubcircuits(subcircuit) {
17921
17945
  subcircuit._normalComponentNameMap = null;
17922
17946
  return;
17923
17947
  }
17924
- const parentRoot = subcircuit.root;
17925
17948
  const childrenToRender = [...subcircuit.children];
17926
17949
  subcircuit.children = [];
17927
17950
  subcircuit._normalComponentNameMap = null;
17951
+ const parentRoot = subcircuit.root;
17928
17952
  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);
17953
+ const cachedResult = cachedSubcircuits?.get(propHash);
17954
+ if (cachedResult) {
17955
+ subcircuit._isolatedCircuitJson = cachedResult;
17956
+ return;
17957
+ }
17958
+ const pendingRenderPromise = pendingSubcircuitRenders?.get(propHash);
17959
+ if (pendingRenderPromise) {
17960
+ subcircuit._isolatedCircuitJson = await pendingRenderPromise;
17961
+ return;
17962
+ }
17963
+ let resolveRender;
17964
+ let rejectRender;
17965
+ const renderPromise = new Promise(
17966
+ (resolve, reject) => {
17967
+ resolveRender = resolve;
17968
+ rejectRender = reject;
17969
+ }
17970
+ );
17971
+ pendingSubcircuitRenders?.set(propHash, renderPromise);
17972
+ try {
17973
+ const isolatedCircuit = new IsolatedCircuit({
17974
+ platform: {
17975
+ ...parentRoot.platform,
17976
+ pcbDisabled: parentRoot.pcbDisabled,
17977
+ schematicDisabled: parentRoot.schematicDisabled
17978
+ },
17979
+ cachedSubcircuits,
17980
+ pendingSubcircuitRenders
17981
+ });
17982
+ for (const child of childrenToRender) {
17983
+ isolatedCircuit.add(child);
17984
+ }
17985
+ await isolatedCircuit.renderUntilSettled();
17986
+ const circuitJson = isolatedCircuit.getCircuitJson();
17987
+ cachedSubcircuits?.set(propHash, circuitJson);
17988
+ subcircuit._isolatedCircuitJson = circuitJson;
17989
+ resolveRender(circuitJson);
17990
+ } catch (error) {
17991
+ rejectRender(error instanceof Error ? error : new Error(String(error)));
17992
+ throw error;
17993
+ } finally {
17994
+ pendingSubcircuitRenders?.delete(propHash);
17939
17995
  }
17940
- await isolatedCircuit.renderUntilSettled();
17941
- const circuitJson = isolatedCircuit.getCircuitJson();
17942
- cachedSubcircuits?.set(propHash, circuitJson);
17943
- subcircuit._isolatedCircuitJson = circuitJson;
17944
17996
  });
17945
17997
  }
17946
17998
 
@@ -17959,6 +18011,32 @@ var EXCLUDED_PROPS = /* @__PURE__ */ new Set([
17959
18011
  "pcbRotation",
17960
18012
  "schRotation"
17961
18013
  ]);
18014
+ function safeSerialize(value, seen = /* @__PURE__ */ new WeakSet()) {
18015
+ if (value === null) return "null";
18016
+ if (value === void 0) return "undefined";
18017
+ const type = typeof value;
18018
+ if (type === "string") return `"${value}"`;
18019
+ if (type === "number" || type === "boolean") return String(value);
18020
+ if (type === "function") return "[function]";
18021
+ if (type === "symbol") return "[symbol]";
18022
+ if (type === "object") {
18023
+ if (seen.has(value)) return "[circular]";
18024
+ seen.add(value);
18025
+ if (value.$$typeof !== void 0) {
18026
+ const elementType = typeof value.type === "string" ? value.type : value.type?.name || "[component]";
18027
+ const propsStr = value.props ? safeSerialize(value.props, seen) : "{}";
18028
+ return `ReactElement(${elementType},${propsStr})`;
18029
+ }
18030
+ if (Array.isArray(value)) {
18031
+ const items = value.map((v) => safeSerialize(v, seen)).join(",");
18032
+ return `[${items}]`;
18033
+ }
18034
+ const keys = Object.keys(value).sort();
18035
+ const pairs3 = keys.map((k) => `${k}:${safeSerialize(value[k], seen)}`);
18036
+ return `{${pairs3.join(",")}}`;
18037
+ }
18038
+ return String(value);
18039
+ }
17962
18040
  function getHashableProps(props) {
17963
18041
  const result = {};
17964
18042
  const keys = Object.keys(props).sort();
@@ -17985,9 +18063,9 @@ function fnv1aHash(str) {
17985
18063
  return hash >>> 0;
17986
18064
  }
17987
18065
  function computeHash(data) {
17988
- const jsonString = JSON.stringify(data);
17989
- const hash1 = fnv1aHash(jsonString);
17990
- const hash2 = fnv1aHash(jsonString + hash1.toString());
18066
+ const serialized = safeSerialize(data);
18067
+ const hash1 = fnv1aHash(serialized);
18068
+ const hash2 = fnv1aHash(serialized + hash1.toString());
17991
18069
  return hash1.toString(16).padStart(8, "0") + hash2.toString(16).padStart(8, "0");
17992
18070
  }
17993
18071
  function Subcircuit_getSubcircuitPropHash(subcircuit) {
@@ -23310,7 +23388,8 @@ var RootCircuit = class extends IsolatedCircuit {
23310
23388
  super({
23311
23389
  platform,
23312
23390
  projectUrl,
23313
- cachedSubcircuits: /* @__PURE__ */ new Map()
23391
+ cachedSubcircuits: /* @__PURE__ */ new Map(),
23392
+ pendingSubcircuitRenders: /* @__PURE__ */ new Map()
23314
23393
  });
23315
23394
  this.root = this;
23316
23395
  }
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.1044",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",