circuitjson-toolkit 1.0.16 → 1.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.
- package/AGENTS.md +15 -0
- package/NOTICE.md +31 -0
- package/README.md +267 -107
- package/docs/api.md +501 -96
- package/docs/capabilities.md +70 -0
- package/docs/migration/behaviors.md +45 -0
- package/docs/migration/parser.md +60 -0
- package/docs/migration/renderers.md +515 -0
- package/docs/migration/root.md +740 -0
- package/docs/migration.md +120 -0
- package/docs/model-format.md +175 -57
- package/docs/provenance.md +206 -0
- package/docs/release-notes-v1.1.0.md +154 -0
- package/docs/testing.md +117 -7
- package/package.json +31 -5
- package/spec/api-baseline-v1.0.17.json +1 -0
- package/spec/baseline-provenance-v1.0.17.json +7 -0
- package/spec/circuitjson-schema-snapshot.json +321 -0
- package/spec/circuitjson-schema-source.json +28 -0
- package/spec/feature-preservation.json +1 -0
- package/spec/library-scope.md +27 -20
- package/src/capabilities.mjs +1 -0
- package/src/core/ArchiveEntryPath.mjs +93 -0
- package/src/core/ArchiveLimits.mjs +31 -0
- package/src/core/ArchiveLimitsValidator.mjs +107 -0
- package/src/core/AsyncInputOwnership.mjs +56 -0
- package/src/core/AttachedValueLimits.mjs +67 -0
- package/src/core/CircuitJsonDiagnosticIndexer.mjs +184 -0
- package/src/core/CircuitJsonDocument.mjs +19 -61
- package/src/core/CircuitJsonElementTypes.mjs +10 -0
- package/src/core/CircuitJsonElementValidator.mjs +98 -847
- package/src/core/CircuitJsonIndexer.mjs +274 -194
- package/src/core/CircuitJsonManufacturingBuilder.mjs +167 -164
- package/src/core/CircuitJsonParser.mjs +75 -13
- package/src/core/CircuitJsonPcbClearanceDiagnostics.mjs +12 -6
- package/src/core/CircuitJsonPcbHolePrimitiveModel.mjs +108 -10
- package/src/core/CircuitJsonPcbPadPrimitiveModel.mjs +1 -1
- package/src/core/CircuitJsonPcbPrimitiveArtwork.mjs +44 -38
- package/src/core/CircuitJsonPcbPrimitiveBuilder.mjs +146 -28
- package/src/core/CircuitJsonPcbPrimitiveFields.mjs +70 -4
- package/src/core/CircuitJsonPcbPrimitiveIndex.mjs +18 -2
- package/src/core/CircuitJsonPcbPrimitiveOverlays.mjs +26 -9
- package/src/core/CircuitJsonPcbZonePrimitiveBuilder.mjs +7 -6
- package/src/core/CircuitJsonSerializedInputAudit.mjs +87 -0
- package/src/core/CircuitJsonSourceMetadata.mjs +5 -1
- package/src/core/CircuitJsonSupportMatrixBuilder.mjs +3 -1
- package/src/core/CircuitJsonToolkitElementSchema.mjs +218 -0
- package/src/core/CircuitJsonUnitParsers.mjs +101 -0
- package/src/core/CircuitJsonUnits.mjs +13 -87
- package/src/core/CircuitJsonUpstreamSchema.mjs +9 -0
- package/src/core/CircuitJsonUpstreamValidator.mjs +418 -0
- package/src/core/CircuitJsonValidationUnits.mjs +6 -0
- package/src/core/ManufacturingService.mjs +323 -0
- package/src/core/Parser.mjs +343 -0
- package/src/core/ParserOptions.mjs +333 -0
- package/src/core/PcbBoundsSelectionModel.mjs +55 -19
- package/src/core/PcbDiagnosticFocusModel.mjs +42 -11
- package/src/core/PcbInteractionIndex.mjs +368 -0
- package/src/core/PcbInteractionPrimitiveModel.mjs +393 -62
- package/src/core/ProjectAsyncInputOwner.mjs +70 -0
- package/src/core/ProjectLoader.mjs +975 -0
- package/src/core/SimulationService.mjs +790 -0
- package/src/core/ToolkitCapabilities.mjs +130 -0
- package/src/core/ZipArchiveInspector.mjs +649 -0
- package/src/core/context/BinaryDataSnapshot.mjs +217 -0
- package/src/core/context/CircuitJsonContextIndexes.mjs +96 -0
- package/src/core/context/CircuitJsonDerivedCache.mjs +114 -0
- package/src/core/context/CircuitJsonDocumentContext.mjs +353 -0
- package/src/core/context/CircuitJsonLegacyModel.mjs +147 -0
- package/src/core/context/CircuitJsonLegacyNormalizer.mjs +847 -0
- package/src/core/context/CircuitJsonMetadataBoundary.mjs +76 -0
- package/src/core/context/CircuitJsonModelFreezeTraversal.mjs +179 -0
- package/src/core/context/CircuitJsonReadOnlyDocument.mjs +920 -0
- package/src/core/context/CircuitJsonSchematicTableNormalizer.mjs +314 -0
- package/src/core/context/CircuitJsonValidationAuthority.mjs +39 -0
- package/src/core/context/CircuitJsonValidationProof.mjs +217 -0
- package/src/core/context/PcbPrimitivePreparation.mjs +198 -0
- package/src/core/context/PcbSpatialIndex.mjs +701 -0
- package/src/core/context/ProtectedExtensionBinaryBoundary.mjs +128 -0
- package/src/core/context/StructuredDataSnapshot.mjs +683 -0
- package/src/core/contracts/DocumentResult.mjs +198 -0
- package/src/core/contracts/ProjectResult.mjs +96 -0
- package/src/core/contracts/RuntimeProxyBoundary.mjs +48 -0
- package/src/core/contracts/ToolkitAsset.mjs +493 -0
- package/src/core/contracts/ToolkitDiagnostic.mjs +38 -0
- package/src/core/contracts/ToolkitError.mjs +176 -0
- package/src/core/contracts/ToolkitProgress.mjs +89 -0
- package/src/core/interaction/CanonicalInteractionOptions.mjs +246 -0
- package/src/core/interaction/PcbInteractionBounds.mjs +167 -0
- package/src/core/query/CircuitTraversal.mjs +343 -0
- package/src/core/query/ComponentGrouping.mjs +275 -0
- package/src/core/query/QueryNetlistBuilder.mjs +306 -0
- package/src/core/query/QueryService.mjs +435 -0
- package/src/core/query/RegexPattern.mjs +75 -0
- package/src/core/rendering/CanonicalBomOrder.mjs +81 -0
- package/src/core/rendering/CanonicalBomRows.mjs +92 -0
- package/src/core/rendering/CanonicalRenderOptions.mjs +498 -0
- package/src/core/rendering/CanonicalSvgDocument.mjs +102 -0
- package/src/core/rendering/PcbRenderPlan.mjs +429 -0
- package/src/core/rendering/SchematicSheetSelector.mjs +335 -0
- package/src/core/scene3d/PcbScene3dBuilder.mjs +906 -0
- package/src/core/scene3d/PcbScene3dPreparator.mjs +47 -0
- package/src/core/scene3d/Scene3dAssetIndex.mjs +284 -0
- package/src/core/scene3d/Scene3dBoardModel.mjs +596 -0
- package/src/core/scene3d/Scene3dDocumentMetadata.mjs +167 -0
- package/src/core/scene3d/Scene3dFreeze.mjs +37 -0
- package/src/core/scene3d/Scene3dIdRegistry.mjs +34 -0
- package/src/core/scene3d/Scene3dInputPreflight.mjs +193 -0
- package/src/core/scene3d/Scene3dMaterials.mjs +58 -0
- package/src/core/scene3d/Scene3dModelReference.mjs +134 -0
- package/src/core/scene3d/Scene3dOptions.mjs +363 -0
- package/src/core/scene3d/SceneAssetResolver.mjs +441 -0
- package/src/core/simulation/SimulationParameterCloner.mjs +543 -0
- package/src/core/worker/ParserWorkerClient.mjs +997 -0
- package/src/core/worker/ToolkitWorkerProtocol.mjs +412 -0
- package/src/core/worker/WorkerRequestData.mjs +623 -0
- package/src/core/worker/WorkerResponseData.mjs +905 -0
- package/src/extensions.mjs +37 -0
- package/src/index.mjs +14 -9
- package/src/interaction.mjs +2 -0
- package/src/manufacturing.mjs +1 -0
- package/src/parser.mjs +12 -2
- package/src/project.mjs +5 -0
- package/src/query.mjs +1 -0
- package/src/renderers.mjs +3 -29
- package/src/scene3d.mjs +3 -0
- package/src/simulation.mjs +1 -0
- package/src/styles/renderers.css +24 -0
- package/src/testing/ToolkitContractFixtures.mjs +124 -0
- package/src/testing/ToolkitLoopbackWorker.mjs +174 -0
- package/src/testing/runToolkitContract.mjs +705 -0
- package/src/testing.mjs +3 -0
- package/src/ui/BomTableRenderer.mjs +304 -0
- package/src/ui/CircuitJsonPcbBoardSvgRenderer.mjs +80 -0
- package/src/ui/CircuitJsonPcbPrimitiveAttributeRenderer.mjs +3 -5
- package/src/ui/CircuitJsonPcbSvgRenderer.mjs +63 -43
- package/src/ui/CircuitJsonPcbViaSvgRenderer.mjs +3 -5
- package/src/ui/CircuitJsonSchematicDebugRenderer.mjs +164 -0
- package/src/ui/CircuitJsonSchematicImageSvgRenderer.mjs +210 -0
- package/src/ui/CircuitJsonSchematicLineRenderer.mjs +86 -0
- package/src/ui/CircuitJsonSchematicSheetSymbolSvgRenderer.mjs +98 -0
- package/src/ui/CircuitJsonSchematicSvgArcPath.mjs +117 -17
- package/src/ui/CircuitJsonSchematicSvgPortMetadata.mjs +67 -20
- package/src/ui/CircuitJsonSchematicSvgPrimitiveAttributes.mjs +45 -9
- package/src/ui/CircuitJsonSchematicSvgRenderer.mjs +151 -148
- package/src/ui/CircuitJsonSchematicTableSvgRenderer.mjs +4 -292
- package/src/ui/PcbSvgRenderer.mjs +41 -0
- package/src/ui/SafeSvgPaint.mjs +26 -0
- package/src/ui/SafeXmlText.mjs +60 -0
- package/src/ui/SchematicGeometryBounds.mjs +540 -0
- package/src/ui/SchematicSvgRenderer.mjs +110 -0
- package/src/ui/SchematicTableGeometry.mjs +319 -0
- package/src/ui/SchematicTextAnchor.mjs +55 -0
- package/src/ui/SchematicTextBounds.mjs +98 -0
- package/src/workers/parser.worker.mjs +59 -0
|
@@ -12,12 +12,21 @@ export class CircuitJsonManufacturingBuilder {
|
|
|
12
12
|
* @returns {{ pickAndPlaceRows: object[], routingDsn: string, routingGuides: object[], fabricationNotes: object[] }}
|
|
13
13
|
*/
|
|
14
14
|
static build(circuitJson, index = CircuitJsonIndexer.index(circuitJson)) {
|
|
15
|
+
const pickAndPlaceRows =
|
|
16
|
+
CircuitJsonManufacturingBuilder.#pickAndPlaceRows(index)
|
|
17
|
+
const sourceNetNames =
|
|
18
|
+
CircuitJsonManufacturingBuilder.#sourceNetNames(index)
|
|
15
19
|
return {
|
|
16
|
-
pickAndPlaceRows
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
pickAndPlaceRows,
|
|
21
|
+
routingDsn: CircuitJsonManufacturingBuilder.#routingDsn(
|
|
22
|
+
index,
|
|
23
|
+
pickAndPlaceRows,
|
|
24
|
+
sourceNetNames
|
|
25
|
+
),
|
|
26
|
+
routingGuides: CircuitJsonManufacturingBuilder.#routingGuides(
|
|
27
|
+
index,
|
|
28
|
+
sourceNetNames
|
|
29
|
+
),
|
|
21
30
|
fabricationNotes:
|
|
22
31
|
CircuitJsonManufacturingBuilder.#fabricationNotes(index)
|
|
23
32
|
}
|
|
@@ -85,13 +94,26 @@ export class CircuitJsonManufacturingBuilder {
|
|
|
85
94
|
/**
|
|
86
95
|
* Builds a compact routing exchange text payload.
|
|
87
96
|
* @param {{ elementsByType?: Map<string, object[]> }} index Element index.
|
|
97
|
+
* @param {object[]} placements Prepared placement rows.
|
|
98
|
+
* @param {Map<string, string>} sourceNetNames Shared source-net lookup.
|
|
88
99
|
* @returns {string}
|
|
89
100
|
*/
|
|
90
|
-
static #routingDsn(index) {
|
|
101
|
+
static #routingDsn(index, placements, sourceNetNames) {
|
|
91
102
|
const lines = ['(pcb assembly)', ' (unit mm)']
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
for (const line of CircuitJsonManufacturingBuilder.#boardLines(index)) {
|
|
104
|
+
lines.push(line)
|
|
105
|
+
}
|
|
106
|
+
for (const line of CircuitJsonManufacturingBuilder.#placementLines(
|
|
107
|
+
placements
|
|
108
|
+
)) {
|
|
109
|
+
lines.push(line)
|
|
110
|
+
}
|
|
111
|
+
for (const line of CircuitJsonManufacturingBuilder.#networkLines(
|
|
112
|
+
index,
|
|
113
|
+
sourceNetNames
|
|
114
|
+
)) {
|
|
115
|
+
lines.push(line)
|
|
116
|
+
}
|
|
95
117
|
lines.push(')')
|
|
96
118
|
return lines.join('\n')
|
|
97
119
|
}
|
|
@@ -139,13 +161,13 @@ export class CircuitJsonManufacturingBuilder {
|
|
|
139
161
|
|
|
140
162
|
/**
|
|
141
163
|
* Builds component placement lines.
|
|
142
|
-
* @param {
|
|
164
|
+
* @param {object[]} rows Prepared placement rows.
|
|
143
165
|
* @returns {string[]}
|
|
144
166
|
*/
|
|
145
|
-
static #placementLines(
|
|
167
|
+
static #placementLines(rows) {
|
|
146
168
|
return [
|
|
147
169
|
' (placement',
|
|
148
|
-
...
|
|
170
|
+
...rows.map(
|
|
149
171
|
(row) =>
|
|
150
172
|
' (component ' +
|
|
151
173
|
CircuitJsonManufacturingBuilder.#token(row.designator) +
|
|
@@ -165,112 +187,149 @@ export class CircuitJsonManufacturingBuilder {
|
|
|
165
187
|
/**
|
|
166
188
|
* Builds network lines for nets, pads, vias, and wires.
|
|
167
189
|
* @param {{ elementsByType?: Map<string, object[]> }} index Element index.
|
|
190
|
+
* @param {Map<string, string>} sourceNetNames Shared source-net lookup.
|
|
168
191
|
* @returns {string[]}
|
|
169
192
|
*/
|
|
170
|
-
static #networkLines(index) {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
sourceNetNames
|
|
188
|
-
),
|
|
189
|
-
...CircuitJsonManufacturingBuilder.#wireLines(
|
|
190
|
-
index,
|
|
191
|
-
netName,
|
|
192
|
-
sourceNetNames
|
|
193
|
-
),
|
|
194
|
-
' )'
|
|
195
|
-
]
|
|
196
|
-
),
|
|
197
|
-
' )'
|
|
198
|
-
]
|
|
193
|
+
static #networkLines(index, sourceNetNames) {
|
|
194
|
+
const model = CircuitJsonManufacturingBuilder.#networkModel(
|
|
195
|
+
index,
|
|
196
|
+
sourceNetNames
|
|
197
|
+
)
|
|
198
|
+
const lines = [' (network']
|
|
199
|
+
for (const netName of model.names) {
|
|
200
|
+
lines.push(
|
|
201
|
+
' (net ' + CircuitJsonManufacturingBuilder.#token(netName)
|
|
202
|
+
)
|
|
203
|
+
for (const family of [model.pins, model.drills, model.wires]) {
|
|
204
|
+
for (const line of family.get(netName) || []) lines.push(line)
|
|
205
|
+
}
|
|
206
|
+
lines.push(' )')
|
|
207
|
+
}
|
|
208
|
+
lines.push(' )')
|
|
209
|
+
return lines
|
|
199
210
|
}
|
|
200
211
|
|
|
201
212
|
/**
|
|
202
|
-
*
|
|
213
|
+
* Groups routing features by net with one pass per element family.
|
|
203
214
|
* @param {{ elementsByType?: Map<string, object[]> }} index Element index.
|
|
204
|
-
* @param {string}
|
|
205
|
-
* @
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
* @param {Map<string, string>} sourceNetNames Shared source-net lookup.
|
|
216
|
+
* @returns {{ names: string[], pins: Map<string, string[]>, drills: Map<string, string[]>, wires: Map<string, string[]> }} Grouped network model.
|
|
217
|
+
*/
|
|
218
|
+
static #networkModel(index, sourceNetNames) {
|
|
219
|
+
const names = new Set([...sourceNetNames.values()].filter(Boolean))
|
|
220
|
+
const pins = new Map()
|
|
221
|
+
const drills = new Map()
|
|
222
|
+
const wires = new Map()
|
|
223
|
+
for (const pad of CircuitJsonManufacturingBuilder.#all(
|
|
224
|
+
index,
|
|
225
|
+
'pcb_smtpad'
|
|
226
|
+
)) {
|
|
227
|
+
const netName = CircuitJsonManufacturingBuilder.#netName(
|
|
228
|
+
pad,
|
|
229
|
+
sourceNetNames
|
|
216
230
|
)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
if (!netName) continue
|
|
232
|
+
CircuitJsonManufacturingBuilder.#appendNetworkLines(
|
|
233
|
+
pins,
|
|
234
|
+
netName,
|
|
235
|
+
[CircuitJsonManufacturingBuilder.#pinLine(pad)],
|
|
236
|
+
names
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
for (const [type, kind] of [
|
|
240
|
+
['pcb_via', 'via'],
|
|
241
|
+
['pcb_plated_hole', 'plated_hole']
|
|
242
|
+
]) {
|
|
243
|
+
for (const element of CircuitJsonManufacturingBuilder.#all(
|
|
244
|
+
index,
|
|
245
|
+
type
|
|
246
|
+
)) {
|
|
247
|
+
const netName = CircuitJsonManufacturingBuilder.#netName(
|
|
248
|
+
element,
|
|
249
|
+
sourceNetNames
|
|
250
|
+
)
|
|
251
|
+
if (!netName) continue
|
|
252
|
+
CircuitJsonManufacturingBuilder.#appendNetworkLines(
|
|
253
|
+
drills,
|
|
254
|
+
netName,
|
|
255
|
+
[CircuitJsonManufacturingBuilder.#drillLine(element, kind)],
|
|
256
|
+
names
|
|
235
257
|
)
|
|
236
|
-
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
for (const trace of CircuitJsonManufacturingBuilder.#all(
|
|
261
|
+
index,
|
|
262
|
+
'pcb_trace'
|
|
263
|
+
)) {
|
|
264
|
+
const netName = CircuitJsonManufacturingBuilder.#netName(
|
|
265
|
+
trace,
|
|
266
|
+
sourceNetNames
|
|
267
|
+
)
|
|
268
|
+
if (!netName) continue
|
|
269
|
+
CircuitJsonManufacturingBuilder.#appendNetworkLines(
|
|
270
|
+
wires,
|
|
271
|
+
netName,
|
|
272
|
+
CircuitJsonManufacturingBuilder.#traceWireLines(trace),
|
|
273
|
+
names
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
for (const type of ['pcb_trace_hint', 'pcb_breakout_point']) {
|
|
277
|
+
for (const element of CircuitJsonManufacturingBuilder.#all(
|
|
278
|
+
index,
|
|
279
|
+
type
|
|
280
|
+
)) {
|
|
281
|
+
const name = CircuitJsonManufacturingBuilder.#netName(
|
|
282
|
+
element,
|
|
283
|
+
sourceNetNames
|
|
284
|
+
)
|
|
285
|
+
if (name) names.add(name)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
names: [...names].sort((left, right) => left.localeCompare(right)),
|
|
290
|
+
pins,
|
|
291
|
+
drills,
|
|
292
|
+
wires
|
|
293
|
+
}
|
|
237
294
|
}
|
|
238
295
|
|
|
239
296
|
/**
|
|
240
|
-
* Builds
|
|
241
|
-
* @param {
|
|
242
|
-
* @
|
|
243
|
-
* @param {Map<string, string>} sourceNetNames Source net lookup.
|
|
244
|
-
* @returns {string[]}
|
|
297
|
+
* Builds one pad pin line.
|
|
298
|
+
* @param {object} pad Pad element.
|
|
299
|
+
* @returns {string} Pin line.
|
|
245
300
|
*/
|
|
246
|
-
static #
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
301
|
+
static #pinLine(pad) {
|
|
302
|
+
const point = CircuitJsonUnits.optionalPoint(pad.center || pad) || {
|
|
303
|
+
x: 0,
|
|
304
|
+
y: 0
|
|
305
|
+
}
|
|
306
|
+
return (
|
|
307
|
+
' (pin ' +
|
|
308
|
+
CircuitJsonManufacturingBuilder.#token(pad.pcb_smtpad_id || '') +
|
|
309
|
+
' ' +
|
|
310
|
+
[
|
|
311
|
+
CircuitJsonManufacturingBuilder.#round(point.x),
|
|
312
|
+
CircuitJsonManufacturingBuilder.#round(point.y)
|
|
313
|
+
].join(' ') +
|
|
314
|
+
')'
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Appends non-empty feature lines and records their net name.
|
|
320
|
+
* @param {Map<string, string[]>} target Lines grouped by net.
|
|
321
|
+
* @param {string} netName Net name.
|
|
322
|
+
* @param {string[]} lines Feature lines.
|
|
323
|
+
* @param {Set<string>} names Discovered net names.
|
|
324
|
+
* @returns {void}
|
|
325
|
+
*/
|
|
326
|
+
static #appendNetworkLines(target, netName, lines, names) {
|
|
327
|
+
if (!netName) return
|
|
328
|
+
names.add(netName)
|
|
329
|
+
if (!target.has(netName)) target.set(netName, [])
|
|
330
|
+
for (const line of lines) {
|
|
331
|
+
if (line) target.get(netName).push(line)
|
|
332
|
+
}
|
|
274
333
|
}
|
|
275
334
|
|
|
276
335
|
/**
|
|
@@ -307,27 +366,6 @@ export class CircuitJsonManufacturingBuilder {
|
|
|
307
366
|
)
|
|
308
367
|
}
|
|
309
368
|
|
|
310
|
-
/**
|
|
311
|
-
* Builds routed wire lines for one net.
|
|
312
|
-
* @param {{ elementsByType?: Map<string, object[]> }} index Element index.
|
|
313
|
-
* @param {string} netName Net name.
|
|
314
|
-
* @param {Map<string, string>} sourceNetNames Source net lookup.
|
|
315
|
-
* @returns {string[]}
|
|
316
|
-
*/
|
|
317
|
-
static #wireLines(index, netName, sourceNetNames) {
|
|
318
|
-
return CircuitJsonManufacturingBuilder.#all(index, 'pcb_trace')
|
|
319
|
-
.filter(
|
|
320
|
-
(trace) =>
|
|
321
|
-
CircuitJsonManufacturingBuilder.#netName(
|
|
322
|
-
trace,
|
|
323
|
-
sourceNetNames
|
|
324
|
-
) === netName
|
|
325
|
-
)
|
|
326
|
-
.flatMap((trace) =>
|
|
327
|
-
CircuitJsonManufacturingBuilder.#traceWireLines(trace)
|
|
328
|
-
)
|
|
329
|
-
}
|
|
330
|
-
|
|
331
369
|
/**
|
|
332
370
|
* Builds routed wire lines for one trace.
|
|
333
371
|
* @param {object} trace Trace element.
|
|
@@ -368,48 +406,13 @@ export class CircuitJsonManufacturingBuilder {
|
|
|
368
406
|
return lines
|
|
369
407
|
}
|
|
370
408
|
|
|
371
|
-
/**
|
|
372
|
-
* Builds sorted net names.
|
|
373
|
-
* @param {{ elementsByType?: Map<string, object[]> }} index Element index.
|
|
374
|
-
* @returns {string[]}
|
|
375
|
-
*/
|
|
376
|
-
static #netNames(index) {
|
|
377
|
-
const names = new Set()
|
|
378
|
-
const sourceNetNames =
|
|
379
|
-
CircuitJsonManufacturingBuilder.#sourceNetNames(index)
|
|
380
|
-
for (const name of sourceNetNames.values()) {
|
|
381
|
-
if (name) names.add(name)
|
|
382
|
-
}
|
|
383
|
-
for (const type of [
|
|
384
|
-
'pcb_smtpad',
|
|
385
|
-
'pcb_trace',
|
|
386
|
-
'pcb_via',
|
|
387
|
-
'pcb_plated_hole',
|
|
388
|
-
'pcb_trace_hint',
|
|
389
|
-
'pcb_breakout_point'
|
|
390
|
-
]) {
|
|
391
|
-
for (const element of CircuitJsonManufacturingBuilder.#all(
|
|
392
|
-
index,
|
|
393
|
-
type
|
|
394
|
-
)) {
|
|
395
|
-
const name = CircuitJsonManufacturingBuilder.#netName(
|
|
396
|
-
element,
|
|
397
|
-
sourceNetNames
|
|
398
|
-
)
|
|
399
|
-
if (name) names.add(name)
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
return [...names].sort((left, right) => left.localeCompare(right))
|
|
403
|
-
}
|
|
404
|
-
|
|
405
409
|
/**
|
|
406
410
|
* Builds route guide metadata from hints and breakout points.
|
|
407
411
|
* @param {{ elementsByType?: Map<string, object[]> }} index Element index.
|
|
412
|
+
* @param {Map<string, string>} sourceNetNames Shared source-net lookup.
|
|
408
413
|
* @returns {object[]}
|
|
409
414
|
*/
|
|
410
|
-
static #routingGuides(index) {
|
|
411
|
-
const sourceNetNames =
|
|
412
|
-
CircuitJsonManufacturingBuilder.#sourceNetNames(index)
|
|
415
|
+
static #routingGuides(index, sourceNetNames) {
|
|
413
416
|
return [
|
|
414
417
|
...CircuitJsonManufacturingBuilder.#all(index, 'pcb_trace_hint')
|
|
415
418
|
.map((hint) =>
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import { CircuitJsonDocument } from './CircuitJsonDocument.mjs'
|
|
2
1
|
import { CircuitJsonBomBuilder } from './CircuitJsonBomBuilder.mjs'
|
|
3
2
|
import { CircuitJsonIndexer } from './CircuitJsonIndexer.mjs'
|
|
4
3
|
import { CircuitJsonManufacturingBuilder } from './CircuitJsonManufacturingBuilder.mjs'
|
|
5
4
|
import { CircuitJsonSupportMatrixBuilder } from './CircuitJsonSupportMatrixBuilder.mjs'
|
|
5
|
+
import { Parser } from './Parser.mjs'
|
|
6
|
+
import { CircuitJsonLegacyModel } from './context/CircuitJsonLegacyModel.mjs'
|
|
7
|
+
import { CircuitJsonValidationProof } from './context/CircuitJsonValidationProof.mjs'
|
|
8
|
+
|
|
9
|
+
const SUPPORT_VARIANT_TYPES = new Set([
|
|
10
|
+
'source_component',
|
|
11
|
+
'pcb_board',
|
|
12
|
+
'pcb_smtpad',
|
|
13
|
+
'pcb_hole',
|
|
14
|
+
'pcb_plated_hole',
|
|
15
|
+
'pcb_solder_paste',
|
|
16
|
+
'pcb_cutout',
|
|
17
|
+
'pcb_copper_pour',
|
|
18
|
+
'simulation_voltage_source',
|
|
19
|
+
'simulation_current_source',
|
|
20
|
+
'simulation_experiment'
|
|
21
|
+
])
|
|
6
22
|
|
|
7
23
|
/**
|
|
8
24
|
* Parses standalone CircuitJSON files.
|
|
@@ -15,25 +31,36 @@ export class CircuitJsonParser {
|
|
|
15
31
|
* @returns {object[]}
|
|
16
32
|
*/
|
|
17
33
|
static parseText(text, options = {}) {
|
|
18
|
-
let
|
|
34
|
+
let document
|
|
19
35
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
36
|
+
document = Parser.parse(
|
|
37
|
+
{
|
|
38
|
+
fileName: options.fileName || '',
|
|
39
|
+
data: String(text || '')
|
|
40
|
+
},
|
|
41
|
+
{ extensions: 'full' }
|
|
25
42
|
)
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw CircuitJsonParser.#legacyError(error)
|
|
26
45
|
}
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
const index = CircuitJsonIndexer.index(
|
|
30
|
-
|
|
47
|
+
const parsed = CircuitJsonLegacyModel.create(document)
|
|
48
|
+
const index = CircuitJsonIndexer.index(
|
|
49
|
+
document.model,
|
|
50
|
+
CircuitJsonValidationProof.indexOptions(document)
|
|
51
|
+
)
|
|
52
|
+
CircuitJsonLegacyModel.setPreparedIndex(parsed, index)
|
|
53
|
+
return CircuitJsonLegacyModel.attachValidated(parsed, {
|
|
31
54
|
fileName: options.fileName || '',
|
|
32
55
|
fileType: 'circuitjson',
|
|
33
56
|
kind: CircuitJsonParser.#resolveKind(index),
|
|
34
|
-
diagnostics: index.diagnostics,
|
|
35
|
-
bom: CircuitJsonBomBuilder.build(
|
|
36
|
-
|
|
57
|
+
diagnostics: structuredClone(index.diagnostics),
|
|
58
|
+
bom: CircuitJsonBomBuilder.build(
|
|
59
|
+
index.elementsByType.get('source_component') || []
|
|
60
|
+
),
|
|
61
|
+
supportMatrix: CircuitJsonSupportMatrixBuilder.build(
|
|
62
|
+
CircuitJsonParser.#supportElements(index)
|
|
63
|
+
),
|
|
37
64
|
manufacturing: CircuitJsonManufacturingBuilder.build(parsed, index)
|
|
38
65
|
})
|
|
39
66
|
}
|
|
@@ -51,6 +78,23 @@ export class CircuitJsonParser {
|
|
|
51
78
|
return CircuitJsonParser.parseText(text, options)
|
|
52
79
|
}
|
|
53
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Restores the source-derived exception type and invalid-JSON message.
|
|
83
|
+
* @param {unknown} error Canonical parser failure.
|
|
84
|
+
* @returns {Error} Legacy parser error.
|
|
85
|
+
*/
|
|
86
|
+
static #legacyError(error) {
|
|
87
|
+
const cause = error?.cause
|
|
88
|
+
if (error?.code !== 'ERR_CIRCUITJSON_PARSE' || !cause) return error
|
|
89
|
+
if (cause.name === 'SyntaxError') {
|
|
90
|
+
return new SyntaxError(
|
|
91
|
+
'CircuitJSON file is not valid JSON: ' + cause.message
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
if (cause.name === 'TypeError') return new TypeError(cause.message)
|
|
95
|
+
return new Error(cause.message)
|
|
96
|
+
}
|
|
97
|
+
|
|
54
98
|
/**
|
|
55
99
|
* Resolves a broad document kind from available elements.
|
|
56
100
|
* @param {{ elementsByType?: Map<string, object[]> }} index Model index.
|
|
@@ -68,4 +112,22 @@ export class CircuitJsonParser {
|
|
|
68
112
|
|
|
69
113
|
return 'circuitjson'
|
|
70
114
|
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Selects one presence row per type plus all variant-bearing rows.
|
|
118
|
+
* @param {{ elementsByType?: Map<string, object[]> }} index Full element index.
|
|
119
|
+
* @returns {object[]} Minimal support-matrix input with identical semantics.
|
|
120
|
+
*/
|
|
121
|
+
static #supportElements(index) {
|
|
122
|
+
const elements = []
|
|
123
|
+
for (const [type, rows] of index.elementsByType || []) {
|
|
124
|
+
if (!rows.length) continue
|
|
125
|
+
if (SUPPORT_VARIANT_TYPES.has(type)) {
|
|
126
|
+
elements.push(...rows)
|
|
127
|
+
} else {
|
|
128
|
+
elements.push(rows[0])
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return elements
|
|
132
|
+
}
|
|
71
133
|
}
|
|
@@ -253,12 +253,18 @@ export class CircuitJsonPcbClearanceDiagnostics {
|
|
|
253
253
|
* @returns {object | null}
|
|
254
254
|
*/
|
|
255
255
|
static #mergeBounds(rows) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
256
|
+
let minX = Infinity
|
|
257
|
+
let minY = Infinity
|
|
258
|
+
let maxX = -Infinity
|
|
259
|
+
let maxY = -Infinity
|
|
260
|
+
for (const bounds of rows) {
|
|
261
|
+
if (!bounds) continue
|
|
262
|
+
minX = Math.min(minX, bounds.minX)
|
|
263
|
+
minY = Math.min(minY, bounds.minY)
|
|
264
|
+
maxX = Math.max(maxX, bounds.maxX)
|
|
265
|
+
maxY = Math.max(maxY, bounds.maxY)
|
|
266
|
+
}
|
|
267
|
+
if (!Number.isFinite(minX)) return null
|
|
262
268
|
return {
|
|
263
269
|
minX: this.#round(minX),
|
|
264
270
|
minY: this.#round(minY),
|