circuitjson-toolkit 1.0.3 → 1.0.16
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/AGENTS.md +5 -3
- package/README.md +21 -2
- package/docs/api.md +50 -4
- package/docs/model-format.md +21 -3
- package/package.json +3 -2
- package/spec/library-scope.md +4 -1
- package/src/core/CircuitJsonBomBuilder.mjs +143 -0
- package/src/core/CircuitJsonDocument.mjs +46 -13
- package/src/core/CircuitJsonElementValidator.mjs +990 -0
- package/src/core/CircuitJsonIndexer.mjs +773 -4
- package/src/core/CircuitJsonManufacturingBuilder.mjs +898 -0
- package/src/core/CircuitJsonManufacturingDownloadBuilder.mjs +196 -0
- package/src/core/CircuitJsonParser.mjs +22 -6
- package/src/core/CircuitJsonPcbClearanceDiagnostics.mjs +329 -0
- package/src/core/CircuitJsonPcbCopperGeometry.mjs +503 -0
- package/src/core/CircuitJsonPcbDrawingStyle.mjs +88 -0
- package/src/core/CircuitJsonPcbHolePrimitiveModel.mjs +172 -0
- package/src/core/CircuitJsonPcbNetMetadata.mjs +247 -0
- package/src/core/CircuitJsonPcbPadPrimitiveModel.mjs +70 -0
- package/src/core/CircuitJsonPcbPrimitiveArtwork.mjs +992 -0
- package/src/core/CircuitJsonPcbPrimitiveBuilder.mjs +872 -0
- package/src/core/CircuitJsonPcbPrimitiveFields.mjs +233 -0
- package/src/core/CircuitJsonPcbPrimitiveGeometry.mjs +142 -0
- package/src/core/CircuitJsonPcbPrimitiveGroups.mjs +305 -0
- package/src/core/CircuitJsonPcbPrimitiveIndex.mjs +65 -0
- package/src/core/CircuitJsonPcbPrimitiveOverlays.mjs +895 -0
- package/src/core/CircuitJsonPcbTraceLengthModel.mjs +257 -0
- package/src/core/CircuitJsonPcbZonePrimitiveBuilder.mjs +683 -0
- package/src/core/CircuitJsonSourceMetadata.mjs +233 -0
- package/src/core/CircuitJsonSupportMatrixBuilder.mjs +481 -0
- package/src/core/CircuitJsonUnits.mjs +133 -8
- package/src/core/PcbBoundsSelectionModel.mjs +250 -0
- package/src/core/PcbCandidateSelectionModel.mjs +77 -0
- package/src/core/PcbDiagnosticFocusModel.mjs +423 -0
- package/src/core/PcbInteractionPrimitiveModel.mjs +560 -0
- package/src/core/SelectedPartCircuitJsonExportAdapter.mjs +335 -0
- package/src/core/spice/SpiceCompatibilityPreprocessor.mjs +139 -0
- package/src/core/spice/SpiceDirectiveParser.mjs +231 -0
- package/src/core/spice/SpiceFallbackSimulationEngine.mjs +168 -0
- package/src/core/spice/SpiceSimulationDiagnostics.mjs +234 -0
- package/src/core/spice/SpiceSimulationGraphBuilder.mjs +421 -0
- package/src/core/spice/SpiceSimulationGraphSummary.mjs +90 -0
- package/src/core/spice/SpiceSimulationService.mjs +92 -0
- package/src/core/spice/SpiceTimeSeriesNormalizer.mjs +132 -0
- package/src/index.mjs +8 -0
- package/src/renderers.mjs +29 -0
- package/src/ui/CircuitJsonPcbPrimitiveAttributeRenderer.mjs +128 -0
- package/src/ui/CircuitJsonPcbSvgRenderer.mjs +964 -0
- package/src/ui/CircuitJsonPcbViaSvgRenderer.mjs +168 -0
- package/src/ui/CircuitJsonSchematicSvgArcPath.mjs +138 -0
- package/src/ui/CircuitJsonSchematicSvgPortMetadata.mjs +114 -0
- package/src/ui/CircuitJsonSchematicSvgPrimitiveAttributes.mjs +130 -0
- package/src/ui/CircuitJsonSchematicSvgRenderer.mjs +994 -0
- package/src/ui/CircuitJsonSchematicTableSvgRenderer.mjs +439 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
const COMPONENT_ICON_BY_TYPE = {
|
|
2
|
+
battery: 'battery',
|
|
3
|
+
capacitor: 'capacitor',
|
|
4
|
+
chip: 'chip',
|
|
5
|
+
connector: 'connector',
|
|
6
|
+
crystal: 'crystal',
|
|
7
|
+
current_source: 'source',
|
|
8
|
+
diode: 'diode',
|
|
9
|
+
fiducial: 'fiducial',
|
|
10
|
+
fuse: 'fuse',
|
|
11
|
+
ground: 'ground',
|
|
12
|
+
inductor: 'inductor',
|
|
13
|
+
interconnect: 'connector',
|
|
14
|
+
led: 'led',
|
|
15
|
+
mosfet: 'transistor',
|
|
16
|
+
op_amp: 'op-amp',
|
|
17
|
+
pin_header: 'connector',
|
|
18
|
+
potentiometer: 'potentiometer',
|
|
19
|
+
push_button: 'switch',
|
|
20
|
+
resistor: 'resistor',
|
|
21
|
+
resonator: 'crystal',
|
|
22
|
+
switch: 'switch',
|
|
23
|
+
test_point: 'test-point',
|
|
24
|
+
transistor: 'transistor',
|
|
25
|
+
voltage_probe: 'probe',
|
|
26
|
+
voltage_source: 'source'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Normalizes generic source-level CircuitJSON metadata for stable consumers.
|
|
31
|
+
*/
|
|
32
|
+
export class CircuitJsonSourceMetadata {
|
|
33
|
+
/**
|
|
34
|
+
* Builds a safe source net name from display-oriented text.
|
|
35
|
+
* @param {unknown} value Source net label.
|
|
36
|
+
* @param {{ fallback?: string, usedNames?: Set<string> }} [options]
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
static normalizeSourceNetName(value, options = {}) {
|
|
40
|
+
const fallback = String(options.fallback || 'net').trim() || 'net'
|
|
41
|
+
let name = String(value || '').trim() || fallback
|
|
42
|
+
name = name
|
|
43
|
+
.replaceAll('+', '_P')
|
|
44
|
+
.replaceAll('-', '_')
|
|
45
|
+
.replace(/[^A-Za-z0-9_]+/gu, '_')
|
|
46
|
+
.replace(/_+/gu, '_')
|
|
47
|
+
.replace(/_+$/u, '')
|
|
48
|
+
if (!name) {
|
|
49
|
+
name = fallback.replace(/[^A-Za-z0-9_]+/gu, '_') || 'net'
|
|
50
|
+
}
|
|
51
|
+
if (/^[0-9]/u.test(name)) {
|
|
52
|
+
name = 'net_' + name
|
|
53
|
+
}
|
|
54
|
+
return CircuitJsonSourceMetadata.#dedupeName(name, options.usedNames)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Builds a stable source port name from a pad or pin label.
|
|
59
|
+
* @param {unknown} value Source port label.
|
|
60
|
+
* @param {{ fallback?: string, usedNames?: Set<string> }} [options]
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
static normalizeSourcePortName(value, options = {}) {
|
|
64
|
+
const text = String(value ?? '').trim()
|
|
65
|
+
const fallback = String(options.fallback || 'pin').trim() || 'pin'
|
|
66
|
+
const name = /^[0-9]+$/u.test(text) ? 'pin' + Number(text) : text
|
|
67
|
+
return CircuitJsonSourceMetadata.#dedupeName(
|
|
68
|
+
name || fallback,
|
|
69
|
+
options.usedNames
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Builds stable semantic metadata for one source component.
|
|
75
|
+
* @param {object} component Source component row.
|
|
76
|
+
* @returns {{ sourceFtype: string, componentType: string, componentIcon: string, supplierPartNumber: string, supplierPartNumbers: Record<string, string> }}
|
|
77
|
+
*/
|
|
78
|
+
static normalizeSourceComponent(component) {
|
|
79
|
+
const sourceFtype =
|
|
80
|
+
CircuitJsonSourceMetadata.#sourceFtype(component) ||
|
|
81
|
+
CircuitJsonSourceMetadata.#inferSourceFtype(component)
|
|
82
|
+
const componentType = sourceFtype
|
|
83
|
+
.replace(/^simple_/u, '')
|
|
84
|
+
.replaceAll('_', '-')
|
|
85
|
+
const supplierPartNumbers =
|
|
86
|
+
CircuitJsonSourceMetadata.#supplierPartNumbers(component)
|
|
87
|
+
return {
|
|
88
|
+
sourceFtype,
|
|
89
|
+
componentType,
|
|
90
|
+
componentIcon:
|
|
91
|
+
COMPONENT_ICON_BY_TYPE[componentType.replaceAll('-', '_')] ||
|
|
92
|
+
componentType ||
|
|
93
|
+
'component',
|
|
94
|
+
supplierPartNumber: String(
|
|
95
|
+
Object.values(supplierPartNumbers).find(Boolean) || ''
|
|
96
|
+
).trim(),
|
|
97
|
+
supplierPartNumbers
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns a unique name against an optional used-name set.
|
|
103
|
+
* @param {string} name Base name.
|
|
104
|
+
* @param {Set<string> | undefined} usedNames Existing names.
|
|
105
|
+
* @returns {string}
|
|
106
|
+
*/
|
|
107
|
+
static #dedupeName(name, usedNames) {
|
|
108
|
+
if (!(usedNames instanceof Set) || !usedNames.has(name)) return name
|
|
109
|
+
let index = 2
|
|
110
|
+
let candidate = name + '_' + index
|
|
111
|
+
while (usedNames.has(candidate)) {
|
|
112
|
+
index += 1
|
|
113
|
+
candidate = name + '_' + index
|
|
114
|
+
}
|
|
115
|
+
return candidate
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolves an explicit source component function type.
|
|
120
|
+
* @param {object} component Source component row.
|
|
121
|
+
* @returns {string}
|
|
122
|
+
*/
|
|
123
|
+
static #sourceFtype(component) {
|
|
124
|
+
return String(component?.ftype || component?.sourceFtype || '').trim()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Infers a source component function type from generic fields.
|
|
129
|
+
* @param {object} component Source component row.
|
|
130
|
+
* @returns {string}
|
|
131
|
+
*/
|
|
132
|
+
static #inferSourceFtype(component) {
|
|
133
|
+
const reference = String(
|
|
134
|
+
component?.name ||
|
|
135
|
+
component?.reference ||
|
|
136
|
+
component?.designator ||
|
|
137
|
+
''
|
|
138
|
+
).trim()
|
|
139
|
+
const text = [
|
|
140
|
+
reference,
|
|
141
|
+
component?.footprint,
|
|
142
|
+
component?.package,
|
|
143
|
+
component?.package_name,
|
|
144
|
+
component?.value,
|
|
145
|
+
component?.description
|
|
146
|
+
]
|
|
147
|
+
.map((value) => String(value || '').toLowerCase())
|
|
148
|
+
.filter(Boolean)
|
|
149
|
+
.join(' ')
|
|
150
|
+
|
|
151
|
+
if (text.includes('led')) return 'simple_led'
|
|
152
|
+
if (/^tp[0-9A-Z_-]*/iu.test(reference) || text.includes('test point')) {
|
|
153
|
+
return 'simple_test_point'
|
|
154
|
+
}
|
|
155
|
+
if (/^fid[0-9A-Z_-]*/iu.test(reference) || text.includes('fiducial')) {
|
|
156
|
+
return 'simple_fiducial'
|
|
157
|
+
}
|
|
158
|
+
if (/^sw[0-9A-Z_-]*/iu.test(reference) || text.includes('switch')) {
|
|
159
|
+
return 'simple_switch'
|
|
160
|
+
}
|
|
161
|
+
if (/^r[0-9A-Z_-]*/iu.test(reference) || component?.resistance) {
|
|
162
|
+
return 'simple_resistor'
|
|
163
|
+
}
|
|
164
|
+
if (/^c[0-9A-Z_-]*/iu.test(reference) || component?.capacitance) {
|
|
165
|
+
return 'simple_capacitor'
|
|
166
|
+
}
|
|
167
|
+
if (/^l[0-9A-Z_-]*/iu.test(reference) || component?.inductance) {
|
|
168
|
+
return 'simple_inductor'
|
|
169
|
+
}
|
|
170
|
+
if (text.includes('mosfet')) return 'simple_mosfet'
|
|
171
|
+
if (/^q[0-9A-Z_-]*/iu.test(reference) || text.includes('transistor')) {
|
|
172
|
+
return 'simple_transistor'
|
|
173
|
+
}
|
|
174
|
+
if (/^d[0-9A-Z_-]*/iu.test(reference)) return 'simple_diode'
|
|
175
|
+
if (/^(u|ic)[0-9A-Z_-]*/iu.test(reference) || text.includes('chip')) {
|
|
176
|
+
return 'simple_chip'
|
|
177
|
+
}
|
|
178
|
+
return ''
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Normalizes supplier part fields into a stable keyed object.
|
|
183
|
+
* @param {object} component Source component row.
|
|
184
|
+
* @returns {Record<string, string>}
|
|
185
|
+
*/
|
|
186
|
+
static #supplierPartNumbers(component) {
|
|
187
|
+
const numbers = {}
|
|
188
|
+
for (const field of ['supplier_part_numbers', 'supplierPartNumbers']) {
|
|
189
|
+
const value = component?.[field]
|
|
190
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
191
|
+
continue
|
|
192
|
+
}
|
|
193
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
194
|
+
const normalized = String(entry || '').trim()
|
|
195
|
+
if (normalized) numbers[String(key || 'supplier')] = normalized
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
CircuitJsonSourceMetadata.#addSupplierNumber(
|
|
199
|
+
numbers,
|
|
200
|
+
'supplier',
|
|
201
|
+
component?.supplier_part_number ?? component?.supplierPartNumber
|
|
202
|
+
)
|
|
203
|
+
CircuitJsonSourceMetadata.#addSupplierNumber(
|
|
204
|
+
numbers,
|
|
205
|
+
'distributor',
|
|
206
|
+
component?.distributor_part_number ??
|
|
207
|
+
component?.distributorPartNumber
|
|
208
|
+
)
|
|
209
|
+
CircuitJsonSourceMetadata.#addSupplierNumber(
|
|
210
|
+
numbers,
|
|
211
|
+
'assembly',
|
|
212
|
+
component?.assembly_part_number ?? component?.assemblyPartNumber
|
|
213
|
+
)
|
|
214
|
+
CircuitJsonSourceMetadata.#addSupplierNumber(
|
|
215
|
+
numbers,
|
|
216
|
+
'catalog',
|
|
217
|
+
component?.catalog_part_number ?? component?.catalogPartNumber
|
|
218
|
+
)
|
|
219
|
+
return numbers
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Adds one supplier part number when present.
|
|
224
|
+
* @param {Record<string, string>} numbers Supplier number map.
|
|
225
|
+
* @param {string} key Supplier key.
|
|
226
|
+
* @param {unknown} value Supplier part value.
|
|
227
|
+
* @returns {void}
|
|
228
|
+
*/
|
|
229
|
+
static #addSupplierNumber(numbers, key, value) {
|
|
230
|
+
const normalized = String(value || '').trim()
|
|
231
|
+
if (normalized && !numbers[key]) numbers[key] = normalized
|
|
232
|
+
}
|
|
233
|
+
}
|