altium-toolkit 1.1.3 → 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 +171 -23
- package/docs/model-format.md +192 -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 +513 -3
- 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 +7 -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/spec/library-scope.md +5 -0
- package/src/core/BinaryReader.mjs +213 -2
- package/src/core/altium/AltiumLibraryBatchExporter.mjs +206 -0
- package/src/core/altium/AltiumLibraryRecordBuilder.mjs +293 -0
- package/src/core/altium/AltiumParser.mjs +357 -16
- package/src/core/altium/AltiumPcbLibExporter.mjs +101 -0
- package/src/core/altium/AltiumSchLibExporter.mjs +57 -0
- package/src/core/altium/AltiumUnits.mjs +205 -0
- package/src/core/altium/AsciiRecordParser.mjs +52 -11
- 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/PcbComponentKindPolicy.mjs +9 -9
- package/src/core/altium/PcbEmbeddedModelExtractor.mjs +22 -3
- 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/PcbOutlineRecovery.mjs +94 -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/SchematicDirectiveParser.mjs +5 -17
- 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/SchematicNoErcSymbolResolver.mjs +36 -0
- package/src/core/altium/SchematicOwnershipGraphParser.mjs +102 -3
- package/src/core/altium/SchematicPinParser.mjs +99 -65
- package/src/core/altium/SchematicPrimitiveParser.mjs +125 -22
- 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 +107 -21
- 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/SourceBundleExporter.mjs +156 -0
- package/src/core/altium/SourceComponentBundleNormalizer.mjs +295 -0
- package/src/core/altium/SourceComponentClient.mjs +239 -0
- package/src/core/altium/UnsupportedFeatureReportBuilder.mjs +380 -0
- package/src/core/ole/OleCompoundDocumentWriter.mjs +449 -0
- package/src/parser.mjs +43 -1
- package/src/renderers.mjs +1 -0
- package/src/styles/altium-renderers.css +6 -6
- package/src/ui/PcbArcUtils.mjs +19 -2
- package/src/ui/PcbScene3dBuilder.mjs +202 -20
- package/src/ui/PcbScene3dModelRegistry.mjs +28 -18
- package/src/ui/PcbScene3dPlacementSideResolver.mjs +48 -6
- package/src/ui/SchematicColorResolver.mjs +185 -0
- package/src/ui/SchematicDirectiveRenderer.mjs +133 -22
- package/src/ui/SchematicLineColorResolver.mjs +88 -0
- package/src/ui/SchematicNoteRenderer.mjs +5 -1
- package/src/ui/SchematicOwnerPinLabelLayout.mjs +269 -8
- package/src/ui/SchematicOwnerPinMarkerLineThemer.mjs +155 -0
- package/src/ui/SchematicPinSvgRenderer.mjs +229 -62
- package/src/ui/SchematicShapeRenderer.mjs +86 -17
- package/src/ui/SchematicSvgRenderer.mjs +980 -58
- package/src/ui/SchematicTypography.mjs +4 -3
|
@@ -2,6 +2,145 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Reads sequential little-endian primitive values from a BinaryReader.
|
|
7
|
+
*/
|
|
8
|
+
export class BinaryReaderCursor {
|
|
9
|
+
#offset
|
|
10
|
+
|
|
11
|
+
#reader
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {BinaryReader} reader
|
|
15
|
+
* @param {number} [offset]
|
|
16
|
+
*/
|
|
17
|
+
constructor(reader, offset = 0) {
|
|
18
|
+
const normalizedOffset = Number(offset)
|
|
19
|
+
if (
|
|
20
|
+
!Number.isInteger(normalizedOffset) ||
|
|
21
|
+
normalizedOffset < 0 ||
|
|
22
|
+
normalizedOffset > reader.byteLength
|
|
23
|
+
) {
|
|
24
|
+
throw new RangeError(
|
|
25
|
+
'BinaryReader cursor offset is out of bounds: ' +
|
|
26
|
+
normalizedOffset
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.#reader = reader
|
|
31
|
+
this.#offset = normalizedOffset
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns the current cursor offset.
|
|
36
|
+
* @returns {number}
|
|
37
|
+
*/
|
|
38
|
+
get offset() {
|
|
39
|
+
return this.#offset
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Reads one unsigned byte and advances the cursor.
|
|
44
|
+
* @returns {number}
|
|
45
|
+
*/
|
|
46
|
+
readUint8() {
|
|
47
|
+
return this.#readNumber(1, (offset) => this.#reader.readUint8(offset))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Reads one signed 16-bit integer and advances the cursor.
|
|
52
|
+
* @returns {number}
|
|
53
|
+
*/
|
|
54
|
+
readInt16() {
|
|
55
|
+
return this.#readNumber(2, (offset) => this.#reader.readInt16(offset))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Reads one unsigned 16-bit integer and advances the cursor.
|
|
60
|
+
* @returns {number}
|
|
61
|
+
*/
|
|
62
|
+
readUint16() {
|
|
63
|
+
return this.#readNumber(2, (offset) => this.#reader.readUint16(offset))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Reads one unsigned 32-bit integer and advances the cursor.
|
|
68
|
+
* @returns {number}
|
|
69
|
+
*/
|
|
70
|
+
readUint32() {
|
|
71
|
+
return this.#readNumber(4, (offset) => this.#reader.readUint32(offset))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Reads one signed 32-bit integer and advances the cursor.
|
|
76
|
+
* @returns {number}
|
|
77
|
+
*/
|
|
78
|
+
readInt32() {
|
|
79
|
+
return this.#readNumber(4, (offset) => this.#reader.readInt32(offset))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Reads one unsigned 64-bit integer and advances the cursor.
|
|
84
|
+
* @returns {number}
|
|
85
|
+
*/
|
|
86
|
+
readUint64() {
|
|
87
|
+
return this.#readNumber(8, (offset) => this.#reader.readUint64(offset))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Reads one 64-bit floating-point value and advances the cursor.
|
|
92
|
+
* @returns {number}
|
|
93
|
+
*/
|
|
94
|
+
readFloat64() {
|
|
95
|
+
return this.#readNumber(8, (offset) => this.#reader.readFloat64(offset))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Reads one byte slice and advances the cursor.
|
|
100
|
+
* @param {number} length
|
|
101
|
+
* @returns {Uint8Array}
|
|
102
|
+
*/
|
|
103
|
+
readBytes(length) {
|
|
104
|
+
const bytes = this.#reader.readBytes(this.#offset, length)
|
|
105
|
+
this.#offset += Number(length)
|
|
106
|
+
return bytes
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Reads one length-prefixed string and advances the cursor.
|
|
111
|
+
* @param {string} [encoding]
|
|
112
|
+
* @returns {string}
|
|
113
|
+
*/
|
|
114
|
+
readPascalString(encoding = 'utf-8') {
|
|
115
|
+
const length = this.#reader.readUint8(this.#offset)
|
|
116
|
+
const value = this.#reader.readPascalString(this.#offset, encoding)
|
|
117
|
+
this.#offset += 1 + length
|
|
118
|
+
return value
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Reads one length-prefixed block and advances the cursor.
|
|
123
|
+
* @returns {{ byteLength: number, flags: number, dataOffset: number, nextOffset: number, bytes: Uint8Array }}
|
|
124
|
+
*/
|
|
125
|
+
readSizedBlock() {
|
|
126
|
+
const block = this.#reader.readSizedBlock(this.#offset)
|
|
127
|
+
this.#offset = block.nextOffset
|
|
128
|
+
return block
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Reads one fixed-width numeric value and advances the cursor.
|
|
133
|
+
* @param {number} size
|
|
134
|
+
* @param {(offset: number) => number} reader
|
|
135
|
+
* @returns {number}
|
|
136
|
+
*/
|
|
137
|
+
#readNumber(size, reader) {
|
|
138
|
+
const value = reader(this.#offset)
|
|
139
|
+
this.#offset += size
|
|
140
|
+
return value
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
5
144
|
/**
|
|
6
145
|
* Reads little-endian primitive values from an ArrayBuffer with bounds checks.
|
|
7
146
|
*/
|
|
@@ -39,6 +178,16 @@ export class BinaryReader {
|
|
|
39
178
|
return this.#dataView.getUint8(offset)
|
|
40
179
|
}
|
|
41
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Reads one signed 16-bit integer.
|
|
183
|
+
* @param {number} offset
|
|
184
|
+
* @returns {number}
|
|
185
|
+
*/
|
|
186
|
+
readInt16(offset) {
|
|
187
|
+
this.#assertReadable(offset, 2)
|
|
188
|
+
return this.#dataView.getInt16(offset, true)
|
|
189
|
+
}
|
|
190
|
+
|
|
42
191
|
/**
|
|
43
192
|
* Reads one unsigned 16-bit integer.
|
|
44
193
|
* @param {number} offset
|
|
@@ -69,6 +218,16 @@ export class BinaryReader {
|
|
|
69
218
|
return this.#dataView.getInt32(offset, true)
|
|
70
219
|
}
|
|
71
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Reads one 64-bit floating-point value.
|
|
223
|
+
* @param {number} offset
|
|
224
|
+
* @returns {number}
|
|
225
|
+
*/
|
|
226
|
+
readFloat64(offset) {
|
|
227
|
+
this.#assertReadable(offset, 8)
|
|
228
|
+
return this.#dataView.getFloat64(offset, true)
|
|
229
|
+
}
|
|
230
|
+
|
|
72
231
|
/**
|
|
73
232
|
* Reads one unsigned 64-bit integer as a JavaScript number.
|
|
74
233
|
* @param {number} offset
|
|
@@ -97,8 +256,58 @@ export class BinaryReader {
|
|
|
97
256
|
* @returns {Uint8Array}
|
|
98
257
|
*/
|
|
99
258
|
readBytes(offset, length) {
|
|
100
|
-
|
|
101
|
-
|
|
259
|
+
const normalizedOffset = Number(offset)
|
|
260
|
+
const normalizedLength = Number(length)
|
|
261
|
+
this.#assertReadable(normalizedOffset, normalizedLength)
|
|
262
|
+
return new Uint8Array(
|
|
263
|
+
this.#arrayBuffer.slice(
|
|
264
|
+
normalizedOffset,
|
|
265
|
+
normalizedOffset + normalizedLength
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Reads one one-byte length-prefixed string.
|
|
272
|
+
* @param {number} offset
|
|
273
|
+
* @param {string} [encoding]
|
|
274
|
+
* @returns {string}
|
|
275
|
+
*/
|
|
276
|
+
readPascalString(offset, encoding = 'utf-8') {
|
|
277
|
+
const length = this.readUint8(offset)
|
|
278
|
+
const bytes = this.readBytes(offset + 1, length)
|
|
279
|
+
return new TextDecoder(encoding).decode(bytes)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Reads one 32-bit length-prefixed byte block.
|
|
284
|
+
* @param {number} offset
|
|
285
|
+
* @returns {{ byteLength: number, flags: number, dataOffset: number, nextOffset: number, bytes: Uint8Array }}
|
|
286
|
+
*/
|
|
287
|
+
readSizedBlock(offset) {
|
|
288
|
+
const normalizedOffset = Number(offset)
|
|
289
|
+
const rawLength = this.readUint32(normalizedOffset)
|
|
290
|
+
const byteLength = rawLength & 0x00ffffff
|
|
291
|
+
const flags = rawLength >>> 24
|
|
292
|
+
const dataOffset = normalizedOffset + 4
|
|
293
|
+
const bytes = this.readBytes(dataOffset, byteLength)
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
byteLength,
|
|
297
|
+
flags,
|
|
298
|
+
dataOffset,
|
|
299
|
+
nextOffset: dataOffset + byteLength,
|
|
300
|
+
bytes
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Creates a sequential cursor over this reader.
|
|
306
|
+
* @param {number} [offset]
|
|
307
|
+
* @returns {BinaryReaderCursor}
|
|
308
|
+
*/
|
|
309
|
+
cursor(offset = 0) {
|
|
310
|
+
return new BinaryReaderCursor(this, offset)
|
|
102
311
|
}
|
|
103
312
|
|
|
104
313
|
/**
|
|
@@ -112,7 +321,9 @@ export class BinaryReader {
|
|
|
112
321
|
|
|
113
322
|
if (
|
|
114
323
|
!Number.isInteger(normalizedOffset) ||
|
|
324
|
+
!Number.isInteger(normalizedSize) ||
|
|
115
325
|
normalizedOffset < 0 ||
|
|
326
|
+
normalizedSize < 0 ||
|
|
116
327
|
normalizedOffset + normalizedSize > this.#byteLength
|
|
117
328
|
) {
|
|
118
329
|
throw new RangeError(
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 André Fiedler
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
import { AltiumPcbLibExporter } from './AltiumPcbLibExporter.mjs'
|
|
6
|
+
import { AltiumSchLibExporter } from './AltiumSchLibExporter.mjs'
|
|
7
|
+
import { SourceBundleExporter } from './SourceBundleExporter.mjs'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Orchestrates source lookup and local library export.
|
|
11
|
+
*/
|
|
12
|
+
export class AltiumLibraryBatchExporter {
|
|
13
|
+
#client
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {{ client?: { fetchComponentBundle?: Function, searchComponents?: Function } }} [options] Batch options.
|
|
17
|
+
*/
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.#client = options.client || null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Searches components and exports the matching ids.
|
|
24
|
+
* @param {string} query Search query.
|
|
25
|
+
* @param {object} [options] Export options.
|
|
26
|
+
* @returns {Promise<object>}
|
|
27
|
+
*/
|
|
28
|
+
async searchAndExport(query, options = {}) {
|
|
29
|
+
const rows = await this.#requireClient().searchComponents(
|
|
30
|
+
query,
|
|
31
|
+
options
|
|
32
|
+
)
|
|
33
|
+
return this.exportIds(
|
|
34
|
+
rows.map((row) => row.id).filter(Boolean),
|
|
35
|
+
options
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Exports one list of provider ids.
|
|
41
|
+
* @param {string[]} ids Component ids.
|
|
42
|
+
* @param {{ appendManifest?: { completedIds?: string[] }, includeSourceBundle?: boolean, includeSchLib?: boolean, includePcbLib?: boolean, merged?: boolean, continueOnError?: boolean, onProgress?: Function }} [options] Export options.
|
|
43
|
+
* @returns {Promise<{ entries: object[], bundles: object[], diagnostics: object[], checkpoint: { completedIds: string[] } }>}
|
|
44
|
+
*/
|
|
45
|
+
async exportIds(ids, options = {}) {
|
|
46
|
+
const completedIds = [
|
|
47
|
+
...new Set(options.appendManifest?.completedIds || [])
|
|
48
|
+
]
|
|
49
|
+
const completedSet = new Set(completedIds)
|
|
50
|
+
const entries = []
|
|
51
|
+
const bundles = []
|
|
52
|
+
const diagnostics = []
|
|
53
|
+
|
|
54
|
+
for (const id of ids
|
|
55
|
+
.map((value) => String(value || ''))
|
|
56
|
+
.filter(Boolean)) {
|
|
57
|
+
if (completedSet.has(id)) {
|
|
58
|
+
AltiumLibraryBatchExporter.#emitProgress(options, {
|
|
59
|
+
id,
|
|
60
|
+
status: 'skipped'
|
|
61
|
+
})
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const bundle =
|
|
67
|
+
await this.#requireClient().fetchComponentBundle(id)
|
|
68
|
+
bundles.push(bundle)
|
|
69
|
+
entries.push(
|
|
70
|
+
...AltiumLibraryBatchExporter.#buildPerComponentEntries(
|
|
71
|
+
id,
|
|
72
|
+
bundle,
|
|
73
|
+
options
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
completedSet.add(id)
|
|
77
|
+
completedIds.push(id)
|
|
78
|
+
AltiumLibraryBatchExporter.#emitProgress(options, {
|
|
79
|
+
id,
|
|
80
|
+
status: 'exported'
|
|
81
|
+
})
|
|
82
|
+
} catch (error) {
|
|
83
|
+
diagnostics.push({
|
|
84
|
+
id,
|
|
85
|
+
severity: 'error',
|
|
86
|
+
message: String(error?.message || error)
|
|
87
|
+
})
|
|
88
|
+
AltiumLibraryBatchExporter.#emitProgress(options, {
|
|
89
|
+
id,
|
|
90
|
+
status: 'failed'
|
|
91
|
+
})
|
|
92
|
+
if (!options.continueOnError) {
|
|
93
|
+
throw error
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (options.merged && bundles.length) {
|
|
99
|
+
entries.push(
|
|
100
|
+
...AltiumLibraryBatchExporter.#buildMergedEntries(bundles)
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
entries,
|
|
106
|
+
bundles,
|
|
107
|
+
diagnostics,
|
|
108
|
+
checkpoint: { completedIds }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Builds per-component export entries.
|
|
114
|
+
* @param {string} id Component id.
|
|
115
|
+
* @param {object} bundle Normalized bundle.
|
|
116
|
+
* @param {object} options Export options.
|
|
117
|
+
* @returns {object[]}
|
|
118
|
+
*/
|
|
119
|
+
static #buildPerComponentEntries(id, bundle, options) {
|
|
120
|
+
const prefix = AltiumLibraryBatchExporter.#safePathSegment(id) + '/'
|
|
121
|
+
const entries = []
|
|
122
|
+
|
|
123
|
+
if (options.includeSourceBundle) {
|
|
124
|
+
entries.push(
|
|
125
|
+
...SourceBundleExporter.export(bundle).entries.map((entry) => ({
|
|
126
|
+
...entry,
|
|
127
|
+
path: prefix + entry.path
|
|
128
|
+
}))
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (options.includeSchLib) {
|
|
133
|
+
entries.push({
|
|
134
|
+
path: prefix + 'library.SchLib',
|
|
135
|
+
bytes: AltiumSchLibExporter.export([bundle]),
|
|
136
|
+
contentType: 'application/octet-stream'
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (options.includePcbLib) {
|
|
141
|
+
entries.push({
|
|
142
|
+
path: prefix + 'library.PcbLib',
|
|
143
|
+
bytes: AltiumPcbLibExporter.export([bundle]),
|
|
144
|
+
contentType: 'application/octet-stream'
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return entries
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Builds merged library output entries.
|
|
153
|
+
* @param {object[]} bundles Normalized bundles.
|
|
154
|
+
* @returns {object[]}
|
|
155
|
+
*/
|
|
156
|
+
static #buildMergedEntries(bundles) {
|
|
157
|
+
return [
|
|
158
|
+
{
|
|
159
|
+
path: 'merged/library.SchLib',
|
|
160
|
+
bytes: AltiumSchLibExporter.export(bundles),
|
|
161
|
+
contentType: 'application/octet-stream'
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
path: 'merged/library.PcbLib',
|
|
165
|
+
bytes: AltiumPcbLibExporter.export(bundles),
|
|
166
|
+
contentType: 'application/octet-stream'
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Emits progress.
|
|
173
|
+
* @param {object} options Export options.
|
|
174
|
+
* @param {object} event Progress event.
|
|
175
|
+
* @returns {void}
|
|
176
|
+
*/
|
|
177
|
+
static #emitProgress(options, event) {
|
|
178
|
+
if (typeof options.onProgress === 'function') {
|
|
179
|
+
options.onProgress(event)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Sanitizes one path segment.
|
|
185
|
+
* @param {string} value Raw value.
|
|
186
|
+
* @returns {string}
|
|
187
|
+
*/
|
|
188
|
+
static #safePathSegment(value) {
|
|
189
|
+
return String(value || 'component').replace(
|
|
190
|
+
/[\\/:\u0000-\u001f]/gu,
|
|
191
|
+
'_'
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Returns the configured client or throws.
|
|
197
|
+
* @returns {{ fetchComponentBundle?: Function, searchComponents?: Function }}
|
|
198
|
+
*/
|
|
199
|
+
#requireClient() {
|
|
200
|
+
if (!this.#client) {
|
|
201
|
+
throw new Error('AltiumLibraryBatchExporter client is required.')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return this.#client
|
|
205
|
+
}
|
|
206
|
+
}
|