kicadts 0.0.1
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/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
- package/.vscode/settings.json +16 -0
- package/AGENTS.md +30 -0
- package/README.md +206 -0
- package/biome.json +93 -0
- package/bun.lock +48 -0
- package/bunfig.toml +5 -0
- package/lib/index.ts +1 -0
- package/lib/sexpr/base-classes/SxClass.ts +164 -0
- package/lib/sexpr/base-classes/SxPrimitiveBoolean.ts +35 -0
- package/lib/sexpr/base-classes/SxPrimitiveNumber.ts +26 -0
- package/lib/sexpr/base-classes/SxPrimitiveString.ts +26 -0
- package/lib/sexpr/classes/At.ts +38 -0
- package/lib/sexpr/classes/Bus.ts +83 -0
- package/lib/sexpr/classes/BusEntry.ts +142 -0
- package/lib/sexpr/classes/Color.ts +29 -0
- package/lib/sexpr/classes/Dnp.ts +8 -0
- package/lib/sexpr/classes/EmbeddedFonts.ts +70 -0
- package/lib/sexpr/classes/ExcludeFromSim.ts +8 -0
- package/lib/sexpr/classes/FieldsAutoplaced.ts +8 -0
- package/lib/sexpr/classes/Footprint.ts +719 -0
- package/lib/sexpr/classes/FootprintAttr.ts +102 -0
- package/lib/sexpr/classes/FootprintAutoplaceCost180.ts +9 -0
- package/lib/sexpr/classes/FootprintAutoplaceCost90.ts +9 -0
- package/lib/sexpr/classes/FootprintClearance.ts +9 -0
- package/lib/sexpr/classes/FootprintDescr.ts +44 -0
- package/lib/sexpr/classes/FootprintLocked.ts +32 -0
- package/lib/sexpr/classes/FootprintModel.ts +145 -0
- package/lib/sexpr/classes/FootprintNetTiePadGroups.ts +50 -0
- package/lib/sexpr/classes/FootprintPad.ts +705 -0
- package/lib/sexpr/classes/FootprintPath.ts +44 -0
- package/lib/sexpr/classes/FootprintPlaced.ts +32 -0
- package/lib/sexpr/classes/FootprintPrivateLayers.ts +56 -0
- package/lib/sexpr/classes/FootprintSheetfile.ts +44 -0
- package/lib/sexpr/classes/FootprintSheetname.ts +44 -0
- package/lib/sexpr/classes/FootprintSolderMaskMargin.ts +9 -0
- package/lib/sexpr/classes/FootprintSolderPasteMargin.ts +9 -0
- package/lib/sexpr/classes/FootprintSolderPasteRatio.ts +9 -0
- package/lib/sexpr/classes/FootprintTags.ts +44 -0
- package/lib/sexpr/classes/FootprintTedit.ts +21 -0
- package/lib/sexpr/classes/FootprintThermalGap.ts +9 -0
- package/lib/sexpr/classes/FootprintThermalWidth.ts +9 -0
- package/lib/sexpr/classes/FootprintZoneConnect.ts +9 -0
- package/lib/sexpr/classes/FpArc.ts +289 -0
- package/lib/sexpr/classes/FpCircle.ts +293 -0
- package/lib/sexpr/classes/FpLine.ts +288 -0
- package/lib/sexpr/classes/FpPoly.ts +266 -0
- package/lib/sexpr/classes/FpPolyFill.ts +48 -0
- package/lib/sexpr/classes/FpPolyLocked.ts +40 -0
- package/lib/sexpr/classes/FpRect.ts +293 -0
- package/lib/sexpr/classes/FpText.ts +341 -0
- package/lib/sexpr/classes/FpTextBox.ts +412 -0
- package/lib/sexpr/classes/GrLine.ts +245 -0
- package/lib/sexpr/classes/GrLineAngle.ts +32 -0
- package/lib/sexpr/classes/GrLineEnd.ts +61 -0
- package/lib/sexpr/classes/GrLineLocked.ts +40 -0
- package/lib/sexpr/classes/GrLineStart.ts +61 -0
- package/lib/sexpr/classes/GrText.ts +202 -0
- package/lib/sexpr/classes/Image.ts +256 -0
- package/lib/sexpr/classes/InBom.ts +8 -0
- package/lib/sexpr/classes/Junction.ts +134 -0
- package/lib/sexpr/classes/KicadPcb.ts +313 -0
- package/lib/sexpr/classes/KicadSch.ts +303 -0
- package/lib/sexpr/classes/KicadSchGenerator.ts +32 -0
- package/lib/sexpr/classes/KicadSchGeneratorVersion.ts +30 -0
- package/lib/sexpr/classes/KicadSchVersion.ts +22 -0
- package/lib/sexpr/classes/Label.ts +136 -0
- package/lib/sexpr/classes/Layer.ts +51 -0
- package/lib/sexpr/classes/Layers.ts +47 -0
- package/lib/sexpr/classes/LibSymbols.ts +61 -0
- package/lib/sexpr/classes/NoConnect.ts +73 -0
- package/lib/sexpr/classes/OnBoard.ts +8 -0
- package/lib/sexpr/classes/PadChamfer.ts +50 -0
- package/lib/sexpr/classes/PadChamferRatio.ts +9 -0
- package/lib/sexpr/classes/PadClearance.ts +9 -0
- package/lib/sexpr/classes/PadDieLength.ts +9 -0
- package/lib/sexpr/classes/PadDrill.ts +145 -0
- package/lib/sexpr/classes/PadDrillOffset.ts +54 -0
- package/lib/sexpr/classes/PadLayers.ts +59 -0
- package/lib/sexpr/classes/PadNet.ts +56 -0
- package/lib/sexpr/classes/PadOptions.ts +182 -0
- package/lib/sexpr/classes/PadPinFunction.ts +9 -0
- package/lib/sexpr/classes/PadPinType.ts +9 -0
- package/lib/sexpr/classes/PadPrimitiveGrArc.ts +254 -0
- package/lib/sexpr/classes/PadPrimitiveGrCircle.ts +279 -0
- package/lib/sexpr/classes/PadPrimitiveGrLine.ts +126 -0
- package/lib/sexpr/classes/PadPrimitives.ts +289 -0
- package/lib/sexpr/classes/PadRectDelta.ts +57 -0
- package/lib/sexpr/classes/PadRoundrectRratio.ts +9 -0
- package/lib/sexpr/classes/PadSize.ts +54 -0
- package/lib/sexpr/classes/PadSolderMaskMargin.ts +9 -0
- package/lib/sexpr/classes/PadSolderPasteMargin.ts +9 -0
- package/lib/sexpr/classes/PadSolderPasteMarginRatio.ts +9 -0
- package/lib/sexpr/classes/PadTeardrops.ts +208 -0
- package/lib/sexpr/classes/PadThermalBridgeAngle.ts +9 -0
- package/lib/sexpr/classes/PadThermalGap.ts +9 -0
- package/lib/sexpr/classes/PadThermalWidth.ts +9 -0
- package/lib/sexpr/classes/PadZoneConnect.ts +9 -0
- package/lib/sexpr/classes/Paper.ts +119 -0
- package/lib/sexpr/classes/PcbGeneral.ts +75 -0
- package/lib/sexpr/classes/PcbGeneralLegacyTeardrops.ts +44 -0
- package/lib/sexpr/classes/PcbGeneralThickness.ts +9 -0
- package/lib/sexpr/classes/PcbGenerator.ts +16 -0
- package/lib/sexpr/classes/PcbGeneratorVersion.ts +16 -0
- package/lib/sexpr/classes/PcbLayerDefinition.ts +102 -0
- package/lib/sexpr/classes/PcbLayers.ts +34 -0
- package/lib/sexpr/classes/PcbNet.ts +56 -0
- package/lib/sexpr/classes/PcbVersion.ts +9 -0
- package/lib/sexpr/classes/Property.ts +246 -0
- package/lib/sexpr/classes/PropertyHide.ts +9 -0
- package/lib/sexpr/classes/PropertyUnlocked.ts +9 -0
- package/lib/sexpr/classes/Pts.ts +65 -0
- package/lib/sexpr/classes/RenderCache.ts +221 -0
- package/lib/sexpr/classes/SchematicText.ts +141 -0
- package/lib/sexpr/classes/Segment.ts +222 -0
- package/lib/sexpr/classes/SegmentEnd.ts +59 -0
- package/lib/sexpr/classes/SegmentLocked.ts +33 -0
- package/lib/sexpr/classes/SegmentNet.ts +62 -0
- package/lib/sexpr/classes/SegmentStart.ts +59 -0
- package/lib/sexpr/classes/Setup/PcbPlotParams.ts +729 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsBase.ts +9 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsNumericProperties.ts +105 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesA.ts +104 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesB.ts +105 -0
- package/lib/sexpr/classes/Setup/Setup.ts +573 -0
- package/lib/sexpr/classes/Setup/SetupPropertyTypes.ts +119 -0
- package/lib/sexpr/classes/Setup/Stackup.ts +140 -0
- package/lib/sexpr/classes/Setup/StackupLayer.ts +233 -0
- package/lib/sexpr/classes/Setup/StackupLayerProperties.ts +78 -0
- package/lib/sexpr/classes/Setup/StackupProperties.ts +41 -0
- package/lib/sexpr/classes/Setup/base.ts +167 -0
- package/lib/sexpr/classes/Setup/index.ts +14 -0
- package/lib/sexpr/classes/Setup/setupMultiValueProperties.ts +54 -0
- package/lib/sexpr/classes/Setup/setupNumericProperties.ts +151 -0
- package/lib/sexpr/classes/Setup/setupPropertyHandlers.ts +90 -0
- package/lib/sexpr/classes/Setup/setupStringProperties.ts +75 -0
- package/lib/sexpr/classes/Sheet.ts +205 -0
- package/lib/sexpr/classes/SheetFill.ts +44 -0
- package/lib/sexpr/classes/SheetInstances.ts +168 -0
- package/lib/sexpr/classes/SheetInstancesRoot.ts +165 -0
- package/lib/sexpr/classes/SheetPin.ts +122 -0
- package/lib/sexpr/classes/SheetProperty.ts +115 -0
- package/lib/sexpr/classes/SheetSize.ts +44 -0
- package/lib/sexpr/classes/Stroke.ts +58 -0
- package/lib/sexpr/classes/StrokeType.ts +34 -0
- package/lib/sexpr/classes/Symbol.ts +1541 -0
- package/lib/sexpr/classes/TextEffects.ts +444 -0
- package/lib/sexpr/classes/TitleBlock.ts +352 -0
- package/lib/sexpr/classes/Unit.ts +28 -0
- package/lib/sexpr/classes/Uuid.ts +8 -0
- package/lib/sexpr/classes/Via.ts +328 -0
- package/lib/sexpr/classes/ViaNet.ts +59 -0
- package/lib/sexpr/classes/Width.ts +8 -0
- package/lib/sexpr/classes/Wire.ts +91 -0
- package/lib/sexpr/classes/Xy.ts +35 -0
- package/lib/sexpr/classes/Zone.ts +41 -0
- package/lib/sexpr/index.ts +130 -0
- package/lib/sexpr/parseKicadSexpr.ts +5 -0
- package/lib/sexpr/parseToPrimitiveSExpr.ts +240 -0
- package/lib/sexpr/utils/indentLines.ts +3 -0
- package/lib/sexpr/utils/parseYesNo.ts +12 -0
- package/lib/sexpr/utils/quoteSExprString.ts +8 -0
- package/lib/sexpr/utils/strokeFromArgs.ts +19 -0
- package/lib/sexpr/utils/toNumberValue.ts +13 -0
- package/lib/sexpr/utils/toStringValue.ts +10 -0
- package/package.json +26 -0
- package/scripts/download-references.ts +66 -0
- package/tests/fixtures/expectEqualPrimitiveSExpr.ts +200 -0
- package/tests/sexpr/KicadPcbDemos.test.ts +48 -0
- package/tests/sexpr/KicadSchDemos.test.ts +49 -0
- package/tests/sexpr/classes/Footprint.test.ts +277 -0
- package/tests/sexpr/classes/FootprintPad.test.ts +71 -0
- package/tests/sexpr/classes/FpArc.test.ts +45 -0
- package/tests/sexpr/classes/FpCircle.test.ts +39 -0
- package/tests/sexpr/classes/FpPoly.test.ts +43 -0
- package/tests/sexpr/classes/FpRect.test.ts +40 -0
- package/tests/sexpr/classes/FpTextBox.test.ts +84 -0
- package/tests/sexpr/classes/Image.test.ts +50 -0
- package/tests/sexpr/classes/KicadSch.test.ts +97 -0
- package/tests/sexpr/classes/Paper.test.ts +30 -0
- package/tests/sexpr/classes/Property.test.ts +48 -0
- package/tests/sexpr/classes/Setup.test.ts +189 -0
- package/tests/sexpr/classes/Sheet.test.ts +107 -0
- package/tests/sexpr/classes/Stroke.test.ts +15 -0
- package/tests/sexpr/classes/Symbol.test.ts +96 -0
- package/tests/sexpr/classes/TextEffects.test.ts +56 -0
- package/tests/sexpr/classes/TitleBlock.test.ts +40 -0
- package/tsconfig.json +35 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { FootprintPad, PadLayers, PadNet, PadSize, PadDrill, SxClass } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("FootprintPad", () => {
|
|
5
|
+
const [pad] = SxClass.parse(`
|
|
6
|
+
(pad "1" smd roundrect
|
|
7
|
+
(at 1.5 -2.5 180)
|
|
8
|
+
(size 1.2 0.6)
|
|
9
|
+
(drill 0.3)
|
|
10
|
+
(layers F.Cu F.Paste F.Mask)
|
|
11
|
+
(roundrect_rratio 0.25)
|
|
12
|
+
(chamfer top_left bottom_right)
|
|
13
|
+
(solder_mask_margin 0.05)
|
|
14
|
+
(solder_paste_margin_ratio -0.1)
|
|
15
|
+
(clearance 0.15)
|
|
16
|
+
(zone_connect 1)
|
|
17
|
+
(thermal_gap 0.2)
|
|
18
|
+
(thermal_width 0.12)
|
|
19
|
+
(net 3 "SIG")
|
|
20
|
+
(pinfunction "SIG")
|
|
21
|
+
(pintype "input")
|
|
22
|
+
(uuid 55555555-6666-7777-8888-999999999999)
|
|
23
|
+
locked
|
|
24
|
+
)
|
|
25
|
+
`)
|
|
26
|
+
|
|
27
|
+
expect(pad).toBeInstanceOf(FootprintPad)
|
|
28
|
+
const fpPad = pad as FootprintPad
|
|
29
|
+
expect(fpPad.number).toBe("1")
|
|
30
|
+
expect(fpPad.padType).toBe("smd")
|
|
31
|
+
expect(fpPad.shape).toBe("roundrect")
|
|
32
|
+
expect(fpPad.at).toBeDefined()
|
|
33
|
+
expect(fpPad.size).toBeInstanceOf(PadSize)
|
|
34
|
+
expect(fpPad.size?.width).toBe(1.2)
|
|
35
|
+
expect(fpPad.size?.height).toBe(0.6)
|
|
36
|
+
expect(fpPad.drill).toBeInstanceOf(PadDrill)
|
|
37
|
+
expect(fpPad.drill?.oval).toBe(false)
|
|
38
|
+
expect(fpPad.drill?.diameter).toBe(0.3)
|
|
39
|
+
expect(fpPad.layers).toBeInstanceOf(PadLayers)
|
|
40
|
+
expect(fpPad.layers?.layers).toEqual(["F.Cu", "F.Paste", "F.Mask"])
|
|
41
|
+
expect(fpPad.roundrectRatio).toBe(0.25)
|
|
42
|
+
expect(fpPad.chamferCorners).toEqual(["top_left", "bottom_right"])
|
|
43
|
+
expect(fpPad.net).toBeInstanceOf(PadNet)
|
|
44
|
+
expect(fpPad.net?.id).toBe(3)
|
|
45
|
+
expect(fpPad.net?.name).toBe("SIG")
|
|
46
|
+
expect(fpPad.pinfunction).toBe("SIG")
|
|
47
|
+
expect(fpPad.pintype).toBe("input")
|
|
48
|
+
expect(fpPad.locked).toBe(true)
|
|
49
|
+
|
|
50
|
+
expect(fpPad.getString()).toMatchInlineSnapshot(`
|
|
51
|
+
"(pad \"1\" smd roundrect
|
|
52
|
+
(at 1.5 -2.5 180)
|
|
53
|
+
(size 1.2 0.6)
|
|
54
|
+
(drill 0.3)
|
|
55
|
+
(layers F.Cu F.Paste F.Mask)
|
|
56
|
+
(roundrect_rratio 0.25)
|
|
57
|
+
(chamfer top_left bottom_right)
|
|
58
|
+
(net 3 \"SIG\")
|
|
59
|
+
(pinfunction SIG)
|
|
60
|
+
(pintype input)
|
|
61
|
+
(solder_mask_margin 0.05)
|
|
62
|
+
(solder_paste_margin_ratio -0.1)
|
|
63
|
+
(clearance 0.15)
|
|
64
|
+
(zone_connect 1)
|
|
65
|
+
(thermal_width 0.12)
|
|
66
|
+
(thermal_gap 0.2)
|
|
67
|
+
(uuid 55555555-6666-7777-8888-999999999999)
|
|
68
|
+
locked
|
|
69
|
+
)"
|
|
70
|
+
`)
|
|
71
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FpArc, Layer, Stroke, SxClass } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("FpArc", () => {
|
|
5
|
+
const [arc] = SxClass.parse(`
|
|
6
|
+
(fp_arc
|
|
7
|
+
(start 0 0)
|
|
8
|
+
(mid 1 1)
|
|
9
|
+
(end 2 0)
|
|
10
|
+
(layer F.SilkS)
|
|
11
|
+
(stroke (width 0.12) (type solid) (color 0 0 1 1))
|
|
12
|
+
(uuid 12340000-0000-0000-0000-000000000000)
|
|
13
|
+
)
|
|
14
|
+
`)
|
|
15
|
+
|
|
16
|
+
expect(arc).toBeInstanceOf(FpArc)
|
|
17
|
+
const fpArc = arc as FpArc
|
|
18
|
+
expect(fpArc.start?.x).toBe(0)
|
|
19
|
+
expect(fpArc.mid?.y).toBe(1)
|
|
20
|
+
expect(fpArc.end?.x).toBe(2)
|
|
21
|
+
expect(fpArc.layer).toBeInstanceOf(Layer)
|
|
22
|
+
expect(fpArc.stroke).toBeInstanceOf(Stroke)
|
|
23
|
+
expect(fpArc.uuid).toBe("12340000-0000-0000-0000-000000000000")
|
|
24
|
+
|
|
25
|
+
fpArc.width = 0.25
|
|
26
|
+
expect(fpArc.width).toBe(0.25)
|
|
27
|
+
fpArc.locked = true
|
|
28
|
+
|
|
29
|
+
expect(fpArc.getString()).toMatchInlineSnapshot(`
|
|
30
|
+
"(fp_arc
|
|
31
|
+
(start 0 0)
|
|
32
|
+
(mid 1 1)
|
|
33
|
+
(end 2 0)
|
|
34
|
+
(layer F.SilkS)
|
|
35
|
+
(width 0.25)
|
|
36
|
+
(stroke
|
|
37
|
+
(width 0.12)
|
|
38
|
+
(type solid)
|
|
39
|
+
(color 0 0 1 1)
|
|
40
|
+
)
|
|
41
|
+
(uuid 12340000-0000-0000-0000-000000000000)
|
|
42
|
+
locked
|
|
43
|
+
)"
|
|
44
|
+
`)
|
|
45
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FpCircle, Layer, Stroke, SxClass } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("FpCircle", () => {
|
|
5
|
+
const [circle] = SxClass.parse(`
|
|
6
|
+
(fp_circle
|
|
7
|
+
(center 1 1)
|
|
8
|
+
(end 2 1)
|
|
9
|
+
(layer F.SilkS)
|
|
10
|
+
(stroke (width 0.1) (type dash) (color 0.2 0.2 0.2 1))
|
|
11
|
+
(uuid 55555555-6666-7777-8888-999999999999)
|
|
12
|
+
)
|
|
13
|
+
`)
|
|
14
|
+
|
|
15
|
+
expect(circle).toBeInstanceOf(FpCircle)
|
|
16
|
+
const fpCircle = circle as FpCircle
|
|
17
|
+
expect(fpCircle.center?.x).toBe(1)
|
|
18
|
+
expect(fpCircle.end?.x).toBe(2)
|
|
19
|
+
expect(fpCircle.layer).toBeInstanceOf(Layer)
|
|
20
|
+
expect(fpCircle.stroke).toBeInstanceOf(Stroke)
|
|
21
|
+
expect(fpCircle.uuid).toBe("55555555-6666-7777-8888-999999999999")
|
|
22
|
+
|
|
23
|
+
fpCircle.locked = true
|
|
24
|
+
|
|
25
|
+
expect(fpCircle.getString()).toMatchInlineSnapshot(`
|
|
26
|
+
"(fp_circle
|
|
27
|
+
(center 1 1)
|
|
28
|
+
(end 2 1)
|
|
29
|
+
(layer F.SilkS)
|
|
30
|
+
(stroke
|
|
31
|
+
(width 0.1)
|
|
32
|
+
(type dash)
|
|
33
|
+
(color 0.2 0.2 0.2 1)
|
|
34
|
+
)
|
|
35
|
+
(uuid 55555555-6666-7777-8888-999999999999)
|
|
36
|
+
locked
|
|
37
|
+
)"
|
|
38
|
+
`)
|
|
39
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FpPoly, Layer, Pts, Stroke, SxClass } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("FpPoly", () => {
|
|
5
|
+
const [poly] = SxClass.parse(`
|
|
6
|
+
(fp_poly
|
|
7
|
+
(pts (xy 0 0) (xy 1 0) (xy 1 1) (xy 0 1))
|
|
8
|
+
(layer F.SilkS)
|
|
9
|
+
(stroke (width 0.1) (type solid) (color 0 0 0 1))
|
|
10
|
+
(fill yes)
|
|
11
|
+
(uuid 10101010-2020-3030-4040-505050505050)
|
|
12
|
+
)
|
|
13
|
+
`)
|
|
14
|
+
|
|
15
|
+
expect(poly).toBeInstanceOf(FpPoly)
|
|
16
|
+
const fpPoly = poly as FpPoly
|
|
17
|
+
expect(fpPoly.points).toBeInstanceOf(Pts)
|
|
18
|
+
expect(fpPoly.layer).toBeInstanceOf(Layer)
|
|
19
|
+
expect(fpPoly.stroke).toBeInstanceOf(Stroke)
|
|
20
|
+
expect(fpPoly.fill?.filled).toBe(true)
|
|
21
|
+
|
|
22
|
+
fpPoly.locked = true
|
|
23
|
+
|
|
24
|
+
expect(fpPoly.getString()).toMatchInlineSnapshot(`
|
|
25
|
+
"(fp_poly
|
|
26
|
+
(pts
|
|
27
|
+
(xy 0 0)
|
|
28
|
+
(xy 1 0)
|
|
29
|
+
(xy 1 1)
|
|
30
|
+
(xy 0 1)
|
|
31
|
+
)
|
|
32
|
+
(layer F.SilkS)
|
|
33
|
+
(stroke
|
|
34
|
+
(width 0.1)
|
|
35
|
+
(type solid)
|
|
36
|
+
(color 0 0 0 1)
|
|
37
|
+
)
|
|
38
|
+
(fill yes)
|
|
39
|
+
(locked yes)
|
|
40
|
+
(uuid 10101010-2020-3030-4040-505050505050)
|
|
41
|
+
)"
|
|
42
|
+
`)
|
|
43
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { FpRect, Layer, Stroke, SxClass } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("FpRect", () => {
|
|
5
|
+
const [rect] = SxClass.parse(`
|
|
6
|
+
(fp_rect
|
|
7
|
+
(start 0 0)
|
|
8
|
+
(end 5 5)
|
|
9
|
+
(layer F.Cu)
|
|
10
|
+
(stroke (width 0.2) (type solid) (color 1 0 0 1))
|
|
11
|
+
(uuid 00000000-1111-2222-3333-444444444444)
|
|
12
|
+
)
|
|
13
|
+
`)
|
|
14
|
+
|
|
15
|
+
expect(rect).toBeInstanceOf(FpRect)
|
|
16
|
+
const fpRect = rect as FpRect
|
|
17
|
+
expect(fpRect.start?.x).toBe(0)
|
|
18
|
+
expect(fpRect.end?.y).toBe(5)
|
|
19
|
+
expect(fpRect.layer).toBeInstanceOf(Layer)
|
|
20
|
+
expect(fpRect.stroke).toBeInstanceOf(Stroke)
|
|
21
|
+
expect(fpRect.uuid).toBe("00000000-1111-2222-3333-444444444444")
|
|
22
|
+
|
|
23
|
+
fpRect.width = 0.3
|
|
24
|
+
expect(fpRect.width).toBe(0.3)
|
|
25
|
+
|
|
26
|
+
expect(fpRect.getString()).toMatchInlineSnapshot(`
|
|
27
|
+
"(fp_rect
|
|
28
|
+
(start 0 0)
|
|
29
|
+
(end 5 5)
|
|
30
|
+
(layer F.Cu)
|
|
31
|
+
(width 0.3)
|
|
32
|
+
(stroke
|
|
33
|
+
(width 0.2)
|
|
34
|
+
(type solid)
|
|
35
|
+
(color 1 0 0 1)
|
|
36
|
+
)
|
|
37
|
+
(uuid 00000000-1111-2222-3333-444444444444)
|
|
38
|
+
)"
|
|
39
|
+
`)
|
|
40
|
+
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FpTextBox,
|
|
3
|
+
FpTextBoxAngle,
|
|
4
|
+
FpTextBoxEnd,
|
|
5
|
+
FpTextBoxStart,
|
|
6
|
+
Layer,
|
|
7
|
+
Pts,
|
|
8
|
+
RenderCache,
|
|
9
|
+
Stroke,
|
|
10
|
+
TextEffects,
|
|
11
|
+
Uuid,
|
|
12
|
+
SxClass,
|
|
13
|
+
} from "lib/sexpr"
|
|
14
|
+
import { expect, test } from "bun:test"
|
|
15
|
+
|
|
16
|
+
test("FpTextBox", () => {
|
|
17
|
+
const [textBox] = SxClass.parse(`
|
|
18
|
+
(fp_text_box locked "Notes"
|
|
19
|
+
(start 0 0)
|
|
20
|
+
(end 10 5)
|
|
21
|
+
(pts (xy 0 0) (xy 10 0) (xy 10 5) (xy 0 5))
|
|
22
|
+
(angle 45)
|
|
23
|
+
(layer F.SilkS)
|
|
24
|
+
(effects (font (size 1 1) (thickness 0.15)))
|
|
25
|
+
(stroke (width 0.1) (type solid) (color 0 0 0 1))
|
|
26
|
+
(uuid 11111111-2222-3333-4444-555555555555)
|
|
27
|
+
(render_cache "Notes text" 0 0)
|
|
28
|
+
)
|
|
29
|
+
`)
|
|
30
|
+
|
|
31
|
+
expect(textBox).toBeInstanceOf(FpTextBox)
|
|
32
|
+
const fpTextBox = textBox as FpTextBox
|
|
33
|
+
|
|
34
|
+
expect(fpTextBox.locked).toBe(true)
|
|
35
|
+
expect(fpTextBox.text).toBe("Notes")
|
|
36
|
+
expect(fpTextBox.start).toBeInstanceOf(FpTextBoxStart)
|
|
37
|
+
expect(fpTextBox.start?.x).toBe(0)
|
|
38
|
+
expect(fpTextBox.end).toBeInstanceOf(FpTextBoxEnd)
|
|
39
|
+
expect(fpTextBox.end?.y).toBe(5)
|
|
40
|
+
expect(fpTextBox.pts).toBeInstanceOf(Pts)
|
|
41
|
+
expect(fpTextBox.pts?.points.length).toBe(4)
|
|
42
|
+
expect(fpTextBox.angle).toBeInstanceOf(FpTextBoxAngle)
|
|
43
|
+
expect(fpTextBox.angle?.value).toBe(45)
|
|
44
|
+
expect(fpTextBox.layer).toBeInstanceOf(Layer)
|
|
45
|
+
expect(fpTextBox.effects).toBeInstanceOf(TextEffects)
|
|
46
|
+
expect(fpTextBox.stroke).toBeInstanceOf(Stroke)
|
|
47
|
+
expect(fpTextBox.uuid).toBeInstanceOf(Uuid)
|
|
48
|
+
expect(fpTextBox.renderCache).toBeInstanceOf(RenderCache)
|
|
49
|
+
expect(fpTextBox.renderCache?.text).toBe("Notes text")
|
|
50
|
+
expect(fpTextBox.renderCache?.angle).toBe(0)
|
|
51
|
+
expect(fpTextBox.renderCache?.offsetX).toBe(0)
|
|
52
|
+
expect(fpTextBox.renderCache?.offsetY).toBeUndefined()
|
|
53
|
+
|
|
54
|
+
fpTextBox.locked = false
|
|
55
|
+
|
|
56
|
+
expect(fpTextBox.getString()).toMatchInlineSnapshot(`
|
|
57
|
+
"(fp_text_box
|
|
58
|
+
\"Notes\"
|
|
59
|
+
(start 0 0)
|
|
60
|
+
(end 10 5)
|
|
61
|
+
(pts
|
|
62
|
+
(xy 0 0)
|
|
63
|
+
(xy 10 0)
|
|
64
|
+
(xy 10 5)
|
|
65
|
+
(xy 0 5)
|
|
66
|
+
)
|
|
67
|
+
(angle 45)
|
|
68
|
+
(layer F.SilkS)
|
|
69
|
+
(effects
|
|
70
|
+
(font
|
|
71
|
+
(size 1 1)
|
|
72
|
+
(thickness 0.15)
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
(stroke
|
|
76
|
+
(width 0.1)
|
|
77
|
+
(type solid)
|
|
78
|
+
(color 0 0 0 1)
|
|
79
|
+
)
|
|
80
|
+
(uuid 11111111-2222-3333-4444-555555555555)
|
|
81
|
+
(render_cache \"Notes text\" 0 0)
|
|
82
|
+
)"
|
|
83
|
+
`)
|
|
84
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { At, Image, ImageData, ImageScale, Layer, SxClass, Uuid } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("Image", () => {
|
|
5
|
+
const [image] = SxClass.parse(`
|
|
6
|
+
(image
|
|
7
|
+
(at 12.7 25.4 90)
|
|
8
|
+
(scale 0.75)
|
|
9
|
+
(layer F.SilkS B.SilkS)
|
|
10
|
+
(uuid 12345678-1234-1234-1234-123456789abc)
|
|
11
|
+
(data iVBORw0KGgoAAAANSUhEUgAAAAUA)
|
|
12
|
+
)
|
|
13
|
+
`)
|
|
14
|
+
|
|
15
|
+
expect(image).toBeInstanceOf(Image)
|
|
16
|
+
const img = image as Image
|
|
17
|
+
|
|
18
|
+
const at = img.position as At
|
|
19
|
+
expect(at.x).toBe(12.7)
|
|
20
|
+
expect(at.y).toBe(25.4)
|
|
21
|
+
expect(at.angle).toBe(90)
|
|
22
|
+
|
|
23
|
+
const scale = img.scale as ImageScale
|
|
24
|
+
expect(scale.value).toBe(0.75)
|
|
25
|
+
|
|
26
|
+
const layer = img.layer as Layer
|
|
27
|
+
expect(layer.names).toEqual(["F.SilkS", "B.SilkS"])
|
|
28
|
+
|
|
29
|
+
const uuid = img.uuid as Uuid
|
|
30
|
+
expect(uuid.value).toBe("12345678-1234-1234-1234-123456789abc")
|
|
31
|
+
|
|
32
|
+
const data = img.data as ImageData
|
|
33
|
+
expect(data.value).toBe("iVBORw0KGgoAAAANSUhEUgAAAAUA")
|
|
34
|
+
|
|
35
|
+
img.scale = 1.2
|
|
36
|
+
img.layer = "F.Cu"
|
|
37
|
+
img.uuid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
|
38
|
+
img.data = "ZGF0YQ=="
|
|
39
|
+
img.position = new At([0, 0])
|
|
40
|
+
|
|
41
|
+
expect(img.getString()).toMatchInlineSnapshot(`
|
|
42
|
+
"(image
|
|
43
|
+
(at 0 0)
|
|
44
|
+
(scale 1.2)
|
|
45
|
+
(layer F.Cu)
|
|
46
|
+
(uuid aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)
|
|
47
|
+
(data \"ZGF0YQ==\")
|
|
48
|
+
)"
|
|
49
|
+
`)
|
|
50
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KicadSch,
|
|
3
|
+
Paper,
|
|
4
|
+
Property,
|
|
5
|
+
SchematicSymbol,
|
|
6
|
+
Sheet,
|
|
7
|
+
SxClass,
|
|
8
|
+
TitleBlock,
|
|
9
|
+
Wire,
|
|
10
|
+
} from "lib/sexpr"
|
|
11
|
+
import { expect, test } from "bun:test"
|
|
12
|
+
|
|
13
|
+
test("KicadSch parse", () => {
|
|
14
|
+
const [parsed] = SxClass.parse(`
|
|
15
|
+
(kicad_sch
|
|
16
|
+
(version 20240101)
|
|
17
|
+
(generator kicad-cli)
|
|
18
|
+
(uuid 01234567-89ab-cdef-0123-456789abcdef)
|
|
19
|
+
(paper A4)
|
|
20
|
+
(title_block
|
|
21
|
+
(title "Demo")
|
|
22
|
+
(company "Example Co")
|
|
23
|
+
)
|
|
24
|
+
(property "Sheetfile" "demo.kicad_sch")
|
|
25
|
+
(sheet
|
|
26
|
+
(at 0 0 0)
|
|
27
|
+
(size 100 80)
|
|
28
|
+
(uuid abcdefab-1234-5678-90ab-abcdefabcdef)
|
|
29
|
+
)
|
|
30
|
+
(symbol "Device:R"
|
|
31
|
+
(at 25.4 12.7)
|
|
32
|
+
(uuid fedcba98-7654-3210-fedc-ba9876543210)
|
|
33
|
+
)
|
|
34
|
+
(wire (pts (xy 0 0) (xy 10 10)))
|
|
35
|
+
)
|
|
36
|
+
`)
|
|
37
|
+
|
|
38
|
+
expect(parsed).toBeInstanceOf(KicadSch)
|
|
39
|
+
const schematic = parsed as KicadSch
|
|
40
|
+
|
|
41
|
+
expect(schematic.version).toBe(20240101)
|
|
42
|
+
expect(schematic.generator).toBe("kicad-cli")
|
|
43
|
+
expect(schematic.uuid?.value).toBe(
|
|
44
|
+
"01234567-89ab-cdef-0123-456789abcdef",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expect(schematic.paper).toBeInstanceOf(Paper)
|
|
48
|
+
expect(schematic.titleBlock).toBeInstanceOf(TitleBlock)
|
|
49
|
+
expect(schematic.titleBlock?.title).toBe("Demo")
|
|
50
|
+
expect(schematic.titleBlock?.company).toBe("Example Co")
|
|
51
|
+
|
|
52
|
+
expect(schematic.properties).toHaveLength(1)
|
|
53
|
+
expect(schematic.properties[0]).toBeInstanceOf(Property)
|
|
54
|
+
expect(schematic.properties[0]?.key).toBe("Sheetfile")
|
|
55
|
+
expect(schematic.properties[0]?.value).toBe("demo.kicad_sch")
|
|
56
|
+
|
|
57
|
+
expect(schematic.sheets).toHaveLength(1)
|
|
58
|
+
expect(schematic.sheets[0]).toBeInstanceOf(Sheet)
|
|
59
|
+
|
|
60
|
+
expect(schematic.symbols).toHaveLength(1)
|
|
61
|
+
expect(schematic.symbols[0]).toBeInstanceOf(SchematicSymbol)
|
|
62
|
+
|
|
63
|
+
expect(schematic.wires).toHaveLength(1)
|
|
64
|
+
expect(schematic.wires[0]).toBeInstanceOf(Wire)
|
|
65
|
+
|
|
66
|
+
expect(schematic.getString()).toMatchInlineSnapshot(`
|
|
67
|
+
"(kicad_sch
|
|
68
|
+
(version 20240101)
|
|
69
|
+
(generator kicad-cli)
|
|
70
|
+
(uuid 01234567-89ab-cdef-0123-456789abcdef)
|
|
71
|
+
(paper
|
|
72
|
+
A4
|
|
73
|
+
)
|
|
74
|
+
(title_block
|
|
75
|
+
(title "Demo")
|
|
76
|
+
(company "Example Co")
|
|
77
|
+
)
|
|
78
|
+
(property "Sheetfile" "demo.kicad_sch"
|
|
79
|
+
)
|
|
80
|
+
(sheet
|
|
81
|
+
(at 0 0 0)
|
|
82
|
+
(size 100 80)
|
|
83
|
+
(uuid abcdefab-1234-5678-90ab-abcdefabcdef)
|
|
84
|
+
)
|
|
85
|
+
(symbol "Device:R"
|
|
86
|
+
(at 25.4 12.7)
|
|
87
|
+
(uuid fedcba98-7654-3210-fedc-ba9876543210)
|
|
88
|
+
)
|
|
89
|
+
(wire
|
|
90
|
+
(pts
|
|
91
|
+
(xy 0 0)
|
|
92
|
+
(xy 10 10)
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
)"
|
|
96
|
+
`)
|
|
97
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Paper, SxClass } from "lib/sexpr"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
|
|
4
|
+
test("Paper standard size", () => {
|
|
5
|
+
const [paper] = SxClass.parse(`
|
|
6
|
+
(paper
|
|
7
|
+
A4
|
|
8
|
+
portrait
|
|
9
|
+
)
|
|
10
|
+
`)
|
|
11
|
+
|
|
12
|
+
expect(paper).toBeInstanceOf(Paper)
|
|
13
|
+
|
|
14
|
+
const page = paper as Paper
|
|
15
|
+
expect(page.size).toBe("A4")
|
|
16
|
+
expect(page.customSize).toBeUndefined()
|
|
17
|
+
expect(page.isPortrait).toBe(true)
|
|
18
|
+
|
|
19
|
+
page.isPortrait = false
|
|
20
|
+
page.customSize = { width: 210, height: 297 }
|
|
21
|
+
|
|
22
|
+
expect(page.size).toBeUndefined()
|
|
23
|
+
expect(page.customSize).toEqual({ width: 210, height: 297 })
|
|
24
|
+
|
|
25
|
+
expect(page.getString()).toMatchInlineSnapshot(`
|
|
26
|
+
"(paper
|
|
27
|
+
210 297
|
|
28
|
+
)"
|
|
29
|
+
`)
|
|
30
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { At, Property, SxClass } from "lib/sexpr"
|
|
3
|
+
import { parseToPrimitiveSExpr } from "lib/sexpr/parseToPrimitiveSExpr"
|
|
4
|
+
import { expectEqualPrimitiveSExpr } from "../../fixtures/expectEqualPrimitiveSExpr"
|
|
5
|
+
|
|
6
|
+
test("Property preserves extended attributes", () => {
|
|
7
|
+
const input = `
|
|
8
|
+
(property "Reference" "R1"
|
|
9
|
+
(at 1 2 90)
|
|
10
|
+
(unlocked yes)
|
|
11
|
+
(layer "F.SilkS")
|
|
12
|
+
(hide yes)
|
|
13
|
+
(uuid 12345678-1234-1234-1234-123456789abc)
|
|
14
|
+
(effects
|
|
15
|
+
(font
|
|
16
|
+
(size 1 1)
|
|
17
|
+
(thickness 0.15)
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
const [parsed] = SxClass.parse(input)
|
|
24
|
+
expect(parsed).toBeInstanceOf(Property)
|
|
25
|
+
|
|
26
|
+
const property = parsed as Property
|
|
27
|
+
expect(property.key).toBe("Reference")
|
|
28
|
+
expect(property.value).toBe("R1")
|
|
29
|
+
const position = property.position
|
|
30
|
+
expect(position).toBeInstanceOf(At)
|
|
31
|
+
if (position instanceof At) {
|
|
32
|
+
expect(position.x).toBe(1)
|
|
33
|
+
expect(position.y).toBe(2)
|
|
34
|
+
expect(position.angle).toBe(90)
|
|
35
|
+
}
|
|
36
|
+
expect(property.unlocked).toBe(true)
|
|
37
|
+
expect(property.layer?.names).toEqual(["F.SilkS"])
|
|
38
|
+
expect(property.hidden).toBe(true)
|
|
39
|
+
expect(property.uuid?.value).toBe("12345678-1234-1234-1234-123456789abc")
|
|
40
|
+
expect(property.effects).toBeDefined()
|
|
41
|
+
|
|
42
|
+
const roundTrip = property.getString()
|
|
43
|
+
|
|
44
|
+
const originalPrimitive = parseToPrimitiveSExpr(input)
|
|
45
|
+
const roundTripPrimitive = parseToPrimitiveSExpr(roundTrip)
|
|
46
|
+
|
|
47
|
+
expectEqualPrimitiveSExpr(roundTripPrimitive, originalPrimitive)
|
|
48
|
+
})
|