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.
Files changed (125) hide show
  1. package/README.md +34 -5
  2. package/docs/api.md +171 -23
  3. package/docs/model-format.md +192 -20
  4. package/docs/schemas/altium_toolkit/embedded_assets_a1.schema.json +56 -0
  5. package/docs/schemas/altium_toolkit/fixture_coverage_matrix_a1.schema.json +89 -0
  6. package/docs/schemas/altium_toolkit/geometry_bounds_a1.schema.json +86 -0
  7. package/docs/schemas/altium_toolkit/library_catalog_a1.schema.json +65 -0
  8. package/docs/schemas/altium_toolkit/library_diff_a1.schema.json +54 -0
  9. package/docs/schemas/altium_toolkit/library_inspection_a1.schema.json +94 -0
  10. package/docs/schemas/altium_toolkit/library_qa_a1.schema.json +4 -0
  11. package/docs/schemas/altium_toolkit/native_stream_inventory_a1.schema.json +66 -0
  12. package/docs/schemas/altium_toolkit/normalized_model_a1.schema.json +513 -3
  13. package/docs/schemas/altium_toolkit/parameter_record_inventory_a1.schema.json +84 -0
  14. package/docs/schemas/altium_toolkit/parser_diagnostics_a1.schema.json +63 -0
  15. package/docs/schemas/altium_toolkit/parser_value_verification_a1.schema.json +74 -0
  16. package/docs/schemas/altium_toolkit/pcb_class_report_a1.schema.json +79 -0
  17. package/docs/schemas/altium_toolkit/pcb_inspection_a1.schema.json +65 -0
  18. package/docs/schemas/altium_toolkit/pcb_net_membership_a1.schema.json +98 -0
  19. package/docs/schemas/altium_toolkit/project_bundle_a1.schema.json +3 -0
  20. package/docs/schemas/altium_toolkit/project_hierarchy_a1.schema.json +79 -0
  21. package/docs/schemas/altium_toolkit/unsupported_features_a1.schema.json +212 -0
  22. package/docs/testing.md +7 -0
  23. package/examples/README.md +21 -0
  24. package/examples/cli-utils.mjs +148 -0
  25. package/examples/corpus-smoke.mjs +523 -0
  26. package/examples/extract-bom.mjs +47 -0
  27. package/examples/generate-pnp.mjs +59 -0
  28. package/examples/inspect-board.mjs +70 -0
  29. package/examples/inspect-schematic.mjs +406 -0
  30. package/examples/library-catalog.mjs +115 -0
  31. package/examples/net-report.mjs +61 -0
  32. package/examples/validate-library.mjs +59 -0
  33. package/package.json +1 -1
  34. package/spec/library-scope.md +5 -0
  35. package/src/core/BinaryReader.mjs +213 -2
  36. package/src/core/altium/AltiumLibraryBatchExporter.mjs +206 -0
  37. package/src/core/altium/AltiumLibraryRecordBuilder.mjs +293 -0
  38. package/src/core/altium/AltiumParser.mjs +357 -16
  39. package/src/core/altium/AltiumPcbLibExporter.mjs +101 -0
  40. package/src/core/altium/AltiumSchLibExporter.mjs +57 -0
  41. package/src/core/altium/AltiumUnits.mjs +205 -0
  42. package/src/core/altium/AsciiRecordParser.mjs +52 -11
  43. package/src/core/altium/EmbeddedAssetReportBuilder.mjs +383 -0
  44. package/src/core/altium/FixtureCoverageMatrixBuilder.mjs +304 -0
  45. package/src/core/altium/GeometryBoundsReportBuilder.mjs +935 -0
  46. package/src/core/altium/LibraryCatalogArtifactBuilder.mjs +296 -0
  47. package/src/core/altium/LibraryDiffReportBuilder.mjs +260 -0
  48. package/src/core/altium/LibraryInspectionReportBuilder.mjs +156 -0
  49. package/src/core/altium/LibraryQaReportBuilder.mjs +374 -1
  50. package/src/core/altium/NativeStreamInventoryBuilder.mjs +177 -0
  51. package/src/core/altium/NormalizedModelSchema.mjs +3 -31
  52. package/src/core/altium/ParameterCollection.mjs +431 -0
  53. package/src/core/altium/ParameterRecordInventoryBuilder.mjs +274 -0
  54. package/src/core/altium/ParserCompatibilityFuzzer.mjs +106 -2
  55. package/src/core/altium/ParserDiagnosticNormalizer.mjs +213 -0
  56. package/src/core/altium/ParserErrors.mjs +90 -0
  57. package/src/core/altium/ParserFieldCoverageReportBuilder.mjs +656 -0
  58. package/src/core/altium/ParserUtils.mjs +24 -0
  59. package/src/core/altium/ParserValueVerificationReportBuilder.mjs +323 -0
  60. package/src/core/altium/PcbClassReportBuilder.mjs +366 -0
  61. package/src/core/altium/PcbComponentKindPolicy.mjs +9 -9
  62. package/src/core/altium/PcbEmbeddedModelExtractor.mjs +22 -3
  63. package/src/core/altium/PcbInspectionReportBuilder.mjs +313 -0
  64. package/src/core/altium/PcbLayerGroups.mjs +308 -0
  65. package/src/core/altium/PcbLayerStackCustomDataParser.mjs +183 -0
  66. package/src/core/altium/PcbLayerStackInterchangeParser.mjs +473 -4
  67. package/src/core/altium/PcbLayerStackReadModelBuilder.mjs +83 -15
  68. package/src/core/altium/PcbLayerStackSourceMetadataParser.mjs +74 -4
  69. package/src/core/altium/PcbLibModelParser.mjs +20 -4
  70. package/src/core/altium/PcbLibStreamExtractor.mjs +49 -6
  71. package/src/core/altium/PcbModelParser.mjs +223 -4
  72. package/src/core/altium/PcbNetMembershipReportBuilder.mjs +270 -0
  73. package/src/core/altium/PcbOutlineRecovery.mjs +94 -0
  74. package/src/core/altium/PcbStreamExtractor.mjs +130 -6
  75. package/src/core/altium/PcbTrackPrimitiveParser.mjs +66 -2
  76. package/src/core/altium/ProjectDesignBundleBuilder.mjs +15 -0
  77. package/src/core/altium/ProjectHierarchyReportBuilder.mjs +660 -0
  78. package/src/core/altium/ProjectNetlistExporter.mjs +2 -0
  79. package/src/core/altium/RawDataPreservationReportBuilder.mjs +348 -0
  80. package/src/core/altium/SchLibModelParser.mjs +840 -0
  81. package/src/core/altium/SchLibStreamExtractor.mjs +586 -0
  82. package/src/core/altium/SchematicBusEntryParser.mjs +3 -2
  83. package/src/core/altium/SchematicCodeSymbolParser.mjs +663 -0
  84. package/src/core/altium/SchematicConnectivityQaBuilder.mjs +177 -2
  85. package/src/core/altium/SchematicDirectiveParser.mjs +5 -17
  86. package/src/core/altium/SchematicDisplayModeCatalogParser.mjs +10 -1
  87. package/src/core/altium/SchematicFieldCoverageReportBuilder.mjs +549 -0
  88. package/src/core/altium/SchematicHarnessParser.mjs +9 -3
  89. package/src/core/altium/SchematicHyperlinkParser.mjs +122 -0
  90. package/src/core/altium/SchematicNetlistBuilder.mjs +271 -8
  91. package/src/core/altium/SchematicNoErcSymbolResolver.mjs +36 -0
  92. package/src/core/altium/SchematicOwnershipGraphParser.mjs +102 -3
  93. package/src/core/altium/SchematicPinParser.mjs +99 -65
  94. package/src/core/altium/SchematicPrimitiveParser.mjs +125 -22
  95. package/src/core/altium/SchematicQaReportBuilder.mjs +2 -0
  96. package/src/core/altium/SchematicRecordStreamParser.mjs +183 -0
  97. package/src/core/altium/SchematicRecordTypeRegistry.mjs +6 -1
  98. package/src/core/altium/SchematicSheetParser.mjs +8 -2
  99. package/src/core/altium/SchematicStreamExtractor.mjs +107 -21
  100. package/src/core/altium/SchematicTextOrientationResolver.mjs +76 -0
  101. package/src/core/altium/SchematicTextParser.mjs +28 -12
  102. package/src/core/altium/SchematicTextRunParser.mjs +81 -0
  103. package/src/core/altium/SchematicThumbnailParser.mjs +425 -0
  104. package/src/core/altium/SourceBundleExporter.mjs +156 -0
  105. package/src/core/altium/SourceComponentBundleNormalizer.mjs +295 -0
  106. package/src/core/altium/SourceComponentClient.mjs +239 -0
  107. package/src/core/altium/UnsupportedFeatureReportBuilder.mjs +380 -0
  108. package/src/core/ole/OleCompoundDocumentWriter.mjs +449 -0
  109. package/src/parser.mjs +43 -1
  110. package/src/renderers.mjs +1 -0
  111. package/src/styles/altium-renderers.css +6 -6
  112. package/src/ui/PcbArcUtils.mjs +19 -2
  113. package/src/ui/PcbScene3dBuilder.mjs +202 -20
  114. package/src/ui/PcbScene3dModelRegistry.mjs +28 -18
  115. package/src/ui/PcbScene3dPlacementSideResolver.mjs +48 -6
  116. package/src/ui/SchematicColorResolver.mjs +185 -0
  117. package/src/ui/SchematicDirectiveRenderer.mjs +133 -22
  118. package/src/ui/SchematicLineColorResolver.mjs +88 -0
  119. package/src/ui/SchematicNoteRenderer.mjs +5 -1
  120. package/src/ui/SchematicOwnerPinLabelLayout.mjs +269 -8
  121. package/src/ui/SchematicOwnerPinMarkerLineThemer.mjs +155 -0
  122. package/src/ui/SchematicPinSvgRenderer.mjs +229 -62
  123. package/src/ui/SchematicShapeRenderer.mjs +86 -17
  124. package/src/ui/SchematicSvgRenderer.mjs +980 -58
  125. package/src/ui/SchematicTypography.mjs +4 -3
