@jlcpcb/core 0.1.0

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +474 -0
  3. package/package.json +48 -0
  4. package/src/api/easyeda-community.ts +259 -0
  5. package/src/api/easyeda.ts +153 -0
  6. package/src/api/index.ts +7 -0
  7. package/src/api/jlc.ts +185 -0
  8. package/src/constants/design-rules.ts +119 -0
  9. package/src/constants/footprints.ts +68 -0
  10. package/src/constants/index.ts +7 -0
  11. package/src/constants/kicad.ts +147 -0
  12. package/src/converter/category-router.ts +638 -0
  13. package/src/converter/footprint-mapper.ts +236 -0
  14. package/src/converter/footprint.ts +949 -0
  15. package/src/converter/global-lib-table.ts +394 -0
  16. package/src/converter/index.ts +46 -0
  17. package/src/converter/lib-table.ts +181 -0
  18. package/src/converter/svg-arc.ts +179 -0
  19. package/src/converter/symbol-templates.ts +214 -0
  20. package/src/converter/symbol.ts +1682 -0
  21. package/src/converter/value-normalizer.ts +262 -0
  22. package/src/index.ts +25 -0
  23. package/src/parsers/easyeda-shapes.ts +628 -0
  24. package/src/parsers/http-client.ts +96 -0
  25. package/src/parsers/index.ts +38 -0
  26. package/src/parsers/utils.ts +29 -0
  27. package/src/services/component-service.ts +100 -0
  28. package/src/services/fix-service.ts +50 -0
  29. package/src/services/index.ts +9 -0
  30. package/src/services/library-service.ts +696 -0
  31. package/src/types/component.ts +61 -0
  32. package/src/types/easyeda-community.ts +78 -0
  33. package/src/types/easyeda.ts +356 -0
  34. package/src/types/index.ts +12 -0
  35. package/src/types/jlc.ts +84 -0
  36. package/src/types/kicad.ts +136 -0
  37. package/src/types/mcp.ts +77 -0
  38. package/src/types/project.ts +60 -0
  39. package/src/utils/conversion.ts +104 -0
  40. package/src/utils/file-system.ts +143 -0
  41. package/src/utils/index.ts +8 -0
  42. package/src/utils/logger.ts +96 -0
  43. package/src/utils/validation.ts +110 -0
  44. package/tsconfig.json +9 -0
