@tscircuit/cli 0.1.1054 → 0.1.1056

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
@@ -71664,7 +71664,7 @@ var registerStaticAssetLoaders = () => {
71664
71664
  // cli/main.ts
71665
71665
  var import_perfect_cli = __toESM2(require_dist2(), 1);
71666
71666
  // package.json
71667
- var version = "0.1.1053";
71667
+ var version = "0.1.1055";
71668
71668
  var package_default = {
71669
71669
  name: "@tscircuit/cli",
71670
71670
  version,
@@ -71676,7 +71676,7 @@ var package_default = {
71676
71676
  devDependencies: {
71677
71677
  "@babel/standalone": "^7.26.9",
71678
71678
  "@biomejs/biome": "^1.9.4",
71679
- "@tscircuit/circuit-json-placement-analysis": "^0.0.1",
71679
+ "@tscircuit/circuit-json-placement-analysis": "^0.0.4",
71680
71680
  "@tscircuit/circuit-json-util": "0.0.81",
71681
71681
  "@tscircuit/fake-snippets": "^0.0.182",
71682
71682
  "@tscircuit/file-server": "^0.0.32",
@@ -82887,6 +82887,66 @@ var getComponentToBoardCalcString = (componentName, direction, distance) => {
82887
82887
  return `${componentName}.centerY=calc(board.centerY+${d})`;
82888
82888
  }
82889
82889
  };
82890
+ var getPadBounds = (element) => {
82891
+ if (element.type === "pcb_smtpad") {
82892
+ const x = toNumber2(element.x);
82893
+ const y = toNumber2(element.y);
82894
+ const width = toNumber2(element.width);
82895
+ const height = toNumber2(element.height);
82896
+ if (x === null || y === null || width === null || height === null)
82897
+ return null;
82898
+ return {
82899
+ minX: x - width / 2,
82900
+ maxX: x + width / 2,
82901
+ minY: y - height / 2,
82902
+ maxY: y + height / 2
82903
+ };
82904
+ }
82905
+ if (element.type === "pcb_plated_hole") {
82906
+ const x = toNumber2(element.x);
82907
+ const y = toNumber2(element.y);
82908
+ const rectPadWidth = toNumber2(element.rect_pad_width);
82909
+ const rectPadHeight = toNumber2(element.rect_pad_height);
82910
+ const holeDiameter = toNumber2(element.hole_diameter);
82911
+ if (x === null || y === null)
82912
+ return null;
82913
+ const width = rectPadWidth ?? holeDiameter;
82914
+ const height = rectPadHeight ?? holeDiameter;
82915
+ if (width === null || height === null)
82916
+ return null;
82917
+ return {
82918
+ minX: x - width / 2,
82919
+ maxX: x + width / 2,
82920
+ minY: y - height / 2,
82921
+ maxY: y + height / 2
82922
+ };
82923
+ }
82924
+ return null;
82925
+ };
82926
+ var getBoundsClearance = (a, b) => {
82927
+ const dx = Math.max(0, a.minX - b.maxX, b.minX - a.maxX);
82928
+ const dy = Math.max(0, a.minY - b.maxY, b.minY - a.maxY);
82929
+ return Math.hypot(dx, dy);
82930
+ };
82931
+ var getPadDisplayName = (pad, componentName, sourcePortNameByPcbPortId) => {
82932
+ const pcbPortId = typeof pad.pcb_port_id === "string" ? pad.pcb_port_id : null;
82933
+ if (pcbPortId) {
82934
+ const sourcePortName = sourcePortNameByPcbPortId.get(pcbPortId);
82935
+ if (sourcePortName)
82936
+ return `${componentName}.${sourcePortName}`;
82937
+ }
82938
+ if (Array.isArray(pad.port_hints)) {
82939
+ const pinHint = pad.port_hints.find((hint) => typeof hint === "string" && /^pin\d+$/i.test(hint));
82940
+ if (typeof pinHint === "string")
82941
+ return `${componentName}.${pinHint}`;
82942
+ const numericHint = pad.port_hints.find((hint) => typeof hint === "string" && /^\d+$/.test(hint));
82943
+ if (typeof numericHint === "string")
82944
+ return `${componentName}.pin${numericHint}`;
82945
+ }
82946
+ if (pcbPortId)
82947
+ return `${componentName}.${pcbPortId}`;
82948
+ return `${componentName}.pad`;
82949
+ };
82890
82950
  var getDirectionAndDistance = (fromX, fromY, toX, toY) => {
82891
82951
  const dx = toX - fromX;
82892
82952
  const dy = toY - fromY;
@@ -82903,6 +82963,13 @@ var getDirectionAndDistance = (fromX, fromY, toX, toY) => {
82903
82963
  axis: "y"
82904
82964
  };
82905
82965
  };
82966
+ var getPinCenter = (pad) => {
82967
+ const x = toNumber2(pad.x);
82968
+ const y = toNumber2(pad.y);
82969
+ if (x === null || y === null)
82970
+ return null;
82971
+ return { x, y };
82972
+ };
82906
82973
  var lineItemToString = (lineItem) => {
82907
82974
  switch (lineItem.line_item_type) {
82908
82975
  case "absolute_component_position":
@@ -82933,6 +83000,10 @@ var lineItemToString = (lineItem) => {
82933
83000
  return `${lineItem.component_name}.orientation=${lineItem.orientation}`;
82934
83001
  case "relative_component_edge_to_board_edge_position":
82935
83002
  return `${lineItem.component_name}.${lineItem.component_edge}=calc(${lineItem.board_edge}${withSignedMm(lineItem.offset)})${isOffBoardEdgeOffset(lineItem.board_edge, lineItem.offset) ? " [offboard]" : ""}`;
83003
+ case "component_pad_clearance":
83004
+ return `${lineItem.component_name}.padClearance=${fmtMm(lineItem.clearance)} [nearest=${lineItem.nearest_pad_name}]`;
83005
+ case "direct_pin_to_pin_distance":
83006
+ return `${lineItem.from_pin_name} -> ${lineItem.to_pin_name} distance: ${fmtMm(lineItem.distance)}`;
82936
83007
  default:
82937
83008
  return "";
82938
83009
  }
@@ -83076,6 +83147,151 @@ var analyzeComponentPlacement = (circuitJson, componentName) => {
83076
83147
  };
83077
83148
  lineItems.push(boardLineItem);
83078
83149
  }
83150
+ const sourcePortNameByPcbPortId = /* @__PURE__ */ new Map;
83151
+ for (const el of circuitJson) {
83152
+ if (el.type === "pcb_port" && typeof el.pcb_port_id === "string" && typeof el.source_port_id === "string") {
83153
+ const sourcePort = circuitJson.find((candidate) => candidate.type === "source_port" && candidate.source_port_id === el.source_port_id && typeof candidate.name === "string");
83154
+ if (sourcePort && typeof sourcePort.name === "string") {
83155
+ sourcePortNameByPcbPortId.set(el.pcb_port_id, sourcePort.name);
83156
+ }
83157
+ }
83158
+ }
83159
+ const sourcePortById = /* @__PURE__ */ new Map;
83160
+ for (const el of circuitJson) {
83161
+ if (el.type === "source_port" && typeof el.source_port_id === "string") {
83162
+ sourcePortById.set(el.source_port_id, el);
83163
+ }
83164
+ }
83165
+ const sourcePortDisplayNameById = /* @__PURE__ */ new Map;
83166
+ for (const el of circuitJson) {
83167
+ if (el.type === "source_port" && typeof el.source_port_id === "string") {
83168
+ if (typeof el.source_component_id === "string" && typeof el.name === "string") {
83169
+ const sourceComp = circuitJson.find((candidate) => candidate.type === "source_component" && candidate.source_component_id === el.source_component_id && typeof candidate.name === "string");
83170
+ if (sourceComp && typeof sourceComp.name === "string") {
83171
+ sourcePortDisplayNameById.set(el.source_port_id, `${sourceComp.name}.${el.name}`);
83172
+ continue;
83173
+ }
83174
+ }
83175
+ if (typeof el.name === "string") {
83176
+ sourcePortDisplayNameById.set(el.source_port_id, el.name);
83177
+ }
83178
+ }
83179
+ }
83180
+ const padBySourcePortId = /* @__PURE__ */ new Map;
83181
+ if (typeof pcbComponent?.pcb_component_id === "string") {
83182
+ for (const el of circuitJson) {
83183
+ if ((el.type === "pcb_smtpad" || el.type === "pcb_plated_hole") && typeof el.pcb_component_id === "string" && typeof el.pcb_port_id === "string") {
83184
+ const pcbPort = circuitJson.find((candidate) => candidate.type === "pcb_port" && candidate.pcb_port_id === el.pcb_port_id && typeof candidate.source_port_id === "string");
83185
+ if (!pcbPort || typeof pcbPort.source_port_id !== "string")
83186
+ continue;
83187
+ const center2 = getPinCenter(el);
83188
+ if (!center2)
83189
+ continue;
83190
+ const sourcePort = sourcePortById.get(pcbPort.source_port_id);
83191
+ const sourcePortComponentId = typeof sourcePort?.source_component_id === "string" ? sourcePort.source_component_id : null;
83192
+ if (sourcePortComponentId !== sourceComponentId)
83193
+ continue;
83194
+ padBySourcePortId.set(pcbPort.source_port_id, {
83195
+ pad: el,
83196
+ padName: getPadDisplayName(el, componentName, sourcePortNameByPcbPortId),
83197
+ center: center2
83198
+ });
83199
+ }
83200
+ }
83201
+ }
83202
+ const directPinDistanceLineItems = [];
83203
+ for (const fromPortId of padBySourcePortId.keys()) {
83204
+ const directPinToPinTraces = circuitJson.filter((el) => el.type === "source_trace" && Array.isArray(el.connected_source_port_ids) && el.connected_source_port_ids.length === 2 && el.connected_source_port_ids.includes(fromPortId) && Array.isArray(el.connected_source_net_ids) && el.connected_source_net_ids.length === 0);
83205
+ if (directPinToPinTraces.length !== 1)
83206
+ continue;
83207
+ const trace = directPinToPinTraces[0];
83208
+ if (!trace)
83209
+ continue;
83210
+ const connectedPortIds = Array.isArray(trace.connected_source_port_ids) ? trace.connected_source_port_ids.filter((value) => typeof value === "string") : [];
83211
+ const otherPortId = connectedPortIds.find((portId) => portId !== fromPortId);
83212
+ if (!otherPortId)
83213
+ continue;
83214
+ const fromPin = padBySourcePortId.get(fromPortId);
83215
+ if (!fromPin)
83216
+ continue;
83217
+ const otherPcbPort = circuitJson.find((candidate) => candidate.type === "pcb_port" && candidate.source_port_id === otherPortId && typeof candidate.pcb_port_id === "string");
83218
+ if (!otherPcbPort || typeof otherPcbPort.pcb_port_id !== "string")
83219
+ continue;
83220
+ const otherPad = circuitJson.find((candidate) => (candidate.type === "pcb_smtpad" || candidate.type === "pcb_plated_hole") && candidate.pcb_port_id === otherPcbPort.pcb_port_id);
83221
+ if (!otherPad)
83222
+ continue;
83223
+ const otherCenter = getPinCenter(otherPad);
83224
+ if (!otherCenter)
83225
+ continue;
83226
+ const fromPortDisplayName = sourcePortDisplayNameById.get(fromPortId);
83227
+ const toPortDisplayName = sourcePortDisplayNameById.get(otherPortId);
83228
+ if (!fromPortDisplayName || !toPortDisplayName)
83229
+ continue;
83230
+ directPinDistanceLineItems.push({
83231
+ line_item_type: "direct_pin_to_pin_distance",
83232
+ component_name: componentName,
83233
+ from_pin_name: fromPortDisplayName,
83234
+ to_pin_name: toPortDisplayName,
83235
+ distance: Math.hypot(otherCenter.x - fromPin.center.x, otherCenter.y - fromPin.center.y)
83236
+ });
83237
+ }
83238
+ lineItems.push(...directPinDistanceLineItems);
83239
+ const componentPadBounds = typeof pcbComponent?.pcb_component_id === "string" ? circuitJson.filter((el) => (el.type === "pcb_smtpad" || el.type === "pcb_plated_hole") && el.pcb_component_id === pcbComponent.pcb_component_id).map((pad) => {
83240
+ const bounds = getPadBounds(pad);
83241
+ if (!bounds)
83242
+ return null;
83243
+ return {
83244
+ bounds,
83245
+ padName: getPadDisplayName(pad, componentName, sourcePortNameByPcbPortId)
83246
+ };
83247
+ }).filter((pad) => pad !== null) : [];
83248
+ if (componentPadBounds.length > 0 && typeof pcbComponent?.pcb_component_id === "string") {
83249
+ const sourceComponentNameByPcbComponentId = /* @__PURE__ */ new Map;
83250
+ for (const el of circuitJson) {
83251
+ if (el.type === "pcb_component" && typeof el.pcb_component_id === "string" && typeof el.source_component_id === "string") {
83252
+ const sourceName = circuitJson.find((candidate) => candidate.type === "source_component" && candidate.source_component_id === el.source_component_id && typeof candidate.name === "string");
83253
+ if (sourceName && typeof sourceName.name === "string") {
83254
+ sourceComponentNameByPcbComponentId.set(el.pcb_component_id, sourceName.name);
83255
+ }
83256
+ }
83257
+ }
83258
+ const otherComponentPadBounds = circuitJson.filter((el) => (el.type === "pcb_smtpad" || el.type === "pcb_plated_hole") && typeof el.pcb_component_id === "string" && el.pcb_component_id !== pcbComponent.pcb_component_id).map((el) => {
83259
+ const bounds = getPadBounds(el);
83260
+ if (!bounds)
83261
+ return null;
83262
+ const otherComponentName = sourceComponentNameByPcbComponentId.get(el.pcb_component_id);
83263
+ if (!otherComponentName)
83264
+ return null;
83265
+ return {
83266
+ bounds,
83267
+ componentName: otherComponentName,
83268
+ padName: getPadDisplayName(el, otherComponentName, sourcePortNameByPcbPortId)
83269
+ };
83270
+ }).filter((entry) => entry !== null);
83271
+ let nearestPadClearance = null;
83272
+ for (const ownPad of componentPadBounds) {
83273
+ for (const otherPad of otherComponentPadBounds) {
83274
+ const clearance = getBoundsClearance(ownPad.bounds, otherPad.bounds);
83275
+ if (!nearestPadClearance || clearance < nearestPadClearance.clearance) {
83276
+ nearestPadClearance = {
83277
+ clearance,
83278
+ componentName: otherPad.componentName,
83279
+ padName: otherPad.padName
83280
+ };
83281
+ }
83282
+ }
83283
+ }
83284
+ if (nearestPadClearance) {
83285
+ const padClearanceLineItem = {
83286
+ line_item_type: "component_pad_clearance",
83287
+ component_name: componentName,
83288
+ clearance: nearestPadClearance.clearance,
83289
+ nearest_component_name: nearestPadClearance.componentName,
83290
+ nearest_pad_name: nearestPadClearance.padName
83291
+ };
83292
+ lineItems.push(padClearanceLineItem);
83293
+ }
83294
+ }
83079
83295
  if (centerX !== null && centerY !== null) {
83080
83296
  const sourceComponentsById = /* @__PURE__ */ new Map;
83081
83297
  for (const el of circuitJson) {
@@ -177307,7 +177523,7 @@ Fuse2.config = Config;
177307
177523
 
177308
177524
  // cli/search/register.ts
177309
177525
  var registerSearch = (program3) => {
177310
- program3.command("search").description("Search for footprints, CAD models or packages in the tscircuit ecosystem").argument("<query>", "Search query (e.g. keyword, author, or package name)").option("--kicad", "Search KiCad footprints").option("--jlcpcb", "Search JLCPCB components").option("--lcsc", "Alias for --jlcpcb").option("--tscircuit", "Search tscircuit registry packages").action(async (query, opts) => {
177526
+ program3.command("search").description("Search for footprints, CAD models or packages in the tscircuit ecosystem").argument("<query>", "Search query (e.g. keyword, author, or package name)").option("--kicad", "Search KiCad footprints").option("--jlcpcb", "Search JLCPCB components").option("--lcsc", "Alias for --jlcpcb").option("--tscircuit", "Search tscircuit registry packages").option("--json", "Output search results as JSON").action(async (query, opts) => {
177311
177527
  const hasFilters = opts.kicad || opts.jlcpcb || opts.lcsc || opts.tscircuit;
177312
177528
  const searchKicad = opts.kicad || !hasFilters;
177313
177529
  const searchJlc = opts.jlcpcb || opts.lcsc || !hasFilters;
@@ -177336,6 +177552,27 @@ var registerSearch = (program3) => {
177336
177552
  console.error(kleur_default.red("Failed to search registry:"), error instanceof Error ? error.message : error);
177337
177553
  process.exit(1);
177338
177554
  }
177555
+ if (opts.json) {
177556
+ const unifiedResults = [
177557
+ ...kicadResults.map((path62) => ({
177558
+ source: "kicad",
177559
+ path: path62
177560
+ })),
177561
+ ...results.packages.map((pkg) => ({
177562
+ source: "tscircuit",
177563
+ ...pkg
177564
+ })),
177565
+ ...jlcResults.map((comp) => ({
177566
+ source: "jlcpcb",
177567
+ ...comp
177568
+ }))
177569
+ ];
177570
+ console.log(JSON.stringify({
177571
+ query,
177572
+ results: unifiedResults
177573
+ }, null, 2));
177574
+ return;
177575
+ }
177339
177576
  if (!kicadResults.length && !results.packages.length && !jlcResults.length) {
177340
177577
  const sources = [
177341
177578
  searchTscircuit && "tscircuit registry",
package/dist/lib/index.js CHANGED
@@ -60435,7 +60435,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
60435
60435
  }));
60436
60436
  };
60437
60437
  // package.json
60438
- var version = "0.1.1053";
60438
+ var version = "0.1.1055";
60439
60439
  var package_default = {
60440
60440
  name: "@tscircuit/cli",
60441
60441
  version,
@@ -60447,7 +60447,7 @@ var package_default = {
60447
60447
  devDependencies: {
60448
60448
  "@babel/standalone": "^7.26.9",
60449
60449
  "@biomejs/biome": "^1.9.4",
60450
- "@tscircuit/circuit-json-placement-analysis": "^0.0.1",
60450
+ "@tscircuit/circuit-json-placement-analysis": "^0.0.4",
60451
60451
  "@tscircuit/circuit-json-util": "0.0.81",
60452
60452
  "@tscircuit/fake-snippets": "^0.0.182",
60453
60453
  "@tscircuit/file-server": "^0.0.32",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1054",
3
+ "version": "0.1.1056",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",
@@ -9,7 +9,7 @@
9
9
  "devDependencies": {
10
10
  "@babel/standalone": "^7.26.9",
11
11
  "@biomejs/biome": "^1.9.4",
12
- "@tscircuit/circuit-json-placement-analysis": "^0.0.1",
12
+ "@tscircuit/circuit-json-placement-analysis": "^0.0.4",
13
13
  "@tscircuit/circuit-json-util": "0.0.81",
14
14
  "@tscircuit/fake-snippets": "^0.0.182",
15
15
  "@tscircuit/file-server": "^0.0.32",