circuitjson-toolkit 1.0.10 → 1.0.17
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 +20 -3
- package/docs/model-format.md +15 -0
- package/package.json +3 -2
- package/src/core/CircuitJsonBomBuilder.mjs +22 -25
- package/src/core/CircuitJsonElementValidator.mjs +233 -16
- package/src/core/CircuitJsonIndexer.mjs +510 -5
- package/src/core/CircuitJsonManufacturingBuilder.mjs +488 -16
- package/src/core/CircuitJsonManufacturingDownloadBuilder.mjs +196 -0
- 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 +227 -5
- 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/index.mjs +2 -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
|
@@ -19,6 +19,20 @@ const ID_FIELDS_BY_TYPE = {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const GROUP_TYPES = new Set(['source_group', 'pcb_group', 'schematic_group'])
|
|
22
|
+
const SCHEMATIC_PRIMITIVE_TYPES = new Set([
|
|
23
|
+
'schematic_arc',
|
|
24
|
+
'schematic_box',
|
|
25
|
+
'schematic_circle',
|
|
26
|
+
'schematic_line',
|
|
27
|
+
'schematic_net_label',
|
|
28
|
+
'schematic_path',
|
|
29
|
+
'schematic_rect',
|
|
30
|
+
'schematic_table',
|
|
31
|
+
'schematic_table_cell',
|
|
32
|
+
'schematic_text',
|
|
33
|
+
'schematic_trace',
|
|
34
|
+
'schematic_voltage_probe'
|
|
35
|
+
])
|
|
22
36
|
|
|
23
37
|
/**
|
|
24
38
|
* Builds lookup maps for CircuitJSON element arrays.
|
|
@@ -27,7 +41,7 @@ export class CircuitJsonIndexer {
|
|
|
27
41
|
/**
|
|
28
42
|
* Indexes a CircuitJSON model.
|
|
29
43
|
* @param {object[]} circuitJson CircuitJSON model.
|
|
30
|
-
* @returns {{ elements: object[], elementsByType: Map<string, object[]>, elementsById: Map<string, object>, relationsByField: Map<string, Map<string, object[]>>, sourceComponentById: Map<string, object>, pcbComponentById: Map<string, object>, componentsBySourceId: Map<string, object>, groupsById: Map<string, object>, elementsByGroupId: Map<string, object[]>, elementsBySubcircuitId: Map<string, object[]>, diagnostics: object[] }}
|
|
44
|
+
* @returns {{ elements: object[], elementsByType: Map<string, object[]>, elementsById: Map<string, object>, relationsByField: Map<string, Map<string, object[]>>, sourceComponentById: Map<string, object>, pcbComponentById: Map<string, object>, sourceTraceById: Map<string, object>, sourceTraceConnectivity: Map<string, object>, componentsBySourceId: Map<string, object>, groupsById: Map<string, object>, elementsByGroupId: Map<string, object[]>, elementsBySubcircuitId: Map<string, object[]>, diagnostics: object[] }}
|
|
31
45
|
*/
|
|
32
46
|
static index(circuitJson) {
|
|
33
47
|
CircuitJsonDocument.assertModel(circuitJson)
|
|
@@ -36,6 +50,7 @@ export class CircuitJsonIndexer {
|
|
|
36
50
|
const relationsByField = new Map()
|
|
37
51
|
const sourceComponentById = new Map()
|
|
38
52
|
const pcbComponentById = new Map()
|
|
53
|
+
const sourceTraceById = new Map()
|
|
39
54
|
|
|
40
55
|
circuitJson.forEach((element) => {
|
|
41
56
|
const type = String(element?.type || '')
|
|
@@ -54,8 +69,13 @@ export class CircuitJsonIndexer {
|
|
|
54
69
|
if (type === 'pcb_component' && id) {
|
|
55
70
|
pcbComponentById.set(id, element)
|
|
56
71
|
}
|
|
72
|
+
if (type === 'source_trace' && id) {
|
|
73
|
+
sourceTraceById.set(id, element)
|
|
74
|
+
}
|
|
57
75
|
CircuitJsonIndexer.#indexRelations(element, relationsByField)
|
|
58
76
|
})
|
|
77
|
+
const sourceTraceConnectivity =
|
|
78
|
+
CircuitJsonIndexer.#sourceTraceConnectivity(sourceTraceById)
|
|
59
79
|
|
|
60
80
|
return {
|
|
61
81
|
elements: circuitJson,
|
|
@@ -64,6 +84,8 @@ export class CircuitJsonIndexer {
|
|
|
64
84
|
relationsByField,
|
|
65
85
|
sourceComponentById,
|
|
66
86
|
pcbComponentById,
|
|
87
|
+
sourceTraceById,
|
|
88
|
+
sourceTraceConnectivity,
|
|
67
89
|
componentsBySourceId: CircuitJsonIndexer.#componentsBySourceId(
|
|
68
90
|
sourceComponentById,
|
|
69
91
|
relationsByField
|
|
@@ -73,7 +95,14 @@ export class CircuitJsonIndexer {
|
|
|
73
95
|
CircuitJsonIndexer.#elementsByGroupId(circuitJson),
|
|
74
96
|
elementsBySubcircuitId:
|
|
75
97
|
CircuitJsonIndexer.#elementsBySubcircuitId(circuitJson),
|
|
76
|
-
diagnostics:
|
|
98
|
+
diagnostics: [
|
|
99
|
+
...CircuitJsonIndexer.collectDiagnostics(circuitJson),
|
|
100
|
+
...CircuitJsonIndexer.#referenceDiagnostics(
|
|
101
|
+
elementsByType,
|
|
102
|
+
sourceTraceById,
|
|
103
|
+
sourceTraceConnectivity
|
|
104
|
+
)
|
|
105
|
+
]
|
|
77
106
|
}
|
|
78
107
|
}
|
|
79
108
|
|
|
@@ -135,7 +164,9 @@ export class CircuitJsonIndexer {
|
|
|
135
164
|
* @returns {string[]}
|
|
136
165
|
*/
|
|
137
166
|
static #relationValues(value) {
|
|
138
|
-
const values = Array.isArray(value)
|
|
167
|
+
const values = Array.isArray(value)
|
|
168
|
+
? value.flatMap((entry) => (Array.isArray(entry) ? entry : [entry]))
|
|
169
|
+
: [value]
|
|
139
170
|
return values.map((entry) => String(entry || '').trim()).filter(Boolean)
|
|
140
171
|
}
|
|
141
172
|
|
|
@@ -169,6 +200,413 @@ export class CircuitJsonIndexer {
|
|
|
169
200
|
return bySource
|
|
170
201
|
}
|
|
171
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Builds connectivity summaries keyed by source trace id.
|
|
205
|
+
* @param {Map<string, object>} sourceTraceById Source trace lookup.
|
|
206
|
+
* @returns {Map<string, object>}
|
|
207
|
+
*/
|
|
208
|
+
static #sourceTraceConnectivity(sourceTraceById) {
|
|
209
|
+
const connectivity = new Map()
|
|
210
|
+
for (const [sourceTraceId, sourceTrace] of sourceTraceById) {
|
|
211
|
+
connectivity.set(sourceTraceId, {
|
|
212
|
+
sourceTraceId,
|
|
213
|
+
connectedSourcePortIds: CircuitJsonIndexer.#relationValues([
|
|
214
|
+
sourceTrace.connected_source_port_id,
|
|
215
|
+
sourceTrace.source_port_id,
|
|
216
|
+
sourceTrace.connected_source_port_ids,
|
|
217
|
+
sourceTrace.source_port_ids
|
|
218
|
+
]),
|
|
219
|
+
connectedSourceNetIds: CircuitJsonIndexer.#relationValues([
|
|
220
|
+
sourceTrace.connected_source_net_id,
|
|
221
|
+
sourceTrace.source_net_id,
|
|
222
|
+
sourceTrace.connected_source_net_ids,
|
|
223
|
+
sourceTrace.source_net_ids
|
|
224
|
+
])
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
return connectivity
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Builds generated diagnostics for broken source-trace references.
|
|
232
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
233
|
+
* @param {Map<string, object>} sourceTraceById Source trace lookup.
|
|
234
|
+
* @param {Map<string, object>} sourceTraceConnectivity Connectivity lookup.
|
|
235
|
+
* @returns {object[]}
|
|
236
|
+
*/
|
|
237
|
+
static #referenceDiagnostics(
|
|
238
|
+
elementsByType,
|
|
239
|
+
sourceTraceById,
|
|
240
|
+
sourceTraceConnectivity
|
|
241
|
+
) {
|
|
242
|
+
const sourcePortIds = new Set(
|
|
243
|
+
CircuitJsonIndexer.#all(elementsByType, 'source_port')
|
|
244
|
+
.map((port) => String(port.source_port_id || '').trim())
|
|
245
|
+
.filter(Boolean)
|
|
246
|
+
)
|
|
247
|
+
const sourceNetIds = new Set(
|
|
248
|
+
CircuitJsonIndexer.#all(elementsByType, 'source_net')
|
|
249
|
+
.map((net) => String(net.source_net_id || '').trim())
|
|
250
|
+
.filter(Boolean)
|
|
251
|
+
)
|
|
252
|
+
const schematicSymbolIds = CircuitJsonIndexer.#elementIds(
|
|
253
|
+
elementsByType,
|
|
254
|
+
'schematic_symbol'
|
|
255
|
+
)
|
|
256
|
+
const schematicComponentIds = CircuitJsonIndexer.#elementIds(
|
|
257
|
+
elementsByType,
|
|
258
|
+
'schematic_component'
|
|
259
|
+
)
|
|
260
|
+
return [
|
|
261
|
+
...CircuitJsonIndexer.#missingSourceTracePortDiagnostics(
|
|
262
|
+
sourceTraceConnectivity,
|
|
263
|
+
sourcePortIds
|
|
264
|
+
),
|
|
265
|
+
...CircuitJsonIndexer.#missingSourceTraceNetDiagnostics(
|
|
266
|
+
sourceTraceConnectivity,
|
|
267
|
+
sourceNetIds
|
|
268
|
+
),
|
|
269
|
+
...CircuitJsonIndexer.#missingPcbSourceTraceDiagnostics(
|
|
270
|
+
elementsByType,
|
|
271
|
+
sourceTraceById
|
|
272
|
+
),
|
|
273
|
+
...CircuitJsonIndexer.#missingSchematicComponentSymbolDiagnostics(
|
|
274
|
+
elementsByType,
|
|
275
|
+
schematicSymbolIds
|
|
276
|
+
),
|
|
277
|
+
...CircuitJsonIndexer.#missingSchematicPortComponentDiagnostics(
|
|
278
|
+
elementsByType,
|
|
279
|
+
schematicComponentIds
|
|
280
|
+
),
|
|
281
|
+
...CircuitJsonIndexer.#missingSchematicPortSourcePortDiagnostics(
|
|
282
|
+
elementsByType,
|
|
283
|
+
sourcePortIds
|
|
284
|
+
),
|
|
285
|
+
...CircuitJsonIndexer.#missingSchematicPrimitiveDiagnostics(
|
|
286
|
+
elementsByType,
|
|
287
|
+
schematicSymbolIds,
|
|
288
|
+
schematicComponentIds
|
|
289
|
+
)
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Builds source-trace missing source-port diagnostics.
|
|
295
|
+
* @param {Map<string, object>} sourceTraceConnectivity Connectivity lookup.
|
|
296
|
+
* @param {Set<string>} sourcePortIds Known source port ids.
|
|
297
|
+
* @returns {object[]}
|
|
298
|
+
*/
|
|
299
|
+
static #missingSourceTracePortDiagnostics(
|
|
300
|
+
sourceTraceConnectivity,
|
|
301
|
+
sourcePortIds
|
|
302
|
+
) {
|
|
303
|
+
return [...sourceTraceConnectivity.values()].flatMap((trace) =>
|
|
304
|
+
trace.connectedSourcePortIds
|
|
305
|
+
.filter((sourcePortId) => !sourcePortIds.has(sourcePortId))
|
|
306
|
+
.map((sourcePortId) => ({
|
|
307
|
+
isGenerated: true,
|
|
308
|
+
severity: 'warning',
|
|
309
|
+
sourceFormat: 'circuitjson',
|
|
310
|
+
type: 'source_trace_missing_source_port_warning',
|
|
311
|
+
category: 'connectivity',
|
|
312
|
+
message:
|
|
313
|
+
'Source trace ' +
|
|
314
|
+
trace.sourceTraceId +
|
|
315
|
+
' references missing source port ' +
|
|
316
|
+
sourcePortId +
|
|
317
|
+
'.',
|
|
318
|
+
elementId:
|
|
319
|
+
trace.sourceTraceId + ':missing-port:' + sourcePortId,
|
|
320
|
+
sourceTraceId: trace.sourceTraceId,
|
|
321
|
+
sourcePortId
|
|
322
|
+
}))
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Builds source-trace missing source-net diagnostics.
|
|
328
|
+
* @param {Map<string, object>} sourceTraceConnectivity Connectivity lookup.
|
|
329
|
+
* @param {Set<string>} sourceNetIds Known source net ids.
|
|
330
|
+
* @returns {object[]}
|
|
331
|
+
*/
|
|
332
|
+
static #missingSourceTraceNetDiagnostics(
|
|
333
|
+
sourceTraceConnectivity,
|
|
334
|
+
sourceNetIds
|
|
335
|
+
) {
|
|
336
|
+
return [...sourceTraceConnectivity.values()].flatMap((trace) =>
|
|
337
|
+
trace.connectedSourceNetIds
|
|
338
|
+
.filter((sourceNetId) => !sourceNetIds.has(sourceNetId))
|
|
339
|
+
.map((sourceNetId) => ({
|
|
340
|
+
isGenerated: true,
|
|
341
|
+
severity: 'warning',
|
|
342
|
+
sourceFormat: 'circuitjson',
|
|
343
|
+
type: 'source_trace_missing_source_net_warning',
|
|
344
|
+
category: 'connectivity',
|
|
345
|
+
message:
|
|
346
|
+
'Source trace ' +
|
|
347
|
+
trace.sourceTraceId +
|
|
348
|
+
' references missing source net ' +
|
|
349
|
+
sourceNetId +
|
|
350
|
+
'.',
|
|
351
|
+
elementId:
|
|
352
|
+
trace.sourceTraceId + ':missing-net:' + sourceNetId,
|
|
353
|
+
sourceTraceId: trace.sourceTraceId,
|
|
354
|
+
sourceNetId
|
|
355
|
+
}))
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Builds PCB-trace missing source-trace diagnostics.
|
|
361
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
362
|
+
* @param {Map<string, object>} sourceTraceById Source trace lookup.
|
|
363
|
+
* @returns {object[]}
|
|
364
|
+
*/
|
|
365
|
+
static #missingPcbSourceTraceDiagnostics(elementsByType, sourceTraceById) {
|
|
366
|
+
return CircuitJsonIndexer.#all(elementsByType, 'pcb_trace')
|
|
367
|
+
.map((trace) => ({
|
|
368
|
+
pcbTraceId: String(trace.pcb_trace_id || '').trim(),
|
|
369
|
+
sourceTraceId: String(trace.source_trace_id || '').trim()
|
|
370
|
+
}))
|
|
371
|
+
.filter(
|
|
372
|
+
(trace) =>
|
|
373
|
+
trace.sourceTraceId &&
|
|
374
|
+
!sourceTraceById.has(trace.sourceTraceId)
|
|
375
|
+
)
|
|
376
|
+
.map((trace) => ({
|
|
377
|
+
isGenerated: true,
|
|
378
|
+
severity: 'warning',
|
|
379
|
+
sourceFormat: 'circuitjson',
|
|
380
|
+
type: 'pcb_trace_missing_source_trace_warning',
|
|
381
|
+
category: 'connectivity',
|
|
382
|
+
message:
|
|
383
|
+
'PCB trace ' +
|
|
384
|
+
trace.pcbTraceId +
|
|
385
|
+
' references missing source trace ' +
|
|
386
|
+
trace.sourceTraceId +
|
|
387
|
+
'.',
|
|
388
|
+
elementId:
|
|
389
|
+
trace.pcbTraceId +
|
|
390
|
+
':missing-source-trace:' +
|
|
391
|
+
trace.sourceTraceId,
|
|
392
|
+
sourceTraceId: trace.sourceTraceId,
|
|
393
|
+
pcbTraceId: trace.pcbTraceId
|
|
394
|
+
}))
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Builds schematic-component missing symbol diagnostics.
|
|
399
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
400
|
+
* @param {Set<string>} schematicSymbolIds Known schematic symbol ids.
|
|
401
|
+
* @returns {object[]}
|
|
402
|
+
*/
|
|
403
|
+
static #missingSchematicComponentSymbolDiagnostics(
|
|
404
|
+
elementsByType,
|
|
405
|
+
schematicSymbolIds
|
|
406
|
+
) {
|
|
407
|
+
return CircuitJsonIndexer.#all(elementsByType, 'schematic_component')
|
|
408
|
+
.map((component) => ({
|
|
409
|
+
schematicComponentId:
|
|
410
|
+
CircuitJsonIndexer.getElementId(component),
|
|
411
|
+
schematicSymbolId: String(
|
|
412
|
+
component.schematic_symbol_id || ''
|
|
413
|
+
).trim()
|
|
414
|
+
}))
|
|
415
|
+
.filter(
|
|
416
|
+
(component) =>
|
|
417
|
+
component.schematicSymbolId &&
|
|
418
|
+
!schematicSymbolIds.has(component.schematicSymbolId)
|
|
419
|
+
)
|
|
420
|
+
.map((component) => ({
|
|
421
|
+
isGenerated: true,
|
|
422
|
+
severity: 'warning',
|
|
423
|
+
sourceFormat: 'circuitjson',
|
|
424
|
+
type: 'schematic_component_missing_schematic_symbol_warning',
|
|
425
|
+
category: 'layout',
|
|
426
|
+
message:
|
|
427
|
+
'Schematic component ' +
|
|
428
|
+
component.schematicComponentId +
|
|
429
|
+
' references missing schematic symbol ' +
|
|
430
|
+
component.schematicSymbolId +
|
|
431
|
+
'.',
|
|
432
|
+
elementId:
|
|
433
|
+
component.schematicComponentId +
|
|
434
|
+
':missing-symbol:' +
|
|
435
|
+
component.schematicSymbolId,
|
|
436
|
+
schematicComponentId: component.schematicComponentId,
|
|
437
|
+
schematicSymbolId: component.schematicSymbolId
|
|
438
|
+
}))
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Builds schematic-port missing component diagnostics.
|
|
443
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
444
|
+
* @param {Set<string>} schematicComponentIds Known schematic component ids.
|
|
445
|
+
* @returns {object[]}
|
|
446
|
+
*/
|
|
447
|
+
static #missingSchematicPortComponentDiagnostics(
|
|
448
|
+
elementsByType,
|
|
449
|
+
schematicComponentIds
|
|
450
|
+
) {
|
|
451
|
+
return CircuitJsonIndexer.#all(elementsByType, 'schematic_port')
|
|
452
|
+
.map((port) => ({
|
|
453
|
+
schematicPortId: CircuitJsonIndexer.getElementId(port),
|
|
454
|
+
schematicComponentId: String(
|
|
455
|
+
port.schematic_component_id || ''
|
|
456
|
+
).trim()
|
|
457
|
+
}))
|
|
458
|
+
.filter(
|
|
459
|
+
(port) =>
|
|
460
|
+
port.schematicComponentId &&
|
|
461
|
+
!schematicComponentIds.has(port.schematicComponentId)
|
|
462
|
+
)
|
|
463
|
+
.map((port) => ({
|
|
464
|
+
isGenerated: true,
|
|
465
|
+
severity: 'warning',
|
|
466
|
+
sourceFormat: 'circuitjson',
|
|
467
|
+
type: 'schematic_port_missing_schematic_component_warning',
|
|
468
|
+
category: 'layout',
|
|
469
|
+
message:
|
|
470
|
+
'Schematic port ' +
|
|
471
|
+
port.schematicPortId +
|
|
472
|
+
' references missing schematic component ' +
|
|
473
|
+
port.schematicComponentId +
|
|
474
|
+
'.',
|
|
475
|
+
elementId:
|
|
476
|
+
port.schematicPortId +
|
|
477
|
+
':missing-component:' +
|
|
478
|
+
port.schematicComponentId,
|
|
479
|
+
schematicComponentId: port.schematicComponentId,
|
|
480
|
+
schematicPortId: port.schematicPortId
|
|
481
|
+
}))
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Builds schematic-port missing source-port diagnostics.
|
|
486
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
487
|
+
* @param {Set<string>} sourcePortIds Known source port ids.
|
|
488
|
+
* @returns {object[]}
|
|
489
|
+
*/
|
|
490
|
+
static #missingSchematicPortSourcePortDiagnostics(
|
|
491
|
+
elementsByType,
|
|
492
|
+
sourcePortIds
|
|
493
|
+
) {
|
|
494
|
+
return CircuitJsonIndexer.#all(elementsByType, 'schematic_port')
|
|
495
|
+
.map((port) => ({
|
|
496
|
+
schematicPortId: CircuitJsonIndexer.getElementId(port),
|
|
497
|
+
sourcePortId: String(port.source_port_id || '').trim()
|
|
498
|
+
}))
|
|
499
|
+
.filter(
|
|
500
|
+
(port) =>
|
|
501
|
+
port.sourcePortId && !sourcePortIds.has(port.sourcePortId)
|
|
502
|
+
)
|
|
503
|
+
.map((port) => ({
|
|
504
|
+
isGenerated: true,
|
|
505
|
+
severity: 'warning',
|
|
506
|
+
sourceFormat: 'circuitjson',
|
|
507
|
+
type: 'schematic_port_missing_source_port_warning',
|
|
508
|
+
category: 'connectivity',
|
|
509
|
+
message:
|
|
510
|
+
'Schematic port ' +
|
|
511
|
+
port.schematicPortId +
|
|
512
|
+
' references missing source port ' +
|
|
513
|
+
port.sourcePortId +
|
|
514
|
+
'.',
|
|
515
|
+
elementId:
|
|
516
|
+
port.schematicPortId +
|
|
517
|
+
':missing-source-port:' +
|
|
518
|
+
port.sourcePortId,
|
|
519
|
+
schematicPortId: port.schematicPortId,
|
|
520
|
+
sourcePortId: port.sourcePortId
|
|
521
|
+
}))
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Builds schematic primitive missing relation diagnostics.
|
|
526
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
527
|
+
* @param {Set<string>} schematicSymbolIds Known schematic symbol ids.
|
|
528
|
+
* @param {Set<string>} schematicComponentIds Known schematic component ids.
|
|
529
|
+
* @returns {object[]}
|
|
530
|
+
*/
|
|
531
|
+
static #missingSchematicPrimitiveDiagnostics(
|
|
532
|
+
elementsByType,
|
|
533
|
+
schematicSymbolIds,
|
|
534
|
+
schematicComponentIds
|
|
535
|
+
) {
|
|
536
|
+
return [...SCHEMATIC_PRIMITIVE_TYPES].flatMap((type) =>
|
|
537
|
+
CircuitJsonIndexer.#all(elementsByType, type).flatMap((element) =>
|
|
538
|
+
CircuitJsonIndexer.#missingSchematicPrimitiveElementDiagnostics(
|
|
539
|
+
element,
|
|
540
|
+
schematicSymbolIds,
|
|
541
|
+
schematicComponentIds
|
|
542
|
+
)
|
|
543
|
+
)
|
|
544
|
+
)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Builds schematic primitive diagnostics for one element.
|
|
549
|
+
* @param {object} element Schematic primitive row.
|
|
550
|
+
* @param {Set<string>} schematicSymbolIds Known schematic symbol ids.
|
|
551
|
+
* @param {Set<string>} schematicComponentIds Known schematic component ids.
|
|
552
|
+
* @returns {object[]}
|
|
553
|
+
*/
|
|
554
|
+
static #missingSchematicPrimitiveElementDiagnostics(
|
|
555
|
+
element,
|
|
556
|
+
schematicSymbolIds,
|
|
557
|
+
schematicComponentIds
|
|
558
|
+
) {
|
|
559
|
+
const primitiveId = CircuitJsonIndexer.getElementId(element)
|
|
560
|
+
const diagnostics = []
|
|
561
|
+
const schematicSymbolId = String(
|
|
562
|
+
element.schematic_symbol_id || ''
|
|
563
|
+
).trim()
|
|
564
|
+
const schematicComponentId = String(
|
|
565
|
+
element.schematic_component_id || ''
|
|
566
|
+
).trim()
|
|
567
|
+
|
|
568
|
+
if (schematicSymbolId && !schematicSymbolIds.has(schematicSymbolId)) {
|
|
569
|
+
diagnostics.push({
|
|
570
|
+
isGenerated: true,
|
|
571
|
+
severity: 'warning',
|
|
572
|
+
sourceFormat: 'circuitjson',
|
|
573
|
+
type: 'schematic_primitive_missing_schematic_symbol_warning',
|
|
574
|
+
category: 'layout',
|
|
575
|
+
message:
|
|
576
|
+
'Schematic primitive ' +
|
|
577
|
+
primitiveId +
|
|
578
|
+
' references missing schematic symbol ' +
|
|
579
|
+
schematicSymbolId +
|
|
580
|
+
'.',
|
|
581
|
+
elementId: primitiveId + ':missing-symbol:' + schematicSymbolId,
|
|
582
|
+
schematicSymbolId
|
|
583
|
+
})
|
|
584
|
+
}
|
|
585
|
+
if (
|
|
586
|
+
schematicComponentId &&
|
|
587
|
+
!schematicComponentIds.has(schematicComponentId)
|
|
588
|
+
) {
|
|
589
|
+
diagnostics.push({
|
|
590
|
+
isGenerated: true,
|
|
591
|
+
severity: 'warning',
|
|
592
|
+
sourceFormat: 'circuitjson',
|
|
593
|
+
type: 'schematic_primitive_missing_schematic_component_warning',
|
|
594
|
+
category: 'layout',
|
|
595
|
+
message:
|
|
596
|
+
'Schematic primitive ' +
|
|
597
|
+
primitiveId +
|
|
598
|
+
' references missing schematic component ' +
|
|
599
|
+
schematicComponentId +
|
|
600
|
+
'.',
|
|
601
|
+
elementId:
|
|
602
|
+
primitiveId + ':missing-component:' + schematicComponentId,
|
|
603
|
+
schematicComponentId
|
|
604
|
+
})
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return diagnostics
|
|
608
|
+
}
|
|
609
|
+
|
|
172
610
|
/**
|
|
173
611
|
* Builds group rows keyed by group id.
|
|
174
612
|
* @param {object[]} elements Element rows.
|
|
@@ -226,6 +664,20 @@ export class CircuitJsonIndexer {
|
|
|
226
664
|
return bySubcircuitId
|
|
227
665
|
}
|
|
228
666
|
|
|
667
|
+
/**
|
|
668
|
+
* Builds a set of known element ids for one type.
|
|
669
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
670
|
+
* @param {string} type Element type.
|
|
671
|
+
* @returns {Set<string>}
|
|
672
|
+
*/
|
|
673
|
+
static #elementIds(elementsByType, type) {
|
|
674
|
+
return new Set(
|
|
675
|
+
CircuitJsonIndexer.#all(elementsByType, type)
|
|
676
|
+
.map((element) => CircuitJsonIndexer.getElementId(element))
|
|
677
|
+
.filter(Boolean)
|
|
678
|
+
)
|
|
679
|
+
}
|
|
680
|
+
|
|
229
681
|
/**
|
|
230
682
|
* Resolves group ids from common group fields.
|
|
231
683
|
* @param {object} element Element row.
|
|
@@ -237,12 +689,36 @@ export class CircuitJsonIndexer {
|
|
|
237
689
|
element?.pcb_group_id,
|
|
238
690
|
element?.schematic_group_id,
|
|
239
691
|
element?.group_id,
|
|
240
|
-
|
|
692
|
+
element?.member_source_group_id,
|
|
693
|
+
element?.member_pcb_group_id,
|
|
694
|
+
element?.member_schematic_group_id,
|
|
695
|
+
element?.member_group_id,
|
|
696
|
+
...CircuitJsonIndexer.#relationValues(element?.group_ids),
|
|
697
|
+
...CircuitJsonIndexer.#relationValues(
|
|
698
|
+
element?.member_source_group_ids
|
|
699
|
+
),
|
|
700
|
+
...CircuitJsonIndexer.#relationValues(
|
|
701
|
+
element?.member_pcb_group_ids
|
|
702
|
+
),
|
|
703
|
+
...CircuitJsonIndexer.#relationValues(
|
|
704
|
+
element?.member_schematic_group_ids
|
|
705
|
+
),
|
|
706
|
+
...CircuitJsonIndexer.#relationValues(element?.member_group_ids)
|
|
241
707
|
]
|
|
242
708
|
.map((value) => String(value || '').trim())
|
|
243
709
|
.filter(Boolean)
|
|
244
710
|
}
|
|
245
711
|
|
|
712
|
+
/**
|
|
713
|
+
* Returns indexed element rows by type.
|
|
714
|
+
* @param {Map<string, object[]>} elementsByType Element rows by type.
|
|
715
|
+
* @param {string} type Element type.
|
|
716
|
+
* @returns {object[]}
|
|
717
|
+
*/
|
|
718
|
+
static #all(elementsByType, type) {
|
|
719
|
+
return elementsByType.get(type) || []
|
|
720
|
+
}
|
|
721
|
+
|
|
246
722
|
/**
|
|
247
723
|
* Returns true when an element is a warning or error row.
|
|
248
724
|
* @param {object} element Element.
|
|
@@ -272,10 +748,39 @@ export class CircuitJsonIndexer {
|
|
|
272
748
|
type,
|
|
273
749
|
category: CircuitJsonIndexer.#diagnosticCategory(type),
|
|
274
750
|
message: String(element?.message || type || 'CircuitJSON issue'),
|
|
275
|
-
elementId: CircuitJsonIndexer.getElementId(element)
|
|
751
|
+
elementId: CircuitJsonIndexer.getElementId(element),
|
|
752
|
+
...CircuitJsonIndexer.#diagnosticRelations(element)
|
|
276
753
|
}
|
|
277
754
|
}
|
|
278
755
|
|
|
756
|
+
/**
|
|
757
|
+
* Extracts optional relation ids from one diagnostic element.
|
|
758
|
+
* @param {object} element Diagnostic element.
|
|
759
|
+
* @returns {object}
|
|
760
|
+
*/
|
|
761
|
+
static #diagnosticRelations(element) {
|
|
762
|
+
return Object.fromEntries(
|
|
763
|
+
[
|
|
764
|
+
['sourceComponentId', element?.source_component_id],
|
|
765
|
+
['sourcePortId', element?.source_port_id],
|
|
766
|
+
['sourceNetId', element?.source_net_id],
|
|
767
|
+
['sourceTraceId', element?.source_trace_id],
|
|
768
|
+
['pcbComponentId', element?.pcb_component_id],
|
|
769
|
+
['pcbPortId', element?.pcb_port_id],
|
|
770
|
+
['pcbTraceId', element?.pcb_trace_id],
|
|
771
|
+
['pcbSmtpadId', element?.pcb_smtpad_id],
|
|
772
|
+
['pcbViaId', element?.pcb_via_id],
|
|
773
|
+
['pcbPlatedHoleId', element?.pcb_plated_hole_id],
|
|
774
|
+
['pcbHoleId', element?.pcb_hole_id],
|
|
775
|
+
['schematicComponentId', element?.schematic_component_id],
|
|
776
|
+
['schematicSymbolId', element?.schematic_symbol_id],
|
|
777
|
+
['schematicPortId', element?.schematic_port_id]
|
|
778
|
+
]
|
|
779
|
+
.map(([key, value]) => [key, String(value || '').trim()])
|
|
780
|
+
.filter(([_key, value]) => value)
|
|
781
|
+
)
|
|
782
|
+
}
|
|
783
|
+
|
|
279
784
|
/**
|
|
280
785
|
* Resolves a broad diagnostic category.
|
|
281
786
|
* @param {string} type Diagnostic type or code.
|