altium-toolkit 1.0.10 → 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 (63) 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 +4 -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 +132 -1
  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/normalized_model_a1.schema.json +692 -2
  11. package/docs/schemas/altium_toolkit/pcb_bom_profile_a1.schema.json +48 -0
  12. package/docs/schemas/altium_toolkit/pcb_layer_stack_a1.schema.json +98 -0
  13. package/docs/schemas/altium_toolkit/pcb_layer_stack_fidelity_a1.schema.json +66 -0
  14. package/docs/schemas/altium_toolkit/pcb_placed_footprint_extraction_a1.schema.json +31 -0
  15. package/docs/schemas/altium_toolkit/pcb_review_metadata_a1.schema.json +62 -0
  16. package/docs/schemas/altium_toolkit/pcb_rigid_flex_topology_a1.schema.json +52 -0
  17. package/docs/schemas/altium_toolkit/pcblib_parity_a1.schema.json +24 -0
  18. package/docs/schemas/altium_toolkit/project_bom_pnp_reconciliation_a1.schema.json +63 -0
  19. package/docs/schemas/altium_toolkit/project_outjob_digest_a1.schema.json +46 -0
  20. package/docs/schemas/altium_toolkit/project_script_a1.schema.json +50 -0
  21. package/docs/schemas/altium_toolkit/schematic_render_ops_a1.schema.json +55 -0
  22. package/docs/schemas/altium_toolkit/schematic_template_extraction_a1.schema.json +37 -0
  23. package/package.json +1 -1
  24. package/src/core/altium/AltiumParser.mjs +7 -2
  25. package/src/core/altium/CiArtifactBundleBuilder.mjs +16 -5
  26. package/src/core/altium/ContractGateReportBuilder.mjs +351 -0
  27. package/src/core/altium/DraftsmanBoardViewMetadataBuilder.mjs +653 -0
  28. package/src/core/altium/DraftsmanDigestParser.mjs +246 -7
  29. package/src/core/altium/DraftsmanImagePayloadManifestBuilder.mjs +178 -0
  30. package/src/core/altium/HostCapabilityDiagnosticsBuilder.mjs +271 -0
  31. package/src/core/altium/LibraryQaReportBuilder.mjs +504 -0
  32. package/src/core/altium/LibraryRenderManifestBuilder.mjs +172 -2
  33. package/src/core/altium/PcbBomProfileBuilder.mjs +263 -0
  34. package/src/core/altium/PcbComponentKindPolicy.mjs +146 -0
  35. package/src/core/altium/PcbLayerStackFidelityReportBuilder.mjs +141 -0
  36. package/src/core/altium/PcbLayerStackInterchangeParser.mjs +453 -0
  37. package/src/core/altium/PcbLayerStackQueryHelper.mjs +195 -0
  38. package/src/core/altium/PcbLayerStackReadModelBuilder.mjs +906 -0
  39. package/src/core/altium/PcbLayerStackSourceMetadataParser.mjs +488 -0
  40. package/src/core/altium/PcbLibModelParser.mjs +2 -0
  41. package/src/core/altium/PcbLibParityReportBuilder.mjs +242 -0
  42. package/src/core/altium/PcbModelParser.mjs +182 -18
  43. package/src/core/altium/PcbPickPlacePositionResolver.mjs +3 -0
  44. package/src/core/altium/PcbPlacedFootprintManifestBuilder.mjs +338 -0
  45. package/src/core/altium/PcbPolygonRecordParser.mjs +120 -0
  46. package/src/core/altium/PcbReviewDrillMetadataBuilder.mjs +301 -0
  47. package/src/core/altium/PcbReviewMetadataBuilder.mjs +373 -0
  48. package/src/core/altium/PcbReviewPolygonRealizationBuilder.mjs +269 -0
  49. package/src/core/altium/PcbReviewRouteHighlightProfileBuilder.mjs +298 -0
  50. package/src/core/altium/PcbRigidFlexTopologyBuilder.mjs +171 -0
  51. package/src/core/altium/PrintableTextDecoder.mjs +70 -6
  52. package/src/core/altium/PrjPcbModelParser.mjs +45 -0
  53. package/src/core/altium/PrjScrModelParser.mjs +386 -0
  54. package/src/core/altium/ProjectBomPnpReconciliationBuilder.mjs +237 -0
  55. package/src/core/altium/ProjectDesignBundleBuilder.mjs +61 -2
  56. package/src/core/altium/ProjectOutJobDigestBuilder.mjs +424 -13
  57. package/src/core/altium/SvgModelCrossLinkValidator.mjs +35 -2
  58. package/src/core/circuit-json/CircuitJsonModelAdapter.mjs +164 -0
  59. package/src/parser.mjs +15 -0
  60. package/src/ui/PcbFootprintPrimitiveSelector.mjs +13 -1
  61. package/src/ui/PcbScene3dBuilder.mjs +26 -4
  62. package/src/ui/SchematicRenderOpsSidecarBuilder.mjs +554 -0
  63. package/src/ui/SchematicSvgRenderer.mjs +48 -2
