circuit-json-to-tscircuit 0.0.96 → 0.0.98
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/dist/{chunk-ULPDKPX5.js → chunk-3EOKTYYU.js} +129 -17
- package/dist/cli/main.js +2 -2
- package/dist/lib/index.js +1 -1
- package/lib/board-conversion-context.ts +1 -1
- package/lib/board-conversion-types.ts +1 -1
- package/lib/board-converter/create-component-preserving-board-conversion-context.ts +5 -15
- package/lib/board-converter/get-internally-connected-source-port-ids.ts +29 -0
- package/lib/board-converter/get-pcb-port-ids-with-safe-original-hints.ts +82 -0
- package/lib/board-converter/get-pin-labels.ts +14 -1
- package/lib/board-converter/get-unambiguous-source-port-aliases.ts +35 -0
- package/lib/board-converter/merge-overlapping-source-port-groups.ts +22 -0
- package/lib/generate-footprint-tsx/convert-smt-pads.ts +3 -2
- package/lib/generate-footprint-tsx/get-imported-port-hints.ts +1 -6
- package/package.json +1 -1
- package/tests/__snapshots__/board-polygon-pad-placement-pcb.snap.svg +8 -0
- package/tests/__snapshots__/tmds62levm-polygon-pad-placement-comparison.snap.svg +8 -0
- package/tests/board-ambiguous-pad-aliases.test.ts +216 -0
- package/tests/board-declared-internal-pin-aliases.test.ts +154 -0
- package/tests/board-polygon-pad-placement.test.ts +172 -0
- package/tests/board-sk-am62-u29-pin-aliases.test.ts +65 -0
- package/tests/board-transitive-internal-pin-aliases.test.ts +128 -0
- package/tests/fixtures/sk-am62-u29-pin-aliases.circuit.json +97 -0
- package/tests/fixtures/ti-evms/README.md +7 -0
- package/tests/fixtures/ti-evms/tmds62levm-r348-polygon-pads.circuit.json +168 -0
- package/tests/merge-overlapping-source-port-groups.test.ts +60 -0
- package/tests/tmds62levm-polygon-pad-placement.test.ts +70 -0
|
@@ -168,7 +168,7 @@ var createBoardConversionContext = ({
|
|
|
168
168
|
}
|
|
169
169
|
return {
|
|
170
170
|
pcbChipName,
|
|
171
|
-
|
|
171
|
+
pcbPortIdsWithSafeOriginalHints: /* @__PURE__ */ new Set(),
|
|
172
172
|
portHintByPcbPortId,
|
|
173
173
|
runtimeNetNameBySourceNetId,
|
|
174
174
|
pcbPortSelectorsBySourcePortId,
|
|
@@ -218,6 +218,59 @@ var getRuntimeNetNamesBySourcePortId = ({
|
|
|
218
218
|
return result;
|
|
219
219
|
};
|
|
220
220
|
|
|
221
|
+
// lib/board-converter/get-pcb-port-ids-with-safe-original-hints.ts
|
|
222
|
+
function getPcbPortIdsWithSafeOriginalHints({
|
|
223
|
+
circuitJson,
|
|
224
|
+
pcbComponentRuntimeNameByPcbComponentId
|
|
225
|
+
}) {
|
|
226
|
+
const sourcePortById = /* @__PURE__ */ new Map();
|
|
227
|
+
const sourcePortsByComponentId = /* @__PURE__ */ new Map();
|
|
228
|
+
const originalHintSetsByPcbPortId = /* @__PURE__ */ new Map();
|
|
229
|
+
for (const element of circuitJson) {
|
|
230
|
+
if (element.type !== "source_port") continue;
|
|
231
|
+
sourcePortById.set(element.source_port_id, element);
|
|
232
|
+
if (!element.source_component_id) continue;
|
|
233
|
+
const componentPorts = sourcePortsByComponentId.get(element.source_component_id) ?? [];
|
|
234
|
+
componentPorts.push(element);
|
|
235
|
+
sourcePortsByComponentId.set(element.source_component_id, componentPorts);
|
|
236
|
+
}
|
|
237
|
+
for (const element of circuitJson) {
|
|
238
|
+
if (element.type !== "pcb_plated_hole" && element.type !== "pcb_smtpad" || !element.pcb_port_id || !element.port_hints) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const originalHintSets = originalHintSetsByPcbPortId.get(element.pcb_port_id) ?? [];
|
|
242
|
+
originalHintSets.push(element.port_hints);
|
|
243
|
+
originalHintSetsByPcbPortId.set(element.pcb_port_id, originalHintSets);
|
|
244
|
+
}
|
|
245
|
+
const safePcbPortIds = /* @__PURE__ */ new Set();
|
|
246
|
+
for (const element of circuitJson) {
|
|
247
|
+
if (element.type !== "pcb_port" || !element.pcb_component_id || !pcbComponentRuntimeNameByPcbComponentId.has(element.pcb_component_id)) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const sourcePort = sourcePortById.get(element.source_port_id);
|
|
251
|
+
const originalHintSets = originalHintSetsByPcbPortId.get(
|
|
252
|
+
element.pcb_port_id
|
|
253
|
+
);
|
|
254
|
+
if (!sourcePort?.source_component_id || !originalHintSets) continue;
|
|
255
|
+
const aliasesOnOtherPorts = /* @__PURE__ */ new Set();
|
|
256
|
+
for (const siblingPort of sourcePortsByComponentId.get(
|
|
257
|
+
sourcePort.source_component_id
|
|
258
|
+
) ?? []) {
|
|
259
|
+
if (siblingPort.source_port_id === sourcePort.source_port_id) continue;
|
|
260
|
+
aliasesOnOtherPorts.add(siblingPort.name);
|
|
261
|
+
for (const portHint of siblingPort.port_hints ?? []) {
|
|
262
|
+
aliasesOnOtherPorts.add(portHint);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (originalHintSets.every(
|
|
266
|
+
(originalHints) => originalHints.some((portHint) => /^(?:pin)?\d+$/u.test(portHint)) || originalHints.every((portHint) => !aliasesOnOtherPorts.has(portHint))
|
|
267
|
+
)) {
|
|
268
|
+
safePcbPortIds.add(element.pcb_port_id);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return safePcbPortIds;
|
|
272
|
+
}
|
|
273
|
+
|
|
221
274
|
// lib/board-converter/create-component-preserving-board-conversion-context.ts
|
|
222
275
|
function createComponentPreservingBoardConversionContext({
|
|
223
276
|
circuitJson,
|
|
@@ -232,15 +285,6 @@ function createComponentPreservingBoardConversionContext({
|
|
|
232
285
|
}
|
|
233
286
|
}
|
|
234
287
|
const pcbPortSelectorsBySourcePortId = /* @__PURE__ */ new Map();
|
|
235
|
-
const pcbPortIdsWithUnambiguousComponentSelectors = new Set(
|
|
236
|
-
circuitJson.flatMap((element) => {
|
|
237
|
-
if (element.type !== "pcb_port") return [];
|
|
238
|
-
const pcbComponent = element.pcb_component_id ? pcbComponentsById.get(element.pcb_component_id) : void 0;
|
|
239
|
-
return pcbComponent && pcbComponentRuntimeNameByPcbComponentId.has(
|
|
240
|
-
pcbComponent.pcb_component_id
|
|
241
|
-
) ? [element.pcb_port_id] : [];
|
|
242
|
-
})
|
|
243
|
-
);
|
|
244
288
|
for (const element of circuitJson) {
|
|
245
289
|
if (element.type !== "pcb_port") continue;
|
|
246
290
|
const pcbComponent = element.pcb_component_id ? pcbComponentsById.get(element.pcb_component_id) : void 0;
|
|
@@ -272,7 +316,10 @@ function createComponentPreservingBoardConversionContext({
|
|
|
272
316
|
}
|
|
273
317
|
return {
|
|
274
318
|
...context,
|
|
275
|
-
|
|
319
|
+
pcbPortIdsWithSafeOriginalHints: getPcbPortIdsWithSafeOriginalHints({
|
|
320
|
+
circuitJson,
|
|
321
|
+
pcbComponentRuntimeNameByPcbComponentId
|
|
322
|
+
}),
|
|
276
323
|
pcbPortSelectorsBySourcePortId,
|
|
277
324
|
pcbPortSelectorsByRuntimeNetName
|
|
278
325
|
};
|
|
@@ -3656,9 +3703,7 @@ var getImportedPortHints = (primitive, context) => {
|
|
|
3656
3703
|
if (!primitive.pcb_port_id || !context) return primitive.port_hints;
|
|
3657
3704
|
const importedHint = context.portHintByPcbPortId.get(primitive.pcb_port_id);
|
|
3658
3705
|
if (!importedHint) return primitive.port_hints;
|
|
3659
|
-
if (!context.
|
|
3660
|
-
primitive.pcb_port_id
|
|
3661
|
-
)) {
|
|
3706
|
+
if (!context.pcbPortIdsWithSafeOriginalHints.has(primitive.pcb_port_id)) {
|
|
3662
3707
|
return [importedHint];
|
|
3663
3708
|
}
|
|
3664
3709
|
return [.../* @__PURE__ */ new Set([importedHint, ...primitive.port_hints ?? []])];
|
|
@@ -3927,10 +3972,10 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
3927
3972
|
if (portHints !== void 0) {
|
|
3928
3973
|
commonAttrs.push(`portHints={${JSON.stringify(portHints)}}`);
|
|
3929
3974
|
}
|
|
3930
|
-
if ("x" in smtPad && smtPad.x !== void 0) {
|
|
3975
|
+
if (smtPad.shape !== "polygon" && "x" in smtPad && smtPad.x !== void 0) {
|
|
3931
3976
|
commonAttrs.push(`pcbX="${mmStr8(smtPad.x)}"`);
|
|
3932
3977
|
}
|
|
3933
|
-
if ("y" in smtPad && smtPad.y !== void 0) {
|
|
3978
|
+
if (smtPad.shape !== "polygon" && "y" in smtPad && smtPad.y !== void 0) {
|
|
3934
3979
|
commonAttrs.push(`pcbY="${mmStr8(smtPad.y)}"`);
|
|
3935
3980
|
}
|
|
3936
3981
|
if (smtPad.layer !== void 0) {
|
|
@@ -4034,6 +4079,65 @@ var getPcbComponentRenderPlacement = ({
|
|
|
4034
4079
|
};
|
|
4035
4080
|
};
|
|
4036
4081
|
|
|
4082
|
+
// lib/board-converter/merge-overlapping-source-port-groups.ts
|
|
4083
|
+
function mergeOverlappingSourcePortGroups(sourcePortGroups) {
|
|
4084
|
+
const groupBySourcePortId = /* @__PURE__ */ new Map();
|
|
4085
|
+
for (const sourcePortIds of sourcePortGroups) {
|
|
4086
|
+
const mergedGroup = new Set(sourcePortIds);
|
|
4087
|
+
for (const sourcePortId of sourcePortIds) {
|
|
4088
|
+
for (const connectedSourcePortId of groupBySourcePortId.get(
|
|
4089
|
+
sourcePortId
|
|
4090
|
+
) ?? []) {
|
|
4091
|
+
mergedGroup.add(connectedSourcePortId);
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
for (const sourcePortId of mergedGroup) {
|
|
4095
|
+
groupBySourcePortId.set(sourcePortId, mergedGroup);
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
return [...new Set(groupBySourcePortId.values())].map((group) => [...group]);
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
// lib/board-converter/get-internally-connected-source-port-ids.ts
|
|
4102
|
+
function getInternallyConnectedSourcePortIds({
|
|
4103
|
+
circuitJson,
|
|
4104
|
+
sourceComponent
|
|
4105
|
+
}) {
|
|
4106
|
+
const internallyConnectedSourcePortIds = [];
|
|
4107
|
+
if ("internally_connected_source_port_ids" in sourceComponent) {
|
|
4108
|
+
internallyConnectedSourcePortIds.push(
|
|
4109
|
+
...sourceComponent.internally_connected_source_port_ids ?? []
|
|
4110
|
+
);
|
|
4111
|
+
}
|
|
4112
|
+
for (const element of circuitJson) {
|
|
4113
|
+
if (element.type === "source_component_internal_connection" && element.source_component_id === sourceComponent.source_component_id) {
|
|
4114
|
+
internallyConnectedSourcePortIds.push(element.source_port_ids);
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
return mergeOverlappingSourcePortGroups(internallyConnectedSourcePortIds);
|
|
4118
|
+
}
|
|
4119
|
+
|
|
4120
|
+
// lib/board-converter/get-unambiguous-source-port-aliases.ts
|
|
4121
|
+
function getUnambiguousSourcePortAliases({
|
|
4122
|
+
sourcePort,
|
|
4123
|
+
sourcePorts,
|
|
4124
|
+
internallyConnectedSourcePortIds = []
|
|
4125
|
+
}) {
|
|
4126
|
+
return (sourcePort.port_hints ?? []).filter((alias) => {
|
|
4127
|
+
if (alias === sourcePort.name) return true;
|
|
4128
|
+
for (const canonicalPort of sourcePorts) {
|
|
4129
|
+
if (canonicalPort.name !== alias || canonicalPort.source_port_id === sourcePort.source_port_id) {
|
|
4130
|
+
continue;
|
|
4131
|
+
}
|
|
4132
|
+
const isDeclaredInternalConnection = internallyConnectedSourcePortIds.some(
|
|
4133
|
+
(group) => group.includes(sourcePort.source_port_id) && group.includes(canonicalPort.source_port_id)
|
|
4134
|
+
);
|
|
4135
|
+
if (!isDeclaredInternalConnection) return false;
|
|
4136
|
+
}
|
|
4137
|
+
return true;
|
|
4138
|
+
});
|
|
4139
|
+
}
|
|
4140
|
+
|
|
4037
4141
|
// lib/board-converter/get-pin-labels.ts
|
|
4038
4142
|
var getCompoundPinNumber = (sourcePort) => {
|
|
4039
4143
|
if (sourcePort.pin_number !== void 0) {
|
|
@@ -4071,9 +4175,17 @@ var getPinLabels = ({
|
|
|
4071
4175
|
const importedPortHint = footprintConversionContext.portHintByPcbPortId.get(element.pcb_port_id);
|
|
4072
4176
|
return importedPortHint ? [importedPortHint] : [];
|
|
4073
4177
|
});
|
|
4178
|
+
const sourceComponent = sourceComponents.find(
|
|
4179
|
+
(component) => component.source_component_id === sourcePort.source_component_id
|
|
4180
|
+
);
|
|
4181
|
+
const internallyConnectedSourcePortIds = sourceComponent ? getInternallyConnectedSourcePortIds({ circuitJson, sourceComponent }) : void 0;
|
|
4074
4182
|
const aliases = [
|
|
4075
4183
|
sourcePort.name,
|
|
4076
|
-
...
|
|
4184
|
+
...getUnambiguousSourcePortAliases({
|
|
4185
|
+
sourcePort,
|
|
4186
|
+
sourcePorts,
|
|
4187
|
+
internallyConnectedSourcePortIds
|
|
4188
|
+
}),
|
|
4077
4189
|
...importedPortHints
|
|
4078
4190
|
].filter(
|
|
4079
4191
|
(alias, aliasIndex, allAliases) => alias.length > 0 && allAliases.indexOf(alias) === aliasIndex
|
package/dist/cli/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
convertCircuitJsonToTscircuit
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-3EOKTYYU.js";
|
|
5
5
|
|
|
6
6
|
// cli/main.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -16,7 +16,7 @@ var package_default = {
|
|
|
16
16
|
"./cli": "./dist/cli/main.js"
|
|
17
17
|
},
|
|
18
18
|
type: "module",
|
|
19
|
-
version: "0.0.
|
|
19
|
+
version: "0.0.97",
|
|
20
20
|
repository: {
|
|
21
21
|
type: "git",
|
|
22
22
|
url: "https://github.com/tscircuit/circuit-json-to-tscircuit.git"
|
package/dist/lib/index.js
CHANGED
|
@@ -69,7 +69,7 @@ export const createBoardConversionContext = ({
|
|
|
69
69
|
|
|
70
70
|
return {
|
|
71
71
|
pcbChipName,
|
|
72
|
-
|
|
72
|
+
pcbPortIdsWithSafeOriginalHints: new Set<PcbPortId>(),
|
|
73
73
|
portHintByPcbPortId,
|
|
74
74
|
runtimeNetNameBySourceNetId,
|
|
75
75
|
pcbPortSelectorsBySourcePortId,
|
|
@@ -10,7 +10,7 @@ export type PcbPortSelector = string
|
|
|
10
10
|
|
|
11
11
|
export interface BoardConversionContext {
|
|
12
12
|
pcbChipName: string
|
|
13
|
-
|
|
13
|
+
pcbPortIdsWithSafeOriginalHints: Set<PcbPortId>
|
|
14
14
|
portHintByPcbPortId: Map<PcbPortId, ImportedPortHint>
|
|
15
15
|
runtimeNetNameBySourceNetId: Map<SourceNetId, RuntimeNetName>
|
|
16
16
|
pcbPortSelectorsBySourcePortId: Map<SourcePortId, PcbPortSelector[]>
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
SourcePortId,
|
|
10
10
|
} from "../board-conversion-types"
|
|
11
11
|
import type { PcbComponentRuntimeNameByPcbComponentId } from "./get-board-child-runtime-names"
|
|
12
|
+
import { getPcbPortIdsWithSafeOriginalHints } from "./get-pcb-port-ids-with-safe-original-hints"
|
|
12
13
|
|
|
13
14
|
type PcbComponentId = PcbComponent["pcb_component_id"]
|
|
14
15
|
export function createComponentPreservingBoardConversionContext({
|
|
@@ -32,20 +33,6 @@ export function createComponentPreservingBoardConversionContext({
|
|
|
32
33
|
SourcePortId,
|
|
33
34
|
PcbPortSelector[]
|
|
34
35
|
>()
|
|
35
|
-
const pcbPortIdsWithUnambiguousComponentSelectors = new Set(
|
|
36
|
-
circuitJson.flatMap((element) => {
|
|
37
|
-
if (element.type !== "pcb_port") return []
|
|
38
|
-
const pcbComponent = element.pcb_component_id
|
|
39
|
-
? pcbComponentsById.get(element.pcb_component_id)
|
|
40
|
-
: undefined
|
|
41
|
-
return pcbComponent &&
|
|
42
|
-
pcbComponentRuntimeNameByPcbComponentId.has(
|
|
43
|
-
pcbComponent.pcb_component_id,
|
|
44
|
-
)
|
|
45
|
-
? [element.pcb_port_id]
|
|
46
|
-
: []
|
|
47
|
-
}),
|
|
48
|
-
)
|
|
49
36
|
for (const element of circuitJson) {
|
|
50
37
|
if (element.type !== "pcb_port") continue
|
|
51
38
|
const pcbComponent = element.pcb_component_id
|
|
@@ -91,7 +78,10 @@ export function createComponentPreservingBoardConversionContext({
|
|
|
91
78
|
|
|
92
79
|
return {
|
|
93
80
|
...context,
|
|
94
|
-
|
|
81
|
+
pcbPortIdsWithSafeOriginalHints: getPcbPortIdsWithSafeOriginalHints({
|
|
82
|
+
circuitJson,
|
|
83
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
84
|
+
}),
|
|
95
85
|
pcbPortSelectorsBySourcePortId,
|
|
96
86
|
pcbPortSelectorsByRuntimeNetName,
|
|
97
87
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AnyCircuitElement } from "circuit-json"
|
|
2
|
+
import type { SourcePortId } from "../board-conversion-types"
|
|
3
|
+
import { mergeOverlappingSourcePortGroups } from "./merge-overlapping-source-port-groups"
|
|
4
|
+
|
|
5
|
+
type SourceComponent = Extract<AnyCircuitElement, { type: "source_component" }>
|
|
6
|
+
|
|
7
|
+
export function getInternallyConnectedSourcePortIds({
|
|
8
|
+
circuitJson,
|
|
9
|
+
sourceComponent,
|
|
10
|
+
}: {
|
|
11
|
+
circuitJson: AnyCircuitElement[]
|
|
12
|
+
sourceComponent: SourceComponent
|
|
13
|
+
}): SourcePortId[][] {
|
|
14
|
+
const internallyConnectedSourcePortIds: SourcePortId[][] = []
|
|
15
|
+
if ("internally_connected_source_port_ids" in sourceComponent) {
|
|
16
|
+
internallyConnectedSourcePortIds.push(
|
|
17
|
+
...(sourceComponent.internally_connected_source_port_ids ?? []),
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
for (const element of circuitJson) {
|
|
21
|
+
if (
|
|
22
|
+
element.type === "source_component_internal_connection" &&
|
|
23
|
+
element.source_component_id === sourceComponent.source_component_id
|
|
24
|
+
) {
|
|
25
|
+
internallyConnectedSourcePortIds.push(element.source_port_ids)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return mergeOverlappingSourcePortGroups(internallyConnectedSourcePortIds)
|
|
29
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { AnyCircuitElement } from "circuit-json"
|
|
2
|
+
import type { PcbPortId, SourcePortId } from "../board-conversion-types"
|
|
3
|
+
import type { PcbComponentRuntimeNameByPcbComponentId } from "./get-board-child-runtime-names"
|
|
4
|
+
|
|
5
|
+
type PortHint = string
|
|
6
|
+
type SourceComponentId = string
|
|
7
|
+
type SourcePort = Extract<AnyCircuitElement, { type: "source_port" }>
|
|
8
|
+
|
|
9
|
+
export function getPcbPortIdsWithSafeOriginalHints({
|
|
10
|
+
circuitJson,
|
|
11
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
12
|
+
}: {
|
|
13
|
+
circuitJson: AnyCircuitElement[]
|
|
14
|
+
pcbComponentRuntimeNameByPcbComponentId: PcbComponentRuntimeNameByPcbComponentId
|
|
15
|
+
}): Set<PcbPortId> {
|
|
16
|
+
const sourcePortById = new Map<SourcePortId, SourcePort>()
|
|
17
|
+
const sourcePortsByComponentId = new Map<SourceComponentId, SourcePort[]>()
|
|
18
|
+
const originalHintSetsByPcbPortId = new Map<PcbPortId, PortHint[][]>()
|
|
19
|
+
|
|
20
|
+
for (const element of circuitJson) {
|
|
21
|
+
if (element.type !== "source_port") continue
|
|
22
|
+
sourcePortById.set(element.source_port_id, element)
|
|
23
|
+
if (!element.source_component_id) continue
|
|
24
|
+
const componentPorts =
|
|
25
|
+
sourcePortsByComponentId.get(element.source_component_id) ?? []
|
|
26
|
+
componentPorts.push(element)
|
|
27
|
+
sourcePortsByComponentId.set(element.source_component_id, componentPorts)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const element of circuitJson) {
|
|
31
|
+
if (
|
|
32
|
+
(element.type !== "pcb_plated_hole" && element.type !== "pcb_smtpad") ||
|
|
33
|
+
!element.pcb_port_id ||
|
|
34
|
+
!element.port_hints
|
|
35
|
+
) {
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
const originalHintSets =
|
|
39
|
+
originalHintSetsByPcbPortId.get(element.pcb_port_id) ?? []
|
|
40
|
+
originalHintSets.push(element.port_hints)
|
|
41
|
+
originalHintSetsByPcbPortId.set(element.pcb_port_id, originalHintSets)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const safePcbPortIds = new Set<PcbPortId>()
|
|
45
|
+
for (const element of circuitJson) {
|
|
46
|
+
if (
|
|
47
|
+
element.type !== "pcb_port" ||
|
|
48
|
+
!element.pcb_component_id ||
|
|
49
|
+
!pcbComponentRuntimeNameByPcbComponentId.has(element.pcb_component_id)
|
|
50
|
+
) {
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
const sourcePort = sourcePortById.get(element.source_port_id)
|
|
54
|
+
const originalHintSets = originalHintSetsByPcbPortId.get(
|
|
55
|
+
element.pcb_port_id,
|
|
56
|
+
)
|
|
57
|
+
if (!sourcePort?.source_component_id || !originalHintSets) continue
|
|
58
|
+
|
|
59
|
+
const aliasesOnOtherPorts = new Set<PortHint>()
|
|
60
|
+
for (const siblingPort of sourcePortsByComponentId.get(
|
|
61
|
+
sourcePort.source_component_id,
|
|
62
|
+
) ?? []) {
|
|
63
|
+
if (siblingPort.source_port_id === sourcePort.source_port_id) continue
|
|
64
|
+
aliasesOnOtherPorts.add(siblingPort.name)
|
|
65
|
+
for (const portHint of siblingPort.port_hints ?? []) {
|
|
66
|
+
aliasesOnOtherPorts.add(portHint)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// A numbered hint only disambiguates the primitive carrying it.
|
|
70
|
+
if (
|
|
71
|
+
originalHintSets.every(
|
|
72
|
+
(originalHints) =>
|
|
73
|
+
originalHints.some((portHint) => /^(?:pin)?\d+$/u.test(portHint)) ||
|
|
74
|
+
originalHints.every((portHint) => !aliasesOnOtherPorts.has(portHint)),
|
|
75
|
+
)
|
|
76
|
+
) {
|
|
77
|
+
safePcbPortIds.add(element.pcb_port_id)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return safePcbPortIds
|
|
82
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AnyCircuitElement, PcbComponent } from "circuit-json"
|
|
2
2
|
import type { BoardConversionContext as FootprintConversionContext } from "../board-conversion-context"
|
|
3
|
+
import { getInternallyConnectedSourcePortIds } from "./get-internally-connected-source-port-ids"
|
|
4
|
+
import { getUnambiguousSourcePortAliases } from "./get-unambiguous-source-port-aliases"
|
|
3
5
|
|
|
4
6
|
type PinLabelKey = `pin${number}`
|
|
5
7
|
type PinLabels = Partial<Record<PinLabelKey, string[]>>
|
|
@@ -71,9 +73,20 @@ export const getPinLabels = ({
|
|
|
71
73
|
footprintConversionContext.portHintByPcbPortId.get(element.pcb_port_id)
|
|
72
74
|
return importedPortHint ? [importedPortHint] : []
|
|
73
75
|
})
|
|
76
|
+
const sourceComponent = sourceComponents.find(
|
|
77
|
+
(component) =>
|
|
78
|
+
component.source_component_id === sourcePort.source_component_id,
|
|
79
|
+
)
|
|
80
|
+
const internallyConnectedSourcePortIds = sourceComponent
|
|
81
|
+
? getInternallyConnectedSourcePortIds({ circuitJson, sourceComponent })
|
|
82
|
+
: undefined
|
|
74
83
|
const aliases = [
|
|
75
84
|
sourcePort.name,
|
|
76
|
-
...(
|
|
85
|
+
...getUnambiguousSourcePortAliases({
|
|
86
|
+
sourcePort,
|
|
87
|
+
sourcePorts,
|
|
88
|
+
internallyConnectedSourcePortIds,
|
|
89
|
+
}),
|
|
77
90
|
...importedPortHints,
|
|
78
91
|
].filter(
|
|
79
92
|
(alias, aliasIndex, allAliases) =>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AnyCircuitElement } from "circuit-json"
|
|
2
|
+
import type { SourcePortId } from "../board-conversion-types"
|
|
3
|
+
|
|
4
|
+
type SourcePort = Extract<AnyCircuitElement, { type: "source_port" }>
|
|
5
|
+
|
|
6
|
+
export function getUnambiguousSourcePortAliases({
|
|
7
|
+
sourcePort,
|
|
8
|
+
sourcePorts,
|
|
9
|
+
internallyConnectedSourcePortIds = [],
|
|
10
|
+
}: {
|
|
11
|
+
sourcePort: SourcePort
|
|
12
|
+
sourcePorts: SourcePort[]
|
|
13
|
+
internallyConnectedSourcePortIds?: SourcePortId[][]
|
|
14
|
+
}): string[] {
|
|
15
|
+
return (sourcePort.port_hints ?? []).filter((alias) => {
|
|
16
|
+
if (alias === sourcePort.name) return true
|
|
17
|
+
|
|
18
|
+
for (const canonicalPort of sourcePorts) {
|
|
19
|
+
if (
|
|
20
|
+
canonicalPort.name !== alias ||
|
|
21
|
+
canonicalPort.source_port_id === sourcePort.source_port_id
|
|
22
|
+
) {
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
const isDeclaredInternalConnection =
|
|
26
|
+
internallyConnectedSourcePortIds.some(
|
|
27
|
+
(group) =>
|
|
28
|
+
group.includes(sourcePort.source_port_id) &&
|
|
29
|
+
group.includes(canonicalPort.source_port_id),
|
|
30
|
+
)
|
|
31
|
+
if (!isDeclaredInternalConnection) return false
|
|
32
|
+
}
|
|
33
|
+
return true
|
|
34
|
+
})
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SourcePortId } from "../board-conversion-types"
|
|
2
|
+
|
|
3
|
+
export function mergeOverlappingSourcePortGroups(
|
|
4
|
+
sourcePortGroups: readonly (readonly SourcePortId[])[],
|
|
5
|
+
): SourcePortId[][] {
|
|
6
|
+
const groupBySourcePortId = new Map<SourcePortId, Set<SourcePortId>>()
|
|
7
|
+
for (const sourcePortIds of sourcePortGroups) {
|
|
8
|
+
const mergedGroup = new Set<SourcePortId>(sourcePortIds)
|
|
9
|
+
for (const sourcePortId of sourcePortIds) {
|
|
10
|
+
for (const connectedSourcePortId of groupBySourcePortId.get(
|
|
11
|
+
sourcePortId,
|
|
12
|
+
) ?? []) {
|
|
13
|
+
mergedGroup.add(connectedSourcePortId)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Later declarations must see the whole group through any of its members.
|
|
17
|
+
for (const sourcePortId of mergedGroup) {
|
|
18
|
+
groupBySourcePortId.set(sourcePortId, mergedGroup)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return [...new Set(groupBySourcePortId.values())].map((group) => [...group])
|
|
22
|
+
}
|
|
@@ -21,10 +21,11 @@ export const convertSmtPads: FootprintElementConverter = (
|
|
|
21
21
|
if (portHints !== undefined) {
|
|
22
22
|
commonAttrs.push(`portHints={${JSON.stringify(portHints)}}`)
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
// Polygon vertices already carry their position in the footprint frame.
|
|
25
|
+
if (smtPad.shape !== "polygon" && "x" in smtPad && smtPad.x !== undefined) {
|
|
25
26
|
commonAttrs.push(`pcbX="${mmStr(smtPad.x)}"`)
|
|
26
27
|
}
|
|
27
|
-
if ("y" in smtPad && smtPad.y !== undefined) {
|
|
28
|
+
if (smtPad.shape !== "polygon" && "y" in smtPad && smtPad.y !== undefined) {
|
|
28
29
|
commonAttrs.push(`pcbY="${mmStr(smtPad.y)}"`)
|
|
29
30
|
}
|
|
30
31
|
if (smtPad.layer !== undefined) {
|
|
@@ -8,13 +8,8 @@ export const getImportedPortHints = (
|
|
|
8
8
|
if (!primitive.pcb_port_id || !context) return primitive.port_hints
|
|
9
9
|
const importedHint = context.portHintByPcbPortId.get(primitive.pcb_port_id)
|
|
10
10
|
if (!importedHint) return primitive.port_hints
|
|
11
|
-
if (
|
|
12
|
-
!context.pcbPortIdsWithUnambiguousComponentSelectors.has(
|
|
13
|
-
primitive.pcb_port_id,
|
|
14
|
-
)
|
|
15
|
-
) {
|
|
11
|
+
if (!context.pcbPortIdsWithSafeOriginalHints.has(primitive.pcb_port_id)) {
|
|
16
12
|
return [importedHint]
|
|
17
13
|
}
|
|
18
|
-
|
|
19
14
|
return [...new Set([importedHint, ...(primitive.port_hints ?? [])])]
|
|
20
15
|
}
|