@tscircuit/cli 0.1.2211 → 0.1.2212

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
@@ -154298,7 +154298,7 @@ var import_perfect_cli = __toESM3(require_dist3(), 1);
154298
154298
  // lib/getVersion.ts
154299
154299
  import { createRequire as createRequire2 } from "node:module";
154300
154300
  // package.json
154301
- var version = "0.1.2210";
154301
+ var version = "0.1.2211";
154302
154302
  var package_default = {
154303
154303
  name: "@tscircuit/cli",
154304
154304
  version,
@@ -154317,7 +154317,7 @@ var package_default = {
154317
154317
  "@tscircuit/check-shorts": "https://jscdn.tscircuit.com/@tscircuit/check-shorts/0.0.26.tgz",
154318
154318
  "@tscircuit/circuit-json-placement-analysis": "^0.0.15",
154319
154319
  "@tscircuit/circuit-json-routing-analysis": "^0.0.8",
154320
- "@tscircuit/circuit-json-schematic-placement-analysis": "https://jscdn.tscircuit.com/@tscircuit/circuit-json-schematic-placement-analysis/0.0.11.tgz",
154320
+ "@tscircuit/circuit-json-schematic-placement-analysis": "https://jscdn.tscircuit.com/@tscircuit/circuit-json-schematic-placement-analysis/0.0.33.tgz",
154321
154321
  "@tscircuit/circuit-json-util": "^0.0.116",
154322
154322
  "@tscircuit/eval": "0.0.1402",
154323
154323
  "@tscircuit/fake-snippets": "^0.0.182",
@@ -330754,7 +330754,7 @@ var registerCheckRoutingDifficulty = (program) => {
330754
330754
  });
330755
330755
  };
330756
330756
 
330757
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ConnectorPlacementSolver/ConnectorPlacementSolver.ts
330757
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/MosfetGateNetworkPlacementSolver/MosfetGateNetworkPlacementSolver.ts
330758
330758
  import { BaseSolver as BaseSolver5 } from "@tscircuit/solver-utils";
330759
330759
 
330760
330760
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/format.ts
@@ -330775,21 +330775,6 @@ var addAttr = (attrs, key, value, options) => {
330775
330775
  attrs.push(`${key}="${stringValue}"`);
330776
330776
  };
330777
330777
 