@@ -8,6 +8,68 @@ import { CircuitJsonModelAdapterPcbElements } from './CircuitJsonModelAdapterPcb
8
8
 
9
9
  const Primitives = CircuitJsonModelAdapterPrimitives
10
10
  const PcbElements = CircuitJsonModelAdapterPcbElements
11
+ const ALTIUM_TOOLKIT_SIDECARS = [
12
+ {
13
+ type: 'altium_toolkit_pcb_layer_stack',
14
+ paths: [['pcb', 'layerStackReadModel']],
15
+ schema: 'altium-toolkit.pcb.layer-stack.a1'
16
+ },
17
+ {
18
+ type: 'altium_toolkit_pcb_rigid_flex_topology',
19
+ paths: [['pcb', 'rigidFlexTopology']],
20
+ schema: 'altium-toolkit.pcb.rigid-flex-topology.a1'
21
+ },
22
+ {
23
+ type: 'altium_toolkit_pcb_review_metadata',
24
+ paths: [['pcb', 'reviewMetadata']],
25
+ schema: 'altium-toolkit.pcb.review-metadata.a1'
26
+ },
27
+ {
28
+ type: 'altium_toolkit_pcb_placed_footprint_extraction',
29
+ paths: [['pcb', 'footprintExtractionManifest']],
30
+ schema: 'altium-toolkit.pcb.placed-footprint-extraction.a1'
31
+ },
32
+ {
33
+ type: 'altium_toolkit_pcblib_parity',
34
+ paths: [['pcbLibrary', 'parityReport']],
35
+ schema: 'altium-toolkit.pcblib.parity.a1'
36
+ },
37
+ {
38
+ type: 'altium_toolkit_project_outjob_digest',
39
+ paths: [['project', 'outJobDigest']],
40
+ schema: 'altium-toolkit.project.outjob-digest.a1'
41
+ },
42
+ {
43
+ type: 'altium_toolkit_project_document_graph',
44
+ paths: [['project', 'documentGraph'], ['documentGraph']],
45
+ schema: 'altium-toolkit.project.document-graph.a1'
46
+ },
47
+ {
48
+ type: 'altium_toolkit_project_bom_pnp_reconciliation',
49
+ paths: [['reconciliation']],
50
+ schema: 'altium-toolkit.project.bom-pnp-reconciliation.a1'
51
+ },
52
+ {
53
+ type: 'altium_toolkit_draftsman_image_payloads',
54
+ paths: [['draftsman', 'imagePayloads']],
55
+ schema: 'altium-toolkit.draftsman.image-payloads.a1'
56
+ },
57
+ {
58
+ type: 'altium_toolkit_draftsman_board_view_metadata',
59
+ paths: [['draftsman', 'boardViewMetadata']],
60
+ schema: 'altium-toolkit.draftsman.board-view-cache.a1'
61
+ },
62
+ {
63
+ type: 'altium_toolkit_contract_gate',
64
+ paths: [['contractGate']],
65
+ schema: 'altium-toolkit.contract-gate.a1'
66
+ },
67
+ {
68
+ type: 'altium_toolkit_host_capabilities',
69
+ paths: [['hostCapabilities']],
70
+ schema: 'altium-toolkit.host-capabilities.a1'
71
+ }
72
+ ]
11
73
 
