circuit-json-to-tscircuit 0.0.75 → 0.0.76
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-A65QMTEY.js → chunk-NQTXLCEN.js} +17 -0
- package/dist/cli/main.js +2 -2
- package/dist/lib/index.js +1 -1
- package/lib/generate-board-schematic-tsx/convert-net-labels.ts +34 -0
- package/package.json +1 -1
- package/tests/board-net-label-name-validation.test.ts +86 -0
- package/tests/board-plain-net-label-anchor.test.ts +82 -0
- package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip-schematic-comparison.snap.svg +44 -2
- package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip.test.tsx.snap +6 -6
- package/tests/ti-lm251772-plain-net-labels.test.ts +47 -0
|
@@ -827,6 +827,13 @@ import { su as su4 } from "@tscircuit/soup-util";
|
|
|
827
827
|
import { schematic_text as schematic_text3 } from "circuit-json";
|
|
828
828
|
import { symbols as symbols2 } from "schematic-symbols";
|
|
829
829
|
import { translate as translate3 } from "transformation-matrix";
|
|
830
|
+
function canRenderNativeNetLabel(name) {
|
|
831
|
+
const selector = `net.${name}`;
|
|
832
|
+
if (/net\.[^\s>]*\./.test(selector) || /net\.[^\s>]*[+-]/.test(selector) || /net\.[0-9]/.test(selector)) {
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
return /^\/?[A-Za-z0-9_]+$/.test(name);
|
|
836
|
+
}
|
|
830
837
|
var convertNetLabels = (circuitJson) => su4(circuitJson).schematic_net_label.list().flatMap((schematicNetLabel) => {
|
|
831
838
|
const anchorPosition = schematicNetLabel.anchor_position ?? schematicNetLabel.center;
|
|
832
839
|
const symbolName = schematicNetLabel.symbol_name;
|
|
@@ -843,6 +850,16 @@ var convertNetLabels = (circuitJson) => su4(circuitJson).schematic_net_label.lis
|
|
|
843
850
|
displayText: schematicNetLabel.text
|
|
844
851
|
});
|
|
845
852
|
}
|
|
853
|
+
if (!symbolName && schematicNetLabel.anchor_position && canRenderNativeNetLabel(schematicNetLabel.text)) {
|
|
854
|
+
return [
|
|
855
|
+
formatElement("netlabel", {
|
|
856
|
+
net: schematicNetLabel.text,
|
|
857
|
+
schX: anchorPosition.x,
|
|
858
|
+
schY: anchorPosition.y,
|
|
859
|
+
anchorSide: schematicNetLabel.anchor_side
|
|
860
|
+
})
|
|
861
|
+
];
|
|
862
|
+
}
|
|
846
863
|
return [
|
|
847
864
|
formatElement("schematictext", {
|
|
848
865
|
text: schematicNetLabel.text,
|
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-NQTXLCEN.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.75",
|
|
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
|
@@ -6,6 +6,23 @@ import type { SchematicElementConverter } from "./converter-types"
|
|
|
6
6
|
import { convertSymbolPrimitives } from "./convert-symbol-primitives"
|
|
7
7
|
import { formatElement } from "./format-attributes"
|
|
8
8
|
|
|
9
|
+
// Match core's preprocessSelector checks for net names. The validator is not
|
|
10
|
+
// exported by @tscircuit/core; runtime regression tests keep these in sync.
|
|
11
|
+
// https://github.com/tscircuit/core/blob/main/lib/components/base-components/PrimitiveComponent/preprocessSelector.ts
|
|
12
|
+
function canRenderNativeNetLabel(name: string): boolean {
|
|
13
|
+
const selector = `net.${name}`
|
|
14
|
+
if (
|
|
15
|
+
/net\.[^\s>]*\./.test(selector) ||
|
|
16
|
+
/net\.[^\s>]*[+-]/.test(selector) ||
|
|
17
|
+
/net\.[0-9]/.test(selector)
|
|
18
|
+
) {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
// A label is one literal name, not a selector expression. Whitespace and CSS
|
|
22
|
+
// punctuation can parse as a different selection even when core accepts it.
|
|
23
|
+
return /^\/?[A-Za-z0-9_]+$/.test(name)
|
|
24
|
+
}
|
|
25
|
+
|
|
9
26
|
export const convertNetLabels: SchematicElementConverter = (circuitJson) =>
|
|
10
27
|
su(circuitJson)
|
|
11
28
|
.schematic_net_label.list()
|
|
@@ -26,6 +43,23 @@ export const convertNetLabels: SchematicElementConverter = (circuitJson) =>
|
|
|
26
43
|
displayText: schematicNetLabel.text,
|
|
27
44
|
})
|
|
28
45
|
}
|
|
46
|
+
// Native labels own their outline, typography and anchor-side layout.
|
|
47
|
+
// Core resolves net names through selectors; retain the text fallback
|
|
48
|
+
// for names that cannot safely be used by that runtime path.
|
|
49
|
+
if (
|
|
50
|
+
!symbolName &&
|
|
51
|
+
schematicNetLabel.anchor_position &&
|
|
52
|
+
canRenderNativeNetLabel(schematicNetLabel.text)
|
|
53
|
+
) {
|
|
54
|
+
return [
|
|
55
|
+
formatElement("netlabel", {
|
|
56
|
+
net: schematicNetLabel.text,
|
|
57
|
+
schX: anchorPosition.x,
|
|
58
|
+
schY: anchorPosition.y,
|
|
59
|
+
anchorSide: schematicNetLabel.anchor_side,
|
|
60
|
+
}),
|
|
61
|
+
]
|
|
62
|
+
}
|
|
29
63
|
return [
|
|
30
64
|
formatElement("schematictext", {
|
|
31
65
|
text: schematicNetLabel.text,
|
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { convertNetLabels } from "../lib/generate-board-schematic-tsx/convert-net-labels"
|
|
3
|
+
import { runTscircuitCode } from "tscircuit"
|
|
4
|
+
|
|
5
|
+
function convertPlainNetLabel(text: string) {
|
|
6
|
+
return convertNetLabels([
|
|
7
|
+
{
|
|
8
|
+
type: "schematic_net_label",
|
|
9
|
+
schematic_net_label_id: "label",
|
|
10
|
+
source_net_id: "net",
|
|
11
|
+
text,
|
|
12
|
+
center: { x: 2, y: 3 },
|
|
13
|
+
anchor_position: { x: 2, y: 3 },
|
|
14
|
+
anchor_side: "left",
|
|
15
|
+
},
|
|
16
|
+
]).join("\n")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const name of ["VCC-P", "VCC+P", "3V3", "1", "-VCC", "net.name"]) {
|
|
20
|
+
test(`conversion preserves text when core rejects ${name}`, async () => {
|
|
21
|
+
await expect(
|
|
22
|
+
runTscircuitCode(
|
|
23
|
+
`export default () => <board><netlabel net={${JSON.stringify(name)}} /></board>`,
|
|
24
|
+
),
|
|
25
|
+
).rejects.toThrow(/Net name/)
|
|
26
|
+
const generated = convertPlainNetLabel(name)
|
|
27
|
+
expect(generated).not.toContain("<netlabel")
|
|
28
|
+
const output = await runTscircuitCode(
|
|
29
|
+
`export default () => <board><symbol>${generated}</symbol></board>`,
|
|
30
|
+
)
|
|
31
|
+
expect(output).toEqual(
|
|
32
|
+
expect.arrayContaining([
|
|
33
|
+
expect.objectContaining({ type: "schematic_text", text: name }),
|
|
34
|
+
]),
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const name of ["SDA", "V3_3", "_RESET", "/RESET", "/3V3", "A1"]) {
|
|
40
|
+
test(`conversion preserves native labels accepted by core: ${name}`, async () => {
|
|
41
|
+
const source = await runTscircuitCode(
|
|
42
|
+
`export default () => <board><netlabel net={${JSON.stringify(name)}} schX={2} schY={3} anchorSide="left" /></board>`,
|
|
43
|
+
)
|
|
44
|
+
const generated = convertNetLabels(source).join("\n")
|
|
45
|
+
expect(generated).toContain("<netlabel")
|
|
46
|
+
const output = await runTscircuitCode(
|
|
47
|
+
`export default () => <board><symbol>${generated}</symbol></board>`,
|
|
48
|
+
)
|
|
49
|
+
expect(output).toEqual(
|
|
50
|
+
expect.arrayContaining([
|
|
51
|
+
expect.objectContaining({
|
|
52
|
+
type: "schematic_net_label",
|
|
53
|
+
text: name,
|
|
54
|
+
anchor_position: { x: 2, y: 3 },
|
|
55
|
+
anchor_side: "left",
|
|
56
|
+
}),
|
|
57
|
+
]),
|
|
58
|
+
)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const name of [
|
|
63
|
+
"BUS/DATA",
|
|
64
|
+
"//RESET",
|
|
65
|
+
"HV VSYS",
|
|
66
|
+
"A>B",
|
|
67
|
+
"A,B",
|
|
68
|
+
"A[1]",
|
|
69
|
+
"A:B",
|
|
70
|
+
'A"B',
|
|
71
|
+
"",
|
|
72
|
+
"電源",
|
|
73
|
+
]) {
|
|
74
|
+
test(`conversion preserves selector-unsafe label text: ${name}`, async () => {
|
|
75
|
+
const generated = convertPlainNetLabel(name)
|
|
76
|
+
expect(generated).not.toContain("<netlabel")
|
|
77
|
+
const output = await runTscircuitCode(
|
|
78
|
+
`export default () => <board><symbol>${generated}</symbol></board>`,
|
|
79
|
+
)
|
|
80
|
+
expect(output).toEqual(
|
|
81
|
+
expect.arrayContaining([
|
|
82
|
+
expect.objectContaining({ type: "schematic_text", text: name }),
|
|
83
|
+
]),
|
|
84
|
+
)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import type { CircuitJson } from "circuit-json"
|
|
3
|
+
import { convertCircuitJsonToSchematicSvg } from "circuit-to-svg"
|
|
4
|
+
import { convertCircuitJsonToTscircuit } from "lib"
|
|
5
|
+
import { runTscircuitCode } from "tscircuit"
|
|
6
|
+
|
|
7
|
+
test("native plain labels preserve rendering on every connection side", async () => {
|
|
8
|
+
for (const side of ["left", "right", "top", "bottom"] as const) {
|
|
9
|
+
const input = await runTscircuitCode(`export default () => (
|
|
10
|
+
<board width={10} height={10}>
|
|
11
|
+
<netlabel net="DATA" schX={2} schY={3} anchorSide="${side}" />
|
|
12
|
+
</board>
|
|
13
|
+
)`)
|
|
14
|
+
const output = await runTscircuitCode(
|
|
15
|
+
convertCircuitJsonToTscircuit(input, { componentName: "LabelBoard" }),
|
|
16
|
+
)
|
|
17
|
+
const sourceLabels = input.filter((e) => e.type === "schematic_net_label")
|
|
18
|
+
const renderedLabels = output.filter(
|
|
19
|
+
(e) => e.type === "schematic_net_label",
|
|
20
|
+
)
|
|
21
|
+
expect(renderedLabels).toHaveLength(1)
|
|
22
|
+
const original = sourceLabels[0]!
|
|
23
|
+
expect(renderedLabels[0]).toMatchObject({
|
|
24
|
+
text: original.text,
|
|
25
|
+
anchor_side: original.anchor_side,
|
|
26
|
+
anchor_position: original.anchor_position,
|
|
27
|
+
center: original.center,
|
|
28
|
+
})
|
|
29
|
+
expect(
|
|
30
|
+
convertCircuitJsonToSchematicSvg(renderedLabels, {
|
|
31
|
+
includeVersion: false,
|
|
32
|
+
}),
|
|
33
|
+
).toBe(
|
|
34
|
+
convertCircuitJsonToSchematicSvg(sourceLabels, { includeVersion: false }),
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
for (const name of [
|
|
38
|
+
"HV VSYS",
|
|
39
|
+
"BUS/DATA",
|
|
40
|
+
"net.name",
|
|
41
|
+
"",
|
|
42
|
+
'A"B',
|
|
43
|
+
"CENTER_ONLY",
|
|
44
|
+
"VCC-P",
|
|
45
|
+
"VCC+P",
|
|
46
|
+
"3V3",
|
|
47
|
+
"1",
|
|
48
|
+
"-VCC",
|
|
49
|
+
]) {
|
|
50
|
+
const input: CircuitJson = [
|
|
51
|
+
{
|
|
52
|
+
type: "pcb_board",
|
|
53
|
+
pcb_board_id: "board",
|
|
54
|
+
center: { x: 0, y: 0 },
|
|
55
|
+
width: 10,
|
|
56
|
+
height: 10,
|
|
57
|
+
num_layers: 2,
|
|
58
|
+
thickness: 1.6,
|
|
59
|
+
material: "fr4",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: "schematic_net_label",
|
|
63
|
+
schematic_net_label_id: "label",
|
|
64
|
+
text: name,
|
|
65
|
+
center: { x: 2, y: 3 },
|
|
66
|
+
anchor_position: name === "CENTER_ONLY" ? undefined : { x: 2, y: 3 },
|
|
67
|
+
anchor_side: "left",
|
|
68
|
+
source_net_id: "net",
|
|
69
|
+
},
|
|
70
|
+
]
|
|
71
|
+
const tsx = convertCircuitJsonToTscircuit(input, {
|
|
72
|
+
componentName: "Fallback",
|
|
73
|
+
})
|
|
74
|
+
expect(tsx).not.toContain("<netlabel")
|
|
75
|
+
const fallback = await runTscircuitCode(tsx)
|
|
76
|
+
expect(fallback).toEqual(
|
|
77
|
+
expect.arrayContaining([
|
|
78
|
+
expect.objectContaining({ type: "schematic_text", text: name }),
|
|
79
|
+
]),
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
})
|