circuitjson-toolkit 1.0.16 → 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 (155) hide show
  1. package/AGENTS.md +15 -0
  2. package/NOTICE.md +31 -0
  3. package/README.md +267 -107
  4. package/docs/api.md +501 -96
  5. package/docs/capabilities.md +70 -0
  6. package/docs/migration/behaviors.md +45 -0
  7. package/docs/migration/parser.md +60 -0
  8. package/docs/migration/renderers.md +515 -0
  9. package/docs/migration/root.md +740 -0
  10. package/docs/migration.md +120 -0
  11. package/docs/model-format.md +175 -57
  12. package/docs/provenance.md +206 -0
  13. package/docs/release-notes-v1.1.0.md +154 -0
  14. package/docs/testing.md +117 -7
  15. package/package.json +31 -5
  16. package/spec/api-baseline-v1.0.17.json +1 -0
  17. package/spec/baseline-provenance-v1.0.17.json +7 -0
  18. package/spec/circuitjson-schema-snapshot.json +321 -0
  19. package/spec/circuitjson-schema-source.json +28 -0
  20. package/spec/feature-preservation.json +1 -0
  21. package/spec/library-scope.md +27 -20
  22. package/src/capabilities.mjs +1 -0
  23. package/src/core/ArchiveEntryPath.mjs +93 -0
  24. package/src/core/ArchiveLimits.mjs +31 -0
  25. package/src/core/ArchiveLimitsValidator.mjs +107 -0
  26. package/src/core/AsyncInputOwnership.mjs +56 -0
  27. package/src/core/AttachedValueLimits.mjs +67 -0
  28. package/src/core/CircuitJsonDiagnosticIndexer.mjs +184 -0
  29. package/src/core/CircuitJsonDocument.mjs +19 -61
  30. package/src/core/CircuitJsonElementTypes.mjs +10 -0
  31. package/src/core/CircuitJsonElementValidator.mjs +98 -847
  32. package/src/core/CircuitJsonIndexer.mjs +274 -194
  33. package/src/core/CircuitJsonManufacturingBuilder.mjs +167 -164
  34. package/src/core/CircuitJsonParser.mjs +75 -13
  35. package/src/core/CircuitJsonPcbClearanceDiagnostics.mjs +12 -6
  36. package/src/core/CircuitJsonPcbHolePrimitiveModel.mjs +108 -10
  37. package/src/core/CircuitJsonPcbPadPrimitiveModel.mjs +1 -1
  38. package/src/core/CircuitJsonPcbPrimitiveArtwork.mjs +44 -38
  39. package/src/core/CircuitJsonPcbPrimitiveBuilder.mjs +146 -28
  40. package/src/core/CircuitJsonPcbPrimitiveFields.mjs +70 -4
  41. package/src/core/CircuitJsonPcbPrimitiveIndex.mjs +18 -2
  42. package/src/core/CircuitJsonPcbPrimitiveOverlays.mjs +26 -9
  43. package/src/core/CircuitJsonPcbZonePrimitiveBuilder.mjs +7 -6
  44. package/src/core/CircuitJsonSerializedInputAudit.mjs +87 -0
  45. package/src/core/CircuitJsonSourceMetadata.mjs +5 -1
  46. package/src/core/CircuitJsonSupportMatrixBuilder.mjs +3 -1
  47. package/src/core/CircuitJsonToolkitElementSchema.mjs +218 -0
  48. package/src/core/CircuitJsonUnitParsers.mjs +101 -0
  49. package/src/core/CircuitJsonUnits.mjs +13 -87
  50. package/src/core/CircuitJsonUpstreamSchema.mjs +9 -0
  51. package/src/core/CircuitJsonUpstreamValidator.mjs +418 -0
  52. package/src/core/CircuitJsonValidationUnits.mjs +6 -0
  53. package/src/core/ManufacturingService.mjs +323 -0
  54. package/src/core/Parser.mjs +343 -0
  55. package/src/core/ParserOptions.mjs +333 -0
  56. package/src/core/PcbBoundsSelectionModel.mjs +55 -19
  57. package/src/core/PcbDiagnosticFocusModel.mjs +42 -11
  58. package/src/core/PcbInteractionIndex.mjs +368 -0
  59. package/src/core/PcbInteractionPrimitiveModel.mjs +393 -62
  60. package/src/core/ProjectAsyncInputOwner.mjs +70 -0
  61. package/src/core/ProjectLoader.mjs +975 -0
  62. package/src/core/SimulationService.mjs +790 -0
  63. package/src/core/ToolkitCapabilities.mjs +130 -0
  64. package/src/core/ZipArchiveInspector.mjs +649 -0
  65. package/src/core/context/BinaryDataSnapshot.mjs +217 -0
  66. package/src/core/context/CircuitJsonContextIndexes.mjs +96 -0
  67. package/src/core/context/CircuitJsonDerivedCache.mjs +114 -0
  68. package/src/core/context/CircuitJsonDocumentContext.mjs +353 -0
  69. package/src/core/context/CircuitJsonLegacyModel.mjs +147 -0
  70. package/src/core/context/CircuitJsonLegacyNormalizer.mjs +847 -0
  71. package/src/core/context/CircuitJsonMetadataBoundary.mjs +76 -0
  72. package/src/core/context/CircuitJsonModelFreezeTraversal.mjs +179 -0
  73. package/src/core/context/CircuitJsonReadOnlyDocument.mjs +920 -0
  74. package/src/core/context/CircuitJsonSchematicTableNormalizer.mjs +314 -0
  75. package/src/core/context/CircuitJsonValidationAuthority.mjs +39 -0
  76. package/src/core/context/CircuitJsonValidationProof.mjs +217 -0
  77. package/src/core/context/PcbPrimitivePreparation.mjs +198 -0
  78. package/src/core/context/PcbSpatialIndex.mjs +701 -0
  79. package/src/core/context/ProtectedExtensionBinaryBoundary.mjs +128 -0
  80. package/src/core/context/StructuredDataSnapshot.mjs +683 -0
  81. package/src/core/contracts/DocumentResult.mjs +198 -0
  82. package/src/core/contracts/ProjectResult.mjs +96 -0
  83. package/src/core/contracts/RuntimeProxyBoundary.mjs +48 -0
  84. package/src/core/contracts/ToolkitAsset.mjs +493 -0
  85. package/src/core/contracts/ToolkitDiagnostic.mjs +38 -0
  86. package/src/core/contracts/ToolkitError.mjs +176 -0
  87. package/src/core/contracts/ToolkitProgress.mjs +89 -0
  88. package/src/core/interaction/CanonicalInteractionOptions.mjs +246 -0
  89. package/src/core/interaction/PcbInteractionBounds.mjs +167 -0
  90. package/src/core/query/CircuitTraversal.mjs +343 -0
  91. package/src/core/query/ComponentGrouping.mjs +275 -0
  92. package/src/core/query/QueryNetlistBuilder.mjs +306 -0
  93. package/src/core/query/QueryService.mjs +435 -0
  94. package/src/core/query/RegexPattern.mjs +75 -0
  95. package/src/core/rendering/CanonicalBomOrder.mjs +81 -0
  96. package/src/core/rendering/CanonicalBomRows.mjs +92 -0
  97. package/src/core/rendering/CanonicalRenderOptions.mjs +498 -0
  98. package/src/core/rendering/CanonicalSvgDocument.mjs +102 -0
  99. package/src/core/rendering/PcbRenderPlan.mjs +429 -0
  100. package/src/core/rendering/SchematicSheetSelector.mjs +335 -0
  101. package/src/core/scene3d/PcbScene3dBuilder.mjs +906 -0
  102. package/src/core/scene3d/PcbScene3dPreparator.mjs +47 -0
  103. package/src/core/scene3d/Scene3dAssetIndex.mjs +284 -0
  104. package/src/core/scene3d/Scene3dBoardModel.mjs +596 -0
  105. package/src/core/scene3d/Scene3dDocumentMetadata.mjs +167 -0
  106. package/src/core/scene3d/Scene3dFreeze.mjs +37 -0
  107. package/src/core/scene3d/Scene3dIdRegistry.mjs +34 -0
  108. package/src/core/scene3d/Scene3dInputPreflight.mjs +193 -0
  109. package/src/core/scene3d/Scene3dMaterials.mjs +58 -0
  110. package/src/core/scene3d/Scene3dModelReference.mjs +134 -0
  111. package/src/core/scene3d/Scene3dOptions.mjs +363 -0
  112. package/src/core/scene3d/SceneAssetResolver.mjs +441 -0
  113. package/src/core/simulation/SimulationParameterCloner.mjs +543 -0
  114. package/src/core/worker/ParserWorkerClient.mjs +997 -0
  115. package/src/core/worker/ToolkitWorkerProtocol.mjs +412 -0
  116. package/src/core/worker/WorkerRequestData.mjs +623 -0
  117. package/src/core/worker/WorkerResponseData.mjs +905 -0
  118. package/src/extensions.mjs +37 -0
  119. package/src/index.mjs +14 -9
  120. package/src/interaction.mjs +2 -0
  121. package/src/manufacturing.mjs +1 -0
  122. package/src/parser.mjs +12 -2
  123. package/src/project.mjs +5 -0
  124. package/src/query.mjs +1 -0
  125. package/src/renderers.mjs +3 -29
  126. package/src/scene3d.mjs +3 -0
  127. package/src/simulation.mjs +1 -0
  128. package/src/styles/renderers.css +24 -0
  129. package/src/testing/ToolkitContractFixtures.mjs +124 -0
  130. package/src/testing/ToolkitLoopbackWorker.mjs +174 -0
  131. package/src/testing/runToolkitContract.mjs +705 -0
  132. package/src/testing.mjs +3 -0
  133. package/src/ui/BomTableRenderer.mjs +304 -0
  134. package/src/ui/CircuitJsonPcbBoardSvgRenderer.mjs +80 -0
  135. package/src/ui/CircuitJsonPcbPrimitiveAttributeRenderer.mjs +3 -5
  136. package/src/ui/CircuitJsonPcbSvgRenderer.mjs +63 -43
  137. package/src/ui/CircuitJsonPcbViaSvgRenderer.mjs +3 -5
  138. package/src/ui/CircuitJsonSchematicDebugRenderer.mjs +164 -0
  139. package/src/ui/CircuitJsonSchematicImageSvgRenderer.mjs +210 -0
  140. package/src/ui/CircuitJsonSchematicLineRenderer.mjs +86 -0
  141. package/src/ui/CircuitJsonSchematicSheetSymbolSvgRenderer.mjs +98 -0
  142. package/src/ui/CircuitJsonSchematicSvgArcPath.mjs +117 -17
  143. package/src/ui/CircuitJsonSchematicSvgPortMetadata.mjs +67 -20
  144. package/src/ui/CircuitJsonSchematicSvgPrimitiveAttributes.mjs +45 -9
  145. package/src/ui/CircuitJsonSchematicSvgRenderer.mjs +151 -148
  146. package/src/ui/CircuitJsonSchematicTableSvgRenderer.mjs +4 -292
  147. package/src/ui/PcbSvgRenderer.mjs +41 -0
  148. package/src/ui/SafeSvgPaint.mjs +26 -0
  149. package/src/ui/SafeXmlText.mjs +60 -0
  150. package/src/ui/SchematicGeometryBounds.mjs +540 -0
  151. package/src/ui/SchematicSvgRenderer.mjs +110 -0
  152. package/src/ui/SchematicTableGeometry.mjs +319 -0
  153. package/src/ui/SchematicTextAnchor.mjs +55 -0
  154. package/src/ui/SchematicTextBounds.mjs +98 -0
  155. package/src/workers/parser.worker.mjs +59 -0