@@ -0,0 +1,236 @@
1
+ /**
2
+ * KiCad Standard Footprint Mapper
3
+ * Maps common package names to KiCad built-in footprints for hybrid approach
4
+ */
5
+
6
+ import { getLibraryCategory, type LibraryCategory } from './category-router.js';
7
+
8
+ export interface FootprintMapping {
9
+ library: string; // KiCad library name (e.g., "Resistor_SMD")
10
+ footprint: string; // Footprint name (e.g., "R_0603_1608Metric")
11
+ }
12
+
13
+ // SMD passive size mappings (Imperial to KiCad naming)
14
+ const SMD_SIZES: Record<string, { metric: string; imperialMm: string }> = {
15
+ '0201': { metric: '0603', imperialMm: '0.6x0.3' },
16
+ '0402': { metric: '1005', imperialMm: '1.0x0.5' },
17
+ '0603': { metric: '1608', imperialMm: '1.6x0.8' },
18
+ '0805': { metric: '2012', imperialMm: '2.0x1.2' },
19
+ '1206': { metric: '3216', imperialMm: '3.2x1.6' },
20
+ '1210': { metric: '3225', imperialMm: '3.2x2.5' },
21
+ '1812': { metric: '4532', imperialMm: '4.5x3.2' },
22
+ '2010': { metric: '5025', imperialMm: '5.0x2.5' },
23
+ '2512': { metric: '6332', imperialMm: '6.3x3.2' },
24
+ };
25
+
26
+ // Prefix to library mapping for passives
27
+ const PASSIVE_LIBRARIES: Record<string, string> = {
28
+ R: 'Resistor_SMD',
29
+ C: 'Capacitor_SMD',
30
+ L: 'Inductor_SMD',
31
+ };
32
+
33
+ // LED/Diode libraries
34
+ const LED_LIBRARY = 'LED_SMD';
35
+ const DIODE_LIBRARY = 'Diode_SMD';
36
+
37
+ // Map library categories to footprint prefixes (for category-based fallback)
38
+ const CATEGORY_TO_PREFIX: Partial<Record<LibraryCategory, string>> = {
39
+ Resistors: 'R',
40
+ Capacitors: 'C',
41
+ Inductors: 'L',
42
+ Diodes: 'D',
43
+ };
44
+
45
+ // SOIC package mappings
46
+ const SOIC_MAPPINGS: Record<string, string> = {
47
+ 'SOIC-8': 'SOIC-8_3.9x4.9mm_P1.27mm',
48
+ 'SOP-8': 'SOIC-8_3.9x4.9mm_P1.27mm',
49
+ 'SOIC-14': 'SOIC-14_3.9x8.7mm_P1.27mm',
50
+ 'SOIC-16': 'SOIC-16_3.9x9.9mm_P1.27mm',
51
+ 'SOIC-16W': 'SOIC-16W_7.5x10.3mm_P1.27mm',
52
+ 'SOIC-20': 'SOIC-20W_7.5x12.8mm_P1.27mm',
53
+ 'SOIC-24': 'SOIC-24W_7.5x15.4mm_P1.27mm',
54
+ 'SOIC-28': 'SOIC-28W_7.5x17.9mm_P1.27mm',
55
+ };
56
+
57
+ // TSSOP package mappings
58
+ const TSSOP_MAPPINGS: Record<string, string> = {
59
+ 'TSSOP-8': 'TSSOP-8_3x3mm_P0.65mm',
60
+ 'TSSOP-14': 'TSSOP-14_4.4x5mm_P0.65mm',
61
+ 'TSSOP-16': 'TSSOP-16_4.4x5mm_P0.65mm',
62
+ 'TSSOP-20': 'TSSOP-20_4.4x6.5mm_P0.65mm',
63
+ 'TSSOP-24': 'TSSOP-24_4.4x7.8mm_P0.65mm',
64
+ 'TSSOP-28': 'TSSOP-28_4.4x9.7mm_P0.65mm',
65
+ };
66
+
67
+ // SOT package mappings
68
+ const SOT_MAPPINGS: Record<string, { library: string; footprint: string }> = {
69
+ 'SOT-23': { library: 'Package_TO_SOT_SMD', footprint: 'SOT-23' },
70
+ 'SOT-23-3': { library: 'Package_TO_SOT_SMD', footprint: 'SOT-23' },
71
+ 'SOT-23-5': { library: 'Package_TO_SOT_SMD', footprint: 'SOT-23-5' },
72
+ 'SOT-23-6': { library: 'Package_TO_SOT_SMD', footprint: 'SOT-23-6' },
73
+ 'SOT-89': { library: 'Package_TO_SOT_SMD', footprint: 'SOT-89-3' },
74
+ 'SOT-223': { library: 'Package_TO_SOT_SMD', footprint: 'SOT-223-3_TabPin2' },
75
+ };
76
+
77
+ // SOD diode package mappings
78
+ const SOD_MAPPINGS: Record<string, { library: string; footprint: string }> = {
79
+ 'SOD-123': { library: 'Diode_SMD', footprint: 'D_SOD-123' },
80
+ 'SOD-123F': { library: 'Diode_SMD', footprint: 'D_SOD-123F' },
81
+ 'SOD-323': { library: 'Diode_SMD', footprint: 'D_SOD-323' },
82
+ 'SOD-523': { library: 'Diode_SMD', footprint: 'D_SOD-523' },
83
+ 'SOD-923': { library: 'Diode_SMD', footprint: 'D_SOD-923' },
84
+ 'SOD-128': { library: 'Diode_SMD', footprint: 'D_SOD-128' },
85
+ 'SOD-80': { library: 'Diode_SMD', footprint: 'D_SOD-80' },
86
+ };
87
+
88
+ // SMA/SMB/SMC diode package mappings
89
+ const DIODE_PACKAGE_MAPPINGS: Record<string, { library: string; footprint: string }> = {
90
+ 'SMA': { library: 'Diode_SMD', footprint: 'D_SMA' },
91
+ 'SMB': { library: 'Diode_SMD', footprint: 'D_SMB' },
92
+ 'SMC': { library: 'Diode_SMD', footprint: 'D_SMC' },
93
+ 'MELF': { library: 'Diode_SMD', footprint: 'D_MELF' },
94
+ 'MINIMELF': { library: 'Diode_SMD', footprint: 'D_MiniMELF' },
95
+ 'MICROMELF': { library: 'Diode_SMD', footprint: 'D_MicroMELF' },
96
+ };
97
+
98
+ /**
99
+ * Normalize package name for matching
100
+ * - Uppercase
101
+ * - Remove common variations in naming
102
+ */
103
+ function normalizePackageName(name: string): string {
104
+ return name
105
+ .toUpperCase()
106
+ .replace(/[_\s-]+/g, '-')
107
+ .replace(/\(.*?\)/g, '') // Remove parenthetical info like "(1608)"
108
+ .trim();
109
+ }
110
+
111
+ /**
112
+ * Extract imperial size code from package name
113
+ * Handles variations like "0603", "SMD0603", "LED0603-RD", "0603(1608)"
114
+ */
115
+ function extractSmdSize(packageName: string): string | null {
116
+ const normalized = normalizePackageName(packageName);
117
+
118
+ // Direct match
119
+ for (const size of Object.keys(SMD_SIZES)) {
120
+ if (normalized === size || normalized === `SMD${size}`) {
121
+ return size;
122
+ }
123
+ }
124
+
125
+ // Pattern match for sizes anywhere in name
126
+ // Allows prefixes like LED, SMD, etc. and suffixes like -RD, -BL
127
+ const sizePattern = /(0201|0402|0603|0805|1206|1210|1812|2010|2512)(?![0-9])/;
128
+ const match = normalized.match(sizePattern);
129
+ return match ? match[1] : null;
130
+ }
131
+
132
+ /**
133
+ * Map package name to KiCad standard footprint
134
+ * Returns null if no standard mapping exists (will fall back to generated)
135
+ */
136
+ export function mapToKicadFootprint(
137
+ packageName: string,
138
+ componentPrefix: string,
139
+ category?: string,
140
+ description?: string
141
+ ): FootprintMapping | null {
142
+ const normalized = normalizePackageName(packageName);
143
+ let prefix = componentPrefix.toUpperCase();
144
+
145
+ // Category-based prefix fallback: if prefix doesn't match known mappings,
146
+ // try to detect the correct prefix from category/description
147
+ const isKnownPrefix = PASSIVE_LIBRARIES[prefix] || prefix === 'D' || prefix === 'LED';
148
+ if (!isKnownPrefix && (category || description)) {
149
+ const detectedCategory = getLibraryCategory(prefix, category, description);
150
+ const categoryPrefix = CATEGORY_TO_PREFIX[detectedCategory];
151
+ if (categoryPrefix) {
152
+ prefix = categoryPrefix;
153
+ }
154
+ }
155
+
156
+ // 1. Check SMD passive sizes (R, C, L)
157
+ const smdSize = extractSmdSize(packageName);
158
+ if (smdSize && PASSIVE_LIBRARIES[prefix]) {
159
+ const sizeInfo = SMD_SIZES[smdSize];
160
+ const library = PASSIVE_LIBRARIES[prefix];
161
+ // KiCad naming: R_0603_1608Metric, C_0603_1608Metric, L_0603_1608Metric
162
+ const footprint = `${prefix}_${smdSize}_${sizeInfo.metric}Metric`;
163
+ return { library, footprint };
164
+ }
165
+
166
+ // 2. Check LED SMD sizes (for LED prefix or components detected as LEDs)
167
+ if (smdSize && prefix === 'LED') {
168
+ const sizeInfo = SMD_SIZES[smdSize];
169
+ // KiCad naming: LED_0805_2012Metric
170
+ const footprint = `LED_${smdSize}_${sizeInfo.metric}Metric`;
171
+ return { library: LED_LIBRARY, footprint };
172
+ }
173
+
174
+ // 3. Check Diode SMD sizes (D prefix)
175
+ if (smdSize && prefix === 'D') {
176
+ const sizeInfo = SMD_SIZES[smdSize];
177
+ // KiCad naming: D_0805_2012Metric
178
+ const footprint = `D_${smdSize}_${sizeInfo.metric}Metric`;
179
+ return { library: DIODE_LIBRARY, footprint };
180
+ }
181
+
182
+ // 4. Check SOD diode packages
183
+ for (const [pattern, mapping] of Object.entries(SOD_MAPPINGS)) {
184
+ if (normalized.includes(pattern) || normalized.startsWith(pattern.replace(/-/g, ''))) {
185
+ return mapping;
186
+ }
187
+ }
188
+
189
+ // 5. Check SMA/SMB/SMC diode packages
190
+ for (const [pattern, mapping] of Object.entries(DIODE_PACKAGE_MAPPINGS)) {
191
+ // Match exact package type or with suffix (e.g., "SMA" in "SMA_L4.3...")
192
+ if (normalized === pattern || normalized.startsWith(pattern + '-') || normalized.startsWith(pattern + '_')) {
193
+ return mapping;
194
+ }
195
+ }
196
+
197
+ // 6. Check SOIC packages
198
+ for (const [pattern, footprint] of Object.entries(SOIC_MAPPINGS)) {
199
+ if (normalized.includes(pattern) || normalized.startsWith(pattern.replace(/-/g, ''))) {
200
+ return { library: 'Package_SO', footprint };
201
+ }
202
+ }
203
+
204
+ // 7. Check TSSOP packages
205
+ for (const [pattern, footprint] of Object.entries(TSSOP_MAPPINGS)) {
206
+ if (normalized.includes(pattern) || normalized.startsWith(pattern.replace(/-/g, ''))) {
207
+ return { library: 'Package_SO', footprint };
208
+ }
209
+ }
210
+
211
+ // 8. Check SOT packages
212
+ for (const [pattern, mapping] of Object.entries(SOT_MAPPINGS)) {
213
+ if (normalized.includes(pattern) || normalized === pattern.replace(/-/g, '')) {
214
+ return mapping;
215
+ }
216
+ }
217
+
218
+ // No standard mapping found - will use generated footprint
219
+ return null;
220
+ }
221
+
222
+ /**
223
+ * Get full KiCad footprint reference string
224
+ * Format: "Library:Footprint"
225
+ */
226
+ export function getKicadFootprintRef(mapping: FootprintMapping): string {
227
+ return `${mapping.library}:${mapping.footprint}`;
228
+ }
229
+
230
+ /**
231
+ * Check if a package is likely a standard passive that can use KiCad footprints
232
+ */
233
+ export function isStandardPassive(packageName: string, prefix: string): boolean {
234
+ const smdSize = extractSmdSize(packageName);
235
+ return smdSize !== null && PASSIVE_LIBRARIES[prefix.toUpperCase()] !== undefined;
236
+ }