@tscircuit/cli 0.1.1392 → 0.1.1393

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
@@ -100616,7 +100616,7 @@ var import_perfect_cli = __toESM2(require_dist2(), 1);
100616
100616
  // lib/getVersion.ts
100617
100617
  import { createRequire as createRequire2 } from "node:module";
100618
100618
  // package.json
100619
- var version = "0.1.1391";
100619
+ var version = "0.1.1392";
100620
100620
  var package_default = {
100621
100621
  name: "@tscircuit/cli",
100622
100622
  version,
@@ -100630,7 +100630,7 @@ var package_default = {
100630
100630
  "@biomejs/biome": "^1.9.4",
100631
100631
  "@tscircuit/circuit-json-placement-analysis": "^0.0.6",
100632
100632
  "@tscircuit/circuit-json-routing-analysis": "^0.0.1",
100633
- "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#8e3b4dc434d342f6b9833777107fc66515d1480b",
100633
+ "@tscircuit/circuit-json-schematic-placement-analysis": "github:tscircuit/circuit-json-schematic-placement-analysis#700017d79a608295cc275dcb9c2e1d160809ef9e",
100634
100634
  "@tscircuit/eval": "^0.0.835",
100635
100635
  "@tscircuit/fake-snippets": "^0.0.182",
100636
100636
  "@tscircuit/file-server": "^0.0.32",
@@ -244242,647 +244242,1254 @@ var registerCheckRoutingDifficulty = (program2) => {
244242
244242
  });
244243
244243
  };
244244
244244
 
244245
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/analyze-schematic-placement.ts
244246
- import { cju as cju7 } from "@tscircuit/circuit-json-util";
244245
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPlacementPipeline/SchematicPlacementPipeline.ts
244246
+ import {
244247
+ BasePipelineSolver as BasePipelineSolver2,
244248
+ definePipelineStep as definePipelineStep3
244249
+ } from "@tscircuit/solver-utils";
244247
244250
 
