@tscircuit/cli 0.1.1821 → 0.1.1822

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
@@ -135252,7 +135252,7 @@ var import_perfect_cli = __toESM2(require_dist2(), 1);
135252
135252
  // lib/getVersion.ts
135253
135253
  import { createRequire as createRequire2 } from "node:module";
135254
135254
  // package.json
135255
- var version = "0.1.1820";
135255
+ var version = "0.1.1821";
135256
135256
  var package_default = {
135257
135257
  name: "@tscircuit/cli",
135258
135258
  version,
@@ -135311,7 +135311,7 @@ var package_default = {
135311
135311
  debug: "^4.4.0",
135312
135312
  delay: "^6.0.0",
135313
135313
  "dsn-converter": "^0.0.90",
135314
- easyeda: "^0.0.275",
135314
+ easyeda: "^0.0.279",
135315
135315
  "fuse.js": "^7.1.0",
135316
135316
  "get-port": "^7.1.0",
135317
135317
  globby: "^14.1.0",
@@ -321650,6 +321650,7 @@ var mil2mm = (mil) => {
321650
321650
  return mm4(`${mil}mil`);
321651
321651
  return mm4(mil);
321652
321652
  };
321653
+ var DEFAULT_PCB_THICKNESS_MM = 1.6;
321653
321654
  function generateArcFromSweep(startX, startY, endX, endY, radius, largeArcFlag, sweepFlag) {
321654
321655
  const start = { x: startX, y: startY };
321655
321656
  const end = { x: endX, y: endY };
@@ -321691,6 +321692,158 @@ function generateArcFromSweep(startX, startY, endX, endY, radius, largeArcFlag,
321691
321692
  return path72;
321692
321693
  }
321693
321694
  var mil10ToMm = (value) => value * 10 * 0.0254;
321695
+ var getPinLabelValues = (labels) => {
321696
+ if (typeof labels === "string")
321697
+ return [labels];
321698
+ return [...labels];
321699
+ };
321700
+ var stripEasyEdaPolarityHintDecoration = (label) => label.toLowerCase().replace(/[^a-z0-9+-]/g, "");
321701
+ var getPinKeySortValue = (pinKey) => {
321702
+ const match = /^pin(\d+)$/i.exec(pinKey);
321703
+ return match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
321704
+ };
321705
+ var getPolarizedPinMetadata = (pinLabels) => {
321706
+ const labelsByPin = Object.entries(pinLabels).map(([pin, labels]) => ({
321707
+ pin,
321708
+ labels: getPinLabelValues(labels).map(stripEasyEdaPolarityHintDecoration)
321709
+ }));
321710
+ const anodePin = labelsByPin.find(({ labels }) => labels.some((label) => ["a", "anode", "pos", "+"].includes(label)))?.pin;
321711
+ const cathodePin = labelsByPin.find(({ labels }) => labels.some((label) => ["c", "k", "cathode", "neg", "-"].includes(label)))?.pin;
321712
+ if (!anodePin || !cathodePin || anodePin === cathodePin)
321713
+ return;
321714
+ const polarizedPinEntries = [
321715
+ [anodePin, ["anode", "pos"]],
321716
+ [cathodePin, ["cathode", "neg"]]
321717
+ ].sort(([pinA], [pinB]) => getPinKeySortValue(pinA) - getPinKeySortValue(pinB));
321718
+ return {
321719
+ portHintsMap: Object.fromEntries(polarizedPinEntries.map(([pin, labels]) => [pin, [pin, ...labels]])),
321720
+ pinLabels: Object.fromEntries(polarizedPinEntries)
321721
+ };
321722
+ };
321723
+ var normalizePinLabels = (inputPinLabels) => {
321724
+ const uniqueInputPinLabels = inputPinLabels.map((labels) => [
321725
+ ...new Set(labels)
321726
+ ]);
321727
+ const result = uniqueInputPinLabels.map(() => []);
321728
+ const desiredNumbers = uniqueInputPinLabels.map(() => null);
321729
+ for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
321730
+ for (const label of uniqueInputPinLabels[i4]) {
321731
+ if (/^\d+$/.test(label)) {
321732
+ desiredNumbers[i4] = Number.parseInt(label);
321733
+ break;
321734
+ }
321735
+ }
321736
+ }
321737
+ let highestPinNumber = 0;
321738
+ const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
321739
+ for (let i4 = 0;i4 < desiredNumbers.length; i4++) {
321740
+ const desiredNumber = desiredNumbers[i4];
321741
+ if (desiredNumber === null || desiredNumber < 1)
321742
+ continue;
321743
+ if (!acceptedDesiredNumbers.has(desiredNumber)) {
321744
+ acceptedDesiredNumbers.add(desiredNumber);
321745
+ result[i4].push(`pin${desiredNumber}`);
321746
+ highestPinNumber = Math.max(highestPinNumber, desiredNumber);
321747
+ continue;
321748
+ }
321749
+ let existingAltCount = 0;
321750
+ for (const label of result[i4]) {
321751
+ if (label.startsWith(`pin${desiredNumber}_alt`)) {
321752
+ existingAltCount += 1;
321753
+ }
321754
+ }
321755
+ result[i4].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
321756
+ }
321757
+ for (let i4 = 0;i4 < result.length; i4++) {
321758
+ const firstLabel = result[i4][0];
321759
+ if (firstLabel?.includes("_alt")) {
321760
+ highestPinNumber += 1;
321761
+ result[i4].unshift(`pin${highestPinNumber}`);
321762
+ }
321763
+ }
321764
+ for (let i4 = 0;i4 < result.length; i4++) {
321765
+ if (result[i4].length === 0) {
321766
+ highestPinNumber += 1;
321767
+ result[i4].push(`pin${highestPinNumber}`);
321768
+ }
321769
+ }
321770
+ const totalLabelCounts = {};
321771
+ for (const inputLabels of uniqueInputPinLabels) {
321772
+ for (const label of inputLabels) {
321773
+ if (/^\d+$/.test(label))
321774
+ continue;
321775
+ totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
321776
+ }
321777
+ }
321778
+ const incrementalLabelCounts = {};
321779
+ for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
321780
+ for (const label of uniqueInputPinLabels[i4]) {
321781
+ if (/^\d+$/.test(label))
321782
+ continue;
321783
+ if (totalLabelCounts[label] === 1) {
321784
+ result[i4].push(label);
321785
+ } else {
321786
+ incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
321787
+ result[i4].push(`${label}${incrementalLabelCounts[label]}`);
321788
+ }
321789
+ }
321790
+ }
321791
+ return result;
321792
+ };
321793
+ var normalizeSymbolName = (name) => {
321794
+ const trimmedName = name.trim();
321795
+ if (trimmedName === "+")
321796
+ return "_POS";
321797
+ if (trimmedName === "-")
321798
+ return "_NEG";
321799
+ return trimmedName;
321800
+ };
321801
+ var categoryValueContainsDiode = (value) => {
321802
+ if (typeof value === "string") {
321803
+ return /(^|[^a-z])diodes?([^a-z]|$)/i.test(value);
321804
+ }
321805
+ if (Array.isArray(value)) {
321806
+ return value.some(categoryValueContainsDiode);
321807
+ }
321808
+ if (value && typeof value === "object") {
321809
+ return Object.values(value).some(categoryValueContainsDiode);
321810
+ }
321811
+ return false;
321812
+ };
321813
+ var isDiodeCategoryComponent = (betterEasy) => {
321814
+ const cPara = betterEasy.dataStr.head.c_para;
321815
+ return [
321816
+ betterEasy.tags,
321817
+ cPara.category,
321818
+ cPara.Category,
321819
+ cPara["LCSC Category"],
321820
+ cPara["JLCPCB Category"],
321821
+ betterEasy.category
321822
+ ].some(categoryValueContainsDiode);
321823
+ };
321824
+ var categoryValueContainsLed = (value) => {
321825
+ if (typeof value === "string") {
321826
+ return /(^|[^a-z])leds?([^a-z]|$)/i.test(value) || /light[-\s]?emitting\s+diodes?/i.test(value);
321827
+ }
321828
+ if (Array.isArray(value)) {
321829
+ return value.some(categoryValueContainsLed);
321830
+ }
321831
+ if (value && typeof value === "object") {
321832
+ return Object.values(value).some(categoryValueContainsLed);
321833
+ }
321834
+ return false;
321835
+ };
321836
+ var isLedCategoryComponent = (betterEasy) => {
321837
+ const cPara = betterEasy.dataStr.head.c_para;
321838
+ return [
321839
+ betterEasy.tags,
321840
+ cPara.category,
321841
+ cPara.Category,
321842
+ cPara["LCSC Category"],
321843
+ cPara["JLCPCB Category"],
321844
+ betterEasy.category
321845
+ ].some(categoryValueContainsLed);
321846
+ };
321694
321847
  var getBoundsCenter3 = (bounds) => ({
321695
321848
  x: (bounds.minX + bounds.maxX) / 2,
321696
321849
  y: (bounds.minY + bounds.maxY) / 2
@@ -321823,85 +321976,6 @@ var getCadSvgNodeZOffsetMm = (easyEdaJson) => {
321823
321976
  return mil10ToMm(svgNodeZ);
321824
321977
  };
321825
321978
  var getCadSvgNodeModelUuid = (easyEdaJson) => getCadSvgNode(easyEdaJson)?.svgData.attrs?.uuid ?? null;
321826
- var normalizePinLabels = (inputPinLabels) => {
321827
- const uniqueInputPinLabels = inputPinLabels.map((labels) => [
321828
- ...new Set(labels)
321829
- ]);
321830
- const result = uniqueInputPinLabels.map(() => []);
321831
- const desiredNumbers = uniqueInputPinLabels.map(() => null);
321832
- for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
321833
- for (const label of uniqueInputPinLabels[i4]) {
321834
- if (/^\d+$/.test(label)) {
321835
- desiredNumbers[i4] = Number.parseInt(label);
321836
- break;
321837
- }
321838
- }
321839
- }
321840
- let highestPinNumber = 0;
321841
- const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
321842
- for (let i4 = 0;i4 < desiredNumbers.length; i4++) {
321843
- const desiredNumber = desiredNumbers[i4];
321844
- if (desiredNumber === null || desiredNumber < 1)
321845
- continue;
321846
- if (!acceptedDesiredNumbers.has(desiredNumber)) {
321847
- acceptedDesiredNumbers.add(desiredNumber);
321848
- result[i4].push(`pin${desiredNumber}`);
321849
- highestPinNumber = Math.max(highestPinNumber, desiredNumber);
321850
- continue;
321851
- }
321852
- let existingAltCount = 0;
321853
- for (const label of result[i4]) {
321854
- if (label.startsWith(`pin${desiredNumber}_alt`)) {
321855
- existingAltCount += 1;
321856
- }
321857
- }
321858
- result[i4].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
321859
- }
321860
- for (let i4 = 0;i4 < result.length; i4++) {
321861
- const firstLabel = result[i4][0];
321862
- if (firstLabel?.includes("_alt")) {
321863
- highestPinNumber += 1;
321864
- result[i4].unshift(`pin${highestPinNumber}`);
321865
- }
321866
- }
321867
- for (let i4 = 0;i4 < result.length; i4++) {
321868
- if (result[i4].length === 0) {
321869
- highestPinNumber += 1;
321870
- result[i4].push(`pin${highestPinNumber}`);
321871
- }
321872
- }
321873
- const totalLabelCounts = {};
321874
- for (const inputLabels of uniqueInputPinLabels) {
321875
- for (const label of inputLabels) {
321876
- if (/^\d+$/.test(label))
321877
- continue;
321878
- totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
321879
- }
321880
- }
321881
- const incrementalLabelCounts = {};
321882
- for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
321883
- for (const label of uniqueInputPinLabels[i4]) {
321884
- if (/^\d+$/.test(label))
321885
- continue;
321886
- if (totalLabelCounts[label] === 1) {
321887
- result[i4].push(label);
321888
- } else {
321889
- incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
321890
- result[i4].push(`${label}${incrementalLabelCounts[label]}`);
321891
- }
321892
- }
321893
- }
321894
- return result;
321895
- };
321896
- var normalizeSymbolName = (name) => {
321897
- const trimmedName = name.trim();
321898
- if (trimmedName === "+")
321899
- return "_POS";
321900
- if (trimmedName === "-")
321901
- return "_NEG";
321902
- return trimmedName;
321903
- };
321904
- var DEFAULT_PCB_THICKNESS_MM = 1.6;
321905
321979
  var EASYEDA_STEP_MODEL_URL = "https://modules.easyeda.com/qAxj6KHrDKw4blvCG8QJPs7Y";
321906
321980
  var EASYEDA_OBJ_MODEL_URL = "https://modules.easyeda.com/3dmodel";
321907
321981
  var TSCIRCUIT_MODEL_CDN_URL = "https://modelcdn.tscircuit.com/easyeda_models";
@@ -322098,9 +322172,16 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
322098
322172
  return labels;
322099
322173
  });
