circuit-json-to-kicad 0.0.36 → 0.0.38

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/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { CircuitJson } from 'circuit-json';
2
2
  import { CircuitJsonUtilObjects, cju } from '@tscircuit/circuit-json-util';
3
3
  import { KicadSch, KicadPcb, SchematicSymbol } from 'kicadts';
4
4
  import { Matrix } from 'transformation-matrix';
5
+ import { KicadFootprintMetadata } from '@tscircuit/props';
5
6
 
6
7
  type PaperSize = "A0" | "A1" | "A2" | "A3" | "A4" | "A5";
7
8
  interface PaperDimensions {
@@ -248,6 +249,12 @@ interface KicadLibraryConverterOptions {
248
249
  * Default: true
249
250
  */
250
251
  includeBuiltins?: boolean;
252
+ /**
253
+ * Callback to get KiCad footprint metadata from a component via prop introspection.
254
+ * This allows extracting kicadFootprintMetadata props without rendering the component.
255
+ * Return null if no metadata is available.
256
+ */
257
+ getComponentKicadMetadata?: (filePath: string, componentName: string) => Promise<KicadFootprintMetadata | null>;
251
258
  }
252
259
  interface KicadLibraryConverterOutput {
253
260
  /**
package/dist/index.js CHANGED
@@ -2705,6 +2705,7 @@ var ExtractFootprintsStage = class extends ConverterStage {
2705
2705
  value: "Ref**",
2706
2706
  position: [0, 0, 0],
2707
2707
  layer: "F.SilkS",
2708
+ uuid: generateDeterministicUuid(`${footprintName}-property-Reference`),
2708
2709
  effects: defaultEffects
2709
2710
  }),
2710
2711
  new Property({
@@ -2712,6 +2713,7 @@ var ExtractFootprintsStage = class extends ConverterStage {
2712
2713
  value: "Val**",
2713
2714
  position: [0, 0, 0],
2714
2715
  layer: "F.Fab",
2716
+ uuid: generateDeterministicUuid(`${footprintName}-property-Value`),
2715
2717
  effects: defaultEffects
2716
2718
  }),
2717
2719
  new Property({
@@ -2720,6 +2722,7 @@ var ExtractFootprintsStage = class extends ConverterStage {
2720
2722
  position: [0, 0, 0],
2721
2723
  layer: "F.Fab",
2722
2724
  hidden: true,
2725
+ uuid: generateDeterministicUuid(`${footprintName}-property-Datasheet`),
2723
2726
  effects: defaultEffects
2724
2727
  }),
2725
2728
  new Property({
@@ -2728,6 +2731,9 @@ var ExtractFootprintsStage = class extends ConverterStage {
2728
2731
  position: [0, 0, 0],
2729
2732
  layer: "F.Fab",
2730
2733
  hidden: true,
2734
+ uuid: generateDeterministicUuid(
2735
+ `${footprintName}-property-Description`
2736
+ ),
2731
2737
  effects: defaultEffects
2732
2738
  })
2733
2739
  ];
@@ -2742,9 +2748,14 @@ var ExtractFootprintsStage = class extends ConverterStage {
2742
2748
  }
2743
2749
  footprint.fpTexts = texts;
2744
2750
  const pads = footprint.fpPads ?? [];
2745
- for (const pad of pads) {
2746
- pad.uuid = void 0;
2747
- pad.net = void 0;
2751
+ for (let i = 0; i < pads.length; i++) {
2752
+ const pad = pads[i];
2753
+ if (pad) {
2754
+ pad.uuid = generateDeterministicUuid(
2755
+ `${footprintName}-pad-${pad.number ?? i}`
2756
+ );
2757
+ pad.net = void 0;
2758
+ }
2748
2759
  }
2749
2760
  footprint.fpPads = pads;
2750
2761
  const models = footprint.models ?? [];
@@ -2945,6 +2956,126 @@ function renameKicadFootprint(params) {
2945
2956
  };
2946
2957
  }
2947
2958
 
2959
+ // lib/kicad-library/kicad-library-converter-utils/applyKicadFootprintMetadata.ts
2960
+ import {
2961
+ parseKicadSexpr as parseKicadSexpr3,
2962
+ Footprint as Footprint3,
2963
+ Property as Property2,
2964
+ TextEffects as TextEffects7,
2965
+ TextEffectsFont as TextEffectsFont7
2966
+ } from "kicadts";
2967
+ function applyKicadFootprintMetadata(kicadModString, metadata, footprintName) {
2968
+ try {
2969
+ const parsed = parseKicadSexpr3(kicadModString);
2970
+ const footprint = parsed.find(
2971
+ (node) => node instanceof Footprint3
2972
+ );
2973
+ if (!footprint) {
2974
+ return kicadModString;
2975
+ }
2976
+ if (metadata.version !== void 0) {
2977
+ footprint.version = Number(metadata.version);
2978
+ }
2979
+ if (metadata.generator !== void 0) {
2980
+ footprint.generator = metadata.generator;
2981
+ }
2982
+ if (metadata.generatorVersion !== void 0) {
2983
+ footprint.generatorVersion = String(metadata.generatorVersion);
2984
+ }
2985
+ if (metadata.embeddedFonts !== void 0) {
2986
+ }
2987
+ if (metadata.properties) {
2988
+ const defaultFont = new TextEffectsFont7();
2989
+ defaultFont.size = { width: 1.27, height: 1.27 };
2990
+ defaultFont.thickness = 0.15;
2991
+ const defaultEffects = new TextEffects7({ font: defaultFont });
2992
+ const newProperties = [];
2993
+ const refMeta = metadata.properties.Reference;
2994
+ newProperties.push(
2995
+ new Property2({
2996
+ key: "Reference",
2997
+ value: refMeta?.value ?? "REF**",
2998
+ position: refMeta?.at ? [
2999
+ Number(refMeta.at.x),
3000
+ Number(refMeta.at.y),
3001
+ Number(refMeta.at.rotation ?? 0)
3002
+ ] : [0, 0, 0],
3003
+ layer: refMeta?.layer ?? "F.SilkS",
3004
+ uuid: refMeta?.uuid ?? generateDeterministicUuid(`${footprintName}-property-Reference`),
3005
+ effects: defaultEffects,
3006
+ hidden: refMeta?.hide
3007
+ })
3008
+ );
3009
+ const valMeta = metadata.properties.Value;
3010
+ newProperties.push(
3011
+ new Property2({
3012
+ key: "Value",
3013
+ value: valMeta?.value ?? footprintName,
3014
+ position: valMeta?.at ? [
3015
+ Number(valMeta.at.x),
3016
+ Number(valMeta.at.y),
3017
+ Number(valMeta.at.rotation ?? 0)
3018
+ ] : [0, 0, 0],
3019
+ layer: valMeta?.layer ?? "F.Fab",
3020
+ uuid: valMeta?.uuid ?? generateDeterministicUuid(`${footprintName}-property-Value`),
3021
+ effects: defaultEffects,
3022
+ hidden: valMeta?.hide
3023
+ })
3024
+ );
3025
+ const dsMeta = metadata.properties.Datasheet;
3026
+ newProperties.push(
3027
+ new Property2({
3028
+ key: "Datasheet",
3029
+ value: dsMeta?.value ?? "",
3030
+ position: dsMeta?.at ? [
3031
+ Number(dsMeta.at.x),
3032
+ Number(dsMeta.at.y),
3033
+ Number(dsMeta.at.rotation ?? 0)
3034
+ ] : [0, 0, 0],
3035
+ layer: dsMeta?.layer ?? "F.Fab",
3036
+ uuid: dsMeta?.uuid ?? generateDeterministicUuid(`${footprintName}-property-Datasheet`),
3037
+ effects: defaultEffects,
3038
+ hidden: dsMeta?.hide ?? true
3039
+ })
3040
+ );
3041
+ const descMeta = metadata.properties.Description;
3042
+ newProperties.push(
3043
+ new Property2({
3044
+ key: "Description",
3045
+ value: descMeta?.value ?? "",
3046
+ position: descMeta?.at ? [
3047
+ Number(descMeta.at.x),
3048
+ Number(descMeta.at.y),
3049
+ Number(descMeta.at.rotation ?? 0)
3050
+ ] : [0, 0, 0],
3051
+ layer: descMeta?.layer ?? "F.Fab",
3052
+ uuid: descMeta?.uuid ?? generateDeterministicUuid(`${footprintName}-property-Description`),
3053
+ effects: defaultEffects,
3054
+ hidden: descMeta?.hide ?? true
3055
+ })
3056
+ );
3057
+ footprint.properties = newProperties;
3058
+ }
3059
+ if (metadata.attributes && footprint.attr) {
3060
+ if (metadata.attributes.through_hole) {
3061
+ footprint.attr.type = "through_hole";
3062
+ } else if (metadata.attributes.smd) {
3063
+ footprint.attr.type = "smd";
3064
+ }
3065
+ if (metadata.attributes.exclude_from_pos_files !== void 0) {
3066
+ footprint.attr.excludeFromPosFiles = metadata.attributes.exclude_from_pos_files;
3067
+ }
3068
+ if (metadata.attributes.exclude_from_bom !== void 0) {
3069
+ footprint.attr.excludeFromBom = metadata.attributes.exclude_from_bom;
3070
+ }
3071
+ }
3072
+ return footprint.getString();
3073
+ } catch (error) {
3074
+ console.warn(`Failed to apply kicadFootprintMetadata:`, error);
3075
+ return kicadModString;
3076
+ }
3077
+ }
3078
+
2948
3079
  // lib/kicad-library/stages/ClassifyKicadFootprintsStage.ts
2949
3080
  function classifyKicadFootprints(ctx) {
2950
3081
  for (const extractedKicadComponent of ctx.extractedKicadComponents) {
@@ -2960,17 +3091,28 @@ function classifyFootprintsForComponent({
2960
3091
  }) {
2961
3092
  const { tscircuitComponentName, kicadFootprints } = extractedKicadComponent;
2962
3093
  let hasAddedUserFootprint = false;
3094
+ const metadata = ctx.footprintMetadataMap.get(tscircuitComponentName);
2963
3095
  for (const kicadFootprint of kicadFootprints) {
2964
3096
  if (kicadFootprint.isBuiltin) {
2965
3097
  addBuiltinFootprint({ ctx, kicadFootprint });
2966
3098
  } else {
2967
3099
  if (!hasAddedUserFootprint) {
2968
3100
  hasAddedUserFootprint = true;
2969
- const renamedFootprint = renameKicadFootprint({
3101
+ let renamedFootprint = renameKicadFootprint({
2970
3102
  kicadFootprint,
2971
3103
  newKicadFootprintName: tscircuitComponentName,
2972
3104
  kicadLibraryName: ctx.kicadLibraryName
2973
3105
  });
3106
+ if (metadata) {
3107
+ renamedFootprint = {
3108
+ ...renamedFootprint,
3109
+ kicadModString: applyKicadFootprintMetadata(
3110
+ renamedFootprint.kicadModString,
3111
+ metadata,
3112
+ tscircuitComponentName
3113
+ )
3114
+ };
3115
+ }
2974
3116
  addUserFootprint({ ctx, kicadFootprint: renamedFootprint });
2975
3117
  } else {
2976
3118
  addUserFootprint({ ctx, kicadFootprint });
@@ -3218,7 +3360,8 @@ var KicadLibraryConverter = class {
3218
3360
  this.options = options;
3219
3361
  this.ctx = createKicadLibraryConverterContext({
3220
3362
  kicadLibraryName: options.kicadLibraryName ?? "tscircuit_library",
3221
- includeBuiltins: options.includeBuiltins ?? true
3363
+ includeBuiltins: options.includeBuiltins ?? true,
3364
+ getComponentKicadMetadata: options.getComponentKicadMetadata
3222
3365
  });
3223
3366
  }
3224
3367
  async run() {
@@ -3251,6 +3394,15 @@ var KicadLibraryConverter = class {
3251
3394
  );
3252
3395
  if (resolved) componentPath = resolved;
3253
3396
  }
3397
+ if (this.ctx.getComponentKicadMetadata) {
3398
+ const metadata = await this.ctx.getComponentKicadMetadata(
3399
+ componentPath,
3400
+ exportName
3401
+ );
3402
+ if (metadata) {
3403
+ this.ctx.footprintMetadataMap.set(exportName, metadata);
3404
+ }
3405
+ }
3254
3406
  const circuitJson = await this.options.buildFileToCircuitJson(
3255
3407
  componentPath,
3256
3408
  exportName
@@ -3272,6 +3424,15 @@ var KicadLibraryConverter = class {
3272
3424
  if (resolved) componentPath = resolved;
3273
3425
  }
3274
3426
  const componentName = deriveComponentNameFromPath(componentPath);
3427
+ if (this.ctx.getComponentKicadMetadata) {
3428
+ const metadata = await this.ctx.getComponentKicadMetadata(
3429
+ componentPath,
3430
+ "default"
3431
+ );
3432
+ if (metadata) {
3433
+ this.ctx.footprintMetadataMap.set(componentName, metadata);
3434
+ }
3435
+ }
3275
3436
  const circuitJson = await this.options.buildFileToCircuitJson(
3276
3437
  componentPath,
3277
3438
  "default"
@@ -3325,6 +3486,8 @@ function createKicadLibraryConverterContext(params) {
3325
3486
  return {
3326
3487
  kicadLibraryName: params.kicadLibraryName,
3327
3488
  includeBuiltins: params.includeBuiltins,
3489
+ getComponentKicadMetadata: params.getComponentKicadMetadata,
3490
+ footprintMetadataMap: /* @__PURE__ */ new Map(),
3328
3491
  builtTscircuitComponents: [],
3329
3492
  extractedKicadComponents: [],
3330
3493
  userKicadFootprints: [],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "circuit-json-to-kicad",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.36",
4
+ "version": "0.0.38",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -21,11 +21,11 @@
21
21
  "@types/bun": "latest",
22
22
  "circuit-json": "^0.0.302",
23
23
  "circuit-to-svg": "^0.0.208",
24
- "kicadts": "^0.0.23",
24
+ "kicadts": "^0.0.24",
25
25
  "schematic-symbols": "^0.0.202",
26
26
  "sharp": "^0.34.4",
27
27
  "transformation-matrix": "^3.1.0",
28
- "tscircuit": "^0.0.866",
28
+ "tscircuit": "^0.0.1186",
29
29
  "tsup": "^8.5.0"
30
30
  },
31
31
  "peerDependencies": {