altium-toolkit 1.0.9 → 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.
Files changed (79) hide show
  1. package/docs/api.md +6 -2
  2. package/docs/model-format.md +29 -4
  3. package/docs/schemas/altium_toolkit/ci_artifact_bundle_a1.schema.json +80 -0
  4. package/docs/schemas/altium_toolkit/contract_gate_a1.schema.json +34 -0
  5. package/docs/schemas/altium_toolkit/draftsman_board_view_cache_a1.schema.json +115 -0
  6. package/docs/schemas/altium_toolkit/draftsman_digest_a1.schema.json +166 -0
  7. package/docs/schemas/altium_toolkit/host_capabilities_a1.schema.json +39 -0
  8. package/docs/schemas/altium_toolkit/library_merge_plan_a1.schema.json +56 -0
  9. package/docs/schemas/altium_toolkit/library_qa_a1.schema.json +70 -0
  10. package/docs/schemas/altium_toolkit/netlist_a1.schema.json +6 -0
  11. package/docs/schemas/altium_toolkit/normalized_model_a1.schema.json +856 -7
  12. package/docs/schemas/altium_toolkit/parser_compatibility_fuzz_a1.schema.json +25 -0
  13. package/docs/schemas/altium_toolkit/pcb_bom_profile_a1.schema.json +48 -0
  14. package/docs/schemas/altium_toolkit/pcb_layer_stack_a1.schema.json +98 -0
  15. package/docs/schemas/altium_toolkit/pcb_layer_stack_fidelity_a1.schema.json +66 -0
  16. package/docs/schemas/altium_toolkit/pcb_placed_footprint_extraction_a1.schema.json +31 -0
  17. package/docs/schemas/altium_toolkit/pcb_review_metadata_a1.schema.json +62 -0
  18. package/docs/schemas/altium_toolkit/pcb_rigid_flex_topology_a1.schema.json +52 -0
  19. package/docs/schemas/altium_toolkit/pcb_svg_semantics_a1.schema.json +27 -0
  20. package/docs/schemas/altium_toolkit/pcblib_parity_a1.schema.json +24 -0
  21. package/docs/schemas/altium_toolkit/project_bom_pnp_reconciliation_a1.schema.json +63 -0
  22. package/docs/schemas/altium_toolkit/project_bundle_a1.schema.json +6 -0
  23. package/docs/schemas/altium_toolkit/project_document_graph_a1.schema.json +33 -0
  24. package/docs/schemas/altium_toolkit/project_outjob_digest_a1.schema.json +46 -0
  25. package/docs/schemas/altium_toolkit/project_script_a1.schema.json +50 -0
  26. package/docs/schemas/altium_toolkit/schematic_render_ops_a1.schema.json +55 -0
  27. package/docs/schemas/altium_toolkit/schematic_template_extraction_a1.schema.json +37 -0
  28. package/docs/schemas/altium_toolkit/svg_model_cross_link_a1.schema.json +39 -0
  29. package/package.json +1 -1
  30. package/src/core/altium/AltiumParser.mjs +12 -2
  31. package/src/core/altium/CiArtifactBundleBuilder.mjs +213 -0
  32. package/src/core/altium/ContractGateReportBuilder.mjs +351 -0
  33. package/src/core/altium/DraftsmanBoardViewMetadataBuilder.mjs +653 -0
  34. package/src/core/altium/DraftsmanDigestParser.mjs +928 -0
  35. package/src/core/altium/DraftsmanImagePayloadManifestBuilder.mjs +178 -0
  36. package/src/core/altium/HostCapabilityDiagnosticsBuilder.mjs +271 -0
  37. package/src/core/altium/LibraryQaReportBuilder.mjs +504 -0
  38. package/src/core/altium/LibraryRenderManifestBuilder.mjs +172 -2
  39. package/src/core/altium/ParserCompatibilityFuzzer.mjs +192 -0
  40. package/src/core/altium/PcbBomProfileBuilder.mjs +263 -0
  41. package/src/core/altium/PcbComponentKindPolicy.mjs +146 -0
  42. package/src/core/altium/PcbLayerStackFidelityReportBuilder.mjs +141 -0
  43. package/src/core/altium/PcbLayerStackInterchangeParser.mjs +453 -0
  44. package/src/core/altium/PcbLayerStackQueryHelper.mjs +195 -0
  45. package/src/core/altium/PcbLayerStackReadModelBuilder.mjs +906 -0
  46. package/src/core/altium/PcbLayerStackSourceMetadataParser.mjs +488 -0
  47. package/src/core/altium/PcbLibModelParser.mjs +2 -0
  48. package/src/core/altium/PcbLibParityReportBuilder.mjs +242 -0
  49. package/src/core/altium/PcbModelParser.mjs +211 -22
  50. package/src/core/altium/PcbPadStackParser.mjs +171 -2
  51. package/src/core/altium/PcbPickPlacePositionResolver.mjs +11 -1
  52. package/src/core/altium/PcbPlacedFootprintManifestBuilder.mjs +338 -0
  53. package/src/core/altium/PcbPolygonRecordParser.mjs +120 -0
  54. package/src/core/altium/PcbRegionPrimitiveParser.mjs +71 -2
  55. package/src/core/altium/PcbReviewDrillMetadataBuilder.mjs +301 -0
  56. package/src/core/altium/PcbReviewMetadataBuilder.mjs +373 -0
  57. package/src/core/altium/PcbReviewPolygonRealizationBuilder.mjs +269 -0
  58. package/src/core/altium/PcbReviewRouteHighlightProfileBuilder.mjs +298 -0
  59. package/src/core/altium/PcbRigidFlexTopologyBuilder.mjs +171 -0
  60. package/src/core/altium/PcbRouteAnalysisBuilder.mjs +730 -0
  61. package/src/core/altium/PcbStatisticsBuilder.mjs +9 -0
  62. package/src/core/altium/PrintableTextDecoder.mjs +70 -6
  63. package/src/core/altium/PrjPcbModelParser.mjs +69 -2
  64. package/src/core/altium/PrjScrModelParser.mjs +386 -0
  65. package/src/core/altium/ProjectBomPnpReconciliationBuilder.mjs +237 -0
  66. package/src/core/altium/ProjectDesignBundleBuilder.mjs +76 -2
  67. package/src/core/altium/ProjectDocumentGraphBuilder.mjs +280 -0
  68. package/src/core/altium/ProjectNetlistExporter.mjs +5 -1
  69. package/src/core/altium/ProjectOutJobDigestBuilder.mjs +424 -13
  70. package/src/core/altium/SvgModelCrossLinkValidator.mjs +435 -0
  71. package/src/core/circuit-json/CircuitJsonModelAdapter.mjs +300 -96
  72. package/src/core/circuit-json/CircuitJsonModelAdapterPcbElements.mjs +244 -0
  73. package/src/core/circuit-json/CircuitJsonModelSchema.mjs +1 -1
  74. package/src/parser.mjs +21 -0
  75. package/src/ui/PcbFootprintPrimitiveSelector.mjs +13 -1
  76. package/src/ui/PcbScene3dBuilder.mjs +26 -4
  77. package/src/ui/PcbSvgRenderer.mjs +65 -0
  78. package/src/ui/SchematicRenderOpsSidecarBuilder.mjs +554 -0
  79. package/src/ui/SchematicSvgRenderer.mjs +48 -2
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "altium-toolkit.schematic.render-ops.a1",
4
+ "title": "Altium Toolkit Schematic Render Operations A1",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "required": ["schema", "profile", "coordinateSpace", "summary", "records"],
8
+ "properties": {
9
+ "schema": {
10
+ "const": "altium-toolkit.schematic.render-ops.a1"
11
+ },
12
+ "profile": {
13
+ "type": "string"
14
+ },
15
+ "coordinateSpace": {
16
+ "type": "object",
17
+ "additionalProperties": true
18
+ },
19
+ "summary": {
20
+ "type": "object",
21
+ "additionalProperties": true
22
+ },
23
+ "records": {
24
+ "type": "array",
25
+ "items": {
26
+ "type": "object",
27
+ "additionalProperties": true,
28
+ "required": [
29
+ "elementKey",
30
+ "recordId",
31
+ "primitive",
32
+ "operations"
33
+ ],
34
+ "properties": {
35
+ "elementKey": {
36
+ "type": "string"
37
+ },
38
+ "recordId": {
39
+ "type": "string"
40
+ },
41
+ "primitive": {
42
+ "type": "string"
43
+ },
44
+ "operations": {
45
+ "type": "array",
46
+ "items": {
47
+ "type": "object",
48
+ "additionalProperties": true
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "altium-toolkit.schematic.template-extraction.a1",
4
+ "title": "Altium Toolkit Schematic Template Extraction A1",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "required": [
8
+ "schema",
9
+ "sourceDocument",
10
+ "template",
11
+ "summary",
12
+ "diagnostics"
13
+ ],
14
+ "properties": {
15
+ "schema": {
16
+ "const": "altium-toolkit.schematic.template-extraction.a1"
17
+ },
18
+ "sourceDocument": {
19
+ "type": "string"
20
+ },
21
+ "template": {
22
+ "type": ["object", "null"],
23
+ "additionalProperties": true
24
+ },
25
+ "summary": {
26
+ "type": "object",
27
+ "additionalProperties": true
28
+ },
29
+ "diagnostics": {
30
+ "type": "array",
31
+ "items": {
32
+ "type": "object",
33
+ "additionalProperties": true
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "altium-toolkit.svg-model-cross-link.a1",
4
+ "title": "Altium Toolkit SVG Model Cross-Link A1",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "required": [
8
+ "schema",
9
+ "documentKind",
10
+ "summary",
11
+ "missingElements",
12
+ "orphanElements",
13
+ "unresolvedReferences"
14
+ ],
15
+ "properties": {
16
+ "schema": {
17
+ "const": "altium-toolkit.svg-model-cross-link.a1"
18
+ },
19
+ "documentKind": {
20
+ "enum": ["schematic", "pcb", "unknown"]
21
+ },
22
+ "summary": {
23
+ "type": "object",
24
+ "additionalProperties": true
25
+ },
26
+ "missingElements": {
27
+ "type": "array"
28
+ },
29
+ "orphanElements": {
30
+ "type": "array"
31
+ },
32
+ "unresolvedReferences": {
33
+ "type": "array"
34
+ },
35
+ "metadata": {
36
+ "type": "object"
37
+ }
38
+ }
39
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "altium-toolkit",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "description": "Altium document parsing and non-interactive rendering utilities",
5
5
  "keywords": [
6
6
  "altium",
@@ -15,10 +15,12 @@ import { AltiumLayoutParser } from './AltiumLayoutParser.mjs'
15
15
  import { NormalizedModelSchema } from './NormalizedModelSchema.mjs'
16
16
  import { IntLibModelParser } from './IntLibModelParser.mjs'
17
17
  import { IntLibStreamExtractor } from './IntLibStreamExtractor.mjs'
18
+ import { DraftsmanDigestParser } from './DraftsmanDigestParser.mjs'
18
19
  import { PcbModelParser } from './PcbModelParser.mjs'
19
20
  import { PcbLibModelParser } from './PcbLibModelParser.mjs'
20
21
  import { PcbLibStreamExtractor } from './PcbLibStreamExtractor.mjs'
21
22
  import { PrjPcbModelParser } from './PrjPcbModelParser.mjs'
23
+ import { PrjScrModelParser } from './PrjScrModelParser.mjs'
22
24
  import { PcbStreamExtractor } from './PcbStreamExtractor.mjs'
23
25
  import { SchematicMultipartOwnerMatcher } from './SchematicMultipartOwnerMatcher.mjs'
24
26
  import { SchematicSheetStyleResolver } from './SchematicSheetStyleResolver.mjs'
@@ -89,7 +91,7 @@ export class AltiumParser {
89
91
  * Parses a native Altium buffer into the renderer compatibility model.
90
92
  * @param {string} fileName
91
93
  * @param {ArrayBuffer} arrayBuffer
92
- * @returns {{ schema: string, kind: 'schematic' | 'pcb' | 'pcb-library' | 'project' | 'integrated-library', fileType: 'SchDoc' | 'PcbDoc' | 'PcbLib' | 'PrjPcb' | 'IntLib', fileName: string, summary: Record<string, number | string>, diagnostics: { severity: 'info' | 'warning', message: string }[], schematic?: Record<string, unknown>, pcb?: Record<string, unknown>, pcbLibrary?: Record<string, unknown>, project?: Record<string, unknown>, integratedLibrary?: Record<string, unknown>, bom: { designators: string[], quantity: number, pattern: string, source: string, value: string }[] }}
94
+ * @returns {{ schema: string, kind: 'schematic' | 'pcb' | 'pcb-library' | 'project' | 'project-script' | 'integrated-library' | 'draftsman', fileType: 'SchDoc' | 'PcbDoc' | 'PcbLib' | 'PrjPcb' | 'PrjScr' | 'IntLib' | 'PCBDwf', fileName: string, summary: Record<string, number | string>, diagnostics: { severity: 'info' | 'warning', message: string }[], schematic?: Record<string, unknown>, pcb?: Record<string, unknown>, pcbLibrary?: Record<string, unknown>, project?: Record<string, unknown>, projectScript?: Record<string, unknown>, integratedLibrary?: Record<string, unknown>, draftsman?: Record<string, unknown>, bom: { designators: string[], quantity: number, pattern: string, source: string, value: string }[] }}
93
95
  */
94
96
  static parseArrayBufferToRendererModel(fileName, arrayBuffer) {
95
97
  const records = AsciiRecordParser.parse(arrayBuffer)
@@ -122,12 +124,18 @@ export class AltiumParser {
122
124
  if (fileType === 'PrjPcb') {
123
125
  return PrjPcbModelParser.parse(fileName, arrayBuffer)
124
126
  }
127
+ if (fileType === 'PrjScr') {
128
+ return PrjScrModelParser.parse(fileName, arrayBuffer)
129
+ }
125
130
  if (fileType === 'IntLib') {
126
131
  return IntLibModelParser.parse(
127
132
  fileName,
128
133
  IntLibStreamExtractor.extractFromArrayBuffer(arrayBuffer)
129
134
  )
130
135
  }
136
+ if (fileType === 'PCBDwf') {
137
+ return DraftsmanDigestParser.parse(fileName, arrayBuffer)
138
+ }
131
139
  throw new Error('Unsupported file type: ' + fileName)
132
140
  }
133
141
 
@@ -135,7 +143,7 @@ export class AltiumParser {
135
143
  * Chooses the format based on extension and content.
136
144
  * @param {string} fileName
137
145
  * @param {{ fields: Record<string, string | string[]> }[]} records
138
- * @returns {'SchDoc' | 'PcbDoc' | 'PcbLib' | 'PrjPcb' | 'IntLib'}
146
+ * @returns {'SchDoc' | 'PcbDoc' | 'PcbLib' | 'PrjPcb' | 'PrjScr' | 'IntLib' | 'PCBDwf'}
139
147
  */
140
148
  static #sniffFileType(fileName, records) {
141
149
  const normalized = String(fileName || '').toLowerCase()
@@ -143,7 +151,9 @@ export class AltiumParser {
143
151
  if (normalized.endsWith('.pcbdoc')) return 'PcbDoc'
144
152
  if (normalized.endsWith('.pcblib')) return 'PcbLib'
145
153
  if (normalized.endsWith('.prjpcb')) return 'PrjPcb'
154
+ if (normalized.endsWith('.prjscr')) return 'PrjScr'
146
155
  if (normalized.endsWith('.intlib')) return 'IntLib'
156
+ if (normalized.endsWith('.pcbdwf')) return 'PCBDwf'
147
157
 
148
158
  const hasSchematicHeader = records.some((record) =>
149
159
  getField(record.fields, 'HEADER').includes('Schematic')
@@ -0,0 +1,213 @@
1
+ // SPDX-FileCopyrightText: 2026 André Fiedler
2
+ //
3
+ // SPDX-License-Identifier: GPL-3.0-or-later
4
+
5
+ import { PcbSvgRenderer } from '../../ui/PcbSvgRenderer.mjs'
6
+ import { SchematicSvgRenderer } from '../../ui/SchematicSvgRenderer.mjs'
7
+ import { ContractGateReportBuilder } from './ContractGateReportBuilder.mjs'
8
+ import { PcbStatisticsBuilder } from './PcbStatisticsBuilder.mjs'
9
+ import { ProjectDesignBundleBuilder } from './ProjectDesignBundleBuilder.mjs'
10
+ import { ProjectDocumentGraphBuilder } from './ProjectDocumentGraphBuilder.mjs'
11
+ import { ProjectNetlistExporter } from './ProjectNetlistExporter.mjs'
12
+
13
+ /**
14
+ * Builds one deterministic CI artifact package from parsed project documents.
15
+ */
16
+ export class CiArtifactBundleBuilder {
17
+ static SCHEMA = 'altium-toolkit.ci.artifact-bundle.a1'
18
+
19
+ static #UNITS = {
20
+ coordinate: 'mil',
21
+ length: 'mil',
22
+ board: 'mil',
23
+ pnp: 'mil',
24
+ angle: 'deg'
25
+ }
26
+
27
+ static #PNP_UNITS = {
28
+ coordinate: 'mil',
29
+ angle: 'deg'
30
+ }
31
+
32
+ /**
33
+ * Builds a deterministic bundle of normalized, rendered, and report outputs.
34
+ * @param {{ projectModel?: object, documentModels?: object[], designBundle?: object, annotationModels?: object[], variantName?: string, renderSchematicSvg?: boolean, renderPcbLayerSvgs?: boolean, schematicSvgOptions?: object }} options Bundle options.
35
+ * @returns {object}
36
+ */
37
+ static build(options = {}) {
38
+ const documentModels = Array.isArray(options.documentModels)
39
+ ? options.documentModels
40
+ : []
41
+ const designBundle =
42
+ options.designBundle ||
43
+ ProjectDesignBundleBuilder.build({
44
+ projectModel: options.projectModel,
45
+ documentModels,
46
+ annotationModels: options.annotationModels || [],
47
+ variantName: options.variantName
48
+ })
49
+ const activeBundle = designBundle.effectiveVariant || designBundle
50
+ const schematicSvgs =
51
+ options.renderSchematicSvg === false
52
+ ? []
53
+ : CiArtifactBundleBuilder.#schematicSvgs(
54
+ documentModels,
55
+ options.schematicSvgOptions || {}
56
+ )
57
+ const pcbLayerSvgs =
58
+ options.renderPcbLayerSvgs === false
59
+ ? []
60
+ : CiArtifactBundleBuilder.#pcbLayerSvgs(documentModels)
61
+ const statistics = CiArtifactBundleBuilder.#statistics(documentModels)
62
+ const diagnostics = CiArtifactBundleBuilder.#diagnostics(
63
+ designBundle,
64
+ documentModels
65
+ )
66
+ const netlistJson =
67
+ ProjectNetlistExporter.buildNetlistJson(activeBundle)
68
+ const netlist = {
69
+ json: netlistJson,
70
+ wirelist: ProjectNetlistExporter.buildWirelist(activeBundle)
71
+ }
72
+ const contractGate = ContractGateReportBuilder.build({
73
+ documentModels,
74
+ netlist,
75
+ schematicSvgs,
76
+ pcbLayerSvgs,
77
+ diagnostics
78
+ })
79
+ const documentGraph =
80
+ designBundle.project?.documentGraph ||
81
+ ProjectDocumentGraphBuilder.build(
82
+ options.projectModel?.project || designBundle.project || {}
83
+ )
84
+
85
+ return {
86
+ schema: CiArtifactBundleBuilder.SCHEMA,
87
+ summary: {
88
+ normalizedModelCount: documentModels.length,
89
+ schematicSvgCount: schematicSvgs.length,
90
+ pcbLayerSvgCount: pcbLayerSvgs.reduce(
91
+ (total, entry) => total + entry.layers.length,
92
+ 0
93
+ ),
94
+ netCount: netlistJson.nets.length,
95
+ bomRowCount: (activeBundle.bom || designBundle.bom || [])
96
+ .length,
97
+ pnpCount: (activeBundle.pnp?.entries || []).length,
98
+ diagnosticCount: diagnostics.length,
99
+ contractGateStatus: contractGate.status
100
+ },
101
+ units: designBundle.units || CiArtifactBundleBuilder.#UNITS,
102
+ designBundle,
103
+ documentGraph,
104
+ normalizedModels: documentModels,
105
+ netlist,
106
+ bom: {
107
+ rows: activeBundle.bom || designBundle.bom || []
108
+ },
109
+ pnp: CiArtifactBundleBuilder.#pnp(activeBundle, designBundle),
110
+ schematicSvgs,
111
+ pcbLayerSvgs,
112
+ statistics,
113
+ contractGate,
114
+ diagnostics
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Resolves a PnP payload with explicit output units.
120
+ * @param {object} activeBundle Effective bundle or variant.
121
+ * @param {object} designBundle Source design bundle.
122
+ * @returns {object}
123
+ */
124
+ static #pnp(activeBundle, designBundle) {
125
+ const pnp = activeBundle.pnp || designBundle.pnp || { entries: [] }
126
+
127
+ return {
128
+ units: pnp.units || CiArtifactBundleBuilder.#PNP_UNITS,
129
+ ...pnp
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Renders schematic SVG entries.
135
+ * @param {object[]} documentModels Parsed document models.
136
+ * @param {object} renderOptions Schematic SVG render options.
137
+ * @returns {object[]}
138
+ */
139
+ static #schematicSvgs(documentModels, renderOptions) {
140
+ return documentModels
141
+ .filter((model) => model?.kind === 'schematic')
142
+ .map((model) => ({
143
+ fileName: model.fileName || '',
144
+ svg: SchematicSvgRenderer.render(model, renderOptions)
145
+ }))
146
+ }
147
+
148
+ /**
149
+ * Renders per-layer PCB SVG entries.
150
+ * @param {object[]} documentModels Parsed document models.
151
+ * @returns {object[]}
152
+ */
153
+ static #pcbLayerSvgs(documentModels) {
154
+ return documentModels
155
+ .filter((model) => model?.kind === 'pcb')
156
+ .map((model) => ({
157
+ fileName: model.fileName || '',
158
+ layers: PcbSvgRenderer.renderLayerSvgs(model)
159
+ }))
160
+ }
161
+
162
+ /**
163
+ * Builds statistics package entries.
164
+ * @param {object[]} documentModels Parsed document models.
165
+ * @returns {{ pcb: object[] }}
166
+ */
167
+ static #statistics(documentModels) {
168
+ return {
169
+ pcb: documentModels
170
+ .filter((model) => model?.kind === 'pcb')
171
+ .map((model) => ({
172
+ fileName: model.fileName || '',
173
+ statistics:
174
+ model.pcb?.statistics ||
175
+ PcbStatisticsBuilder.build(model.pcb || {})
176
+ }))
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Collects diagnostics from the bundle and source documents.
182
+ * @param {object} designBundle Composed design bundle.
183
+ * @param {object[]} documentModels Parsed document models.
184
+ * @returns {object[]}
185
+ */
186
+ static #diagnostics(designBundle, documentModels) {
187
+ return [
188
+ ...CiArtifactBundleBuilder.#sourceDiagnostics(
189
+ 'design-bundle',
190
+ designBundle.diagnostics || []
191
+ ),
192
+ ...documentModels.flatMap((model) =>
193
+ CiArtifactBundleBuilder.#sourceDiagnostics(
194
+ model.fileName || model.kind || 'document',
195
+ model.diagnostics || []
196
+ )
197
+ )
198
+ ]
199
+ }
200
+
201
+ /**
202
+ * Adds source labels to diagnostics without changing their codes.
203
+ * @param {string} source Diagnostic source label.
204
+ * @param {object[]} diagnostics Source diagnostics.
205
+ * @returns {object[]}
206
+ */
207
+ static #sourceDiagnostics(source, diagnostics) {
208
+ return (diagnostics || []).map((diagnostic) => ({
209
+ source,
210
+ ...diagnostic
211
+ }))
212
+ }
213
+ }