12
74
  /**
13
75
  * Converts between legacy renderer models and Circuit JSON element arrays.
@@ -55,6 +117,7 @@ export class CircuitJsonModelAdapter {
55
117
  }
56
118
 
57
119
  CircuitJsonModelAdapter.#appendBom(circuitJson, model, idScope)
120
+ CircuitJsonModelAdapter.#appendSidecars(circuitJson, model, idScope)
58
121
  CircuitJsonModelAdapter.#attachCompatibility(circuitJson, model)
59
122
 
60
123
  return CircuitJsonModelSchema.attach(circuitJson)
@@ -651,6 +714,107 @@ export class CircuitJsonModelAdapter {
651
714
  }
652
715
  }
653
716
 
717
+ /**
718
+ * Appends serialized Altium Toolkit sidecar elements.
719
+ * @param {object[]} circuitJson
720
+ * @param {Record<string, unknown>} model
721
+ * @param {string} idScope
722
+ * @returns {void}
723
+ */
724
+ static #appendSidecars(circuitJson, model, idScope) {
725
+ for (const descriptor of ALTIUM_TOOLKIT_SIDECARS) {
726
+ const payload = CircuitJsonModelAdapter.#sidecarPayload(
727
+ model,
728
+ descriptor.paths
729
+ )
730
+ if (!payload) continue
731
+
732
+ circuitJson.push(
733
+ CircuitJsonModelAdapter.#sidecarElement(
734
+ descriptor,
735
+ payload,
736
+ model,
737
+ idScope
738
+ )
739
+ )
740
+ }
741
+ }
742
+
743
+ /**
744
+ * Builds one custom Altium Toolkit Circuit JSON sidecar element.
745
+ * @param {{ type: string, schema: string }} descriptor
746
+ * @param {Record<string, unknown>} payload
747
+ * @param {Record<string, unknown>} model
748
+ * @param {string} idScope
749
+ * @returns {object}
750
+ */
751
+ static #sidecarElement(descriptor, payload, model, idScope) {
752
+ return {
753
+ type: descriptor.type,
754
+ altium_toolkit_sidecar_id: Primitives.id(idScope, [
755
+ 'altium_toolkit_sidecar',
756
+ descriptor.type
757
+ ]),
758
+ source_document: CircuitJsonModelAdapter.#sourceDocument(model),
759
+ schema: Primitives.string(payload.schema, descriptor.schema),
760
+ payload
761
+ }
762
+ }
763
+
764
+ /**
765
+ * Returns the first available sidecar payload from candidate model paths.
766
+ * @param {Record<string, unknown>} model
767
+ * @param {string[][]} paths
768
+ * @returns {Record<string, unknown> | null}
769
+ */
770
+ static #sidecarPayload(model, paths) {
771
+ for (const path of paths) {
772
+ const payload = CircuitJsonModelAdapter.#valueAtPath(model, path)
773
+ if (CircuitJsonModelAdapter.#isSidecarPayload(payload)) {
774
+ return payload
775
+ }
776
+ }
777
+ return null
778
+ }
779
+
780
+ /**
781
+ * Returns a nested object value.
782
+ * @param {Record<string, unknown>} value
783
+ * @param {string[]} path
784
+ * @returns {unknown}
785
+ */
786
+ static #valueAtPath(value, path) {
787
+ return path.reduce(
788
+ (current, key) =>
789
+ current && typeof current === 'object'
790
+ ? current[key]
791
+ : undefined,
792
+ value
793
+ )
794
+ }
795
+
796
+ /**
797
+ * Returns true when a value can be serialized as a sidecar payload.
798
+ * @param {unknown} value
799
+ * @returns {value is Record<string, unknown>}
800
+ */
801
+ static #isSidecarPayload(value) {
802
+ return !!value && typeof value === 'object' && !Array.isArray(value)
803
+ }
804
+
805
+ /**
806
+ * Builds the source document identity for sidecar elements.
807
+ * @param {Record<string, unknown>} model
808
+ * @returns {{ kind: string, file_type: string, file_name: string }}
809
+ */
810
+ static #sourceDocument(model) {
811
+ return {
812
+ kind: Primitives.string(model.kind, 'document'),
813
+ file_type: Primitives.string(model.fileType, ''),
814
+ file_name: Primitives.string(model.fileName, '')
815
+ }
816
+ }
817
+
654
818
  /**
655
819
  * Appends one schematic line or trace.
656
820
  * @param {object[]} circuitJson
package/src/parser.mjs CHANGED
@@ -9,12 +9,16 @@ export { OleDirectoryEntry } from './core/ole/OleDirectoryEntry.mjs'
9
9
  export { AltiumParser } from './core/altium/AltiumParser.mjs'
10
10
  export { AltiumLayoutParser } from './core/altium/AltiumLayoutParser.mjs'
11
11
  export { AsciiRecordParser } from './core/altium/AsciiRecordParser.mjs'
12
+ export { HostCapabilityDiagnosticsBuilder } from './core/altium/HostCapabilityDiagnosticsBuilder.mjs'
12
13
  export { IntLibModelParser } from './core/altium/IntLibModelParser.mjs'
13
14
  export { IntLibStreamExtractor } from './core/altium/IntLibStreamExtractor.mjs'
14
15
  export { EmbeddedFileInventoryBuilder } from './core/altium/EmbeddedFileInventoryBuilder.mjs'
15
16
  export { CiArtifactBundleBuilder } from './core/altium/CiArtifactBundleBuilder.mjs'
17
+ export { ContractGateReportBuilder } from './core/altium/ContractGateReportBuilder.mjs'
18
+ export { DraftsmanBoardViewMetadataBuilder } from './core/altium/DraftsmanBoardViewMetadataBuilder.mjs'
16
19
  export { DraftsmanDigestParser } from './core/altium/DraftsmanDigestParser.mjs'
17
20
  export { LibraryRenderManifestBuilder } from './core/altium/LibraryRenderManifestBuilder.mjs'
21
+ export { LibraryQaReportBuilder } from './core/altium/LibraryQaReportBuilder.mjs'
18
22
  export { LibrarySearchIndex } from './core/altium/LibrarySearchIndex.mjs'
19
23
  export { ParserUtils } from './core/altium/ParserUtils.mjs'
20
24
  export { ParserCompatibilityFuzzer } from './core/altium/ParserCompatibilityFuzzer.mjs'
@@ -27,7 +31,9 @@ export { ProjectVariantViewBuilder } from './core/altium/ProjectVariantViewBuild
27
31
  export { CircuitJsonModelSchema } from './core/circuit-json/CircuitJsonModelSchema.mjs'
28
32
  export { CircuitJsonModelAdapter } from './core/circuit-json/CircuitJsonModelAdapter.mjs'
29
33
  export { PcbBinaryPrimitiveParser } from './core/altium/PcbBinaryPrimitiveParser.mjs'
34
+ export { PcbBomProfileBuilder } from './core/altium/PcbBomProfileBuilder.mjs'
30
35
  export { PcbBoardRegionSemanticsParser } from './core/altium/PcbBoardRegionSemanticsParser.mjs'
36
+ export { PcbComponentKindPolicy } from './core/altium/PcbComponentKindPolicy.mjs'
31
37
  export { PcbComponentPrimitiveIndexer } from './core/altium/PcbComponentPrimitiveIndexer.mjs'
32
38
  export { PcbCustomPadShapeParser } from './core/altium/PcbCustomPadShapeParser.mjs'
33
39
  export { PcbDimensionParser } from './core/altium/PcbDimensionParser.mjs'
@@ -36,7 +42,11 @@ export { PcbEmbeddedModelExtractor } from './core/altium/PcbEmbeddedModelExtract
36
42
  export { PcbExtendedPrimitiveInformationParser } from './core/altium/PcbExtendedPrimitiveInformationParser.mjs'
37
43
  export { PcbFontMetricsParser } from './core/altium/PcbFontMetricsParser.mjs'
38
44
  export { PcbLayerIdCodec } from './core/altium/PcbLayerIdCodec.mjs'
45
+ export { PcbLayerStackFidelityReportBuilder } from './core/altium/PcbLayerStackFidelityReportBuilder.mjs'
46
+ export { PcbLayerStackInterchangeParser } from './core/altium/PcbLayerStackInterchangeParser.mjs'
47
+ export { PcbLayerStackQueryHelper } from './core/altium/PcbLayerStackQueryHelper.mjs'
39
48
  export { PcbLibModelParser } from './core/altium/PcbLibModelParser.mjs'
49
+ export { PcbLibParityReportBuilder } from './core/altium/PcbLibParityReportBuilder.mjs'
40
50
  export { PcbLibStreamExtractor } from './core/altium/PcbLibStreamExtractor.mjs'
41
51
  export { PcbMechanicalLayerPairParser } from './core/altium/PcbMechanicalLayerPairParser.mjs'
42
52
  export { PcbModelParser } from './core/altium/PcbModelParser.mjs'
@@ -44,8 +54,11 @@ export { PcbOutlineRasterizer } from './core/altium/PcbOutlineRasterizer.mjs'
44
54
  export { PcbOutlineRecovery } from './core/altium/PcbOutlineRecovery.mjs'
45
55
  export { PcbOwnershipGraphBuilder } from './core/altium/PcbOwnershipGraphBuilder.mjs'
46
56
  export { PcbPadStackParser } from './core/altium/PcbPadStackParser.mjs'
57
+ export { PcbPlacedFootprintManifestBuilder } from './core/altium/PcbPlacedFootprintManifestBuilder.mjs'
47
58
  export { PcbPickPlacePositionResolver } from './core/altium/PcbPickPlacePositionResolver.mjs'
59
+ export { PcbPolygonRecordParser } from './core/altium/PcbPolygonRecordParser.mjs'
48
60
  export { PcbRawRecordRegistry } from './core/altium/PcbRawRecordRegistry.mjs'
61
+ export { PcbReviewMetadataBuilder } from './core/altium/PcbReviewMetadataBuilder.mjs'
49
62
  export { PcbRouteAnalysisBuilder } from './core/altium/PcbRouteAnalysisBuilder.mjs'
50
63
  export { PcbRuleParser } from './core/altium/PcbRuleParser.mjs'
51
64
  export { PcbSidecarRecordParser } from './core/altium/PcbSidecarRecordParser.mjs'
@@ -57,6 +70,8 @@ export { PcbViaStackParser } from './core/altium/PcbViaStackParser.mjs'
57
70
  export { PcbViaStructureParser } from './core/altium/PcbViaStructureParser.mjs'
58
71
  export { PrintableTextDecoder } from './core/altium/PrintableTextDecoder.mjs'
59
72
  export { PrjPcbModelParser } from './core/altium/PrjPcbModelParser.mjs'
73
+ export { PrjScrModelParser } from './core/altium/PrjScrModelParser.mjs'
74
+ export { ProjectBomPnpReconciliationBuilder } from './core/altium/ProjectBomPnpReconciliationBuilder.mjs'
60
75
  export { SchematicMultipartOwnerMatcher } from './core/altium/SchematicMultipartOwnerMatcher.mjs'
61
76
  export { SchematicCrossSheetConnectorParser } from './core/altium/SchematicCrossSheetConnectorParser.mjs'
62
77
  export { SchematicHarnessParser } from './core/altium/SchematicHarnessParser.mjs'
@@ -141,9 +141,21 @@ export class PcbFootprintPrimitiveSelector {
141
141
  * @returns {boolean}
142
142
  */