322100
322174
  const normalizedPinLabels = normalizePinLabels(pinLabelSets);
322175
+ const normalizedPinLabelsByPin = Object.fromEntries(normalizedPinLabels.map((labels) => {
322176
+ const pin = labels.find((label) => /^pin\d+$/i.test(label));
322177
+ return [pin, labels.filter((label) => label !== pin)];
322178
+ }));
322179
+ const polarizedPinMetadata = pads.length === 2 && (isDiodeCategoryComponent(easyEdaJson) || isLedCategoryComponent(easyEdaJson)) ? getPolarizedPinMetadata(normalizedPinLabelsByPin) : undefined;
322101
322180
  pads.forEach((pad2, index) => {
322102
322181
  const portHints2 = normalizedPinLabels[index];
322103
322182
  const pinNumber = Number.parseInt(portHints2.find((hint) => hint.match(/pin\d+/)).replace("pin", ""));
322183
+ const canonicalPinName = `pin${pinNumber}`;
322184
+ const pcbPortHints = polarizedPinMetadata?.portHintsMap[canonicalPinName] ?? [canonicalPinName];
322104
322185
  circuitElements.push({
322105
322186
  type: "source_port",
322106
322187
  source_port_id: `source_port_${index + 1}`,
@@ -322117,7 +322198,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
322117
322198
  x: mil2mm(pad2.center.x),
322118
322199
  y: mil2mm(pad2.center.y),
322119
322200
  layers: ["top"],
322120
- port_hints: [`pin${pinNumber}`],
322201
+ port_hints: pcbPortHints,
322121
322202
  pcb_component_id: "pcb_component_1",
322122
322203
  pcb_port_id: `pcb_port_${index + 1}`
322123
322204
  };
@@ -322221,7 +322302,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
322221
322302
  radius: Math.min(mil2mm(pad2.width), mil2mm(pad2.height)) / 2
322222
322303
  },
322223
322304
  layer: "top",
322224
- port_hints: [`pin${pinNumber}`],
322305
+ port_hints: pcbPortHints,
322225
322306
  pcb_component_id: "pcb_component_1",
322226
322307
  pcb_port_id: `pcb_port_${index + 1}`
322227
322308
  });
