@tscircuit/cli 0.1.1434 → 0.1.1435

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/cli/main.js CHANGED
@@ -100688,7 +100688,7 @@ var import_perfect_cli = __toESM2(require_dist2(), 1);
100688
100688
  // lib/getVersion.ts
100689
100689
  import { createRequire as createRequire2 } from "node:module";
100690
100690
  // package.json
100691
- var version = "0.1.1432";
100691
+ var version = "0.1.1434";
100692
100692
  var package_default = {
100693
100693
  name: "@tscircuit/cli",
100694
100694
  version,
@@ -100702,7 +100702,7 @@ var package_default = {
100702
100702
  "@biomejs/biome": "^1.9.4",
100703
100703
  "@tscircuit/circuit-json-placement-analysis": "^0.0.6",
100704
100704
  "@tscircuit/circuit-json-routing-analysis": "^0.0.1",
100705
- "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#700017d79a608295cc275dcb9c2e1d160809ef9e",
100705
+ "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#40f49bb8ae9dabedb19b47ec0a621c713b40615c",
100706
100706
  "@tscircuit/eval": "^0.0.835",
100707
100707
  "@tscircuit/fake-snippets": "^0.0.182",
100708
100708
  "@tscircuit/file-server": "^0.0.32",
@@ -244585,6 +244585,7 @@ var addAttr = (attrs, key, value, options) => {
244585
244585
 
244586
244586
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
244587
244587
  class CapacitorOrientationSolver extends BaseSolver6 {
244588
+ static ORIENTATION_MESSAGE = 'Use schOrientation="vertical" on this capacitor to fix the symbol orientation';
244588
244589
  ctx;
244589
244590
  out;
244590
244591
  schematicComponentById;
@@ -244681,7 +244682,8 @@ class CapacitorOrientationSolver extends BaseSolver6 {
244681
244682
  return;
244682
244683
  return {
244683
244684
  lineItemType: "CapacitorSymbolHorizontal",
244684
- schematicBox: this.createIssuePlacement(placement)
244685
+ schematicBox: this.createIssuePlacement(placement),
244686
+ message: CapacitorOrientationSolver.ORIENTATION_MESSAGE
244685
244687
  };
244686
244688
  }
244687
244689
  static issueToString(issue) {
@@ -244691,6 +244693,7 @@ class CapacitorOrientationSolver extends BaseSolver6 {
244691
244693
  addAttr(attrs, "schY", issue.schematicBox.schY);
244692
244694
  addAttr(attrs, "width", issue.schematicBox.width);
244693
244695
  addAttr(attrs, "height", issue.schematicBox.height);
244696
+ addAttr(attrs, "message", issue.message, { escape: false });
244694
244697
  return `<CapacitorSymbolHorizontal ${attrs.join(" ")} />`;
244695
244698
  }
244696
244699
  }
@@ -244835,6 +244838,8 @@ class SchematicBoxInnerLabelCollisionSolver extends BaseSolver9 {
244835
244838
  this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
244836
244839
  this.sourcePortById = this.getSourcePortById(circuitJson);
244837
244840
  this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson));
244841
+ const passiveComponentIds = new Set(circuitJson.filter((el3) => el3.type === "schematic_component").filter((el3) => el3.symbol_name).map((el3) => el3.schematic_component_id));
244842
+ this.entries = this.entries.filter(([id2]) => !passiveComponentIds.has(id2));
244838
244843
  this.solved = this.entries.length === 0;
244839
244844
  }
244840
244845
  _step() {
@@ -245676,6 +245681,349 @@ class DiodeResistorAlignmentSolver extends BaseSolver13 {
245676
245681
  }
245677
245682
  }
245678
245683
 
245684
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ComponentNetLabelCollisionSolver/ComponentNetLabelCollisionSolver.ts
245685
+ import { BaseSolver as BaseSolver14 } from "@tscircuit/solver-utils";
245686
+
245687
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/geometry.ts
245688
+ function centeredRect(cx2, cy2, w4, h4) {
245689
+ return {
245690
+ left: cx2 - w4 / 2,
245691
+ right: cx2 + w4 / 2,
245692
+ top: cy2 + h4 / 2,
245693
+ bottom: cy2 - h4 / 2
245694
+ };
245695
+ }
245696
+ function rectOverlap(a2, b) {
245697
+ const ow = Math.min(a2.right, b.right) - Math.max(a2.left, b.left);
245698
+ const oh2 = Math.min(a2.top, b.top) - Math.max(a2.bottom, b.bottom);
245699
+ return ow > 0 && oh2 > 0 ? { ow, oh: oh2 } : null;
245700
+ }
245701
+
245702
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ComponentNetLabelCollisionSolver/ComponentNetLabelCollisionSolver.ts
245703
+ class ComponentNetLabelCollisionSolver extends BaseSolver14 {
245704
+ params;
245705
+ LABEL_HALF_HEIGHT = 0.1;
245706
+ LABEL_BOUNDS_SLACK = 0.1;
245707
+ SCH_CHAR_WIDTH = 0.13;
245708
+ placements;
245709
+ netLabelsByComponentId;
245710
+ rawCollisions = [];
245711
+ firstIndex = 0;
245712
+ secondIndex = 1;
245713
+ constructor(params2) {
245714
+ super();
245715
+ this.params = params2;
245716
+ this.placements = params2.ctx.componentPlacements;
245717
+ this.netLabelsByComponentId = this.buildNetLabelsByComponentId(params2.ctx.circuitJson);
245718
+ this.solved = this.placements.length < 2;
245719
+ }
245720
+ _step() {
245721
+ if (this.firstIndex >= this.placements.length - 1) {
245722
+ this.buildAndPushIssues();
245723
+ this.solved = true;
245724
+ return;
245725
+ }
245726
+ const compA = this.placements[this.firstIndex];
245727
+ const compB = this.placements[this.secondIndex];
245728
+ this.detectPair(compA, compB);
245729
+ this.secondIndex++;
245730
+ if (this.secondIndex >= this.placements.length) {
245731
+ this.firstIndex++;
245732
+ this.secondIndex = this.firstIndex + 1;
245733
+ }
245734
+ }
245735
+ detectPair(compA, compB) {
245736
+ this.rawCollisions.push(...this.detectLabelLabel(compA, compB));
245737
+ this.rawCollisions.push(...this.detectBoxLabel(compA, compB));
245738
+ this.rawCollisions.push(...this.detectBoxLabel(compB, compA));
245739
+ }
245740
+ detectLabelLabel(firstComponent, secondComponent) {
245741
+ let leftComp = firstComponent;
245742
+ let rightComp = secondComponent;
245743
+ if (firstComponent.schX > secondComponent.schX) {
245744
+ leftComp = secondComponent;
245745
+ rightComp = firstComponent;
245746
+ }
245747
+ const leftId = leftComp.schematicComponentId;
245748
+ const rightId = rightComp.schematicComponentId;
245749
+ if (!leftId || !rightId)
245750
+ return [];
245751
+ const leftLabels = this.netLabelsByComponentId.get(leftId) ?? [];
245752
+ const rightLabels = this.netLabelsByComponentId.get(rightId) ?? [];
245753
+ if (leftLabels.length === 0 || rightLabels.length === 0)
245754
+ return [];
245755
+ const hits = [];
245756
+ for (const leftLabel of leftLabels) {
245757
+ for (const rightLabel of rightLabels) {
245758
+ const leftBounds = this.getNetLabelBounds(leftLabel);
245759
+ const rightBounds = this.getNetLabelBounds(rightLabel);
245760
+ if (rectOverlap(leftBounds, rightBounds)) {
245761
+ hits.push({
245762
+ type: "label-label",
245763
+ leftComp,
245764
+ rightComp,
245765
+ leftId,
245766
+ rightId,
245767
+ xSeparation: leftBounds.right - rightBounds.left + 0.1
245768
+ });
245769
+ }
245770
+ }
245771
+ }
245772
+ return hits;
245773
+ }
245774
+ detectBoxLabel(boxComp, labelComp) {
245775
+ const boxId = boxComp.schematicComponentId;
245776
+ const labelId = labelComp.schematicComponentId;
245777
+ if (!boxId || !labelId)
245778
+ return [];
245779
+ const labels = this.netLabelsByComponentId.get(labelId) ?? [];
245780
+ if (labels.length === 0)
245781
+ return [];
245782
+ const boxBounds = centeredRect(boxComp.schX, boxComp.schY, boxComp.width, boxComp.height);
245783
+ const boxIsLeft = boxComp.schX <= labelComp.schX;
245784
+ const hits = [];
245785
+ for (const label of labels) {
245786
+ const labelBounds = this.getNetLabelBounds(label);
245787
+ if (!rectOverlap(boxBounds, labelBounds))
245788
+ continue;
245789
+ let xSeparation;
245790
+ if (boxIsLeft) {
245791
+ xSeparation = boxBounds.right - labelBounds.left + 0.1;
245792
+ } else {
245793
+ xSeparation = labelBounds.right - boxBounds.left + 0.1;
245794
+ }
245795
+ hits.push({
245796
+ type: "box-label",
245797
+ boxComp,
245798
+ labelComp,
245799
+ boxId,
245800
+ labelId,
245801
+ xSeparation
245802
+ });
245803
+ }
245804
+ return hits;
245805
+ }
245806
+ buildAndPushIssues() {
245807
+ if (this.rawCollisions.length === 0)
245808
+ return;
245809
+ const globalFixes = this.computeGlobalFixes();
245810
+ if (globalFixes.size === 0)
245811
+ return;
245812
+ const seenPairs = new Set;
245813
+ const pairs3 = [];
245814
+ for (const collision of this.rawCollisions) {
245815
+ let comp1Name;
245816
+ let comp2Name;
245817
+ if (collision.type === "label-label") {
245818
+ comp1Name = collision.leftComp.sourceComponentName ?? "";
245819
+ comp2Name = collision.rightComp.sourceComponentName ?? "";
245820
+ } else {
245821
+ comp1Name = collision.boxComp.sourceComponentName ?? "";
245822
+ comp2Name = collision.labelComp.sourceComponentName ?? "";
245823
+ }
245824
+ const key = `${comp1Name}/${comp2Name}`;
245825
+ if (!seenPairs.has(key)) {
245826
+ seenPairs.add(key);
245827
+ pairs3.push({ comp1Name, comp2Name });
245828
+ }
245829
+ }
245830
+ this.params.issues.push({
245831
+ lineItemType: "NetLabelCollision",
245832
+ pairs: pairs3,
245833
+ moves: Array.from(globalFixes.values())
245834
+ });
245835
+ }
245836
+ computeGlobalFixes() {
245837
+ const compById = new Map;
245838
+ for (const placement of this.placements) {
245839
+ if (placement.schematicComponentId)
245840
+ compById.set(placement.schematicComponentId, placement);
245841
+ }
245842
+ const constraintMap = new Map;
245843
+ const addConstraint = (leftId, rightId, xSeparation) => {
245844
+ const leftComp = compById.get(leftId);
245845
+ const rightComp = compById.get(rightId);
245846
+ if (!leftComp || !rightComp)
245847
+ return;
245848
+ const minSep = rightComp.schX - leftComp.schX + xSeparation;
245849
+ const key = `${leftId}|${rightId}`;
245850
+ constraintMap.set(key, Math.max(constraintMap.get(key) ?? 0, minSep));
245851
+ };
245852
+ for (const collision of this.rawCollisions) {
245853
+ if (collision.type === "label-label") {
245854
+ addConstraint(collision.leftId, collision.rightId, collision.xSeparation);
245855
+ } else if (collision.boxComp.schX <= collision.labelComp.schX) {
245856
+ addConstraint(collision.boxId, collision.labelId, collision.xSeparation);
245857
+ } else {
245858
+ addConstraint(collision.labelId, collision.boxId, collision.xSeparation);
245859
+ }
245860
+ }
245861
+ const constraints = [...constraintMap.entries()].map(([key, minSep]) => {
245862
+ const pipeIndex = key.indexOf("|");
245863
+ return {
245864
+ leftId: key.slice(0, pipeIndex),
245865
+ rightId: key.slice(pipeIndex + 1),
245866
+ minSep
245867
+ };
245868
+ });
245869
+ const allIds = new Set;
245870
+ const adjacency = new Map;
245871
+ for (const { leftId, rightId } of constraints) {
245872
+ allIds.add(leftId);
245873
+ allIds.add(rightId);
245874
+ if (!adjacency.has(leftId))
245875
+ adjacency.set(leftId, new Set);
245876
+ if (!adjacency.has(rightId))
245877
+ adjacency.set(rightId, new Set);
245878
+ adjacency.get(leftId).add(rightId);
245879
+ adjacency.get(rightId).add(leftId);
245880
+ }
245881
+ const visited = new Set;
245882
+ const result = new Map;
245883
+ for (const startId of allIds) {
245884
+ if (visited.has(startId))
245885
+ continue;
245886
+ const group = [];
245887
+ const queue = [startId];
245888
+ visited.add(startId);
245889
+ while (queue.length) {
245890
+ const compId = queue.shift();
245891
+ group.push(compId);
245892
+ for (const neighbor of adjacency.get(compId) ?? []) {
245893
+ if (!visited.has(neighbor)) {
245894
+ visited.add(neighbor);
245895
+ queue.push(neighbor);
245896
+ }
245897
+ }
245898
+ }
245899
+ group.sort((idA, idB) => (compById.get(idA)?.schX ?? 0) - (compById.get(idB)?.schX ?? 0));
245900
+ const groupIds = new Set(group);
245901
+ const groupConstraints = constraints.filter((c3) => groupIds.has(c3.leftId) && groupIds.has(c3.rightId));
245902
+ const assigned = new Map;
245903
+ for (const compId of group) {
245904
+ let newX = compById.get(compId)?.schX ?? 0;
245905
+ for (const { leftId, rightId, minSep } of groupConstraints) {
245906
+ if (rightId === compId && assigned.has(leftId)) {
245907
+ newX = Math.max(newX, assigned.get(leftId) + minSep);
245908
+ }
245909
+ }
245910
+ assigned.set(compId, newX);
245911
+ }
245912
+ const totalPush = [...assigned.entries()].reduce((sum, [compId, newX]) => sum + (newX - (compById.get(compId)?.schX ?? 0)), 0);
245913
+ if (totalPush > 0.000000001) {
245914
+ const pullBack = totalPush / group.length;
245915
+ const shifted = new Map;
245916
+ for (const compId of group) {
245917
+ let newX = (compById.get(compId)?.schX ?? 0) - pullBack;
245918
+ for (const { leftId, rightId, minSep } of groupConstraints) {
245919
+ if (rightId === compId && shifted.has(leftId)) {
245920
+ newX = Math.max(newX, shifted.get(leftId) + minSep);
245921
+ }
245922
+ }
245923
+ shifted.set(compId, newX);
245924
+ }
245925
+ const maxDisplacement = (positions) => [...positions.entries()].reduce((currentMax, [compId, newX]) => Math.max(currentMax, Math.abs(newX - (compById.get(compId)?.schX ?? 0))), 0);
245926
+ if (maxDisplacement(shifted) < maxDisplacement(assigned)) {
245927
+ for (const [compId, newX] of shifted)
245928
+ assigned.set(compId, newX);
245929
+ }
245930
+ }
245931
+ for (const [compId, newX] of assigned) {
245932
+ const comp = compById.get(compId);
245933
+ if (!comp || Math.abs(newX - comp.schX) < 0.000000001)
245934
+ continue;
245935
+ result.set(compId, {
245936
+ componentName: comp.sourceComponentName ?? compId,
245937
+ newSchX: Math.round(newX * 100) / 100,
245938
+ newSchY: Math.round(comp.schY * 100) / 100
245939
+ });
245940
+ }
245941
+ }
245942
+ return result;
245943
+ }
245944
+ buildNetLabelsByComponentId(circuitJson) {
245945
+ const MATCH_EPSILON = 0.0001;
245946
+ const portPositions = [];
245947
+ for (const element of circuitJson) {
245948
+ if (element.type !== "schematic_port")
245949
+ continue;
245950
+ const port = element;
245951
+ if (!port.schematic_component_id)
245952
+ continue;
245953
+ portPositions.push({
245954
+ componentId: port.schematic_component_id,
245955
+ cx: port.center.x,
245956
+ cy: port.center.y
245957
+ });
245958
+ }
245959
+ const result = new Map;
245960
+ for (const element of circuitJson) {
245961
+ if (element.type !== "schematic_net_label")
245962
+ continue;
245963
+ const label = element;
245964
+ if (!label.anchor_position)
245965
+ continue;
245966
+ const { x: anchorX, y: anchorY } = label.anchor_position;
245967
+ const matches = portPositions.filter((port) => Math.hypot(port.cx - anchorX, port.cy - anchorY) < MATCH_EPSILON);
245968
+ if (matches.length === 0)
245969
+ continue;
245970
+ const componentIds = new Set(matches.map((match) => match.componentId));
245971
+ if (componentIds.size !== 1)
245972
+ continue;
245973
+ const componentId = matches[0].componentId;
245974
+ const labels = result.get(componentId) ?? [];
245975
+ labels.push(label);
245976
+ result.set(componentId, labels);
245977
+ }
245978
+ return result;
245979
+ }
245980
+ getNetLabelBounds(label) {
245981
+ const anchorSide = label.anchor_side;
245982
+ const isVertical3 = anchorSide === "top" || anchorSide === "bottom";
245983
+ if (isVertical3) {
245984
+ const anchorY = label.anchor_position?.y ?? label.center.y;
245985
+ const textHalfExtent = (label.text?.length ?? 8) * this.SCH_CHAR_WIDTH / 2 + this.LABEL_BOUNDS_SLACK;
245986
+ const left = label.center.x - this.LABEL_HALF_HEIGHT;
245987
+ const right = label.center.x + this.LABEL_HALF_HEIGHT;
245988
+ if (anchorSide === "top") {
245989
+ return {
245990
+ left,
245991
+ right,
245992
+ top: anchorY,
245993
+ bottom: anchorY - textHalfExtent * 2
245994
+ };
245995
+ }
245996
+ return { left, right, top: anchorY + textHalfExtent * 2, bottom: anchorY };
245997
+ }
245998
+ const anchorX = label.anchor_position?.x ?? label.center.x;
245999
+ const halfWidth = Math.abs(label.center.x - anchorX);
246000
+ const farHalfWidth = halfWidth + this.LABEL_BOUNDS_SLACK;
246001
+ const top = label.center.y + this.LABEL_HALF_HEIGHT;
246002
+ const bottom = label.center.y - this.LABEL_HALF_HEIGHT;
246003
+ if (label.center.x >= anchorX) {
246004
+ return {
246005
+ left: anchorX,
246006
+ right: label.center.x + farHalfWidth,
246007
+ top,
246008
+ bottom
246009
+ };
246010
+ }
246011
+ return { left: label.center.x - farHalfWidth, right: anchorX, top, bottom };
246012
+ }
246013
+ static netLabelCollisionToString(issue) {
246014
+ const pairAttrs = issue.pairs.map((pair, i2) => `pair${i2 + 1}="${pair.comp1Name}/${pair.comp2Name}"`).join(" ");
246015
+ const moves = issue.moves.map((move) => ` <Move componentName="${move.componentName}" newSchX="${move.newSchX}" newSchY="${move.newSchY}" />`);
246016
+ return [
246017
+ `<ComponentNetLabelCollision ${pairAttrs}>`,
246018
+ ` <SuggestedFix note="Apply all moves simultaneously. Set schAutoLayoutEnabled on your circuit.">`,
246019
+ ...moves,
246020
+ ` </SuggestedFix>`,
246021
+ `</ComponentNetLabelCollision>`
246022
+ ].join(`
246023
+ `);
246024
+ }
246025
+ }
246026
+
245679
246027
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPlacementPipeline/SchematicPlacementPipeline.ts
245680
246028
  class SchematicPlacementPipeline extends BasePipelineSolver2 {
245681
246029
  ctx;
@@ -245701,6 +246049,9 @@ class SchematicPlacementPipeline extends BasePipelineSolver2 {
245701
246049
  ]),
245702
246050
  definePipelineStep3("DiodeResistorAlignmentSolver", DiodeResistorAlignmentSolver, (p3) => [
245703
246051
  { ctx: p3.ctx, issues: p3.issues }
246052
+ ]),
246053
+ definePipelineStep3("ComponentNetLabelCollisionSolver", ComponentNetLabelCollisionSolver, (p3) => [
246054
+ { ctx: p3.ctx, issues: p3.issues }
245704
246055
  ])
245705
246056
  ];
245706
246057
  _setup() {
@@ -245753,6 +246104,8 @@ class SchematicPlacementAnalysis {
245753
246104
  return SchematicPinPaddingToEdgeSolver.issueToString(issue);
245754
246105
  case "DiodeResistorNotAligned":
245755
246106
  return DiodeResistorAlignmentSolver.issueToString(issue);
246107
+ case "NetLabelCollision":
246108
+ return ComponentNetLabelCollisionSolver.netLabelCollisionToString(issue);
245756
246109
  default:
245757
246110
  return "";
245758
246111
  }
package/dist/lib/index.js CHANGED
@@ -65733,7 +65733,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
65733
65733
  }));