143
143
  static #includesLayerName(layerName, needle) {
144
+ return PcbFootprintPrimitiveSelector.#compactLayerName(
145
+ layerName
146
+ ).includes(PcbFootprintPrimitiveSelector.#compactLayerName(needle))
147
+ }
148
+
149
+ /**
150
+ * Normalizes layer labels so compact names such as TopOverlay match
151
+ * spaced Altium labels such as Top Overlay.
152
+ * @param {string} layerName
153
+ * @returns {string}
154
+ */
155
+ static #compactLayerName(layerName) {
144
156
  return String(layerName || '')
145
157
  .trim()
146
158
  .toUpperCase()
147
- .includes(needle)
159
+ .replace(/[^A-Z0-9]/g, '')
148
160
  }
149
161
  }
@@ -986,16 +986,38 @@ export class PcbScene3dBuilder {
986
986
  return new Set(
987
987
  (Array.isArray(primitiveLayers) ? primitiveLayers : [])
988
988
  .filter((layer) =>
989
- String(layer?.name || '')
990
- .trim()
991
- .toUpperCase()
992
- .includes(needle)
989
+ PcbScene3dBuilder.#includesLayerName(layer?.name, needle)
993
990
  )
994
991
  .map((layer) => Number(layer.layerId))
995
992
  .filter((layerId) => Number.isInteger(layerId))
996
993
  )
997
994
  }