@@ -322454,7 +322535,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
322454
322535
  };
322455
322536
  var safeNumber = (defaultValue = 0) => external_exports2.union([external_exports2.number(), external_exports2.string()]).transform((val) => {
322456
322537
  const num = Number(val);
322457
- return isNaN(num) ? defaultValue : num;
322538
+ return Number.isNaN(num) ? defaultValue : num;
322458
322539
  }).default(defaultValue);
322459
322540
  var tenthmil = external_exports2.union([external_exports2.number(), external_exports2.string()]).optional().transform((n3) => typeof n3 === "string" && n3.endsWith("mil") ? n3 : `${Number.parseFloat(n3) * 10}mil`).pipe(external_exports2.string());
322460
322541
  var PointSchema = external_exports2.any().transform((p3) => {
@@ -322594,6 +322675,7 @@ var ShapeItemSchema = external_exports2.object({
322594
322675
  }
322595
322676
  case "PAD": {
322596
322677
  const [padShape, ...params2] = shape.data.split("~");
322678
+ const rawPadNumber = params2[6];
322597
322679
  const [
322598
322680
  centerX,
322599
322681
  centerY,
@@ -322601,10 +322683,11 @@ var ShapeItemSchema = external_exports2.object({
322601
322683
  height,
322602
322684
  layermask,
322603
322685
  net2,
322604
- number,
322686
+ numericPadNumber,
322605
322687
  holeRadius,
322606
322688
  ...rest
322607
322689
  ] = params2.map((p3) => Number.isNaN(Number(p3)) ? p3 : Number(p3));
322690
+ const padNumber = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(rawPadNumber) ? numericPadNumber : rawPadNumber;
322608
322691
  const center2 = { x: centerX, y: centerY };
322609
322692
  let points;
322610
322693
  if (padShape === "RECT" || padShape === "POLYGON") {
@@ -322620,7 +322703,7 @@ var ShapeItemSchema = external_exports2.object({
322620
322703
  height,
322621
322704
  layermask,
322622
322705
  net: net2,
322623
- number,
322706
+ number: padNumber,
322624
322707
  holeRadius,
322625
322708
  points,
322626
322709
  rotation: rotation23,
@@ -323071,7 +323154,7 @@ var OwnerSchema = external_exports2.object({
323071
323154
  });
323072
323155
  var HeadSchema = external_exports2.object({
323073
323156
  docType: external_exports2.preprocess((val) => val == null ? val : String(val), external_exports2.string()),
323074
- editorVersion: external_exports2.string(),
323157
+ editorVersion: external_exports2.string().default(""),
323075
323158
  c_para: external_exports2.record(external_exports2.string(), external_exports2.string().nullable()),
323076
323159
  x: external_exports2.number(),
323077
323160
  y: external_exports2.number(),
@@ -323086,7 +323169,7 @@ var HeadSchema = external_exports2.object({
323086
323169
  }, external_exports2.number()),
323087
323170
  importFlag: external_exports2.number().optional(),
323088
323171
  c_spiceCmd: external_exports2.any().optional(),
323089
- hasIdFlag: external_exports2.boolean()
323172
+ hasIdFlag: external_exports2.boolean().default(false)
323090
323173
  });
323091
323174
  var BBoxSchema = external_exports2.object({
323092
323175
  x: external_exports2.number(),
@@ -323111,9 +323194,17 @@ var DataStrSchema = external_exports2.object({
323111
323194
  head: HeadSchema,
323112
323195
  canvas: external_exports2.string(),
323113
323196
  shape: external_exports2.array(SingleLetterShapeSchema),
323114
- BBox: BBoxSchema,
323115
- colors: external_exports2.union([external_exports2.array(external_exports2.string()), external_exports2.record(external_exports2.string())])
323116
- });
323197
+ BBox: BBoxSchema.optional(),
323198
+ colors: external_exports2.union([external_exports2.array(external_exports2.string()), external_exports2.record(external_exports2.string())]).default([])
323199
+ }).transform((data) => ({
323200
+ ...data,
323201
+ BBox: data.BBox ?? {
323202
+ x: data.head.x,
323203
+ y: data.head.y,
323204
+ width: 0,
323205
+ height: 0
323206
+ }
323207
+ }));
323117
323208
  var PackageDetailDataStrSchema = external_exports2.object({
323118
323209
  head: HeadSchema,
323119
323210
  canvas: external_exports2.string(),
@@ -323313,7 +323404,7 @@ var getEasyEdaCadModelPlacement = async (easyEdaJson, { fetch: fetch22 = globalT
323313
323404
  var mapPortHints = (portHints2, portHintsMap) => {
323314
323405
  if (!portHintsMap || !portHints2)
323315
323406
  return portHints2;
323316
- return portHints2.flatMap((hint) => portHintsMap[hint] ?? [hint]);
323407
+ return [...new Set(portHints2.flatMap((hint) => portHintsMap[hint] ?? [hint]))];
323317
323408
  };
323318
323409
  var generateFootprintTsx2 = (circuitJson, options = {}) => {
323319
323410
  const holes = su17(circuitJson).pcb_hole.list();
@@ -323380,34 +323471,6 @@ var generateFootprintTsx2 = (circuitJson, options = {}) => {
323380
323471
  </footprint>
323381
323472
  `.trim();
323382
323473
  };
323383
- var getPinLabelValues = (labels) => {
323384
- if (typeof labels === "string")
323385
- return [labels];
323386
- return [...labels];
323387
- };
323388
- var stripEasyEdaPolarityHintDecoration = (label) => label.toLowerCase().replace(/[^a-z0-9+-]/g, "");
323389
- var getPinKeySortValue = (pinKey) => {
323390
- const match = /^pin(\d+)$/i.exec(pinKey);
323391
- return match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
323392
- };
323393
- var getPolarizedPinMetadata = (pinLabels) => {
323394
- const labelsByPin = Object.entries(pinLabels ?? {}).map(([pin, labels]) => ({
323395
- pin,
323396
- labels: getPinLabelValues(labels).map(stripEasyEdaPolarityHintDecoration)
323397
- }));
323398
- const anodePin = labelsByPin.find(({ labels }) => labels.some((label) => ["a", "anode", "pos", "+"].includes(label)))?.pin;
323399
- const cathodePin = labelsByPin.find(({ labels }) => labels.some((label) => ["c", "k", "cathode", "neg", "-"].includes(label)))?.pin;
323400
- if (!anodePin || !cathodePin)
323401
- return;
323402
- const polarizedPinEntries = [
323403
- [anodePin, ["anode", "pos"]],
323404
- [cathodePin, ["cathode", "neg"]]
323405
- ].sort(([pinA], [pinB]) => getPinKeySortValue(pinA) - getPinKeySortValue(pinB));
323406
- return {
323407
- portHintsMap: Object.fromEntries(polarizedPinEntries.map(([pin, labels]) => [pin, [pin, ...labels]])),
323408
- pinLabels: Object.fromEntries(polarizedPinEntries)
323409
- };
323410
- };
323411
323474
  var generateTypescriptComponent = ({
323412
323475
  pinLabels,
323413
323476
  componentName,
@@ -323576,52 +323639,6 @@ ${cadModelLines}
323576
323639
  }
323577
323640
  `.trim();
323578
323641
  };
323579
- var categoryValueContainsDiode = (value) => {
323580
- if (typeof value === "string") {
323581
- return /(^|[^a-z])diodes?([^a-z]|$)/i.test(value);
323582
- }
323583
- if (Array.isArray(value)) {
323584
- return value.some(categoryValueContainsDiode);
323585
- }
323586
- if (value && typeof value === "object") {
323587
- return Object.values(value).some(categoryValueContainsDiode);
323588
- }
323589
- return false;
323590
- };
323591
- var isDiodeCategoryComponent = (betterEasy) => {
323592
- const cPara = betterEasy.dataStr.head.c_para;
323593
- return [
323594
- betterEasy.tags,
323595
- cPara.category,
323596
- cPara.Category,
323597
- cPara["LCSC Category"],
323598
- cPara["JLCPCB Category"],
323599
- betterEasy.category
323600
- ].some(categoryValueContainsDiode);
323601
- };
323602
- var categoryValueContainsLed = (value) => {
323603
- if (typeof value === "string") {
323604
- return /(^|[^a-z])leds?([^a-z]|$)/i.test(value) || /light[-\s]?emitting\s+diodes?/i.test(value);
323605
- }
323606
- if (Array.isArray(value)) {
323607
- return value.some(categoryValueContainsLed);
323608
- }
323609
- if (value && typeof value === "object") {
323610
- return Object.values(value).some(categoryValueContainsLed);
323611
- }
323612
- return false;
323613
- };
323614
- var isLedCategoryComponent = (betterEasy) => {
323615
- const cPara = betterEasy.dataStr.head.c_para;
323616
- return [
323617
- betterEasy.tags,
323618
- cPara.category,
323619
- cPara.Category,
323620
- cPara["LCSC Category"],
323621
- cPara["JLCPCB Category"],
323622
- betterEasy.category
323623
- ].some(categoryValueContainsLed);
323624
- };
323625
323642
  var categoryValueContainsPushbutton = (value) => {
323626
323643
  if (typeof value === "string") {
323627
323644
  const normalized = value.toLowerCase();
@@ -324124,7 +324141,10 @@ async function fetchEasyEDAComponent(jlcpcbPartNumber, {
324124
324141
  body: searchData
324125
324142
  });
324126
324143
  if (!searchResponse.ok) {
324127
- throw new Error("Failed to search for the component");
324144
+ if (searchResponse.status === 403) {
324145
+ throw new Error(`EasyEDA API rate limit exceeded while searching for "${jlcpcbPartNumber}" (HTTP 403). EasyEDA rate-limits by IP — the part number is likely fine. Wait ~2 minutes and try again.`);
324146
+ }
324147
+ throw new Error(`Failed to search for the component (HTTP ${searchResponse.status})`);
324128
324148
  }
324129
324149
  const searchResult = await searchResponse.json();
324130
324150
  if (!searchResult.success || !searchResult.result.lists.lcsc.length) {
@@ -324140,7 +324160,10 @@ async function fetchEasyEDAComponent(jlcpcbPartNumber, {
324140
324160
  }
324141
324161
  });
324142
324162
  if (!componentResponse.ok) {
324143
- throw new Error("Failed to fetch the component details");
324163
+ if (componentResponse.status === 403) {
324164
+ throw new Error(`EasyEDA API rate limit exceeded while fetching "${jlcpcbPartNumber}" (HTTP 403). EasyEDA rate-limits by IP — the part number is likely fine. Wait ~2 minutes and try again.`);
324165
+ }
324166
+ throw new Error(`Failed to fetch the component details (HTTP ${componentResponse.status})`);
324144
324167
  }
324145
324168
  const componentResult = await componentResponse.json();
324146
324169
  const result = componentResult.result;
@@ -329403,6 +329426,7 @@ var mil2mm2 = (mil) => {
329403
329426
  return mm5(`${mil}mil`);
329404
329427
  return mm5(mil);
329405
329428
  };
329429
+ var DEFAULT_PCB_THICKNESS_MM2 = 1.6;
329406
329430
  function generateArcFromSweep2(startX, startY, endX, endY, radius, largeArcFlag, sweepFlag) {
329407
329431
  const start = { x: startX, y: startY };
329408
329432
  const end = { x: endX, y: endY };
@@ -329444,6 +329468,158 @@ function generateArcFromSweep2(startX, startY, endX, endY, radius, largeArcFlag,
329444
329468
  return path72;
329445
329469
  }
329446
329470
  var mil10ToMm2 = (value) => value * 10 * 0.0254;
329471
+ var getPinLabelValues2 = (labels) => {
329472
+ if (typeof labels === "string")
329473
+ return [labels];
329474
+ return [...labels];
329475
+ };
329476
+ var stripEasyEdaPolarityHintDecoration2 = (label) => label.toLowerCase().replace(/[^a-z0-9+-]/g, "");
329477
+ var getPinKeySortValue2 = (pinKey) => {
329478
+ const match = /^pin(\d+)$/i.exec(pinKey);
329479
+ return match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
329480
+ };
329481
+ var getPolarizedPinMetadata2 = (pinLabels) => {
329482
+ const labelsByPin = Object.entries(pinLabels).map(([pin, labels]) => ({
329483
+ pin,
329484
+ labels: getPinLabelValues2(labels).map(stripEasyEdaPolarityHintDecoration2)
329485
+ }));
329486
+ const anodePin = labelsByPin.find(({ labels }) => labels.some((label) => ["a", "anode", "pos", "+"].includes(label)))?.pin;
329487
+ const cathodePin = labelsByPin.find(({ labels }) => labels.some((label) => ["c", "k", "cathode", "neg", "-"].includes(label)))?.pin;
329488
+ if (!anodePin || !cathodePin || anodePin === cathodePin)
329489
+ return;
329490
+ const polarizedPinEntries = [
329491
+ [anodePin, ["anode", "pos"]],
329492
+ [cathodePin, ["cathode", "neg"]]
329493
+ ].sort(([pinA], [pinB]) => getPinKeySortValue2(pinA) - getPinKeySortValue2(pinB));
329494
+ return {
329495
+ portHintsMap: Object.fromEntries(polarizedPinEntries.map(([pin, labels]) => [pin, [pin, ...labels]])),
329496
+ pinLabels: Object.fromEntries(polarizedPinEntries)
329497
+ };
329498
+ };
329499
+ var normalizePinLabels2 = (inputPinLabels) => {
329500
+ const uniqueInputPinLabels = inputPinLabels.map((labels) => [
329501
+ ...new Set(labels)
329502
+ ]);
329503
+ const result = uniqueInputPinLabels.map(() => []);
329504
+ const desiredNumbers = uniqueInputPinLabels.map(() => null);
329505
+ for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
329506
+ for (const label of uniqueInputPinLabels[i4]) {
329507
+ if (/^\d+$/.test(label)) {
329508
+ desiredNumbers[i4] = Number.parseInt(label);
329509
+ break;
329510
+ }
329511
+ }
329512
+ }
329513
+ let highestPinNumber = 0;
329514
+ const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
329515
+ for (let i4 = 0;i4 < desiredNumbers.length; i4++) {
329516
+ const desiredNumber = desiredNumbers[i4];
329517
+ if (desiredNumber === null || desiredNumber < 1)
329518
+ continue;
329519
+ if (!acceptedDesiredNumbers.has(desiredNumber)) {
329520
+ acceptedDesiredNumbers.add(desiredNumber);
329521
+ result[i4].push(`pin${desiredNumber}`);
329522
+ highestPinNumber = Math.max(highestPinNumber, desiredNumber);
329523
+ continue;
329524
+ }
329525
+ let existingAltCount = 0;
329526
+ for (const label of result[i4]) {
329527
+ if (label.startsWith(`pin${desiredNumber}_alt`)) {
329528
+ existingAltCount += 1;
329529
+ }
329530
+ }
329531
+ result[i4].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
329532
+ }
329533
+ for (let i4 = 0;i4 < result.length; i4++) {
329534
+ const firstLabel = result[i4][0];
329535
+ if (firstLabel?.includes("_alt")) {
329536
+ highestPinNumber += 1;
329537
+ result[i4].unshift(`pin${highestPinNumber}`);
329538
+ }
329539
+ }
329540
+ for (let i4 = 0;i4 < result.length; i4++) {
329541
+ if (result[i4].length === 0) {
329542
+ highestPinNumber += 1;
329543
+ result[i4].push(`pin${highestPinNumber}`);
329544
+ }
329545
+ }
329546
+ const totalLabelCounts = {};
329547
+ for (const inputLabels of uniqueInputPinLabels) {
329548
+ for (const label of inputLabels) {
329549
+ if (/^\d+$/.test(label))
329550
+ continue;
329551
+ totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
329552
+ }
329553
+ }
329554
+ const incrementalLabelCounts = {};
329555
+ for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
329556
+ for (const label of uniqueInputPinLabels[i4]) {
329557
+ if (/^\d+$/.test(label))
329558
+ continue;
329559
+ if (totalLabelCounts[label] === 1) {
329560
+ result[i4].push(label);
329561
+ } else {
329562
+ incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
329563
+ result[i4].push(`${label}${incrementalLabelCounts[label]}`);
329564
+ }
329565
+ }
329566
+ }
329567
+ return result;
329568
+ };
329569
+ var normalizeSymbolName2 = (name) => {
329570
+ const trimmedName = name.trim();
329571
+ if (trimmedName === "+")
329572
+ return "_POS";
329573
+ if (trimmedName === "-")
329574
+ return "_NEG";
329575
+ return trimmedName;
329576
+ };
329577
+ var categoryValueContainsDiode2 = (value) => {
329578
+ if (typeof value === "string") {
329579
+ return /(^|[^a-z])diodes?([^a-z]|$)/i.test(value);
329580
+ }
329581
+ if (Array.isArray(value)) {
329582
+ return value.some(categoryValueContainsDiode2);
329583
+ }
329584
+ if (value && typeof value === "object") {
329585
+ return Object.values(value).some(categoryValueContainsDiode2);
329586
+ }
329587
+ return false;
329588
+ };
329589
+ var isDiodeCategoryComponent2 = (betterEasy) => {
329590
+ const cPara = betterEasy.dataStr.head.c_para;
329591
+ return [
329592
+ betterEasy.tags,
329593
+ cPara.category,
329594
+ cPara.Category,
329595
+ cPara["LCSC Category"],
329596
+ cPara["JLCPCB Category"],
329597
+ betterEasy.category
329598
+ ].some(categoryValueContainsDiode2);
329599
+ };
329600
+ var categoryValueContainsLed2 = (value) => {
329601
+ if (typeof value === "string") {
329602
+ return /(^|[^a-z])leds?([^a-z]|$)/i.test(value) || /light[-\s]?emitting\s+diodes?/i.test(value);
329603
+ }
329604
+ if (Array.isArray(value)) {
329605
+ return value.some(categoryValueContainsLed2);
329606
+ }
329607
+ if (value && typeof value === "object") {
329608
+ return Object.values(value).some(categoryValueContainsLed2);
329609
+ }
329610
+ return false;
329611
+ };
329612
+ var isLedCategoryComponent2 = (betterEasy) => {
329613
+ const cPara = betterEasy.dataStr.head.c_para;
329614
+ return [
329615
+ betterEasy.tags,
329616
+ cPara.category,
329617
+ cPara.Category,
329618
+ cPara["LCSC Category"],
329619
+ cPara["JLCPCB Category"],
329620
+ betterEasy.category
329621
+ ].some(categoryValueContainsLed2);
329622
+ };
329447
329623
  var getBoundsCenter4 = (bounds) => ({
329448
329624
  x: (bounds.minX + bounds.maxX) / 2,
329449
329625
  y: (bounds.minY + bounds.maxY) / 2
@@ -329562,85 +329738,6 @@ var getCadModelOffsetMmFromBounds2 = (easyEdaJson, bounds, {
329562
329738
  y: modelCenter.y - targetOriginInModelFrame.y
329563
329739
  });
329564
329740
  };
329565
- var normalizePinLabels2 = (inputPinLabels) => {
329566
- const uniqueInputPinLabels = inputPinLabels.map((labels) => [
329567
- ...new Set(labels)
329568
- ]);
329569
- const result = uniqueInputPinLabels.map(() => []);
329570
- const desiredNumbers = uniqueInputPinLabels.map(() => null);
329571
- for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
329572
- for (const label of uniqueInputPinLabels[i4]) {
329573
- if (/^\d+$/.test(label)) {
329574
- desiredNumbers[i4] = Number.parseInt(label);
329575
- break;
329576
- }
329577
- }
329578
- }
329579
- let highestPinNumber = 0;
329580
- const acceptedDesiredNumbers = /* @__PURE__ */ new Set;
329581
- for (let i4 = 0;i4 < desiredNumbers.length; i4++) {
329582
- const desiredNumber = desiredNumbers[i4];
329583
- if (desiredNumber === null || desiredNumber < 1)
329584
- continue;
329585
- if (!acceptedDesiredNumbers.has(desiredNumber)) {
329586
- acceptedDesiredNumbers.add(desiredNumber);
329587
- result[i4].push(`pin${desiredNumber}`);
329588
- highestPinNumber = Math.max(highestPinNumber, desiredNumber);
329589
- continue;
329590
- }
329591
- let existingAltCount = 0;
329592
- for (const label of result[i4]) {
329593
- if (label.startsWith(`pin${desiredNumber}_alt`)) {
329594
- existingAltCount += 1;
329595
- }
329596
- }
329597
- result[i4].push(`pin${desiredNumber}_alt${existingAltCount + 1}`);
329598
- }
329599
- for (let i4 = 0;i4 < result.length; i4++) {
329600
- const firstLabel = result[i4][0];
329601
- if (firstLabel?.includes("_alt")) {
329602
- highestPinNumber += 1;
329603
- result[i4].unshift(`pin${highestPinNumber}`);
329604
- }
329605
- }
329606
- for (let i4 = 0;i4 < result.length; i4++) {
329607
- if (result[i4].length === 0) {
329608
- highestPinNumber += 1;
329609
- result[i4].push(`pin${highestPinNumber}`);
329610
- }
329611
- }
329612
- const totalLabelCounts = {};
329613
- for (const inputLabels of uniqueInputPinLabels) {
329614
- for (const label of inputLabels) {
329615
- if (/^\d+$/.test(label))
329616
- continue;
329617
- totalLabelCounts[label] = (totalLabelCounts[label] ?? 0) + 1;
329618
- }
329619
- }
329620
- const incrementalLabelCounts = {};
329621
- for (let i4 = 0;i4 < uniqueInputPinLabels.length; i4++) {
329622
- for (const label of uniqueInputPinLabels[i4]) {
329623
- if (/^\d+$/.test(label))
329624
- continue;
329625
- if (totalLabelCounts[label] === 1) {
329626
- result[i4].push(label);
329627
- } else {
329628
- incrementalLabelCounts[label] = (incrementalLabelCounts[label] ?? 0) + 1;
329629
- result[i4].push(`${label}${incrementalLabelCounts[label]}`);
329630
- }
329631
- }
329632
- }
329633
- return result;
329634
- };
329635
- var normalizeSymbolName2 = (name) => {
329636
- const trimmedName = name.trim();
329637
- if (trimmedName === "+")
329638
- return "_POS";
329639
- if (trimmedName === "-")
329640
- return "_NEG";
329641
- return trimmedName;
329642
- };
329643
- var DEFAULT_PCB_THICKNESS_MM2 = 1.6;
329644
329741
  var EASYEDA_STEP_MODEL_URL2 = "https://modules.easyeda.com/qAxj6KHrDKw4blvCG8QJPs7Y";
329645
329742
  var EASYEDA_OBJ_MODEL_URL2 = "https://modules.easyeda.com/3dmodel";
329646
329743
  var TSCIRCUIT_MODEL_CDN_URL2 = "https://modelcdn.tscircuit.com/easyeda_models";
@@ -329837,9 +329934,16 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
329837
329934
  return labels;
329838
329935
  });
329839
329936
  const normalizedPinLabels = normalizePinLabels2(pinLabelSets);
329937
+ const normalizedPinLabelsByPin = Object.fromEntries(normalizedPinLabels.map((labels) => {
329938
+ const pin = labels.find((label) => /^pin\d+$/i.test(label));
329939
+ return [pin, labels.filter((label) => label !== pin)];
329940
+ }));
329941
+ const polarizedPinMetadata = pads.length === 2 && (isDiodeCategoryComponent2(easyEdaJson) || isLedCategoryComponent2(easyEdaJson)) ? getPolarizedPinMetadata2(normalizedPinLabelsByPin) : undefined;
329840
329942
  pads.forEach((pad2, index) => {
329841
329943
  const portHints2 = normalizedPinLabels[index];
329842
329944
  const pinNumber = Number.parseInt(portHints2.find((hint) => hint.match(/pin\d+/)).replace("pin", ""));
329945
+ const canonicalPinName = `pin${pinNumber}`;
329946
+ const pcbPortHints = polarizedPinMetadata?.portHintsMap[canonicalPinName] ?? [canonicalPinName];
329843
329947
  circuitElements.push({
329844
329948
  type: "source_port",
329845
329949
  source_port_id: `source_port_${index + 1}`,
@@ -329856,7 +329960,7 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
329856
329960
  x: mil2mm2(pad2.center.x),
329857
329961
  y: mil2mm2(pad2.center.y),
329858
329962
  layers: ["top"],
329859
- port_hints: [`pin${pinNumber}`],
329963
+ port_hints: pcbPortHints,
329860
329964
  pcb_component_id: "pcb_component_1",
329861
329965
  pcb_port_id: `pcb_port_${index + 1}`
329862
329966
  };
@@ -329960,7 +330064,7 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
329960
330064
  radius: Math.min(mil2mm2(pad2.width), mil2mm2(pad2.height)) / 2
329961
330065
  },
329962
330066
  layer: "top",
329963
- port_hints: [`pin${pinNumber}`],
330067
+ port_hints: pcbPortHints,
329964
330068
  pcb_component_id: "pcb_component_1",
329965
330069
  pcb_port_id: `pcb_port_${index + 1}`
329966
330070
  });
@@ -330193,7 +330297,7 @@ var convertEasyEdaJsonToCircuitJson2 = (easyEdaJson, {
330193
330297
  };
330194
330298
  var safeNumber2 = (defaultValue = 0) => z179.union([z179.number(), z179.string()]).transform((val) => {
330195
330299
  const num = Number(val);
330196
- return isNaN(num) ? defaultValue : num;
330300
+ return Number.isNaN(num) ? defaultValue : num;
330197
330301
  }).default(defaultValue);
330198
330302
  var tenthmil2 = z179.union([z179.number(), z179.string()]).optional().transform((n3) => typeof n3 === "string" && n3.endsWith("mil") ? n3 : `${Number.parseFloat(n3) * 10}mil`).pipe(z179.string());
330199
330303
  var PointSchema3 = z179.any().transform((p3) => {
@@ -330333,6 +330437,7 @@ var ShapeItemSchema2 = z179.object({
330333
330437
  }
330334
330438
  case "PAD": {
330335
330439
  const [padShape, ...params2] = shape.data.split("~");
330440
+ const rawPadNumber = params2[6];
330336
330441
  const [
330337
330442
  centerX,
330338
330443
  centerY,
@@ -330340,10 +330445,11 @@ var ShapeItemSchema2 = z179.object({
330340
330445
  height,
330341
330446
  layermask,
330342
330447
  net2,
330343
- number,
330448
+ numericPadNumber,
330344
330449
  holeRadius,
330345
330450
  ...rest
330346
330451
  ] = params2.map((p3) => Number.isNaN(Number(p3)) ? p3 : Number(p3));
330452
+ const padNumber = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(rawPadNumber) ? numericPadNumber : rawPadNumber;
330347
330453
  const center2 = { x: centerX, y: centerY };
330348
330454
  let points;
330349
330455
  if (padShape === "RECT" || padShape === "POLYGON") {
@@ -330359,7 +330465,7 @@ var ShapeItemSchema2 = z179.object({
330359
330465
  height,
330360
330466
  layermask,
330361
330467
  net: net2,
330362
- number,
330468
+ number: padNumber,
330363
330469
  holeRadius,
330364
330470
  points,
330365
330471
  rotation: rotation23,
@@ -330810,7 +330916,7 @@ var OwnerSchema2 = z181.object({
330810
330916
  });
330811
330917
  var HeadSchema2 = z181.object({
330812
330918
  docType: z181.preprocess((val) => val == null ? val : String(val), z181.string()),
330813
- editorVersion: z181.string(),
330919
+ editorVersion: z181.string().default(""),
330814
330920
  c_para: z181.record(z181.string(), z181.string().nullable()),
330815
330921
  x: z181.number(),
330816
330922
  y: z181.number(),
@@ -330825,7 +330931,7 @@ var HeadSchema2 = z181.object({
330825
330931
  }, z181.number()),
330826
330932
  importFlag: z181.number().optional(),
330827
330933
  c_spiceCmd: z181.any().optional(),
330828
- hasIdFlag: z181.boolean()
330934
+ hasIdFlag: z181.boolean().default(false)
330829
330935
  });
330830
330936
  var BBoxSchema2 = z181.object({
330831
330937
  x: z181.number(),
@@ -330850,9 +330956,17 @@ var DataStrSchema2 = z181.object({
330850
330956
  head: HeadSchema2,
330851
330957
  canvas: z181.string(),
330852
330958
  shape: z181.array(SingleLetterShapeSchema2),
330853
- BBox: BBoxSchema2,
330854
- colors: z181.union([z181.array(z181.string()), z181.record(z181.string())])
330855
- });
330959
+ BBox: BBoxSchema2.optional(),
330960
+ colors: z181.union([z181.array(z181.string()), z181.record(z181.string())]).default([])
330961
+ }).transform((data) => ({
330962
+ ...data,
330963
+ BBox: data.BBox ?? {
330964
+ x: data.head.x,
330965
+ y: data.head.y,
330966
+ width: 0,
330967
+ height: 0
330968
+ }
330969
+ }));
330856
330970
  var PackageDetailDataStrSchema2 = z181.object({
330857
330971
  head: HeadSchema2,
330858
330972
  canvas: z181.string(),
package/dist/lib/index.js CHANGED
@@ -65757,7 +65757,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
65757
65757
  }));
65758
65758
  };
65759
65759
  // package.json
65760
- var version = "0.1.1820";
65760
+ var version = "0.1.1821";
65761
65761
  var package_default = {
65762
65762
  name: "@tscircuit/cli",
65763
65763
  version,
@@ -65816,7 +65816,7 @@ var package_default = {
65816
65816
  debug: "^4.4.0",
65817
65817
  delay: "^6.0.0",
65818
65818
  "dsn-converter": "^0.0.90",
65819
- easyeda: "^0.0.275",
65819
+ easyeda: "^0.0.279",
65820
65820
  "fuse.js": "^7.1.0",
65821
65821
  "get-port": "^7.1.0",
65822
65822
  globby: "^14.1.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1821",
3
+ "version": "0.1.1822",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",
@@ -56,7 +56,7 @@
56
56
  "debug": "^4.4.0",
57
57
  "delay": "^6.0.0",
58
58
  "dsn-converter": "^0.0.90",
59
- "easyeda": "^0.0.275",
59
+ "easyeda": "^0.0.279",
60
60
  "fuse.js": "^7.1.0",
61
61
  "get-port": "^7.1.0",
62
62
  "globby": "^14.1.0",