@@ -0,0 +1,212 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "altium-toolkit.unsupported-features.a1",
4
+ "title": "Altium Toolkit Unsupported Features A1",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "required": [
8
+ "schema",
9
+ "summary",
10
+ "recordTypes",
11
+ "rawRecords",
12
+ "opaqueRecords",
13
+ "diagnostics"
14
+ ],
15
+ "properties": {
16
+ "schema": {
17
+ "const": "altium-toolkit.unsupported-features.a1"
18
+ },
19
+ "summary": {
20
+ "type": "object",
21
+ "additionalProperties": true,
22
+ "required": [
23
+ "modelCount",
24
+ "unsupportedRecordTypeCount",
25
+ "rawRecordCount",
26
+ "opaqueRecordCount",
27
+ "diagnosticCount",
28
+ "itemCount",
29
+ "status"
30
+ ],
31
+ "properties": {
32
+ "modelCount": {
33
+ "type": "number"
34
+ },
35
+ "unsupportedRecordTypeCount": {
36
+ "type": "number"
37
+ },
38
+ "rawRecordCount": {
39
+ "type": "number"
40
+ },
41
+ "opaqueRecordCount": {
42
+ "type": "number"
43
+ },
44
+ "diagnosticCount": {
45
+ "type": "number"
46
+ },
47
+ "itemCount": {
48
+ "type": "number"
49
+ },
50
+ "status": {
51
+ "enum": ["supported", "unsupported"]
52
+ }
53
+ }
54
+ },
55
+ "recordTypes": {
56
+ "type": "array",
57
+ "items": {
58
+ "$ref": "#/$defs/recordType"
59
+ }
60
+ },
61
+ "rawRecords": {
62
+ "type": "array",
63
+ "items": {
64
+ "$ref": "#/$defs/rawRecord"
65
+ }
66
+ },
67
+ "opaqueRecords": {
68
+ "type": "array",
69
+ "items": {
70
+ "$ref": "#/$defs/opaqueRecord"
71
+ }
72
+ },
73
+ "diagnostics": {
74
+ "type": "array",
75
+ "items": {
76
+ "$ref": "#/$defs/diagnostic"
77
+ }
78
+ }
79
+ },
80
+ "$defs": {
81
+ "recordType": {
82
+ "type": "object",
83
+ "additionalProperties": true,
84
+ "required": ["domain", "recordType", "name", "family", "count"],
85
+ "properties": {
86
+ "fileName": {
87
+ "type": "string"
88
+ },
89
+ "domain": {
90
+ "type": "string"
91
+ },
92
+ "recordType": {
93
+ "type": "number"
94
+ },
95
+ "name": {
96
+ "type": "string"
97
+ },
98
+ "family": {
99
+ "type": "string"
100
+ },
101
+ "count": {
102
+ "type": "number"
103
+ }
104
+ }
105
+ },
106
+ "rawRecord": {
107
+ "type": "object",
108
+ "additionalProperties": true,
109
+ "required": ["domain"],
110
+ "properties": {
111
+ "fileName": {
112
+ "type": "string"
113
+ },
114
+ "domain": {
115
+ "type": "string"
116
+ },
117
+ "sourceStream": {
118
+ "type": "string"
119
+ },
120
+ "sourceStorage": {
121
+ "type": "string"
122
+ },
123
+ "recordIndex": {
124
+ "type": "number"
125
+ },
126
+ "family": {
127
+ "type": "string"
128
+ },
129
+ "type": {
130
+ "type": "string"
131
+ },
132
+ "typeId": {
133
+ "type": "number"
134
+ },
135
+ "byteLength": {
136
+ "type": "number"
137
+ },
138
+ "supported": {
139
+ "type": "boolean"
140
+ },
141
+ "parsed": {
142
+ "type": "boolean"
143
+ }
144
+ }
145
+ },
146
+ "opaqueRecord": {
147
+ "type": "object",
148
+ "additionalProperties": true,
149
+ "required": ["domain"],
150
+ "properties": {
151
+ "fileName": {
152
+ "type": "string"
153
+ },
154
+ "domain": {
155
+ "type": "string"
156
+ },
157
+ "sourceStream": {
158
+ "type": "string"
159
+ },
160
+ "sourceStorage": {
161
+ "type": "string"
162
+ },
163
+ "frameType": {
164
+ "type": "number"
165
+ },
166
+ "recordIndex": {
167
+ "type": "number"
168
+ },
169
+ "byteLength": {
170
+ "type": "number"
171
+ }
172
+ }
173
+ },
174
+ "diagnostic": {
175
+ "type": "object",
176
+ "additionalProperties": true,
177
+ "required": ["code", "severity", "message"],
178
+ "properties": {
179
+ "fileName": {
180
+ "type": "string"
181
+ },
182
+ "code": {
183
+ "type": "string"
184
+ },
185
+ "severity": {
186
+ "enum": ["info", "warning", "error"]
187
+ },
188
+ "message": {
189
+ "type": "string"
190
+ },
191
+ "source": {
192
+ "type": "string"
193
+ },
194
+ "sourceStream": {
195
+ "type": "string"
196
+ },
197
+ "sourceStorage": {
198
+ "type": "string"
199
+ },
200
+ "recordIndex": {
201
+ "type": "number"
202
+ },
203
+ "recordType": {
204
+ "type": "number"
205
+ },
206
+ "errorKind": {
207
+ "type": "string"
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
package/docs/testing.md CHANGED
@@ -6,6 +6,11 @@ SPDX-License-Identifier: CC-BY-SA-4.0
6
6
 
7
7
  # Testing
8
8
 
9
+ Exporter tests use only synthetic component responses and generated OLE
10
+ streams. Do not add native customer files or provider-derived raw fixtures.
11
+ When exercising source lookup, inject a fake fetcher/client and assert emitted
12
+ entries, progress events, checkpoints, diagnostics, and OLE round trips.
13
+
9
14
  Run the complete suite:
10
15
 
11
16
  ```bash
@@ -34,3 +39,5 @@ areas and must keep `assetPolicy` set to `repo-owned-synthetic-only`. Each
34
39
  fixture entry records `source: inline-synthetic-records` plus expected parser,
35
40
  SVG, schema, and diagnostic contracts so tests can catch drift between fake
36
41
  fixtures and public read-model coverage.
42
+ `FixtureCoverageMatrixBuilder` can turn the manifest into a machine-readable
43
+ required-coverage report without adding native fixture files.
@@ -6,6 +6,27 @@ SPDX-License-Identifier: CC-BY-SA-4.0
6
6
 
7
7
  # Examples
8
8
 
9
+ ## Read-only utility scripts
10
+
11
+ The repository includes small Node.js examples for common non-interactive
12
+ workflows. They read the requested input file, write deterministic output to
13
+ stdout, and do not modify source documents:
14
+
15
+ - `node examples/inspect-board.mjs <file> [--json]`
16
+ - `node examples/inspect-schematic.mjs <file> [--json] [--view <view>]`
17
+ - `node examples/extract-bom.mjs <file> [--json]`
18
+ - `node examples/generate-pnp.mjs <file> [--json]`
19
+ - `node examples/net-report.mjs <file> [--json]`
20
+ - `node examples/library-catalog.mjs <file> [--json]`
21
+ - `node examples/library-catalog.mjs <file> --html`
22
+ - `node examples/validate-library.mjs <file> [--json]`
23
+ - `node examples/corpus-smoke.mjs <directory> [--json] [--coverage]`
24
+
25
+ Run any script with `--help` to see its output mode. The schematic inspection
26
+ views are `summary`, `flat`, `hierarchy`, `parts`, `nets`, and `all`. Corpus
27
+ coverage reports include aggregate record-type counters and field-gap counters
28
+ for caller-owned local sample directories.
29
+
9
30
  ## Arduino Uno
10
31
 
11
32
  The `arduino-uno` example is a browser page for loading `.SchDoc` and
@@ -0,0 +1,148 @@
1
+ // SPDX-FileCopyrightText: 2026 André Fiedler
2
+ //
3
+ // SPDX-License-Identifier: GPL-3.0-or-later
4
+
5
+ import { readFile } from 'node:fs/promises'
6
+ import { basename } from 'node:path'
7
+
8
+ import { AltiumParser } from '../src/index.mjs'
9
+
10
+ /**
11
+ * Returns true when help was requested.
12
+ * @param {string[]} args CLI arguments.
13
+ * @returns {boolean}
14
+ */
15
+ export function hasHelpFlag(args) {
16
+ return args.includes('--help') || args.includes('-h')
17
+ }
18
+
19
+ /**
20
+ * Prints a read-only script help message.
21
+ * @param {string} scriptName Script name.
22
+ * @param {string} summary Script summary.
23
+ * @param {string[]} lines Additional help lines.
24
+ * @returns {void}
25
+ */
26
+ export function printHelp(scriptName, summary, lines = []) {
27
+ console.log(
28
+ [
29
+ 'Usage: ' + scriptName + ' <file> [--json]',
30
+ '',
31
+ summary,
32
+ '',
33
+ 'This is a read-only example. It reads the input file and writes report output to stdout.',
34
+ ...lines
35
+ ].join('\n')
36
+ )
37
+ }
38
+
39
+ /**
40
+ * Resolves the first non-option argument as an input path.
41
+ * @param {string[]} args CLI arguments.
42
+ * @returns {string}
43
+ */
44
+ export function inputPathFromArgs(args) {
45
+ return args.find((arg) => !arg.startsWith('-')) || ''
46
+ }
47
+
48
+ /**
49
+ * Returns true when JSON output was requested.
50
+ * @param {string[]} args CLI arguments.
51
+ * @returns {boolean}
52
+ */
53
+ export function wantsJson(args) {
54
+ return args.includes('--json')
55
+ }
56
+
57
+ /**
58
+ * Parses an Altium file from disk using the library parser.
59
+ * @param {string} filePath Input path.
60
+ * @returns {Promise<object>}
61
+ */
62
+ export async function parseModelFromPath(filePath) {
63
+ const bytes = await readFile(filePath)
64
+ const arrayBuffer = bytes.buffer.slice(
65
+ bytes.byteOffset,
66
+ bytes.byteOffset + bytes.byteLength
67
+ )
68
+ return AltiumParser.parseArrayBuffer(basename(filePath), arrayBuffer)
69
+ }
70
+
71
+ /**
72
+ * Prints a JSON value with deterministic indentation.
73
+ * @param {unknown} value JSON-compatible value.
74
+ * @returns {void}
75
+ */
76
+ export function printJson(value) {
77
+ console.log(JSON.stringify(value, null, 4))
78
+ }
79
+
80
+ /**
81
+ * Prints an error and marks the process as failed.
82
+ * @param {string} scriptName Script name.
83
+ * @returns {void}
84
+ */
85
+ export function printMissingPath(scriptName) {
86
+ console.error('Usage: ' + scriptName + ' <file> [--json]')
87
+ console.error('Run `' + scriptName + ' --help` for details.')
88
+ process.exitCode = 1
89
+ }
90
+
91
+ /**
92
+ * Escapes one CSV field.
93
+ * @param {unknown} value Field value.
94
+ * @returns {string}
95
+ */
96
+ export function csvField(value) {
97
+ const text = String(value ?? '')
98
+ return /[",\n\r]/u.test(text) ? '"' + text.replace(/"/gu, '""') + '"' : text
99
+ }
100
+
101
+ /**
102
+ * Prints CSV rows.
103
+ * @param {string[]} headers CSV headers.
104
+ * @param {object[]} rows Data rows.
105
+ * @returns {void}
106
+ */
107
+ export function printCsv(headers, rows) {
108
+ console.log(headers.map(csvField).join(','))
109
+ for (const row of rows) {
110
+ console.log(headers.map((header) => csvField(row[header])).join(','))
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Returns a compact parser identity for report output.
116
+ * @param {object} model Parsed model.
117
+ * @returns {object}
118
+ */
119
+ export function modelIdentity(model) {
120
+ return {
121
+ fileName: model.fileName,
122
+ fileType: model.fileType,
123
+ kind: model.kind,
124
+ title: model.summary?.title || model.fileName
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Runs a read-only CLI script.
130
+ * @param {{ scriptName: string, summary: string, helpLines?: string[], run: (model: object, args: string[]) => void | Promise<void> }} options Script options.
131
+ * @returns {Promise<void>}
132
+ */
133
+ export async function runReadOnlyScript(options) {
134
+ const args = process.argv.slice(2)
135
+ if (hasHelpFlag(args)) {
136
+ printHelp(options.scriptName, options.summary, options.helpLines || [])
137
+ return
138
+ }
139
+
140
+ const filePath = inputPathFromArgs(args)
141
+ if (!filePath) {
142
+ printMissingPath(options.scriptName)
143
+ return
144
+ }
145
+
146
+ const model = await parseModelFromPath(filePath)
147
+ await options.run(model, args)
148
+ }