circuitjson-toolkit 1.0.17 → 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/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
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
const SELECTED_SCOPE = 1
|
|
2
|
+
const OTHER_SCOPE = 2
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Selects one CircuitJSON schematic sheet through explicit and owned relations.
|
|
6
|
+
*/
|
|
7
|
+
export class SchematicSheetSelector {
|
|
8
|
+
/**
|
|
9
|
+
* Builds an element-index view for one schematic sheet.
|
|
10
|
+
* @param {{ elements?: object[], elementsByType: Map<string, object[]> }} index Full element index.
|
|
11
|
+
* @param {string} sheetId Selected sheet id.
|
|
12
|
+
* @returns {{ elements: object[], elementsByType: Map<string, object[]>, statistics: { scopeUpdates: number, scopedElements: number } }} Sheet index view.
|
|
13
|
+
*/
|
|
14
|
+
static select(index, sheetId) {
|
|
15
|
+
const elements = Array.isArray(index.elements)
|
|
16
|
+
? index.elements
|
|
17
|
+
: Array.from(index.elementsByType.values()).flat()
|
|
18
|
+
const sheetCount = (index.elementsByType.get('schematic_sheet') || [])
|
|
19
|
+
.length
|
|
20
|
+
const scoped = SchematicSheetSelector.#scopes(elements, sheetId)
|
|
21
|
+
const elementsByType = new Map()
|
|
22
|
+
const selectedElements = []
|
|
23
|
+
for (const [type, rows] of index.elementsByType) {
|
|
24
|
+
if (!type.startsWith('schematic_')) continue
|
|
25
|
+
const selected = rows.filter((element) =>
|
|
26
|
+
SchematicSheetSelector.#belongs(
|
|
27
|
+
element,
|
|
28
|
+
type,
|
|
29
|
+
sheetId,
|
|
30
|
+
sheetCount,
|
|
31
|
+
scoped.masks
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
if (selected.length) {
|
|
35
|
+
elementsByType.set(type, selected)
|
|
36
|
+
for (const element of selected) {
|
|
37
|
+
selectedElements.push(element)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
SchematicSheetSelector.#appendReferencedSources(
|
|
42
|
+
index,
|
|
43
|
+
selectedElements,
|
|
44
|
+
elementsByType,
|
|
45
|
+
'source_component',
|
|
46
|
+
'source_component_id'
|
|
47
|
+
)
|
|
48
|
+
SchematicSheetSelector.#appendReferencedSources(
|
|
49
|
+
index,
|
|
50
|
+
selectedElements,
|
|
51
|
+
elementsByType,
|
|
52
|
+
'source_port',
|
|
53
|
+
'source_port_id'
|
|
54
|
+
)
|
|
55
|
+
for (const [type, rows] of elementsByType) {
|
|
56
|
+
if (!type.startsWith('source_')) continue
|
|
57
|
+
for (const row of rows) selectedElements.push(row)
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
elements: selectedElements,
|
|
61
|
+
elementsByType,
|
|
62
|
+
statistics: {
|
|
63
|
+
scopeUpdates: scoped.updates,
|
|
64
|
+
scopedElements: scoped.masks.size
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Retains only source rows directly referenced by selected schematic rows.
|
|
71
|
+
* @param {{ elementsByType: Map<string, object[]> }} index Full index.
|
|
72
|
+
* @param {object[]} selectedElements Selected schematic rows.
|
|
73
|
+
* @param {Map<string, object[]>} elementsByType Selected type map.
|
|
74
|
+
* @param {string} sourceType Source element type.
|
|
75
|
+
* @param {string} idField Qualified id field.
|
|
76
|
+
* @returns {void}
|
|
77
|
+
*/
|
|
78
|
+
static #appendReferencedSources(
|
|
79
|
+
index,
|
|
80
|
+
selectedElements,
|
|
81
|
+
elementsByType,
|
|
82
|
+
sourceType,
|
|
83
|
+
idField
|
|
84
|
+
) {
|
|
85
|
+
const ids = new Set(
|
|
86
|
+
selectedElements
|
|
87
|
+
.map((element) => String(element[idField] || ''))
|
|
88
|
+
.filter(Boolean)
|
|
89
|
+
)
|
|
90
|
+
const sources = (index.elementsByType.get(sourceType) || []).filter(
|
|
91
|
+
(element) => ids.has(String(element[idField] || ''))
|
|
92
|
+
)
|
|
93
|
+
if (sources.length) elementsByType.set(sourceType, sources)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolves constant-size target/other scope masks through ownership.
|
|
98
|
+
* @param {object[]} elements CircuitJSON elements.
|
|
99
|
+
* @param {string} targetSheetId Selected sheet id.
|
|
100
|
+
* @returns {{ masks: Map<object, number>, updates: number }} Scope state.
|
|
101
|
+
*/
|
|
102
|
+
static #scopes(elements, targetSheetId) {
|
|
103
|
+
const schematicElements = elements.filter((element) =>
|
|
104
|
+
String(element.type || '').startsWith('schematic_')
|
|
105
|
+
)
|
|
106
|
+
const masks = new Map(schematicElements.map((element) => [element, 0]))
|
|
107
|
+
const references = SchematicSheetSelector.#references(schematicElements)
|
|
108
|
+
const subcircuitMasks = new Map()
|
|
109
|
+
let updates = 0
|
|
110
|
+
for (const element of schematicElements) {
|
|
111
|
+
if (element.type !== 'schematic_sheet') continue
|
|
112
|
+
const sheetId = String(element.schematic_sheet_id || '')
|
|
113
|
+
const subcircuitId = String(element.subcircuit_id || '')
|
|
114
|
+
if (!sheetId || !subcircuitId) continue
|
|
115
|
+
const mask =
|
|
116
|
+
sheetId === targetSheetId ? SELECTED_SCOPE : OTHER_SCOPE
|
|
117
|
+
subcircuitMasks.set(
|
|
118
|
+
subcircuitId,
|
|
119
|
+
(subcircuitMasks.get(subcircuitId) || 0) | mask
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
const explicit = new Set()
|
|
123
|
+
for (const element of schematicElements) {
|
|
124
|
+
const sheetId = String(element.schematic_sheet_id || '')
|
|
125
|
+
if (!sheetId) continue
|
|
126
|
+
masks.set(
|
|
127
|
+
element,
|
|
128
|
+
sheetId === targetSheetId ? SELECTED_SCOPE : OTHER_SCOPE
|
|
129
|
+
)
|
|
130
|
+
explicit.add(element)
|
|
131
|
+
updates += 1
|
|
132
|
+
}
|
|
133
|
+
const dependents = SchematicSheetSelector.#dependents(
|
|
134
|
+
schematicElements,
|
|
135
|
+
references
|
|
136
|
+
)
|
|
137
|
+
updates += SchematicSheetSelector.#propagateScopes(
|
|
138
|
+
masks,
|
|
139
|
+
dependents,
|
|
140
|
+
[...explicit],
|
|
141
|
+
explicit
|
|
142
|
+
)
|
|
143
|
+
const authoritative = new Set(
|
|
144
|
+
schematicElements.filter((element) => masks.get(element))
|
|
145
|
+
)
|
|
146
|
+
const fallback = []
|
|
147
|
+
for (const element of schematicElements) {
|
|
148
|
+
if (masks.get(element)) continue
|
|
149
|
+
const mask =
|
|
150
|
+
subcircuitMasks.get(String(element.subcircuit_id || '')) || 0
|
|
151
|
+
if (!mask) continue
|
|
152
|
+
masks.set(element, mask)
|
|
153
|
+
fallback.push(element)
|
|
154
|
+
updates += 1
|
|
155
|
+
}
|
|
156
|
+
updates += SchematicSheetSelector.#propagateScopes(
|
|
157
|
+
masks,
|
|
158
|
+
dependents,
|
|
159
|
+
fallback,
|
|
160
|
+
authoritative
|
|
161
|
+
)
|
|
162
|
+
return { masks, updates }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Builds owner-to-dependent scope relationships.
|
|
167
|
+
* @param {object[]} elements Schematic elements.
|
|
168
|
+
* @param {Map<string, object>} references Qualified id lookup.
|
|
169
|
+
* @returns {Map<object, Set<object>>} Dependency graph.
|
|
170
|
+
*/
|
|
171
|
+
static #dependents(elements, references) {
|
|
172
|
+
const dependents = new Map(
|
|
173
|
+
elements.map((element) => [element, new Set()])
|
|
174
|
+
)
|
|
175
|
+
for (const element of elements) {
|
|
176
|
+
for (const owner of SchematicSheetSelector.#owners(
|
|
177
|
+
element,
|
|
178
|
+
references
|
|
179
|
+
)) {
|
|
180
|
+
dependents.get(owner)?.add(element)
|
|
181
|
+
}
|
|
182
|
+
if (element.type === 'schematic_component') {
|
|
183
|
+
const symbol = references.get(
|
|
184
|
+
'schematic_symbol_id:' +
|
|
185
|
+
String(element.schematic_symbol_id || '')
|
|
186
|
+
)
|
|
187
|
+
if (symbol) dependents.get(element)?.add(symbol)
|
|
188
|
+
}
|
|
189
|
+
if (element.type === 'schematic_group') {
|
|
190
|
+
for (const member of SchematicSheetSelector.#groupMembers(
|
|
191
|
+
element,
|
|
192
|
+
references
|
|
193
|
+
)) {
|
|
194
|
+
dependents.get(element)?.add(member)
|
|
195
|
+
dependents.get(member)?.add(element)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return dependents
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Propagates two-bit scope masks through ownership dependencies.
|
|
204
|
+
* @param {Map<object, number>} masks Mutable masks.
|
|
205
|
+
* @param {Map<object, Set<object>>} dependents Owner-to-dependent graph.
|
|
206
|
+
* @param {object[]} seeds Initially resolved elements.
|
|
207
|
+
* @param {Set<object>} protectedElements Authoritative elements.
|
|
208
|
+
* @returns {number} Number of bounded mask updates.
|
|
209
|
+
*/
|
|
210
|
+
static #propagateScopes(masks, dependents, seeds, protectedElements) {
|
|
211
|
+
let updates = 0
|
|
212
|
+
const queue = [...seeds]
|
|
213
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
214
|
+
const owner = queue[cursor]
|
|
215
|
+
for (const dependent of dependents.get(owner) || []) {
|
|
216
|
+
if (protectedElements.has(dependent)) continue
|
|
217
|
+
const current = masks.get(dependent) || 0
|
|
218
|
+
const merged = current | (masks.get(owner) || 0)
|
|
219
|
+
if (merged === current) continue
|
|
220
|
+
masks.set(dependent, merged)
|
|
221
|
+
queue.push(dependent)
|
|
222
|
+
updates += 1
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return updates
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Builds ownership lookup maps for schematic relation ids.
|
|
230
|
+
* @param {object[]} elements CircuitJSON elements.
|
|
231
|
+
* @returns {Map<string, object>} Qualified owner lookup.
|
|
232
|
+
*/
|
|
233
|
+
static #references(elements) {
|
|
234
|
+
const result = new Map()
|
|
235
|
+
for (const element of elements) {
|
|
236
|
+
const field = String(element.type || '') + '_id'
|
|
237
|
+
const value = element[field]
|
|
238
|
+
if (
|
|
239
|
+
field.startsWith('schematic_') &&
|
|
240
|
+
typeof value === 'string' &&
|
|
241
|
+
value
|
|
242
|
+
) {
|
|
243
|
+
result.set(field + ':' + value, element)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return result
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Resolves direct owner elements, including nested trace endpoints.
|
|
251
|
+
* @param {object} element CircuitJSON element.
|
|
252
|
+
* @param {Map<string, object>} references Qualified owner lookup.
|
|
253
|
+
* @returns {object[]} Referenced owners.
|
|
254
|
+
*/
|
|
255
|
+
static #owners(element, references) {
|
|
256
|
+
const owners = new Set()
|
|
257
|
+
const ownIdField = String(element.type || '') + '_id'
|
|
258
|
+
for (const [field, value] of SchematicSheetSelector.#nestedFields(
|
|
259
|
+
element
|
|
260
|
+
)) {
|
|
261
|
+
const match = field.match(/(schematic_[a-z0-9_]+_id)$/u)
|
|
262
|
+
const ownerField = match?.[1] || ''
|
|
263
|
+
if (
|
|
264
|
+
!ownerField ||
|
|
265
|
+
ownerField === 'schematic_sheet_id' ||
|
|
266
|
+
ownerField === ownIdField ||
|
|
267
|
+
typeof value !== 'string'
|
|
268
|
+
) {
|
|
269
|
+
continue
|
|
270
|
+
}
|
|
271
|
+
const owner = references.get(ownerField + ':' + value)
|
|
272
|
+
if (owner && owner !== element) owners.add(owner)
|
|
273
|
+
}
|
|
274
|
+
return [...owners]
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Resolves group member components for bidirectional scope inference.
|
|
279
|
+
* @param {object} group Schematic group.
|
|
280
|
+
* @param {Map<string, object>} references Qualified owner lookup.
|
|
281
|
+
* @returns {object[]} Member components.
|
|
282
|
+
*/
|
|
283
|
+
static #groupMembers(group, references) {
|
|
284
|
+
return (
|
|
285
|
+
Array.isArray(group.schematic_component_ids)
|
|
286
|
+
? group.schematic_component_ids
|
|
287
|
+
: []
|
|
288
|
+
)
|
|
289
|
+
.map((id) =>
|
|
290
|
+
references.get('schematic_component_id:' + String(id || ''))
|
|
291
|
+
)
|
|
292
|
+
.filter(Boolean)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Streams scalar fields in validated nested CircuitJSON data.
|
|
297
|
+
* @param {object} root Root element.
|
|
298
|
+
* @returns {Generator<[string, unknown], void, unknown>} Field/value pairs.
|
|
299
|
+
*/
|
|
300
|
+
static *#nestedFields(root) {
|
|
301
|
+
const stack = [root]
|
|
302
|
+
const seen = new WeakSet()
|
|
303
|
+
while (stack.length) {
|
|
304
|
+
const value = stack.pop()
|
|
305
|
+
if (!value || typeof value !== 'object' || seen.has(value)) continue
|
|
306
|
+
seen.add(value)
|
|
307
|
+
if (Array.isArray(value)) {
|
|
308
|
+
for (const entry of value) stack.push(entry)
|
|
309
|
+
continue
|
|
310
|
+
}
|
|
311
|
+
for (const [field, entry] of Object.entries(value)) {
|
|
312
|
+
yield [field, entry]
|
|
313
|
+
if (entry && typeof entry === 'object') stack.push(entry)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Returns whether one element belongs in the selected sheet view.
|
|
320
|
+
* @param {object} element CircuitJSON element.
|
|
321
|
+
* @param {string} type Element type.
|
|
322
|
+
* @param {string} sheetId Selected sheet id.
|
|
323
|
+
* @param {number} sheetCount Document sheet count.
|
|
324
|
+
* @param {Map<object, number>} masks Resolved two-bit scopes.
|
|
325
|
+
* @returns {boolean} Whether to retain the row.
|
|
326
|
+
*/
|
|
327
|
+
static #belongs(element, type, sheetId, sheetCount, masks) {
|
|
328
|
+
if (type === 'schematic_sheet') {
|
|
329
|
+
return element.schematic_sheet_id === sheetId
|
|
330
|
+
}
|
|
331
|
+
const mask = masks.get(element) || 0
|
|
332
|
+
if (mask) return Boolean(mask & SELECTED_SCOPE)
|
|
333
|
+
return sheetCount <= 1
|
|
334
|
+
}
|
|
335
|
+
}
|