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,705 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
3
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
4
+ import { printSExpr } from "../parseToPrimitiveSExpr"
5
+ import { quoteSExprString } from "../utils/quoteSExprString"
6
+ import { toStringValue } from "../utils/toStringValue"
7
+ import { At } from "./At"
8
+ import { PadChamfer } from "./PadChamfer"
9
+ import { PadChamferRatio } from "./PadChamferRatio"
10
+ import { PadClearance } from "./PadClearance"
11
+ import { PadDieLength } from "./PadDieLength"
12
+ import { PadDrill } from "./PadDrill"
13
+ import { PadLayers } from "./PadLayers"
14
+ import { PadNet } from "./PadNet"
15
+ import { PadOptions } from "./PadOptions"
16
+ import { PadPinFunction } from "./PadPinFunction"
17
+ import { PadPinType } from "./PadPinType"
18
+ import { PadPrimitives } from "./PadPrimitives"
19
+ import { PadRoundrectRratio } from "./PadRoundrectRratio"
20
+ import { PadSize } from "./PadSize"
21
+ import { PadSolderMaskMargin } from "./PadSolderMaskMargin"
22
+ import { PadSolderPasteMargin } from "./PadSolderPasteMargin"
23
+ import { PadSolderPasteMarginRatio } from "./PadSolderPasteMarginRatio"
24
+ import { PadThermalGap } from "./PadThermalGap"
25
+ import { PadThermalWidth } from "./PadThermalWidth"
26
+ import { PadThermalBridgeAngle } from "./PadThermalBridgeAngle"
27
+ import { PadZoneConnect } from "./PadZoneConnect"
28
+ import { Property } from "./Property"
29
+ import { Stroke } from "./Stroke"
30
+ import { Uuid } from "./Uuid"
31
+ import { Width } from "./Width"
32
+ import { PadTeardrops } from "./PadTeardrops"
33
+ import { PadRectDelta } from "./PadRectDelta"
34
+
35
+ const SINGLE_TOKENS = new Set([
36
+ "at",
37
+ "size",
38
+ "drill",
39
+ "layers",
40
+ "width",
41
+ "stroke",
42
+ "rect_delta",
43
+ "roundrect_rratio",
44
+ "chamfer_ratio",
45
+ "chamfer",
46
+ "net",
47
+ "uuid",
48
+ "pinfunction",
49
+ "pintype",
50
+ "die_length",
51
+ "solder_mask_margin",
52
+ "solder_paste_margin",
53
+ "solder_paste_margin_ratio",
54
+ "clearance",
55
+ "zone_connect",
56
+ "thermal_width",
57
+ "thermal_gap",
58
+ "thermal_bridge_angle",
59
+ "options",
60
+ "primitives",
61
+ "remove_unused_layers",
62
+ "keep_end_layers",
63
+ "teardrops",
64
+ ])
65
+
66
+ const MULTI_TOKENS = new Set(["property"])
67
+
68
+ const SUPPORTED_TOKENS = new Set([...SINGLE_TOKENS, ...MULTI_TOKENS])
69
+
70
+ const ensureSingle = (
71
+ arrayPropertyMap: Record<string, SxClass[]>,
72
+ token: string,
73
+ ) => {
74
+ const entries = arrayPropertyMap[token]
75
+ if (entries && entries.length > 1) {
76
+ throw new Error(`pad does not support repeated "${token}" children`)
77
+ }
78
+ }
79
+
80
+ export class FootprintPad extends SxClass {
81
+ static override token = "pad"
82
+ token = "pad"
83
+
84
+ private _number = ""
85
+ private _padType = ""
86
+ private _shape = ""
87
+ private _locked = false
88
+ private _sxRemoveUnusedLayers?: PadRemoveUnusedLayers
89
+ private _sxKeepEndLayers?: PadKeepEndLayers
90
+
91
+ private _sxAt?: At
92
+ private _sxSize?: PadSize
93
+ private _sxDrill?: PadDrill
94
+ private _sxLayers?: PadLayers
95
+ private _sxWidth?: Width
96
+ private _sxStroke?: Stroke
97
+ private _properties: Property[] = []
98
+ private _sxRoundrectRatio?: PadRoundrectRratio
99
+ private _sxChamferRatio?: PadChamferRatio
100
+ private _sxChamfer?: PadChamfer
101
+ private _sxRectDelta?: PadRectDelta
102
+ private _sxNet?: PadNet
103
+ private _sxUuid?: Uuid
104
+ private _sxPinFunction?: PadPinFunction
105
+ private _sxPinType?: PadPinType
106
+ private _sxDieLength?: PadDieLength
107
+ private _sxSolderMaskMargin?: PadSolderMaskMargin
108
+ private _sxSolderPasteMargin?: PadSolderPasteMargin
109
+ private _sxSolderPasteMarginRatio?: PadSolderPasteMarginRatio
110
+ private _sxClearance?: PadClearance
111
+ private _sxZoneConnect?: PadZoneConnect
112
+ private _sxThermalWidth?: PadThermalWidth
113
+ private _sxThermalGap?: PadThermalGap
114
+ private _sxThermalBridgeAngle?: PadThermalBridgeAngle
115
+ private _sxOptions?: PadOptions
116
+ private _sxPrimitives?: PadPrimitives
117
+ private _sxTeardrops?: PadTeardrops
118
+
119
+ constructor(number = "", padType = "", shape = "") {
120
+ super()
121
+ this._number = number
122
+ this._padType = padType
123
+ this._shape = shape
124
+ }
125
+
126
+ static override fromSexprPrimitives(
127
+ primitiveSexprs: PrimitiveSExpr[],
128
+ ): FootprintPad {
129
+ if (primitiveSexprs.length < 3) {
130
+ throw new Error("pad requires number, type, and shape arguments")
131
+ }
132
+
133
+ const [rawNumber, rawType, rawShape, ...rest] = primitiveSexprs
134
+ const number = toStringValue(rawNumber)
135
+ const padType = toStringValue(rawType)
136
+ const shape = toStringValue(rawShape)
137
+ if (number === undefined || padType === undefined || shape === undefined) {
138
+ throw new Error("pad header tokens must be strings")
139
+ }
140
+
141
+ const pad = new FootprintPad(number, padType, shape)
142
+
143
+ const primitiveStrings: string[] = []
144
+ const primitiveNodes: PrimitiveSExpr[] = []
145
+
146
+ for (const primitive of rest) {
147
+ if (typeof primitive === "string") {
148
+ primitiveStrings.push(primitive)
149
+ } else if (Array.isArray(primitive)) {
150
+ primitiveNodes.push(primitive)
151
+ } else {
152
+ throw new Error(
153
+ `pad encountered unexpected primitive child: ${JSON.stringify(primitive)}`,
154
+ )
155
+ }
156
+ }
157
+
158
+ for (const flag of primitiveStrings) {
159
+ switch (flag) {
160
+ case "locked":
161
+ pad._locked = true
162
+ break
163
+ case "remove_unused_layer":
164
+ pad._sxRemoveUnusedLayers = new PadRemoveUnusedLayers({
165
+ value: true,
166
+ bareToken: "remove_unused_layer",
167
+ })
168
+ break
169
+ case "keep_end_layers":
170
+ pad._sxKeepEndLayers = new PadKeepEndLayers({
171
+ value: true,
172
+ bare: true,
173
+ })
174
+ break
175
+ default:
176
+ throw new Error(`pad encountered unsupported flag "${flag}"`)
177
+ }
178
+ }
179
+
180
+ const { propertyMap, arrayPropertyMap } =
181
+ SxClass.parsePrimitivesToClassProperties(primitiveNodes, this.token)
182
+
183
+ for (const token of Object.keys(propertyMap)) {
184
+ if (!SUPPORTED_TOKENS.has(token)) {
185
+ throw new Error(`pad encountered unsupported child token "${token}"`)
186
+ }
187
+ }
188
+
189
+ for (const [token, entries] of Object.entries(arrayPropertyMap)) {
190
+ if (!SUPPORTED_TOKENS.has(token)) {
191
+ throw new Error(`pad encountered unsupported child token "${token}"`)
192
+ }
193
+ if (!MULTI_TOKENS.has(token) && entries.length > 1) {
194
+ throw new Error(`pad does not support repeated child "${token}"`)
195
+ }
196
+ }
197
+
198
+ ensureSingle(arrayPropertyMap, "at")
199
+ ensureSingle(arrayPropertyMap, "size")
200
+ ensureSingle(arrayPropertyMap, "drill")
201
+ ensureSingle(arrayPropertyMap, "layers")
202
+ ensureSingle(arrayPropertyMap, "width")
203
+ ensureSingle(arrayPropertyMap, "stroke")
204
+ ensureSingle(arrayPropertyMap, "rect_delta")
205
+ ensureSingle(arrayPropertyMap, "roundrect_rratio")
206
+ ensureSingle(arrayPropertyMap, "chamfer_ratio")
207
+ ensureSingle(arrayPropertyMap, "chamfer")
208
+ ensureSingle(arrayPropertyMap, "net")
209
+ ensureSingle(arrayPropertyMap, "uuid")
210
+ ensureSingle(arrayPropertyMap, "pinfunction")
211
+ ensureSingle(arrayPropertyMap, "pintype")
212
+ ensureSingle(arrayPropertyMap, "die_length")
213
+ ensureSingle(arrayPropertyMap, "solder_mask_margin")
214
+ ensureSingle(arrayPropertyMap, "solder_paste_margin")
215
+ ensureSingle(arrayPropertyMap, "solder_paste_margin_ratio")
216
+ ensureSingle(arrayPropertyMap, "clearance")
217
+ ensureSingle(arrayPropertyMap, "zone_connect")
218
+ ensureSingle(arrayPropertyMap, "thermal_width")
219
+ ensureSingle(arrayPropertyMap, "thermal_gap")
220
+ ensureSingle(arrayPropertyMap, "thermal_bridge_angle")
221
+ ensureSingle(arrayPropertyMap, "options")
222
+ ensureSingle(arrayPropertyMap, "primitives")
223
+
224
+ pad._sxAt = propertyMap.at as At | undefined
225
+ pad._sxSize = propertyMap.size as PadSize | undefined
226
+ pad._sxDrill = propertyMap.drill as PadDrill | undefined
227
+ pad._sxLayers = propertyMap.layers as PadLayers | undefined
228
+ pad._sxWidth = propertyMap.width as Width | undefined
229
+ pad._sxStroke = propertyMap.stroke as Stroke | undefined
230
+ pad._sxRectDelta = propertyMap.rect_delta as PadRectDelta | undefined
231
+
232
+ pad._properties = (arrayPropertyMap.property as Property[]) ?? []
233
+
234
+ pad._sxRoundrectRatio = propertyMap.roundrect_rratio as
235
+ | PadRoundrectRratio
236
+ | undefined
237
+ pad._sxChamferRatio = propertyMap.chamfer_ratio as PadChamferRatio | undefined
238
+ pad._sxChamfer = propertyMap.chamfer as PadChamfer | undefined
239
+ pad._sxNet = propertyMap.net as PadNet | undefined
240
+ pad._sxUuid = propertyMap.uuid as Uuid | undefined
241
+ pad._sxPinFunction = propertyMap.pinfunction as PadPinFunction | undefined
242
+ pad._sxPinType = propertyMap.pintype as PadPinType | undefined
243
+ pad._sxDieLength = propertyMap.die_length as PadDieLength | undefined
244
+ pad._sxSolderMaskMargin = propertyMap.solder_mask_margin as
245
+ | PadSolderMaskMargin
246
+ | undefined
247
+ pad._sxSolderPasteMargin = propertyMap.solder_paste_margin as
248
+ | PadSolderPasteMargin
249
+ | undefined
250
+ pad._sxSolderPasteMarginRatio =
251
+ propertyMap.solder_paste_margin_ratio as PadSolderPasteMarginRatio | undefined
252
+ pad._sxClearance = propertyMap.clearance as PadClearance | undefined
253
+ pad._sxZoneConnect = propertyMap.zone_connect as PadZoneConnect | undefined
254
+ pad._sxThermalWidth = propertyMap.thermal_width as PadThermalWidth | undefined
255
+ pad._sxThermalGap = propertyMap.thermal_gap as PadThermalGap | undefined
256
+ pad._sxThermalBridgeAngle =
257
+ propertyMap.thermal_bridge_angle as PadThermalBridgeAngle | undefined
258
+ pad._sxOptions = propertyMap.options as PadOptions | undefined
259
+ pad._sxPrimitives = propertyMap.primitives as PadPrimitives | undefined
260
+ pad._sxRemoveUnusedLayers =
261
+ (arrayPropertyMap.remove_unused_layers?.[0] as
262
+ | PadRemoveUnusedLayers
263
+ | undefined) ??
264
+ pad._sxRemoveUnusedLayers
265
+ pad._sxKeepEndLayers =
266
+ (arrayPropertyMap.keep_end_layers?.[0] as PadKeepEndLayers | undefined) ??
267
+ pad._sxKeepEndLayers
268
+ pad._sxTeardrops =
269
+ (arrayPropertyMap.teardrops?.[0] as PadTeardrops | undefined) ?? undefined
270
+
271
+ return pad
272
+ }
273
+
274
+ get number(): string {
275
+ return this._number
276
+ }
277
+
278
+ set number(value: string) {
279
+ this._number = value
280
+ }
281
+
282
+ get padType(): string {
283
+ return this._padType
284
+ }
285
+
286
+ set padType(value: string) {
287
+ this._padType = value
288
+ }
289
+
290
+ get shape(): string {
291
+ return this._shape
292
+ }
293
+
294
+ set shape(value: string) {
295
+ this._shape = value
296
+ }
297
+
298
+ get locked(): boolean {
299
+ return this._locked
300
+ }
301
+
302
+ set locked(value: boolean) {
303
+ this._locked = value
304
+ }
305
+
306
+ get removeUnusedLayer(): boolean {
307
+ return this._sxRemoveUnusedLayers?.value ?? false
308
+ }
309
+
310
+ set removeUnusedLayer(value: boolean) {
311
+ this._sxRemoveUnusedLayers = value
312
+ ? new PadRemoveUnusedLayers({ value })
313
+ : undefined
314
+ }
315
+
316
+ get keepEndLayers(): boolean {
317
+ return this._sxKeepEndLayers?.value ?? false
318
+ }
319
+
320
+ set keepEndLayers(value: boolean) {
321
+ this._sxKeepEndLayers = value
322
+ ? new PadKeepEndLayers({ value })
323
+ : undefined
324
+ }
325
+
326
+ get at(): At | undefined {
327
+ return this._sxAt
328
+ }
329
+
330
+ set at(value: At | undefined) {
331
+ this._sxAt = value
332
+ }
333
+
334
+ get size(): PadSize | undefined {
335
+ return this._sxSize
336
+ }
337
+
338
+ set size(value: PadSize | undefined) {
339
+ this._sxSize = value
340
+ }
341
+
342
+ get drill(): PadDrill | undefined {
343
+ return this._sxDrill
344
+ }
345
+
346
+ set drill(value: PadDrill | undefined) {
347
+ this._sxDrill = value
348
+ }
349
+
350
+ get layers(): PadLayers | undefined {
351
+ return this._sxLayers
352
+ }
353
+
354
+ set layers(value: PadLayers | undefined) {
355
+ this._sxLayers = value
356
+ }
357
+
358
+ get width(): Width | undefined {
359
+ return this._sxWidth
360
+ }
361
+
362
+ set width(value: Width | undefined) {
363
+ this._sxWidth = value
364
+ }
365
+
366
+ get stroke(): Stroke | undefined {
367
+ return this._sxStroke
368
+ }
369
+
370
+ set stroke(value: Stroke | undefined) {
371
+ this._sxStroke = value
372
+ }
373
+
374
+ get properties(): Property[] {
375
+ return [...this._properties]
376
+ }
377
+
378
+ set properties(value: Property[]) {
379
+ this._properties = [...value]
380
+ }
381
+
382
+ get roundrectRatio(): number | undefined {
383
+ return this._sxRoundrectRatio?.value
384
+ }
385
+
386
+ set roundrectRatio(value: number | undefined) {
387
+ this._sxRoundrectRatio =
388
+ value === undefined ? undefined : new PadRoundrectRratio(value)
389
+ }
390
+
391
+ get chamferRatio(): number | undefined {
392
+ return this._sxChamferRatio?.value
393
+ }
394
+
395
+ set chamferRatio(value: number | undefined) {
396
+ this._sxChamferRatio =
397
+ value === undefined ? undefined : new PadChamferRatio(value)
398
+ }
399
+
400
+ get chamfer(): PadChamfer | undefined {
401
+ return this._sxChamfer
402
+ }
403
+
404
+ set chamfer(value: PadChamfer | undefined) {
405
+ this._sxChamfer = value
406
+ }
407
+
408
+ get chamferCorners(): string[] | undefined {
409
+ return this._sxChamfer?.corners
410
+ }
411
+
412
+ get rectDelta(): PadRectDelta | undefined {
413
+ return this._sxRectDelta
414
+ }
415
+
416
+ set rectDelta(value: PadRectDelta | { x: number; y: number } | undefined) {
417
+ if (value === undefined) {
418
+ this._sxRectDelta = undefined
419
+ return
420
+ }
421
+ if (value instanceof PadRectDelta) {
422
+ this._sxRectDelta = value
423
+ return
424
+ }
425
+ this._sxRectDelta = new PadRectDelta(value.x, value.y)
426
+ }
427
+
428
+ get net(): PadNet | undefined {
429
+ return this._sxNet
430
+ }
431
+
432
+ set net(value: PadNet | undefined) {
433
+ this._sxNet = value
434
+ }
435
+
436
+ get uuid(): Uuid | undefined {
437
+ return this._sxUuid
438
+ }
439
+
440
+ set uuid(value: Uuid | string | undefined) {
441
+ if (value === undefined) {
442
+ this._sxUuid = undefined
443
+ return
444
+ }
445
+ this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
446
+ }
447
+
448
+ get pinfunction(): string | undefined {
449
+ return this._sxPinFunction?.value
450
+ }
451
+
452
+ set pinfunction(value: string | undefined) {
453
+ this._sxPinFunction =
454
+ value === undefined ? undefined : new PadPinFunction(value)
455
+ }
456
+
457
+ get pintype(): string | undefined {
458
+ return this._sxPinType?.value
459
+ }
460
+
461
+ set pintype(value: string | undefined) {
462
+ this._sxPinType = value === undefined ? undefined : new PadPinType(value)
463
+ }
464
+
465
+ get dieLength(): number | undefined {
466
+ return this._sxDieLength?.value
467
+ }
468
+
469
+ set dieLength(value: number | undefined) {
470
+ this._sxDieLength = value === undefined ? undefined : new PadDieLength(value)
471
+ }
472
+
473
+ get solderMaskMargin(): number | undefined {
474
+ return this._sxSolderMaskMargin?.value
475
+ }
476
+
477
+ set solderMaskMargin(value: number | undefined) {
478
+ this._sxSolderMaskMargin =
479
+ value === undefined ? undefined : new PadSolderMaskMargin(value)
480
+ }
481
+
482
+ get solderPasteMargin(): number | undefined {
483
+ return this._sxSolderPasteMargin?.value
484
+ }
485
+
486
+ set solderPasteMargin(value: number | undefined) {
487
+ this._sxSolderPasteMargin =
488
+ value === undefined ? undefined : new PadSolderPasteMargin(value)
489
+ }
490
+
491
+ get solderPasteMarginRatio(): number | undefined {
492
+ return this._sxSolderPasteMarginRatio?.value
493
+ }
494
+
495
+ set solderPasteMarginRatio(value: number | undefined) {
496
+ this._sxSolderPasteMarginRatio =
497
+ value === undefined ? undefined : new PadSolderPasteMarginRatio(value)
498
+ }
499
+
500
+ get clearance(): number | undefined {
501
+ return this._sxClearance?.value
502
+ }
503
+
504
+ set clearance(value: number | undefined) {
505
+ this._sxClearance = value === undefined ? undefined : new PadClearance(value)
506
+ }
507
+
508
+ get zoneConnect(): number | undefined {
509
+ return this._sxZoneConnect?.value
510
+ }
511
+
512
+ set zoneConnect(value: number | undefined) {
513
+ this._sxZoneConnect = value === undefined ? undefined : new PadZoneConnect(value)
514
+ }
515
+
516
+ get thermalWidth(): number | undefined {
517
+ return this._sxThermalWidth?.value
518
+ }
519
+
520
+ set thermalWidth(value: number | undefined) {
521
+ this._sxThermalWidth = value === undefined ? undefined : new PadThermalWidth(value)
522
+ }
523
+
524
+ get thermalGap(): number | undefined {
525
+ return this._sxThermalGap?.value
526
+ }
527
+
528
+ set thermalGap(value: number | undefined) {
529
+ this._sxThermalGap = value === undefined ? undefined : new PadThermalGap(value)
530
+ }
531
+
532
+ get thermalBridgeAngle(): number | undefined {
533
+ return this._sxThermalBridgeAngle?.value
534
+ }
535
+
536
+ set thermalBridgeAngle(value: number | undefined) {
537
+ this._sxThermalBridgeAngle =
538
+ value === undefined ? undefined : new PadThermalBridgeAngle(value)
539
+ }
540
+
541
+ get options(): PadOptions | undefined {
542
+ return this._sxOptions
543
+ }
544
+
545
+ set options(value: PadOptions | undefined) {
546
+ this._sxOptions = value
547
+ }
548
+
549
+ get primitives(): PadPrimitives | undefined {
550
+ return this._sxPrimitives
551
+ }
552
+
553
+ set primitives(value: PadPrimitives | undefined) {
554
+ this._sxPrimitives = value
555
+ }
556
+
557
+ get teardrops(): PadTeardrops | undefined {
558
+ return this._sxTeardrops
559
+ }
560
+
561
+ set teardrops(value: PadTeardrops | undefined) {
562
+ this._sxTeardrops = value
563
+ }
564
+
565
+ override getChildren(): SxClass[] {
566
+ const children: SxClass[] = []
567
+ if (this._sxAt) children.push(this._sxAt)
568
+ if (this._sxSize) children.push(this._sxSize)
569
+ if (this._sxDrill) children.push(this._sxDrill)
570
+ if (this._sxLayers) children.push(this._sxLayers)
571
+ if (this._sxWidth) children.push(this._sxWidth)
572
+ if (this._sxStroke) children.push(this._sxStroke)
573
+ children.push(...this._properties)
574
+ if (this._sxRoundrectRatio) children.push(this._sxRoundrectRatio)
575
+ if (this._sxChamferRatio) children.push(this._sxChamferRatio)
576
+ if (this._sxChamfer) children.push(this._sxChamfer)
577
+ if (this._sxRectDelta) children.push(this._sxRectDelta)
578
+ if (this._sxNet) children.push(this._sxNet)
579
+ if (this._sxPinFunction) children.push(this._sxPinFunction)
580
+ if (this._sxPinType) children.push(this._sxPinType)
581
+ if (this._sxDieLength) children.push(this._sxDieLength)
582
+ if (this._sxSolderMaskMargin) children.push(this._sxSolderMaskMargin)
583
+ if (this._sxSolderPasteMargin) children.push(this._sxSolderPasteMargin)
584
+ if (this._sxSolderPasteMarginRatio)
585
+ children.push(this._sxSolderPasteMarginRatio)
586
+ if (this._sxClearance) children.push(this._sxClearance)
587
+ if (this._sxZoneConnect) children.push(this._sxZoneConnect)
588
+ if (this._sxThermalWidth) children.push(this._sxThermalWidth)
589
+ if (this._sxThermalGap) children.push(this._sxThermalGap)
590
+ if (this._sxThermalBridgeAngle)
591
+ children.push(this._sxThermalBridgeAngle)
592
+ if (this._sxUuid) children.push(this._sxUuid)
593
+ if (this._sxRemoveUnusedLayers) children.push(this._sxRemoveUnusedLayers)
594
+ if (this._sxKeepEndLayers) children.push(this._sxKeepEndLayers)
595
+ if (this._sxTeardrops) children.push(this._sxTeardrops)
596
+ if (this._sxOptions) children.push(this._sxOptions)
597
+ if (this._sxPrimitives) children.push(this._sxPrimitives)
598
+ return children
599
+ }
600
+
601
+ override getString(): string {
602
+ const lines = [
603
+ `(pad ${quoteSExprString(this._number)} ${this._padType} ${this._shape}`,
604
+ ]
605
+ for (const child of this.getChildren()) {
606
+ lines.push(child.getStringIndented())
607
+ }
608
+ if (this._locked) {
609
+ lines.push(" locked")
610
+ }
611
+ lines.push(")")
612
+ return lines.join("\n")
613
+ }
614
+ }
615
+ SxClass.register(FootprintPad)
616
+
617
+ class PadRemoveUnusedLayers extends SxPrimitiveBoolean {
618
+ static override token = "remove_unused_layers"
619
+ static override parentToken = "pad"
620
+ override token = "remove_unused_layers"
621
+
622
+ private readonly bareToken?: string
623
+
624
+ constructor(options: { value?: boolean; bareToken?: string } = {}) {
625
+ super(options.value ?? false)
626
+ this.bareToken = options.bareToken
627
+ }
628
+
629
+ static override fromSexprPrimitives(
630
+ primitiveSexprs: PrimitiveSExpr[],
631
+ ): PadRemoveUnusedLayers {
632
+ const [raw] = primitiveSexprs
633
+ if (raw === undefined) {
634
+ return new PadRemoveUnusedLayers({ value: false })
635
+ }
636
+ if (typeof raw === "boolean") {
637
+ return new PadRemoveUnusedLayers({ value: raw })
638
+ }
639
+ if (typeof raw === "string") {
640
+ const normalized = raw.toLowerCase()
641
+ if (normalized === "yes" || normalized === "true") {
642
+ return new PadRemoveUnusedLayers({ value: true })
643
+ }
644
+ if (normalized === "no" || normalized === "false") {
645
+ return new PadRemoveUnusedLayers({ value: false })
646
+ }
647
+ }
648
+ throw new Error(
649
+ `remove_unused_layers expects yes/no or boolean, received ${JSON.stringify(raw)}`,
650
+ )
651
+ }
652
+
653
+ override getString(): string {
654
+ if (this.bareToken) {
655
+ return this.bareToken
656
+ }
657
+ return `(remove_unused_layers ${this.value ? "yes" : "no"})`
658
+ }
659
+ }
660
+ SxClass.register(PadRemoveUnusedLayers)
661
+
662
+ class PadKeepEndLayers extends SxPrimitiveBoolean {
663
+ static override token = "keep_end_layers"
664
+ static override parentToken = "pad"
665
+ override token = "keep_end_layers"
666
+
667
+ private readonly renderBare: boolean
668
+
669
+ constructor(options: { value?: boolean; bare?: boolean } = {}) {
670
+ super(options.value ?? false)
671
+ this.renderBare = options.bare ?? false
672
+ }
673
+
674
+ static override fromSexprPrimitives(
675
+ primitiveSexprs: PrimitiveSExpr[],
676
+ ): PadKeepEndLayers {
677
+ const [raw] = primitiveSexprs
678
+ if (raw === undefined) {
679
+ return new PadKeepEndLayers({ value: false })
680
+ }
681
+ if (typeof raw === "boolean") {
682
+ return new PadKeepEndLayers({ value: raw })
683
+ }
684
+ if (typeof raw === "string") {
685
+ const normalized = raw.toLowerCase()
686
+ if (normalized === "yes" || normalized === "true") {
687
+ return new PadKeepEndLayers({ value: true })
688
+ }
689
+ if (normalized === "no" || normalized === "false") {
690
+ return new PadKeepEndLayers({ value: false })
691
+ }
692
+ }
693
+ throw new Error(
694
+ `keep_end_layers expects yes/no or boolean, received ${JSON.stringify(raw)}`,
695
+ )
696
+ }
697
+
698
+ override getString(): string {
699
+ if (this.renderBare) {
700
+ return "keep_end_layers"
701
+ }
702
+ return `(keep_end_layers ${this.value ? "yes" : "no"})`
703
+ }
704
+ }
705
+ SxClass.register(PadKeepEndLayers)