65734
65734
  };
65735
65735
  // package.json
65736
- var version = "0.1.1432";
65736
+ var version = "0.1.1434";
65737
65737
  var package_default = {
65738
65738
  name: "@tscircuit/cli",
65739
65739
  version,
@@ -65747,7 +65747,7 @@ var package_default = {
65747
65747
  "@biomejs/biome": "^1.9.4",
65748
65748
  "@tscircuit/circuit-json-placement-analysis": "^0.0.6",
65749
65749
  "@tscircuit/circuit-json-routing-analysis": "^0.0.1",
65750
- "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#700017d79a608295cc275dcb9c2e1d160809ef9e",
65750
+ "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#40f49bb8ae9dabedb19b47ec0a621c713b40615c",
65751
65751
  "@tscircuit/eval": "^0.0.835",
65752
65752
  "@tscircuit/fake-snippets": "^0.0.182",
65753
65753
  "@tscircuit/file-server": "^0.0.32",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1434",
3
+ "version": "0.1.1435",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",
@@ -11,7 +11,7 @@
11
11
  "@biomejs/biome": "^1.9.4",
12
12
  "@tscircuit/circuit-json-placement-analysis": "^0.0.6",
13
13
  "@tscircuit/circuit-json-routing-analysis": "^0.0.1",
14
- "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#700017d79a608295cc275dcb9c2e1d160809ef9e",
14
+ "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#40f49bb8ae9dabedb19b47ec0a621c713b40615c",
15
15
  "@tscircuit/eval": "^0.0.835",
16
16
  "@tscircuit/fake-snippets": "^0.0.182",
17
17
  "@tscircuit/file-server": "^0.0.32",