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,254 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { Width } from "./Width"
4
+ import { toNumberValue } from "../utils/toNumberValue"
5
+
6
+ const SUPPORTED_TOKENS = new Set(["start", "mid", "end", "width"])
7
+
8
+ export class PadPrimitiveGrArc extends SxClass {
9
+ static override token = "gr_arc"
10
+ static override parentToken = "primitives"
11
+ override token = "gr_arc"
12
+
13
+ private _sxStart?: PadPrimitiveGrArcStart
14
+ private _sxMid?: PadPrimitiveGrArcMid
15
+ private _sxEnd?: PadPrimitiveGrArcEnd
16
+ private _sxWidth?: Width
17
+
18
+ static override fromSexprPrimitives(
19
+ primitiveSexprs: PrimitiveSExpr[],
20
+ ): PadPrimitiveGrArc {
21
+ const arc = new PadPrimitiveGrArc()
22
+
23
+ const { propertyMap, arrayPropertyMap } =
24
+ SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
25
+
26
+ for (const token of Object.keys(propertyMap)) {
27
+ if (!SUPPORTED_TOKENS.has(token)) {
28
+ throw new Error(
29
+ `pad primitive gr_arc encountered unsupported child token "${token}"`,
30
+ )
31
+ }
32
+ }
33
+
34
+ for (const [token, entries] of Object.entries(arrayPropertyMap)) {
35
+ if (!SUPPORTED_TOKENS.has(token)) {
36
+ throw new Error(
37
+ `pad primitive gr_arc encountered unsupported child token "${token}"`,
38
+ )
39
+ }
40
+ if (entries.length > 1) {
41
+ throw new Error(
42
+ `pad primitive gr_arc does not support repeated "${token}" tokens`,
43
+ )
44
+ }
45
+ }
46
+
47
+ arc._sxStart = propertyMap.start as PadPrimitiveGrArcStart | undefined
48
+ arc._sxMid = propertyMap.mid as PadPrimitiveGrArcMid | undefined
49
+ arc._sxEnd = propertyMap.end as PadPrimitiveGrArcEnd | undefined
50
+ arc._sxWidth = propertyMap.width as Width | undefined
51
+
52
+ if (!arc._sxStart) {
53
+ throw new Error("pad primitive gr_arc requires a start child token")
54
+ }
55
+ if (!arc._sxMid) {
56
+ throw new Error("pad primitive gr_arc requires a mid child token")
57
+ }
58
+ if (!arc._sxEnd) {
59
+ throw new Error("pad primitive gr_arc requires an end child token")
60
+ }
61
+
62
+ return arc
63
+ }
64
+
65
+ get start(): PadPrimitiveGrArcStart | undefined {
66
+ return this._sxStart
67
+ }
68
+
69
+ set start(
70
+ value: PadPrimitiveGrArcStart | { x: number; y: number } | undefined,
71
+ ) {
72
+ this._sxStart = normalizeArcPoint(value, PadPrimitiveGrArcStart)
73
+ }
74
+
75
+ get mid(): PadPrimitiveGrArcMid | undefined {
76
+ return this._sxMid
77
+ }
78
+
79
+ set mid(value: PadPrimitiveGrArcMid | { x: number; y: number } | undefined) {
80
+ this._sxMid = normalizeArcPoint(value, PadPrimitiveGrArcMid)
81
+ }
82
+
83
+ get end(): PadPrimitiveGrArcEnd | undefined {
84
+ return this._sxEnd
85
+ }
86
+
87
+ set end(value: PadPrimitiveGrArcEnd | { x: number; y: number } | undefined) {
88
+ this._sxEnd = normalizeArcPoint(value, PadPrimitiveGrArcEnd)
89
+ }
90
+
91
+ get width(): number | undefined {
92
+ return this._sxWidth?.value
93
+ }
94
+
95
+ set width(value: Width | number | undefined) {
96
+ if (value === undefined) {
97
+ this._sxWidth = undefined
98
+ return
99
+ }
100
+ this._sxWidth = value instanceof Width ? value : new Width(value)
101
+ }
102
+
103
+ get widthClass(): Width | undefined {
104
+ return this._sxWidth
105
+ }
106
+
107
+ override getChildren(): SxClass[] {
108
+ const children: SxClass[] = []
109
+ if (this._sxStart) children.push(this._sxStart)
110
+ if (this._sxMid) children.push(this._sxMid)
111
+ if (this._sxEnd) children.push(this._sxEnd)
112
+ if (this._sxWidth) children.push(this._sxWidth)
113
+ return children
114
+ }
115
+
116
+ override getString(): string {
117
+ const lines = ["(gr_arc"]
118
+ if (this._sxStart) lines.push(this._sxStart.getStringIndented())
119
+ if (this._sxMid) lines.push(this._sxMid.getStringIndented())
120
+ if (this._sxEnd) lines.push(this._sxEnd.getStringIndented())
121
+ if (this._sxWidth) lines.push(this._sxWidth.getStringIndented())
122
+ lines.push(")")
123
+ return lines.join("\n")
124
+ }
125
+ }
126
+ SxClass.register(PadPrimitiveGrArc)
127
+
128
+ type ArcPointConstructor<T extends PadPrimitiveGrArcPoint> = new (
129
+ x: number,
130
+ y: number,
131
+ ) => T
132
+
133
+ const normalizeArcPoint = <T extends PadPrimitiveGrArcPoint>(
134
+ value: T | { x: number; y: number } | undefined,
135
+ Constructor: ArcPointConstructor<T>,
136
+ ): T | undefined => {
137
+ if (value === undefined) {
138
+ return undefined
139
+ }
140
+ if (value instanceof Constructor) {
141
+ return value
142
+ }
143
+ return new Constructor(value.x, value.y)
144
+ }
145
+
146
+ abstract class PadPrimitiveGrArcPoint extends SxClass {
147
+ protected _x: number
148
+ protected _y: number
149
+
150
+ protected constructor(x: number, y: number) {
151
+ super()
152
+ this._x = x
153
+ this._y = y
154
+ }
155
+
156
+ get x(): number {
157
+ return this._x
158
+ }
159
+
160
+ set x(value: number) {
161
+ this._x = value
162
+ }
163
+
164
+ get y(): number {
165
+ return this._y
166
+ }
167
+
168
+ set y(value: number) {
169
+ this._y = value
170
+ }
171
+
172
+ override getChildren(): SxClass[] {
173
+ return []
174
+ }
175
+
176
+ override getString(): string {
177
+ return `(${this.token} ${this._x} ${this._y})`
178
+ }
179
+ }
180
+
181
+ class PadPrimitiveGrArcStart extends PadPrimitiveGrArcPoint {
182
+ static override token = "start"
183
+ static override parentToken = "gr_arc"
184
+ override token = "start"
185
+
186
+ constructor(x: number, y: number) {
187
+ super(x, y)
188
+ }
189
+
190
+ static override fromSexprPrimitives(
191
+ primitiveSexprs: PrimitiveSExpr[],
192
+ ): PadPrimitiveGrArcStart {
193
+ const [rawX, rawY] = primitiveSexprs
194
+ const x = toNumberValue(rawX)
195
+ const y = toNumberValue(rawY)
196
+
197
+ if (x === undefined || y === undefined) {
198
+ throw new Error("pad primitive gr_arc start expects two numeric arguments")
199
+ }
200
+
201
+ return new PadPrimitiveGrArcStart(x, y)
202
+ }
203
+ }
204
+ SxClass.register(PadPrimitiveGrArcStart)
205
+
206
+ class PadPrimitiveGrArcMid extends PadPrimitiveGrArcPoint {
207
+ static override token = "mid"
208
+ static override parentToken = "gr_arc"
209
+ override token = "mid"
210
+
211
+ constructor(x: number, y: number) {
212
+ super(x, y)
213
+ }
214
+
215
+ static override fromSexprPrimitives(
216
+ primitiveSexprs: PrimitiveSExpr[],
217
+ ): PadPrimitiveGrArcMid {
218
+ const [rawX, rawY] = primitiveSexprs
219
+ const x = toNumberValue(rawX)
220
+ const y = toNumberValue(rawY)
221
+
222
+ if (x === undefined || y === undefined) {
223
+ throw new Error("pad primitive gr_arc mid expects two numeric arguments")
224
+ }
225
+
226
+ return new PadPrimitiveGrArcMid(x, y)
227
+ }
228
+ }
229
+ SxClass.register(PadPrimitiveGrArcMid)
230
+
231
+ class PadPrimitiveGrArcEnd extends PadPrimitiveGrArcPoint {
232
+ static override token = "end"
233
+ static override parentToken = "gr_arc"
234
+ override token = "end"
235
+
236
+ constructor(x: number, y: number) {
237
+ super(x, y)
238
+ }
239
+
240
+ static override fromSexprPrimitives(
241
+ primitiveSexprs: PrimitiveSExpr[],
242
+ ): PadPrimitiveGrArcEnd {
243
+ const [rawX, rawY] = primitiveSexprs
244
+ const x = toNumberValue(rawX)
245
+ const y = toNumberValue(rawY)
246
+
247
+ if (x === undefined || y === undefined) {
248
+ throw new Error("pad primitive gr_arc end expects two numeric arguments")
249
+ }
250
+
251
+ return new PadPrimitiveGrArcEnd(x, y)
252
+ }
253
+ }
254
+ SxClass.register(PadPrimitiveGrArcEnd)
@@ -0,0 +1,279 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
3
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
4
+ import { Width } from "./Width"
5
+ import { toNumberValue } from "../utils/toNumberValue"
6
+
7
+ const SUPPORTED_TOKENS = new Set(["center", "end", "width", "fill"])
8
+
9
+ export class PadPrimitiveGrCircle extends SxClass {
10
+ static override token = "gr_circle"
11
+ static override parentToken = "primitives"
12
+ override token = "gr_circle"
13
+
14
+ private _sxCenter?: PadPrimitiveGrCircleCenter
15
+ private _sxEnd?: PadPrimitiveGrCircleEnd
16
+ private _sxWidth?: Width
17
+ private _sxFill?: PadPrimitiveGrCircleFill
18
+
19
+ static override fromSexprPrimitives(
20
+ primitiveSexprs: PrimitiveSExpr[],
21
+ ): PadPrimitiveGrCircle {
22
+ const circle = new PadPrimitiveGrCircle()
23
+
24
+ const { propertyMap, arrayPropertyMap } =
25
+ SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
26
+
27
+ for (const token of Object.keys(propertyMap)) {
28
+ if (!SUPPORTED_TOKENS.has(token)) {
29
+ throw new Error(
30
+ `pad primitive gr_circle encountered unsupported child token "${token}"`,
31
+ )
32
+ }
33
+ }
34
+
35
+ for (const [token, entries] of Object.entries(arrayPropertyMap)) {
36
+ if (!SUPPORTED_TOKENS.has(token)) {
37
+ throw new Error(
38
+ `pad primitive gr_circle encountered unsupported child token "${token}"`,
39
+ )
40
+ }
41
+ if (entries.length > 1) {
42
+ throw new Error(
43
+ `pad primitive gr_circle does not support repeated "${token}" tokens`,
44
+ )
45
+ }
46
+ }
47
+
48
+ circle._sxCenter = propertyMap.center as
49
+ | PadPrimitiveGrCircleCenter
50
+ | undefined
51
+ circle._sxEnd = propertyMap.end as PadPrimitiveGrCircleEnd | undefined
52
+ circle._sxWidth = propertyMap.width as Width | undefined
53
+ circle._sxFill = propertyMap.fill as PadPrimitiveGrCircleFill | undefined
54
+
55
+ if (!circle._sxCenter) {
56
+ throw new Error("pad primitive gr_circle requires a center child token")
57
+ }
58
+ if (!circle._sxEnd) {
59
+ throw new Error("pad primitive gr_circle requires an end child token")
60
+ }
61
+
62
+ return circle
63
+ }
64
+
65
+ get center(): PadPrimitiveGrCircleCenter | undefined {
66
+ return this._sxCenter
67
+ }
68
+
69
+ set center(
70
+ value: PadPrimitiveGrCircleCenter | { x: number; y: number } | undefined,
71
+ ) {
72
+ this._sxCenter = normalizeCirclePoint(value, PadPrimitiveGrCircleCenter)
73
+ }
74
+
75
+ get end(): PadPrimitiveGrCircleEnd | undefined {
76
+ return this._sxEnd
77
+ }
78
+
79
+ set end(value: PadPrimitiveGrCircleEnd | { x: number; y: number } | undefined) {
80
+ this._sxEnd = normalizeCirclePoint(value, PadPrimitiveGrCircleEnd)
81
+ }
82
+
83
+ get width(): number | undefined {
84
+ return this._sxWidth?.value
85
+ }
86
+
87
+ set width(value: Width | number | undefined) {
88
+ if (value === undefined) {
89
+ this._sxWidth = undefined
90
+ return
91
+ }
92
+ this._sxWidth = value instanceof Width ? value : new Width(value)
93
+ }
94
+
95
+ get widthClass(): Width | undefined {
96
+ return this._sxWidth
97
+ }
98
+
99
+ get fill(): boolean | undefined {
100
+ return this._sxFill?.value
101
+ }
102
+
103
+ set fill(value: PadPrimitiveGrCircleFill | boolean | undefined) {
104
+ if (value === undefined) {
105
+ this._sxFill = undefined
106
+ return
107
+ }
108
+ this._sxFill =
109
+ value instanceof PadPrimitiveGrCircleFill
110
+ ? value
111
+ : new PadPrimitiveGrCircleFill(value)
112
+ }
113
+
114
+ get fillClass(): PadPrimitiveGrCircleFill | undefined {
115
+ return this._sxFill
116
+ }
117
+
118
+ override getChildren(): SxClass[] {
119
+ const children: SxClass[] = []
120
+ if (this._sxCenter) children.push(this._sxCenter)
121
+ if (this._sxEnd) children.push(this._sxEnd)
122
+ if (this._sxWidth) children.push(this._sxWidth)
123
+ if (this._sxFill) children.push(this._sxFill)
124
+ return children
125
+ }
126
+
127
+ override getString(): string {
128
+ const lines = ["(gr_circle"]
129
+ if (this._sxCenter) lines.push(this._sxCenter.getStringIndented())
130
+ if (this._sxEnd) lines.push(this._sxEnd.getStringIndented())
131
+ if (this._sxWidth) lines.push(this._sxWidth.getStringIndented())
132
+ if (this._sxFill) lines.push(this._sxFill.getStringIndented())
133
+ lines.push(")")
134
+ return lines.join("\n")
135
+ }
136
+ }
137
+ SxClass.register(PadPrimitiveGrCircle)
138
+
139
+ type CirclePointConstructor<T extends PadPrimitiveGrCirclePoint> = new (
140
+ x: number,
141
+ y: number,
142
+ ) => T
143
+
144
+ const normalizeCirclePoint = <T extends PadPrimitiveGrCirclePoint>(
145
+ value: T | { x: number; y: number } | undefined,
146
+ Constructor: CirclePointConstructor<T>,
147
+ ): T | undefined => {
148
+ if (value === undefined) {
149
+ return undefined
150
+ }
151
+ if (value instanceof Constructor) {
152
+ return value
153
+ }
154
+ return new Constructor(value.x, value.y)
155
+ }
156
+
157
+ abstract class PadPrimitiveGrCirclePoint extends SxClass {
158
+ protected _x: number
159
+ protected _y: number
160
+
161
+ protected constructor(x: number, y: number) {
162
+ super()
163
+ this._x = x
164
+ this._y = y
165
+ }
166
+
167
+ get x(): number {
168
+ return this._x
169
+ }
170
+
171
+ set x(value: number) {
172
+ this._x = value
173
+ }
174
+
175
+ get y(): number {
176
+ return this._y
177
+ }
178
+
179
+ set y(value: number) {
180
+ this._y = value
181
+ }
182
+
183
+ override getChildren(): SxClass[] {
184
+ return []
185
+ }
186
+
187
+ override getString(): string {
188
+ return `(${this.token} ${this._x} ${this._y})`
189
+ }
190
+ }
191
+
192
+ class PadPrimitiveGrCircleCenter extends PadPrimitiveGrCirclePoint {
193
+ static override token = "center"
194
+ static override parentToken = "gr_circle"
195
+ override token = "center"
196
+
197
+ constructor(x: number, y: number) {
198
+ super(x, y)
199
+ }
200
+
201
+ static override fromSexprPrimitives(
202
+ primitiveSexprs: PrimitiveSExpr[],
203
+ ): PadPrimitiveGrCircleCenter {
204
+ const [rawX, rawY] = primitiveSexprs
205
+ const x = toNumberValue(rawX)
206
+ const y = toNumberValue(rawY)
207
+
208
+ if (x === undefined || y === undefined) {
209
+ throw new Error(
210
+ "pad primitive gr_circle center expects two numeric arguments",
211
+ )
212
+ }
213
+
214
+ return new PadPrimitiveGrCircleCenter(x, y)
215
+ }
216
+ }
217
+ SxClass.register(PadPrimitiveGrCircleCenter)
218
+
219
+ class PadPrimitiveGrCircleEnd extends PadPrimitiveGrCirclePoint {
220
+ static override token = "end"
221
+ static override parentToken = "gr_circle"
222
+ override token = "end"
223
+
224
+ constructor(x: number, y: number) {
225
+ super(x, y)
226
+ }
227
+
228
+ static override fromSexprPrimitives(
229
+ primitiveSexprs: PrimitiveSExpr[],
230
+ ): PadPrimitiveGrCircleEnd {
231
+ const [rawX, rawY] = primitiveSexprs
232
+ const x = toNumberValue(rawX)
233
+ const y = toNumberValue(rawY)
234
+
235
+ if (x === undefined || y === undefined) {
236
+ throw new Error(
237
+ "pad primitive gr_circle end expects two numeric arguments",
238
+ )
239
+ }
240
+
241
+ return new PadPrimitiveGrCircleEnd(x, y)
242
+ }
243
+ }
244
+ SxClass.register(PadPrimitiveGrCircleEnd)
245
+
246
+ class PadPrimitiveGrCircleFill extends SxPrimitiveBoolean {
247
+ static override token = "fill"
248
+ static override parentToken = "gr_circle"
249
+ override token = "fill"
250
+
251
+ constructor(value?: boolean) {
252
+ super(value ?? false)
253
+ }
254
+
255
+ static override fromSexprPrimitives(
256
+ primitiveSexprs: PrimitiveSExpr[],
257
+ ): PadPrimitiveGrCircleFill {
258
+ const [raw] = primitiveSexprs
259
+ if (raw === undefined) {
260
+ return new PadPrimitiveGrCircleFill(false)
261
+ }
262
+ if (typeof raw === "boolean") {
263
+ return new PadPrimitiveGrCircleFill(raw)
264
+ }
265
+ if (typeof raw === "string") {
266
+ const normalized = raw.toLowerCase()
267
+ if (normalized === "yes" || normalized === "true") {
268
+ return new PadPrimitiveGrCircleFill(true)
269
+ }
270
+ if (normalized === "no" || normalized === "false") {
271
+ return new PadPrimitiveGrCircleFill(false)
272
+ }
273
+ }
274
+ throw new Error(
275
+ `pad primitive gr_circle fill expects yes/no or boolean, received ${JSON.stringify(raw)}`,
276
+ )
277
+ }
278
+ }
279
+ SxClass.register(PadPrimitiveGrCircleFill)
@@ -0,0 +1,126 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { GrLineEnd } from "./GrLineEnd"
4
+ import { GrLineStart } from "./GrLineStart"
5
+ import { Width } from "./Width"
6
+
7
+ const SUPPORTED_TOKENS = new Set(["start", "end", "width"])
8
+
9
+ export class PadPrimitiveGrLine extends SxClass {
10
+ static override token = "gr_line"
11
+ static override parentToken = "primitives"
12
+ override token = "gr_line"
13
+
14
+ private _sxStart?: GrLineStart
15
+ private _sxEnd?: GrLineEnd
16
+ private _sxWidth?: Width
17
+
18
+ static override fromSexprPrimitives(
19
+ primitiveSexprs: PrimitiveSExpr[],
20
+ ): PadPrimitiveGrLine {
21
+ const line = new PadPrimitiveGrLine()
22
+
23
+ const { propertyMap, arrayPropertyMap } =
24
+ SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
25
+
26
+ for (const token of Object.keys(propertyMap)) {
27
+ if (!SUPPORTED_TOKENS.has(token)) {
28
+ throw new Error(
29
+ `pad primitive gr_line encountered unsupported child token "${token}"`,
30
+ )
31
+ }
32
+ }
33
+
34
+ for (const [token, entries] of Object.entries(arrayPropertyMap)) {
35
+ if (!SUPPORTED_TOKENS.has(token)) {
36
+ throw new Error(
37
+ `pad primitive gr_line encountered unsupported child token "${token}"`,
38
+ )
39
+ }
40
+ if (entries.length > 1) {
41
+ throw new Error(
42
+ `pad primitive gr_line does not support repeated "${token}" tokens`,
43
+ )
44
+ }
45
+ }
46
+
47
+ line._sxStart = propertyMap.start as GrLineStart | undefined
48
+ line._sxEnd = propertyMap.end as GrLineEnd | undefined
49
+ line._sxWidth = propertyMap.width as Width | undefined
50
+
51
+ if (!line._sxStart) {
52
+ throw new Error("pad primitive gr_line requires a start child token")
53
+ }
54
+ if (!line._sxEnd) {
55
+ throw new Error("pad primitive gr_line requires an end child token")
56
+ }
57
+
58
+ return line
59
+ }
60
+
61
+ get start(): GrLineStart | undefined {
62
+ return this._sxStart
63
+ }
64
+
65
+ set start(value: GrLineStart | { x: number; y: number } | undefined) {
66
+ if (value === undefined) {
67
+ this._sxStart = undefined
68
+ return
69
+ }
70
+ if (value instanceof GrLineStart) {
71
+ this._sxStart = value
72
+ return
73
+ }
74
+ this._sxStart = new GrLineStart(value.x, value.y)
75
+ }
76
+
77
+ get end(): GrLineEnd | undefined {
78
+ return this._sxEnd
79
+ }
80
+
81
+ set end(value: GrLineEnd | { x: number; y: number } | undefined) {
82
+ if (value === undefined) {
83
+ this._sxEnd = undefined
84
+ return
85
+ }
86
+ if (value instanceof GrLineEnd) {
87
+ this._sxEnd = value
88
+ return
89
+ }
90
+ this._sxEnd = new GrLineEnd(value.x, value.y)
91
+ }
92
+
93
+ get width(): number | undefined {
94
+ return this._sxWidth?.value
95
+ }
96
+
97
+ set width(value: Width | number | undefined) {
98
+ if (value === undefined) {
99
+ this._sxWidth = undefined
100
+ return
101
+ }
102
+ this._sxWidth = value instanceof Width ? value : new Width(value)
103
+ }
104
+
105
+ get widthClass(): Width | undefined {
106
+ return this._sxWidth
107
+ }
108
+
109
+ override getChildren(): SxClass[] {
110
+ const children: SxClass[] = []
111
+ if (this._sxStart) children.push(this._sxStart)
112
+ if (this._sxEnd) children.push(this._sxEnd)
113
+ if (this._sxWidth) children.push(this._sxWidth)
114
+ return children
115
+ }
116
+
117
+ override getString(): string {
118
+ const lines = ["(gr_line"]
119
+ if (this._sxStart) lines.push(this._sxStart.getStringIndented())
120
+ if (this._sxEnd) lines.push(this._sxEnd.getStringIndented())
121
+ if (this._sxWidth) lines.push(this._sxWidth.getStringIndented())
122
+ lines.push(")")
123
+ return lines.join("\n")
124
+ }
125
+ }
126
+ SxClass.register(PadPrimitiveGrLine)