244248
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/capacitor-orientation.ts
244249
- var HORIZONTAL_CAPACITOR_SYMBOL_NAMES = new Set([
244250
- "capacitor_left",
244251
- "capacitor_right"
244252
- ]);
244253
- var isSchematicComponent = (element) => element.type === "schematic_component";
244254
- var isSourceCapacitor = (circuitJson, sourceComponentId) => {
244251
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/placements.ts
244252
+ import { cju as cju7 } from "@tscircuit/circuit-json-util";
244253
+ var isSchematicBox = (el3) => el3.type === "schematic_box";
244254
+ var isSchematicComponent = (el3) => el3.type === "schematic_component";
244255
+ var getSourceComponentName = (circuitJson, sourceComponentId) => {
244255
244256
  if (!sourceComponentId)
244256
- return false;
244257
- return circuitJson.some((element) => element.type === "source_component" && element.source_component_id === sourceComponentId && element.ftype === "simple_capacitor");
244258
- };
244259
- var generateCapacitorOrientationIssues = (componentPlacements, circuitJson) => {
244260
- const placementBySchematicComponentId = new Map(componentPlacements.filter((placement) => placement.schematicComponentId).map((placement) => [placement.schematicComponentId, placement]));
244261
- return circuitJson.filter(isSchematicComponent).filter((schematicComponent) => isSourceCapacitor(circuitJson, schematicComponent.source_component_id) && HORIZONTAL_CAPACITOR_SYMBOL_NAMES.has(schematicComponent.symbol_name ?? "")).flatMap((schematicComponent) => {
244262
- const schematicBox = placementBySchematicComponentId.get(schematicComponent.schematic_component_id);
244263
- if (!schematicBox)
244264
- return [];
244265
- return [
244266
- {
244267
- lineItemType: "CapacitorSymbolHorizontal",
244268
- schematicBox
244269
- }
244270
- ];
244271
- });
244257
+ return;
244258
+ return cju7(circuitJson).source_component.get(sourceComponentId)?.name;
244272
244259
  };
244273
-
244274
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/schematic-box-sizing/shared.ts
244275
- var SCHEMATIC_BOX_TOO_WIDE_MESSAGE = "Shrink schematic box width";
244276
- var SCHEMATIC_PIN_PADDING_TO_EDGE_TOO_LARGE_MESSAGE = "Move schematic pins closer to the box edge or change the schematic box";
244277
- var PIN_HEADER_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP = 0.1;
244278
- var GENERIC_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP = 1;
244279
- var PIN_LABEL_EDGE_PADDING = 0.1;
244280
- var PIN_NAME_CHARACTER_WIDTH = 0.095;
244281
- var FALLBACK_CHARACTER_WIDTH = 0.13;
244282
- var GAP_COMPARISON_EPSILON = 0.000000001;
244283
- var isSchematicPort = (element) => element.type === "schematic_port";
244284
- var isSourcePort = (element) => element.type === "source_port";
244285
- var isSchematicComponent2 = (element) => element.type === "schematic_component";
244286
- var getSourceComponentWithFtype = (element) => {
244287
- if (element.type !== "source_component" || !("source_component_id" in element) || typeof element.source_component_id !== "string") {
244288
- return null;
244289
- }
244260
+ var getSourceComponentMetadata = (schematicBox, circuitJson) => {
244261
+ if (!schematicBox.schematic_component_id)
244262
+ return {};
244263
+ const util2 = cju7(circuitJson);
244264
+ const sc2 = util2.schematic_component.get(schematicBox.schematic_component_id);
244265
+ if (!sc2?.source_component_id)
244266
+ return {};
244267
+ const sourceComponent = util2.source_component.get(sc2.source_component_id);
244290
244268
  return {
244291
- type: "source_component",
244292
- source_component_id: element.source_component_id,
244293
- ftype: "ftype" in element && typeof element.ftype === "string" ? element.ftype : undefined
244269
+ sourceComponentId: sc2.source_component_id,
244270
+ sourceComponentName: sourceComponent?.name
244294
244271
  };
244295
244272
  };
244296
- var isHorizontalSide = (side) => side === "left" || side === "right";
244297
- var isVerticalSide = (side) => side === "top" || side === "bottom";
244298
- var getCenteredRectBounds = (box2) => {
244299
- const halfWidth = box2.width / 2;
244300
- const halfHeight = box2.height / 2;
244273
+ var schematicComponentToPlacement = (schematicComponent, circuitJson, schematicBox) => ({
244274
+ lineItemType: "SchematicBoxPlacement",
244275
+ positionAnchor: "center",
244276
+ schX: schematicComponent.center.x,
244277
+ schY: schematicComponent.center.y,
244278
+ width: schematicBox?.width ?? schematicComponent.size.width,
244279
+ height: schematicBox?.height ?? schematicComponent.size.height,
244280
+ sourceComponentId: schematicComponent.source_component_id,
244281
+ sourceComponentName: getSourceComponentName(circuitJson, schematicComponent.source_component_id),
244282
+ schematicComponentId: schematicComponent.schematic_component_id,
244283
+ schematicSymbolId: schematicBox?.schematic_symbol_id ?? schematicComponent.schematic_symbol_id,
244284
+ subcircuitId: schematicComponent.subcircuit_id ?? schematicBox?.subcircuit_id
244285
+ });
244286
+ var schematicBoxToPlacement = (schematicBox, circuitJson) => ({
244287
+ lineItemType: "SchematicBoxPlacement",
244288
+ positionAnchor: "center",
244289
+ schX: schematicBox.x,
244290
+ schY: schematicBox.y,
244291
+ width: schematicBox.width,
244292
+ height: schematicBox.height,
244293
+ ...getSourceComponentMetadata(schematicBox, circuitJson),
244294
+ schematicComponentId: schematicBox.schematic_component_id,
244295
+ schematicSymbolId: schematicBox.schematic_symbol_id,
244296
+ subcircuitId: schematicBox.subcircuit_id
244297
+ });
244298
+ var buildSolverContext = (circuitJson) => {
244299
+ const schematicBoxes = circuitJson.filter(isSchematicBox);
244300
+ const schematicComponentIds = new Set(circuitJson.filter(isSchematicComponent).map((sc2) => sc2.schematic_component_id));
244301
+ const componentPlacements = [
244302
+ ...circuitJson.filter(isSchematicComponent).map((sc2) => schematicComponentToPlacement(sc2, circuitJson, schematicBoxes.find((sb2) => sb2.schematic_component_id === sc2.schematic_component_id))),
244303
+ ...schematicBoxes.filter((sb2) => !sb2.schematic_component_id || !schematicComponentIds.has(sb2.schematic_component_id)).map((sb2) => schematicBoxToPlacement(sb2, circuitJson))
244304
+ ];
244305
+ return { circuitJson, componentPlacements };
244306
+ };
244307
+
244308
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
244309
+ import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
244310
+
244311
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/graphics.ts
244312
+ import { mergeGraphics as mergeGraphics2 } from "graphics-debug";
244313
+ function mergeGraphicsObjects2(objects) {
244314
+ return objects.filter((o3) => o3 !== undefined).reduce((acc, o3) => mergeGraphics2(acc, o3), {});
244315
+ }
244316
+ function highlightPlacement(placement, color, label) {
244301
244317
  return {
244302
- left: box2.schX - halfWidth,
244303
- right: box2.schX + halfWidth,
244304
- top: box2.schY + halfHeight,
244305
- bottom: box2.schY - halfHeight
244318
+ rects: [
244319
+ {
244320
+ center: { x: placement.schX, y: placement.schY },
244321
+ width: placement.width,
244322
+ height: placement.height,
244323
+ stroke: color,
244324
+ fill: color.replace("0.95", "0.15"),
244325
+ label
244326
+ }
244327
+ ]
244306
244328
  };
244329
+ }
244330
+ function visualizeCircuitJson(circuitJson) {
244331
+ const rects = circuitJson.filter((el3) => el3.type === "schematic_box").map((el3) => {
244332
+ const box2 = el3;
244333
+ return {
244334
+ center: { x: box2.x, y: box2.y },
244335
+ width: box2.width,
244336
+ height: box2.height,
244337
+ stroke: "hsl(0,0%,60%)"
244338
+ };
244339
+ });
244340
+ return { rects };
244341
+ }
244342
+
244343
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/format.ts
244344
+ var fmtNumber5 = (value) => {
244345
+ if (Number.isInteger(value))
244346
+ return String(value);
244347
+ return value.toFixed(3).replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
244307
244348
  };
244308
- var isPinNameLabel = (label, sourcePort) => {
244309
- if (!sourcePort)
244310
- return false;
244311
- return label === sourcePort.name || label === String(sourcePort.pin_number) || (sourcePort.port_hints ?? []).includes(label);
244312
- };
244313
- var estimateLabelWidth = (label, sourcePort) => {
244314
- const characterWidth = isPinNameLabel(label, sourcePort) ? PIN_NAME_CHARACTER_WIDTH : FALLBACK_CHARACTER_WIDTH;
244315
- return Array.from(label).length * characterWidth;
244316
- };
244317
- var exceedsMaxAllowedGap = (measuredInnerLabelEmptySpace, maxAllowedInnerLabelEmptySpace) => measuredInnerLabelEmptySpace - maxAllowedInnerLabelEmptySpace > GAP_COMPARISON_EPSILON;
244318
- var getSourcePortById = (circuitJson) => new Map(circuitJson.filter(isSourcePort).map((sourcePort) => [sourcePort.source_port_id, sourcePort]));
244319
- var getSourceComponentById = (circuitJson) => new Map(circuitJson.flatMap((element) => {
244320
- const sourceComponent = getSourceComponentWithFtype(element);
244321
- return sourceComponent ? [sourceComponent] : [];
244322
- }).map((sourceComponent) => [
244323
- sourceComponent.source_component_id,
244324
- sourceComponent
244325
- ]));
244326
- var getSchematicComponentById = (circuitJson) => new Map(circuitJson.filter(isSchematicComponent2).map((schematicComponent) => [
244327
- schematicComponent.schematic_component_id,
244328
- schematicComponent
244329
- ]));
244330
- var getPlacementBySchematicComponentId = (componentPlacements) => new Map(componentPlacements.filter((placement) => placement.schematicComponentId).map((placement) => [placement.schematicComponentId, placement]));
244331
- var getPortsBySchematicComponentId = (circuitJson, isRelevantSide) => {
244332
- const portsBySchematicComponentId = new Map;
244333
- for (const port of circuitJson.filter(isSchematicPort)) {
244334
- if (!port.schematic_component_id)
244335
- continue;
244336
- if (!isRelevantSide(port.side_of_component))
244337
- continue;
244338
- const ports = portsBySchematicComponentId.get(port.schematic_component_id);
244339
- if (ports) {
244340
- ports.push(port);
244341
- } else {
244342
- portsBySchematicComponentId.set(port.schematic_component_id, [port]);
244349
+ var fmtDelta = (value) => {
244350
+ const formatted = fmtNumber5(value);
244351
+ return value > 0 ? `+${formatted}` : formatted;
244352
+ };
244353
+ var escapeAttr3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
244354
+ var addAttr = (attrs, key, value, options) => {
244355
+ if (value === undefined)
244356
+ return;
244357
+ const stringValue = typeof value === "number" ? options?.formatDelta ? fmtDelta(value) : fmtNumber5(value) : options?.escape === false ? value : escapeAttr3(value);
244358
+ attrs.push(`${key}="${stringValue}"`);
244359
+ };
244360
+
244361
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
244362
+ class CapacitorOrientationSolver extends BaseSolver6 {
244363
+ ctx;
244364
+ out;
244365
+ schematicComponentById;
244366
+ sourceComponentById;
244367
+ capacitorPlacements;
244368
+ currentPlacementIndex = 0;
244369
+ horizontalSymbolNames = new Set([
244370
+ "capacitor_left",
244371
+ "capacitor_right"
244372
+ ]);
244373
+ constructor({
244374
+ ctx,
244375
+ issues: out
244376
+ }) {
244377
+ super();
244378
+ this.ctx = ctx;
244379
+ this.out = out;
244380
+ this.schematicComponentById = this.buildSchematicComponentById(ctx.circuitJson);
244381
+ this.sourceComponentById = this.buildSourceComponentById(ctx.circuitJson);
244382
+ this.capacitorPlacements = this.getCapacitorPlacements();
244383
+ this.solved = this.capacitorPlacements.length === 0;
244384
+ }
244385
+ getCapacitorPlacements() {
244386
+ return this.ctx.componentPlacements.filter((p3) => p3.sourceComponentId !== undefined && this.sourceComponentById.get(p3.sourceComponentId)?.ftype === "simple_capacitor").map((p3) => ({
244387
+ schX: p3.schX,
244388
+ schY: p3.schY,
244389
+ width: p3.width,
244390
+ height: p3.height,
244391
+ sourceComponentId: p3.sourceComponentId,
244392
+ sourceComponentName: p3.sourceComponentName,
244393
+ schematicComponentId: p3.schematicComponentId
244394
+ }));
244395
+ }
244396
+ _step() {
244397
+ const currentPlacement = this.capacitorPlacements[this.currentPlacementIndex];
244398
+ if (!currentPlacement) {
244399
+ this.solved = true;
244400
+ return;
244343
244401
  }
244402
+ this.currentPlacementIndex += 1;
244403
+ this.solved = this.currentPlacementIndex >= this.capacitorPlacements.length;
244404
+ const issue = this.getIssueForPlacement(currentPlacement);
244405
+ if (issue)
244406
+ this.out.push(issue);
244344
244407
  }
244345
- return portsBySchematicComponentId;
244346
- };
244347
- var getSourceComponentFtype = (schematicBox, sourceComponentById) => schematicBox.sourceComponentId ? sourceComponentById.get(schematicBox.sourceComponentId)?.ftype : undefined;
244408
+ visualize() {
244409
+ const focusedPlacement = this.getFocusedPlacement();
244410
+ return mergeGraphicsObjects2([
244411
+ visualizeCircuitJson(this.ctx.circuitJson),
244412
+ focusedPlacement ? highlightPlacement(focusedPlacement, "hsl(210, 100%, 50%, 0.95)", "capacitorOrientation") : undefined
244413
+ ]);
244414
+ }
244415
+ getFocusedPlacement() {
244416
+ if (this.capacitorPlacements.length === 0)
244417
+ return;
244418
+ const index = this.iterations === 0 ? this.currentPlacementIndex : Math.max(0, this.currentPlacementIndex - 1);
244419
+ return this.capacitorPlacements[index];
244420
+ }
244421
+ buildSchematicComponentById(circuitJson) {
244422
+ return new Map(circuitJson.filter((el3) => el3.type === "schematic_component").map((sc2) => [sc2.schematic_component_id, sc2]));
244423
+ }
244424
+ buildSourceComponentById(circuitJson) {
244425
+ return new Map(circuitJson.flatMap((el3) => {
244426
+ if (el3.type !== "source_component" || !("source_component_id" in el3) || typeof el3.source_component_id !== "string")
244427
+ return [];
244428
+ return [
244429
+ {
244430
+ type: "source_component",
244431
+ source_component_id: el3.source_component_id,
244432
+ ftype: "ftype" in el3 && typeof el3.ftype === "string" ? el3.ftype : undefined
244433
+ }
244434
+ ];
244435
+ }).map((sc2) => [sc2.source_component_id, sc2]));
244436
+ }
244437
+ createIssuePlacement(placement) {
244438
+ return {
244439
+ positionAnchor: "center",
244440
+ schX: placement.schX,
244441
+ schY: placement.schY,
244442
+ width: placement.width,
244443
+ height: placement.height,
244444
+ sourceComponentId: placement.sourceComponentId,
244445
+ sourceComponentName: placement.sourceComponentName,
244446
+ schematicComponentId: placement.schematicComponentId
244447
+ };
244448
+ }
244449
+ getIssueForPlacement(placement) {
244450
+ if (!placement.schematicComponentId || !placement.sourceComponentId)
244451
+ return;
244452
+ const schematicComponent = this.schematicComponentById.get(placement.schematicComponentId);
244453
+ if (!schematicComponent)
244454
+ return;
244455
+ if (!this.horizontalSymbolNames.has(schematicComponent.symbol_name ?? ""))
244456
+ return;
244457
+ return {
244458
+ lineItemType: "CapacitorSymbolHorizontal",
244459
+ schematicBox: this.createIssuePlacement(placement)
244460
+ };
244461
+ }
244462
+ static issueToString(issue) {
244463
+ const attrs = [];
244464
+ addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
244465
+ addAttr(attrs, "schX", issue.schematicBox.schX);
244466
+ addAttr(attrs, "schY", issue.schematicBox.schY);
244467
+ addAttr(attrs, "width", issue.schematicBox.width);
244468
+ addAttr(attrs, "height", issue.schematicBox.height);
244469
+ return `<CapacitorSymbolHorizontal ${attrs.join(" ")} />`;
244470
+ }
244471
+ }
244348
244472
 
244349
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/schematic-box-sizing/pin-padding-to-edge.ts
244350
- var isSchematicSide = (side) => isHorizontalSide(side) || isVerticalSide(side);
244351
- var getPinSpacing = (schematicBox, schematicComponentById) => {
244352
- if (!schematicBox.schematicComponentId)
244353
- return null;
244354
- const schematicComponent = schematicComponentById.get(schematicBox.schematicComponentId);
244355
- return typeof schematicComponent?.pin_spacing === "number" ? schematicComponent.pin_spacing : null;
244356
- };
244357
- var getPinName = (port, sourcePortById) => {
244358
- const sourcePort = sourcePortById.get(port.source_port_id);
244359
- if (sourcePort?.name)
244360
- return sourcePort.name;
244361
- if (port.display_pin_label)
244362
- return port.display_pin_label;
244363
- if (sourcePort?.pin_number !== undefined)
244364
- return String(sourcePort.pin_number);
244365
- return;
244366
- };
244367
- var getMaxLabelLengthBySide = (ports, sourcePortById) => {
244368
- const maxLabelLengthBySide = {
244369
- left: 0,
244370
- right: 0,
244371
- top: 0,
244372
- bottom: 0
244373
- };
244374
- for (const port of ports) {
244375
- if (!isSchematicSide(port.side_of_component))
244376
- continue;
244377
- if (!port.display_pin_label)
244378
- continue;
244379
- maxLabelLengthBySide[port.side_of_component] = Math.max(maxLabelLengthBySide[port.side_of_component], estimateLabelWidth(port.display_pin_label, sourcePortById.get(port.source_port_id)));
244473
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxOverlapSolver/SchematicBoxOverlapSolver.ts
244474
+ import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
244475
+ class SchematicBoxOverlapSolver extends BaseSolver8 {
244476
+ params;
244477
+ placements;
244478
+ firstIndex = 0;
244479
+ secondIndex = 1;
244480
+ constructor(params2) {
244481
+ super();
244482
+ this.params = params2;
244483
+ this.placements = params2.ctx.componentPlacements;
244484
+ this.solved = this.placements.length < 2;
244380
244485
  }
244381
- return maxLabelLengthBySide;
244382
- };
244383
- var getOuterPinBySide = (edgeSide, ports) => {
244384
- if (ports.length === 0)
244385
- return null;
244386
- switch (edgeSide) {
244387
- case "top":
244388
- return ports.reduce((topPort, port) => port.center.y > topPort.center.y ? port : topPort);
244389
- case "bottom":
244390
- return ports.reduce((bottomPort, port) => port.center.y < bottomPort.center.y ? port : bottomPort);
244391
- case "left":
244392
- return ports.reduce((leftPort, port) => port.center.x < leftPort.center.x ? port : leftPort);
244393
- case "right":
244394
- return ports.reduce((rightPort, port) => port.center.x > rightPort.center.x ? port : rightPort);
244486
+ _step() {
244487
+ if (this.firstIndex >= this.placements.length - 1) {
244488
+ this.solved = true;
244489
+ return;
244490
+ }
244491
+ const overlap = this.getComponentOverlap(this.placements[this.firstIndex], this.placements[this.secondIndex]);
244492
+ if (overlap)
244493
+ this.params.issues.push(overlap);
244494
+ this.secondIndex++;
244495
+ if (this.secondIndex >= this.placements.length) {
244496
+ this.firstIndex++;
244497
+ this.secondIndex = this.firstIndex + 1;
244498
+ }
244499
+ this.solved = this.firstIndex >= this.placements.length - 1;
244395
244500
  }
244396
- };
244397
- var getPinPaddingToEdge = (input) => {
244398
- const bounds = getCenteredRectBounds(input.schematicBox);
244399
- switch (input.edgeSide) {
244400
- case "top":
244401
- return Math.max(0, bounds.top - input.port.center.y);
244402
- case "bottom":
244403
- return Math.max(0, input.port.center.y - bounds.bottom);
244404
- case "left":
244405
- return Math.max(0, input.port.center.x - bounds.left);
244406
- case "right":
244407
- return Math.max(0, bounds.right - input.port.center.x);
244501
+ getCenteredRectBounds(box2) {
244502
+ return {
244503
+ left: box2.schX - box2.width / 2,
244504
+ right: box2.schX + box2.width / 2,
244505
+ top: box2.schY - box2.height / 2,
244506
+ bottom: box2.schY + box2.height / 2
244507
+ };
244408
244508
  }
244409
- };
244410
- var getBoxEdgeSidesForPinSide = (pinSide) => isHorizontalSide(pinSide) ? ["top", "bottom"] : ["left", "right"];
244411
- var hasPinsOnAllSides = (portsBySide) => portsBySide.has("left") && portsBySide.has("right") && portsBySide.has("top") && portsBySide.has("bottom");
244412
- var getMaxAllowedPinPadding = (input) => {
244413
- const edgeAxisSides = isHorizontalSide(input.edgeSide) ? ["left", "right"] : ["top", "bottom"];
244414
- return (input.maxLabelLengthBySide[edgeAxisSides[0]] + input.maxLabelLengthBySide[edgeAxisSides[1]] + input.spacing) / 2;
244415
- };
244416
- var createPinPaddingToEdgeIssue = (candidate) => {
244417
- const excessPadding = Math.max(0, candidate.measuredPadding - candidate.maxAllowedPadding);
244418
- const widthReduction = excessPadding * 2;
244419
- const heightReduction = excessPadding * 2;
244420
- return {
244421
- lineItemType: "SchematicPinPaddingToEdgeTooLarge",
244422
- pinSide: candidate.pinSide,
244423
- edgeSide: candidate.edgeSide,
244424
- pinName: candidate.pinName,
244425
- schematicBox: candidate.schematicBox,
244426
- measuredPadding: candidate.measuredPadding,
244427
- maxAllowedPadding: candidate.maxAllowedPadding,
244428
- excessPadding,
244429
- suggestedSchWidth: isHorizontalSide(candidate.pinSide) ? undefined : Math.max(0, candidate.schematicBox.width - widthReduction),
244430
- suggestedSchHeight: isHorizontalSide(candidate.pinSide) ? Math.max(0, candidate.schematicBox.height - heightReduction) : undefined,
244431
- message: isHorizontalSide(candidate.pinSide) ? `${SCHEMATIC_PIN_PADDING_TO_EDGE_TOO_LARGE_MESSAGE} height` : `${SCHEMATIC_PIN_PADDING_TO_EDGE_TOO_LARGE_MESSAGE} width`
244432
- };
244433
- };
244434
- var generateSchematicPinPaddingToEdgeCandidates = (componentPlacements, circuitJson) => {
244435
- const placementBySchematicComponentId = getPlacementBySchematicComponentId(componentPlacements);
244436
- const schematicComponentById = getSchematicComponentById(circuitJson);
244437
- const sourcePortById = getSourcePortById(circuitJson);
244438
- const portsBySchematicComponentId = getPortsBySchematicComponentId(circuitJson, isSchematicSide);
244439
- const candidates = [];
244440
- for (const [schematicComponentId, ports] of portsBySchematicComponentId) {
244441
- const schematicBox = placementBySchematicComponentId.get(schematicComponentId);
244509
+ getOverlapCorrectionSuggestions({
244510
+ firstComponent,
244511
+ secondComponent,
244512
+ overlapWidth,
244513
+ overlapHeight
244514
+ }) {
244515
+ const firstArea = firstComponent.width * firstComponent.height;
244516
+ const secondArea = secondComponent.width * secondComponent.height;
244517
+ const target = firstArea <= secondArea ? firstComponent : secondComponent;
244518
+ const other = target === firstComponent ? secondComponent : firstComponent;
244519
+ const deltaSchX = target.schX <= other.schX ? -overlapWidth : overlapWidth;
244520
+ const deltaSchY = target.schY <= other.schY ? -overlapHeight : overlapHeight;
244521
+ return [
244522
+ {
244523
+ targetComponentName: target.sourceComponentName,
244524
+ deltaSchX,
244525
+ deltaSchY: 0,
244526
+ newSchX: target.schX + deltaSchX,
244527
+ newSchY: target.schY
244528
+ },
244529
+ {
244530
+ targetComponentName: target.sourceComponentName,
244531
+ deltaSchX: 0,
244532
+ deltaSchY,
244533
+ newSchX: target.schX,
244534
+ newSchY: target.schY + deltaSchY
244535
+ }
244536
+ ];
244537
+ }
244538
+ static issueToString(issue) {
244539
+ const attrs = [];
244540
+ addAttr(attrs, "component1Name", issue.firstComponent.sourceComponentName);
244541
+ addAttr(attrs, "component2Name", issue.secondComponent.sourceComponentName);
244542
+ addAttr(attrs, "component1SchX", issue.firstComponent.schX);
244543
+ addAttr(attrs, "component1SchY", issue.firstComponent.schY);
244544
+ addAttr(attrs, "component2SchX", issue.secondComponent.schX);
244545
+ addAttr(attrs, "component2SchY", issue.secondComponent.schY);
244546
+ addAttr(attrs, "overlapWidth", issue.overlapWidth);
244547
+ addAttr(attrs, "overlapHeight", issue.overlapHeight);
244548
+ return [
244549
+ `<ComponentOverlap ${attrs.join(" ")}>`,
244550
+ ...issue.correctionSuggestions.map(SchematicBoxOverlapSolver.correctionSuggestionToString),
244551
+ "</ComponentOverlap>"
244552
+ ].join(`
244553
+ `);
244554
+ }
244555
+ static correctionSuggestionToString(suggestion) {
244556
+ const attrs = [];
244557
+ addAttr(attrs, "target", suggestion.targetComponentName);
244558
+ if (suggestion.deltaSchX !== 0) {
244559
+ addAttr(attrs, "newSchX", suggestion.newSchX);
244560
+ addAttr(attrs, "deltaSchX", suggestion.deltaSchX, { formatDelta: true });
244561
+ }
244562
+ if (suggestion.deltaSchY !== 0) {
244563
+ addAttr(attrs, "newSchY", suggestion.newSchY);
244564
+ addAttr(attrs, "deltaSchY", suggestion.deltaSchY, { formatDelta: true });
244565
+ }
244566
+ return `<OverlapCorrectionSuggestion ${attrs.join(" ")} />`;
244567
+ }
244568
+ getComponentOverlap(firstComponent, secondComponent) {
244569
+ const a2 = this.getCenteredRectBounds(firstComponent);
244570
+ const b = this.getCenteredRectBounds(secondComponent);
244571
+ const overlapWidth = Math.min(a2.right, b.right) - Math.max(a2.left, b.left);
244572
+ const overlapHeight = Math.min(a2.bottom, b.bottom) - Math.max(a2.top, b.top);
244573
+ if (overlapWidth <= 0 || overlapHeight <= 0)
244574
+ return null;
244575
+ return {
244576
+ lineItemType: "ComponentOverlap",
244577
+ firstComponent,
244578
+ secondComponent,
244579
+ overlapWidth,
244580
+ overlapHeight,
244581
+ correctionSuggestions: this.getOverlapCorrectionSuggestions({
244582
+ firstComponent,
244583
+ secondComponent,
244584
+ overlapWidth,
244585
+ overlapHeight
244586
+ })
244587
+ };
244588
+ }
244589
+ }
244590
+
244591
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxInnerLabelCollisionSolver/SchematicBoxInnerLabelCollisionSolver.ts
244592
+ import { BaseSolver as BaseSolver9 } from "@tscircuit/solver-utils";
244593
+ class SchematicBoxInnerLabelCollisionSolver extends BaseSolver9 {
244594
+ params;
244595
+ MESSAGE = "Inner labels are colliding. Increase the schWidth or schHeight.";
244596
+ PIN_LABEL_EDGE_PADDING = 0.1;
244597
+ PIN_LABEL_TEXT_HEIGHT = 0.15;
244598
+ PIN_NAME_CHARACTER_WIDTH = 0.095;
244599
+ FALLBACK_CHARACTER_WIDTH = 0.13;
244600
+ INNER_LABEL_COLLISION_PADDING = 0.02;
244601
+ COLLISION_COMPARISON_EPSILON = 0.000000001;
244602
+ entries;
244603
+ placementById;
244604
+ sourcePortById;
244605
+ currentIndex = 0;
244606
+ constructor(params2) {
244607
+ super();
244608
+ this.params = params2;
244609
+ const { circuitJson, componentPlacements } = params2.ctx;
244610
+ this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
244611
+ this.sourcePortById = this.getSourcePortById(circuitJson);
244612
+ this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson));
244613
+ this.solved = this.entries.length === 0;
244614
+ }
244615
+ _step() {
244616
+ const entry = this.entries[this.currentIndex++];
244617
+ if (!entry) {
244618
+ this.solved = true;
244619
+ return;
244620
+ }
244621
+ this.solved = this.currentIndex >= this.entries.length;
244622
+ const [schematicComponentId, ports] = entry;
244623
+ const schematicBox = this.placementById.get(schematicComponentId);
244442
244624
  if (!schematicBox)
244443
- continue;
244444
- const pinSpacing = getPinSpacing(schematicBox, schematicComponentById);
244625
+ return;
244626
+ const bounds = this.getCenteredRectBounds(schematicBox);
244627
+ const labelRects = this.getLabelRects(bounds, ports, this.sourcePortById);
244628
+ if (labelRects.length === 0)
244629
+ return;
244630
+ const collisionSummary = this.getCollisionSummary(labelRects);
244631
+ if (collisionSummary.overlappingSides.length === 0)
244632
+ return;
244633
+ this.params.issues.push({
244634
+ lineItemType: "SchematicBoxInnerLabelCollision",
244635
+ schematicBox,
244636
+ overlappingSides: collisionSummary.overlappingSides,
244637
+ message: this.MESSAGE
244638
+ });
244639
+ }
244640
+ static issueToString(issue) {
244641
+ const attrs = [];
244642
+ addAttr(attrs, "message", issue.message, { escape: false });
244643
+ addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
244644
+ addAttr(attrs, "currentSchWidth", issue.schematicBox.width);
244645
+ addAttr(attrs, "currentSchHeight", issue.schematicBox.height);
244646
+ addAttr(attrs, "overlappingSides", issue.overlappingSides.join(","));
244647
+ return `<SchematicBoxInnerLabelCollision ${attrs.join(" ")} />`;
244648
+ }
244649
+ isSchematicPort(el3) {
244650
+ return el3.type === "schematic_port";
244651
+ }
244652
+ isSourcePort(el3) {
244653
+ return el3.type === "source_port";
244654
+ }
244655
+ isSchematicSide(side) {
244656
+ return side === "left" || side === "right" || side === "top" || side === "bottom";
244657
+ }
244658
+ isPinNameLabel(label, sourcePort) {
244659
+ if (!sourcePort)
244660
+ return false;
244661
+ return label === sourcePort.name || label === String(sourcePort.pin_number) || (sourcePort.port_hints ?? []).includes(label);
244662
+ }
244663
+ estimateLabelLength(label, sourcePort) {
244664
+ return Array.from(label).length * (this.isPinNameLabel(label, sourcePort) ? this.PIN_NAME_CHARACTER_WIDTH : this.FALLBACK_CHARACTER_WIDTH);
244665
+ }
244666
+ hasCollision(requiredGrowth) {
244667
+ return requiredGrowth > this.COLLISION_COMPARISON_EPSILON;
244668
+ }
244669
+ getCenteredRectBounds(box2) {
244670
+ return {
244671
+ left: box2.schX - box2.width / 2,
244672
+ right: box2.schX + box2.width / 2,
244673
+ top: box2.schY + box2.height / 2,
244674
+ bottom: box2.schY - box2.height / 2
244675
+ };
244676
+ }
244677
+ getSourcePortById(circuitJson) {
244678
+ return new Map(circuitJson.filter((el3) => this.isSourcePort(el3)).map((sp3) => [sp3.source_port_id, sp3]));
244679
+ }
244680
+ getPlacementBySchematicComponentId(componentPlacements) {
244681
+ return new Map(componentPlacements.filter((p3) => p3.schematicComponentId).map((p3) => [p3.schematicComponentId, p3]));
244682
+ }
244683
+ getPortsBySchematicComponentId(circuitJson) {
244684
+ const map = new Map;
244685
+ for (const port of circuitJson.filter((el3) => this.isSchematicPort(el3))) {
244686
+ if (!port.schematic_component_id)
244687
+ continue;
244688
+ if (!this.isSchematicSide(port.side_of_component))
244689
+ continue;
244690
+ const ports = map.get(port.schematic_component_id);
244691
+ if (ports)
244692
+ ports.push(port);
244693
+ else
244694
+ map.set(port.schematic_component_id, [port]);
244695
+ }
244696
+ return map;
244697
+ }
244698
+ getLabelRects(bounds, ports, sourcePortById) {
244699
+ const rects = [];
244700
+ for (const port of ports) {
244701
+ if (!this.isSchematicSide(port.side_of_component))
244702
+ continue;
244703
+ if (!port.display_pin_label)
244704
+ continue;
244705
+ const labelLength = this.estimateLabelLength(port.display_pin_label, sourcePortById.get(port.source_port_id));
244706
+ const halfTextHeight = this.PIN_LABEL_TEXT_HEIGHT / 2;
244707
+ switch (port.side_of_component) {
244708
+ case "left": {
244709
+ const xMin = bounds.left + this.PIN_LABEL_EDGE_PADDING;
244710
+ rects.push({
244711
+ side: port.side_of_component,
244712
+ xMin,
244713
+ xMax: xMin + labelLength,
244714
+ yMin: port.center.y - halfTextHeight,
244715
+ yMax: port.center.y + halfTextHeight
244716
+ });
244717
+ break;
244718
+ }
244719
+ case "right": {
244720
+ const xMax = bounds.right - this.PIN_LABEL_EDGE_PADDING;
244721
+ rects.push({
244722
+ side: port.side_of_component,
244723
+ xMin: xMax - labelLength,
244724
+ xMax,
244725
+ yMin: port.center.y - halfTextHeight,
244726
+ yMax: port.center.y + halfTextHeight
244727
+ });
244728
+ break;
244729
+ }
244730
+ case "top": {
244731
+ const yMax = bounds.top - this.PIN_LABEL_EDGE_PADDING;
244732
+ rects.push({
244733
+ side: port.side_of_component,
244734
+ xMin: port.center.x - halfTextHeight,
244735
+ xMax: port.center.x + halfTextHeight,
244736
+ yMin: yMax - labelLength,
244737
+ yMax
244738
+ });
244739
+ break;
244740
+ }
244741
+ case "bottom": {
244742
+ const yMin = bounds.bottom + this.PIN_LABEL_EDGE_PADDING;
244743
+ rects.push({
244744
+ side: port.side_of_component,
244745
+ xMin: port.center.x - halfTextHeight,
244746
+ xMax: port.center.x + halfTextHeight,
244747
+ yMin,
244748
+ yMax: yMin + labelLength
244749
+ });
244750
+ break;
244751
+ }
244752
+ }
244753
+ }
244754
+ return rects;
244755
+ }
244756
+ getCollisionSummary(rects) {
244757
+ const overlappingSides = new Set;
244758
+ for (let i2 = 0;i2 < rects.length; i2++) {
244759
+ for (let j4 = i2 + 1;j4 < rects.length; j4++) {
244760
+ const a2 = rects[i2];
244761
+ const b = rects[j4];
244762
+ if (a2.side === b.side)
244763
+ continue;
244764
+ if (!this.rectsOverlap(a2, b))
244765
+ continue;
244766
+ overlappingSides.add(a2.side);
244767
+ overlappingSides.add(b.side);
244768
+ }
244769
+ }
244770
+ return {
244771
+ overlappingSides: this.sortSides(Array.from(overlappingSides))
244772
+ };
244773
+ }
244774
+ rectsOverlap(a2, b) {
244775
+ return this.hasCollision(Math.min(a2.xMax, b.xMax) - Math.max(a2.xMin, b.xMin) + this.INNER_LABEL_COLLISION_PADDING) && this.hasCollision(Math.min(a2.yMax, b.yMax) - Math.max(a2.yMin, b.yMin) + this.INNER_LABEL_COLLISION_PADDING);
244776
+ }
244777
+ sortSides(sides) {
244778
+ const order = {
244779
+ left: 0,
244780
+ right: 1,
244781
+ top: 2,
244782
+ bottom: 3
244783
+ };
244784
+ return sides.sort((a2, b) => order[a2] - order[b]);
244785
+ }
244786
+ }
244787
+
244788
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxTooWideSolver/SchematicBoxTooWideSolver.ts
244789
+ import { BaseSolver as BaseSolver10 } from "@tscircuit/solver-utils";
244790
+ class SchematicBoxTooWideSolver extends BaseSolver10 {
244791
+ params;
244792
+ SCHEMATIC_BOX_TOO_WIDE_MESSAGE = "Shrink schematic box width";
244793
+ PIN_HEADER_MAX_ALLOWED_GAP = 0.1;
244794
+ GENERIC_MAX_ALLOWED_GAP = 1;
244795
+ PIN_LABEL_EDGE_PADDING = 0.1;
244796
+ PIN_NAME_CHARACTER_WIDTH = 0.095;
244797
+ FALLBACK_CHARACTER_WIDTH = 0.13;
244798
+ GAP_COMPARISON_EPSILON = 0.000000001;
244799
+ entries;
244800
+ placementById;
244801
+ sourcePortById;
244802
+ sourceComponentById;
244803
+ currentIndex = 0;
244804
+ constructor(params2) {
244805
+ super();
244806
+ this.params = params2;
244807
+ const { circuitJson, componentPlacements } = params2.ctx;
244808
+ this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
244809
+ this.sourcePortById = this.getSourcePortById(circuitJson);
244810
+ this.sourceComponentById = this.getSourceComponentById(circuitJson);
244811
+ this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson));
244812
+ this.solved = this.entries.length === 0;
244813
+ }
244814
+ _step() {
244815
+ const entry = this.entries[this.currentIndex++];
244816
+ if (!entry) {
244817
+ this.solved = true;
244818
+ return;
244819
+ }
244820
+ this.solved = this.currentIndex >= this.entries.length;
244821
+ const [schematicComponentId, ports] = entry;
244822
+ const schematicBox = this.placementById.get(schematicComponentId);
244823
+ if (!schematicBox)
244824
+ return;
244825
+ const bounds = this.getCenteredRectBounds(schematicBox);
244826
+ const leftCol = this.getLabelColumn("left", ports, this.sourcePortById);
244827
+ const rightCol = this.getLabelColumn("right", ports, this.sourcePortById);
244828
+ const ftype = this.getSourceComponentFtype(schematicBox, this.sourceComponentById);
244829
+ let measuredSpace;
244830
+ if (leftCol && rightCol) {
244831
+ measuredSpace = this.getInnerLabelEdge(bounds, rightCol) - this.getInnerLabelEdge(bounds, leftCol);
244832
+ } else if (leftCol && leftCol.labelCount >= 4) {
244833
+ measuredSpace = bounds.right - this.getInnerLabelEdge(bounds, leftCol);
244834
+ } else if (rightCol && rightCol.labelCount >= 4) {
244835
+ measuredSpace = this.getInnerLabelEdge(bounds, rightCol) - bounds.left;
244836
+ }
244837
+ if (measuredSpace === undefined)
244838
+ return;
244839
+ const maxAllowed = ftype === "simple_pin_header" ? this.PIN_HEADER_MAX_ALLOWED_GAP : this.GENERIC_MAX_ALLOWED_GAP;
244840
+ if (!this.exceedsMaxAllowedGap(measuredSpace, maxAllowed))
244841
+ return;
244842
+ const suggestedSchWidth = this.getSuggestedWidth({
244843
+ measuredInnerLabelHorizontalEmptySpace: measuredSpace,
244844
+ maxAllowedInnerLabelHorizontalEmptySpace: maxAllowed,
244845
+ currentWidth: schematicBox.width
244846
+ });
244847
+ if (ftype === "simple_pin_header") {
244848
+ this.params.issues.push({
244849
+ lineItemType: "PinHeaderSchematicBoxTooWide",
244850
+ schematicBox,
244851
+ measuredInnerLabelHorizontalEmptySpace: measuredSpace,
244852
+ maxAllowedInnerLabelHorizontalEmptySpace: maxAllowed,
244853
+ suggestedSchWidth,
244854
+ message: this.SCHEMATIC_BOX_TOO_WIDE_MESSAGE
244855
+ });
244856
+ } else {
244857
+ this.params.issues.push({
244858
+ lineItemType: "GenericSchematicBoxTooWide",
244859
+ schematicBox,
244860
+ measuredInnerLabelHorizontalEmptySpace: measuredSpace,
244861
+ maxAllowedInnerLabelHorizontalEmptySpace: maxAllowed,
244862
+ suggestedSchWidth,
244863
+ message: this.SCHEMATIC_BOX_TOO_WIDE_MESSAGE
244864
+ });
244865
+ }
244866
+ }
244867
+ static issueToString(issue) {
244868
+ const attrs = [];
244869
+ addAttr(attrs, "message", issue.message, { escape: false });
244870
+ addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
244871
+ addAttr(attrs, "currentSchWidth", issue.schematicBox.width);
244872
+ addAttr(attrs, "measuredInnerLabelHorizontalEmptySpace", issue.measuredInnerLabelHorizontalEmptySpace);
244873
+ addAttr(attrs, "maxAllowedInnerLabelHorizontalEmptySpace", issue.maxAllowedInnerLabelHorizontalEmptySpace);
244874
+ addAttr(attrs, "suggestedSchWidth", issue.suggestedSchWidth);
244875
+ return `<${issue.lineItemType} ${attrs.join(" ")} />`;
244876
+ }
244877
+ isSchematicPort(el3) {
244878
+ return el3.type === "schematic_port";
244879
+ }
244880
+ isSourcePort(el3) {
244881
+ return el3.type === "source_port";
244882
+ }
244883
+ isHorizontalSide(side) {
244884
+ return side === "left" || side === "right";
244885
+ }
244886
+ getSourceComponentWithFtype(el3) {
244887
+ if (el3.type !== "source_component" || !("source_component_id" in el3) || typeof el3.source_component_id !== "string")
244888
+ return null;
244889
+ return {
244890
+ type: "source_component",
244891
+ source_component_id: el3.source_component_id,
244892
+ ftype: "ftype" in el3 && typeof el3.ftype === "string" ? el3.ftype : undefined
244893
+ };
244894
+ }
244895
+ isPinNameLabel(label, sourcePort) {
244896
+ if (!sourcePort)
244897
+ return false;
244898
+ return label === sourcePort.name || label === String(sourcePort.pin_number) || (sourcePort.port_hints ?? []).includes(label);
244899
+ }
244900
+ estimateLabelWidth(label, sourcePort) {
244901
+ return Array.from(label).length * (this.isPinNameLabel(label, sourcePort) ? this.PIN_NAME_CHARACTER_WIDTH : this.FALLBACK_CHARACTER_WIDTH);
244902
+ }
244903
+ exceedsMaxAllowedGap(measured, maxAllowed) {
244904
+ return measured - maxAllowed > this.GAP_COMPARISON_EPSILON;
244905
+ }
244906
+ getCenteredRectBounds(box2) {
244907
+ return {
244908
+ left: box2.schX - box2.width / 2,
244909
+ right: box2.schX + box2.width / 2,
244910
+ top: box2.schY + box2.height / 2,
244911
+ bottom: box2.schY - box2.height / 2
244912
+ };
244913
+ }
244914
+ getSourcePortById(circuitJson) {
244915
+ return new Map(circuitJson.filter((el3) => this.isSourcePort(el3)).map((sp3) => [sp3.source_port_id, sp3]));
244916
+ }
244917
+ getSourceComponentById(circuitJson) {
244918
+ return new Map(circuitJson.flatMap((el3) => {
244919
+ const sc2 = this.getSourceComponentWithFtype(el3);
244920
+ return sc2 ? [sc2] : [];
244921
+ }).map((sc2) => [sc2.source_component_id, sc2]));
244922
+ }
244923
+ getPlacementBySchematicComponentId(componentPlacements) {
244924
+ return new Map(componentPlacements.filter((p3) => p3.schematicComponentId).map((p3) => [p3.schematicComponentId, p3]));
244925
+ }
244926
+ getPortsBySchematicComponentId(circuitJson) {
244927
+ const map = new Map;
244928
+ for (const port of circuitJson.filter((el3) => this.isSchematicPort(el3))) {
244929
+ if (!port.schematic_component_id)
244930
+ continue;
244931
+ if (!this.isHorizontalSide(port.side_of_component))
244932
+ continue;
244933
+ const ports = map.get(port.schematic_component_id);
244934
+ if (ports)
244935
+ ports.push(port);
244936
+ else
244937
+ map.set(port.schematic_component_id, [port]);
244938
+ }
244939
+ return map;
244940
+ }
244941
+ getSourceComponentFtype(schematicBox, sourceComponentById) {
244942
+ return schematicBox.sourceComponentId ? sourceComponentById.get(schematicBox.sourceComponentId)?.ftype : undefined;
244943
+ }
244944
+ getLabelColumn(side, ports, sourcePortById) {
244945
+ const widths = ports.filter((p3) => p3.side_of_component === side).flatMap((p3) => p3.display_pin_label ? [
244946
+ this.estimateLabelWidth(p3.display_pin_label, sourcePortById.get(p3.source_port_id))
244947
+ ] : []);
244948
+ if (widths.length === 0)
244949
+ return null;
244950
+ return {
244951
+ side,
244952
+ labelCount: widths.length,
244953
+ maxLabelWidth: Math.max(...widths)
244954
+ };
244955
+ }
244956
+ getInnerLabelEdge(bounds, col) {
244957
+ return col.side === "left" ? bounds.left + this.PIN_LABEL_EDGE_PADDING + col.maxLabelWidth : bounds.right - this.PIN_LABEL_EDGE_PADDING - col.maxLabelWidth;
244958
+ }
244959
+ getSuggestedWidth(input) {
244960
+ return input.currentWidth - input.measuredInnerLabelHorizontalEmptySpace + input.maxAllowedInnerLabelHorizontalEmptySpace;
244961
+ }
244962
+ }
244963
+
244964
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPinPaddingToEdgeSolver/SchematicPinPaddingToEdgeSolver.ts
244965
+ import { BaseSolver as BaseSolver11 } from "@tscircuit/solver-utils";
244966
+ class SchematicPinPaddingToEdgeSolver extends BaseSolver11 {
244967
+ params;
244968
+ MESSAGE = "Move schematic pins closer to the box edge or change the schematic box";
244969
+ PIN_NAME_CHARACTER_WIDTH = 0.095;
244970
+ FALLBACK_CHARACTER_WIDTH = 0.13;
244971
+ GAP_COMPARISON_EPSILON = 0.000000001;
244972
+ entries;
244973
+ placementById;
244974
+ schematicComponentById;
244975
+ sourcePortById;
244976
+ currentIndex = 0;
244977
+ constructor(params2) {
244978
+ super();
244979
+ this.params = params2;
244980
+ const { circuitJson, componentPlacements } = params2.ctx;
244981
+ this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
244982
+ this.schematicComponentById = this.getSchematicComponentById(circuitJson);
244983
+ this.sourcePortById = this.getSourcePortById(circuitJson);
244984
+ this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson));
244985
+ this.solved = this.entries.length === 0;
244986
+ }
244987
+ _step() {
244988
+ const entry = this.entries[this.currentIndex++];
244989
+ if (!entry) {
244990
+ this.solved = true;
244991
+ return;
244992
+ }
244993
+ this.solved = this.currentIndex >= this.entries.length;
244994
+ const [schematicComponentId, ports] = entry;
244995
+ const schematicBox = this.placementById.get(schematicComponentId);
244996
+ if (!schematicBox)
244997
+ return;
244998
+ const pinSpacing = this.getPinSpacing(schematicBox, this.schematicComponentById);
244445
244999
  if (pinSpacing === null)
244446
- continue;
244447
- const maxLabelLengthBySide = getMaxLabelLengthBySide(ports, sourcePortById);
245000
+ return;
245001
+ const maxLabelLengthBySide = this.getMaxLabelLengthBySide(ports, this.sourcePortById);
244448
245002
  const portsBySide = new Map;
244449
245003
  for (const port of ports) {
244450
- if (!isSchematicSide(port.side_of_component))
245004
+ if (!this.isSchematicSide(port.side_of_component))
244451
245005
  continue;
244452
245006
  const sidePorts = portsBySide.get(port.side_of_component) ?? [];
244453
245007
  sidePorts.push(port);
244454
245008
  portsBySide.set(port.side_of_component, sidePorts);
244455
245009
  }
244456
- const useLabelAwareMaxPadding = hasPinsOnAllSides(portsBySide);
245010
+ const useLabelAwareMaxPadding = this.hasPinsOnAllSides(portsBySide);
244457
245011
  for (const [pinSide, sidePorts] of portsBySide) {
244458
- for (const edgeSide of getBoxEdgeSidesForPinSide(pinSide)) {
244459
- const outerPin = getOuterPinBySide(edgeSide, sidePorts);
245012
+ for (const edgeSide of this.getBoxEdgeSidesForPinSide(pinSide)) {
245013
+ const outerPin = this.getOuterPinBySide(edgeSide, sidePorts);
244460
245014
  if (!outerPin)
244461
245015
  continue;
244462
- const measuredPinPadding = {
244463
- pinName: getPinName(outerPin, sourcePortById),
244464
- measuredPadding: getPinPaddingToEdge({
244465
- schematicBox,
244466
- port: outerPin,
244467
- edgeSide
244468
- })
244469
- };
244470
- candidates.push({
245016
+ const measuredPadding = this.getPinPaddingToEdge(schematicBox, outerPin, edgeSide);
245017
+ const maxAllowedPadding = useLabelAwareMaxPadding ? this.getMaxAllowedPinPadding(pinSpacing, edgeSide, maxLabelLengthBySide) : pinSpacing;
245018
+ if (!this.exceedsMaxAllowedGap(measuredPadding, maxAllowedPadding))
245019
+ continue;
245020
+ this.params.issues.push(this.createIssue({
244471
245021
  schematicBox,
244472
245022
  pinSide,
244473
245023
  edgeSide,
244474
- pinName: measuredPinPadding.pinName,
244475
- measuredPadding: measuredPinPadding.measuredPadding,
244476
- maxAllowedPadding: useLabelAwareMaxPadding ? getMaxAllowedPinPadding({
244477
- spacing: pinSpacing,
244478
- edgeSide,
244479
- maxLabelLengthBySide
244480
- }) : pinSpacing
244481
- });
245024
+ pinName: this.getPinName(outerPin, this.sourcePortById),
245025
+ measuredPadding,
245026
+ maxAllowedPadding
245027
+ }));
244482
245028
  }
244483
245029
  }
244484
245030
  }
244485
- return candidates;
244486
- };
244487
- var getSchematicPinPaddingToEdgeTooLargeIssues = (candidates) => candidates.filter((candidate) => exceedsMaxAllowedGap(candidate.measuredPadding, candidate.maxAllowedPadding)).map(createPinPaddingToEdgeIssue);
244488
- var generateSchematicPinPaddingToEdgeTooLargeIssues = (componentPlacements, circuitJson) => getSchematicPinPaddingToEdgeTooLargeIssues(generateSchematicPinPaddingToEdgeCandidates(componentPlacements, circuitJson));
244489
-
244490
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/schematic-box-sizing/too-wide.ts
244491
- var getLabelColumn = (side, ports, sourcePortById) => {
244492
- const labelWidths = ports.filter((port) => port.side_of_component === side).flatMap((port) => port.display_pin_label ? [
244493
- estimateLabelWidth(port.display_pin_label, sourcePortById.get(port.source_port_id))
244494
- ] : []);
244495
- if (labelWidths.length === 0)
244496
- return null;
244497
- return {
244498
- side,
244499
- labelCount: labelWidths.length,
244500
- maxLabelWidth: Math.max(...labelWidths)
244501
- };
244502
- };
244503
- var getInnerLabelEdge = (bounds, labelColumn) => {
244504
- if (labelColumn.side === "left") {
244505
- return bounds.left + PIN_LABEL_EDGE_PADDING + labelColumn.maxLabelWidth;
244506
- }
244507
- return bounds.right - PIN_LABEL_EDGE_PADDING - labelColumn.maxLabelWidth;
244508
- };
244509
- var getSuggestedWidth = (input) => input.currentWidth - input.measuredInnerLabelHorizontalEmptySpace + input.maxAllowedInnerLabelHorizontalEmptySpace;
244510
- var createPinHeaderIssue = (input) => ({
244511
- lineItemType: "PinHeaderSchematicBoxTooWide",
244512
- schematicBox: input.schematicBox,
244513
- measuredInnerLabelHorizontalEmptySpace: input.measuredInnerLabelHorizontalEmptySpace,
244514
- maxAllowedInnerLabelHorizontalEmptySpace: PIN_HEADER_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP,
244515
- suggestedSchWidth: input.suggestedSchWidth,
244516
- message: SCHEMATIC_BOX_TOO_WIDE_MESSAGE
244517
- });
244518
- var createGenericIssue = (input) => ({
244519
- lineItemType: "GenericSchematicBoxTooWide",
244520
- schematicBox: input.schematicBox,
244521
- measuredInnerLabelHorizontalEmptySpace: input.measuredInnerLabelHorizontalEmptySpace,
244522
- maxAllowedInnerLabelHorizontalEmptySpace: GENERIC_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP,
244523
- suggestedSchWidth: input.suggestedSchWidth,
244524
- message: SCHEMATIC_BOX_TOO_WIDE_MESSAGE
244525
- });
244526
- var generateSchematicBoxWidthSizingCandidates = (componentPlacements, circuitJson) => {
244527
- const placementBySchematicComponentId = getPlacementBySchematicComponentId(componentPlacements);
244528
- const sourcePortById = getSourcePortById(circuitJson);
244529
- const sourceComponentById = getSourceComponentById(circuitJson);
244530
- const portsBySchematicComponentId = getPortsBySchematicComponentId(circuitJson, isHorizontalSide);
244531
- const candidates = [];
244532
- for (const [schematicComponentId, ports] of portsBySchematicComponentId) {
244533
- const schematicBox = placementBySchematicComponentId.get(schematicComponentId);
244534
- if (!schematicBox)
244535
- continue;
244536
- const bounds = getCenteredRectBounds(schematicBox);
244537
- const leftLabelColumn = getLabelColumn("left", ports, sourcePortById);
244538
- const rightLabelColumn = getLabelColumn("right", ports, sourcePortById);
244539
- const sourceComponentFtype = getSourceComponentFtype(schematicBox, sourceComponentById);
244540
- if (leftLabelColumn && rightLabelColumn) {
244541
- const measuredInnerLabelHorizontalEmptySpace = getInnerLabelEdge(bounds, rightLabelColumn) - getInnerLabelEdge(bounds, leftLabelColumn);
244542
- candidates.push({
244543
- schematicBox,
244544
- sourceComponentFtype,
244545
- measuredInnerLabelHorizontalEmptySpace
244546
- });
244547
- continue;
245031
+ static issueToString(issue) {
245032
+ const attrs = [];
245033
+ addAttr(attrs, "message", issue.message, { escape: false });
245034
+ addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
245035
+ addAttr(attrs, "pinSide", issue.pinSide);
245036
+ addAttr(attrs, "edgeSide", issue.edgeSide);
245037
+ addAttr(attrs, "pinName", issue.pinName);
245038
+ addAttr(attrs, "measuredPadding", issue.measuredPadding);
245039
+ addAttr(attrs, "maxAllowedPadding", issue.maxAllowedPadding);
245040
+ addAttr(attrs, "excessPadding", issue.excessPadding);
245041
+ addAttr(attrs, "suggestedSchWidth", issue.suggestedSchWidth);
245042
+ addAttr(attrs, "suggestedSchHeight", issue.suggestedSchHeight);
245043
+ return `<SchematicPinPaddingToEdgeTooLarge ${attrs.join(" ")} />`;
245044
+ }
245045
+ isSchematicPort(el3) {
245046
+ return el3.type === "schematic_port";
245047
+ }
245048
+ isSourcePort(el3) {
245049
+ return el3.type === "source_port";
245050
+ }
245051
+ isSchematicComponent(el3) {
245052
+ return el3.type === "schematic_component";
245053
+ }
245054
+ isHorizontalSide(side) {
245055
+ return side === "left" || side === "right";
245056
+ }
245057
+ isVerticalSide(side) {
245058
+ return side === "top" || side === "bottom";
245059
+ }
245060
+ isSchematicSide(side) {
245061
+ return this.isHorizontalSide(side) || this.isVerticalSide(side);
245062
+ }
245063
+ isPinNameLabel(label, sourcePort) {
245064
+ if (!sourcePort)
245065
+ return false;
245066
+ return label === sourcePort.name || label === String(sourcePort.pin_number) || (sourcePort.port_hints ?? []).includes(label);
245067
+ }
245068
+ estimateLabelWidth(label, sourcePort) {
245069
+ return Array.from(label).length * (this.isPinNameLabel(label, sourcePort) ? this.PIN_NAME_CHARACTER_WIDTH : this.FALLBACK_CHARACTER_WIDTH);
245070
+ }
245071
+ exceedsMaxAllowedGap(measured, maxAllowed) {
245072
+ return measured - maxAllowed > this.GAP_COMPARISON_EPSILON;
245073
+ }
245074
+ getCenteredRectBounds(box2) {
245075
+ return {
245076
+ left: box2.schX - box2.width / 2,
245077
+ right: box2.schX + box2.width / 2,
245078
+ top: box2.schY + box2.height / 2,
245079
+ bottom: box2.schY - box2.height / 2
245080
+ };
245081
+ }
245082
+ getSourcePortById(circuitJson) {
245083
+ return new Map(circuitJson.filter((el3) => this.isSourcePort(el3)).map((sp3) => [sp3.source_port_id, sp3]));
245084
+ }
245085
+ getSchematicComponentById(circuitJson) {
245086
+ return new Map(circuitJson.filter((el3) => this.isSchematicComponent(el3)).map((sc2) => [sc2.schematic_component_id, sc2]));
245087
+ }
245088
+ getPlacementBySchematicComponentId(componentPlacements) {
245089
+ return new Map(componentPlacements.filter((p3) => p3.schematicComponentId).map((p3) => [p3.schematicComponentId, p3]));
245090
+ }
245091
+ getPortsBySchematicComponentId(circuitJson) {
245092
+ const map = new Map;
245093
+ for (const port of circuitJson.filter((el3) => this.isSchematicPort(el3))) {
245094
+ if (!port.schematic_component_id)
245095
+ continue;
245096
+ if (!this.isSchematicSide(port.side_of_component))
245097
+ continue;
245098
+ const ports = map.get(port.schematic_component_id);
245099
+ if (ports)
245100
+ ports.push(port);
245101
+ else
245102
+ map.set(port.schematic_component_id, [port]);
244548
245103
  }
244549
- if (leftLabelColumn && leftLabelColumn.labelCount >= 4) {
244550
- const measuredInnerLabelHorizontalEmptySpace = bounds.right - getInnerLabelEdge(bounds, leftLabelColumn);
244551
- candidates.push({
244552
- schematicBox,
244553
- sourceComponentFtype,
244554
- measuredInnerLabelHorizontalEmptySpace
244555
- });
245104
+ return map;
245105
+ }
245106
+ getPinSpacing(schematicBox, schematicComponentById) {
245107
+ if (!schematicBox.schematicComponentId)
245108
+ return null;
245109
+ const sc2 = schematicComponentById.get(schematicBox.schematicComponentId);
245110
+ return typeof sc2?.pin_spacing === "number" ? sc2.pin_spacing : null;
245111
+ }
245112
+ getPinName(port, sourcePortById) {
245113
+ const sp3 = sourcePortById.get(port.source_port_id);
245114
+ if (sp3?.name)
245115
+ return sp3.name;
245116
+ if (port.display_pin_label)
245117
+ return port.display_pin_label;
245118
+ if (sp3?.pin_number !== undefined)
245119
+ return String(sp3.pin_number);
245120
+ return;
245121
+ }
245122
+ getMaxLabelLengthBySide(ports, sourcePortById) {
245123
+ const result = {
245124
+ left: 0,
245125
+ right: 0,
245126
+ top: 0,
245127
+ bottom: 0
245128
+ };
245129
+ for (const port of ports) {
245130
+ if (!this.isSchematicSide(port.side_of_component))
245131
+ continue;
245132
+ if (!port.display_pin_label)
245133
+ continue;
245134
+ result[port.side_of_component] = Math.max(result[port.side_of_component], this.estimateLabelWidth(port.display_pin_label, sourcePortById.get(port.source_port_id)));
244556
245135
  }
244557
- if (rightLabelColumn && rightLabelColumn.labelCount >= 4) {
244558
- const measuredInnerLabelHorizontalEmptySpace = getInnerLabelEdge(bounds, rightLabelColumn) - bounds.left;
244559
- candidates.push({
244560
- schematicBox,
244561
- sourceComponentFtype,
244562
- measuredInnerLabelHorizontalEmptySpace
244563
- });
245136
+ return result;
245137
+ }
245138
+ getOuterPinBySide(edgeSide, ports) {
245139
+ if (ports.length === 0)
245140
+ return null;
245141
+ switch (edgeSide) {
245142
+ case "top":
245143
+ return ports.reduce((a2, b) => b.center.y > a2.center.y ? b : a2);
245144
+ case "bottom":
245145
+ return ports.reduce((a2, b) => b.center.y < a2.center.y ? b : a2);
245146
+ case "left":
245147
+ return ports.reduce((a2, b) => b.center.x < a2.center.x ? b : a2);
245148
+ case "right":
245149
+ return ports.reduce((a2, b) => b.center.x > a2.center.x ? b : a2);
244564
245150
  }
244565
245151
  }
244566
- return candidates;
244567
- };
244568
- var getPinHeaderSchematicBoxTooWideIssues = (candidates) => candidates.filter((candidate) => candidate.sourceComponentFtype === "simple_pin_header").filter((candidate) => exceedsMaxAllowedGap(candidate.measuredInnerLabelHorizontalEmptySpace, PIN_HEADER_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP)).map((candidate) => createPinHeaderIssue({
244569
- schematicBox: candidate.schematicBox,
244570
- measuredInnerLabelHorizontalEmptySpace: candidate.measuredInnerLabelHorizontalEmptySpace,
244571
- suggestedSchWidth: getSuggestedWidth({
244572
- measuredInnerLabelHorizontalEmptySpace: candidate.measuredInnerLabelHorizontalEmptySpace,
244573
- maxAllowedInnerLabelHorizontalEmptySpace: PIN_HEADER_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP,
244574
- currentWidth: candidate.schematicBox.width
244575
- })
244576
- }));
244577
- var getGenericSchematicBoxTooWideIssues = (candidates) => candidates.filter((candidate) => candidate.sourceComponentFtype !== "simple_pin_header").filter((candidate) => exceedsMaxAllowedGap(candidate.measuredInnerLabelHorizontalEmptySpace, GENERIC_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP)).map((candidate) => createGenericIssue({
244578
- schematicBox: candidate.schematicBox,
244579
- measuredInnerLabelHorizontalEmptySpace: candidate.measuredInnerLabelHorizontalEmptySpace,
244580
- suggestedSchWidth: getSuggestedWidth({
244581
- measuredInnerLabelHorizontalEmptySpace: candidate.measuredInnerLabelHorizontalEmptySpace,
244582
- maxAllowedInnerLabelHorizontalEmptySpace: GENERIC_SCHEMATIC_BOX_SIZING_MAX_ALLOWED_GAP,
244583
- currentWidth: candidate.schematicBox.width
244584
- })
244585
- }));
244586
- var generatePinHeaderSchematicBoxTooWideIssues = (componentPlacements, circuitJson) => getPinHeaderSchematicBoxTooWideIssues(generateSchematicBoxWidthSizingCandidates(componentPlacements, circuitJson));
244587
- var generateGenericSchematicBoxTooWideIssues = (componentPlacements, circuitJson) => getGenericSchematicBoxTooWideIssues(generateSchematicBoxWidthSizingCandidates(componentPlacements, circuitJson));
244588
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/schematic-box-overlap.ts
244589
- var getCenteredRectBounds2 = (box2) => {
244590
- const halfWidth = box2.width / 2;
244591
- const halfHeight = box2.height / 2;
244592
- return {
244593
- left: box2.schX - halfWidth,
244594
- right: box2.schX + halfWidth,
244595
- top: box2.schY - halfHeight,
244596
- bottom: box2.schY + halfHeight
244597
- };
244598
- };
244599
- var getComponentOverlap = (firstComponent, secondComponent) => {
244600
- const firstBounds = getCenteredRectBounds2(firstComponent);
244601
- const secondBounds = getCenteredRectBounds2(secondComponent);
244602
- const left = Math.max(firstBounds.left, secondBounds.left);
244603
- const right = Math.min(firstBounds.right, secondBounds.right);
244604
- const top = Math.max(firstBounds.top, secondBounds.top);
244605
- const bottom = Math.min(firstBounds.bottom, secondBounds.bottom);
244606
- const overlapWidth = right - left;
244607
- const overlapHeight = bottom - top;
244608
- if (overlapWidth <= 0 || overlapHeight <= 0) {
244609
- return null;
245152
+ getPinPaddingToEdge(schematicBox, port, edgeSide) {
245153
+ const bounds = this.getCenteredRectBounds(schematicBox);
245154
+ switch (edgeSide) {
245155
+ case "top":
245156
+ return Math.max(0, bounds.top - port.center.y);
245157
+ case "bottom":
245158
+ return Math.max(0, port.center.y - bounds.bottom);
245159
+ case "left":
245160
+ return Math.max(0, port.center.x - bounds.left);
245161
+ case "right":
245162
+ return Math.max(0, bounds.right - port.center.x);
245163
+ }
244610
245164
  }
244611
- return {
244612
- lineItemType: "ComponentOverlap",
244613
- firstComponent,
244614
- secondComponent,
244615
- overlapWidth,
244616
- overlapHeight,
244617
- correctionSuggestions: getOverlapCorrectionSuggestions({
244618
- firstComponent,
244619
- secondComponent,
244620
- overlapWidth,
244621
- overlapHeight
244622
- })
244623
- };
244624
- };
244625
- var getOverlapCorrectionSuggestions = ({
244626
- firstComponent,
244627
- secondComponent,
244628
- overlapWidth,
244629
- overlapHeight
244630
- }) => {
244631
- const firstArea = firstComponent.width * firstComponent.height;
244632
- const secondArea = secondComponent.width * secondComponent.height;
244633
- const targetComponent = firstArea <= secondArea ? firstComponent : secondComponent;
244634
- const otherComponent = targetComponent === firstComponent ? secondComponent : firstComponent;
244635
- const deltaSchX = targetComponent.schX <= otherComponent.schX ? -overlapWidth : overlapWidth;
244636
- const deltaSchY = targetComponent.schY <= otherComponent.schY ? -overlapHeight : overlapHeight;
244637
- return [
244638
- {
244639
- targetComponentName: targetComponent.sourceComponentName,
244640
- deltaSchX,
244641
- deltaSchY: 0,
244642
- newSchX: targetComponent.schX + deltaSchX,
244643
- newSchY: targetComponent.schY
244644
- },
244645
- {
244646
- targetComponentName: targetComponent.sourceComponentName,
244647
- deltaSchX: 0,
244648
- deltaSchY,
244649
- newSchX: targetComponent.schX,
244650
- newSchY: targetComponent.schY + deltaSchY
245165
+ getBoxEdgeSidesForPinSide(pinSide) {
245166
+ return this.isHorizontalSide(pinSide) ? ["top", "bottom"] : ["left", "right"];
245167
+ }
245168
+ hasPinsOnAllSides(portsBySide) {
245169
+ return portsBySide.has("left") && portsBySide.has("right") && portsBySide.has("top") && portsBySide.has("bottom");
245170
+ }
245171
+ getMaxAllowedPinPadding(spacing, edgeSide, maxLabelLengthBySide) {
245172
+ const sides = this.isHorizontalSide(edgeSide) ? ["left", "right"] : ["top", "bottom"];
245173
+ return (maxLabelLengthBySide[sides[0]] + maxLabelLengthBySide[sides[1]] + spacing) / 2;
245174
+ }
245175
+ createIssue(candidate) {
245176
+ const excessPadding = Math.max(0, candidate.measuredPadding - candidate.maxAllowedPadding);
245177
+ const reduction = excessPadding * 2;
245178
+ return {
245179
+ lineItemType: "SchematicPinPaddingToEdgeTooLarge",
245180
+ pinSide: candidate.pinSide,
245181
+ edgeSide: candidate.edgeSide,
245182
+ pinName: candidate.pinName,
245183
+ schematicBox: candidate.schematicBox,
245184
+ measuredPadding: candidate.measuredPadding,
245185
+ maxAllowedPadding: candidate.maxAllowedPadding,
245186
+ excessPadding,
245187
+ suggestedSchWidth: this.isHorizontalSide(candidate.pinSide) ? undefined : Math.max(0, candidate.schematicBox.width - reduction),
245188
+ suggestedSchHeight: this.isHorizontalSide(candidate.pinSide) ? Math.max(0, candidate.schematicBox.height - reduction) : undefined,
245189
+ message: this.isHorizontalSide(candidate.pinSide) ? `${this.MESSAGE} height` : `${this.MESSAGE} width`
245190
+ };
245191
+ }
245192
+ }
245193
+
245194
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/VerboseNetLabelSolver/VerboseNetLabelSolver.ts
245195
+ import { BaseSolver as BaseSolver12 } from "@tscircuit/solver-utils";
245196
+ class VerboseNetLabelSolver extends BaseSolver12 {
245197
+ params;
245198
+ VERBOSE_NET_LABEL_MESSAGE = "Create trace with schDisplayLabel";
245199
+ netLabels;
245200
+ tokenToInvolvedPin;
245201
+ currentIndex = 0;
245202
+ seen = new Set;
245203
+ constructor(params2) {
245204
+ super();
245205
+ this.params = params2;
245206
+ const { circuitJson } = params2.ctx;
245207
+ this.netLabels = circuitJson.filter((el3) => this.isSchematicNetLabel(el3));
245208
+ this.tokenToInvolvedPin = this.buildTokenToInvolvedPinMap(circuitJson);
245209
+ this.solved = this.netLabels.length === 0;
245210
+ }
245211
+ _step() {
245212
+ const label = this.netLabels[this.currentIndex++];
245213
+ if (!label) {
245214
+ this.solved = true;
245215
+ return;
244651
245216
  }
244652
- ];
244653
- };
244654
- var generateSchematicPlacementIssues = (componentPlacements) => {
244655
- const issues = [];
244656
- for (let firstIndex = 0;firstIndex < componentPlacements.length; firstIndex++) {
244657
- for (let secondIndex = firstIndex + 1;secondIndex < componentPlacements.length; secondIndex++) {
244658
- const overlap = getComponentOverlap(componentPlacements[firstIndex], componentPlacements[secondIndex]);
244659
- if (overlap) {
244660
- issues.push(overlap);
245217
+ this.solved = this.currentIndex >= this.netLabels.length;
245218
+ if (!label.text.includes("/") || this.seen.has(label.text))
245219
+ return;
245220
+ this.seen.add(label.text);
245221
+ const issue = {
245222
+ lineItemType: "VerboseSchematicNetLabel",
245223
+ schematicNetLabelId: label.schematic_net_label_id,
245224
+ sourceNetId: label.source_net_id,
245225
+ text: label.text,
245226
+ involvedPins: this.getInvolvedPins(label.text, this.tokenToInvolvedPin),
245227
+ schX: label.center.x,
245228
+ schY: label.center.y,
245229
+ message: this.VERBOSE_NET_LABEL_MESSAGE
245230
+ };
245231
+ this.params.issues.push(issue);
245232
+ }
245233
+ static issueToString(issue) {
245234
+ const attrs = [];
245235
+ addAttr(attrs, "message", issue.message, { escape: false });
245236
+ addAttr(attrs, "text", issue.text);
245237
+ addAttr(attrs, "involvedPins", issue.involvedPins.join(","));
245238
+ addAttr(attrs, "schX", issue.schX);
245239
+ addAttr(attrs, "schY", issue.schY);
245240
+ return `<VerboseSchematicNetLabel ${attrs.join(" ")} />`;
245241
+ }
245242
+ isSchematicNetLabel(el3) {
245243
+ return el3.type === "schematic_net_label";
245244
+ }
245245
+ isSourcePort(el3) {
245246
+ return el3.type === "source_port";
245247
+ }
245248
+ getSourceComponentWithName(el3) {
245249
+ if (el3.type !== "source_component" || !("source_component_id" in el3) || !("name" in el3) || typeof el3.source_component_id !== "string" || typeof el3.name !== "string")
245250
+ return null;
245251
+ return { source_component_id: el3.source_component_id, name: el3.name };
245252
+ }
245253
+ getSourcePortNameCandidates(port) {
245254
+ return [
245255
+ port.most_frequently_referenced_by_name,
245256
+ port.name,
245257
+ ...port.port_hints ?? [],
245258
+ port.pin_number === undefined ? undefined : String(port.pin_number)
245259
+ ].filter((n3) => Boolean(n3));
245260
+ }
245261
+ getBestSourcePortName(port) {
245262
+ return port.most_frequently_referenced_by_name ?? port.name ?? (port.pin_number === undefined ? "" : `pin${port.pin_number}`);
245263
+ }
245264
+ buildTokenToInvolvedPinMap(circuitJson) {
245265
+ const sourceComponentById = new Map(circuitJson.flatMap((el3) => {
245266
+ const sc2 = this.getSourceComponentWithName(el3);
245267
+ return sc2 ? [sc2] : [];
245268
+ }).map((sc2) => [sc2.source_component_id, sc2]));
245269
+ const map = new Map;
245270
+ for (const port of circuitJson.filter((el3) => this.isSourcePort(el3))) {
245271
+ if (!port.source_component_id)
245272
+ continue;
245273
+ const sc2 = sourceComponentById.get(port.source_component_id);
245274
+ if (!sc2?.name)
245275
+ continue;
245276
+ const involvedPin = `${sc2.name}.${this.getBestSourcePortName(port)}`;
245277
+ for (const name of this.getSourcePortNameCandidates(port)) {
245278
+ map.set(`${sc2.name}_${name}`, involvedPin);
244661
245279
  }
244662
245280
  }
245281
+ return map;
245282
+ }
245283
+ getInvolvedPins(text, tokenToInvolvedPin) {
245284
+ const pins = new Set;
245285
+ for (const token of text.split("/")) {
245286
+ const pin = tokenToInvolvedPin.get(token);
245287
+ if (pin)
245288
+ pins.add(pin);
245289
+ }
245290
+ return Array.from(pins);
244663
245291
  }
244664
- return issues;
244665
- };
245292
+ }
244666
245293
 
244667
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/verbose-net-label.ts
244668
- var VERBOSE_NET_LABEL_MESSAGE = "Create trace with schDisplayLabel";
244669
- var isSchematicNetLabel = (element) => element.type === "schematic_net_label";
244670
- var isSourcePort2 = (element) => element.type === "source_port";
244671
- var getSourceComponentWithName = (element) => {
244672
- if (element.type !== "source_component" || !("source_component_id" in element) || !("name" in element) || typeof element.source_component_id !== "string" || typeof element.name !== "string") {
244673
- return null;
245294
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/DiodeResistorAlignmentSolver/DiodeResistorAlignmentSolver.ts
245295
+ import { BaseSolver as BaseSolver13 } from "@tscircuit/solver-utils";
245296
+ class DiodeResistorAlignmentSolver extends BaseSolver13 {
245297
+ static DIODE_FTYPES = new Set(["simple_led", "simple_diode"]);
245298
+ ctx;
245299
+ out;
245300
+ schematicTraces;
245301
+ currentIndex = 0;
245302
+ sourceComponentFtypeById;
245303
+ sourceComponentIdBySourcePortId;
245304
+ schematicPorts;
245305
+ schematicBoxBySourceComponentId;
245306
+ constructor({
245307
+ ctx,
245308
+ issues
245309
+ }) {
245310
+ super();
245311
+ this.ctx = ctx;
245312
+ this.out = issues;
245313
+ const { circuitJson } = ctx;
245314
+ this.sourceComponentFtypeById = this.buildSourceComponentFtypeById(circuitJson);
245315
+ this.sourceComponentIdBySourcePortId = this.buildSourceComponentIdBySourcePortId(circuitJson);
245316
+ this.schematicPorts = circuitJson.filter((el3) => el3.type === "schematic_port");
245317
+ this.schematicBoxBySourceComponentId = this.buildSchematicBoxBySourceComponentId();
245318
+ this.schematicTraces = circuitJson.filter((el3) => el3.type === "schematic_trace");
245319
+ this.solved = this.schematicTraces.length === 0;
244674
245320
  }
244675
- return {
244676
- type: "source_component",
244677
- source_component_id: element.source_component_id,
244678
- name: element.name
244679
- };
244680
- };
244681
- var getSourcePortNameCandidates = (sourcePort) => [
244682
- sourcePort.most_frequently_referenced_by_name,
244683
- sourcePort.name,
244684
- ...sourcePort.port_hints ?? [],
244685
- sourcePort.pin_number === undefined ? undefined : String(sourcePort.pin_number)
244686
- ].filter((name) => Boolean(name));
244687
- var getBestSourcePortName = (sourcePort) => sourcePort.most_frequently_referenced_by_name ?? sourcePort.name ?? (sourcePort.pin_number === undefined ? "" : `pin${sourcePort.pin_number}`);
244688
- var getLabelTokenToInvolvedPinMap = (circuitJson) => {
244689
- const sourceComponentById = new Map(circuitJson.flatMap((element) => {
244690
- const sourceComponent = getSourceComponentWithName(element);
244691
- return sourceComponent ? [sourceComponent] : [];
244692
- }).map((sourceComponent) => [
244693
- sourceComponent.source_component_id,
244694
- sourceComponent
244695
- ]));
244696
- const tokenToInvolvedPin = new Map;
244697
- for (const sourcePort of circuitJson.filter(isSourcePort2)) {
244698
- if (!sourcePort.source_component_id)
244699
- continue;
244700
- const sourceComponent = sourceComponentById.get(sourcePort.source_component_id);
244701
- if (!sourceComponent?.name)
244702
- continue;
244703
- const involvedPin = `${sourceComponent.name}.${getBestSourcePortName(sourcePort)}`;
244704
- for (const portName of getSourcePortNameCandidates(sourcePort)) {
244705
- tokenToInvolvedPin.set(`${sourceComponent.name}_${portName}`, involvedPin);
245321
+ _step() {
245322
+ const trace = this.schematicTraces[this.currentIndex];
245323
+ if (!trace) {
245324
+ this.solved = true;
245325
+ return;
245326
+ }
245327
+ this.currentIndex++;
245328
+ this.solved = this.currentIndex >= this.schematicTraces.length;
245329
+ if (!trace.edges || trace.edges.length === 0)
245330
+ return;
245331
+ const firstEdge = trace.edges[0];
245332
+ const lastEdge = trace.edges[trace.edges.length - 1];
245333
+ if (!firstEdge || !lastEdge)
245334
+ return;
245335
+ const start = firstEdge.from;
245336
+ const end = lastEdge.to;
245337
+ const startSourceCompId = this.findSourceComponentIdNearPoint(start);
245338
+ const endSourceCompId = this.findSourceComponentIdNearPoint(end);
245339
+ if (!startSourceCompId || !endSourceCompId)
245340
+ return;
245341
+ const startFtype = this.sourceComponentFtypeById.get(startSourceCompId);
245342
+ const endFtype = this.sourceComponentFtypeById.get(endSourceCompId);
245343
+ const { DIODE_FTYPES } = DiodeResistorAlignmentSolver;
245344
+ const isDiodeResistorPair = DIODE_FTYPES.has(startFtype) && endFtype === "simple_resistor" || startFtype === "simple_resistor" && DIODE_FTYPES.has(endFtype);
245345
+ if (!isDiodeResistorPair)
245346
+ return;
245347
+ const diodeCompId = DIODE_FTYPES.has(startFtype) ? startSourceCompId : endSourceCompId;
245348
+ const resistorCompId = startFtype === "simple_resistor" ? startSourceCompId : endSourceCompId;
245349
+ const diodeBox = this.schematicBoxBySourceComponentId.get(diodeCompId);
245350
+ const resistorBox = this.schematicBoxBySourceComponentId.get(resistorCompId);
245351
+ if (!diodeBox || !resistorBox)
245352
+ return;
245353
+ const diodePort = this.findNearestPort(DIODE_FTYPES.has(startFtype) ? start : end);
245354
+ const resistorPort = this.findNearestPort(startFtype === "simple_resistor" ? start : end);
245355
+ if (!diodePort?.center || !resistorPort?.center)
245356
+ return;
245357
+ const diodeName = diodeBox.sourceComponentName ?? diodeCompId;
245358
+ const resistorName = resistorBox.sourceComponentName ?? resistorCompId;
245359
+ const diodePin = diodePort?.display_pin_label ?? diodePort?.pin_number?.toString();
245360
+ const resistorPin = resistorPort?.display_pin_label ?? resistorPort?.pin_number?.toString();
245361
+ const diodeFacing = diodePort?.facing_direction;
245362
+ const resistorFacing = resistorPort?.facing_direction;
245363
+ const diodePinDesc = diodePin ? `${diodeName}.${diodePin}` : diodeName;
245364
+ const resistorPinDesc = resistorPin ? `${resistorName}.${resistorPin}` : resistorName;
245365
+ const makeIssue2 = (message) => ({
245366
+ lineItemType: "DiodeResistorNotAligned",
245367
+ diodeSchematicBox: diodeBox,
245368
+ resistorSchematicBox: resistorBox,
245369
+ diodePin,
245370
+ resistorPin,
245371
+ diodePinFacingDirection: diodeFacing,
245372
+ resistorPinFacingDirection: resistorFacing,
245373
+ message
245374
+ });
245375
+ if (!DiodeResistorAlignmentSolver.isCoLinear(diodePort.center, resistorPort.center)) {
245376
+ this.out.push(makeIssue2(`trace has corners — align ${diodeName} and ${resistorName} on same axis and rotate so ${diodePinDesc} faces ${resistorPinDesc}`));
245377
+ return;
245378
+ }
245379
+ if (diodeFacing && resistorFacing && !DiodeResistorAlignmentSolver.pinsFacingEachOther(diodePort.center, diodeFacing, resistorPort.center, resistorFacing)) {
245380
+ this.out.push(makeIssue2(`${diodePinDesc} and ${resistorPinDesc} face away from each other — rotate ${diodeName} so ${diodePinDesc} faces ${resistorPinDesc}`));
244706
245381
  }
244707
245382
  }
244708
- return tokenToInvolvedPin;
244709
- };
244710
- var getInvolvedPins = (netLabelText, tokenToInvolvedPin) => {
244711
- const involvedPins = new Set;
244712
- for (const token of netLabelText.split("/")) {
244713
- const involvedPin = tokenToInvolvedPin.get(token);
244714
- if (involvedPin)
244715
- involvedPins.add(involvedPin);
245383
+ static isCoLinear(a2, b, epsilon = 0.01) {
245384
+ return Math.abs(a2.x - b.x) < epsilon || Math.abs(a2.y - b.y) < epsilon;
244716
245385
  }
244717
- return Array.from(involvedPins);
244718
- };
244719
- var generateVerboseNetLabelIssues = (circuitJson) => {
244720
- const tokenToInvolvedPin = getLabelTokenToInvolvedPinMap(circuitJson);
244721
- const issuesByText = new Map;
244722
- for (const netLabel of circuitJson.filter(isSchematicNetLabel)) {
244723
- if (!netLabel.text.includes("/"))
244724
- continue;
244725
- if (issuesByText.has(netLabel.text))
244726
- continue;
244727
- issuesByText.set(netLabel.text, {
244728
- lineItemType: "VerboseSchematicNetLabel",
244729
- schematicNetLabelId: netLabel.schematic_net_label_id,
244730
- sourceNetId: netLabel.source_net_id,
244731
- text: netLabel.text,
244732
- involvedPins: getInvolvedPins(netLabel.text, tokenToInvolvedPin),
244733
- schX: netLabel.center.x,
244734
- schY: netLabel.center.y,
244735
- message: VERBOSE_NET_LABEL_MESSAGE
244736
- });
245386
+ static pinsFacingEachOther(aCenter, aFacing, bCenter, bFacing) {
245387
+ const dx2 = bCenter.x - aCenter.x;
245388
+ const dy2 = bCenter.y - aCenter.y;
245389
+ const aToward = aFacing === "right" && dx2 > 0 || aFacing === "left" && dx2 < 0 || aFacing === "up" && dy2 > 0 || aFacing === "down" && dy2 < 0;
245390
+ const bToward = bFacing === "right" && dx2 < 0 || bFacing === "left" && dx2 > 0 || bFacing === "up" && dy2 < 0 || bFacing === "down" && dy2 > 0;
245391
+ return aToward && bToward;
244737
245392
  }
244738
- return Array.from(issuesByText.values());
244739
- };
245393
+ static dist(a2, b) {
245394
+ return Math.sqrt((a2.x - b.x) ** 2 + (a2.y - b.y) ** 2);
245395
+ }
245396
+ findNearestPort(point5) {
245397
+ let nearest;
245398
+ let minDist = Infinity;
245399
+ for (const port of this.schematicPorts) {
245400
+ if (!port.center)
245401
+ continue;
245402
+ const d3 = DiodeResistorAlignmentSolver.dist(point5, port.center);
245403
+ if (d3 < minDist) {
245404
+ minDist = d3;
245405
+ nearest = port;
245406
+ }
245407
+ }
245408
+ return nearest;
245409
+ }
245410
+ findSourceComponentIdNearPoint(point5) {
245411
+ const nearest = this.findNearestPort(point5);
245412
+ if (!nearest || !nearest.source_port_id)
245413
+ return;
245414
+ return this.sourceComponentIdBySourcePortId.get(nearest.source_port_id);
245415
+ }
245416
+ buildSourceComponentFtypeById(circuitJson) {
245417
+ const map = new Map;
245418
+ for (const el3 of circuitJson) {
245419
+ if (el3.type === "source_component" && "source_component_id" in el3 && "ftype" in el3 && typeof el3.ftype === "string") {
245420
+ map.set(el3.source_component_id, el3.ftype);
245421
+ }
245422
+ }
245423
+ return map;
245424
+ }
245425
+ buildSourceComponentIdBySourcePortId(circuitJson) {
245426
+ const map = new Map;
245427
+ for (const el3 of circuitJson) {
245428
+ if (el3.type === "source_port" && "source_port_id" in el3 && "source_component_id" in el3 && typeof el3.source_port_id === "string" && typeof el3.source_component_id === "string") {
245429
+ map.set(el3.source_port_id, el3.source_component_id);
245430
+ }
245431
+ }
245432
+ return map;
245433
+ }
245434
+ buildSchematicBoxBySourceComponentId() {
245435
+ const map = new Map;
245436
+ for (const placement of this.ctx.componentPlacements) {
245437
+ if (placement.sourceComponentId) {
245438
+ map.set(placement.sourceComponentId, placement);
245439
+ }
245440
+ }
245441
+ return map;
245442
+ }
245443
+ static issueToString(issue) {
245444
+ const attrs = [];
245445
+ addAttr(attrs, "diodeComponentName", issue.diodeSchematicBox.sourceComponentName);
245446
+ addAttr(attrs, "diodePin", issue.diodePin);
245447
+ addAttr(attrs, "resistorComponentName", issue.resistorSchematicBox.sourceComponentName);
245448
+ addAttr(attrs, "resistorPin", issue.resistorPin);
245449
+ addAttr(attrs, "message", issue.message);
245450
+ return `<DiodeResistorNotAligned ${attrs.join(" ")} />`;
245451
+ }
245452
+ }
244740
245453
 
244741
- // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyzers/analyze-schematic-placement.ts
244742
- var fmtNumber5 = (value) => {
244743
- if (Number.isInteger(value))
244744
- return String(value);
244745
- return value.toFixed(3).replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
244746
- };
244747
- var fmtDelta = (value) => {
244748
- const formattedValue = fmtNumber5(value);
244749
- return value > 0 ? `+${formattedValue}` : formattedValue;
244750
- };
244751
- var isSchematicBox = (element) => element.type === "schematic_box";
244752
- var isSchematicComponent3 = (element) => element.type === "schematic_component";
244753
- var getSourceComponentName = (circuitJson, sourceComponentId) => {
244754
- if (!sourceComponentId)
244755
- return;
244756
- return cju7(circuitJson).source_component.get(sourceComponentId)?.name;
244757
- };
244758
- var schematicComponentToLineItem = (schematicComponent, circuitJson, schematicBox) => ({
244759
- lineItemType: "SchematicBoxPlacement",
244760
- positionAnchor: "center",
244761
- schX: schematicComponent.center.x,
244762
- schY: schematicComponent.center.y,
244763
- width: schematicBox?.width ?? schematicComponent.size.width,
244764
- height: schematicBox?.height ?? schematicComponent.size.height,
244765
- sourceComponentId: schematicComponent.source_component_id,
244766
- sourceComponentName: getSourceComponentName(circuitJson, schematicComponent.source_component_id),
244767
- schematicComponentId: schematicComponent.schematic_component_id,
244768
- schematicSymbolId: schematicBox?.schematic_symbol_id ?? schematicComponent.schematic_symbol_id,
244769
- subcircuitId: schematicComponent.subcircuit_id ?? schematicBox?.subcircuit_id
244770
- });
244771
- var schematicBoxToLineItem = (schematicBox, circuitJson) => ({
244772
- lineItemType: "SchematicBoxPlacement",
244773
- positionAnchor: "center",
244774
- schX: schematicBox.x,
244775
- schY: schematicBox.y,
244776
- width: schematicBox.width,
244777
- height: schematicBox.height,
244778
- ...getSourceComponentMetadata(schematicBox, circuitJson),
244779
- schematicComponentId: schematicBox.schematic_component_id,
244780
- schematicSymbolId: schematicBox.schematic_symbol_id,
244781
- subcircuitId: schematicBox.subcircuit_id
244782
- });
244783
- var getSourceComponentMetadata = (schematicBox, circuitJson) => {
244784
- if (!schematicBox.schematic_component_id)
244785
- return {};
244786
- const circuitJsonUtil = cju7(circuitJson);
244787
- const schematicComponent = circuitJsonUtil.schematic_component.get(schematicBox.schematic_component_id);
244788
- if (!schematicComponent?.source_component_id)
244789
- return {};
244790
- const sourceComponent = circuitJsonUtil.source_component.get(schematicComponent.source_component_id);
244791
- return {
244792
- sourceComponentId: schematicComponent.source_component_id,
244793
- sourceComponentName: sourceComponent?.name
244794
- };
244795
- };
244796
- var addAttr = (attrs, key, value, options) => {
244797
- if (value === undefined)
244798
- return;
244799
- const stringValue = typeof value === "number" ? options?.formatDelta ? fmtDelta(value) : fmtNumber5(value) : options?.escape === false ? value : escapeAttr3(value);
244800
- attrs.push(`${key}="${stringValue}"`);
244801
- };
244802
- var lineItemToString3 = (lineItem) => {
244803
- const attrs = [];
244804
- addAttr(attrs, "componentName", lineItem.sourceComponentName);
244805
- addAttr(attrs, "positionAnchor", lineItem.positionAnchor);
244806
- addAttr(attrs, "schX", lineItem.schX);
244807
- addAttr(attrs, "schY", lineItem.schY);
244808
- addAttr(attrs, "width", lineItem.width);
244809
- addAttr(attrs, "height", lineItem.height);
244810
- return `<SchematicBoxPlacement ${attrs.join(" ")} />`;
244811
- };
244812
- var overlapIssueToString = (issue) => {
244813
- const attrs = [];
244814
- addAttr(attrs, "component1Name", issue.firstComponent.sourceComponentName);
244815
- addAttr(attrs, "component2Name", issue.secondComponent.sourceComponentName);
244816
- addAttr(attrs, "component1SchX", issue.firstComponent.schX);
244817
- addAttr(attrs, "component1SchY", issue.firstComponent.schY);
244818
- addAttr(attrs, "component2SchX", issue.secondComponent.schX);
244819
- addAttr(attrs, "component2SchY", issue.secondComponent.schY);
244820
- addAttr(attrs, "overlapWidth", issue.overlapWidth);
244821
- addAttr(attrs, "overlapHeight", issue.overlapHeight);
244822
- return [
244823
- `<ComponentOverlap ${attrs.join(" ")}>`,
244824
- ...issue.correctionSuggestions.map(correctionSuggestionToString),
244825
- "</ComponentOverlap>"
244826
- ].join(`
244827
- `);
244828
- };
244829
- var capacitorSymbolHorizontalIssueToString = (issue) => {
244830
- const attrs = [];
244831
- addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
244832
- addAttr(attrs, "schX", issue.schematicBox.schX);
244833
- addAttr(attrs, "schY", issue.schematicBox.schY);
244834
- addAttr(attrs, "width", issue.schematicBox.width);
244835
- addAttr(attrs, "height", issue.schematicBox.height);
244836
- return `<CapacitorSymbolHorizontal ${attrs.join(" ")} />`;
244837
- };
244838
- var verboseSchematicNetLabelIssueToString = (issue) => {
244839
- const attrs = [];
244840
- addAttr(attrs, "message", issue.message, { escape: false });
244841
- addAttr(attrs, "text", issue.text);
244842
- addAttr(attrs, "involvedPins", issue.involvedPins.join(","));
244843
- addAttr(attrs, "schX", issue.schX);
244844
- addAttr(attrs, "schY", issue.schY);
244845
- return `<VerboseSchematicNetLabel ${attrs.join(" ")} />`;
244846
- };
244847
- var schematicBoxTooWideIssueToString = (issue) => {
244848
- const attrs = [];
244849
- addAttr(attrs, "message", issue.message, { escape: false });
244850
- addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
244851
- addAttr(attrs, "currentSchWidth", issue.schematicBox.width);
244852
- addAttr(attrs, "measuredInnerLabelHorizontalEmptySpace", issue.measuredInnerLabelHorizontalEmptySpace);
244853
- addAttr(attrs, "maxAllowedInnerLabelHorizontalEmptySpace", issue.maxAllowedInnerLabelHorizontalEmptySpace);
244854
- addAttr(attrs, "suggestedSchWidth", issue.suggestedSchWidth);
244855
- return `<${issue.lineItemType} ${attrs.join(" ")} />`;
244856
- };
244857
- var schematicPinPaddingToEdgeTooLargeIssueToString = (issue) => {
244858
- const attrs = [];
244859
- addAttr(attrs, "message", issue.message, { escape: false });
244860
- addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
244861
- addAttr(attrs, "pinSide", issue.pinSide);
244862
- addAttr(attrs, "edgeSide", issue.edgeSide);
244863
- addAttr(attrs, "pinName", issue.pinName);
244864
- addAttr(attrs, "measuredPadding", issue.measuredPadding);
244865
- addAttr(attrs, "maxAllowedPadding", issue.maxAllowedPadding);
244866
- addAttr(attrs, "excessPadding", issue.excessPadding);
244867
- addAttr(attrs, "suggestedSchWidth", issue.suggestedSchWidth);
244868
- addAttr(attrs, "suggestedSchHeight", issue.suggestedSchHeight);
244869
- return `<SchematicPinPaddingToEdgeTooLarge ${attrs.join(" ")} />`;
244870
- };
244871
- var correctionSuggestionToString = (suggestion) => {
244872
- const attrs = [];
244873
- addAttr(attrs, "target", suggestion.targetComponentName);
244874
- if (suggestion.deltaSchX !== 0) {
244875
- addAttr(attrs, "newSchX", suggestion.newSchX);
244876
- addAttr(attrs, "deltaSchX", suggestion.deltaSchX, { formatDelta: true });
244877
- }
244878
- if (suggestion.deltaSchY !== 0) {
244879
- addAttr(attrs, "newSchY", suggestion.newSchY);
244880
- addAttr(attrs, "deltaSchY", suggestion.deltaSchY, { formatDelta: true });
244881
- }
244882
- return `<OverlapCorrectionSuggestion ${attrs.join(" ")} />`;
244883
- };
244884
- var escapeAttr3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
245454
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPlacementPipeline/SchematicPlacementPipeline.ts
245455
+ class SchematicPlacementPipeline extends BasePipelineSolver2 {
245456
+ ctx;
245457
+ issues = [];
245458
+ pipelineDef = [
245459
+ definePipelineStep3("SchematicBoxOverlapSolver", SchematicBoxOverlapSolver, (p3) => [
245460
+ { ctx: p3.ctx, issues: p3.issues }
245461
+ ]),
245462
+ definePipelineStep3("CapacitorOrientationSolver", CapacitorOrientationSolver, (p3) => [
245463
+ { ctx: p3.ctx, issues: p3.issues }
245464
+ ]),
245465
+ definePipelineStep3("VerboseNetLabelSolver", VerboseNetLabelSolver, (p3) => [
245466
+ { ctx: p3.ctx, issues: p3.issues }
245467
+ ]),
245468
+ definePipelineStep3("SchematicBoxTooWideSolver", SchematicBoxTooWideSolver, (p3) => [
245469
+ { ctx: p3.ctx, issues: p3.issues }
245470
+ ]),
245471
+ definePipelineStep3("SchematicPinPaddingToEdgeSolver", SchematicPinPaddingToEdgeSolver, (p3) => [
245472
+ { ctx: p3.ctx, issues: p3.issues }
245473
+ ]),
245474
+ definePipelineStep3("SchematicBoxInnerLabelCollisionSolver", SchematicBoxInnerLabelCollisionSolver, (p3) => [
245475
+ { ctx: p3.ctx, issues: p3.issues }
245476
+ ]),
245477
+ definePipelineStep3("DiodeResistorAlignmentSolver", DiodeResistorAlignmentSolver, (p3) => [
245478
+ { ctx: p3.ctx, issues: p3.issues }
245479
+ ])
245480
+ ];
245481
+ _setup() {
245482
+ this.ctx = buildSolverContext(this.inputProblem);
245483
+ }
245484
+ getOutput() {
245485
+ return {
245486
+ issues: this.issues,
245487
+ componentPlacements: this.ctx.componentPlacements
245488
+ };
245489
+ }
245490
+ }
244885
245491
 
245492
+ // node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/analyze-schematic-placement.ts
244886
245493
  class SchematicPlacementAnalysis {
244887
245494
  lineItems;
244888
245495
  constructor(lineItems) {
@@ -244894,32 +245501,47 @@ class SchematicPlacementAnalysis {
244894
245501
  getString() {
244895
245502
  return this.toString();
244896
245503
  }
245504
+ schematicBoxPlacementsToString(lineItem) {
245505
+ const attrs = [];
245506
+ addAttr(attrs, "componentName", lineItem.sourceComponentName);
245507
+ addAttr(attrs, "positionAnchor", lineItem.positionAnchor);
245508
+ addAttr(attrs, "schX", lineItem.schX);
245509
+ addAttr(attrs, "schY", lineItem.schY);
245510
+ addAttr(attrs, "width", lineItem.width);
245511
+ addAttr(attrs, "height", lineItem.height);
245512
+ return `<SchematicBoxPlacement ${attrs.join(" ")} />`;
245513
+ }
245514
+ schematicIssuesToString(issue) {
245515
+ switch (issue.lineItemType) {
245516
+ case "ComponentOverlap":
245517
+ return SchematicBoxOverlapSolver.issueToString(issue);
245518
+ case "CapacitorSymbolHorizontal":
245519
+ return CapacitorOrientationSolver.issueToString(issue);
245520
+ case "VerboseSchematicNetLabel":
245521
+ return VerboseNetLabelSolver.issueToString(issue);
245522
+ case "PinHeaderSchematicBoxTooWide":
245523
+ case "GenericSchematicBoxTooWide":
245524
+ return SchematicBoxTooWideSolver.issueToString(issue);
245525
+ case "SchematicBoxInnerLabelCollision":
245526
+ return SchematicBoxInnerLabelCollisionSolver.issueToString(issue);
245527
+ case "SchematicPinPaddingToEdgeTooLarge":
245528
+ return SchematicPinPaddingToEdgeSolver.issueToString(issue);
245529
+ case "DiodeResistorNotAligned":
245530
+ return DiodeResistorAlignmentSolver.issueToString(issue);
245531
+ default:
245532
+ return "";
245533
+ }
245534
+ }
244897
245535
  toString() {
244898
245536
  const schematicBoxPlacements = this.lineItems.filter((lineItem) => lineItem.lineItemType === "SchematicBoxPlacement");
244899
245537
  const issues = this.lineItems.flatMap((lineItem) => lineItem.lineItemType === "SchematicPlacementIssues" ? lineItem.issues : []);
244900
245538
  return [
244901
245539
  "<SchematicBoxPositions>",
244902
- ...schematicBoxPlacements.map(lineItemToString3),
245540
+ ...schematicBoxPlacements.map(this.schematicBoxPlacementsToString),
244903
245541
  "</SchematicBoxPositions>",
244904
245542
  ...issues.length > 0 ? [
244905
245543
  "<SchematicPlacementIssues>",
244906
- ...issues.map((issue) => {
244907
- switch (issue.lineItemType) {
244908
- case "ComponentOverlap":
244909
- return overlapIssueToString(issue);
244910
- case "CapacitorSymbolHorizontal":
244911
- return capacitorSymbolHorizontalIssueToString(issue);
244912
- case "VerboseSchematicNetLabel":
244913
- return verboseSchematicNetLabelIssueToString(issue);
244914
- case "PinHeaderSchematicBoxTooWide":
244915
- case "GenericSchematicBoxTooWide":
244916
- return schematicBoxTooWideIssueToString(issue);
244917
- case "SchematicPinPaddingToEdgeTooLarge":
244918
- return schematicPinPaddingToEdgeTooLargeIssueToString(issue);
244919
- default:
244920
- return "";
244921
- }
244922
- }),
245544
+ ...issues.map(this.schematicIssuesToString),
244923
245545
  "</SchematicPlacementIssues>"
244924
245546
  ] : []
244925
245547
  ].join(`
@@ -244927,24 +245549,14 @@ class SchematicPlacementAnalysis {
244927
245549
  }
244928
245550
  }
244929
245551
  var analyzeSchematicPlacement = (circuitJson) => {
244930
- const schematicBoxes = circuitJson.filter(isSchematicBox);
244931
- const schematicComponentIds = new Set(circuitJson.filter(isSchematicComponent3).map((schematicComponent) => schematicComponent.schematic_component_id));
245552
+ const pipeline = new SchematicPlacementPipeline(circuitJson);
245553
+ pipeline.solve();
245554
+ const { issues, componentPlacements } = pipeline.getOutput();
244932
245555
  const lineItems = [
244933
- ...circuitJson.filter(isSchematicComponent3).map((schematicComponent) => schematicComponentToLineItem(schematicComponent, circuitJson, schematicBoxes.find((schematicBox) => schematicBox.schematic_component_id === schematicComponent.schematic_component_id))),
244934
- ...schematicBoxes.filter((schematicBox) => !schematicBox.schematic_component_id || !schematicComponentIds.has(schematicBox.schematic_component_id)).map((schematicBox) => schematicBoxToLineItem(schematicBox, circuitJson))
244935
- ];
244936
- const issues = [
244937
- ...generateSchematicPlacementIssues(lineItems),
244938
- ...generateCapacitorOrientationIssues(lineItems, circuitJson),
244939
- ...generateVerboseNetLabelIssues(circuitJson),
244940
- ...generatePinHeaderSchematicBoxTooWideIssues(lineItems, circuitJson),
244941
- ...generateGenericSchematicBoxTooWideIssues(lineItems, circuitJson),
244942
- ...generateSchematicPinPaddingToEdgeTooLargeIssues(lineItems, circuitJson)
244943
- ];
244944
- return new SchematicPlacementAnalysis([
244945
- ...lineItems,
245556
+ ...componentPlacements,
244946
245557
  ...issues.length > 0 ? [{ lineItemType: "SchematicPlacementIssues", issues }] : []
244947
- ]);
245558
+ ];
245559
+ return new SchematicPlacementAnalysis(lineItems);
244948
245560
  };
244949
245561
  // cli/check/schematic-placement/register.ts
244950
245562
  var checkSchematicPlacement = async (file) => {