circuit-json-to-kicad 0.0.39 → 0.0.41

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
@@ -255,6 +255,21 @@ interface KicadLibraryConverterOptions {
255
255
  * Return null if no metadata is available.
256
256
  */
257
257
  getComponentKicadMetadata?: (filePath: string, componentName: string) => Promise<KicadFootprintMetadata | null>;
258
+ /**
259
+ * Whether to generate files for KiCad PCM (Plugin and Content Manager).
260
+ * When true:
261
+ * - Footprint references in symbols will be prefixed with "PCM_"
262
+ * - 3D model paths will use ${KICAD_3RD_PARTY} variable instead of relative paths
263
+ * Default: false
264
+ */
265
+ isPcm?: boolean;
266
+ /**
267
+ * The KiCad PCM package identifier (e.g., "com_tscircuit_author_package-name").
268
+ * Required when useKicadPcmPaths is true.
269
+ * Used to construct 3D model paths like:
270
+ * ${KICAD9_3RD_PARTY}/3dmodels/<kicadPcmPackageId>/<library>.3dshapes/<model>.step
271
+ */
272
+ kicadPcmPackageId?: string;
258
273
  }
259
274
  interface KicadLibraryConverterOutput {
260
275
  /**
package/dist/index.js CHANGED
@@ -101,6 +101,50 @@ function extractReferencePrefix(name) {
101
101
  const match = name.match(/^([A-Za-z]+)/);
102
102
  return match?.[1]?.toUpperCase() ?? "U";
103
103
  }
104
+ var referencePrefixByFtype = {
105
+ simple_resistor: "R",
106
+ simple_capacitor: "C",
107
+ simple_inductor: "L",
108
+ simple_diode: "D",
109
+ simple_led: "D",
110
+ simple_chip: "U",
111
+ simple_transistor: "Q",
112
+ simple_mosfet: "Q",
113
+ simple_fuse: "F",
114
+ simple_switch: "SW",
115
+ simple_push_button: "SW",
116
+ simple_potentiometer: "RV",
117
+ simple_crystal: "Y",
118
+ simple_resonator: "Y",
119
+ simple_pin_header: "J",
120
+ simple_pinout: "J",
121
+ simple_test_point: "TP",
122
+ simple_battery: "BT"
123
+ };
124
+ var referenceDesignatorPattern = /^[A-Za-z]+\\d+$/;
125
+ function isReferenceDesignator(value) {
126
+ if (!value) return false;
127
+ return referenceDesignatorPattern.test(value.trim());
128
+ }
129
+ function getReferencePrefixForComponent(sourceComponent) {
130
+ const name = sourceComponent?.name;
131
+ if (isReferenceDesignator(name)) {
132
+ return extractReferencePrefix(name);
133
+ }
134
+ const ftype = sourceComponent?.ftype;
135
+ if (ftype && referencePrefixByFtype[ftype]) {
136
+ return referencePrefixByFtype[ftype];
137
+ }
138
+ return extractReferencePrefix(name);
139
+ }
140
+ function getReferenceDesignator(sourceComponent) {
141
+ const name = sourceComponent?.name;
142
+ if (isReferenceDesignator(name)) {
143
+ return name.trim();
144
+ }
145
+ const prefix = getReferencePrefixForComponent(sourceComponent);
146
+ return `${prefix}?`;
147
+ }
104
148
 
105
149
  // lib/schematic/getLibraryId.ts
106
150
  import { symbols } from "schematic-symbols";
@@ -127,7 +171,7 @@ function getLibraryId(sourceComp, schematicComp, cadComponent) {
127
171
  sourceComp,
128
172
  cadComponent
129
173
  );
130
- const refPrefix = extractReferencePrefix(sourceComp.name);
174
+ const refPrefix = getReferencePrefixForComponent(sourceComp);
131
175
  return `Device:${refPrefix}_${ergonomicName}`;
132
176
  }
133
177
 
@@ -197,7 +241,8 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
197
241
  description: this.getDescription(sourceComp),
198
242
  keywords: this.getKeywords(sourceComp),
199
243
  fpFilters: this.getFpFilters(sourceComp),
200
- footprintRef: footprintName ? `tscircuit:${footprintName}` : ""
244
+ footprintRef: footprintName ? `tscircuit:${footprintName}` : "",
245
+ referencePrefix: getReferencePrefixForComponent(sourceComp)
201
246
  });
202
247
  }
203
248
  /**
@@ -220,7 +265,8 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
220
265
  schematicComponent: void 0,
221
266
  description: isPower ? "Power net label" : isGround ? "Ground net label" : "Net symbol",
222
267
  keywords: isPower ? "power net" : isGround ? "ground net" : "net",
223
- fpFilters: ""
268
+ fpFilters: "",
269
+ referencePrefix: libId.split(":")[1]?.[0] || "U"
224
270
  });
225
271
  }
226
272
  /**
@@ -280,7 +326,8 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
280
326
  description,
281
327
  keywords,
282
328
  fpFilters,
283
- footprintRef = ""
329
+ footprintRef = "",
330
+ referencePrefix
284
331
  }) {
285
332
  const symbol = new SchematicSymbol({
286
333
  libraryId: libId,
@@ -300,7 +347,8 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
300
347
  description,
301
348
  keywords,
302
349
  fpFilters,
303
- footprintRef
350
+ footprintRef,
351
+ referencePrefix
304
352
  });
305
353
  const drawingSymbol = this.createDrawingSubsymbol({
306
354
  libId,
@@ -327,9 +375,10 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
327
375
  description,
328
376
  keywords,
329
377
  fpFilters,
330
- footprintRef = ""
378
+ footprintRef = "",
379
+ referencePrefix
331
380
  }) {
332
- const refPrefix = libId.split(":")[1]?.[0] || "U";
381
+ const refPrefix = referencePrefix || libId.split(":")[1]?.[0] || "U";
333
382
  const properties = [
334
383
  {
335
384
  key: "Reference",
@@ -794,43 +843,44 @@ var AddSchematicSymbolsStage = class extends ConverterStage {
794
843
  */
795
844
  getComponentMetadata(sourceComp) {
796
845
  const name = sourceComp.name || "?";
846
+ const reference = getReferenceDesignator(sourceComp);
797
847
  if (sourceComp.ftype === "simple_resistor") {
798
848
  return {
799
- reference: name,
849
+ reference,
800
850
  value: sourceComp.display_resistance || "R",
801
851
  description: "Resistor"
802
852
  };
803
853
  }
804
854
  if (sourceComp.ftype === "simple_capacitor") {
805
855
  return {
806
- reference: name,
856
+ reference,
807
857
  value: sourceComp.display_capacitance || "C",
808
858
  description: "Capacitor"
809
859
  };
810
860
  }
811
861
  if (sourceComp.ftype === "simple_inductor") {
812
862
  return {
813
- reference: name,
863
+ reference,
814
864
  value: sourceComp.display_inductance || "L",
815
865
  description: "Inductor"
816
866
  };
817
867
  }
818
868
  if (sourceComp.ftype === "simple_diode") {
819
869
  return {
820
- reference: name,
870
+ reference,
821
871
  value: "D",
822
872
  description: "Diode"
823
873
  };
824
874
  }
825
875
  if (sourceComp.ftype === "simple_chip") {
826
876
  return {
827
- reference: name,
877
+ reference,
828
878
  value: name,
829
879
  description: "Integrated Circuit"
830
880
  };
831
881
  }
832
882
  return {
833
- reference: name,
883
+ reference,
834
884
  value: name,
835
885
  description: "Component"
836
886
  };
@@ -2937,8 +2987,15 @@ var CircuitJsonToKicadLibraryConverter = class {
2937
2987
 
2938
2988
  // lib/kicad-library/kicad-library-converter-utils/renameKicadFootprint.ts
2939
2989
  import { parseKicadMod } from "kicadts";
2990
+ var KICAD_3RD_PARTY_PLACEHOLDER = "${KICAD_3RD_PARTY}";
2940
2991
  function renameKicadFootprint(params) {
2941
- const { kicadFootprint, newKicadFootprintName, kicadLibraryName } = params;
2992
+ const {
2993
+ kicadFootprint,
2994
+ newKicadFootprintName,
2995
+ kicadLibraryName,
2996
+ isPcm,
2997
+ kicadPcmPackageId
2998
+ } = params;
2942
2999
  const footprint = parseKicadMod(kicadFootprint.kicadModString);
2943
3000
  footprint.libraryLink = newKicadFootprintName;
2944
3001
  for (const model of footprint.models) {
@@ -2946,7 +3003,11 @@ function renameKicadFootprint(params) {
2946
3003
  const usesProjectPath = currentPath.includes("${KIPRJMOD}/") || /3dmodels[\\/]/.test(currentPath);
2947
3004
  if (usesProjectPath) {
2948
3005
  const filename = currentPath.split(/[\\/]/).pop() ?? "";
2949
- model.path = `../../3dmodels/${kicadLibraryName}.3dshapes/${filename}`;
3006
+ if (isPcm && kicadPcmPackageId) {
3007
+ model.path = `${KICAD_3RD_PARTY_PLACEHOLDER}/3dmodels/${kicadPcmPackageId}/${kicadLibraryName}.3dshapes/${filename}`;
3008
+ } else {
3009
+ model.path = `../../3dmodels/${kicadLibraryName}.3dshapes/${filename}`;
3010
+ }
2950
3011
  }
2951
3012
  }
2952
3013
  return {
@@ -3077,6 +3138,8 @@ function applyKicadFootprintMetadata(kicadModString, metadata, footprintName) {
3077
3138
  }
3078
3139
 
3079
3140
  // lib/kicad-library/stages/ClassifyKicadFootprintsStage.ts
3141
+ import { parseKicadMod as parseKicadMod2 } from "kicadts";
3142
+ var KICAD_3RD_PARTY_PLACEHOLDER2 = "${KICAD_3RD_PARTY}";
3080
3143
  function classifyKicadFootprints(ctx) {
3081
3144
  for (const extractedKicadComponent of ctx.extractedKicadComponents) {
3082
3145
  classifyFootprintsForComponent({
@@ -3101,7 +3164,9 @@ function classifyFootprintsForComponent({
3101
3164
  let renamedFootprint = renameKicadFootprint({
3102
3165
  kicadFootprint,
3103
3166
  newKicadFootprintName: tscircuitComponentName,
3104
- kicadLibraryName: ctx.kicadLibraryName
3167
+ kicadLibraryName: ctx.kicadLibraryName,
3168
+ isPcm: ctx.isPcm,
3169
+ kicadPcmPackageId: ctx.kicadPcmPackageId
3105
3170
  });
3106
3171
  if (metadata) {
3107
3172
  renamedFootprint = {
@@ -3139,9 +3204,37 @@ function addBuiltinFootprint({
3139
3204
  (fp) => fp.footprintName === kicadFootprint.footprintName
3140
3205
  );
3141
3206
  if (!alreadyExists) {
3142
- ctx.builtinKicadFootprints.push(kicadFootprint);
3207
+ if (ctx.isPcm && ctx.kicadPcmPackageId) {
3208
+ const updatedFootprint = updateBuiltinFootprintModelPaths({
3209
+ kicadFootprint,
3210
+ kicadPcmPackageId: ctx.kicadPcmPackageId
3211
+ });
3212
+ ctx.builtinKicadFootprints.push(updatedFootprint);
3213
+ } else {
3214
+ ctx.builtinKicadFootprints.push(kicadFootprint);
3215
+ }
3143
3216
  }
3144
3217
  }
3218
+ function updateBuiltinFootprintModelPaths({
3219
+ kicadFootprint,
3220
+ kicadPcmPackageId
3221
+ }) {
3222
+ const footprint = parseKicadMod2(kicadFootprint.kicadModString);
3223
+ for (const model of footprint.models) {
3224
+ const currentPath = model.path;
3225
+ const usesProjectPath = currentPath.includes("${KIPRJMOD}/") || /3dmodels[\\/]/.test(currentPath);
3226
+ if (usesProjectPath) {
3227
+ const filename = currentPath.split(/[\\/]/).pop() ?? "";
3228
+ model.path = `${KICAD_3RD_PARTY_PLACEHOLDER2}/3dmodels/${kicadPcmPackageId}/tscircuit_builtin.3dshapes/${filename}`;
3229
+ }
3230
+ }
3231
+ return {
3232
+ footprintName: kicadFootprint.footprintName,
3233
+ kicadModString: footprint.getString(),
3234
+ model3dSourcePaths: kicadFootprint.model3dSourcePaths,
3235
+ isBuiltin: kicadFootprint.isBuiltin
3236
+ };
3237
+ }
3145
3238
  function componentHasCustomFootprint(extractedKicadComponent) {
3146
3239
  return extractedKicadComponent.kicadFootprints.some((fp) => !fp.isBuiltin);
3147
3240
  }
@@ -3165,24 +3258,26 @@ function renameKicadSymbol(params) {
3165
3258
 
3166
3259
  // lib/kicad-library/kicad-library-converter-utils/updateKicadSymbolFootprint.ts
3167
3260
  function updateKicadSymbolFootprint(params) {
3168
- const { kicadSymbol, kicadLibraryName, kicadFootprintName } = params;
3261
+ const { kicadSymbol, kicadLibraryName, kicadFootprintName, isPcm } = params;
3169
3262
  const properties = kicadSymbol.symbol.properties ?? [];
3263
+ const effectiveKicadLibraryName = isPcm ? `PCM_${kicadLibraryName}` : kicadLibraryName;
3170
3264
  for (const prop of properties) {
3171
3265
  if (prop.key === "Footprint") {
3172
- prop.value = `${kicadLibraryName}:${kicadFootprintName}`;
3266
+ prop.value = `${effectiveKicadLibraryName}:${kicadFootprintName}`;
3173
3267
  }
3174
3268
  }
3175
3269
  }
3176
3270
 
3177
3271
  // lib/kicad-library/kicad-library-converter-utils/updateBuiltinKicadSymbolFootprint.ts
3178
- function updateBuiltinKicadSymbolFootprint(kicadSymbol) {
3272
+ function updateBuiltinKicadSymbolFootprint(kicadSymbol, options) {
3179
3273
  const symbol = kicadSymbol.symbol;
3180
3274
  const properties = symbol.properties ?? [];
3275
+ const libraryName = options?.isPcm ? "PCM_tscircuit_builtin" : "tscircuit_builtin";
3181
3276
  for (const prop of properties) {
3182
3277
  if (prop.key === "Footprint" && prop.value) {
3183
3278
  const parts = prop.value.split(":");
3184
3279
  const footprintName = parts.length > 1 ? parts[1] : parts[0];
3185
- prop.value = `tscircuit_builtin:${footprintName}`;
3280
+ prop.value = `${libraryName}:${footprintName}`;
3186
3281
  }
3187
3282
  }
3188
3283
  return { symbolName: kicadSymbol.symbolName, symbol };
@@ -3218,7 +3313,8 @@ function classifySymbolsForComponent({
3218
3313
  updateKicadSymbolFootprint({
3219
3314
  kicadSymbol: renamedSymbol,
3220
3315
  kicadLibraryName: ctx.kicadLibraryName,
3221
- kicadFootprintName: tscircuitComponentName
3316
+ kicadFootprintName: tscircuitComponentName,
3317
+ isPcm: ctx.isPcm
3222
3318
  });
3223
3319
  }
3224
3320
  addUserSymbol({ ctx, kicadSymbol: renamedSymbol });
@@ -3234,11 +3330,14 @@ function classifySymbolsForComponent({
3234
3330
  updateKicadSymbolFootprint({
3235
3331
  kicadSymbol: renamedSymbol,
3236
3332
  kicadLibraryName: ctx.kicadLibraryName,
3237
- kicadFootprintName: tscircuitComponentName
3333
+ kicadFootprintName: tscircuitComponentName,
3334
+ isPcm: ctx.isPcm
3238
3335
  });
3239
3336
  addUserSymbol({ ctx, kicadSymbol: renamedSymbol });
3240
3337
  } else {
3241
- const updatedSymbol = updateBuiltinKicadSymbolFootprint(kicadSymbol);
3338
+ const updatedSymbol = updateBuiltinKicadSymbolFootprint(kicadSymbol, {
3339
+ isPcm: ctx.isPcm
3340
+ });
3242
3341
  addBuiltinSymbol({ ctx, kicadSymbol: updatedSymbol });
3243
3342
  }
3244
3343
  }
@@ -3361,7 +3460,9 @@ var KicadLibraryConverter = class {
3361
3460
  this.ctx = createKicadLibraryConverterContext({
3362
3461
  kicadLibraryName: options.kicadLibraryName ?? "tscircuit_library",
3363
3462
  includeBuiltins: options.includeBuiltins ?? true,
3364
- getComponentKicadMetadata: options.getComponentKicadMetadata
3463
+ getComponentKicadMetadata: options.getComponentKicadMetadata,
3464
+ isPcm: options.isPcm ?? false,
3465
+ kicadPcmPackageId: options.kicadPcmPackageId
3365
3466
  });
3366
3467
  }
3367
3468
  async run() {
@@ -3487,6 +3588,8 @@ function createKicadLibraryConverterContext(params) {
3487
3588
  kicadLibraryName: params.kicadLibraryName,
3488
3589
  includeBuiltins: params.includeBuiltins,
3489
3590
  getComponentKicadMetadata: params.getComponentKicadMetadata,
3591
+ isPcm: params.isPcm,
3592
+ kicadPcmPackageId: params.kicadPcmPackageId,
3490
3593
  footprintMetadataMap: /* @__PURE__ */ new Map(),
3491
3594
  builtTscircuitComponents: [],
3492
3595
  extractedKicadComponents: [],
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.39",
4
+ "version": "0.0.41",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"