@tscircuit/cli 0.1.2209 → 0.1.2210

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.2208";
154301
+ var version = "0.1.2209";
154302
154302
  var package_default = {
154303
154303
  name: "@tscircuit/cli",
154304
154304
  version,
@@ -154355,7 +154355,7 @@ var package_default = {
154355
154355
  "circuit-json-to-readable-netlist": "^0.0.15",
154356
154356
  "circuit-json-to-spice": "^0.0.45",
154357
154357
  "circuit-json-to-step": "^0.0.38",
154358
- "circuit-json-to-tscircuit": "^0.0.42",
154358
+ "circuit-json-to-tscircuit": "^0.0.50",
154359
154359
  "circuit-json-trace-length-analysis": "github:tscircuit/circuit-json-trace-length-analysis#2b44792a40df0ca83b6bfb6ac95ed5e35e7168b8",
154360
154360
  "circuit-to-canvas": "^0.0.123",
154361
154361
  "circuit-to-svg": "^0.0.430",
@@ -335799,7 +335799,7 @@ var mmStr = (n) => {
335799
335799
  return `${mm3(n)}mm`;
335800
335800
  };
335801
335801
 
335802
- // node_modules/circuit-json-to-tscircuit/dist/chunk-UXTI3RT6.js
335802
+ // node_modules/circuit-json-to-tscircuit/dist/chunk-6TIIS52N.js
335803
335803
  import { su as su122 } from "@tscircuit/soup-util";
335804
335804
  import { su as su13 } from "@tscircuit/soup-util";
335805
335805
  import { su as su24 } from "@tscircuit/soup-util";
@@ -336180,7 +336180,14 @@ var convertSilkscreen = (circuitJson) => {
336180
336180
  const silkscreenCircles = su92(circuitJson).pcb_silkscreen_circle.list();
336181
336181
  const elementStrings = [];
336182
336182
  for (const silkscreenPath of silkscreenPaths) {
336183
- elementStrings.push(`<silkscreenpath route={${JSON.stringify(silkscreenPath.route)}} />`);
336183
+ const attrs = [`route={${JSON.stringify(silkscreenPath.route)}}`];
336184
+ if (silkscreenPath.stroke_width !== undefined) {
336185
+ attrs.push(`strokeWidth={${silkscreenPath.stroke_width}}`);
336186
+ }
336187
+ if (silkscreenPath.layer === "bottom") {
336188
+ attrs.push(`layer="bottom"`);
336189
+ }
336190
+ elementStrings.push(`<silkscreenpath ${attrs.join(" ")} />`);
336184
336191
  }
336185
336192
  for (const silkscreenRect of silkscreenRects) {
336186
336193
  const center = silkscreenRect.center ?? { x: 0, y: 0 };
@@ -336277,7 +336284,7 @@ var convertSmtPads = (circuitJson) => {
336277
336284
  elementStrings.push(`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`);
336278
336285
  } else if (smtPad.shape === "rotated_rect") {
336279
336286
  const cornerRadius = smtPad.corner_radius ?? smtPad.rect_border_radius ?? undefined;
336280
- elementStrings.push(`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("cornerRadius", cornerRadius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="rotated_rect" />`);
336287
+ elementStrings.push(`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("cornerRadius", cornerRadius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}" ccwRotation={${smtPad.ccw_rotation ?? 0}} shape="rotated_rect" />`);
336281
336288
  }
336282
336289
  }
336283
336290
  return elementStrings;
@@ -336555,6 +336562,82 @@ var generateSymbolTsx = (circuitJson) => {
336555
336562
  </symbol>
336556
336563
  `.trim();
336557
336564
  };
336565
+ var attributeNames2 = {
336566
+ is_input: "isInput",
336567
+ is_output: "isOutput",
336568
+ is_bidirectional: "isBidirectional",
336569
+ is_passive: "isPassive",
336570
+ can_use_tri_state: "canUseTriState",
336571
+ is_using_tri_state: "isUsingTriState",
336572
+ can_use_open_collector: "canUseOpenCollector",
336573
+ is_using_open_collector: "isUsingOpenCollector",
336574
+ can_use_open_emitter: "canUseOpenEmitter",
336575
+ is_using_open_emitter: "isUsingOpenEmitter",
336576
+ is_gpio: "isGpio",
336577
+ highlight_color: "highlightColor",
336578
+ must_be_connected: "mustBeConnected",
336579
+ provides_power: "providesPower",
336580
+ requires_power: "requiresPower",
336581
+ provides_ground: "providesGround",
336582
+ requires_ground: "requiresGround",
336583
+ provides_voltage: "providesVoltage",
336584
+ requires_voltage: "requiresVoltage",
336585
+ do_not_connect: "doNotConnect",
336586
+ include_in_board_pinout: "includeInBoardPinout",
336587
+ can_use_internal_pullup: "canUseInternalPullup",
336588
+ is_using_internal_pullup: "isUsingInternalPullup",
336589
+ needs_external_pullup: "needsExternalPullup",
336590
+ can_use_internal_pulldown: "canUseInternalPulldown",
336591
+ is_using_internal_pulldown: "isUsingInternalPulldown",
336592
+ needs_external_pulldown: "needsExternalPulldown",
336593
+ can_use_open_drain: "canUseOpenDrain",
336594
+ is_using_open_drain: "isUsingOpenDrain",
336595
+ can_use_push_pull: "canUsePushPull",
336596
+ is_using_push_pull: "isUsingPushPull",
336597
+ should_have_decoupling_capacitor: "shouldHaveDecouplingCapacitor",
336598
+ recommended_decoupling_capacitor_capacitance: "recommendedDecouplingCapacitorCapacitance"
336599
+ };
336600
+ var capabilities = [
336601
+ "i2c_sda",
336602
+ "i2c_scl",
336603
+ "spi_mosi",
336604
+ "spi_miso",
336605
+ "spi_sck",
336606
+ "spi_cs",
336607
+ "uart_tx",
336608
+ "uart_rx"
336609
+ ];
336610
+ var getPinAttributes = (circuitJson) => {
336611
+ const components = circuitJson.filter((e) => e.type === "source_component");
336612
+ if (components.length > 1)
336613
+ return;
336614
+ const componentId = components[0]?.source_component_id;
336615
+ const pins = /* @__PURE__ */ new Map;
336616
+ for (const port of circuitJson) {
336617
+ if (port.type !== "source_port")
336618
+ continue;
336619
+ if (componentId && port.source_component_id && port.source_component_id !== componentId)
336620
+ continue;
336621
+ const source = { ...port };
336622
+ const attributes = {};
336623
+ for (const [sourceName, propName] of Object.entries(attributeNames2)) {
336624
+ if (source[sourceName] !== undefined) {
336625
+ attributes[propName] = source[sourceName];
336626
+ }
336627
+ }
336628
+ const supported = capabilities.filter((c) => source[`supports_${c}`] === true);
336629
+ const active = capabilities.filter((c) => source[`is_configured_for_${c}`] === true);
336630
+ if (supported.length)
336631
+ attributes.capabilities = supported;
336632
+ if (active.length)
336633
+ attributes.activeCapabilities = active;
336634
+ if (Object.keys(attributes).length === 0)
336635
+ continue;
336636
+ const key = port.pin_number !== undefined ? `pin${port.pin_number}` : port.name;
336637
+ pins.set(key, { ...pins.get(key), ...attributes });
336638
+ }
336639
+ return pins.size ? Object.fromEntries(pins) : undefined;
336640
+ };
336558
336641
  var getComponentUsingTemplate = ({
336559
336642
  pinLabels,
336560
336643
  componentName,
@@ -336565,6 +336648,7 @@ var getComponentUsingTemplate = ({
336565
336648
  }) => {
336566
336649
  const footprintTsx = generateFootprintTsx(circuitJson);
336567
336650
  const symbolTsx = generateSymbolTsx(circuitJson);
336651
+ const pinAttributes = getPinAttributes(circuitJson);
336568
336652
  return `
336569
336653
  import { type ChipProps } from "tscircuit"
336570
336654
  ${pinLabels ? `const pinLabels = ${JSON.stringify(pinLabels, null, " ")} as const
@@ -336573,6 +336657,7 @@ ${pinLabels ? `const pinLabels = ${JSON.stringify(pinLabels, null, " ")} as con
336573
336657
  ${footprintTsx ? `footprint={${footprintTsx}}` : ""}
336574
336658
  ${symbolTsx ? `symbol={${symbolTsx}}` : ""}
336575
336659
  ${pinLabels ? "pinLabels={pinLabels}" : ""}
336660
+ ${pinAttributes ? `pinAttributes={${JSON.stringify(pinAttributes, null, " ")}}` : ""}
336576
336661
  ${objUrl ? `cadModel={{
336577
336662
  objUrl: "${objUrl}",
336578
336663
  rotationOffset: { x: 0, y: 0, z: 0 },
@@ -375180,6 +375265,76 @@ function normalizeManufacturerPartNumber2(partNumber) {
375180
375265
  import fs66 from "node:fs/promises";
375181
375266
  import path75 from "node:path";
375182
375267
 
375268
+ // lib/import/fetch-datasheet-pin-attributes.ts
375269
+ import { commonComponentProps as commonComponentProps2 } from "@tscircuit/props";
375270
+ import { z as z204 } from "zod";
375271
+ var responseSchema = z204.object({
375272
+ datasheet: z204.object({
375273
+ chip_name: z204.string(),
375274
+ pin_attributes: commonComponentProps2.shape.pinAttributes.nullable()
375275
+ })
375276
+ });
375277
+ var normalizeChipName = (name) => name.replace(/[^0-9a-zA-Z_-]/g, "").toLowerCase();
375278
+ var fetchDatasheetPinAttributes = async (manufacturerPartNumber) => {
375279
+ if (!manufacturerPartNumber)
375280
+ return;
375281
+ const chipName = normalizeChipName(manufacturerPartNumber);
375282
+ if (!/[a-z0-9]/.test(chipName))
375283
+ return;
375284
+ const signal = AbortSignal.timeout(5000);
375285
+ try {
375286
+ const url = new URL(`${getRegistryApiUrl().replace(/\/$/, "")}/datasheets/get`);
375287
+ url.searchParams.set("chip_name", chipName);
375288
+ const response = await fetch(url, { signal });
375289
+ if (response.status === 404)
375290
+ return;
375291
+ if (!response.ok)
375292
+ throw new Error(`HTTP ${response.status}`);
375293
+ const parsed = responseSchema.safeParse(await response.json());
375294
+ if (!parsed.success)
375295
+ throw new Error("invalid datasheet response");
375296
+ const { datasheet } = parsed.data;
375297
+ if (normalizeChipName(datasheet.chip_name) !== chipName) {
375298
+ throw new Error("datasheet manufacturer part number does not match");
375299
+ }
375300
+ return datasheet.pin_attributes ?? undefined;
375301
+ } catch (error) {
375302
+ const message = signal.aborted || error instanceof Error && error.name === "TimeoutError" ? `Datasheet API did not respond within 5 seconds for ${manufacturerPartNumber}` : `Could not load datasheet pin attributes for ${manufacturerPartNumber}: ${error instanceof Error ? error.message : "request failed"}`;
375303
+ console.warn(`${message}. pinAttributes may not be populated. Continuing with imported attributes.`);
375304
+ return;
375305
+ }
375306
+ };
375307
+
375308
+ // lib/import/add-datasheet-attributes-to-circuit-json.ts
375309
+ var addDatasheetAttributesToCircuitJson = (circuitJson, pinAttributes) => {
375310
+ const components = circuitJson.filter((element) => element.type === "source_component");
375311
+ if (components.length !== 1)
375312
+ return circuitJson;
375313
+ return circuitJson.map((element) => {
375314
+ if (element.type !== "source_port" || element.source_component_id !== components[0].source_component_id)
375315
+ return element;
375316
+ const pinKey = element.pin_number !== undefined ? `pin${element.pin_number}` : element.name;
375317
+ const keys = new Set([...element.port_hints ?? [], element.name]);
375318
+ keys.delete(pinKey);
375319
+ keys.add(pinKey);
375320
+ const attributes = Object.assign({}, ...[...keys].map((key) => pinAttributes[key]));
375321
+ const sourceAttributes = {};
375322
+ for (const [key, value] of Object.entries(attributes)) {
375323
+ if (value === undefined)
375324
+ continue;
375325
+ if (key === "capabilities" || key === "activeCapabilities" || key === "activeCapability") {
375326
+ const prefix = key === "capabilities" ? "supports_" : "is_configured_for_";
375327
+ for (const capability of Array.isArray(value) ? value : [value]) {
375328
+ sourceAttributes[`${prefix}${capability}`] = true;
375329
+ }
375330
+ } else {
375331
+ sourceAttributes[key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)] = value;
375332
+ }
375333
+ }
375334
+ return { ...element, ...sourceAttributes };
375335
+ });
375336
+ };
375337
+
375183
375338
  // lib/import/add-cad-model-to-tsx.ts
375184
375339
  var addCadModelToTsx = (tsx, cadModel, cadComponent) => {
375185
375340
  if (tsx.includes("cadModel={{") || !cadModel.objUrl && !cadModel.stepUrl) {
@@ -375411,11 +375566,35 @@ var importComponentFromJlcpcb = async (jlcpcbPartNumber, projectDir = process.cw
375411
375566
  const rawEasy = await fetchEasyEDAComponent(jlcpcbPartNumber);
375412
375567
  const betterEasy = EasyEdaJsonSchema2.parse(rawEasy);
375413
375568
  const rawPn = betterEasy.dataStr.head.c_para["Manufacturer Part"];
375569
+ const datasheetAttributesPromise = options.excludePinAttributes ? undefined : fetchDatasheetPinAttributes(rawPn);
375414
375570
  const componentName = rawPn ? normalizeManufacturerPartNumber2(rawPn) : jlcpcbPartNumber;
375415
- let tsx = await convertRawEasyToTsx({ rawEasy });
375416
- const circuitJson = convertEasyEdaJsonToCircuitJson2(betterEasy, {
375571
+ let circuitJson = convertEasyEdaJsonToCircuitJson2(betterEasy, {
375417
375572
  useModelCdn: true
375418
375573
  });
375574
+ const datasheetAttributes = await datasheetAttributesPromise;
375575
+ let tsx;
375576
+ if (datasheetAttributes && Object.keys(datasheetAttributes).length > 0) {
375577
+ circuitJson = addDatasheetAttributesToCircuitJson(circuitJson, datasheetAttributes);
375578
+ const pinLabels = Object.fromEntries(circuitJson.flatMap((element) => {
375579
+ if (element.type !== "source_port")
375580
+ return [];
375581
+ const pinKey = element.pin_number !== undefined ? `pin${element.pin_number}` : element.name;
375582
+ return [
375583
+ [
375584
+ pinKey,
375585
+ (element.port_hints ?? [element.name]).filter((label) => label !== pinKey)
375586
+ ]
375587
+ ];
375588
+ }));
375589
+ tsx = convertCircuitJsonToTscircuit(circuitJson, {
375590
+ componentName,
375591
+ pinLabels,
375592
+ manufacturerPartNumber: rawPn ?? undefined,
375593
+ supplierPartNumbers: { jlcpcb: [jlcpcbPartNumber] }
375594
+ });
375595
+ } else {
375596
+ tsx = await convertRawEasyToTsx({ rawEasy });
375597
+ }
375419
375598
  const footprintConversion = options.useExactFootprint ? { mode: "exact-requested", tsx } : convertImportedFootprintToFootprinter({
375420
375599
  circuitJson,
375421
375600
  sourceHints: getEasyEdaFootprinterSourceHints(rawEasy),
@@ -375465,7 +375644,8 @@ var logFootprintConversion = (conversion) => {
375465
375644
  var importJlcpcbPart = async ({
375466
375645
  download,
375467
375646
  partNumber,
375468
- useExactFootprint
375647
+ useExactFootprint,
375648
+ excludePinAttributes
375469
375649
  }) => {
375470
375650
  const spinner = ora({
375471
375651
  text: `Importing "${partNumber}" from JLCPCB...`,
@@ -375474,7 +375654,8 @@ var importJlcpcbPart = async ({
375474
375654
  try {
375475
375655
  const { filePath, footprintConversion } = await importComponentFromJlcpcb(partNumber, process.cwd(), {
375476
375656
  download,
375477
- useExactFootprint
375657
+ useExactFootprint,
375658
+ excludePinAttributes
375478
375659
  });
375479
375660
  spinner.succeed(kleur_default.green(`Imported ${filePath}`));
375480
375661
  logFootprintConversion(footprintConversion);
@@ -375496,7 +375677,7 @@ var parseDirectLcscPartNumber = (query) => {
375496
375677
 
375497
375678
  // cli/import/register.ts
375498
375679
  var registerImport = (program) => {
375499
- program.command("import").description("Search JLCPCB or the tscircuit registry and import a component").argument("<query...>", "Chip name, part number, or package name").option("--jlcpcb", "Search JLCPCB components").option("--lcsc", "Alias for --jlcpcb").option("--tscircuit", "Search tscircuit registry packages").option("--download", "Download 3D model assets (.step, .obj) locally").option("--use-exact-footprint", "Keep the exact EasyEDA footprint instead of using a >98% footprinter match").action(async (queryParts, opts) => {
375680
+ program.command("import").description("Search JLCPCB or the tscircuit registry and import a component").argument("<query...>", "Chip name, part number, or package name").option("--jlcpcb", "Search JLCPCB components").option("--lcsc", "Alias for --jlcpcb").option("--tscircuit", "Search tscircuit registry packages").option("--download", "Download 3D model assets (.step, .obj) locally").option("--exclude-pin-attributes", "Skip datasheet pin attributes when importing").option("--use-exact-footprint", "Keep the exact EasyEDA footprint instead of using a >98% footprinter match").action(async (queryParts, opts) => {
375500
375681
  const query = getQueryFromParts(queryParts);
375501
375682
  const hasFilters = opts.jlcpcb || opts.lcsc || opts.tscircuit;
375502
375683
  const searchJlc = opts.jlcpcb || opts.lcsc || !hasFilters;
@@ -375536,7 +375717,8 @@ var registerImport = (program) => {
375536
375717
  await importJlcpcbPart({
375537
375718
  download: opts.download,
375538
375719
  partNumber: directLcscPartNumber,
375539
- useExactFootprint: opts.useExactFootprint
375720
+ useExactFootprint: opts.useExactFootprint,
375721
+ excludePinAttributes: opts.excludePinAttributes
375540
375722
  });
375541
375723
  return;
375542
375724
  }
@@ -375586,7 +375768,8 @@ var registerImport = (program) => {
375586
375768
  await importJlcpcbPart({
375587
375769
  download: opts.download,
375588
375770
  partNumber: `C${String(choice.part)}`,
375589
- useExactFootprint: opts.useExactFootprint
375771
+ useExactFootprint: opts.useExactFootprint,
375772
+ excludePinAttributes: opts.excludePinAttributes
375590
375773
  });
375591
375774
  }
375592
375775
  });
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.2208";
69112
+ var version = "0.1.2209";
69113
69113
  var package_default = {
69114
69114
  name: "@tscircuit/cli",
69115
69115
  version,
@@ -69166,7 +69166,7 @@ var package_default = {
69166
69166
  "circuit-json-to-readable-netlist": "^0.0.15",
69167
69167
  "circuit-json-to-spice": "^0.0.45",
69168
69168
  "circuit-json-to-step": "^0.0.38",
69169
- "circuit-json-to-tscircuit": "^0.0.42",
69169
+ "circuit-json-to-tscircuit": "^0.0.50",
69170
69170
  "circuit-json-trace-length-analysis": "github:tscircuit/circuit-json-trace-length-analysis#2b44792a40df0ca83b6bfb6ac95ed5e35e7168b8",
69171
69171
  "circuit-to-canvas": "^0.0.123",
69172
69172
  "circuit-to-svg": "^0.0.430",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.2209",
3
+ "version": "0.1.2210",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/tscircuit/cli"
@@ -54,7 +54,7 @@
54
54
  "circuit-json-to-readable-netlist": "^0.0.15",
55
55
  "circuit-json-to-spice": "^0.0.45",
56
56
  "circuit-json-to-step": "^0.0.38",
57
- "circuit-json-to-tscircuit": "^0.0.42",
57
+ "circuit-json-to-tscircuit": "^0.0.50",
58
58
  "circuit-json-trace-length-analysis": "github:tscircuit/circuit-json-trace-length-analysis#2b44792a40df0ca83b6bfb6ac95ed5e35e7168b8",
59
59
  "circuit-to-canvas": "^0.0.123",
60
60
  "circuit-to-svg": "^0.0.430",