altium-toolkit 1.1.22 → 1.1.23
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/README.md +34 -5
- package/docs/api.md +134 -23
- package/docs/model-format.md +174 -20
- package/docs/schemas/altium_toolkit/embedded_assets_a1.schema.json +56 -0
- package/docs/schemas/altium_toolkit/fixture_coverage_matrix_a1.schema.json +89 -0
- package/docs/schemas/altium_toolkit/geometry_bounds_a1.schema.json +86 -0
- package/docs/schemas/altium_toolkit/library_catalog_a1.schema.json +65 -0
- package/docs/schemas/altium_toolkit/library_diff_a1.schema.json +54 -0
- package/docs/schemas/altium_toolkit/library_inspection_a1.schema.json +94 -0
- package/docs/schemas/altium_toolkit/library_qa_a1.schema.json +4 -0
- package/docs/schemas/altium_toolkit/native_stream_inventory_a1.schema.json +66 -0
- package/docs/schemas/altium_toolkit/normalized_model_a1.schema.json +511 -1
- package/docs/schemas/altium_toolkit/parameter_record_inventory_a1.schema.json +84 -0
- package/docs/schemas/altium_toolkit/parser_diagnostics_a1.schema.json +63 -0
- package/docs/schemas/altium_toolkit/parser_value_verification_a1.schema.json +74 -0
- package/docs/schemas/altium_toolkit/pcb_class_report_a1.schema.json +79 -0
- package/docs/schemas/altium_toolkit/pcb_inspection_a1.schema.json +65 -0
- package/docs/schemas/altium_toolkit/pcb_net_membership_a1.schema.json +98 -0
- package/docs/schemas/altium_toolkit/project_bundle_a1.schema.json +3 -0
- package/docs/schemas/altium_toolkit/project_hierarchy_a1.schema.json +79 -0
- package/docs/schemas/altium_toolkit/unsupported_features_a1.schema.json +212 -0
- package/docs/testing.md +2 -0
- package/examples/README.md +21 -0
- package/examples/cli-utils.mjs +148 -0
- package/examples/corpus-smoke.mjs +523 -0
- package/examples/extract-bom.mjs +47 -0
- package/examples/generate-pnp.mjs +59 -0
- package/examples/inspect-board.mjs +70 -0
- package/examples/inspect-schematic.mjs +406 -0
- package/examples/library-catalog.mjs +115 -0
- package/examples/net-report.mjs +61 -0
- package/examples/validate-library.mjs +59 -0
- package/package.json +1 -1
- package/src/core/BinaryReader.mjs +213 -2
- package/src/core/altium/AltiumParser.mjs +352 -14
- package/src/core/altium/AltiumUnits.mjs +205 -0
- package/src/core/altium/AsciiRecordParser.mjs +9 -0
- package/src/core/altium/EmbeddedAssetReportBuilder.mjs +383 -0
- package/src/core/altium/FixtureCoverageMatrixBuilder.mjs +304 -0
- package/src/core/altium/GeometryBoundsReportBuilder.mjs +935 -0
- package/src/core/altium/LibraryCatalogArtifactBuilder.mjs +296 -0
- package/src/core/altium/LibraryDiffReportBuilder.mjs +260 -0
- package/src/core/altium/LibraryInspectionReportBuilder.mjs +156 -0
- package/src/core/altium/LibraryQaReportBuilder.mjs +374 -1
- package/src/core/altium/NativeStreamInventoryBuilder.mjs +177 -0
- package/src/core/altium/NormalizedModelSchema.mjs +3 -31
- package/src/core/altium/ParameterCollection.mjs +431 -0
- package/src/core/altium/ParameterRecordInventoryBuilder.mjs +274 -0
- package/src/core/altium/ParserCompatibilityFuzzer.mjs +106 -2
- package/src/core/altium/ParserDiagnosticNormalizer.mjs +213 -0
- package/src/core/altium/ParserErrors.mjs +90 -0
- package/src/core/altium/ParserFieldCoverageReportBuilder.mjs +656 -0
- package/src/core/altium/ParserUtils.mjs +24 -0
- package/src/core/altium/ParserValueVerificationReportBuilder.mjs +323 -0
- package/src/core/altium/PcbClassReportBuilder.mjs +366 -0
- package/src/core/altium/PcbInspectionReportBuilder.mjs +313 -0
- package/src/core/altium/PcbLayerGroups.mjs +308 -0
- package/src/core/altium/PcbLayerStackCustomDataParser.mjs +183 -0
- package/src/core/altium/PcbLayerStackInterchangeParser.mjs +473 -4
- package/src/core/altium/PcbLayerStackReadModelBuilder.mjs +83 -15
- package/src/core/altium/PcbLayerStackSourceMetadataParser.mjs +74 -4
- package/src/core/altium/PcbLibModelParser.mjs +20 -4
- package/src/core/altium/PcbLibStreamExtractor.mjs +49 -6
- package/src/core/altium/PcbModelParser.mjs +223 -4
- package/src/core/altium/PcbNetMembershipReportBuilder.mjs +270 -0
- package/src/core/altium/PcbStreamExtractor.mjs +130 -6
- package/src/core/altium/PcbTrackPrimitiveParser.mjs +66 -2
- package/src/core/altium/ProjectDesignBundleBuilder.mjs +15 -0
- package/src/core/altium/ProjectHierarchyReportBuilder.mjs +660 -0
- package/src/core/altium/ProjectNetlistExporter.mjs +2 -0
- package/src/core/altium/RawDataPreservationReportBuilder.mjs +348 -0
- package/src/core/altium/SchLibModelParser.mjs +840 -0
- package/src/core/altium/SchLibStreamExtractor.mjs +586 -0
- package/src/core/altium/SchematicBusEntryParser.mjs +3 -2
- package/src/core/altium/SchematicCodeSymbolParser.mjs +663 -0
- package/src/core/altium/SchematicConnectivityQaBuilder.mjs +177 -2
- package/src/core/altium/SchematicDisplayModeCatalogParser.mjs +10 -1
- package/src/core/altium/SchematicFieldCoverageReportBuilder.mjs +549 -0
- package/src/core/altium/SchematicHarnessParser.mjs +9 -3
- package/src/core/altium/SchematicHyperlinkParser.mjs +122 -0
- package/src/core/altium/SchematicNetlistBuilder.mjs +271 -8
- package/src/core/altium/SchematicOwnershipGraphParser.mjs +102 -3
- package/src/core/altium/SchematicPinParser.mjs +12 -45
- package/src/core/altium/SchematicPrimitiveParser.mjs +9 -14
- package/src/core/altium/SchematicQaReportBuilder.mjs +2 -0
- package/src/core/altium/SchematicRecordStreamParser.mjs +183 -0
- package/src/core/altium/SchematicRecordTypeRegistry.mjs +6 -1
- package/src/core/altium/SchematicSheetParser.mjs +8 -2
- package/src/core/altium/SchematicStreamExtractor.mjs +64 -25
- package/src/core/altium/SchematicTextOrientationResolver.mjs +76 -0
- package/src/core/altium/SchematicTextParser.mjs +28 -12
- package/src/core/altium/SchematicTextRunParser.mjs +81 -0
- package/src/core/altium/SchematicThumbnailParser.mjs +425 -0
- package/src/core/altium/UnsupportedFeatureReportBuilder.mjs +380 -0
- package/src/parser.mjs +35 -1
- package/src/renderers.mjs +1 -0
- package/src/ui/SchematicShapeRenderer.mjs +49 -6
- package/src/ui/SchematicSvgRenderer.mjs +37 -8
- package/src/ui/SchematicTypography.mjs +4 -3
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 André Fiedler
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Builds fixture coverage matrices from synthetic fixture manifests.
|
|
7
|
+
*/
|
|
8
|
+
export class FixtureCoverageMatrixBuilder {
|
|
9
|
+
static SCHEMA = 'altium-toolkit.fixture-coverage-matrix.a1'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Builds a fixture coverage matrix report.
|
|
13
|
+
* @param {{ manifest?: object, requiredCoverage?: string[], requiredContracts?: Record<string, string[]> } | object} [input]
|
|
14
|
+
* @returns {object}
|
|
15
|
+
*/
|
|
16
|
+
static build(input = {}) {
|
|
17
|
+
const manifest = input.manifest || input
|
|
18
|
+
const fixtures = Array.isArray(manifest.fixtures)
|
|
19
|
+
? manifest.fixtures
|
|
20
|
+
: []
|
|
21
|
+
const requiredCoverage = FixtureCoverageMatrixBuilder.#stringList(
|
|
22
|
+
input.requiredCoverage
|
|
23
|
+
)
|
|
24
|
+
const requiredContracts =
|
|
25
|
+
FixtureCoverageMatrixBuilder.#requiredContracts(
|
|
26
|
+
input.requiredContracts
|
|
27
|
+
)
|
|
28
|
+
const coverage = FixtureCoverageMatrixBuilder.#coverageRows(
|
|
29
|
+
fixtures,
|
|
30
|
+
requiredCoverage
|
|
31
|
+
)
|
|
32
|
+
const contracts = FixtureCoverageMatrixBuilder.#contractRows(
|
|
33
|
+
fixtures,
|
|
34
|
+
requiredContracts
|
|
35
|
+
)
|
|
36
|
+
const missingCoverage = coverage
|
|
37
|
+
.filter((entry) => entry.required && !entry.covered)
|
|
38
|
+
.map((entry) => entry.tag)
|
|
39
|
+
const missingContracts = contracts
|
|
40
|
+
.filter((entry) => entry.required && !entry.covered)
|
|
41
|
+
.map((entry) => ({
|
|
42
|
+
group: entry.group,
|
|
43
|
+
contract: entry.contract
|
|
44
|
+
}))
|
|
45
|
+
const policy = FixtureCoverageMatrixBuilder.#policy(manifest, fixtures)
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
schema: FixtureCoverageMatrixBuilder.SCHEMA,
|
|
49
|
+
summary: {
|
|
50
|
+
fixtureCount: fixtures.length,
|
|
51
|
+
coverageTagCount: coverage.length,
|
|
52
|
+
contractCount: contracts.length,
|
|
53
|
+
requiredCoverageCount: requiredCoverage.length,
|
|
54
|
+
requiredContractCount: requiredContracts.length,
|
|
55
|
+
missingCoverageCount: missingCoverage.length,
|
|
56
|
+
missingContractCount: missingContracts.length,
|
|
57
|
+
nativeAssetCount: policy.nativeAssetCount,
|
|
58
|
+
status:
|
|
59
|
+
missingCoverage.length || missingContracts.length
|
|
60
|
+
? 'gap'
|
|
61
|
+
: 'pass'
|
|
62
|
+
},
|
|
63
|
+
policy,
|
|
64
|
+
coverage,
|
|
65
|
+
contracts,
|
|
66
|
+
missingCoverage,
|
|
67
|
+
missingContracts
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Builds coverage rows.
|
|
73
|
+
* @param {object[]} fixtures Fixture rows.
|
|
74
|
+
* @param {string[]} requiredCoverage Required coverage tags.
|
|
75
|
+
* @returns {object[]}
|
|
76
|
+
*/
|
|
77
|
+
static #coverageRows(fixtures, requiredCoverage) {
|
|
78
|
+
const required = new Set(requiredCoverage)
|
|
79
|
+
const fixtureKeysByTag = new Map()
|
|
80
|
+
|
|
81
|
+
for (const fixture of fixtures) {
|
|
82
|
+
for (const tag of FixtureCoverageMatrixBuilder.#stringList(
|
|
83
|
+
fixture.coverage
|
|
84
|
+
)) {
|
|
85
|
+
FixtureCoverageMatrixBuilder.#appendKey(
|
|
86
|
+
fixtureKeysByTag,
|
|
87
|
+
tag,
|
|
88
|
+
FixtureCoverageMatrixBuilder.#fixtureKey(fixture)
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return FixtureCoverageMatrixBuilder.#sortedUnion(
|
|
94
|
+
[...fixtureKeysByTag.keys()],
|
|
95
|
+
requiredCoverage
|
|
96
|
+
).map((tag) =>
|
|
97
|
+
FixtureCoverageMatrixBuilder.#coverageRow(
|
|
98
|
+
tag,
|
|
99
|
+
fixtureKeysByTag.get(tag) || new Set(),
|
|
100
|
+
required.has(tag)
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Builds one coverage row.
|
|
107
|
+
* @param {string} tag Coverage tag.
|
|
108
|
+
* @param {Set<string>} fixtureKeys Fixture keys.
|
|
109
|
+
* @param {boolean} required Required flag.
|
|
110
|
+
* @returns {object}
|
|
111
|
+
*/
|
|
112
|
+
static #coverageRow(tag, fixtureKeys, required) {
|
|
113
|
+
const keys = [...fixtureKeys].sort()
|
|
114
|
+
return {
|
|
115
|
+
tag,
|
|
116
|
+
fixtureKeys: keys,
|
|
117
|
+
count: keys.length,
|
|
118
|
+
required,
|
|
119
|
+
covered: keys.length > 0
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Builds contract rows.
|
|
125
|
+
* @param {object[]} fixtures Fixture rows.
|
|
126
|
+
* @param {{ group: string, contract: string }[]} requiredContracts Required contracts.
|
|
127
|
+
* @returns {object[]}
|
|
128
|
+
*/
|
|
129
|
+
static #contractRows(fixtures, requiredContracts) {
|
|
130
|
+
const required = new Set(
|
|
131
|
+
requiredContracts.map((entry) =>
|
|
132
|
+
FixtureCoverageMatrixBuilder.#contractKey(
|
|
133
|
+
entry.group,
|
|
134
|
+
entry.contract
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
const fixtureKeysByContract = new Map()
|
|
139
|
+
|
|
140
|
+
for (const fixture of fixtures) {
|
|
141
|
+
const contracts = fixture.contracts || {}
|
|
142
|
+
for (const [group, groupContracts] of Object.entries(contracts)) {
|
|
143
|
+
for (const contract of FixtureCoverageMatrixBuilder.#stringList(
|
|
144
|
+
groupContracts
|
|
145
|
+
)) {
|
|
146
|
+
FixtureCoverageMatrixBuilder.#appendKey(
|
|
147
|
+
fixtureKeysByContract,
|
|
148
|
+
FixtureCoverageMatrixBuilder.#contractKey(
|
|
149
|
+
group,
|
|
150
|
+
contract
|
|
151
|
+
),
|
|
152
|
+
FixtureCoverageMatrixBuilder.#fixtureKey(fixture)
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const allKeys = FixtureCoverageMatrixBuilder.#sortedUnion(
|
|
159
|
+
[...fixtureKeysByContract.keys()],
|
|
160
|
+
requiredContracts.map((entry) =>
|
|
161
|
+
FixtureCoverageMatrixBuilder.#contractKey(
|
|
162
|
+
entry.group,
|
|
163
|
+
entry.contract
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return allKeys.map((key) => {
|
|
169
|
+
const [group, contract] =
|
|
170
|
+
FixtureCoverageMatrixBuilder.#splitContractKey(key)
|
|
171
|
+
const fixtureKeys = fixtureKeysByContract.get(key) || new Set()
|
|
172
|
+
return FixtureCoverageMatrixBuilder.#contractRow(
|
|
173
|
+
group,
|
|
174
|
+
contract,
|
|
175
|
+
fixtureKeys,
|
|
176
|
+
required.has(key)
|
|
177
|
+
)
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Builds one contract row.
|
|
183
|
+
* @param {string} group Contract group.
|
|
184
|
+
* @param {string} contract Contract name.
|
|
185
|
+
* @param {Set<string>} fixtureKeys Fixture keys.
|
|
186
|
+
* @param {boolean} required Required flag.
|
|
187
|
+
* @returns {object}
|
|
188
|
+
*/
|
|
189
|
+
static #contractRow(group, contract, fixtureKeys, required) {
|
|
190
|
+
const keys = [...fixtureKeys].sort()
|
|
191
|
+
return {
|
|
192
|
+
group,
|
|
193
|
+
contract,
|
|
194
|
+
fixtureKeys: keys,
|
|
195
|
+
count: keys.length,
|
|
196
|
+
required,
|
|
197
|
+
covered: keys.length > 0
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Normalizes required contract input.
|
|
203
|
+
* @param {Record<string, string[]> | undefined} requiredContracts Required contract groups.
|
|
204
|
+
* @returns {{ group: string, contract: string }[]}
|
|
205
|
+
*/
|
|
206
|
+
static #requiredContracts(requiredContracts) {
|
|
207
|
+
return Object.entries(requiredContracts || {}).flatMap(
|
|
208
|
+
([group, contracts]) =>
|
|
209
|
+
FixtureCoverageMatrixBuilder.#stringList(contracts).map(
|
|
210
|
+
(contract) => ({ group, contract })
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Builds fixture policy metadata.
|
|
217
|
+
* @param {object} manifest Fixture manifest.
|
|
218
|
+
* @param {object[]} fixtures Fixture rows.
|
|
219
|
+
* @returns {{ assetPolicy: string, nativeAssetCount: number, compliant: boolean }}
|
|
220
|
+
*/
|
|
221
|
+
static #policy(manifest, fixtures) {
|
|
222
|
+
const assetPolicy = String(manifest.assetPolicy || '')
|
|
223
|
+
const nativeAssetCount = fixtures.filter(
|
|
224
|
+
(fixture) => fixture.nativeAsset
|
|
225
|
+
).length
|
|
226
|
+
const compliant =
|
|
227
|
+
nativeAssetCount === 0 &&
|
|
228
|
+
fixtures.every(
|
|
229
|
+
(fixture) =>
|
|
230
|
+
!fixture.nativeAsset &&
|
|
231
|
+
(!assetPolicy || fixture.assetPolicy === assetPolicy)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
assetPolicy,
|
|
236
|
+
nativeAssetCount,
|
|
237
|
+
compliant
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Appends one fixture key to a map of sets.
|
|
243
|
+
* @param {Map<string, Set<string>>} map Destination map.
|
|
244
|
+
* @param {string} tag Map key.
|
|
245
|
+
* @param {string} fixtureKey Fixture key.
|
|
246
|
+
* @returns {void}
|
|
247
|
+
*/
|
|
248
|
+
static #appendKey(map, tag, fixtureKey) {
|
|
249
|
+
if (!tag) return
|
|
250
|
+
map.set(tag, new Set([...(map.get(tag) || []), fixtureKey]))
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Returns a fixture key.
|
|
255
|
+
* @param {object} fixture Fixture row.
|
|
256
|
+
* @returns {string}
|
|
257
|
+
*/
|
|
258
|
+
static #fixtureKey(fixture) {
|
|
259
|
+
return String(fixture.key || fixture.id || fixture.name || '')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Builds a stable contract key.
|
|
264
|
+
* @param {string} group Contract group.
|
|
265
|
+
* @param {string} contract Contract name.
|
|
266
|
+
* @returns {string}
|
|
267
|
+
*/
|
|
268
|
+
static #contractKey(group, contract) {
|
|
269
|
+
return String(group || '') + '\u0000' + String(contract || '')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Splits one stable contract key.
|
|
274
|
+
* @param {string} key Contract key.
|
|
275
|
+
* @returns {[string, string]}
|
|
276
|
+
*/
|
|
277
|
+
static #splitContractKey(key) {
|
|
278
|
+
const [group, contract] = String(key).split('\u0000')
|
|
279
|
+
return [group || '', contract || '']
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Builds a sorted unique array from two lists.
|
|
284
|
+
* @param {string[]} first First values.
|
|
285
|
+
* @param {string[]} second Second values.
|
|
286
|
+
* @returns {string[]}
|
|
287
|
+
*/
|
|
288
|
+
static #sortedUnion(first, second) {
|
|
289
|
+
return [...new Set([...first, ...second])]
|
|
290
|
+
.filter(Boolean)
|
|
291
|
+
.sort((left, right) => left.localeCompare(right))
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Normalizes string-list input.
|
|
296
|
+
* @param {unknown} value Source value.
|
|
297
|
+
* @returns {string[]}
|
|
298
|
+
*/
|
|
299
|
+
static #stringList(value) {
|
|
300
|
+
return Array.isArray(value)
|
|
301
|
+
? value.map((entry) => String(entry)).filter(Boolean)
|
|
302
|
+
: []
|
|
303
|
+
}
|
|
304
|
+
}
|