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,266 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { Layer } from "./Layer"
4
+ import { Stroke } from "./Stroke"
5
+ import { Uuid } from "./Uuid"
6
+ import { Width } from "./Width"
7
+ import { Pts } from "./Pts"
8
+ import { Xy } from "./Xy"
9
+ import { FpPolyFill } from "./FpPolyFill"
10
+ import { FpPolyLocked } from "./FpPolyLocked"
11
+
12
+ const SUPPORTED_TOKENS = new Set([
13
+ "pts",
14
+ "xy",
15
+ "layer",
16
+ "width",
17
+ "stroke",
18
+ "fill",
19
+ "locked",
20
+ "uuid",
21
+ ])
22
+
23
+ export class FpPoly extends SxClass {
24
+ static override token = "fp_poly"
25
+ override token = "fp_poly"
26
+
27
+ private _sxPts?: Pts
28
+ private _sxLayer?: Layer
29
+ private _sxWidth?: Width
30
+ private _sxStroke?: Stroke
31
+ private _sxFill?: FpPolyFill
32
+ private _sxLocked?: FpPolyLocked
33
+ private _sxUuid?: Uuid
34
+
35
+ static override fromSexprPrimitives(
36
+ primitiveSexprs: PrimitiveSExpr[],
37
+ ): FpPoly {
38
+ const fpPoly = new FpPoly()
39
+
40
+ const { propertyMap, arrayPropertyMap } =
41
+ SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
42
+
43
+ const unexpectedTokens = new Set<string>()
44
+ for (const token of Object.keys(propertyMap)) {
45
+ if (!SUPPORTED_TOKENS.has(token)) {
46
+ unexpectedTokens.add(token)
47
+ }
48
+ }
49
+ for (const token of Object.keys(arrayPropertyMap)) {
50
+ if (!SUPPORTED_TOKENS.has(token)) {
51
+ unexpectedTokens.add(token)
52
+ }
53
+ if (token !== "xy" && arrayPropertyMap[token]!.length > 1) {
54
+ unexpectedTokens.add(token)
55
+ }
56
+ }
57
+
58
+ if (unexpectedTokens.size > 0) {
59
+ throw new Error(
60
+ `Unsupported child tokens inside fp_poly expression: ${[...unexpectedTokens].join(", ")}`,
61
+ )
62
+ }
63
+
64
+ const ptsEntries = arrayPropertyMap.pts as Pts[] | undefined
65
+ if (ptsEntries && ptsEntries.length > 1) {
66
+ throw new Error("fp_poly does not support repeated pts tokens")
67
+ }
68
+
69
+ const xyEntries = arrayPropertyMap.xy as Xy[] | undefined
70
+ let pts = propertyMap.pts as Pts | undefined
71
+
72
+ if (pts && xyEntries && xyEntries.length > 0) {
73
+ throw new Error("fp_poly cannot mix pts and xy child tokens")
74
+ }
75
+
76
+ if (!pts && ptsEntries?.length) {
77
+ pts = ptsEntries[0]
78
+ }
79
+
80
+ if (!pts && xyEntries && xyEntries.length > 0) {
81
+ pts = new Pts(xyEntries)
82
+ }
83
+
84
+ fpPoly._sxPts = pts
85
+ fpPoly._sxLayer = propertyMap.layer as Layer | undefined
86
+ fpPoly._sxWidth = propertyMap.width as Width | undefined
87
+ fpPoly._sxStroke = propertyMap.stroke as Stroke | undefined
88
+ fpPoly._sxFill = propertyMap.fill as FpPolyFill | undefined
89
+ const lockedClass = propertyMap.locked as FpPolyLocked | undefined
90
+ fpPoly._sxLocked = lockedClass && lockedClass.value ? lockedClass : undefined
91
+ fpPoly._sxUuid = propertyMap.uuid as Uuid | undefined
92
+
93
+ for (const primitive of primitiveSexprs) {
94
+ if (primitive === "locked") {
95
+ if (!fpPoly._sxLocked) {
96
+ fpPoly._sxLocked = new FpPolyLocked(true)
97
+ }
98
+ continue
99
+ }
100
+
101
+ if (!Array.isArray(primitive) || primitive.length === 0) {
102
+ throw new Error(
103
+ `fp_poly encountered unexpected primitive child: ${JSON.stringify(primitive)}`,
104
+ )
105
+ }
106
+
107
+ const [token, ...rest] = primitive
108
+ if (typeof token !== "string") {
109
+ throw new Error(
110
+ `fp_poly child token must be a string, received: ${JSON.stringify(token)}`,
111
+ )
112
+ }
113
+
114
+ if (!SUPPORTED_TOKENS.has(token)) {
115
+ throw new Error(
116
+ `Unsupported child token inside fp_poly expression: ${token}`,
117
+ )
118
+ }
119
+
120
+ if (token === "locked" && !fpPoly._sxLocked) {
121
+ fpPoly._sxLocked = FpPolyLocked.fromSexprPrimitives(
122
+ rest as PrimitiveSExpr[],
123
+ )
124
+ if (!fpPoly._sxLocked.value) {
125
+ fpPoly._sxLocked = undefined
126
+ }
127
+ }
128
+ }
129
+
130
+ if (!fpPoly._sxPts) {
131
+ throw new Error("fp_poly requires pts or xy child tokens")
132
+ }
133
+ if (!fpPoly._sxLayer) {
134
+ throw new Error("fp_poly requires a layer child token")
135
+ }
136
+ if (!fpPoly._sxUuid) {
137
+ throw new Error("fp_poly requires a uuid child token")
138
+ }
139
+
140
+ return fpPoly
141
+ }
142
+
143
+ get points(): Pts | undefined {
144
+ return this._sxPts
145
+ }
146
+
147
+ set points(value: Pts | Xy[] | Array<{ x: number; y: number }> | undefined) {
148
+ if (value === undefined) {
149
+ this._sxPts = undefined
150
+ return
151
+ }
152
+
153
+ if (value instanceof Pts) {
154
+ this._sxPts = value
155
+ return
156
+ }
157
+
158
+ if (Array.isArray(value) && value.every((point) => point instanceof Xy)) {
159
+ this._sxPts = new Pts(value as Xy[])
160
+ return
161
+ }
162
+
163
+ if (Array.isArray(value)) {
164
+ this._sxPts = new Pts(
165
+ value.map(({ x, y }) => new Xy(x, y)),
166
+ )
167
+ return
168
+ }
169
+
170
+ throw new Error("Unsupported points value provided to fp_poly")
171
+ }
172
+
173
+ get layer(): Layer | undefined {
174
+ return this._sxLayer
175
+ }
176
+
177
+ set layer(value: Layer | string | Array<string | number> | undefined) {
178
+ if (value === undefined) {
179
+ this._sxLayer = undefined
180
+ return
181
+ }
182
+ if (value instanceof Layer) {
183
+ this._sxLayer = value
184
+ return
185
+ }
186
+ const names = Array.isArray(value) ? value : [value]
187
+ this._sxLayer = new Layer(names)
188
+ }
189
+
190
+ get width(): number | undefined {
191
+ return this._sxWidth?.value
192
+ }
193
+
194
+ set width(value: Width | number | undefined) {
195
+ if (value === undefined) {
196
+ this._sxWidth = undefined
197
+ return
198
+ }
199
+ this._sxWidth = value instanceof Width ? value : new Width(value)
200
+ }
201
+
202
+ get widthClass(): Width | undefined {
203
+ return this._sxWidth
204
+ }
205
+
206
+ set widthClass(value: Width | undefined) {
207
+ this._sxWidth = value
208
+ }
209
+
210
+ get stroke(): Stroke | undefined {
211
+ return this._sxStroke
212
+ }
213
+
214
+ set stroke(value: Stroke | undefined) {
215
+ this._sxStroke = value
216
+ }
217
+
218
+ get fill(): FpPolyFill | undefined {
219
+ return this._sxFill
220
+ }
221
+
222
+ set fill(value: FpPolyFill | boolean | undefined) {
223
+ if (value === undefined) {
224
+ this._sxFill = undefined
225
+ return
226
+ }
227
+ if (value instanceof FpPolyFill) {
228
+ this._sxFill = value
229
+ return
230
+ }
231
+ this._sxFill = new FpPolyFill(value)
232
+ }
233
+
234
+ get locked(): boolean {
235
+ return this._sxLocked?.value ?? false
236
+ }
237
+
238
+ set locked(value: boolean) {
239
+ this._sxLocked = value ? new FpPolyLocked(true) : undefined
240
+ }
241
+
242
+ get uuid(): Uuid | undefined {
243
+ return this._sxUuid
244
+ }
245
+
246
+ set uuid(value: Uuid | string | undefined) {
247
+ if (value === undefined) {
248
+ this._sxUuid = undefined
249
+ return
250
+ }
251
+ this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
252
+ }
253
+
254
+ override getChildren(): SxClass[] {
255
+ const children: SxClass[] = []
256
+ if (this._sxPts) children.push(this._sxPts)
257
+ if (this._sxLayer) children.push(this._sxLayer)
258
+ if (this._sxWidth) children.push(this._sxWidth)
259
+ if (this._sxStroke) children.push(this._sxStroke)
260
+ if (this._sxFill) children.push(this._sxFill)
261
+ if (this._sxLocked) children.push(this._sxLocked)
262
+ if (this._sxUuid) children.push(this._sxUuid)
263
+ return children
264
+ }
265
+ }
266
+ SxClass.register(FpPoly)
@@ -0,0 +1,48 @@
1
+ import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { SxClass } from "../base-classes/SxClass"
4
+
5
+ const truthyStrings = new Set(["yes", "true", "1"])
6
+
7
+ export class FpPolyFill extends SxPrimitiveBoolean {
8
+ static override token = "fill"
9
+ static override parentToken = "fp_poly"
10
+ override token = "fill"
11
+
12
+ constructor(filled: boolean) {
13
+ super(filled)
14
+ }
15
+
16
+ static override fromSexprPrimitives(
17
+ primitiveSexprs: PrimitiveSExpr[],
18
+ ): FpPolyFill {
19
+ const [rawValue] = primitiveSexprs
20
+
21
+ if (rawValue === undefined) {
22
+ return new FpPolyFill(false)
23
+ }
24
+
25
+ if (typeof rawValue === "boolean") {
26
+ return new FpPolyFill(rawValue)
27
+ }
28
+
29
+ if (typeof rawValue === "string") {
30
+ return new FpPolyFill(truthyStrings.has(rawValue.toLowerCase()))
31
+ }
32
+
33
+ return new FpPolyFill(false)
34
+ }
35
+
36
+ get filled(): boolean {
37
+ return this.value
38
+ }
39
+
40
+ set filled(filled: boolean) {
41
+ this.value = filled
42
+ }
43
+
44
+ override getString(): string {
45
+ return `(fill ${this.value ? "yes" : "no"})`
46
+ }
47
+ }
48
+ SxClass.register(FpPolyFill)
@@ -0,0 +1,40 @@
1
+ import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { SxClass } from "../base-classes/SxClass"
4
+
5
+ const truthyStrings = new Set(["yes", "true", "1"])
6
+
7
+ export class FpPolyLocked extends SxPrimitiveBoolean {
8
+ static override token = "locked"
9
+ static override parentToken = "fp_poly"
10
+ override token = "locked"
11
+
12
+ constructor(value: boolean) {
13
+ super(value)
14
+ }
15
+
16
+ static override fromSexprPrimitives(
17
+ primitiveSexprs: PrimitiveSExpr[],
18
+ ): FpPolyLocked {
19
+ const [rawValue] = primitiveSexprs
20
+
21
+ if (rawValue === undefined) {
22
+ return new FpPolyLocked(true)
23
+ }
24
+
25
+ if (typeof rawValue === "boolean") {
26
+ return new FpPolyLocked(rawValue)
27
+ }
28
+
29
+ if (typeof rawValue === "string") {
30
+ return new FpPolyLocked(truthyStrings.has(rawValue.toLowerCase()))
31
+ }
32
+
33
+ return new FpPolyLocked(false)
34
+ }
35
+
36
+ override getString(): string {
37
+ return `(locked ${this.value ? "yes" : "no"})`
38
+ }
39
+ }
40
+ SxClass.register(FpPolyLocked)
@@ -0,0 +1,293 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { Layer } from "./Layer"
4
+ import { Stroke } from "./Stroke"
5
+ import { Uuid } from "./Uuid"
6
+ import { Width } from "./Width"
7
+ import { toNumberValue } from "../utils/toNumberValue"
8
+ import { toStringValue } from "../utils/toStringValue"
9
+
10
+ export class FpRect extends SxClass {
11
+ static override token = "fp_rect"
12
+ token = "fp_rect"
13
+
14
+ private _sxStart?: FpRectStart
15
+ private _sxEnd?: FpRectEnd
16
+ private _sxLayer?: Layer
17
+ private _sxWidth?: Width
18
+ private _sxStroke?: Stroke
19
+ private _sxFill?: FpRectFill
20
+ private _sxUuid?: Uuid
21
+ private _locked = false
22
+
23
+ static override fromSexprPrimitives(
24
+ primitiveSexprs: PrimitiveSExpr[],
25
+ ): FpRect {
26
+ const rect = new FpRect()
27
+
28
+ const { propertyMap } = SxClass.parsePrimitivesToClassProperties(
29
+ primitiveSexprs,
30
+ this.token,
31
+ )
32
+
33
+ rect._sxStart = propertyMap.start as FpRectStart | undefined
34
+ rect._sxEnd = propertyMap.end as FpRectEnd | undefined
35
+ rect._sxLayer = propertyMap.layer as Layer | undefined
36
+ rect._sxWidth = propertyMap.width as Width | undefined
37
+ rect._sxStroke = propertyMap.stroke as Stroke | undefined
38
+ rect._sxFill = propertyMap.fill as FpRectFill | undefined
39
+ rect._sxUuid = propertyMap.uuid as Uuid | undefined
40
+
41
+ for (const primitive of primitiveSexprs) {
42
+ if (primitive === "locked") {
43
+ rect._locked = true
44
+ }
45
+ }
46
+
47
+ return rect
48
+ }
49
+
50
+ get start(): FpRectStart | undefined {
51
+ return this._sxStart
52
+ }
53
+
54
+ set start(
55
+ value: FpRectStart | { x: number; y: number } | undefined,
56
+ ) {
57
+ if (value === undefined) {
58
+ this._sxStart = undefined
59
+ return
60
+ }
61
+ if (value instanceof FpRectStart) {
62
+ this._sxStart = value
63
+ return
64
+ }
65
+ this._sxStart = new FpRectStart(value.x, value.y)
66
+ }
67
+
68
+ get end(): FpRectEnd | undefined {
69
+ return this._sxEnd
70
+ }
71
+
72
+ set end(value: FpRectEnd | { x: number; y: number } | undefined) {
73
+ if (value === undefined) {
74
+ this._sxEnd = undefined
75
+ return
76
+ }
77
+ if (value instanceof FpRectEnd) {
78
+ this._sxEnd = value
79
+ return
80
+ }
81
+ this._sxEnd = new FpRectEnd(value.x, value.y)
82
+ }
83
+
84
+ get layer(): Layer | undefined {
85
+ return this._sxLayer
86
+ }
87
+
88
+ set layer(value: Layer | string | string[] | undefined) {
89
+ if (value === undefined) {
90
+ this._sxLayer = undefined
91
+ return
92
+ }
93
+ if (value instanceof Layer) {
94
+ this._sxLayer = value
95
+ return
96
+ }
97
+ const names = Array.isArray(value) ? value : [value]
98
+ this._sxLayer = new Layer(names)
99
+ }
100
+
101
+ get stroke(): Stroke | undefined {
102
+ return this._sxStroke
103
+ }
104
+
105
+ set stroke(value: Stroke | undefined) {
106
+ this._sxStroke = value
107
+ }
108
+
109
+ get width(): number | undefined {
110
+ return this._sxWidth?.value
111
+ }
112
+
113
+ set width(value: number | Width | undefined) {
114
+ if (value === undefined) {
115
+ this._sxWidth = undefined
116
+ return
117
+ }
118
+ if (value instanceof Width) {
119
+ this._sxWidth = value
120
+ return
121
+ }
122
+ this._sxWidth = new Width(value)
123
+ }
124
+
125
+ get widthClass(): Width | undefined {
126
+ return this._sxWidth
127
+ }
128
+
129
+ get fill(): boolean | undefined {
130
+ return this._sxFill?.filled
131
+ }
132
+
133
+ set fill(value: boolean | FpRectFill | undefined) {
134
+ if (value === undefined) {
135
+ this._sxFill = undefined
136
+ return
137
+ }
138
+ if (value instanceof FpRectFill) {
139
+ this._sxFill = value
140
+ return
141
+ }
142
+ this._sxFill = new FpRectFill(value)
143
+ }
144
+
145
+ get fillClass(): FpRectFill | undefined {
146
+ return this._sxFill
147
+ }
148
+
149
+ get uuid(): string | undefined {
150
+ return this._sxUuid?.value
151
+ }
152
+
153
+ set uuid(value: string | Uuid | undefined) {
154
+ if (value === undefined) {
155
+ this._sxUuid = undefined
156
+ return
157
+ }
158
+ if (value instanceof Uuid) {
159
+ this._sxUuid = value
160
+ return
161
+ }
162
+ this._sxUuid = new Uuid(value)
163
+ }
164
+
165
+ get uuidClass(): Uuid | undefined {
166
+ return this._sxUuid
167
+ }
168
+
169
+ get locked(): boolean {
170
+ return this._locked
171
+ }
172
+
173
+ set locked(value: boolean) {
174
+ this._locked = value
175
+ }
176
+
177
+ override getChildren(): SxClass[] {
178
+ const children: SxClass[] = []
179
+ if (this._sxStart) children.push(this._sxStart)
180
+ if (this._sxEnd) children.push(this._sxEnd)
181
+ if (this._sxLayer) children.push(this._sxLayer)
182
+ if (this._sxWidth) children.push(this._sxWidth)
183
+ if (this._sxStroke) children.push(this._sxStroke)
184
+ if (this._sxFill) children.push(this._sxFill)
185
+ if (this._sxUuid) children.push(this._sxUuid)
186
+ return children
187
+ }
188
+
189
+ override getString(): string {
190
+ const lines = ["(fp_rect"]
191
+ const push = (value?: SxClass) => {
192
+ if (!value) return
193
+ lines.push(value.getStringIndented())
194
+ }
195
+
196
+ push(this._sxStart)
197
+ push(this._sxEnd)
198
+ push(this._sxLayer)
199
+ push(this._sxWidth)
200
+ push(this._sxStroke)
201
+ push(this._sxFill)
202
+ push(this._sxUuid)
203
+
204
+ if (this._locked) {
205
+ lines.push(" locked")
206
+ }
207
+
208
+ lines.push(")")
209
+ return lines.join("\n")
210
+ }
211
+ }
212
+ SxClass.register(FpRect)
213
+
214
+ export class FpRectStart extends SxClass {
215
+ static override token = "start"
216
+ static override parentToken = "fp_rect"
217
+ token = "start"
218
+
219
+ x: number
220
+ y: number
221
+
222
+ constructor(x: number, y: number) {
223
+ super()
224
+ this.x = x
225
+ this.y = y
226
+ }
227
+
228
+ static override fromSexprPrimitives(
229
+ primitiveSexprs: PrimitiveSExpr[],
230
+ ): FpRectStart {
231
+ const x = toNumberValue(primitiveSexprs[0]) ?? 0
232
+ const y = toNumberValue(primitiveSexprs[1]) ?? 0
233
+ return new FpRectStart(x, y)
234
+ }
235
+
236
+ override getString(): string {
237
+ return `(start ${this.x} ${this.y})`
238
+ }
239
+ }
240
+ SxClass.register(FpRectStart)
241
+
242
+ export class FpRectEnd extends SxClass {
243
+ static override token = "end"
244
+ static override parentToken = "fp_rect"
245
+ token = "end"
246
+
247
+ x: number
248
+ y: number
249
+
250
+ constructor(x: number, y: number) {
251
+ super()
252
+ this.x = x
253
+ this.y = y
254
+ }
255
+
256
+ static override fromSexprPrimitives(
257
+ primitiveSexprs: PrimitiveSExpr[],
258
+ ): FpRectEnd {
259
+ const x = toNumberValue(primitiveSexprs[0]) ?? 0
260
+ const y = toNumberValue(primitiveSexprs[1]) ?? 0
261
+ return new FpRectEnd(x, y)
262
+ }
263
+
264
+ override getString(): string {
265
+ return `(end ${this.x} ${this.y})`
266
+ }
267
+ }
268
+ SxClass.register(FpRectEnd)
269
+
270
+ export class FpRectFill extends SxClass {
271
+ static override token = "fill"
272
+ static override parentToken = "fp_rect"
273
+ token = "fill"
274
+
275
+ filled: boolean
276
+
277
+ constructor(filled: boolean) {
278
+ super()
279
+ this.filled = filled
280
+ }
281
+
282
+ static override fromSexprPrimitives(
283
+ primitiveSexprs: PrimitiveSExpr[],
284
+ ): FpRectFill {
285
+ const state = toStringValue(primitiveSexprs[0])
286
+ return new FpRectFill(state === "yes")
287
+ }
288
+
289
+ override getString(): string {
290
+ return `(fill ${this.filled ? "yes" : "no"})`
291
+ }
292
+ }
293
+ SxClass.register(FpRectFill)