998
995
 
996
+ /**
997
+ * Returns true when one layer name matches a spaced or compact target.
998
+ * @param {string} layerName
999
+ * @param {string} needle
1000
+ * @returns {boolean}
1001
+ */
1002
+ static #includesLayerName(layerName, needle) {
1003
+ return PcbScene3dBuilder.#compactLayerName(layerName).includes(
1004
+ PcbScene3dBuilder.#compactLayerName(needle)
1005
+ )
1006
+ }
1007
+
1008
+ /**
1009
+ * Normalizes layer labels so compact names such as TopOverlay match
1010
+ * spaced Altium labels such as Top Overlay.
1011
+ * @param {string} layerName
1012
+ * @returns {string}
1013
+ */
1014
+ static #compactLayerName(layerName) {
1015
+ return String(layerName || '')
1016
+ .trim()
1017
+ .toUpperCase()
1018
+ .replace(/[^A-Z0-9]/g, '')
1019
+ }
1020
+
999
1021
  /**
1000
1022
  * Normalizes one Altium overlay text into the runtime stroke-text shape.
1001
1023
  * @param {{ text?: string, value?: string, x?: number, y?: number, height?: number, strokeWidth?: number, rotation?: number, mirrored?: boolean | number | string, isMirrored?: boolean | number | string, mirrorFlag?: boolean | number | string, Mirrored?: boolean | number | string, IsMirrored?: boolean | number | string, MirrorFlag?: boolean | number | string, layerId?: number }} text