@tscircuit/cli 0.1.2229 → 0.1.2230

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/main.js CHANGED
@@ -154298,7 +154298,7 @@ var import_perfect_cli = __toESM3(require_dist3(), 1);
154298
154298
  // lib/getVersion.ts
154299
154299
  import { createRequire as createRequire2 } from "node:module";
154300
154300
  // package.json
154301
- var version = "0.1.2228";
154301
+ var version = "0.1.2229";
154302
154302
  var package_default = {
154303
154303
  name: "@tscircuit/cli",
154304
154304
  version,
@@ -154326,7 +154326,7 @@ var package_default = {
154326
154326
  "@tscircuit/image-utils": "^0.0.8",
154327
154327
  "@tscircuit/krt-wasm": "^0.1.6",
154328
154328
  "@tscircuit/math-utils": "0.0.36",
154329
- "@tscircuit/props": "^0.0.657",
154329
+ "@tscircuit/props": "^0.0.666",
154330
154330
  "@tscircuit/runframe": "^0.0.2884",
154331
154331
  "@tscircuit/schematic-match-adapt": "^0.0.22",
154332
154332
  "@tscircuit/schematic-trace-solver": "^0.0.204",
@@ -154367,7 +154367,7 @@ var package_default = {
154367
154367
  debug: "^4.4.0",
154368
154368
  delay: "^6.0.0",
154369
154369
  "dsn-converter": "^0.0.90",
154370
- easyeda: "^0.0.357",
154370
+ easyeda: "^0.0.366",
154371
154371
  "fuse.js": "^7.1.0",
154372
154372
  "get-port": "^7.1.0",
154373
154373
  globby: "^14.1.0",
@@ -365015,6 +365015,208 @@ var transformPCBElements2 = (elms, matrix) => {
365015
365015
  }
365016
365016
  return transformedElms;
365017
365017
  };
365018
+ var mergeBounds4 = (currentBounds, nextBounds) => ({
365019
+ minX: Math.min(currentBounds.minX, nextBounds.minX),
365020
+ minY: Math.min(currentBounds.minY, nextBounds.minY),
365021
+ maxX: Math.max(currentBounds.maxX, nextBounds.maxX),
365022
+ maxY: Math.max(currentBounds.maxY, nextBounds.maxY)
365023
+ });
365024
+ var getCircleBounds2 = (x, y, diameter) => {
365025
+ const radius = diameter / 2;
365026
+ return {
365027
+ minX: x - radius,
365028
+ minY: y - radius,
365029
+ maxX: x + radius,
365030
+ maxY: y + radius
365031
+ };
365032
+ };
365033
+ var getRotatedRectBounds2 = (x, y, width, height, rotationDegrees) => {
365034
+ const halfWidth = width / 2;
365035
+ const halfHeight = height / 2;
365036
+ const theta = rotationDegrees * Math.PI / 180;
365037
+ const cosTheta = Math.cos(theta);
365038
+ const sinTheta = Math.sin(theta);
365039
+ const corners = [
365040
+ { x: -halfWidth, y: -halfHeight },
365041
+ { x: halfWidth, y: -halfHeight },
365042
+ { x: halfWidth, y: halfHeight },
365043
+ { x: -halfWidth, y: halfHeight }
365044
+ ].map((corner) => ({
365045
+ x: x + corner.x * cosTheta - corner.y * sinTheta,
365046
+ y: y + corner.x * sinTheta + corner.y * cosTheta
365047
+ }));
365048
+ return {
365049
+ minX: Math.min(...corners.map((corner) => corner.x)),
365050
+ minY: Math.min(...corners.map((corner) => corner.y)),
365051
+ maxX: Math.max(...corners.map((corner) => corner.x)),
365052
+ maxY: Math.max(...corners.map((corner) => corner.y))
365053
+ };
365054
+ };
365055
+ var getRotatedOvalBounds = (x, y, width, height, rotationDegrees) => {
365056
+ const radiusX = width / 2;
365057
+ const radiusY = height / 2;
365058
+ const theta = rotationDegrees * Math.PI / 180;
365059
+ const cosTheta = Math.cos(theta);
365060
+ const sinTheta = Math.sin(theta);
365061
+ const halfWidth = Math.hypot(radiusX * cosTheta, radiusY * sinTheta);
365062
+ const halfHeight = Math.hypot(radiusX * sinTheta, radiusY * cosTheta);
365063
+ return {
365064
+ minX: x - halfWidth,
365065
+ minY: y - halfHeight,
365066
+ maxX: x + halfWidth,
365067
+ maxY: y + halfHeight
365068
+ };
365069
+ };
365070
+ var getRotatedPillBounds = (x, y, width, height, rotationDegrees) => {
365071
+ const radius = Math.min(width, height) / 2;
365072
+ const halfLineLength = Math.max(width, height) / 2 - radius;
365073
+ const theta = rotationDegrees * Math.PI / 180;
365074
+ const axis = width >= height ? { x: halfLineLength, y: 0 } : { x: 0, y: halfLineLength };
365075
+ const rotatedAxis = {
365076
+ x: axis.x * Math.cos(theta) - axis.y * Math.sin(theta),
365077
+ y: axis.x * Math.sin(theta) + axis.y * Math.cos(theta)
365078
+ };
365079
+ const halfWidth = Math.abs(rotatedAxis.x) + radius;
365080
+ const halfHeight = Math.abs(rotatedAxis.y) + radius;
365081
+ return {
365082
+ minX: x - halfWidth,
365083
+ minY: y - halfHeight,
365084
+ maxX: x + halfWidth,
365085
+ maxY: y + halfHeight
365086
+ };
365087
+ };
365088
+ var getBoundsFromPoints6 = (points) => {
365089
+ if (points.length === 0)
365090
+ return null;
365091
+ return {
365092
+ minX: Math.min(...points.map((point2) => point2.x)),
365093
+ minY: Math.min(...points.map((point2) => point2.y)),
365094
+ maxX: Math.max(...points.map((point2) => point2.x)),
365095
+ maxY: Math.max(...points.map((point2) => point2.y))
365096
+ };
365097
+ };
365098
+ var getRoutePoints = (route) => {
365099
+ if (!Array.isArray(route))
365100
+ return [];
365101
+ return route.flatMap((point2) => {
365102
+ if (!point2 || typeof point2 !== "object")
365103
+ return [];
365104
+ if ("x" in point2 && "y" in point2 && typeof point2.x === "number" && typeof point2.y === "number") {
365105
+ return [{ x: point2.x, y: point2.y }];
365106
+ }
365107
+ if ("start" in point2 && "end" in point2) {
365108
+ const positions = [point2.start, point2.end];
365109
+ return positions.filter((position2) => Boolean(position2 && typeof position2 === "object" && "x" in position2 && "y" in position2 && typeof position2.x === "number" && typeof position2.y === "number"));
365110
+ }
365111
+ return [];
365112
+ });
365113
+ };
365114
+ var getPcbElementBounds = (elm) => {
365115
+ if (!elm.type.startsWith("pcb_"))
365116
+ return null;
365117
+ if (elm.type === "pcb_smtpad" && elm.shape === "polygon" && Array.isArray(elm.points)) {
365118
+ return getBoundsFromPoints6(elm.points);
365119
+ }
365120
+ if (elm.type === "pcb_hole" && elm.hole_shape === "circle") {
365121
+ return getCircleBounds2(elm.x, elm.y, elm.hole_diameter);
365122
+ }
365123
+ if (elm.type === "pcb_plated_hole") {
365124
+ let platedHoleBounds;
365125
+ if ("outer_diameter" in elm && typeof elm.outer_diameter === "number") {
365126
+ platedHoleBounds = getCircleBounds2(elm.x, elm.y, elm.outer_diameter);
365127
+ } else if ("hole_diameter" in elm && typeof elm.hole_diameter === "number") {
365128
+ platedHoleBounds = getCircleBounds2(elm.x, elm.y, elm.hole_diameter);
365129
+ }
365130
+ if ((elm.shape === "oval" || elm.shape === "pill") && typeof elm.outer_width === "number" && typeof elm.outer_height === "number") {
365131
+ const getOuterBounds = elm.shape === "pill" ? getRotatedPillBounds : getRotatedOvalBounds;
365132
+ platedHoleBounds = getOuterBounds(elm.x, elm.y, elm.outer_width, elm.outer_height, elm.ccw_rotation ?? 0);
365133
+ }
365134
+ if ("rect_pad_width" in elm && typeof elm.rect_pad_width === "number" && "rect_pad_height" in elm && typeof elm.rect_pad_height === "number") {
365135
+ const rectBounds = getRotatedRectBounds2(elm.x, elm.y, elm.rect_pad_width, elm.rect_pad_height, "rect_ccw_rotation" in elm ? elm.rect_ccw_rotation ?? 0 : 0);
365136
+ platedHoleBounds = platedHoleBounds ? mergeBounds4(platedHoleBounds, rectBounds) : rectBounds;
365137
+ }
365138
+ if ("hole_diameter" in elm && typeof elm.hole_diameter === "number") {
365139
+ const drillBounds = getCircleBounds2(elm.x + ("hole_offset_x" in elm ? elm.hole_offset_x ?? 0 : 0), elm.y + ("hole_offset_y" in elm ? elm.hole_offset_y ?? 0 : 0), elm.hole_diameter);
365140
+ platedHoleBounds = platedHoleBounds ? mergeBounds4(platedHoleBounds, drillBounds) : drillBounds;
365141
+ }
365142
+ if (platedHoleBounds)
365143
+ return platedHoleBounds;
365144
+ }
365145
+ const elementRecord = elm;
365146
+ const routeBounds = getBoundsFromPoints6(getRoutePoints(elementRecord.route));
365147
+ if (routeBounds)
365148
+ return routeBounds;
365149
+ const outlineBounds = getBoundsFromPoints6(getRoutePoints(elementRecord.outline));
365150
+ if (outlineBounds)
365151
+ return outlineBounds;
365152
+ const pointsBounds = getBoundsFromPoints6(getRoutePoints(elementRecord.points));
365153
+ if (pointsBounds)
365154
+ return pointsBounds;
365155
+ let centerX;
365156
+ let centerY;
365157
+ let width;
365158
+ let height;
365159
+ if ("x" in elm && "y" in elm) {
365160
+ centerX = Number(elm.x);
365161
+ centerY = Number(elm.y);
365162
+ }
365163
+ if ("outer_diameter" in elm) {
365164
+ width = Number(elm.outer_diameter);
365165
+ height = Number(elm.outer_diameter);
365166
+ }
365167
+ if ("width" in elm) {
365168
+ width = Number(elm.width);
365169
+ }
365170
+ if ("height" in elm) {
365171
+ height = Number(elm.height);
365172
+ }
365173
+ if ("center" in elm && elm.center && typeof elm.center === "object" && "x" in elm.center && "y" in elm.center) {
365174
+ centerX = Number(elm.center.x);
365175
+ centerY = Number(elm.center.y);
365176
+ }
365177
+ let rotation2 = 0;
365178
+ if ("rotation" in elm && typeof elm.rotation === "number") {
365179
+ rotation2 = elm.rotation;
365180
+ }
365181
+ if ("ccw_rotation" in elm && typeof elm.ccw_rotation === "number") {
365182
+ rotation2 = elm.ccw_rotation;
365183
+ }
365184
+ if (centerX !== undefined && centerY !== undefined) {
365185
+ if (width !== undefined && height !== undefined) {
365186
+ return rotation2 ? getRotatedRectBounds2(centerX, centerY, width, height, rotation2) : {
365187
+ minX: centerX - width / 2,
365188
+ minY: centerY - height / 2,
365189
+ maxX: centerX + width / 2,
365190
+ maxY: centerY + height / 2
365191
+ };
365192
+ }
365193
+ if ("radius" in elm && typeof elm.radius === "number") {
365194
+ return getCircleBounds2(centerX, centerY, elm.radius * 2);
365195
+ }
365196
+ return { minX: centerX, minY: centerY, maxX: centerX, maxY: centerY };
365197
+ }
365198
+ const anchoredPoint = [elementRecord.anchor_position, elementRecord.position].filter((position2) => Boolean(position2 && typeof position2 === "object" && "x" in position2 && "y" in position2 && typeof position2.x === "number" && typeof position2.y === "number")).at(0);
365199
+ return anchoredPoint ? {
365200
+ minX: anchoredPoint.x,
365201
+ minY: anchoredPoint.y,
365202
+ maxX: anchoredPoint.x,
365203
+ maxY: anchoredPoint.y
365204
+ } : null;
365205
+ };
365206
+ var getBoundsOfPcbElements3 = (elements) => {
365207
+ let bounds = {
365208
+ minX: Number.POSITIVE_INFINITY,
365209
+ minY: Number.POSITIVE_INFINITY,
365210
+ maxX: Number.NEGATIVE_INFINITY,
365211
+ maxY: Number.NEGATIVE_INFINITY
365212
+ };
365213
+ for (const element of elements) {
365214
+ const elementBounds = getPcbElementBounds(element);
365215
+ if (elementBounds)
365216
+ bounds = mergeBounds4(bounds, elementBounds);
365217
+ }
365218
+ return bounds;
365219
+ };
365018
365220
  function stringHash3(str) {
365019
365221
  let hash = 0;
365020
365222
  if (str.length == 0)
@@ -365226,6 +365428,116 @@ var PIN1_LOCATION_PARTS = {
365226
365428
  bottomside_right: { side: "bottomside", alignment: "right" }
365227
365429
  };
365228
365430
  var PIN1_LOCATIONS2 = Object.keys(PIN1_LOCATION_PARTS);
365431
+ var normalizeActiveLowPinLabel = (label) => {
365432
+ const hasActiveLowMarker = label.startsWith("#") || label.endsWith("#");
365433
+ if (!hasActiveLowMarker)
365434
+ return label;
365435
+ const activeLowLabel = label.replace(/^#/, "").replace(/#$/, "");
365436
+ if (activeLowLabel.length === 0)
365437
+ return label;
365438
+ if (activeLowLabel.startsWith("N_"))
365439
+ return activeLowLabel;
365440
+ return `N_${activeLowLabel}`;
365441
+ };
365442
+ var normalizePinLabels = (inputPinLabels) => {
365443
+ const normalizedInputPinLabels = inputPinLabels.map((labels) => labels.map(normalizeActiveLowPinLabel));
365444
+ const uniqueInputPinLabels = normalizedInputPinLabels.map((labels) => [
365445
+ ...new Set(labels)
365446
+ ]);
365447
+ const result = uniqueInputPinLabels.map(() => []);
365448
+ const desiredNumbers = uniqueInputPinLabels.map(() => null);
365449
+ for (let i = 0;i < uniqueInputPinLabels.length; i++) {
365450
+ for (const label of uniqueInputPinLabels[i]) {
365451
+ if (/^\d+$/.test(label)) {
365452
+ desiredNumbers[i] = Number.parseInt(label);
365453
+ break;
365454
+ }
365455
+ }
365456
+ }
365457
+ let highestPinNumber = 0;
365458
+ const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
365459
+ for (let i = 0;i < desiredNumbers.length; i++) {
365460
+ const desiredNumber = desiredNumbers[i];
365461
+ if (desiredNumber === null || desiredNumber < 1)
365462
+ continue;
365463
+ if (!acceptedDesiredNumbers.has(desiredNumber)) {
365464
+ acceptedDesiredNumbers.add(desiredNumber);
365465
+ result[i].push(`pin${desiredNumber}`);
365466
+ highestPinNumber = Math.max(highestPinNumber, desiredNumber);
365467
+ continue;
365468
+ }
365469
+ let existingAltCount = 0;
365470
+ for (const label of result[i]) {
365471
+ if (label.startsWith(`pin${desiredNumber}_alt`)) {
365472
+ existingAltCount += 1;
365473
+ }
365474
+ }
365475
+ result[i].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
365476
+ }
365477
+ for (let i = 0;i < result.length; i++) {
365478
+ const firstLabel = result[i][0];
365479
+ if (firstLabel?.includes("_alt")) {
365480
+ highestPinNumber += 1;
365481
+ result[i].unshift(`pin${highestPinNumber}`);
365482
+ }
365483
+ }
365484
+ for (let i = 0;i < result.length; i++) {
365485
+ if (result[i].length === 0) {
365486
+ highestPinNumber += 1;
365487
+ result[i].push(`pin${highestPinNumber}`);
365488
+ }
365489
+ }
365490
+ const totalLabelCounts = {};
365491
+ for (const inputLabels of uniqueInputPinLabels) {
365492
+ for (const label of inputLabels) {
365493
+ if (/^\d+$/.test(label))
365494
+ continue;
365495
+ totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
365496
+ }
365497
+ }
365498
+ const incrementalLabelCounts = {};
365499
+ for (let i = 0;i < uniqueInputPinLabels.length; i++) {
365500
+ for (const label of uniqueInputPinLabels[i]) {
365501
+ if (/^\d+$/.test(label))
365502
+ continue;
365503
+ if (totalLabelCounts[label] === 1) {
365504
+ result[i].push(label);
365505
+ } else {
365506
+ incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
365507
+ result[i].push(`${label}${incrementalLabelCounts[label]}`);
365508
+ }
365509
+ }
365510
+ }
365511
+ return result;
365512
+ };
365513
+ var normalizeEasyEdaPinLabel = (label) => {
365514
+ if (label.endsWith("+"))
365515
+ label = `${label.slice(0, -1)}_POS`;
365516
+ if (/[-–−]$/.test(label))
365517
+ label = `${label.slice(0, -1)}_NEG`;
365518
+ label = normalizeActiveLowPinLabel(label);
365519
+ if (/^\+\d+(?:\.\d+)?V$/i.test(label))
365520
+ label = `V${label.slice(1, -1)}`;
365521
+ if (label.startsWith("+"))
365522
+ label = `${label.slice(1)}_POS`;
365523
+ if (/^[-–−]/.test(label))
365524
+ label = `${label.slice(1)}_NEG`;
365525
+ return label;
365526
+ };
365527
+ var getEasyEdaPinAliases = (label) => {
365528
+ label = label.replace(/&#(x[0-9a-f]+|[0-9]+);/gi, (entity, code) => {
365529
+ let codePoint = Number(code);
365530
+ if (/^x/i.test(code))
365531
+ codePoint = Number.parseInt(code.slice(1), 16);
365532
+ const maximumUnicodeCodePoint = 1114111;
365533
+ if (codePoint > maximumUnicodeCodePoint)
365534
+ return entity;
365535
+ return String.fromCodePoint(codePoint);
365536
+ });
365537
+ if (label.includes("/") && !/[a-zA-Z0-9]/.test(label))
365538
+ return [];
365539
+ return label.split("/").map((alias) => normalizeEasyEdaPinLabel(alias.trim()).replace(/[`′]/g, "_PRIME").replace(/^[()]+|[()]+$/g, "").replace(/[^a-zA-Z0-9_]/g, "_")).filter((alias) => /[a-zA-Z0-9]/.test(alias));
365540
+ };
365229
365541
  function orientation3(p, q, r) {
365230
365542
  const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
365231
365543
  if (val === 0)
@@ -365253,7 +365565,7 @@ var getBoundsCenter3 = (bounds) => ({
365253
365565
  x: (bounds.minX + bounds.maxX) / 2,
365254
365566
  y: (bounds.minY + bounds.maxY) / 2
365255
365567
  });
365256
- var getBoundsFromPoints6 = (points) => {
365568
+ var getBoundsFromPoints23 = (points) => {
365257
365569
  if (points.length === 0) {
365258
365570
  return null;
365259
365571
  }
@@ -365500,96 +365812,6 @@ var getPolarizedPinMetadata = (pinLabels) => {
365500
365812
  pinLabels: Object.fromEntries(polarizedPinEntries)
365501
365813
  };
365502
365814
  };
365503
- var normalizeActiveLowPinLabel = (label) => {
365504
- const hasActiveLowMarker = label.startsWith("#") || label.endsWith("#");
365505
- if (!hasActiveLowMarker)
365506
- return label;
365507
- const activeLowLabel = label.replace(/^#/, "").replace(/#$/, "");
365508
- if (activeLowLabel.length === 0)
365509
- return label;
365510
- if (activeLowLabel.startsWith("N_"))
365511
- return activeLowLabel;
365512
- return `N_${activeLowLabel}`;
365513
- };
365514
- var normalizePinLabels = (inputPinLabels) => {
365515
- const normalizedInputPinLabels = inputPinLabels.map((labels) => labels.map(normalizeActiveLowPinLabel));
365516
- const uniqueInputPinLabels = normalizedInputPinLabels.map((labels) => [
365517
- ...new Set(labels)
365518
- ]);
365519
- const result = uniqueInputPinLabels.map(() => []);
365520
- const desiredNumbers = uniqueInputPinLabels.map(() => null);
365521
- for (let i = 0;i < uniqueInputPinLabels.length; i++) {
365522
- for (const label of uniqueInputPinLabels[i]) {
365523
- if (/^\d+$/.test(label)) {
365524
- desiredNumbers[i] = Number.parseInt(label);
365525
- break;
365526
- }
365527
- }
365528
- }
365529
- let highestPinNumber = 0;
365530
- const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
365531
- for (let i = 0;i < desiredNumbers.length; i++) {
365532
- const desiredNumber = desiredNumbers[i];
365533
- if (desiredNumber === null || desiredNumber < 1)
365534
- continue;
365535
- if (!acceptedDesiredNumbers.has(desiredNumber)) {
365536
- acceptedDesiredNumbers.add(desiredNumber);
365537
- result[i].push(`pin${desiredNumber}`);
365538
- highestPinNumber = Math.max(highestPinNumber, desiredNumber);
365539
- continue;
365540
- }
365541
- let existingAltCount = 0;
365542
- for (const label of result[i]) {
365543
- if (label.startsWith(`pin${desiredNumber}_alt`)) {
365544
- existingAltCount += 1;
365545
- }
365546
- }
365547
- result[i].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
365548
- }
365549
- for (let i = 0;i < result.length; i++) {
365550
- const firstLabel = result[i][0];
365551
- if (firstLabel?.includes("_alt")) {
365552
- highestPinNumber += 1;
365553
- result[i].unshift(`pin${highestPinNumber}`);
365554
- }
365555
- }
365556
- for (let i = 0;i < result.length; i++) {
365557
- if (result[i].length === 0) {
365558
- highestPinNumber += 1;
365559
- result[i].push(`pin${highestPinNumber}`);
365560
- }
365561
- }
365562
- const totalLabelCounts = {};
365563
- for (const inputLabels of uniqueInputPinLabels) {
365564
- for (const label of inputLabels) {
365565
- if (/^\d+$/.test(label))
365566
- continue;
365567
- totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
365568
- }
365569
- }
365570
- const incrementalLabelCounts = {};
365571
- for (let i = 0;i < uniqueInputPinLabels.length; i++) {
365572
- for (const label of uniqueInputPinLabels[i]) {
365573
- if (/^\d+$/.test(label))
365574
- continue;
365575
- if (totalLabelCounts[label] === 1) {
365576
- result[i].push(label);
365577
- } else {
365578
- incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
365579
- result[i].push(`${label}${incrementalLabelCounts[label]}`);
365580
- }
365581
- }
365582
- }
365583
- return result;
365584
- };
365585
- var normalizeSymbolName = (name) => {
365586
- const trimmedName = name.trim();
365587
- if (trimmedName === "+")
365588
- return "_POS";
365589
- if (trimmedName === "-")
365590
- return "_NEG";
365591
- return trimmedName.replace(/(?<=[A-Za-z0-9])-(?=[A-Za-z0-9])/g, "_");
365592
- };
365593
365815
  var categoryValueContainsDiode = (value) => {
365594
365816
  if (typeof value === "string") {
365595
365817
  return /(^|[^a-z])diodes?([^a-z]|$)/i.test(value);
@@ -365683,7 +365905,7 @@ var getEasyEdaModelOriginOnBoardMm = ({
365683
365905
  }
365684
365906
  let modelOriginMm = null;
365685
365907
  if (points.length > 0) {
365686
- const bounds = getBoundsFromPoints6(points);
365908
+ const bounds = getBoundsFromPoints23(points);
365687
365909
  modelOriginMm = bounds ? getBoundsCenter3(bounds) : null;
365688
365910
  } else {
365689
365911
  const [originX, originY] = String(svgNode.svgData.attrs?.c_origin ?? "0,0").split(",").map((value) => Number(value.trim()));
@@ -365772,6 +365994,45 @@ var parseCadOffsetsFromSvgNode = (svgNode) => {
365772
365994
  })()
365773
365995
  };
365774
365996
  };
365997
+ var getCadModelOutlineBounds = (svgNode) => {
365998
+ const points = [];
365999
+ for (const childNode of svgNode?.svgData.childNodes ?? []) {
366000
+ if (typeof childNode !== "object" || childNode === null)
366001
+ continue;
366002
+ const attrs = childNode.attrs;
366003
+ if (typeof attrs !== "object" || attrs === null)
366004
+ continue;
366005
+ const rawPoints = attrs.points;
366006
+ if (typeof rawPoints !== "string")
366007
+ continue;
366008
+ const coordinates = rawPoints.trim().split(/\s+/).map(Number);
366009
+ for (let index = 0;index + 1 < coordinates.length; index += 2) {
366010
+ const x = coordinates[index];
366011
+ const y = coordinates[index + 1];
366012
+ if (!Number.isFinite(x) || !Number.isFinite(y))
366013
+ continue;
366014
+ points.push({ x: milx10(x), y: milx10(y) });
366015
+ }
366016
+ }
366017
+ if (points.length === 0)
366018
+ return;
366019
+ return {
366020
+ minX: Math.min(...points.map((point2) => point2.x)),
366021
+ minY: Math.min(...points.map((point2) => point2.y)),
366022
+ maxX: Math.max(...points.map((point2) => point2.x)),
366023
+ maxY: Math.max(...points.map((point2) => point2.y))
366024
+ };
366025
+ };
366026
+ var unionBounds2 = (first, second) => {
366027
+ if (!second)
366028
+ return first;
366029
+ return {
366030
+ minX: Math.min(first.minX, second.minX),
366031
+ minY: Math.min(first.minY, second.minY),
366032
+ maxX: Math.max(first.maxX, second.maxX),
366033
+ maxY: Math.max(first.maxY, second.maxY)
366034
+ };
366035
+ };
365775
366036
  var readModelHeightMm = (raw) => {
365776
366037
  const fallback = 3.5;
365777
366038
  if (raw == null)
@@ -366012,13 +366273,11 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
366012
366273
  const pads = easyEdaJson.packageDetail.dataStr.shape.filter((shape) => shape.type === "PAD");
366013
366274
  const pins = easyEdaJson.dataStr.shape.filter((shape) => shape.type === "PIN");
366014
366275
  const pinLabelSets = pads.map((pad) => {
366015
- const labels = [];
366016
- if (pad.number)
366017
- labels.push(pad.number.toString());
366276
+ const padAliases = pad.number ? getEasyEdaPinAliases(pad.number.toString()) : [];
366018
366277
  const pin = pins.find((p) => p.pinNumber === pad.number);
366019
- if (pin)
366020
- labels.push(normalizeSymbolName(pin.label));
366021
- return labels;
366278
+ const schematicAliases = pin ? getEasyEdaPinAliases(pin.label) : [];
366279
+ const hasNamedSchematicAlias = schematicAliases.some((alias) => !/^\d+$/.test(alias));
366280
+ return hasNamedSchematicAlias ? [...schematicAliases, ...padAliases] : [...padAliases, ...schematicAliases];
366022
366281
  });
366023
366282
  const padNumberKeys = pads.map((pad, index) => {
366024
366283
  const padNumber = String(pad.number ?? "").trim();
@@ -366308,16 +366567,26 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
366308
366567
  model_step_url: stepFileUrl
366309
366568
  }));
366310
366569
  }
366311
- const hasExplicitCourtyard = circuitElements.some((e) => e.type === "pcb_courtyard_outline");
366570
+ const hasExplicitCourtyard = circuitElements.some((e) => e.type === "pcb_courtyard_outline" || e.type === "pcb_courtyard_rect");
366312
366571
  if (!hasExplicitCourtyard) {
366313
366572
  const bbox = easyEdaJson.packageDetail.dataStr.BBox;
366314
- if (bbox) {
366573
+ const modelOutlineBounds = getCadModelOutlineBounds(svgNode);
366574
+ const packageElements = circuitElements.filter((element) => element.type === "pcb_smtpad" || element.type === "pcb_plated_hole" || element.type === "pcb_hole" || element.type === "pcb_via");
366575
+ const packageElementBounds = packageElements.length > 0 ? getBoundsOfPcbElements3(packageElements) : undefined;
366576
+ const fallbackBounds = bbox ? {
366577
+ minX: milx10(bbox.x),
366578
+ minY: milx10(bbox.y),
366579
+ maxX: milx10(bbox.x + bbox.width),
366580
+ maxY: milx10(bbox.y + bbox.height)
366581
+ } : undefined;
366582
+ const courtyardBounds = modelOutlineBounds ? unionBounds2(modelOutlineBounds, packageElementBounds) : fallbackBounds;
366583
+ if (courtyardBounds) {
366315
366584
  const strokeWidth = 0.05;
366316
366585
  const margin = 0.25;
366317
- const x1 = milx10(bbox.x) - margin;
366318
- const y1 = milx10(bbox.y) - margin;
366319
- const x2 = milx10(bbox.x + bbox.width) + margin;
366320
- const y2 = milx10(bbox.y + bbox.height) + margin;
366586
+ const x1 = courtyardBounds.minX - margin;
366587
+ const y1 = courtyardBounds.minY - margin;
366588
+ const x2 = courtyardBounds.maxX + margin;
366589
+ const y2 = courtyardBounds.maxY + margin;
366321
366590
  circuitElements.push(pcb_courtyard_outline2.parse({
366322
366591
  type: "pcb_courtyard_outline",
366323
366592
  pcb_courtyard_outline_id: `pcb_courtyard_outline_${easyEdaJson.lcsc.number}_1`,
@@ -366848,19 +367117,10 @@ var PinShapeOutputSchema = external_exports2.object({
366848
367117
  var parsePin = (pinString) => {
366849
367118
  const parts = pinString.split("~");
366850
367119
  const [, visibility, , pinNumber, x, y, rotation2, id] = parts;
366851
- const nameMatch = pinString.match(/~([\w+#-]+)~(start|end)~/);
366852
- let label = nameMatch ? nameMatch[1] : "";
366853
- if (label.endsWith("+"))
366854
- label = `${label.slice(0, -1)}_POS`;
366855
- if (label.endsWith("-"))
366856
- label = `${label.slice(0, -1)}_NEG`;
366857
- label = normalizeActiveLowPinLabel(label);
366858
- if (/^\+\d+(?:\.\d+)?V$/i.test(label))
366859
- label = `V${label.slice(1, -1)}`;
366860
- if (label.startsWith("+"))
366861
- label = `${label.slice(1)}_POS`;
366862
- if (label.startsWith("-"))
366863
- label = `${label.slice(1)}_NEG`;
367120
+ const pinNameSection = pinString.split("^^")[3];
367121
+ let label = pinNameSection?.split("~")[4] ?? "";
367122
+ if (!label.includes("/"))
367123
+ label = normalizeEasyEdaPinLabel(label);
366864
367124
  const colorMatch = pinString.match(/#[0-9A-F]{6}/);
366865
367125
  const labelColor = colorMatch ? colorMatch[0] : "";
366866
367126
  const path = pinString.split("^^")[2]?.split("~")[0] ?? "";
@@ -367350,6 +367610,14 @@ var getEasyEdaCadModelPlacement = async (easyEdaJson, { fetch: fetch2 = globalTh
367350
367610
  placementCache.set(cacheKey, placementPromise);
367351
367611
  return placementPromise;
367352
367612
  };
367613
+ var normalizeSymbolName = (name) => {
367614
+ const trimmedName = name.trim();
367615
+ if (trimmedName === "+")
367616
+ return "_POS";
367617
+ if (trimmedName === "-")
367618
+ return "_NEG";
367619
+ return trimmedName.replace(/(?<=[A-Za-z0-9])-(?=[A-Za-z0-9])/g, "_");
367620
+ };
367353
367621
  var round3 = (value) => Number(value.toFixed(6));
367354
367622
  var EASYEDA_SCHEMATIC_UNIT_TO_TSCIRCUIT_UNIT = 0.02;
367355
367623
  var toSchematicUnits = (value) => round3(value * EASYEDA_SCHEMATIC_UNIT_TO_TSCIRCUIT_UNIT);
@@ -367563,13 +367831,14 @@ var getPortMetadataByShapeId = (easyEdaJson, circuitJson) => {
367563
367831
  portName ??= `pin${pinIndex + 1}`;
367564
367832
  usedPortNames.add(portName);
367565
367833
  const sourcePort = sourcePorts.find((port) => port.name === portName);
367834
+ let aliases = getEasyEdaPinAliases(pin.label);
367835
+ if (sourcePort?.port_hints?.length) {
367836
+ aliases = sourcePort.port_hints;
367837
+ }
367566
367838
  metadataByShapeId.set(pin.id, {
367567
367839
  name: portName,
367568
367840
  pinNumber: sourcePort?.pin_number,
367569
- aliases: [
367570
- ...sourcePort?.port_hints ?? [],
367571
- ...pin.label ? [normalizeSymbolName(pin.label)] : []
367572
- ].filter((alias, index, aliases) => alias !== portName && aliases.indexOf(alias) === index)
367841
+ aliases: aliases.filter((alias, index, aliases2) => alias !== portName && aliases2.indexOf(alias) === index)
367573
367842
  });
367574
367843
  });
367575
367844
  return metadataByShapeId;
@@ -367819,7 +368088,7 @@ var generateFootprintTsx2 = (circuitJson, options = {}) => {
367819
368088
  </footprint>
367820
368089
  `.trim();
367821
368090
  };
367822
- var POWER_PIN_LABEL = /^(?:VCC|VDD|VIN|VDDA)\d*$/;
368091
+ var POWER_PIN_LABEL = /^(?:VCC|VDD|VIN|VDDA|VBUS)\d*$/;
367823
368092
  var GROUND_PIN_LABEL = /^(?:GND|VSS|PGND|AGND)\d*$/;
367824
368093
  var NO_CONNECT_PIN_LABEL = /^NC\d*$/;
367825
368094
  var getAttributeKind = (label) => {
@@ -368319,34 +368588,36 @@ var normalizeResistorValue = (value) => {
368319
368588
  var isResistorComponent = (betterEasy) => {
368320
368589
  const componentParameters = betterEasy.dataStr.head.c_para;
368321
368590
  const packageName = componentParameters.package;
368322
- return componentParameters.pre?.toUpperCase() === "R?" && typeof packageName === "string" && standardSmdResistorPackagePattern.test(packageName.trim()) && normalizeResistorValue(componentParameters.Value) !== undefined;
368591
+ const hasResistorCategory = betterEasy.tags.some((tag) => /\bresistors?\b/i.test(tag));
368592
+ return (componentParameters.pre?.toUpperCase() === "R?" || hasResistorCategory) && typeof packageName === "string" && standardSmdResistorPackagePattern.test(packageName.trim()) && normalizeResistorValue(componentParameters.Value) !== undefined;
368323
368593
  };
368324
- var categoryValueContainsSwitch = (value) => {
368325
- if (typeof value === "string") {
368326
- const normalized = value.toLowerCase();
368327
- if (/analog\s+switch/.test(normalized) || /multiplex/.test(normalized) || /switching\s+diodes?/.test(normalized) || /\bics?\b/.test(normalized)) {
368328
- return false;
368329
- }
368330
- return /(?:slide|toggle|dip|key|micro|limit)\s+switch(?:es)?/.test(normalized) || /(^|[^a-z])switch(?:es)?([^a-z]|$)/.test(normalized);
368331
- }
368332
- if (Array.isArray(value)) {
368333
- return value.some(categoryValueContainsSwitch);
368594
+ var getCategoryStrings = (category) => {
368595
+ if (typeof category === "string")
368596
+ return [category.toLowerCase()];
368597
+ if (Array.isArray(category))
368598
+ return category.flatMap(getCategoryStrings);
368599
+ if (category && typeof category === "object") {
368600
+ return Object.values(category).flatMap(getCategoryStrings);
368334
368601
  }
368335
- if (value && typeof value === "object") {
368336
- return Object.values(value).some(categoryValueContainsSwitch);
368602
+ return [];
368603
+ };
368604
+ var categoryValueContainsSwitch = (category) => {
368605
+ const categoryStrings = getCategoryStrings(category);
368606
+ if (categoryStrings.some((category2) => /analog[\s-]+switch/.test(category2) || /multiplex/.test(category2) || /switching\s+diodes?/.test(category2) || /\bics?\b/.test(category2) || /\b(?:power[\s-]+distribution|load)[\s-]+switch(?:es)?\b/.test(category2))) {
368607
+ return false;
368337
368608
  }
368338
- return false;
368609
+ return categoryStrings.some((category2) => /(?:slide|toggle|dip|key|micro|limit)\s+switch(?:es)?/.test(category2) || /(^|[^a-z])switch(?:es)?([^a-z]|$)/.test(category2));
368339
368610
  };
368340
368611
  var isSwitchCategoryComponent = (betterEasy) => {
368341
368612
  const cPara = betterEasy.dataStr.head.c_para;
368342
- return [
368613
+ return categoryValueContainsSwitch([
368343
368614
  betterEasy.tags,
368344
368615
  cPara.category,
368345
368616
  cPara.Category,
368346
368617
  cPara["LCSC Category"],
368347
368618
  cPara["JLCPCB Category"],
368348
368619
  betterEasy.category
368349
- ].some(categoryValueContainsSwitch);
368620
+ ]);
368350
368621
  };
368351
368622
  var getGeneratedComponentType = (betterEasy, pinCount) => {
368352
368623
  if (isLedCategoryComponent(betterEasy) && pinCount === 2)
@@ -368881,6 +369152,116 @@ var __export6 = (target, all) => {
368881
369152
  for (var name in all)
368882
369153
  __defProp7(target, name, { get: all[name], enumerable: true });
368883
369154
  };
369155
+ var normalizeActiveLowPinLabel2 = (label) => {
369156
+ const hasActiveLowMarker = label.startsWith("#") || label.endsWith("#");
369157
+ if (!hasActiveLowMarker)
369158
+ return label;
369159
+ const activeLowLabel = label.replace(/^#/, "").replace(/#$/, "");
369160
+ if (activeLowLabel.length === 0)
369161
+ return label;
369162
+ if (activeLowLabel.startsWith("N_"))
369163
+ return activeLowLabel;
369164
+ return `N_${activeLowLabel}`;
369165
+ };
369166
+ var normalizePinLabels2 = (inputPinLabels) => {
369167
+ const normalizedInputPinLabels = inputPinLabels.map((labels) => labels.map(normalizeActiveLowPinLabel2));
369168
+ const uniqueInputPinLabels = normalizedInputPinLabels.map((labels) => [
369169
+ ...new Set(labels)
369170
+ ]);
369171
+ const result = uniqueInputPinLabels.map(() => []);
369172
+ const desiredNumbers = uniqueInputPinLabels.map(() => null);
369173
+ for (let i = 0;i < uniqueInputPinLabels.length; i++) {
369174
+ for (const label of uniqueInputPinLabels[i]) {
369175
+ if (/^\d+$/.test(label)) {
369176
+ desiredNumbers[i] = Number.parseInt(label);
369177
+ break;
369178
+ }
369179
+ }
369180
+ }
369181
+ let highestPinNumber = 0;
369182
+ const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
369183
+ for (let i = 0;i < desiredNumbers.length; i++) {
369184
+ const desiredNumber = desiredNumbers[i];
369185
+ if (desiredNumber === null || desiredNumber < 1)
369186
+ continue;
369187
+ if (!acceptedDesiredNumbers.has(desiredNumber)) {
369188
+ acceptedDesiredNumbers.add(desiredNumber);
369189
+ result[i].push(`pin${desiredNumber}`);
369190
+ highestPinNumber = Math.max(highestPinNumber, desiredNumber);
369191
+ continue;
369192
+ }
369193
+ let existingAltCount = 0;
369194
+ for (const label of result[i]) {
369195
+ if (label.startsWith(`pin${desiredNumber}_alt`)) {
369196
+ existingAltCount += 1;
369197
+ }
369198
+ }
369199
+ result[i].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
369200
+ }
369201
+ for (let i = 0;i < result.length; i++) {
369202
+ const firstLabel = result[i][0];
369203
+ if (firstLabel?.includes("_alt")) {
369204
+ highestPinNumber += 1;
369205
+ result[i].unshift(`pin${highestPinNumber}`);
369206
+ }
369207
+ }
369208
+ for (let i = 0;i < result.length; i++) {
369209
+ if (result[i].length === 0) {
369210
+ highestPinNumber += 1;
369211
+ result[i].push(`pin${highestPinNumber}`);
369212
+ }
369213
+ }
369214
+ const totalLabelCounts = {};
369215
+ for (const inputLabels of uniqueInputPinLabels) {
369216
+ for (const label of inputLabels) {
369217
+ if (/^\d+$/.test(label))
369218
+ continue;
369219
+ totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
369220
+ }
369221
+ }
369222
+ const incrementalLabelCounts = {};
369223
+ for (let i = 0;i < uniqueInputPinLabels.length; i++) {
369224
+ for (const label of uniqueInputPinLabels[i]) {
369225
+ if (/^\d+$/.test(label))
369226
+ continue;
369227
+ if (totalLabelCounts[label] === 1) {
369228
+ result[i].push(label);
369229
+ } else {
369230
+ incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
369231
+ result[i].push(`${label}${incrementalLabelCounts[label]}`);
369232
+ }
369233
+ }
369234
+ }
369235
+ return result;
369236
+ };
369237
+ var normalizeEasyEdaPinLabel2 = (label) => {
369238
+ if (label.endsWith("+"))
369239
+ label = `${label.slice(0, -1)}_POS`;
369240
+ if (/[-–−]$/.test(label))
369241
+ label = `${label.slice(0, -1)}_NEG`;
369242
+ label = normalizeActiveLowPinLabel2(label);
369243
+ if (/^\+\d+(?:\.\d+)?V$/i.test(label))
369244
+ label = `V${label.slice(1, -1)}`;
369245
+ if (label.startsWith("+"))
369246
+ label = `${label.slice(1)}_POS`;
369247
+ if (/^[-–−]/.test(label))
369248
+ label = `${label.slice(1)}_NEG`;
369249
+ return label;
369250
+ };
369251
+ var getEasyEdaPinAliases2 = (label) => {
369252
+ label = label.replace(/&#(x[0-9a-f]+|[0-9]+);/gi, (entity, code) => {
369253
+ let codePoint = Number(code);
369254
+ if (/^x/i.test(code))
369255
+ codePoint = Number.parseInt(code.slice(1), 16);
369256
+ const maximumUnicodeCodePoint = 1114111;
369257
+ if (codePoint > maximumUnicodeCodePoint)
369258
+ return entity;
369259
+ return String.fromCodePoint(codePoint);
369260
+ });
369261
+ if (label.includes("/") && !/[a-zA-Z0-9]/.test(label))
369262
+ return [];
369263
+ return label.split("/").map((alias) => normalizeEasyEdaPinLabel2(alias.trim()).replace(/[`′]/g, "_PRIME").replace(/^[()]+|[()]+$/g, "").replace(/[^a-zA-Z0-9_]/g, "_")).filter((alias) => /[a-zA-Z0-9]/.test(alias));
369264
+ };
368884
369265
  function orientation4(p, q, r) {
368885
369266
  const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
368886
369267
  if (val === 0)
@@ -374319,6 +374700,208 @@ var transformPCBElements3 = (elms, matrix) => {
374319
374700
  }
374320
374701
  return transformedElms;
374321
374702
  };
374703
+ var mergeBounds5 = (currentBounds, nextBounds) => ({
374704
+ minX: Math.min(currentBounds.minX, nextBounds.minX),
374705
+ minY: Math.min(currentBounds.minY, nextBounds.minY),
374706
+ maxX: Math.max(currentBounds.maxX, nextBounds.maxX),
374707
+ maxY: Math.max(currentBounds.maxY, nextBounds.maxY)
374708
+ });
374709
+ var getCircleBounds3 = (x, y, diameter) => {
374710
+ const radius = diameter / 2;
374711
+ return {
374712
+ minX: x - radius,
374713
+ minY: y - radius,
374714
+ maxX: x + radius,
374715
+ maxY: y + radius
374716
+ };
374717
+ };
374718
+ var getRotatedRectBounds3 = (x, y, width, height, rotationDegrees) => {
374719
+ const halfWidth = width / 2;
374720
+ const halfHeight = height / 2;
374721
+ const theta = rotationDegrees * Math.PI / 180;
374722
+ const cosTheta = Math.cos(theta);
374723
+ const sinTheta = Math.sin(theta);
374724
+ const corners = [
374725
+ { x: -halfWidth, y: -halfHeight },
374726
+ { x: halfWidth, y: -halfHeight },
374727
+ { x: halfWidth, y: halfHeight },
374728
+ { x: -halfWidth, y: halfHeight }
374729
+ ].map((corner) => ({
374730
+ x: x + corner.x * cosTheta - corner.y * sinTheta,
374731
+ y: y + corner.x * sinTheta + corner.y * cosTheta
374732
+ }));
374733
+ return {
374734
+ minX: Math.min(...corners.map((corner) => corner.x)),
374735
+ minY: Math.min(...corners.map((corner) => corner.y)),
374736
+ maxX: Math.max(...corners.map((corner) => corner.x)),
374737
+ maxY: Math.max(...corners.map((corner) => corner.y))
374738
+ };
374739
+ };
374740
+ var getRotatedOvalBounds2 = (x, y, width, height, rotationDegrees) => {
374741
+ const radiusX = width / 2;
374742
+ const radiusY = height / 2;
374743
+ const theta = rotationDegrees * Math.PI / 180;
374744
+ const cosTheta = Math.cos(theta);
374745
+ const sinTheta = Math.sin(theta);
374746
+ const halfWidth = Math.hypot(radiusX * cosTheta, radiusY * sinTheta);
374747
+ const halfHeight = Math.hypot(radiusX * sinTheta, radiusY * cosTheta);
374748
+ return {
374749
+ minX: x - halfWidth,
374750
+ minY: y - halfHeight,
374751
+ maxX: x + halfWidth,
374752
+ maxY: y + halfHeight
374753
+ };
374754
+ };
374755
+ var getRotatedPillBounds2 = (x, y, width, height, rotationDegrees) => {
374756
+ const radius = Math.min(width, height) / 2;
374757
+ const halfLineLength = Math.max(width, height) / 2 - radius;
374758
+ const theta = rotationDegrees * Math.PI / 180;
374759
+ const axis = width >= height ? { x: halfLineLength, y: 0 } : { x: 0, y: halfLineLength };
374760
+ const rotatedAxis = {
374761
+ x: axis.x * Math.cos(theta) - axis.y * Math.sin(theta),
374762
+ y: axis.x * Math.sin(theta) + axis.y * Math.cos(theta)
374763
+ };
374764
+ const halfWidth = Math.abs(rotatedAxis.x) + radius;
374765
+ const halfHeight = Math.abs(rotatedAxis.y) + radius;
374766
+ return {
374767
+ minX: x - halfWidth,
374768
+ minY: y - halfHeight,
374769
+ maxX: x + halfWidth,
374770
+ maxY: y + halfHeight
374771
+ };
374772
+ };
374773
+ var getBoundsFromPoints24 = (points) => {
374774
+ if (points.length === 0)
374775
+ return null;
374776
+ return {
374777
+ minX: Math.min(...points.map((point2) => point2.x)),
374778
+ minY: Math.min(...points.map((point2) => point2.y)),
374779
+ maxX: Math.max(...points.map((point2) => point2.x)),
374780
+ maxY: Math.max(...points.map((point2) => point2.y))
374781
+ };
374782
+ };
374783
+ var getRoutePoints2 = (route) => {
374784
+ if (!Array.isArray(route))
374785
+ return [];
374786
+ return route.flatMap((point2) => {
374787
+ if (!point2 || typeof point2 !== "object")
374788
+ return [];
374789
+ if ("x" in point2 && "y" in point2 && typeof point2.x === "number" && typeof point2.y === "number") {
374790
+ return [{ x: point2.x, y: point2.y }];
374791
+ }
374792
+ if ("start" in point2 && "end" in point2) {
374793
+ const positions = [point2.start, point2.end];
374794
+ return positions.filter((position2) => Boolean(position2 && typeof position2 === "object" && "x" in position2 && "y" in position2 && typeof position2.x === "number" && typeof position2.y === "number"));
374795
+ }
374796
+ return [];
374797
+ });
374798
+ };
374799
+ var getPcbElementBounds2 = (elm) => {
374800
+ if (!elm.type.startsWith("pcb_"))
374801
+ return null;
374802
+ if (elm.type === "pcb_smtpad" && elm.shape === "polygon" && Array.isArray(elm.points)) {
374803
+ return getBoundsFromPoints24(elm.points);
374804
+ }
374805
+ if (elm.type === "pcb_hole" && elm.hole_shape === "circle") {
374806
+ return getCircleBounds3(elm.x, elm.y, elm.hole_diameter);
374807
+ }
374808
+ if (elm.type === "pcb_plated_hole") {
374809
+ let platedHoleBounds;
374810
+ if ("outer_diameter" in elm && typeof elm.outer_diameter === "number") {
374811
+ platedHoleBounds = getCircleBounds3(elm.x, elm.y, elm.outer_diameter);
374812
+ } else if ("hole_diameter" in elm && typeof elm.hole_diameter === "number") {
374813
+ platedHoleBounds = getCircleBounds3(elm.x, elm.y, elm.hole_diameter);
374814
+ }
374815
+ if ((elm.shape === "oval" || elm.shape === "pill") && typeof elm.outer_width === "number" && typeof elm.outer_height === "number") {
374816
+ const getOuterBounds = elm.shape === "pill" ? getRotatedPillBounds2 : getRotatedOvalBounds2;
374817
+ platedHoleBounds = getOuterBounds(elm.x, elm.y, elm.outer_width, elm.outer_height, elm.ccw_rotation ?? 0);
374818
+ }
374819
+ if ("rect_pad_width" in elm && typeof elm.rect_pad_width === "number" && "rect_pad_height" in elm && typeof elm.rect_pad_height === "number") {
374820
+ const rectBounds = getRotatedRectBounds3(elm.x, elm.y, elm.rect_pad_width, elm.rect_pad_height, "rect_ccw_rotation" in elm ? elm.rect_ccw_rotation ?? 0 : 0);
374821
+ platedHoleBounds = platedHoleBounds ? mergeBounds5(platedHoleBounds, rectBounds) : rectBounds;
374822
+ }
374823
+ if ("hole_diameter" in elm && typeof elm.hole_diameter === "number") {
374824
+ const drillBounds = getCircleBounds3(elm.x + ("hole_offset_x" in elm ? elm.hole_offset_x ?? 0 : 0), elm.y + ("hole_offset_y" in elm ? elm.hole_offset_y ?? 0 : 0), elm.hole_diameter);
374825
+ platedHoleBounds = platedHoleBounds ? mergeBounds5(platedHoleBounds, drillBounds) : drillBounds;
374826
+ }
374827
+ if (platedHoleBounds)
374828
+ return platedHoleBounds;
374829
+ }
374830
+ const elementRecord = elm;
374831
+ const routeBounds = getBoundsFromPoints24(getRoutePoints2(elementRecord.route));
374832
+ if (routeBounds)
374833
+ return routeBounds;
374834
+ const outlineBounds = getBoundsFromPoints24(getRoutePoints2(elementRecord.outline));
374835
+ if (outlineBounds)
374836
+ return outlineBounds;
374837
+ const pointsBounds = getBoundsFromPoints24(getRoutePoints2(elementRecord.points));
374838
+ if (pointsBounds)
374839
+ return pointsBounds;
374840
+ let centerX;
374841
+ let centerY;
374842
+ let width;
374843
+ let height;
374844
+ if ("x" in elm && "y" in elm) {
374845
+ centerX = Number(elm.x);
374846
+ centerY = Number(elm.y);
374847
+ }
374848
+ if ("outer_diameter" in elm) {
374849
+ width = Number(elm.outer_diameter);
374850
+ height = Number(elm.outer_diameter);
374851
+ }
374852
+ if ("width" in elm) {
374853
+ width = Number(elm.width);
374854
+ }
374855
+ if ("height" in elm) {
374856
+ height = Number(elm.height);
374857
+ }
374858
+ if ("center" in elm && elm.center && typeof elm.center === "object" && "x" in elm.center && "y" in elm.center) {
374859
+ centerX = Number(elm.center.x);
374860
+ centerY = Number(elm.center.y);
374861
+ }
374862
+ let rotation2 = 0;
374863
+ if ("rotation" in elm && typeof elm.rotation === "number") {
374864
+ rotation2 = elm.rotation;
374865
+ }
374866
+ if ("ccw_rotation" in elm && typeof elm.ccw_rotation === "number") {
374867
+ rotation2 = elm.ccw_rotation;
374868
+ }
374869
+ if (centerX !== undefined && centerY !== undefined) {
374870
+ if (width !== undefined && height !== undefined) {
374871
+ return rotation2 ? getRotatedRectBounds3(centerX, centerY, width, height, rotation2) : {
374872
+ minX: centerX - width / 2,
374873
+ minY: centerY - height / 2,
374874
+ maxX: centerX + width / 2,
374875
+ maxY: centerY + height / 2
374876
+ };
374877
+ }
374878
+ if ("radius" in elm && typeof elm.radius === "number") {
374879
+ return getCircleBounds3(centerX, centerY, elm.radius * 2);
374880
+ }
374881
+ return { minX: centerX, minY: centerY, maxX: centerX, maxY: centerY };
374882
+ }
374883
+ const anchoredPoint = [elementRecord.anchor_position, elementRecord.position].filter((position2) => Boolean(position2 && typeof position2 === "object" && "x" in position2 && "y" in position2 && typeof position2.x === "number" && typeof position2.y === "number")).at(0);
374884
+ return anchoredPoint ? {
374885
+ minX: anchoredPoint.x,
374886
+ minY: anchoredPoint.y,
374887
+ maxX: anchoredPoint.x,
374888
+ maxY: anchoredPoint.y
374889
+ } : null;
374890
+ };
374891
+ var getBoundsOfPcbElements4 = (elements) => {
374892
+ let bounds = {
374893
+ minX: Number.POSITIVE_INFINITY,
374894
+ minY: Number.POSITIVE_INFINITY,
374895
+ maxX: Number.NEGATIVE_INFINITY,
374896
+ maxY: Number.NEGATIVE_INFINITY
374897
+ };
374898
+ for (const element of elements) {
374899
+ const elementBounds = getPcbElementBounds2(element);
374900
+ if (elementBounds)
374901
+ bounds = mergeBounds5(bounds, elementBounds);
374902
+ }
374903
+ return bounds;
374904
+ };
374322
374905
  function stringHash4(str) {
374323
374906
  let hash = 0;
374324
374907
  if (str.length == 0)
@@ -374692,96 +375275,6 @@ var getPolarizedPinMetadata2 = (pinLabels) => {
374692
375275
  pinLabels: Object.fromEntries(polarizedPinEntries)
374693
375276
  };
374694
375277
  };
374695
- var normalizeActiveLowPinLabel2 = (label) => {
374696
- const hasActiveLowMarker = label.startsWith("#") || label.endsWith("#");
374697
- if (!hasActiveLowMarker)
374698
- return label;
374699
- const activeLowLabel = label.replace(/^#/, "").replace(/#$/, "");
374700
- if (activeLowLabel.length === 0)
374701
- return label;
374702
- if (activeLowLabel.startsWith("N_"))
374703
- return activeLowLabel;
374704
- return `N_${activeLowLabel}`;
374705
- };
374706
- var normalizePinLabels2 = (inputPinLabels) => {
374707
- const normalizedInputPinLabels = inputPinLabels.map((labels) => labels.map(normalizeActiveLowPinLabel2));
374708
- const uniqueInputPinLabels = normalizedInputPinLabels.map((labels) => [
374709
- ...new Set(labels)
374710
- ]);
374711
- const result = uniqueInputPinLabels.map(() => []);
374712
- const desiredNumbers = uniqueInputPinLabels.map(() => null);
374713
- for (let i = 0;i < uniqueInputPinLabels.length; i++) {
374714
- for (const label of uniqueInputPinLabels[i]) {
374715
- if (/^\d+$/.test(label)) {
374716
- desiredNumbers[i] = Number.parseInt(label);
374717
- break;
374718
- }
374719
- }
374720
- }
374721
- let highestPinNumber = 0;
374722
- const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
374723
- for (let i = 0;i < desiredNumbers.length; i++) {
374724
- const desiredNumber = desiredNumbers[i];
374725
- if (desiredNumber === null || desiredNumber < 1)
374726
- continue;
374727
- if (!acceptedDesiredNumbers.has(desiredNumber)) {
374728
- acceptedDesiredNumbers.add(desiredNumber);
374729
- result[i].push(`pin${desiredNumber}`);
374730
- highestPinNumber = Math.max(highestPinNumber, desiredNumber);
374731
- continue;
374732
- }
374733
- let existingAltCount = 0;
374734
- for (const label of result[i]) {
374735
- if (label.startsWith(`pin${desiredNumber}_alt`)) {
374736
- existingAltCount += 1;
374737
- }
374738
- }
374739
- result[i].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
374740
- }
374741
- for (let i = 0;i < result.length; i++) {
374742
- const firstLabel = result[i][0];
374743
- if (firstLabel?.includes("_alt")) {
374744
- highestPinNumber += 1;
374745
- result[i].unshift(`pin${highestPinNumber}`);
374746
- }
374747
- }
374748
- for (let i = 0;i < result.length; i++) {
374749
- if (result[i].length === 0) {
374750
- highestPinNumber += 1;
374751
- result[i].push(`pin${highestPinNumber}`);
374752
- }
374753
- }
374754
- const totalLabelCounts = {};
374755
- for (const inputLabels of uniqueInputPinLabels) {
374756
- for (const label of inputLabels) {
374757
- if (/^\d+$/.test(label))
374758
- continue;
374759
- totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
374760
- }
374761
- }
374762
- const incrementalLabelCounts = {};
374763
- for (let i = 0;i < uniqueInputPinLabels.length; i++) {
374764
- for (const label of uniqueInputPinLabels[i]) {
374765
- if (/^\d+$/.test(label))
374766
- continue;
374767
- if (totalLabelCounts[label] === 1) {
374768
- result[i].push(label);
374769
- } else {
374770
- incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
374771
- result[i].push(`${label}${incrementalLabelCounts[label]}`);
374772
- }
374773
- }
374774
- }
374775
- return result;
374776
- };
374777
- var normalizeSymbolName2 = (name) => {
374778
- const trimmedName = name.trim();
374779
- if (trimmedName === "+")
374780
- return "_POS";
374781
- if (trimmedName === "-")
374782
- return "_NEG";
374783
- return trimmedName.replace(/(?<=[A-Za-z0-9])-(?=[A-Za-z0-9])/g, "_");
374784
- };
374785
375278
  var categoryValueContainsDiode2 = (value) => {
374786
375279
  if (typeof value === "string") {
374787
375280
  return /(^|[^a-z])diodes?([^a-z]|$)/i.test(value);
@@ -374950,6 +375443,45 @@ var parseCadOffsetsFromSvgNode2 = (svgNode) => {
374950
375443
  })()
374951
375444
  };
374952
375445
  };
375446
+ var getCadModelOutlineBounds2 = (svgNode) => {
375447
+ const points = [];
375448
+ for (const childNode of svgNode?.svgData.childNodes ?? []) {
375449
+ if (typeof childNode !== "object" || childNode === null)
375450
+ continue;
375451
+ const attrs = childNode.attrs;
375452
+ if (typeof attrs !== "object" || attrs === null)
375453
+ continue;
375454
+ const rawPoints = attrs.points;
375455
+ if (typeof rawPoints !== "string")
375456
+ continue;
375457
+ const coordinates = rawPoints.trim().split(/\s+/).map(Number);
375458
+ for (let index = 0;index + 1 < coordinates.length; index += 2) {
375459
+ const x = coordinates[index];
375460
+ const y = coordinates[index + 1];
375461
+ if (!Number.isFinite(x) || !Number.isFinite(y))
375462
+ continue;
375463
+ points.push({ x: milx102(x), y: milx102(y) });
375464
+ }
375465
+ }
375466
+ if (points.length === 0)
375467
+ return;
375468
+ return {
375469
+ minX: Math.min(...points.map((point2) => point2.x)),
375470
+ minY: Math.min(...points.map((point2) => point2.y)),
375471
+ maxX: Math.max(...points.map((point2) => point2.x)),
375472
+ maxY: Math.max(...points.map((point2) => point2.y))
375473
+ };
375474
+ };
375475
+ var unionBounds3 = (first, second) => {
375476
+ if (!second)
375477
+ return first;
375478
+ return {
375479
+ minX: Math.min(first.minX, second.minX),
375480
+ minY: Math.min(first.minY, second.minY),
375481
+ maxX: Math.max(first.maxX, second.maxX),
375482
+ maxY: Math.max(first.maxY, second.maxY)
375483
+ };
375484
+ };
374953
375485
  var readModelHeightMm2 = (raw) => {
374954
375486
  const fallback = 3.5;
374955
375487
  if (raw == null)
@@ -375190,13 +375722,11 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
375190
375722
  const pads = easyEdaJson.packageDetail.dataStr.shape.filter((shape) => shape.type === "PAD");
375191
375723
  const pins = easyEdaJson.dataStr.shape.filter((shape) => shape.type === "PIN");
375192
375724
  const pinLabelSets = pads.map((pad) => {
375193
- const labels = [];
375194
- if (pad.number)
375195
- labels.push(pad.number.toString());
375725
+ const padAliases = pad.number ? getEasyEdaPinAliases2(pad.number.toString()) : [];
375196
375726
  const pin = pins.find((p) => p.pinNumber === pad.number);
375197
- if (pin)
375198
- labels.push(normalizeSymbolName2(pin.label));
375199
- return labels;
375727
+ const schematicAliases = pin ? getEasyEdaPinAliases2(pin.label) : [];
375728
+ const hasNamedSchematicAlias = schematicAliases.some((alias) => !/^\d+$/.test(alias));
375729
+ return hasNamedSchematicAlias ? [...schematicAliases, ...padAliases] : [...padAliases, ...schematicAliases];
375200
375730
  });
375201
375731
  const padNumberKeys = pads.map((pad, index) => {
375202
375732
  const padNumber = String(pad.number ?? "").trim();
@@ -375486,16 +376016,26 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
375486
376016
  model_step_url: stepFileUrl
375487
376017
  }));
375488
376018
  }
375489
- const hasExplicitCourtyard = circuitElements.some((e) => e.type === "pcb_courtyard_outline");
376019
+ const hasExplicitCourtyard = circuitElements.some((e) => e.type === "pcb_courtyard_outline" || e.type === "pcb_courtyard_rect");
375490
376020
  if (!hasExplicitCourtyard) {
375491
376021
  const bbox = easyEdaJson.packageDetail.dataStr.BBox;
375492
- if (bbox) {
376022
+ const modelOutlineBounds = getCadModelOutlineBounds2(svgNode);
376023
+ const packageElements = circuitElements.filter((element) => element.type === "pcb_smtpad" || element.type === "pcb_plated_hole" || element.type === "pcb_hole" || element.type === "pcb_via");
376024
+ const packageElementBounds = packageElements.length > 0 ? getBoundsOfPcbElements4(packageElements) : undefined;
376025
+ const fallbackBounds = bbox ? {
376026
+ minX: milx102(bbox.x),
376027
+ minY: milx102(bbox.y),
376028
+ maxX: milx102(bbox.x + bbox.width),
376029
+ maxY: milx102(bbox.y + bbox.height)
376030
+ } : undefined;
376031
+ const courtyardBounds = modelOutlineBounds ? unionBounds3(modelOutlineBounds, packageElementBounds) : fallbackBounds;
376032
+ if (courtyardBounds) {
375493
376033
  const strokeWidth = 0.05;
375494
376034
  const margin = 0.25;
375495
- const x1 = milx102(bbox.x) - margin;
375496
- const y1 = milx102(bbox.y) - margin;
375497
- const x2 = milx102(bbox.x + bbox.width) + margin;
375498
- const y2 = milx102(bbox.y + bbox.height) + margin;
376035
+ const x1 = courtyardBounds.minX - margin;
376036
+ const y1 = courtyardBounds.minY - margin;
376037
+ const x2 = courtyardBounds.maxX + margin;
376038
+ const y2 = courtyardBounds.maxY + margin;
375499
376039
  circuitElements.push(pcb_courtyard_outline3.parse({
375500
376040
  type: "pcb_courtyard_outline",
375501
376041
  pcb_courtyard_outline_id: `pcb_courtyard_outline_${easyEdaJson.lcsc.number}_1`,
@@ -376048,19 +376588,10 @@ var PinShapeOutputSchema2 = z201.object({
376048
376588
  var parsePin2 = (pinString) => {
376049
376589
  const parts = pinString.split("~");
376050
376590
  const [, visibility, , pinNumber, x, y, rotation2, id] = parts;
376051
- const nameMatch = pinString.match(/~([\w+#-]+)~(start|end)~/);
376052
- let label = nameMatch ? nameMatch[1] : "";
376053
- if (label.endsWith("+"))
376054
- label = `${label.slice(0, -1)}_POS`;
376055
- if (label.endsWith("-"))
376056
- label = `${label.slice(0, -1)}_NEG`;
376057
- label = normalizeActiveLowPinLabel2(label);
376058
- if (/^\+\d+(?:\.\d+)?V$/i.test(label))
376059
- label = `V${label.slice(1, -1)}`;
376060
- if (label.startsWith("+"))
376061
- label = `${label.slice(1)}_POS`;
376062
- if (label.startsWith("-"))
376063
- label = `${label.slice(1)}_NEG`;
376591
+ const pinNameSection = pinString.split("^^")[3];
376592
+ let label = pinNameSection?.split("~")[4] ?? "";
376593
+ if (!label.includes("/"))
376594
+ label = normalizeEasyEdaPinLabel2(label);
376064
376595
  const colorMatch = pinString.match(/#[0-9A-F]{6}/);
376065
376596
  const labelColor = colorMatch ? colorMatch[0] : "";
376066
376597
  const path = pinString.split("^^")[2]?.split("~")[0] ?? "";
package/dist/lib/index.js CHANGED
@@ -69109,7 +69109,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
69109
69109
  }));
69110
69110
  };
69111
69111
  // package.json
69112
- var version = "0.1.2228";
69112
+ var version = "0.1.2229";
69113
69113
  var package_default = {
69114
69114
  name: "@tscircuit/cli",
69115
69115
  version,
@@ -69137,7 +69137,7 @@ var package_default = {
69137
69137
  "@tscircuit/image-utils": "^0.0.8",
69138
69138
  "@tscircuit/krt-wasm": "^0.1.6",
69139
69139
  "@tscircuit/math-utils": "0.0.36",
69140
- "@tscircuit/props": "^0.0.657",
69140
+ "@tscircuit/props": "^0.0.666",
69141
69141
  "@tscircuit/runframe": "^0.0.2884",
69142
69142
  "@tscircuit/schematic-match-adapt": "^0.0.22",
69143
69143
  "@tscircuit/schematic-trace-solver": "^0.0.204",
@@ -69178,7 +69178,7 @@ var package_default = {
69178
69178
  debug: "^4.4.0",
69179
69179
  delay: "^6.0.0",
69180
69180
  "dsn-converter": "^0.0.90",
69181
- easyeda: "^0.0.357",
69181
+ easyeda: "^0.0.366",
69182
69182
  "fuse.js": "^7.1.0",
69183
69183
  "get-port": "^7.1.0",
69184
69184
  globby: "^14.1.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.2229",
3
+ "version": "0.1.2230",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/tscircuit/cli"
@@ -25,7 +25,7 @@
25
25
  "@tscircuit/image-utils": "^0.0.8",
26
26
  "@tscircuit/krt-wasm": "^0.1.6",
27
27
  "@tscircuit/math-utils": "0.0.36",
28
- "@tscircuit/props": "^0.0.657",
28
+ "@tscircuit/props": "^0.0.666",
29
29
  "@tscircuit/runframe": "^0.0.2884",
30
30
  "@tscircuit/schematic-match-adapt": "^0.0.22",
31
31
  "@tscircuit/schematic-trace-solver": "^0.0.204",
@@ -66,7 +66,7 @@
66
66
  "debug": "^4.4.0",
67
67
  "delay": "^6.0.0",
68
68
  "dsn-converter": "^0.0.90",
69
- "easyeda": "^0.0.357",
69
+ "easyeda": "^0.0.366",
70
70
  "fuse.js": "^7.1.0",
71
71
  "get-port": "^7.1.0",
72
72
  "globby": "^14.1.0",