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.
Files changed (188) hide show
  1. package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
  2. package/.vscode/settings.json +16 -0
  3. package/AGENTS.md +30 -0
  4. package/README.md +206 -0
  5. package/biome.json +93 -0
  6. package/bun.lock +48 -0
  7. package/bunfig.toml +5 -0
  8. package/lib/index.ts +1 -0
  9. package/lib/sexpr/base-classes/SxClass.ts +164 -0
  10. package/lib/sexpr/base-classes/SxPrimitiveBoolean.ts +35 -0
  11. package/lib/sexpr/base-classes/SxPrimitiveNumber.ts +26 -0
  12. package/lib/sexpr/base-classes/SxPrimitiveString.ts +26 -0
  13. package/lib/sexpr/classes/At.ts +38 -0
  14. package/lib/sexpr/classes/Bus.ts +83 -0
  15. package/lib/sexpr/classes/BusEntry.ts +142 -0
  16. package/lib/sexpr/classes/Color.ts +29 -0
  17. package/lib/sexpr/classes/Dnp.ts +8 -0
  18. package/lib/sexpr/classes/EmbeddedFonts.ts +70 -0
  19. package/lib/sexpr/classes/ExcludeFromSim.ts +8 -0
  20. package/lib/sexpr/classes/FieldsAutoplaced.ts +8 -0
  21. package/lib/sexpr/classes/Footprint.ts +719 -0
  22. package/lib/sexpr/classes/FootprintAttr.ts +102 -0
  23. package/lib/sexpr/classes/FootprintAutoplaceCost180.ts +9 -0
  24. package/lib/sexpr/classes/FootprintAutoplaceCost90.ts +9 -0
  25. package/lib/sexpr/classes/FootprintClearance.ts +9 -0
  26. package/lib/sexpr/classes/FootprintDescr.ts +44 -0
  27. package/lib/sexpr/classes/FootprintLocked.ts +32 -0
  28. package/lib/sexpr/classes/FootprintModel.ts +145 -0
  29. package/lib/sexpr/classes/FootprintNetTiePadGroups.ts +50 -0
  30. package/lib/sexpr/classes/FootprintPad.ts +705 -0
  31. package/lib/sexpr/classes/FootprintPath.ts +44 -0
  32. package/lib/sexpr/classes/FootprintPlaced.ts +32 -0
  33. package/lib/sexpr/classes/FootprintPrivateLayers.ts +56 -0
  34. package/lib/sexpr/classes/FootprintSheetfile.ts +44 -0
  35. package/lib/sexpr/classes/FootprintSheetname.ts +44 -0
  36. package/lib/sexpr/classes/FootprintSolderMaskMargin.ts +9 -0
  37. package/lib/sexpr/classes/FootprintSolderPasteMargin.ts +9 -0
  38. package/lib/sexpr/classes/FootprintSolderPasteRatio.ts +9 -0
  39. package/lib/sexpr/classes/FootprintTags.ts +44 -0
  40. package/lib/sexpr/classes/FootprintTedit.ts +21 -0
  41. package/lib/sexpr/classes/FootprintThermalGap.ts +9 -0
  42. package/lib/sexpr/classes/FootprintThermalWidth.ts +9 -0
  43. package/lib/sexpr/classes/FootprintZoneConnect.ts +9 -0
  44. package/lib/sexpr/classes/FpArc.ts +289 -0
  45. package/lib/sexpr/classes/FpCircle.ts +293 -0
  46. package/lib/sexpr/classes/FpLine.ts +288 -0
  47. package/lib/sexpr/classes/FpPoly.ts +266 -0
  48. package/lib/sexpr/classes/FpPolyFill.ts +48 -0
  49. package/lib/sexpr/classes/FpPolyLocked.ts +40 -0
  50. package/lib/sexpr/classes/FpRect.ts +293 -0
  51. package/lib/sexpr/classes/FpText.ts +341 -0
  52. package/lib/sexpr/classes/FpTextBox.ts +412 -0
  53. package/lib/sexpr/classes/GrLine.ts +245 -0
  54. package/lib/sexpr/classes/GrLineAngle.ts +32 -0
  55. package/lib/sexpr/classes/GrLineEnd.ts +61 -0
  56. package/lib/sexpr/classes/GrLineLocked.ts +40 -0
  57. package/lib/sexpr/classes/GrLineStart.ts +61 -0
  58. package/lib/sexpr/classes/GrText.ts +202 -0
  59. package/lib/sexpr/classes/Image.ts +256 -0
  60. package/lib/sexpr/classes/InBom.ts +8 -0
  61. package/lib/sexpr/classes/Junction.ts +134 -0
  62. package/lib/sexpr/classes/KicadPcb.ts +313 -0
  63. package/lib/sexpr/classes/KicadSch.ts +303 -0
  64. package/lib/sexpr/classes/KicadSchGenerator.ts +32 -0
  65. package/lib/sexpr/classes/KicadSchGeneratorVersion.ts +30 -0
  66. package/lib/sexpr/classes/KicadSchVersion.ts +22 -0
  67. package/lib/sexpr/classes/Label.ts +136 -0
  68. package/lib/sexpr/classes/Layer.ts +51 -0
  69. package/lib/sexpr/classes/Layers.ts +47 -0
  70. package/lib/sexpr/classes/LibSymbols.ts +61 -0
  71. package/lib/sexpr/classes/NoConnect.ts +73 -0
  72. package/lib/sexpr/classes/OnBoard.ts +8 -0
  73. package/lib/sexpr/classes/PadChamfer.ts +50 -0
  74. package/lib/sexpr/classes/PadChamferRatio.ts +9 -0
  75. package/lib/sexpr/classes/PadClearance.ts +9 -0
  76. package/lib/sexpr/classes/PadDieLength.ts +9 -0
  77. package/lib/sexpr/classes/PadDrill.ts +145 -0
  78. package/lib/sexpr/classes/PadDrillOffset.ts +54 -0
  79. package/lib/sexpr/classes/PadLayers.ts +59 -0
  80. package/lib/sexpr/classes/PadNet.ts +56 -0
  81. package/lib/sexpr/classes/PadOptions.ts +182 -0
  82. package/lib/sexpr/classes/PadPinFunction.ts +9 -0
  83. package/lib/sexpr/classes/PadPinType.ts +9 -0
  84. package/lib/sexpr/classes/PadPrimitiveGrArc.ts +254 -0
  85. package/lib/sexpr/classes/PadPrimitiveGrCircle.ts +279 -0
  86. package/lib/sexpr/classes/PadPrimitiveGrLine.ts +126 -0
  87. package/lib/sexpr/classes/PadPrimitives.ts +289 -0
  88. package/lib/sexpr/classes/PadRectDelta.ts +57 -0
  89. package/lib/sexpr/classes/PadRoundrectRratio.ts +9 -0
  90. package/lib/sexpr/classes/PadSize.ts +54 -0
  91. package/lib/sexpr/classes/PadSolderMaskMargin.ts +9 -0
  92. package/lib/sexpr/classes/PadSolderPasteMargin.ts +9 -0
  93. package/lib/sexpr/classes/PadSolderPasteMarginRatio.ts +9 -0
  94. package/lib/sexpr/classes/PadTeardrops.ts +208 -0
  95. package/lib/sexpr/classes/PadThermalBridgeAngle.ts +9 -0
  96. package/lib/sexpr/classes/PadThermalGap.ts +9 -0
  97. package/lib/sexpr/classes/PadThermalWidth.ts +9 -0
  98. package/lib/sexpr/classes/PadZoneConnect.ts +9 -0
  99. package/lib/sexpr/classes/Paper.ts +119 -0
  100. package/lib/sexpr/classes/PcbGeneral.ts +75 -0
  101. package/lib/sexpr/classes/PcbGeneralLegacyTeardrops.ts +44 -0
  102. package/lib/sexpr/classes/PcbGeneralThickness.ts +9 -0
  103. package/lib/sexpr/classes/PcbGenerator.ts +16 -0
  104. package/lib/sexpr/classes/PcbGeneratorVersion.ts +16 -0
  105. package/lib/sexpr/classes/PcbLayerDefinition.ts +102 -0
  106. package/lib/sexpr/classes/PcbLayers.ts +34 -0
  107. package/lib/sexpr/classes/PcbNet.ts +56 -0
  108. package/lib/sexpr/classes/PcbVersion.ts +9 -0
  109. package/lib/sexpr/classes/Property.ts +246 -0
  110. package/lib/sexpr/classes/PropertyHide.ts +9 -0
  111. package/lib/sexpr/classes/PropertyUnlocked.ts +9 -0
  112. package/lib/sexpr/classes/Pts.ts +65 -0
  113. package/lib/sexpr/classes/RenderCache.ts +221 -0
  114. package/lib/sexpr/classes/SchematicText.ts +141 -0
  115. package/lib/sexpr/classes/Segment.ts +222 -0
  116. package/lib/sexpr/classes/SegmentEnd.ts +59 -0
  117. package/lib/sexpr/classes/SegmentLocked.ts +33 -0
  118. package/lib/sexpr/classes/SegmentNet.ts +62 -0
  119. package/lib/sexpr/classes/SegmentStart.ts +59 -0
  120. package/lib/sexpr/classes/Setup/PcbPlotParams.ts +729 -0
  121. package/lib/sexpr/classes/Setup/PcbPlotParamsBase.ts +9 -0
  122. package/lib/sexpr/classes/Setup/PcbPlotParamsNumericProperties.ts +105 -0
  123. package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesA.ts +104 -0
  124. package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesB.ts +105 -0
  125. package/lib/sexpr/classes/Setup/Setup.ts +573 -0
  126. package/lib/sexpr/classes/Setup/SetupPropertyTypes.ts +119 -0
  127. package/lib/sexpr/classes/Setup/Stackup.ts +140 -0
  128. package/lib/sexpr/classes/Setup/StackupLayer.ts +233 -0
  129. package/lib/sexpr/classes/Setup/StackupLayerProperties.ts +78 -0
  130. package/lib/sexpr/classes/Setup/StackupProperties.ts +41 -0
  131. package/lib/sexpr/classes/Setup/base.ts +167 -0
  132. package/lib/sexpr/classes/Setup/index.ts +14 -0
  133. package/lib/sexpr/classes/Setup/setupMultiValueProperties.ts +54 -0
  134. package/lib/sexpr/classes/Setup/setupNumericProperties.ts +151 -0
  135. package/lib/sexpr/classes/Setup/setupPropertyHandlers.ts +90 -0
  136. package/lib/sexpr/classes/Setup/setupStringProperties.ts +75 -0
  137. package/lib/sexpr/classes/Sheet.ts +205 -0
  138. package/lib/sexpr/classes/SheetFill.ts +44 -0
  139. package/lib/sexpr/classes/SheetInstances.ts +168 -0
  140. package/lib/sexpr/classes/SheetInstancesRoot.ts +165 -0
  141. package/lib/sexpr/classes/SheetPin.ts +122 -0
  142. package/lib/sexpr/classes/SheetProperty.ts +115 -0
  143. package/lib/sexpr/classes/SheetSize.ts +44 -0
  144. package/lib/sexpr/classes/Stroke.ts +58 -0
  145. package/lib/sexpr/classes/StrokeType.ts +34 -0
  146. package/lib/sexpr/classes/Symbol.ts +1541 -0
  147. package/lib/sexpr/classes/TextEffects.ts +444 -0
  148. package/lib/sexpr/classes/TitleBlock.ts +352 -0
  149. package/lib/sexpr/classes/Unit.ts +28 -0
  150. package/lib/sexpr/classes/Uuid.ts +8 -0
  151. package/lib/sexpr/classes/Via.ts +328 -0
  152. package/lib/sexpr/classes/ViaNet.ts +59 -0
  153. package/lib/sexpr/classes/Width.ts +8 -0
  154. package/lib/sexpr/classes/Wire.ts +91 -0
  155. package/lib/sexpr/classes/Xy.ts +35 -0
  156. package/lib/sexpr/classes/Zone.ts +41 -0
  157. package/lib/sexpr/index.ts +130 -0
  158. package/lib/sexpr/parseKicadSexpr.ts +5 -0
  159. package/lib/sexpr/parseToPrimitiveSExpr.ts +240 -0
  160. package/lib/sexpr/utils/indentLines.ts +3 -0
  161. package/lib/sexpr/utils/parseYesNo.ts +12 -0
  162. package/lib/sexpr/utils/quoteSExprString.ts +8 -0
  163. package/lib/sexpr/utils/strokeFromArgs.ts +19 -0
  164. package/lib/sexpr/utils/toNumberValue.ts +13 -0
  165. package/lib/sexpr/utils/toStringValue.ts +10 -0
  166. package/package.json +26 -0
  167. package/scripts/download-references.ts +66 -0
  168. package/tests/fixtures/expectEqualPrimitiveSExpr.ts +200 -0
  169. package/tests/sexpr/KicadPcbDemos.test.ts +48 -0
  170. package/tests/sexpr/KicadSchDemos.test.ts +49 -0
  171. package/tests/sexpr/classes/Footprint.test.ts +277 -0
  172. package/tests/sexpr/classes/FootprintPad.test.ts +71 -0
  173. package/tests/sexpr/classes/FpArc.test.ts +45 -0
  174. package/tests/sexpr/classes/FpCircle.test.ts +39 -0
  175. package/tests/sexpr/classes/FpPoly.test.ts +43 -0
  176. package/tests/sexpr/classes/FpRect.test.ts +40 -0
  177. package/tests/sexpr/classes/FpTextBox.test.ts +84 -0
  178. package/tests/sexpr/classes/Image.test.ts +50 -0
  179. package/tests/sexpr/classes/KicadSch.test.ts +97 -0
  180. package/tests/sexpr/classes/Paper.test.ts +30 -0
  181. package/tests/sexpr/classes/Property.test.ts +48 -0
  182. package/tests/sexpr/classes/Setup.test.ts +189 -0
  183. package/tests/sexpr/classes/Sheet.test.ts +107 -0
  184. package/tests/sexpr/classes/Stroke.test.ts +15 -0
  185. package/tests/sexpr/classes/Symbol.test.ts +96 -0
  186. package/tests/sexpr/classes/TextEffects.test.ts +56 -0
  187. package/tests/sexpr/classes/TitleBlock.test.ts +40 -0
  188. 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
+ })