@@ -0,0 +1,198 @@
1
+ import { CircuitJsonPcbPrimitiveBuilder } from '../CircuitJsonPcbPrimitiveBuilder.mjs'
2
+ import { ToolkitError } from '../contracts/ToolkitError.mjs'
3
+ import { PcbSpatialIndex } from './PcbSpatialIndex.mjs'
4
+
5
+ const INTERACTION_CACHE = Object.freeze({
6
+ namespace: 'pcb',
7
+ key: 'interaction-primitives-v1'
8
+ })
9
+ const COMPLETE_CACHE = Object.freeze({
10
+ namespace: 'render',
11
+ key: 'pcb-primitives-v1'
12
+ })
13
+ const SPATIAL_CACHE = Object.freeze({
14
+ namespace: 'interaction',
15
+ key: 'pcb-spatial-v2'
16
+ })
17
+ const INTERACTION_OWNERS = new WeakMap()
18
+ const COMPLETE_OWNERS = new WeakMap()
19
+ const SPATIAL_OWNERS = new WeakMap()
20
+
21
+ /**
22
+ * Owns immutable PCB primitive preparations shared by interaction and render
23
+ * consumers without trusting namespace strings as type brands.
24
+ */
25
+ export class PcbPrimitivePreparation {
26
+ /**
27
+ * Returns the immutable interaction-only primitive model for one context.
28
+ * @param {import('./CircuitJsonDocumentContext.mjs').CircuitJsonDocumentContext} context Prepared context.
29
+ * @returns {Record<string, any>} Context-owned primitive model.
30
+ */
31
+ static prepareInteraction(context) {
32
+ const value = context.getOrCreateDerived(
33
+ INTERACTION_CACHE.namespace,
34
+ INTERACTION_CACHE.key,
35
+ () => {
36
+ const model = CircuitJsonPcbPrimitiveBuilder.buildInteraction(
37
+ context.model
38
+ )
39
+ PcbPrimitivePreparation.#freeze(model)
40
+ INTERACTION_OWNERS.set(model, {
41
+ context,
42
+ key: INTERACTION_CACHE
43
+ })
44
+ return model
45
+ }
46
+ )
47
+ return PcbPrimitivePreparation.#requireOwned(
48
+ context,
49
+ INTERACTION_CACHE,
50
+ INTERACTION_OWNERS,
51
+ value
52
+ )
53
+ }
54
+
55
+ /**
56
+ * Returns the immutable complete primitive model shared with render plans.
57
+ * @param {import('./CircuitJsonDocumentContext.mjs').CircuitJsonDocumentContext} context Prepared context.
58
+ * @returns {Record<string, any>} Context-owned complete primitive model.
59
+ */
60
+ static prepareComplete(context) {
61
+ const value = context.getOrCreateDerived(
62
+ COMPLETE_CACHE.namespace,
63
+ COMPLETE_CACHE.key,
64
+ () => {
65
+ const model = CircuitJsonPcbPrimitiveBuilder.buildComplete(
66
+ context.model,
67
+ PcbPrimitivePreparation.prepareInteraction(context)
68
+ )
69
+ PcbPrimitivePreparation.#freeze(model)
70
+ COMPLETE_OWNERS.set(model, {
71
+ context,
72
+ key: COMPLETE_CACHE
73
+ })
74
+ return model
75
+ }
76
+ )
77
+ return PcbPrimitivePreparation.#requireOwned(
78
+ context,
79
+ COMPLETE_CACHE,
80
+ COMPLETE_OWNERS,
81
+ value
82
+ )
83
+ }
84
+
85
+ /**
86
+ * Returns the immutable spatial index bound to one exact primitive model.
87
+ * @param {import('./CircuitJsonDocumentContext.mjs').CircuitJsonDocumentContext} context Prepared context.
88
+ * @param {Record<string, any>} model Owned interaction primitive model.
89
+ * @param {() => object[]} recordsFactory Stable spatial-record factory.
90
+ * @returns {PcbSpatialIndex} Context-owned spatial index.
91
+ */
92
+ static prepareSpatial(context, model, recordsFactory) {
93
+ PcbPrimitivePreparation.#requireOwned(
94
+ context,
95
+ INTERACTION_CACHE,
96
+ INTERACTION_OWNERS,
97
+ model
98
+ )
99
+ const value = context.getOrCreateDerived(
100
+ SPATIAL_CACHE.namespace,
101
+ SPATIAL_CACHE.key,
102
+ () => {
103
+ const spatial = PcbSpatialIndex.create(recordsFactory())
104
+ SPATIAL_OWNERS.set(spatial, {
105
+ context,
106
+ key: SPATIAL_CACHE,
107
+ model
108
+ })
109
+ return spatial
110
+ }
111
+ )
112
+ const spatial = PcbPrimitivePreparation.#requireOwned(
113
+ context,
114
+ SPATIAL_CACHE,
115
+ SPATIAL_OWNERS,
116
+ value
117
+ )
118
+ if (SPATIAL_OWNERS.get(spatial).model !== model) {
119
+ throw PcbPrimitivePreparation.#collisionError()
120
+ }
121
+ return spatial
122
+ }
123
+
124
+ /**
125
+ * Requires both the private type brand and exact context cache ownership.
126
+ * @param {import('./CircuitJsonDocumentContext.mjs').CircuitJsonDocumentContext} context Prepared context.
127
+ * @param {{ namespace: string, key: string }} key Expected cache key.
128
+ * @param {WeakMap<object, object>} owners Type-specific ownership map.
129
+ * @param {unknown} value Cache value candidate.
130
+ * @returns {any} Verified value.
131
+ */
132
+ static #requireOwned(context, key, owners, value) {
133
+ const owner =
134
+ value && typeof value === 'object' ? owners.get(value) : null
135
+ if (
136
+ owner?.context !== context ||
137
+ owner.key !== key ||
138
+ !context.ownsDerived(key.namespace, key.key, value) ||
139
+ !Object.isFrozen(value)
140
+ ) {
141
+ throw PcbPrimitivePreparation.#collisionError()
142
+ }
143
+ return value
144
+ }
145
+
146
+ /**
147
+ * Deep-freezes a cyclic plain primitive graph before caching it.
148
+ * @param {unknown} value Root cache value.
149
+ * @returns {unknown} Frozen root value.
150
+ */
151
+ static #freeze(value) {
152
+ if (!value || typeof value !== 'object') return value
153
+ const pending = [{ value, expanded: false }]
154
+ const visited = new WeakSet()
155
+ while (pending.length) {
156
+ const current = pending.pop()
157
+ if (current.expanded) {
158
+ Object.freeze(current.value)
159
+ continue
160
+ }
161
+ if (visited.has(current.value) || Object.isFrozen(current.value)) {
162
+ continue
163
+ }
164
+ visited.add(current.value)
165
+ pending.push({ value: current.value, expanded: true })
166
+ for (const descriptor of Object.values(
167
+ Object.getOwnPropertyDescriptors(current.value)
168
+ )) {
169
+ if (
170
+ Object.hasOwn(descriptor, 'value') &&
171
+ descriptor.value &&
172
+ typeof descriptor.value === 'object'
173
+ ) {
174
+ pending.push({
175
+ value: descriptor.value,
176
+ expanded: false
177
+ })
178
+ }
179
+ }
180
+ }
181
+ return value
182
+ }
183
+
184
+ /**
185
+ * Creates a typed cache collision or transplant error.
186
+ * @returns {ToolkitError} Typed interaction cache error.
187
+ */
188
+ static #collisionError() {
189
+ return new ToolkitError(
190
+ 'Prepared PCB interaction encountered a cache collision or transplant.',
191
+ {
192
+ code: 'ERR_INTERACTION_CACHE_COLLISION',
193
+ category: 'runtime',
194
+ format: 'circuitjson'
195
+ }
196
+ )
197
+ }
198
+ }