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
|
@@ -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.
|
package/examples/README.md
CHANGED
|
@@ -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
|
+
}
|