330778
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/geometry.ts
330779
- function centeredRect(cx, cy, w, h) {
330780
- return {
330781
- left: cx - w / 2,
330782
- right: cx + w / 2,
330783
- top: cy + h / 2,
330784
- bottom: cy - h / 2
330785
- };
330786
- }
330787
- function rectOverlap(a, b) {
330788
- const ow = Math.min(a.right, b.right) - Math.max(a.left, b.left);
330789
- const oh = Math.min(a.top, b.top) - Math.max(a.bottom, b.bottom);
330790
- return ow > 0 && oh > 0 ? { ow, oh } : null;
330791
- }
330792
-
330793
330778
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/source-connectivity.ts
330794
330779
  function getSourceConnectivity(circuitJson) {
330795
330780
  const parent = new Map;
@@ -330934,8 +330919,632 @@ function append2(map, key, value) {
330934
330919
  map.set(key, [value]);
330935
330920
  }
330936
330921
 
330937
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ConnectorPlacementSolver/ConnectorPlacementSolver.ts
330922
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/MosfetGateNetworkPlacementSolver/MosfetGateNetworkPlacementSolver.ts
330923
+ class MosfetGateNetworkPlacementSolver extends BaseSolver5 {
330924
+ params;
330925
+ index;
330926
+ mosfetIds;
330927
+ currentIndex = 0;
330928
+ constructor(params2) {
330929
+ super();
330930
+ this.params = params2;
330931
+ this.index = new PlacementNetworkIndex(params2.ctx);
330932
+ this.mosfetIds = [...this.index.components.keys()].filter((id) => this.mosfetPorts(id));
330933
+ this.solved = this.mosfetIds.length === 0;
330934
+ }
330935
+ _step() {
330936
+ const id = this.mosfetIds[this.currentIndex++];
330937
+ this.solved = this.currentIndex >= this.mosfetIds.length;
330938
+ if (!id)
330939
+ return;
330940
+ const index = this.index;
330941
+ const mosfet = index.placement(id);
330942
+ const roles = this.mosfetPorts(id);
330943
+ if (!mosfet)
330944
+ return;
330945
+ const gateNet = index.connected(roles.gate.source_port_id);
330946
+ const sourceNet = index.connected(roles.sources[0].source_port_id);
330947
+ const drainNet = index.connected(roles.drains[0].source_port_id);
330948
+ if (new Set([gateNet, sourceNet, drainNet]).size !== 3 || index.isRail(gateNet))
330949
+ return;
330950
+ if ([roles.gate, ...roles.sources, ...roles.drains].some((p) => {
330951
+ const pin = index.port(p);
330952
+ return !pin || pin.schematic_sheet_id !== mosfet.schematicSheetId;
330953
+ }))
330954
+ return;
330955
+ const peers = (index.portsByNet.get(gateNet) ?? []).filter((p) => p.source_component_id !== id);
330956
+ if (peers.length !== 2)
330957
+ return;
330958
+ const resistors = peers.map((p) => {
330959
+ const resistorId = p.source_component_id;
330960
+ const component = index.components.get(resistorId);
330961
+ const placement = index.placement(resistorId);
330962
+ const nets = index.twoTerminalNets(resistorId);
330963
+ if (component?.ftype !== "simple_resistor" || !Number.isFinite(component.resistance) || component.resistance <= 0 || !placement || !nets || !index.sameLocalScope(mosfet, placement) || index.portsByComponent.get(resistorId).some((port) => {
330964
+ const pin = index.port(port);
330965
+ return port.do_not_connect || !pin || pin.schematic_sheet_id !== mosfet.schematicSheetId;
330966
+ }))
330967
+ return;
330968
+ return { placement, otherNet: nets.find((net) => net !== gateNet) };
330969
+ });
330970
+ if (resistors.some((r) => !r))
330971
+ return;
330972
+ const shunts = resistors.filter((r) => r.otherNet === sourceNet);
330973
+ const series = resistors.filter((r) => r.otherNet !== sourceNet);
330974
+ if (shunts.length !== 1 || series.length !== 1)
330975
+ return;
330976
+ const gateSourceResistor = shunts[0].placement;
330977
+ const seriesGateResistor = series[0].placement;
330978
+ if (series[0].otherNet === drainNet || index.isRail(series[0].otherNet))
330979
+ return;
330980
+ const maxRecommendedBodyGap = Math.max(6, 3 * Math.max(mosfet.width, mosfet.height));
330981
+ const maxBodyGap = Math.max(bodyGap(mosfet, seriesGateResistor), bodyGap(mosfet, gateSourceResistor));
330982
+ if (maxBodyGap <= maxRecommendedBodyGap)
330983
+ return;
330984
+ this.params.issues.push({
330985
+ lineItemType: "MosfetGateNetworkNotGrouped",
330986
+ mosfetSchematicBox: mosfet,
330987
+ seriesGateResistorSchematicBox: seriesGateResistor,
330988
+ gateSourceResistorSchematicBox: gateSourceResistor,
330989
+ maxBodyGap,
330990
+ maxRecommendedBodyGap,
330991
+ message: `Group ${seriesGateResistor.sourceComponentName ?? seriesGateResistor.sourceComponentId} and ${gateSourceResistor.sourceComponentName ?? gateSourceResistor.sourceComponentId} beside ${mosfet.sourceComponentName ?? id}'s gate/source pins so the gate-drive branch can be read together. Preserve all pin connections, leave room for labels, and reroute affected traces.`
330992
+ });
330993
+ }
330994
+ mosfetPorts(id) {
330995
+ const type = this.index.components.get(id)?.ftype;
330996
+ if (type !== "simple_mosfet" && type !== "simple_chip")
330997
+ return;
330998
+ const ports = this.index.portsByComponent.get(id) ?? [];
330999
+ const gate = ports.filter((p) => hasRole(p, /^(G|GATE)$/));
331000
+ const sources = ports.filter((p) => hasRole(p, /^(S|SOURCE)[0-9]*$/));
331001
+ const drains = ports.filter((p) => hasRole(p, /^(D|DRAIN)[0-9]*$/));
331002
+ if (gate.length !== 1 || !sources.length || !drains.length || gate.length + sources.length + drains.length !== ports.length || new Set([...gate, ...sources, ...drains]).size !== ports.length || ports.some((p) => p.do_not_connect))
331003
+ return;
331004
+ for (const group of [sources, drains])
331005
+ if (new Set(group.map((p) => this.index.connected(p.source_port_id))).size !== 1)
331006
+ return;
331007
+ return { gate: gate[0], sources, drains };
331008
+ }
331009
+ static issueToString(issue) {
331010
+ const attrs = [];
331011
+ addAttr(attrs, "mosfetName", issue.mosfetSchematicBox.sourceComponentName);
331012
+ addAttr(attrs, "seriesGateResistorName", issue.seriesGateResistorSchematicBox.sourceComponentName);
331013
+ addAttr(attrs, "gateSourceResistorName", issue.gateSourceResistorSchematicBox.sourceComponentName);
331014
+ addAttr(attrs, "maxBodyGap", issue.maxBodyGap);
331015
+ addAttr(attrs, "maxRecommendedBodyGap", issue.maxRecommendedBodyGap);
331016
+ addAttr(attrs, "message", issue.message);
331017
+ return `<MosfetGateNetworkNotGrouped ${attrs.join(" ")} />`;
331018
+ }
331019
+ }
331020
+ function hasRole(port, pattern) {
331021
+ return [port.name, ...port.port_hints ?? []].some((hint) => pattern.test(hint.toUpperCase().replace(/[\s_]/g, "")));
331022
+ }
331023
+ function bodyGap(a, b) {
331024
+ return Math.hypot(Math.max(0, Math.abs(a.schX - b.schX) - (a.width + b.width) / 2), Math.max(0, Math.abs(a.schY - b.schY) - (a.height + b.height) / 2));
331025
+ }
331026
+
331027
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/RelayFlybackDiodePlacementSolver/RelayFlybackDiodePlacementSolver.ts
331028
+ import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
331029
+ class RelayFlybackDiodePlacementSolver extends BaseSolver6 {
331030
+ params;
331031
+ index;
331032
+ relayIds;
331033
+ currentIndex = 0;
331034
+ constructor(params2) {
331035
+ super();
331036
+ this.params = params2;
331037
+ this.index = new PlacementNetworkIndex(params2.ctx);
331038
+ this.relayIds = [...this.index.components.keys()].filter((id) => this.coilPorts(id));
331039
+ this.solved = this.relayIds.length === 0;
331040
+ }
331041
+ _step() {
331042
+ const relayId = this.relayIds[this.currentIndex++];
331043
+ this.solved = this.currentIndex >= this.relayIds.length;
331044
+ if (!relayId)
331045
+ return;
331046
+ const index = this.index;
331047
+ const relay = index.placement(relayId);
331048
+ const coil = this.coilPorts(relayId);
331049
+ if (!relay || coil.some((p) => p.do_not_connect))
331050
+ return;
331051
+ const nets = coil.map((p) => index.connected(p.source_port_id));
331052
+ if (nets[0] === nets[1])
331053
+ return;
331054
+ if (this.relayIds.some((id) => id !== relayId && this.coilPorts(id).every((p) => nets.includes(index.connected(p.source_port_id)))))
331055
+ return;
331056
+ const diodeIds = new Set((index.portsByNet.get(nets[0]) ?? []).filter((p) => index.components.get(p.source_component_id)?.ftype === "simple_diode").map((p) => p.source_component_id).filter((id) => index.twoTerminalNets(id)?.includes(nets[1])));
331057
+ if (diodeIds.size !== 1)
331058
+ return;
331059
+ const diodeId = [...diodeIds][0];
331060
+ const diode = index.placement(diodeId);
331061
+ const anode = this.uniquePort(diodeId, /^(?:ANODE|A)$/);
331062
+ const cathode = this.uniquePort(diodeId, /^(?:CATHODE|K)$/);
331063
+ if (!diode || !index.sameLocalScope(relay, diode) || !anode || !cathode || anode === cathode || anode.do_not_connect || cathode.do_not_connect)
331064
+ return;
331065
+ const anodeNet = index.connected(anode.source_port_id);
331066
+ const cathodeNet = index.connected(cathode.source_port_id);
331067
+ if (index.isRail(anodeNet) || index.groundNets.has(cathodeNet) || !this.hasGroundedDriver(anodeNet, cathodeNet))
331068
+ return;
331069
+ const coilPins = coil.map((p) => index.port(p));
331070
+ const diodePins = [anode, cathode].map((p) => index.port(p));
331071
+ if ([...coilPins, ...diodePins].some((p) => !p || p.schematic_sheet_id !== relay.schematicSheetId))
331072
+ return;
331073
+ const [first, second] = coilPins;
331074
+ const left = Math.min(first.center.x, second.center.x);
331075
+ const right = Math.max(first.center.x, second.center.x);
331076
+ const bottom = Math.min(first.center.y, second.center.y);
331077
+ const top = Math.max(first.center.y, second.center.y);
331078
+ const gapX = Math.max(left - (diode.schX + diode.width / 2), diode.schX - diode.width / 2 - right, 0);
331079
+ const gapY = Math.max(bottom - (diode.schY + diode.height / 2), diode.schY - diode.height / 2 - top, 0);
331080
+ const distanceFromCoilPins = Math.hypot(gapX, gapY);
331081
+ const pinSpan = Math.hypot(right - left, top - bottom);
331082
+ if (distanceFromCoilPins <= Math.max(1.5, 2 * pinSpan) || distanceFromCoilPins > Math.max(8, 4 * Math.max(relay.width, relay.height)))
331083
+ return;
331084
+ if (!this.params.ctx.circuitJson.some((e) => e.type === "schematic_net_label" && e.schematic_sheet_id === relay.schematicSheetId && e.anchor_position && diodePins.some((p) => Math.hypot(p.center.x - e.anchor_position.x, p.center.y - e.anchor_position.y) < 0.01 && !this.hasWireAtPin(p))))
331085
+ return;
331086
+ this.params.issues.push({
331087
+ lineItemType: "FlybackDiodeSeparatedFromRelayCoil",
331088
+ relaySchematicBox: relay,
331089
+ diodeSchematicBox: diode,
331090
+ coilSourcePortIds: [coil[0].source_port_id, coil[1].source_port_id],
331091
+ distanceFromCoilPins,
331092
+ message: `Place ${diode.sourceComponentName ?? diodeId} beside ${relay.sourceComponentName ?? relayId}'s coil pins so the flyback protection loop can be read together. Preserve diode polarity and all pin connections; leave room for labels and reroute affected traces.`
331093
+ });
331094
+ }
331095
+ hasWireAtPin(pin) {
331096
+ return this.params.ctx.circuitJson.some((e) => e.type === "schematic_trace" && e.schematic_sheet_id === pin.schematic_sheet_id && e.edges.some(({ from, to }) => {
331097
+ const dx = to.x - from.x, dy = to.y - from.y;
331098
+ const lengthSquared = dx * dx + dy * dy;
331099
+ const t = lengthSquared ? Math.max(0, Math.min(1, ((pin.center.x - from.x) * dx + (pin.center.y - from.y) * dy) / lengthSquared)) : 0;
331100
+ return Math.hypot(pin.center.x - from.x - t * dx, pin.center.y - from.y - t * dy) < 0.01;
331101
+ }));
331102
+ }
331103
+ uniquePort(id, pattern) {
331104
+ const ports = this.index.portsByComponent.get(id)?.filter((p) => hasHint(p, pattern));
331105
+ return ports?.length === 1 ? ports[0] : undefined;
331106
+ }
331107
+ coilPorts(id) {
331108
+ if (this.index.components.get(id)?.ftype !== "simple_chip")
331109
+ return;
331110
+ const ports = this.index.portsByComponent.get(id) ?? [];
331111
+ if (!this.uniquePort(id, /^(?:COM|COMMON)$/) || !ports.some((p) => hasHint(p, /^(?:NO|NC|NORMALLYOPEN|NORMALLYCLOSED)$/)))
331112
+ return;
331113
+ const coil = ports.filter((p) => hasHint(p, /^(?:COIL[A-B12]|A[12])$/));
331114
+ if (coil.length !== 2)
331115
+ return;
331116
+ for (const [a, b] of [
331117
+ ["COILA", "COILB"],
331118
+ ["COIL1", "COIL2"],
331119
+ ["A1", "A2"]
331120
+ ]) {
331121
+ const first = this.uniquePort(id, new RegExp(`^${a}$`));
331122
+ const second = this.uniquePort(id, new RegExp(`^${b}$`));
331123
+ if (first && second && first !== second && !hasHint(first, new RegExp(`^${b}$`)) && !hasHint(second, new RegExp(`^${a}$`)))
331124
+ return [first, second];
331125
+ }
331126
+ }
331127
+ hasGroundedDriver(anodeNet, cathodeNet) {
331128
+ return (this.index.portsByNet.get(anodeNet) ?? []).some((p) => {
331129
+ const id = p.source_component_id;
331130
+ const component = this.index.components.get(id);
331131
+ if (component?.ftype !== "simple_chip" && !(component?.ftype === "simple_transistor" && component.transistor_type === "npn"))
331132
+ return false;
331133
+ if (this.index.portsByComponent.get(id)?.length !== 3)
331134
+ return false;
331135
+ const c = this.uniquePort(id, /^(?:C|COLLECTOR)$/);
331136
+ const e = this.uniquePort(id, /^(?:E|EMITTER)$/);
331137
+ const b = this.uniquePort(id, /^(?:B|BASE)$/);
331138
+ if (!c || !e || !b || new Set([c, e, b]).size !== 3 || [c, e, b].some((p) => p.do_not_connect) || c.source_port_id !== p.source_port_id)
331139
+ return false;
331140
+ const emitterNet = this.index.connected(e.source_port_id), baseNet = this.index.connected(b.source_port_id);
331141
+ return this.index.groundNets.has(emitterNet) && !this.index.powerNets.has(emitterNet) && new Set([anodeNet, cathodeNet, emitterNet, baseNet]).size === 4;
331142
+ });
331143
+ }
331144
+ static issueToString(issue) {
331145
+ const attrs = [];
331146
+ addAttr(attrs, "relayName", issue.relaySchematicBox.sourceComponentName);
331147
+ addAttr(attrs, "diodeName", issue.diodeSchematicBox.sourceComponentName);
331148
+ addAttr(attrs, "distanceFromCoilPins", issue.distanceFromCoilPins);
331149
+ addAttr(attrs, "message", issue.message);
331150
+ return `<FlybackDiodeSeparatedFromRelayCoil ${attrs.join(" ")} />`;
331151
+ }
331152
+ }
331153
+ function hasHint(port, pattern) {
331154
+ return [port.name, ...port.port_hints ?? []].some((hint) => pattern.test(hint.toUpperCase().replace(/[\s_]/g, "")));
331155
+ }
331156
+
331157
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CurrentSenseShuntPlacementSolver/CurrentSenseShuntPlacementSolver.ts
331158
+ import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
330938
331159
  var EPSILON3 = 0.01;
331160
+
331161
+ class CurrentSenseShuntPlacementSolver extends BaseSolver7 {
331162
+ params;
331163
+ index;
331164
+ hostIds;
331165
+ traces;
331166
+ currentIndex = 0;
331167
+ constructor(params2) {
331168
+ super();
331169
+ this.params = params2;
331170
+ this.index = new PlacementNetworkIndex(params2.ctx);
331171
+ this.hostIds = [...this.index.components.values()].filter((component) => component.ftype === "simple_chip").map((component) => component.source_component_id);
331172
+ this.traces = params2.ctx.circuitJson.filter((element) => element.type === "schematic_trace");
331173
+ this.solved = this.hostIds.length === 0;
331174
+ }
331175
+ _step() {
331176
+ const hostId = this.hostIds[this.currentIndex++];
331177
+ this.solved = this.currentIndex >= this.hostIds.length;
331178
+ if (!hostId)
331179
+ return;
331180
+ const index = this.index;
331181
+ const host = index.placement(hostId);
331182
+ const ports = index.portsByComponent.get(hostId) ?? [];
331183
+ const positive = ports.filter((port) => inputRole(port) === "positive");
331184
+ const negative = ports.filter((port) => inputRole(port) === "negative");
331185
+ const outputs = ports.filter((port) => hasHint2(port, /^(?:OUT|VOUT|OUTPUT)$/));
331186
+ if (!host || positive.length !== 1 || negative.length !== 1 || outputs.length !== 1 || !ports.some((port) => hasHint2(port, /^(?:VS|VCC|VDD)$/)) || !ports.some((port) => hasHint2(port, /^(?:GND|GROUND|VSS)$/)))
331187
+ return;
331188
+ const inputs = [positive[0], negative[0]];
331189
+ const nets = inputs.map((port) => index.connected(port.source_port_id));
331190
+ if (inputs.some((port) => port.do_not_connect) || nets[0] === nets[1] || nets.includes(index.connected(outputs[0].source_port_id)))
331191
+ return;
331192
+ const pins = inputs.map((port) => index.port(port));
331193
+ const [positivePin, negativePin] = pins;
331194
+ if (!positivePin || !negativePin || !positivePin.facing_direction || positivePin.facing_direction !== negativePin.facing_direction || pins.some((pin) => pin.schematic_sheet_id !== host.schematicSheetId))
331195
+ return;
331196
+ const resistorIds = new Set((index.portsByNet.get(nets[0]) ?? []).filter((port) => index.components.get(port.source_component_id)?.ftype === "simple_resistor").map((port) => port.source_component_id).filter((id) => index.twoTerminalNets(id)?.includes(nets[1])));
331197
+ if (resistorIds.size !== 1)
331198
+ return;
331199
+ const shuntId = [...resistorIds][0];
331200
+ const component = index.components.get(shuntId);
331201
+ if (component?.ftype !== "simple_resistor" || !Number.isFinite(component.resistance) || component.resistance <= 0 || component.resistance > 1)
331202
+ return;
331203
+ if (nets.some((net) => (index.portsByNet.get(net) ?? []).some((port) => port.source_component_id !== hostId && inputRole(port) !== undefined && index.components.get(port.source_component_id)?.ftype === "simple_chip")))
331204
+ return;
331205
+ const shunt = index.placement(shuntId);
331206
+ if (!shunt || !index.sameLocalScope(host, shunt))
331207
+ return;
331208
+ const shuntPorts = index.portsByComponent.get(shuntId);
331209
+ if (shuntPorts.some((port) => port.do_not_connect))
331210
+ return;
331211
+ const shuntPins = nets.map((net) => index.port(shuntPorts.find((port) => index.connected(port.source_port_id) === net)));
331212
+ if (shuntPins.some((pin) => !pin || pin.schematic_sheet_id !== host.schematicSheetId))
331213
+ return;
331214
+ const horizontalInputs = positivePin.facing_direction === "left" || positivePin.facing_direction === "right";
331215
+ const across = (point) => horizontalInputs ? point.y : point.x;
331216
+ const first = across(positivePin.center), second = across(negativePin.center);
331217
+ const span = Math.abs(first - second);
331218
+ if (span < EPSILON3)
331219
+ return;
331220
+ const shuntAcross = horizontalInputs ? shunt.schY : shunt.schX;
331221
+ const halfSize = (horizontalInputs ? shunt.height : shunt.width) / 2;
331222
+ const inputBandGap = Math.max(Math.min(first, second) - (shuntAcross + halfSize), shuntAcross - halfSize - Math.max(first, second));
331223
+ if (inputBandGap <= Math.max(1.5, 2 * span) || Math.hypot(shunt.schX - host.schX, shunt.schY - host.schY) > Math.max(8, 4 * Math.max(host.width, host.height)))
331224
+ return;
331225
+ const visible = pins.map((pin, i) => this.hasVisibleConnection(shuntPins[i], pin, nets[i]));
331226
+ if (visible[0] === visible[1])
331227
+ return;
331228
+ const labeledIndex = visible[0] ? 1 : 0;
331229
+ const labeledNet = nets[labeledIndex];
331230
+ if (!this.params.ctx.circuitJson.some((element) => {
331231
+ if (element.type !== "schematic_net_label" || element.schematic_sheet_id !== host.schematicSheetId)
331232
+ return false;
331233
+ if (element.source_net_id && (index.connected(element.source_net_id) === labeledNet || index.connected(`connectivity:${element.source_net_id}`) === labeledNet))
331234
+ return true;
331235
+ const pin = shuntPins[labeledIndex].center;
331236
+ if (element.anchor_position && Math.hypot(element.anchor_position.x - pin.x, element.anchor_position.y - pin.y) < EPSILON3)
331237
+ return true;
331238
+ return element.source_trace_id !== undefined && this.sourceTraceTouchesNet(element.source_trace_id, labeledNet);
331239
+ }))
331240
+ return;
331241
+ this.params.issues.push({
331242
+ lineItemType: "CurrentSenseShuntSeparatedFromInputs",
331243
+ amplifierSchematicBox: host,
331244
+ shuntSchematicBox: shunt,
331245
+ positiveInputSourcePortId: inputs[0].source_port_id,
331246
+ negativeInputSourcePortId: inputs[1].source_port_id,
331247
+ inputBandGap,
331248
+ message: `Place ${shunt.sourceComponentName ?? shuntId} near ${host.sourceComponentName ?? hostId}.${inputs[0].name}/${inputs[1].name}, so both sense connections can be read together. Move or rotate the shunt as needed; preserve all pin connections and leave room for labels.`
331249
+ });
331250
+ }
331251
+ hasVisibleConnection(from, to, net) {
331252
+ const edges = this.traces.filter((trace) => {
331253
+ if (trace.schematic_sheet_id !== from.schematic_sheet_id)
331254
+ return false;
331255
+ if (trace.subcircuit_connectivity_map_key)
331256
+ return this.index.connected(`connectivity:${trace.subcircuit_connectivity_map_key}`) === net;
331257
+ if (this.sourceTraceTouchesNet(trace.source_trace_id, net))
331258
+ return true;
331259
+ const endpoints = [trace.edges[0]?.from, trace.edges.at(-1)?.to];
331260
+ const endpointNets = new Set(this.params.ctx.circuitJson.flatMap((element) => element.type === "schematic_port" && element.source_port_id && element.schematic_sheet_id === trace.schematic_sheet_id && endpoints.some((point) => point && Math.hypot(point.x - element.center.x, point.y - element.center.y) < EPSILON3) ? [this.index.connected(element.source_port_id)] : []));
331261
+ return endpointNets.size === 1 && endpointNets.has(net);
331262
+ }).flatMap((trace) => trace.edges);
331263
+ const reached = edges.filter((edge) => onSegment4(from.center, edge.from, edge.to));
331264
+ const visited = new Set;
331265
+ for (let i = 0;i < reached.length; i++) {
331266
+ const current = reached[i];
331267
+ if (onSegment4(to.center, current.from, current.to))
331268
+ return true;
331269
+ for (const [edgeIndex, edge] of edges.entries()) {
331270
+ if (visited.has(edgeIndex) || ![current.from, current.to].some((point) => onSegment4(point, edge.from, edge.to)) && ![edge.from, edge.to].some((point) => onSegment4(point, current.from, current.to)))
331271
+ continue;
331272
+ visited.add(edgeIndex);
331273
+ reached.push(edge);
331274
+ }
331275
+ }
331276
+ return false;
331277
+ }
331278
+ sourceTraceTouchesNet(traceId, net) {
331279
+ if (!traceId)
331280
+ return false;
331281
+ const source = this.params.ctx.circuitJson.find((element) => element.type === "source_trace" && element.source_trace_id === traceId);
331282
+ return source?.type === "source_trace" && source.connected_source_port_ids.some((id) => this.index.connected(id) === net);
331283
+ }
331284
+ static issueToString(issue) {
331285
+ const attrs = [];
331286
+ addAttr(attrs, "amplifierName", issue.amplifierSchematicBox.sourceComponentName);
331287
+ addAttr(attrs, "shuntName", issue.shuntSchematicBox.sourceComponentName);
331288
+ addAttr(attrs, "inputBandGap", issue.inputBandGap);
331289
+ addAttr(attrs, "message", issue.message);
331290
+ return `<CurrentSenseShuntSeparatedFromInputs ${attrs.join(" ")} />`;
331291
+ }
331292
+ }
331293
+ function hasHint2(port, pattern) {
331294
+ return [port.name, ...port.port_hints ?? []].some((hint) => pattern.test(hint.toUpperCase().replace(/[\s_]/g, "")));
331295
+ }
331296
+ function inputRole(port) {
331297
+ const positive = hasHint2(port, /^(?:IN\+|VIN\+|INPOS|VINPOS)$/);
331298
+ const negative = hasHint2(port, /^(?:IN-|VIN-|INNEG|VINNEG)$/);
331299
+ return positive === negative ? undefined : positive ? "positive" : "negative";
331300
+ }
331301
+ function onSegment4(point, from, to) {
331302
+ const dx = to.x - from.x, dy = to.y - from.y;
331303
+ const length = Math.hypot(dx, dy);
331304
+ if (length < EPSILON3)
331305
+ return Math.hypot(point.x - from.x, point.y - from.y) < EPSILON3;
331306
+ const projection = ((point.x - from.x) * dx + (point.y - from.y) * dy) / length;
331307
+ return projection >= -EPSILON3 && projection <= length + EPSILON3 && Math.abs((point.x - from.x) * dy - (point.y - from.y) * dx) / length < EPSILON3;
331308
+ }
331309
+
331310
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/VoltageDividerPlacementSolver/VoltageDividerPlacementSolver.ts
331311
+ import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
331312
+ class VoltageDividerPlacementSolver extends BaseSolver8 {
331313
+ params;
331314
+ index;
331315
+ positiveNets = new Set;
331316
+ resistorIds;
331317
+ currentIndex = 0;
331318
+ constructor(params2) {
331319
+ super();
331320
+ this.params = params2;
331321
+ this.index = new PlacementNetworkIndex(params2.ctx);
331322
+ this.resistorIds = [...this.index.components.values()].filter((component) => component.ftype === "simple_resistor").map((component) => component.source_component_id);
331323
+ for (const element of params2.ctx.circuitJson) {
331324
+ if (element.type === "source_net" && element.is_positive_voltage_source)
331325
+ this.positiveNets.add(this.index.connected(element.source_net_id));
331326
+ }
331327
+ this.solved = this.resistorIds.length === 0;
331328
+ }
331329
+ _step() {
331330
+ const supplyId = this.resistorIds[this.currentIndex++];
331331
+ this.solved = this.currentIndex >= this.resistorIds.length;
331332
+ if (!supplyId || !this.isResistor(supplyId))
331333
+ return;
331334
+ const index = this.index;
331335
+ const nets = index.twoTerminalNets(supplyId);
331336
+ if (!nets)
331337
+ return;
331338
+ const rails = nets.filter((net) => index.isRail(net));
331339
+ if (rails.length !== 1)
331340
+ return;
331341
+ const supplyNet = rails[0];
331342
+ if (!this.positiveNets.has(supplyNet) || index.groundNets.has(supplyNet))
331343
+ return;
331344
+ const tap = nets.find((net) => net !== supplyNet);
331345
+ const tapPorts = index.portsByNet.get(tap) ?? [];
331346
+ const resistorIds = new Set(tapPorts.filter((port) => index.components.get(port.source_component_id)?.ftype === "simple_resistor").map((port) => port.source_component_id));
331347
+ if (resistorIds.size !== 2)
331348
+ return;
331349
+ const groundId = [...resistorIds].find((id) => id !== supplyId);
331350
+ if (!this.isResistor(groundId))
331351
+ return;
331352
+ const groundNets = index.twoTerminalNets(groundId);
331353
+ const groundNet = groundNets?.find((net) => net !== tap);
331354
+ if (!groundNets?.includes(tap) || !groundNet || !index.groundNets.has(groundNet) || index.powerNets.has(groundNet) || !tapPorts.some((port) => !resistorIds.has(port.source_component_id)))
331355
+ return;
331356
+ const supply = index.placement(supplyId);
331357
+ const ground = index.placement(groundId);
331358
+ if (!supply || !ground || !index.sameLocalScope(supply, ground))
331359
+ return;
331360
+ const supplyTap = this.getDownwardResistorPorts(supplyId, supplyNet, tap);
331361
+ const groundTap = this.getDownwardResistorPorts(groundId, tap, groundNet);
331362
+ if (!supplyTap || !groundTap)
331363
+ return;
331364
+ const reversedBodyGap = ground.schY - ground.height / 2 - (supply.schY + supply.height / 2);
331365
+ if (reversedBodyGap <= 1.5)
331366
+ return;
331367
+ this.params.issues.push({
331368
+ lineItemType: "VoltageDividerSupplyResistorBelowGroundResistor",
331369
+ supplyResistorSchematicBox: supply,
331370
+ groundResistorSchematicBox: ground,
331371
+ supplyTapSourcePortId: supplyTap.bottom.source_port_id,
331372
+ groundTapSourcePortId: groundTap.top.source_port_id,
331373
+ reversedBodyGap,
331374
+ message: `Place ${supply.sourceComponentName ?? supplyId} above ${ground.sourceComponentName ?? groundId}, close enough to read their shared divider tap. Preserve all connections and leave room for labels; exact alignment is not required.`
331375
+ });
331376
+ }
331377
+ isResistor(id) {
331378
+ const component = this.index.components.get(id);
331379
+ return component?.ftype === "simple_resistor" && Number.isFinite(component.resistance) && component.resistance > 0;
331380
+ }
331381
+ getDownwardResistorPorts(id, topNet, bottomNet) {
331382
+ const index = this.index;
331383
+ const placement = index.placement(id);
331384
+ const ports = index.portsByComponent.get(id);
331385
+ if (ports.some((port) => port.do_not_connect))
331386
+ return;
331387
+ const top = ports.find((port) => index.connected(port.source_port_id) === topNet);
331388
+ const bottom = ports.find((port) => index.connected(port.source_port_id) === bottomNet);
331389
+ if (!top || !bottom)
331390
+ return;
331391
+ const topPin = index.port(top);
331392
+ const bottomPin = index.port(bottom);
331393
+ if (!topPin || !bottomPin || topPin.schematic_sheet_id !== placement.schematicSheetId || bottomPin.schematic_sheet_id !== placement.schematicSheetId || topPin.facing_direction !== "up" || bottomPin.facing_direction !== "down" || topPin.center.y <= bottomPin.center.y)
331394
+ return;
331395
+ return { top, bottom };
331396
+ }
331397
+ static issueToString(issue) {
331398
+ const attrs = [];
331399
+ addAttr(attrs, "supplyResistorName", issue.supplyResistorSchematicBox.sourceComponentName);
331400
+ addAttr(attrs, "groundResistorName", issue.groundResistorSchematicBox.sourceComponentName);
331401
+ addAttr(attrs, "reversedBodyGap", issue.reversedBodyGap);
331402
+ addAttr(attrs, "message", issue.message);
331403
+ return `<VoltageDividerSupplyResistorBelowGroundResistor ${attrs.join(" ")} />`;
331404
+ }
331405
+ }
331406
+
331407
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/RegulatorInputOutputCapacitorPlacementSolver/RegulatorInputOutputCapacitorPlacementSolver.ts
331408
+ import { BaseSolver as BaseSolver9 } from "@tscircuit/solver-utils";
331409
+ class RegulatorInputOutputCapacitorPlacementSolver extends BaseSolver9 {
331410
+ params;
331411
+ index;
331412
+ hostIds;
331413
+ currentIndex = 0;
331414
+ constructor(params2) {
331415
+ super();
331416
+ this.params = params2;
331417
+ this.index = new PlacementNetworkIndex(params2.ctx);
331418
+ this.hostIds = [...this.index.components.values()].filter((component) => component.ftype === "simple_chip").map((component) => component.source_component_id);
331419
+ this.solved = this.hostIds.length === 0;
331420
+ }
331421
+ _step() {
331422
+ const hostId = this.hostIds[this.currentIndex++];
331423
+ this.solved = this.currentIndex >= this.hostIds.length;
331424
+ if (!hostId)
331425
+ return;
331426
+ const index = this.index;
331427
+ const host = index.placement(hostId);
331428
+ const ports = index.portsByComponent.get(hostId) ?? [];
331429
+ if (!host || ports.some((port) => !portRole(port)))
331430
+ return;
331431
+ const inputs = ports.filter((port) => portRole(port) === "input");
331432
+ const outputs = ports.filter((port) => portRole(port) === "output");
331433
+ const grounds = ports.filter((port) => portRole(port) === "ground");
331434
+ if (inputs.length !== 1 || outputs.length !== 1 || !grounds.length)
331435
+ return;
331436
+ const input = inputs[0];
331437
+ const output = outputs[0];
331438
+ if ([input, output, ...grounds].some((port) => port.do_not_connect))
331439
+ return;
331440
+ const inputNet = index.connected(input.source_port_id);
331441
+ const outputNet = index.connected(output.source_port_id);
331442
+ const groundNets = new Set(grounds.map((port) => index.connected(port.source_port_id)));
331443
+ if (groundNets.size !== 1)
331444
+ return;
331445
+ const groundNet = [...groundNets][0];
331446
+ if (new Set([inputNet, outputNet, groundNet]).size !== 3 || !(index.groundNets.has(groundNet) || grounds.some((port) => port.requires_ground || port.provides_ground)) || !(index.powerNets.has(inputNet) || input.requires_power) || !(index.powerNets.has(outputNet) || output.provides_power))
331447
+ return;
331448
+ const inputPin = index.port(input);
331449
+ const outputPin = index.port(output);
331450
+ if (!inputPin || !outputPin || inputPin.schematic_sheet_id !== host.schematicSheetId || outputPin.schematic_sheet_id !== host.schematicSheetId)
331451
+ return;
331452
+ const horizontal = inputPin.facing_direction === "left" && outputPin.facing_direction === "right" || inputPin.facing_direction === "right" && outputPin.facing_direction === "left";
331453
+ const vertical = inputPin.facing_direction === "up" && outputPin.facing_direction === "down" || inputPin.facing_direction === "down" && outputPin.facing_direction === "up";
331454
+ if (!horizontal && !vertical)
331455
+ return;
331456
+ const sign = outputPin.facing_direction === "right" || outputPin.facing_direction === "up" ? 1 : -1;
331457
+ const pinSeparation = sign * (horizontal ? outputPin.center.x - inputPin.center.x : outputPin.center.y - inputPin.center.y);
331458
+ if (pinSeparation <= 0.01)
331459
+ return;
331460
+ const inputCap = this.localCapacitor(host, inputNet, groundNet);
331461
+ const outputCap = this.localCapacitor(host, outputNet, groundNet);
331462
+ if (!inputCap || !outputCap)
331463
+ return;
331464
+ const beyondOppositeSide = (cap, side) => {
331465
+ const distance = side * sign * (horizontal ? cap.schX - host.schX : cap.schY - host.schY);
331466
+ const halfBodies = horizontal ? (host.width + cap.width) / 2 : (host.height + cap.height) / 2;
331467
+ return distance > halfBodies + 0.2;
331468
+ };
331469
+ if (!beyondOppositeSide(inputCap, 1) || !beyondOppositeSide(outputCap, -1))
331470
+ return;
331471
+ const name = host.sourceComponentName ?? hostId;
331472
+ this.params.issues.push({
331473
+ lineItemType: "RegulatorCapacitorsOnWrongSides",
331474
+ regulatorSchematicBox: host,
331475
+ inputCapacitorSchematicBox: inputCap,
331476
+ outputCapacitorSchematicBox: outputCap,
331477
+ inputSourcePortId: input.source_port_id,
331478
+ outputSourcePortId: output.source_port_id,
331479
+ message: `Place ${inputCap.sourceComponentName} near ${name}.${input.name} on the ${inputPin.facing_direction} side and ${outputCap.sourceComponentName} near ${name}.${output.name} on the ${outputPin.facing_direction} side. Preserve all connections and leave room for labels; exact alignment is not required.`
331480
+ });
331481
+ }
331482
+ localCapacitor(host, rail, ground) {
331483
+ const index = this.index;
331484
+ const candidates = [];
331485
+ const maxDistance = Math.max(6, 4 * Math.max(host.width, host.height));
331486
+ const ids = new Set((index.portsByNet.get(rail) ?? []).map((port) => port.source_component_id));
331487
+ for (const id of ids) {
331488
+ if (index.components.get(id)?.ftype !== "simple_capacitor")
331489
+ continue;
331490
+ const nets = index.twoTerminalNets(id);
331491
+ const cap = index.placement(id);
331492
+ if (!nets?.includes(ground) || !cap || !index.sameLocalScope(host, cap))
331493
+ continue;
331494
+ if (Math.hypot(cap.schX - host.schX, cap.schY - host.schY) > maxDistance)
331495
+ continue;
331496
+ const ports = index.portsByComponent.get(id);
331497
+ if (ports.some((port) => port.do_not_connect || !index.port(port) || index.port(port).schematic_sheet_id !== host.schematicSheetId))
331498
+ continue;
331499
+ candidates.push(cap);
331500
+ }
331501
+ return candidates.length === 1 ? candidates[0] : undefined;
331502
+ }
331503
+ static issueToString(issue) {
331504
+ const attrs = [];
331505
+ addAttr(attrs, "regulatorName", issue.regulatorSchematicBox.sourceComponentName);
331506
+ addAttr(attrs, "inputCapacitorName", issue.inputCapacitorSchematicBox.sourceComponentName);
331507
+ addAttr(attrs, "outputCapacitorName", issue.outputCapacitorSchematicBox.sourceComponentName);
331508
+ addAttr(attrs, "message", issue.message);
331509
+ return `<RegulatorCapacitorsOnWrongSides ${attrs.join(" ")} />`;
331510
+ }
331511
+ }
331512
+ function portRole(port) {
331513
+ const roles = new Set;
331514
+ for (const hint of [port.name, ...port.port_hints ?? []]) {
331515
+ const name = hint.toUpperCase().replace(/[ _-]/g, "");
331516
+ if (/^(?:VIN|IN|INPUT)$/.test(name))
331517
+ roles.add("input");
331518
+ else if (/^(?:VOUT|OUT|OUTPUT)$/.test(name))
331519
+ roles.add("output");
331520
+ else if (/^(?:GND\d*|VSS)$/.test(name))
331521
+ roles.add("ground");
331522
+ else if (/^(?:EN|ENABLE|CE|SHDN|NC\d*|EP|PAD|ADJ|FB|BYP|BYPASS|NR|PG|PGOOD)$/.test(name))
331523
+ roles.add("control");
331524
+ }
331525
+ return roles.size === 1 ? [...roles][0] : undefined;
331526
+ }
331527
+
331528
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ConnectorPlacementSolver/ConnectorPlacementSolver.ts
331529
+ import { BaseSolver as BaseSolver10 } from "@tscircuit/solver-utils";
331530
+
331531
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/geometry.ts
331532
+ function centeredRect(cx, cy, w, h) {
331533
+ return {
331534
+ left: cx - w / 2,
331535
+ right: cx + w / 2,
331536
+ top: cy + h / 2,
331537
+ bottom: cy - h / 2
331538
+ };
331539
+ }
331540
+ function rectOverlap(a, b) {
331541
+ const ow = Math.min(a.right, b.right) - Math.max(a.left, b.left);
331542
+ const oh = Math.min(a.top, b.top) - Math.max(a.bottom, b.bottom);
331543
+ return ow > 0 && oh > 0 ? { ow, oh } : null;
331544
+ }
331545
+
331546
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ConnectorPlacementSolver/ConnectorPlacementSolver.ts
331547
+ var EPSILON4 = 0.01;
330939
331548
  var directions = {
330940
331549
  right: { x: 1, y: 0 },
330941
331550
  left: { x: -1, y: 0 },
@@ -330944,10 +331553,10 @@ var directions = {
330944
331553
  };
330945
331554
  var dot2 = (a, b) => a.x * b.x + a.y * b.y;
330946
331555
  var distance49 = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
330947
- var near = (a, b) => distance49(a, b) <= EPSILON3;
331556
+ var near = (a, b) => distance49(a, b) <= EPSILON4;
330948
331557
  var round = (value) => Math.round(value * 100) / 100;
330949
331558
 
330950
- class ConnectorPlacementSolver extends BaseSolver5 {
331559
+ class ConnectorPlacementSolver extends BaseSolver10 {
330951
331560
  params;
330952
331561
  constructor(params2) {
330953
331562
  super();
@@ -331015,7 +331624,7 @@ class ConnectorPlacementSolver extends BaseSolver5 {
331015
331624
  continue;
331016
331625
  const detours = detouredConnections.flat();
331017
331626
  const ordered = [...connections].sort((a, b) => dot2(a.pin.center, across) - dot2(b.pin.center, across));
331018
- if (ordered.some((c, i) => i > 0 && dot2(c.peer.center, across) <= dot2(ordered[i - 1].peer.center, across) + EPSILON3))
331627
+ if (ordered.some((c, i) => i > 0 && dot2(c.peer.center, across) <= dot2(ordered[i - 1].peer.center, across) + EPSILON4))
331019
331628
  continue;
331020
331629
  const center = { x: connector.schX, y: connector.schY };
331021
331630
  const pinOffset = Math.max(...connections.map((c) => dot2(c.pin.center, along) - dot2(center, along)));
@@ -331031,7 +331640,7 @@ class ConnectorPlacementSolver extends BaseSolver5 {
331031
331640
  x: pin.center.x + delta.x,
331032
331641
  y: pin.center.y + delta.y
331033
331642
  });
331034
- if (connections.some((c) => distance49(movedPin(c.pin), c.peer.center) > distance49(c.pin.center, c.peer.center) + EPSILON3))
331643
+ if (connections.some((c) => distance49(movedPin(c.pin), c.peer.center) > distance49(c.pin.center, c.peer.center) + EPSILON4))
331035
331644
  continue;
331036
331645
  const before = connections.reduce((sum, c) => sum + distance49(c.pin.center, c.peer.center), 0);
331037
331646
  const after = connections.reduce((sum, c) => sum + distance49(movedPin(c.pin), c.peer.center), 0);
@@ -331118,7 +331727,7 @@ function bendCount(trace) {
331118
331727
  return 0;
331119
331728
  if (near(edge.from, edge.to))
331120
331729
  continue;
331121
- const axis = Math.abs(edge.from.y - edge.to.y) < EPSILON3 ? "x" : Math.abs(edge.from.x - edge.to.x) < EPSILON3 ? "y" : undefined;
331730
+ const axis = Math.abs(edge.from.y - edge.to.y) < EPSILON4 ? "x" : Math.abs(edge.from.x - edge.to.x) < EPSILON4 ? "y" : undefined;
331122
331731
  if (!axis)
331123
331732
  return 0;
331124
331733
  if (previousAxis && previousAxis !== axis)
@@ -331133,8 +331742,8 @@ function segmentCrossesBox(a, b, box) {
331133
331742
  }
331134
331743
 
331135
331744
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/LowSideTransistorPlacementSolver/LowSideTransistorPlacementSolver.ts
331136
- import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
331137
- class LowSideTransistorPlacementSolver extends BaseSolver6 {
331745
+ import { BaseSolver as BaseSolver11 } from "@tscircuit/solver-utils";
331746
+ class LowSideTransistorPlacementSolver extends BaseSolver11 {
331138
331747
  index;
331139
331748
  positiveNets = new Set;
331140
331749
  transistorIds;
@@ -331253,8 +331862,129 @@ class LowSideTransistorPlacementSolver extends BaseSolver6 {
331253
331862
  }
331254
331863
  }
331255
331864
 
331865
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/UsbSeriesResistorPlacementSolver/UsbSeriesResistorPlacementSolver.ts
331866
+ import { BaseSolver as BaseSolver12 } from "@tscircuit/solver-utils";
331867
+ class UsbSeriesResistorPlacementSolver extends BaseSolver12 {
331868
+ params;
331869
+ index;
331870
+ hostIds;
331871
+ reportedPairs = new Set;
331872
+ currentIndex = 0;
331873
+ constructor(params2) {
331874
+ super();
331875
+ this.params = params2;
331876
+ this.index = new PlacementNetworkIndex(params2.ctx);
331877
+ this.hostIds = [...this.index.components.values()].filter((component) => component.ftype === "simple_chip").map((component) => component.source_component_id);
331878
+ this.solved = this.hostIds.length === 0;
331879
+ }
331880
+ _step() {
331881
+ const hostId = this.hostIds[this.currentIndex++];
331882
+ this.solved = this.currentIndex >= this.hostIds.length;
331883
+ if (!hostId)
331884
+ return;
331885
+ const ports = this.index.portsByComponent.get(hostId) ?? [];
331886
+ const positivePorts = ports.filter((port) => usbRole(port) === "positive");
331887
+ const negativePorts = ports.filter((port) => usbRole(port) === "negative");
331888
+ if (positivePorts.length !== 1 || negativePorts.length !== 1)
331889
+ return;
331890
+ const positivePort = positivePorts[0];
331891
+ const negativePort = negativePorts[0];
331892
+ const positive = this.seriesResistor(positivePort);
331893
+ const negative = this.seriesResistor(negativePort);
331894
+ if (!positive || !negative || positive.axis !== negative.axis || !this.index.sameLocalScope(positive.placement, negative.placement) || new Set([
331895
+ positive.hostNet,
331896
+ negative.hostNet,
331897
+ positive.interfaceNet,
331898
+ negative.interfaceNet
331899
+ ]).size !== 4 || !this.shareInterface(positive, negative, hostId))
331900
+ return;
331901
+ const pairKey = [positive.id, negative.id].sort().join("\x00");
331902
+ if (this.reportedPairs.has(pairKey))
331903
+ return;
331904
+ const a = positive.placement;
331905
+ const b = negative.placement;
331906
+ const horizontal = positive.axis === "horizontal";
331907
+ const along = Math.abs(horizontal ? a.schX - b.schX : a.schY - b.schY);
331908
+ const across = Math.abs(horizontal ? a.schY - b.schY : a.schX - b.schX);
331909
+ const alongA = horizontal ? a.width : a.height;
331910
+ const alongB = horizontal ? b.width : b.height;
331911
+ const acrossA = horizontal ? a.height : a.width;
331912
+ const acrossB = horizontal ? b.height : b.width;
331913
+ const bodyGap = along - (alongA + alongB) / 2;
331914
+ if (bodyGap < Math.max(alongA, alongB) || across >= (acrossA + acrossB) / 2 - 0.01)
331915
+ return;
331916
+ this.reportedPairs.add(pairKey);
331917
+ const positiveName = a.sourceComponentName ?? positive.id;
331918
+ const negativeName = b.sourceComponentName ?? negative.id;
331919
+ this.params.issues.push({
331920
+ lineItemType: "UsbSeriesResistorsNotAligned",
331921
+ positiveResistorSchematicBox: a,
331922
+ negativeResistorSchematicBox: b,
331923
+ hostSourceComponentId: hostId,
331924
+ positiveSourcePortId: positivePort.source_port_id,
331925
+ negativeSourcePortId: negativePort.source_port_id,
331926
+ signalAxis: positive.axis,
331927
+ message: `Place ${positiveName} (D+) and ${negativeName} (D−) near each other and draw clear traces to their corresponding USB ports. Exact alignment is not required; preserve pin assignments and leave space for labels.`
331928
+ });
331929
+ }
331930
+ seriesResistor(hostPort) {
331931
+ const index = this.index;
331932
+ const hostNet = index.connected(hostPort.source_port_id);
331933
+ if (index.isRail(hostNet))
331934
+ return;
331935
+ const candidates = new Set((index.portsByNet.get(hostNet) ?? []).filter((port) => index.components.get(port.source_component_id)?.ftype === "simple_resistor").map((port) => port.source_component_id));
331936
+ if (candidates.size !== 1)
331937
+ return;
331938
+ const id = [...candidates][0];
331939
+ const nets = index.twoTerminalNets(id);
331940
+ const interfaceNet = nets?.find((net) => net !== hostNet);
331941
+ const placement = index.placement(id);
331942
+ if (!interfaceNet || index.isRail(interfaceNet) || !placement)
331943
+ return;
331944
+ if ((index.portsByNet.get(interfaceNet) ?? []).some((port) => port.source_component_id !== id && index.components.get(port.source_component_id)?.ftype === "simple_resistor"))
331945
+ return;
331946
+ const pins = index.portsByComponent.get(id).map((port) => index.port(port));
331947
+ const [first, second] = pins;
331948
+ if (!first || !second)
331949
+ return;
331950
+ const facing = new Set([first.facing_direction, second.facing_direction]);
331951
+ let axis;
331952
+ if (facing.has("left") && facing.has("right") && Math.abs(first.center.y - second.center.y) < 0.01)
331953
+ axis = "horizontal";
331954
+ else if (facing.has("up") && facing.has("down") && Math.abs(first.center.x - second.center.x) < 0.01)
331955
+ axis = "vertical";
331956
+ else
331957
+ return;
331958
+ return { id, placement, hostNet, interfaceNet, axis };
331959
+ }
331960
+ shareInterface(positive, negative, hostId) {
331961
+ const peerIds = (net) => new Set((this.index.portsByNet.get(net) ?? []).map((port) => port.source_component_id).filter((id) => id !== hostId && id !== positive.id && id !== negative.id && (this.index.portsByComponent.get(id)?.length ?? 0) > 2));
331962
+ const positivePeers = peerIds(positive.interfaceNet);
331963
+ return [...peerIds(negative.interfaceNet)].some((id) => positivePeers.has(id));
331964
+ }
331965
+ static issueToString(issue) {
331966
+ const attrs = [];
331967
+ addAttr(attrs, "positiveResistorName", issue.positiveResistorSchematicBox.sourceComponentName);
331968
+ addAttr(attrs, "negativeResistorName", issue.negativeResistorSchematicBox.sourceComponentName);
331969
+ addAttr(attrs, "signalAxis", issue.signalAxis);
331970
+ addAttr(attrs, "message", issue.message);
331971
+ return `<UsbSeriesResistorsNotAligned ${attrs.join(" ")} />`;
331972
+ }
331973
+ }
331974
+ function usbRole(port) {
331975
+ const roles = new Set;
331976
+ for (const hint of [port.name, ...port.port_hints ?? []]) {
331977
+ const name = hint.toUpperCase();
331978
+ if (/^(?:USB_?)?D(?:P|\+|_POS)$/.test(name))
331979
+ roles.add("positive");
331980
+ if (/^(?:USB_?)?D(?:M|N|-|_NEG)$/.test(name))
331981
+ roles.add("negative");
331982
+ }
331983
+ return roles.size === 1 ? [...roles][0] : undefined;
331984
+ }
331985
+
331256
331986
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
331257
- import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
331987
+ import { BaseSolver as BaseSolver13 } from "@tscircuit/solver-utils";
331258
331988
 
331259
331989
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/graphics.ts
331260
331990
  import { mergeGraphics as mergeGraphics2 } from "graphics-debug";
@@ -331289,7 +332019,7 @@ function visualizeCircuitJson(circuitJson) {
331289
332019
  }
331290
332020
 
331291
332021
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
331292
- class CapacitorOrientationSolver extends BaseSolver7 {
332022
+ class CapacitorOrientationSolver extends BaseSolver13 {
331293
332023
  static EPSILON = 0.01;
331294
332024
  static ORIENTATION_MESSAGE = 'Use schOrientation="vertical" on this capacitor to fix the symbol orientation';
331295
332025
  ctx;
@@ -331434,8 +332164,8 @@ class CapacitorOrientationSolver extends BaseSolver7 {
331434
332164
  }
331435
332165
 
331436
332166
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/DecouplingCapacitorGroupingSolver/DecouplingCapacitorGroupingSolver.ts
331437
- import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
331438
- class DecouplingCapacitorGroupingSolver extends BaseSolver8 {
332167
+ import { BaseSolver as BaseSolver14 } from "@tscircuit/solver-utils";
332168
+ class DecouplingCapacitorGroupingSolver extends BaseSolver14 {
331439
332169
  params;
331440
332170
  static MIN_BODY_GAP = 4;
331441
332171
  banks = [];
@@ -331567,8 +332297,8 @@ function getNetLabelBounds(label) {
331567
332297
  }
331568
332298
 
331569
332299
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ComponentNetLabelCollisionSolver/ComponentNetLabelCollisionSolver.ts
331570
- import { BaseSolver as BaseSolver9 } from "@tscircuit/solver-utils";
331571
- class ComponentNetLabelCollisionSolver extends BaseSolver9 {
332300
+ import { BaseSolver as BaseSolver15 } from "@tscircuit/solver-utils";
332301
+ class ComponentNetLabelCollisionSolver extends BaseSolver15 {
331572
332302
  params;
331573
332303
  placements;
331574
332304
  netLabelsByComponentId;
@@ -331892,8 +332622,8 @@ class ComponentNetLabelCollisionSolver extends BaseSolver9 {
331892
332622
  }
331893
332623
 
331894
332624
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ComponentPinAlignmentSolver/ComponentPinAlignmentSolver.ts
331895
- import { BaseSolver as BaseSolver10 } from "@tscircuit/solver-utils";
331896
- class ComponentPinAlignmentSolver extends BaseSolver10 {
332625
+ import { BaseSolver as BaseSolver16 } from "@tscircuit/solver-utils";
332626
+ class ComponentPinAlignmentSolver extends BaseSolver16 {
331897
332627
  static ALIGNMENT_EPSILON = 0.01;
331898
332628
  ctx;
331899
332629
  out;
@@ -332027,8 +332757,8 @@ class ComponentPinAlignmentSolver extends BaseSolver10 {
332027
332757
  }
332028
332758
 
332029
332759
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CrystalLoadCapacitorPlacementSolver/CrystalLoadCapacitorPlacementSolver.ts
332030
- import { BaseSolver as BaseSolver11 } from "@tscircuit/solver-utils";
332031
- class CrystalLoadCapacitorPlacementSolver extends BaseSolver11 {
332760
+ import { BaseSolver as BaseSolver17 } from "@tscircuit/solver-utils";
332761
+ class CrystalLoadCapacitorPlacementSolver extends BaseSolver17 {
332032
332762
  static ALIGNMENT_TOLERANCE = 0.1;
332033
332763
  issues;
332034
332764
  networks;
@@ -332188,9 +332918,9 @@ var distance50 = (first, second) => Math.hypot(first.schX - second.schX, first.s
332188
332918
  var round2 = (value) => Math.round(value * 100) / 100;
332189
332919
 
332190
332920
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/DiodeResistorAlignmentSolver/DiodeResistorAlignmentSolver.ts
332191
- import { BaseSolver as BaseSolver12 } from "@tscircuit/solver-utils";
332921
+ import { BaseSolver as BaseSolver18 } from "@tscircuit/solver-utils";
332192
332922
  import { getSourcePortConnectivityMapFromCircuitJson as getSourcePortConnectivityMapFromCircuitJson2 } from "circuit-json-to-connectivity-map";
332193
- class DiodeResistorAlignmentSolver extends BaseSolver12 {
332923
+ class DiodeResistorAlignmentSolver extends BaseSolver18 {
332194
332924
  static DIODE_FTYPES = new Set(["simple_led", "simple_diode"]);
332195
332925
  ctx;
332196
332926
  out;
@@ -332356,8 +333086,8 @@ class DiodeResistorAlignmentSolver extends BaseSolver12 {
332356
333086
  }
332357
333087
 
332358
333088
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/FeedbackNetworkPlacementSolver/FeedbackNetworkPlacementSolver.ts
332359
- import { BaseSolver as BaseSolver13 } from "@tscircuit/solver-utils";
332360
- class FeedbackNetworkPlacementSolver extends BaseSolver13 {
333089
+ import { BaseSolver as BaseSolver19 } from "@tscircuit/solver-utils";
333090
+ class FeedbackNetworkPlacementSolver extends BaseSolver19 {
332361
333091
  static MIN_BODY_GAP = 4;
332362
333092
  index;
332363
333093
  amplifierIds;
@@ -332442,11 +333172,75 @@ function distanceBetweenBoxes(a, b) {
332442
333172
  }
332443
333173
 
332444
333174
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/PullResistorPlacementSolver/PullResistorPlacementSolver.ts
332445
- import { BaseSolver as BaseSolver14 } from "@tscircuit/solver-utils";
332446
- class PullResistorPlacementSolver extends BaseSolver14 {
333175
+ import { BaseSolver as BaseSolver20 } from "@tscircuit/solver-utils";
333176
+
333177
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/switch-pull-resistor-pairs.ts
333178
+ function getSwitchPullResistorPairs(index) {
333179
+ const pairs = [];
333180
+ const isHorizontal = (id) => {
333181
+ const ports = index.portsByComponent.get(id);
333182
+ if (ports?.length !== 2)
333183
+ return false;
333184
+ const a = index.port(ports[0]);
333185
+ const b = index.port(ports[1]);
333186
+ return !!a && !!b && Math.abs(a.center.y - b.center.y) < 0.01 && Math.abs(a.center.x - b.center.x) > 0.01;
333187
+ };
333188
+ for (const component of index.components.values()) {
333189
+ if (component.ftype !== "simple_resistor" || component.resistance <= 0)
333190
+ continue;
333191
+ const id = component.source_component_id;
333192
+ const nets = index.twoTerminalNets(id);
333193
+ if (!nets || nets.filter((net) => index.isRail(net)).length !== 1)
333194
+ continue;
333195
+ const rail = nets.find((net) => index.isRail(net));
333196
+ if (index.powerNets.has(rail) && index.groundNets.has(rail))
333197
+ continue;
333198
+ const signal = nets.find((net) => net !== rail);
333199
+ const peers = index.portsByNet.get(signal) ?? [];
333200
+ const switches = peers.filter((port) => {
333201
+ const type = index.components.get(port.source_component_id)?.ftype;
333202
+ return type === "simple_switch" || type === "simple_push_button";
333203
+ });
333204
+ if (switches.length !== 1 || peers.filter((port) => index.components.get(port.source_component_id)?.ftype === "simple_resistor").length !== 1)
333205
+ continue;
333206
+ const signalPort = switches[0];
333207
+ const switchId = signalPort.source_component_id;
333208
+ const switchType = index.components.get(switchId)?.ftype;
333209
+ const switchNets = index.twoTerminalNets(switchId);
333210
+ const otherRail = switchNets?.find((net) => net !== signal);
333211
+ if (!otherRail)
333212
+ continue;
333213
+ const pullDirection = index.powerNets.has(rail) ? "up" : "down";
333214
+ if (pullDirection === "up" ? !index.groundNets.has(otherRail) || index.powerNets.has(otherRail) : !index.powerNets.has(otherRail) || index.groundNets.has(otherRail))
333215
+ continue;
333216
+ if ([id, switchId].some((componentId) => index.portsByComponent.get(componentId)?.some((port) => port.do_not_connect)))
333217
+ continue;
333218
+ const resistor = index.placement(id);
333219
+ const switchBox = index.placement(switchId);
333220
+ const pin = index.port(signalPort);
333221
+ if (!resistor || !switchBox || !pin || !index.sameLocalScope(resistor, switchBox))
333222
+ continue;
333223
+ pairs.push({
333224
+ resistor,
333225
+ switchBox,
333226
+ signalPort,
333227
+ signalSchY: pin.center.y,
333228
+ pullDirection,
333229
+ horizontalPushbutton: switchType === "simple_push_button" && isHorizontal(id) && isHorizontal(switchId)
333230
+ });
333231
+ }
333232
+ return pairs;
333233
+ }
333234
+ function getHorizontalPushbuttonComponentIds(index) {
333235
+ return new Set(getSwitchPullResistorPairs(index).flatMap((pair) => pair.horizontalPushbutton ? [pair.resistor.sourceComponentId, pair.switchBox.sourceComponentId] : []));
333236
+ }
333237
+
333238
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/PullResistorPlacementSolver/PullResistorPlacementSolver.ts
333239
+ class PullResistorPlacementSolver extends BaseSolver20 {
332447
333240
  static MIN_WRONG_SIDE_GAP = 1.5;
332448
333241
  index;
332449
333242
  resistorIds;
333243
+ horizontalPushbuttonComponentIds;
332450
333244
  issues;
332451
333245
  currentIndex = 0;
332452
333246
  constructor({
@@ -332456,6 +333250,7 @@ class PullResistorPlacementSolver extends BaseSolver14 {
332456
333250
  super();
332457
333251
  this.issues = issues;
332458
333252
  this.index = new PlacementNetworkIndex(ctx);
333253
+ this.horizontalPushbuttonComponentIds = getHorizontalPushbuttonComponentIds(this.index);
332459
333254
  this.resistorIds = [...this.index.components.values()].filter((component) => component.ftype === "simple_resistor" && component.resistance > 0).map((component) => component.source_component_id);
332460
333255
  this.solved = this.resistorIds.length === 0;
332461
333256
  }
@@ -332464,6 +333259,8 @@ class PullResistorPlacementSolver extends BaseSolver14 {
332464
333259
  this.solved = this.currentIndex >= this.resistorIds.length;
332465
333260
  if (!id)
332466
333261
  return;
333262
+ if (this.horizontalPushbuttonComponentIds.has(id))
333263
+ return;
332467
333264
  const index = this.index;
332468
333265
  const resistor = index.placement(id);
332469
333266
  const nets = index.twoTerminalNets(id);
@@ -332539,14 +333336,15 @@ class PullResistorPlacementSolver extends BaseSolver14 {
332539
333336
  }
332540
333337
 
332541
333338
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentRailOrientationSolver/TwoPinComponentRailOrientationSolver.ts
332542
- import { BaseSolver as BaseSolver15 } from "@tscircuit/solver-utils";
332543
- class TwoPinComponentRailOrientationSolver extends BaseSolver15 {
333339
+ import { BaseSolver as BaseSolver21 } from "@tscircuit/solver-utils";
333340
+ class TwoPinComponentRailOrientationSolver extends BaseSolver21 {
332544
333341
  static EPSILON = 0.01;
332545
333342
  index;
332546
333343
  powerNets;
332547
333344
  groundNets;
332548
333345
  positiveVoltageNets = new Set;
332549
333346
  componentIds;
333347
+ horizontalPushbuttonComponentIds;
332550
333348
  issues;
332551
333349
  currentIndex = 0;
332552
333350
  constructor({
@@ -332556,6 +333354,7 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver15 {
332556
333354
  super();
332557
333355
  this.issues = issues;
332558
333356
  this.index = new PlacementNetworkIndex(ctx);
333357
+ this.horizontalPushbuttonComponentIds = getHorizontalPushbuttonComponentIds(this.index);
332559
333358
  this.powerNets = new Set(this.index.powerNets);
332560
333359
  this.groundNets = new Set(this.index.groundNets);
332561
333360
  for (const element of ctx.circuitJson) {
@@ -332579,10 +333378,13 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver15 {
332579
333378
  return;
332580
333379
  const index = this.index;
332581
333380
  const component = index.placement(id);
333381
+ const sourceComponent = index.components.get(id);
332582
333382
  const nets = index.twoTerminalNets(id);
332583
333383
  if (!component || !nets)
332584
333384
  return;
332585
- if (index.components.get(id)?.ftype === "simple_inductor" && !nets.some((net) => this.groundNets.has(net)))
333385
+ if (sourceComponent?.ftype === "simple_inductor" && !nets.some((net) => this.groundNets.has(net)))
333386
+ return;
333387
+ if (sourceComponent?.ftype === "simple_diode" && nets.every((net) => this.powerNets.has(net)))
332586
333388
  return;
332587
333389
  if (nets.some((net) => this.powerNets.has(net) && this.groundNets.has(net)))
332588
333390
  return;
@@ -332617,6 +333419,8 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver15 {
332617
333419
  const horizontal = Math.abs(railPort.center.y - otherPort.center.y) <= TwoPinComponentRailOrientationSolver.EPSILON && Math.abs(railPort.center.x - otherPort.center.x) > TwoPinComponentRailOrientationSolver.EPSILON && (railPort.facing_direction === "left" && otherPort.facing_direction === "right" || railPort.facing_direction === "right" && otherPort.facing_direction === "left");
332618
333420
  if (!horizontal)
332619
333421
  return;
333422
+ if (this.horizontalPushbuttonComponentIds.has(id))
333423
+ return;
332620
333424
  const suggestedRailFacingDirection = railType === "power" ? "up" : "down";
332621
333425
  const deltaSchRotation = railPort.facing_direction === "left" === (railType === "power") ? -90 : 90;
332622
333426
  this.issues.push({
@@ -332648,8 +333452,8 @@ function getSchematicBoxComponentIds(circuitJson) {
332648
333452
  }
332649
333453
 
332650
333454
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxInnerLabelCollisionSolver/SchematicBoxInnerLabelCollisionSolver.ts
332651
- import { BaseSolver as BaseSolver16 } from "@tscircuit/solver-utils";
332652
- class SchematicBoxInnerLabelCollisionSolver extends BaseSolver16 {
333455
+ import { BaseSolver as BaseSolver22 } from "@tscircuit/solver-utils";
333456
+ class SchematicBoxInnerLabelCollisionSolver extends BaseSolver22 {
332653
333457
  params;
332654
333458
  MESSAGE = "Inner labels are colliding. Increase the schWidth or schHeight.";
332655
333459
  PIN_LABEL_EDGE_PADDING = 0.1;
@@ -332846,8 +333650,8 @@ class SchematicBoxInnerLabelCollisionSolver extends BaseSolver16 {
332846
333650
  }
332847
333651
 
332848
333652
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxOverlapSolver/SchematicBoxOverlapSolver.ts
332849
- import { BaseSolver as BaseSolver17 } from "@tscircuit/solver-utils";
332850
- class SchematicBoxOverlapSolver extends BaseSolver17 {
333653
+ import { BaseSolver as BaseSolver23 } from "@tscircuit/solver-utils";
333654
+ class SchematicBoxOverlapSolver extends BaseSolver23 {
332851
333655
  params;
332852
333656
  placements;
332853
333657
  firstIndex = 0;
@@ -332966,8 +333770,8 @@ class SchematicBoxOverlapSolver extends BaseSolver17 {
332966
333770
  }
332967
333771
 
332968
333772
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxTooWideSolver/SchematicBoxTooWideSolver.ts
332969
- import { BaseSolver as BaseSolver18 } from "@tscircuit/solver-utils";
332970
- class SchematicBoxTooWideSolver extends BaseSolver18 {
333773
+ import { BaseSolver as BaseSolver24 } from "@tscircuit/solver-utils";
333774
+ class SchematicBoxTooWideSolver extends BaseSolver24 {
332971
333775
  params;
332972
333776
  SCHEMATIC_BOX_TOO_WIDE_MESSAGE = "Shrink schematic box width";
332973
333777
  PIN_HEADER_MAX_ALLOWED_GAP = 0.1;
@@ -333147,8 +333951,8 @@ class SchematicBoxTooWideSolver extends BaseSolver18 {
333147
333951
  }
333148
333952
 
333149
333953
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPinPaddingToEdgeSolver/SchematicPinPaddingToEdgeSolver.ts
333150
- import { BaseSolver as BaseSolver19 } from "@tscircuit/solver-utils";
333151
- class SchematicPinPaddingToEdgeSolver extends BaseSolver19 {
333954
+ import { BaseSolver as BaseSolver25 } from "@tscircuit/solver-utils";
333955
+ class SchematicPinPaddingToEdgeSolver extends BaseSolver25 {
333152
333956
  params;
333153
333957
  MESSAGE = "Move schematic pins closer to the box edge or change the schematic box";
333154
333958
  PIN_NAME_CHARACTER_WIDTH = 0.095;
@@ -333204,7 +334008,7 @@ class SchematicPinPaddingToEdgeSolver extends BaseSolver19 {
333204
334008
  continue;
333205
334009
  const measuredPadding = this.getPinPaddingToEdge(schematicBox, outerPin, edgeSide);
333206
334010
  const maxAllowedPadding = useLabelAwareMaxPadding ? this.getMaxAllowedPinPadding(pinSpacing, edgeSide, maxLabelLengthBySide) : pinSpacing;
333207
- if (!this.exceedsMaxAllowedGap(measuredPadding, maxAllowedPadding))
334011
+ if (!this.exceedsMaxAllowedGap(measuredPadding, maxAllowedPadding + pinSpacing))
333208
334012
  continue;
333209
334013
  candidates.push({
333210
334014
  schematicBox,
@@ -333527,6 +334331,47 @@ var buildSolverContext = (circuitJson) => {
333527
334331
  return { circuitJson, componentPlacements };
333528
334332
  };
333529
334333
 
334334
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SwitchPullResistorPlacementSolver/SwitchPullResistorPlacementSolver.ts
334335
+ import { BaseSolver as BaseSolver26 } from "@tscircuit/solver-utils";
334336
+ class SwitchPullResistorPlacementSolver extends BaseSolver26 {
334337
+ params;
334338
+ constructor(params2) {
334339
+ super();
334340
+ this.params = params2;
334341
+ }
334342
+ _step() {
334343
+ const index = new PlacementNetworkIndex(this.params.ctx);
334344
+ for (const pair of getSwitchPullResistorPairs(index)) {
334345
+ const { resistor, switchBox, signalPort, signalSchY, pullDirection } = pair;
334346
+ if (pair.horizontalPushbutton)
334347
+ continue;
334348
+ const signal = index.connected(signalPort.source_port_id);
334349
+ if (index.portsByNet.get(signal)?.length !== 2)
334350
+ continue;
334351
+ if (signalPort.needs_external_pullup || signalPort.needs_external_pulldown)
334352
+ continue;
334353
+ const wrongSideGap = pullDirection === "up" ? signalSchY - (resistor.schY + resistor.height / 2) : resistor.schY - resistor.height / 2 - signalSchY;
334354
+ if (wrongSideGap <= 1.5)
334355
+ continue;
334356
+ const preferredSide = pullDirection === "up" ? "above" : "below";
334357
+ this.params.issues.push({
334358
+ lineItemType: "PullResistorOnWrongSide",
334359
+ resistorSchematicBox: resistor,
334360
+ hostSchematicBox: switchBox,
334361
+ signalSourcePortId: signalPort.source_port_id,
334362
+ signalPinName: signalPort.name,
334363
+ signalSchY,
334364
+ pullDirection,
334365
+ preferredSide,
334366
+ wrongSideGap,
334367
+ maxRecommendedWrongSideGap: 1.5,
334368
+ message: `place ${resistor.sourceComponentName} ${preferredSide} ${switchBox.sourceComponentName} so the pull-${pullDirection} branch reads toward ${pullDirection === "up" ? "power" : "ground"}`
334369
+ });
334370
+ }
334371
+ this.solved = true;
334372
+ }
334373
+ }
334374
+
333530
334375
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/trace-name.ts
333531
334376
  function getTraceName(circuitJson, trace) {
333532
334377
  const sourceTrace = circuitJson.find((e) => e.type === "source_trace" && e.source_trace_id === trace.source_trace_id);
@@ -333679,8 +334524,8 @@ var polygonBounds = (polygons) => {
333679
334524
  };
333680
334525
 
333681
334526
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TraceSimplificationSolver/TraceSimplificationSolver.ts
333682
- import { BaseSolver as BaseSolver20 } from "@tscircuit/solver-utils";
333683
- class TraceSimplificationSolver extends BaseSolver20 {
334527
+ import { BaseSolver as BaseSolver27 } from "@tscircuit/solver-utils";
334528
+ class TraceSimplificationSolver extends BaseSolver27 {
333684
334529
  static EPSILON = 0.01;
333685
334530
  ctx;
333686
334531
  out;
@@ -334038,7 +334883,7 @@ class TraceSimplificationSolver extends BaseSolver20 {
334038
334883
  }
334039
334884
 
334040
334885
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentOrientationSolver/TwoPinComponentOrientationSolver.ts
334041
- import { BaseSolver as BaseSolver21 } from "@tscircuit/solver-utils";
334886
+ import { BaseSolver as BaseSolver28 } from "@tscircuit/solver-utils";
334042
334887
 
334043
334888
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentOrientationSolver/getPowerOrGroundConnectionIds.ts
334044
334889
  import {
@@ -334077,7 +334922,7 @@ function getPowerOrGroundConnectionIds(circuitJson) {
334077
334922
  }
334078
334923
 
334079
334924
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentOrientationSolver/TwoPinComponentOrientationSolver.ts
334080
- class TwoPinComponentOrientationSolver extends BaseSolver21 {
334925
+ class TwoPinComponentOrientationSolver extends BaseSolver28 {
334081
334926
  static EPSILON = 0.01;
334082
334927
  ctx;
334083
334928
  out;
@@ -334323,8 +335168,8 @@ class TwoPinComponentOrientationSolver extends BaseSolver21 {
334323
335168
  }
334324
335169
 
334325
335170
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/VerboseNetLabelSolver/VerboseNetLabelSolver.ts
334326
- import { BaseSolver as BaseSolver22 } from "@tscircuit/solver-utils";
334327
- class VerboseNetLabelSolver extends BaseSolver22 {
335171
+ import { BaseSolver as BaseSolver29 } from "@tscircuit/solver-utils";
335172
+ class VerboseNetLabelSolver extends BaseSolver29 {
334328
335173
  params;
334329
335174
  VERBOSE_NET_LABEL_MESSAGE = "Create trace with schDisplayLabel";
334330
335175
  netLabels;
@@ -334433,8 +335278,8 @@ class VerboseNetLabelSolver extends BaseSolver22 {
334433
335278
  }
334434
335279
 
334435
335280
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicTextClearanceSolver/SchematicTextClearanceSolver.ts
334436
- import { BaseSolver as BaseSolver23 } from "@tscircuit/solver-utils";
334437
- class SchematicTextClearanceSolver extends BaseSolver23 {
335281
+ import { BaseSolver as BaseSolver30 } from "@tscircuit/solver-utils";
335282
+ class SchematicTextClearanceSolver extends BaseSolver30 {
334438
335283
  params;
334439
335284
  texts;
334440
335285
  obstacles;
@@ -334585,8 +335430,8 @@ class SchematicTextClearanceSolver extends BaseSolver23 {
334585
335430
  }
334586
335431
 
334587
335432
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ResetNetworkGroupingSolver/ResetNetworkGroupingSolver.ts
334588
- import { BaseSolver as BaseSolver24 } from "@tscircuit/solver-utils";
334589
- class ResetNetworkGroupingSolver extends BaseSolver24 {
335433
+ import { BaseSolver as BaseSolver31 } from "@tscircuit/solver-utils";
335434
+ class ResetNetworkGroupingSolver extends BaseSolver31 {
334590
335435
  params;
334591
335436
  static MIN_DISTANCE = 6;
334592
335437
  networks;
@@ -334740,6 +335585,50 @@ class ResetNetworkGroupingSolver extends BaseSolver24 {
334740
335585
  var resetPinName = (port) => [port.name, ...port.port_hints ?? []].find((name) => /^N?(RESET|RST)(N|B)?$/.test(name.toUpperCase().replace(/[_\-!~#/]/g, "")));
334741
335586
 
334742
335587
  // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPlacementPipeline/SchematicPlacementPipeline.ts
335588
+ var solversByIssueType = {
335589
+ MosfetGateNetworkNotGrouped: [MosfetGateNetworkPlacementSolver],
335590
+ FlybackDiodeSeparatedFromRelayCoil: [RelayFlybackDiodePlacementSolver],
335591
+ ComponentOverlap: [SchematicBoxOverlapSolver],
335592
+ SchematicBoxHasALotOfSurroundingWhitespace: [],
335593
+ CapacitorSymbolHorizontal: [
335594
+ CapacitorOrientationSolver,
335595
+ TwoPinComponentRailOrientationSolver
335596
+ ],
335597
+ VerboseSchematicNetLabel: [VerboseNetLabelSolver],
335598
+ PinHeaderSchematicBoxTooWide: [SchematicBoxTooWideSolver],
335599
+ GenericSchematicBoxTooWide: [SchematicBoxTooWideSolver],
335600
+ SchematicBoxInnerLabelCollision: [SchematicBoxInnerLabelCollisionSolver],
335601
+ SchematicPinPaddingToEdgeTooLarge: [SchematicPinPaddingToEdgeSolver],
335602
+ DiodeResistorNotAligned: [DiodeResistorAlignmentSolver],
335603
+ ComponentPinsWouldAlignWithVerticalShift: [ComponentPinAlignmentSolver],
335604
+ TraceCanBeSimplifiedByMovingComponent: [TraceSimplificationSolver],
335605
+ CrystalNotCenteredOverLoadCapacitors: [CrystalLoadCapacitorPlacementSolver],
335606
+ ComponentNetLabelCollision: [ComponentNetLabelCollisionSolver],
335607
+ ComponentBoxNetLabelCollision: [ComponentNetLabelCollisionSolver],
335608
+ NetLabelCollision: [ComponentNetLabelCollisionSolver],
335609
+ FeedbackNetworkNotCompact: [FeedbackNetworkPlacementSolver],
335610
+ PullResistorOnWrongSide: [
335611
+ PullResistorPlacementSolver,
335612
+ SwitchPullResistorPlacementSolver
335613
+ ],
335614
+ SchematicTextCollision: [SchematicTextClearanceSolver],
335615
+ ResetNetworkNotGrouped: [ResetNetworkGroupingSolver],
335616
+ TwoPinComponentCouldBeFlipped: [TwoPinComponentOrientationSolver],
335617
+ TwoPinComponentShouldBeVertical: [TwoPinComponentRailOrientationSolver],
335618
+ TwoPinComponentHasInvertedRails: [TwoPinComponentRailOrientationSolver],
335619
+ DecouplingCapacitorsNotCloseTogether: [DecouplingCapacitorGroupingSolver],
335620
+ ConnectorPositionCausesTraceDetours: [ConnectorPlacementSolver],
335621
+ LowSideTransistorNotAlignedWithLoad: [LowSideTransistorPlacementSolver],
335622
+ UsbSeriesResistorsNotAligned: [UsbSeriesResistorPlacementSolver],
335623
+ CurrentSenseShuntSeparatedFromInputs: [CurrentSenseShuntPlacementSolver],
335624
+ VoltageDividerSupplyResistorBelowGroundResistor: [
335625
+ VoltageDividerPlacementSolver
335626
+ ],
335627
+ RegulatorCapacitorsOnWrongSides: [
335628
+ RegulatorInputOutputCapacitorPlacementSolver
335629
+ ]
335630
+ };
335631
+
334743
335632
  class SchematicPlacementPipeline extends BasePipelineSolver2 {
334744
335633
  ctx;
334745
335634
  issues = [];
@@ -334792,6 +335681,9 @@ class SchematicPlacementPipeline extends BasePipelineSolver2 {
334792
335681
  definePipelineStep3("PullResistorPlacementSolver", PullResistorPlacementSolver, (p) => [
334793
335682
  { ctx: p.ctx, issues: p.issues }
334794
335683
  ]),
335684
+ definePipelineStep3("SwitchPullResistorPlacementSolver", SwitchPullResistorPlacementSolver, (p) => [
335685
+ { ctx: p.ctx, issues: p.issues }
335686
+ ]),
334795
335687
  definePipelineStep3("ComponentNetLabelCollisionSolver", ComponentNetLabelCollisionSolver, (p) => [
334796
335688
  { ctx: p.ctx, issues: p.issues }
334797
335689
  ]),
@@ -334803,15 +335695,42 @@ class SchematicPlacementPipeline extends BasePipelineSolver2 {
334803
335695
  ]),
334804
335696
  definePipelineStep3("LowSideTransistorPlacementSolver", LowSideTransistorPlacementSolver, (p) => [
334805
335697
  { ctx: p.ctx, issues: p.issues }
335698
+ ]),
335699
+ definePipelineStep3("UsbSeriesResistorPlacementSolver", UsbSeriesResistorPlacementSolver, (p) => [
335700
+ { ctx: p.ctx, issues: p.issues }
335701
+ ]),
335702
+ definePipelineStep3("RegulatorInputOutputCapacitorPlacementSolver", RegulatorInputOutputCapacitorPlacementSolver, (p) => [
335703
+ { ctx: p.ctx, issues: p.issues }
335704
+ ]),
335705
+ definePipelineStep3("VoltageDividerPlacementSolver", VoltageDividerPlacementSolver, (p) => [
335706
+ { ctx: p.ctx, issues: p.issues }
335707
+ ]),
335708
+ definePipelineStep3("CurrentSenseShuntPlacementSolver", CurrentSenseShuntPlacementSolver, (p) => [
335709
+ { ctx: p.ctx, issues: p.issues }
335710
+ ]),
335711
+ definePipelineStep3("RelayFlybackDiodePlacementSolver", RelayFlybackDiodePlacementSolver, (p) => [
335712
+ { ctx: p.ctx, issues: p.issues }
335713
+ ]),
335714
+ definePipelineStep3("MosfetGateNetworkPlacementSolver", MosfetGateNetworkPlacementSolver, (p) => [
335715
+ { ctx: p.ctx, issues: p.issues }
334806
335716
  ])
334807
335717
  ];
335718
+ selectedIssueTypes;
335719
+ constructor(circuitJson, options = {}) {
335720
+ super(circuitJson);
335721
+ if (options.issueTypes !== undefined) {
335722
+ this.selectedIssueTypes = new Set(options.issueTypes);
335723
+ const selectedSolvers = new Set(options.issueTypes.flatMap((type) => solversByIssueType[type]));
335724
+ this.pipelineDef = this.pipelineDef.filter((step) => selectedSolvers.has(step.solverClass));
335725
+ }
335726
+ }
334808
335727
  _setup() {
334809
335728
  this.ctx = buildSolverContext(this.inputProblem);
334810
335729
  }
334811
335730
  getOutput() {
334812
335731
  const railOrientationComponentIds = new Set(this.issues.flatMap((issue) => issue.lineItemType === "TwoPinComponentShouldBeVertical" && issue.schematicBox.schematicComponentId ? [issue.schematicBox.schematicComponentId] : []));
334813
335732
  return {
334814
- issues: this.issues.filter((issue) => issue.lineItemType !== "CapacitorSymbolHorizontal" || !railOrientationComponentIds.has(issue.schematicBox.schematicComponentId ?? "")),
335733
+ issues: this.issues.filter((issue) => issue.lineItemType !== "CapacitorSymbolHorizontal" || !railOrientationComponentIds.has(issue.schematicBox.schematicComponentId ?? "")).filter((issue) => this.selectedIssueTypes === undefined || this.selectedIssueTypes.has(issue.lineItemType)),
334815
335734
  componentPlacements: this.ctx.componentPlacements
334816
335735
  };
334817
335736
  }
@@ -334854,6 +335773,32 @@ var getRelevantPlacementsForIssues = ({
334854
335773
  };
334855
335774
  for (const issue of issues) {
334856
335775
  switch (issue.lineItemType) {
335776
+ case "MosfetGateNetworkNotGrouped":
335777
+ addPlacement(issue.mosfetSchematicBox);
335778
+ addPlacement(issue.seriesGateResistorSchematicBox);
335779
+ addPlacement(issue.gateSourceResistorSchematicBox);
335780
+ break;
335781
+ case "FlybackDiodeSeparatedFromRelayCoil":
335782
+ addPlacement(issue.relaySchematicBox);
335783
+ addPlacement(issue.diodeSchematicBox);
335784
+ break;
335785
+ case "CurrentSenseShuntSeparatedFromInputs":
335786
+ addPlacement(issue.amplifierSchematicBox);
335787
+ addPlacement(issue.shuntSchematicBox);
335788
+ break;
335789
+ case "VoltageDividerSupplyResistorBelowGroundResistor":
335790
+ addPlacement(issue.supplyResistorSchematicBox);
335791
+ addPlacement(issue.groundResistorSchematicBox);
335792
+ break;
335793
+ case "RegulatorCapacitorsOnWrongSides":
335794
+ addPlacement(issue.regulatorSchematicBox);
335795
+ addPlacement(issue.inputCapacitorSchematicBox);
335796
+ addPlacement(issue.outputCapacitorSchematicBox);
335797
+ break;
335798
+ case "UsbSeriesResistorsNotAligned":
335799
+ addPlacement(issue.positiveResistorSchematicBox);
335800
+ addPlacement(issue.negativeResistorSchematicBox);
335801
+ break;
334857
335802
  case "LowSideTransistorNotAlignedWithLoad":
334858
335803
  addPlacement(issue.transistorSchematicBox);
334859
335804
  addPlacement(issue.loadSchematicBox);
@@ -335027,6 +335972,7 @@ class SchematicPlacementAnalysis {
335027
335972
  }
335028
335973
  getIssueCounts(filter = {}) {
335029
335974
  const counts = {
335975
+ FlybackDiodeSeparatedFromRelayCoil: 0,
335030
335976
  ComponentOverlap: 0,
335031
335977
  SchematicBoxHasALotOfSurroundingWhitespace: 0,
335032
335978
  CapacitorSymbolHorizontal: 0,
@@ -335051,7 +335997,12 @@ class SchematicPlacementAnalysis {
335051
335997
  TwoPinComponentHasInvertedRails: 0,
335052
335998
  DecouplingCapacitorsNotCloseTogether: 0,
335053
335999
  ConnectorPositionCausesTraceDetours: 0,
335054
- LowSideTransistorNotAlignedWithLoad: 0
336000
+ LowSideTransistorNotAlignedWithLoad: 0,
336001
+ UsbSeriesResistorsNotAligned: 0,
336002
+ RegulatorCapacitorsOnWrongSides: 0,
336003
+ VoltageDividerSupplyResistorBelowGroundResistor: 0,
336004
+ CurrentSenseShuntSeparatedFromInputs: 0,
336005
+ MosfetGateNetworkNotGrouped: 0
335055
336006
  };
335056
336007
  for (const issue of this.getIssues(filter))
335057
336008
  counts[issue.lineItemType]++;
@@ -335072,6 +336023,10 @@ class SchematicPlacementAnalysis {
335072
336023
  }
335073
336024
  schematicIssuesToString(issue) {
335074
336025
  switch (issue.lineItemType) {
336026
+ case "MosfetGateNetworkNotGrouped":
336027
+ return MosfetGateNetworkPlacementSolver.issueToString(issue);
336028
+ case "CurrentSenseShuntSeparatedFromInputs":
336029
+ return CurrentSenseShuntPlacementSolver.issueToString(issue);
335075
336030
  case "ComponentOverlap":
335076
336031
  return SchematicBoxOverlapSolver.issueToString(issue);
335077
336032
  case "CapacitorSymbolHorizontal":
@@ -335114,6 +336069,14 @@ class SchematicPlacementAnalysis {
335114
336069
  return ConnectorPlacementSolver.issueToString(issue);
335115
336070
  case "LowSideTransistorNotAlignedWithLoad":
335116
336071
  return LowSideTransistorPlacementSolver.issueToString(issue);
336072
+ case "FlybackDiodeSeparatedFromRelayCoil":
336073
+ return RelayFlybackDiodePlacementSolver.issueToString(issue);
336074
+ case "VoltageDividerSupplyResistorBelowGroundResistor":
336075
+ return VoltageDividerPlacementSolver.issueToString(issue);
336076
+ case "RegulatorCapacitorsOnWrongSides":
336077
+ return RegulatorInputOutputCapacitorPlacementSolver.issueToString(issue);
336078
+ case "UsbSeriesResistorsNotAligned":
336079
+ return UsbSeriesResistorPlacementSolver.issueToString(issue);
335117
336080
  default:
335118
336081
  return "";
335119
336082
  }
@@ -335171,8 +336134,8 @@ class SchematicPlacementAnalysis {
335171
336134
  ];
335172
336135
  }
335173
336136
  }
335174
- var analyzeSchematicPlacement = (circuitJson) => {
335175
- const pipeline = new SchematicPlacementPipeline(circuitJson);
336137
+ var analyzeSchematicPlacement = (circuitJson, options = {}) => {
336138
+ const pipeline = new SchematicPlacementPipeline(circuitJson, options);
335176
336139
  pipeline.solve();
335177
336140
  const { issues, componentPlacements } = pipeline.getOutput();
335178
336141
  const relevantPlacements = getRelevantPlacementsForIssues({