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,73 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { At } from "./At"
4
+ import { Uuid } from "./Uuid"
5
+
6
+ const SUPPORTED_TOKENS = new Set(["at", "uuid"])
7
+
8
+ export class NoConnect extends SxClass {
9
+ static override token = "no_connect"
10
+ static override parentToken = "kicad_sch"
11
+ override token = "no_connect"
12
+
13
+ private _sxAt?: At
14
+ private _sxUuid?: Uuid
15
+
16
+ static override fromSexprPrimitives(
17
+ primitiveSexprs: PrimitiveSExpr[],
18
+ ): NoConnect {
19
+ const noConnect = new NoConnect()
20
+
21
+ const { propertyMap, arrayPropertyMap } =
22
+ SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
23
+
24
+ if (Object.keys(arrayPropertyMap).length > 0) {
25
+ const tokens = Object.keys(arrayPropertyMap).join(", ")
26
+ throw new Error(
27
+ `no_connect does not support repeated child tokens: ${tokens}`,
28
+ )
29
+ }
30
+
31
+ const unsupportedTokens = Object.keys(propertyMap).filter(
32
+ (token) => !SUPPORTED_TOKENS.has(token),
33
+ )
34
+ if (unsupportedTokens.length > 0) {
35
+ throw new Error(
36
+ `Unsupported child tokens inside no_connect expression: ${unsupportedTokens.join(", ")}`,
37
+ )
38
+ }
39
+
40
+ noConnect._sxAt = propertyMap.at as At | undefined
41
+ noConnect._sxUuid = propertyMap.uuid as Uuid | undefined
42
+
43
+ return noConnect
44
+ }
45
+
46
+ get at(): At | undefined {
47
+ return this._sxAt
48
+ }
49
+
50
+ set at(value: At | undefined) {
51
+ this._sxAt = value
52
+ }
53
+
54
+ get uuid(): Uuid | undefined {
55
+ return this._sxUuid
56
+ }
57
+
58
+ set uuid(value: Uuid | string | undefined) {
59
+ if (value === undefined) {
60
+ this._sxUuid = undefined
61
+ return
62
+ }
63
+ this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
64
+ }
65
+
66
+ override getChildren(): SxClass[] {
67
+ const children: SxClass[] = []
68
+ if (this._sxAt) children.push(this._sxAt)
69
+ if (this._sxUuid) children.push(this._sxUuid)
70
+ return children
71
+ }
72
+ }
73
+ SxClass.register(NoConnect)
@@ -0,0 +1,8 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
3
+
4
+ export class OnBoard extends SxPrimitiveBoolean {
5
+ static override token = "on_board"
6
+ token = "on_board"
7
+ }
8
+ SxClass.register(OnBoard)
@@ -0,0 +1,50 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { printSExpr } from "../parseToPrimitiveSExpr"
4
+ import { toStringValue } from "../utils/toStringValue"
5
+
6
+ export class PadChamfer extends SxClass {
7
+ static override token = "chamfer"
8
+ static override parentToken = "pad"
9
+ token = "chamfer"
10
+
11
+ private _corners: string[] = []
12
+
13
+ constructor(corners: string[]) {
14
+ super()
15
+ this.corners = corners
16
+ }
17
+
18
+ static override fromSexprPrimitives(
19
+ primitiveSexprs: PrimitiveSExpr[],
20
+ ): PadChamfer {
21
+ const corners = primitiveSexprs.map((primitive) => {
22
+ const corner = toStringValue(primitive)
23
+ if (corner === undefined) {
24
+ return printSExpr(primitive)
25
+ }
26
+ return corner
27
+ })
28
+ return new PadChamfer(corners)
29
+ }
30
+
31
+ get corners(): string[] {
32
+ return [...this._corners]
33
+ }
34
+
35
+ set corners(values: string[]) {
36
+ this._corners = values.map((value) => String(value))
37
+ }
38
+
39
+ override getChildren(): SxClass[] {
40
+ return []
41
+ }
42
+
43
+ override getString(): string {
44
+ if (this._corners.length === 0) {
45
+ return "(chamfer)"
46
+ }
47
+ return `(chamfer ${this._corners.join(" ")})`
48
+ }
49
+ }
50
+ SxClass.register(PadChamfer)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class PadChamferRatio extends SxPrimitiveNumber {
5
+ static override token = "chamfer_ratio"
6
+ static override parentToken = "pad"
7
+ token = "chamfer_ratio"
8
+ }
9
+ SxClass.register(PadChamferRatio)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class PadClearance extends SxPrimitiveNumber {
5
+ static override token = "clearance"
6
+ static override parentToken = "pad"
7
+ token = "clearance"
8
+ }
9
+ SxClass.register(PadClearance)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class PadDieLength extends SxPrimitiveNumber {
5
+ static override token = "die_length"
6
+ static override parentToken = "pad"
7
+ token = "die_length"
8
+ }
9
+ SxClass.register(PadDieLength)
@@ -0,0 +1,145 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { printSExpr } from "../parseToPrimitiveSExpr"
4
+ import { toNumberValue } from "../utils/toNumberValue"
5
+ import { PadDrillOffset } from "./PadDrillOffset"
6
+
7
+ export class PadDrill extends SxClass {
8
+ static override token = "drill"
9
+ static override parentToken = "pad"
10
+ token = "drill"
11
+
12
+ private _oval = false
13
+ private _diameter: number
14
+ private _width?: number
15
+ private _sxOffset?: PadDrillOffset
16
+
17
+ constructor({
18
+ oval = false,
19
+ diameter,
20
+ width,
21
+ offset,
22
+ }: {
23
+ oval?: boolean
24
+ diameter: number
25
+ width?: number
26
+ offset?: PadDrillOffset | { x: number; y: number }
27
+ }) {
28
+ super()
29
+ this._oval = oval
30
+ this._diameter = diameter
31
+ this._width = width
32
+ if (offset instanceof PadDrillOffset) {
33
+ this._sxOffset = offset
34
+ } else if (offset) {
35
+ this._sxOffset = new PadDrillOffset(offset.x, offset.y)
36
+ }
37
+ }
38
+
39
+ static override fromSexprPrimitives(
40
+ primitiveSexprs: PrimitiveSExpr[],
41
+ ): PadDrill {
42
+ const remaining = [...primitiveSexprs]
43
+ let oval = false
44
+ if (remaining[0] === "oval") {
45
+ oval = true
46
+ remaining.shift()
47
+ }
48
+
49
+ const diameter = toNumberValue(remaining.shift())
50
+ if (diameter === undefined) {
51
+ throw new Error("drill requires a diameter value")
52
+ }
53
+
54
+ let width: number | undefined
55
+ const potentialWidth = toNumberValue(remaining[0])
56
+ if (potentialWidth !== undefined) {
57
+ width = potentialWidth
58
+ remaining.shift()
59
+ }
60
+
61
+ const drill = new PadDrill({ oval, diameter, width })
62
+
63
+ for (const primitive of remaining) {
64
+ if (!Array.isArray(primitive)) {
65
+ throw new Error(
66
+ `drill encountered unexpected primitive child: ${JSON.stringify(primitive)}`,
67
+ )
68
+ }
69
+ const parsed = SxClass.parsePrimitiveSexpr(primitive, {
70
+ parentToken: this.token,
71
+ })
72
+ if (!(parsed instanceof PadDrillOffset)) {
73
+ throw new Error(
74
+ `drill encountered unsupported child token: ${printSExpr(primitive)}`,
75
+ )
76
+ }
77
+ if (drill._sxOffset) {
78
+ throw new Error("drill does not support multiple offset children")
79
+ }
80
+ drill._sxOffset = parsed
81
+ }
82
+
83
+ return drill
84
+ }
85
+
86
+ get oval(): boolean {
87
+ return this._oval
88
+ }
89
+
90
+ set oval(value: boolean) {
91
+ this._oval = value
92
+ }
93
+
94
+ get diameter(): number {
95
+ return this._diameter
96
+ }
97
+
98
+ set diameter(value: number) {
99
+ this._diameter = value
100
+ }
101
+
102
+ get width(): number | undefined {
103
+ return this._width
104
+ }
105
+
106
+ set width(value: number | undefined) {
107
+ this._width = value
108
+ }
109
+
110
+ get offset(): PadDrillOffset | undefined {
111
+ return this._sxOffset
112
+ }
113
+
114
+ set offset(value: PadDrillOffset | { x: number; y: number } | undefined) {
115
+ if (value === undefined) {
116
+ this._sxOffset = undefined
117
+ return
118
+ }
119
+ this._sxOffset =
120
+ value instanceof PadDrillOffset
121
+ ? value
122
+ : new PadDrillOffset(value.x, value.y)
123
+ }
124
+
125
+ override getChildren(): SxClass[] {
126
+ return this._sxOffset ? [this._sxOffset] : []
127
+ }
128
+
129
+ override getString(): string {
130
+ const tokens: string[] = []
131
+ if (this._oval) tokens.push("oval")
132
+ tokens.push(String(this._diameter))
133
+ if (this._width !== undefined) tokens.push(String(this._width))
134
+
135
+ if (!this._sxOffset) {
136
+ return `(drill ${tokens.join(" ")})`
137
+ }
138
+
139
+ const lines = [`(drill ${tokens.join(" ")}`]
140
+ lines.push(this._sxOffset.getStringIndented())
141
+ lines.push(")")
142
+ return lines.join("\n")
143
+ }
144
+ }
145
+ SxClass.register(PadDrill)
@@ -0,0 +1,54 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { toNumberValue } from "../utils/toNumberValue"
4
+
5
+ export class PadDrillOffset extends SxClass {
6
+ static override token = "offset"
7
+ static override parentToken = "drill"
8
+ token = "offset"
9
+
10
+ private _x: number
11
+ private _y: number
12
+
13
+ constructor(x: number, y: number) {
14
+ super()
15
+ this._x = x
16
+ this._y = y
17
+ }
18
+
19
+ static override fromSexprPrimitives(
20
+ primitiveSexprs: PrimitiveSExpr[],
21
+ ): PadDrillOffset {
22
+ const x = toNumberValue(primitiveSexprs[0])
23
+ const y = toNumberValue(primitiveSexprs[1])
24
+ if (x === undefined || y === undefined) {
25
+ throw new Error("drill offset requires x and y numeric values")
26
+ }
27
+ return new PadDrillOffset(x, y)
28
+ }
29
+
30
+ get x(): number {
31
+ return this._x
32
+ }
33
+
34
+ set x(value: number) {
35
+ this._x = value
36
+ }
37
+
38
+ get y(): number {
39
+ return this._y
40
+ }
41
+
42
+ set y(value: number) {
43
+ this._y = value
44
+ }
45
+
46
+ override getChildren(): SxClass[] {
47
+ return []
48
+ }
49
+
50
+ override getString(): string {
51
+ return `(offset ${this._x} ${this._y})`
52
+ }
53
+ }
54
+ SxClass.register(PadDrillOffset)
@@ -0,0 +1,59 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { printSExpr } from "../parseToPrimitiveSExpr"
4
+ import { quoteSExprString } from "../utils/quoteSExprString"
5
+ import { toStringValue } from "../utils/toStringValue"
6
+
7
+ export class PadLayers extends SxClass {
8
+ static override token = "layers"
9
+ static override parentToken = "pad"
10
+ token = "layers"
11
+
12
+ private _layers: string[] = []
13
+
14
+ constructor(layers: string[]) {
15
+ super()
16
+ this.layers = layers
17
+ }
18
+
19
+ static override fromSexprPrimitives(
20
+ primitiveSexprs: PrimitiveSExpr[],
21
+ ): PadLayers {
22
+ const layers = primitiveSexprs.map((primitive) => {
23
+ const value = toStringValue(primitive)
24
+ if (value === undefined) {
25
+ return printSExpr(primitive)
26
+ }
27
+ return value
28
+ })
29
+ return new PadLayers(layers)
30
+ }
31
+
32
+ get layers(): string[] {
33
+ return [...this._layers]
34
+ }
35
+
36
+ set layers(values: string[]) {
37
+ this._layers = values.map((value) => String(value))
38
+ }
39
+
40
+ override getChildren(): SxClass[] {
41
+ return []
42
+ }
43
+
44
+ override getString(): string {
45
+ if (this._layers.length === 0) {
46
+ return "(layers)"
47
+ }
48
+ const rendered = this._layers
49
+ .map((layer) => {
50
+ if (/^[^\s()"]+$/u.test(layer) && !["nil", "#t", "#f"].includes(layer)) {
51
+ return layer
52
+ }
53
+ return quoteSExprString(layer)
54
+ })
55
+ .join(" ")
56
+ return `(layers ${rendered})`
57
+ }
58
+ }
59
+ SxClass.register(PadLayers)
@@ -0,0 +1,56 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { quoteSExprString } from "../utils/quoteSExprString"
4
+ import { toNumberValue } from "../utils/toNumberValue"
5
+ import { toStringValue } from "../utils/toStringValue"
6
+
7
+ export class PadNet extends SxClass {
8
+ static override token = "net"
9
+ static override parentToken = "pad"
10
+ token = "net"
11
+
12
+ private _id: number
13
+ private _name: string
14
+
15
+ constructor(id: number, name: string) {
16
+ super()
17
+ this._id = id
18
+ this._name = name
19
+ }
20
+
21
+ static override fromSexprPrimitives(
22
+ primitiveSexprs: PrimitiveSExpr[],
23
+ ): PadNet {
24
+ const id = toNumberValue(primitiveSexprs[0])
25
+ const name = toStringValue(primitiveSexprs[1])
26
+ if (id === undefined || name === undefined) {
27
+ throw new Error("pad net requires numeric id and string name")
28
+ }
29
+ return new PadNet(id, name)
30
+ }
31
+
32
+ get id(): number {
33
+ return this._id
34
+ }
35
+
36
+ set id(value: number) {
37
+ this._id = value
38
+ }
39
+
40
+ get name(): string {
41
+ return this._name
42
+ }
43
+
44
+ set name(value: string) {
45
+ this._name = value
46
+ }
47
+
48
+ override getChildren(): SxClass[] {
49
+ return []
50
+ }
51
+
52
+ override getString(): string {
53
+ return `(net ${this._id} ${quoteSExprString(this._name)})`
54
+ }
55
+ }
56
+ SxClass.register(PadNet)
@@ -0,0 +1,182 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { toStringValue } from "../utils/toStringValue"
4
+
5
+ export type PadOptionsClearanceType = "outline" | "convexhull"
6
+ export type PadOptionsAnchorShape = "rect" | "circle"
7
+
8
+ const CLEARANCE_TYPES: PadOptionsClearanceType[] = [
9
+ "outline",
10
+ "convexhull",
11
+ ]
12
+
13
+ const ANCHOR_SHAPES: PadOptionsAnchorShape[] = ["rect", "circle"]
14
+
15
+ export class PadOptions extends SxClass {
16
+ static override token = "options"
17
+ static override parentToken = "pad"
18
+ override token = "options"
19
+
20
+ private _sxClearance?: PadOptionsClearance
21
+ private _sxAnchor?: PadOptionsAnchor
22
+
23
+ static override fromSexprPrimitives(
24
+ primitiveSexprs: PrimitiveSExpr[],
25
+ ): PadOptions {
26
+ const options = new PadOptions()
27
+
28
+ for (const primitive of primitiveSexprs) {
29
+ if (!Array.isArray(primitive) || primitive.length === 0) {
30
+ throw new Error(
31
+ `pad options encountered invalid child expression: ${JSON.stringify(primitive)}`,
32
+ )
33
+ }
34
+
35
+ const parsed = SxClass.parsePrimitiveSexpr(primitive, {
36
+ parentToken: this.token,
37
+ })
38
+
39
+ if (!(parsed instanceof SxClass)) {
40
+ throw new Error(
41
+ `pad options child did not resolve to an SxClass: ${JSON.stringify(primitive)}`,
42
+ )
43
+ }
44
+
45
+ if (parsed instanceof PadOptionsClearance) {
46
+ if (options._sxClearance) {
47
+ throw new Error("pad options encountered duplicate clearance tokens")
48
+ }
49
+ options._sxClearance = parsed
50
+ continue
51
+ }
52
+
53
+ if (parsed instanceof PadOptionsAnchor) {
54
+ if (options._sxAnchor) {
55
+ throw new Error("pad options encountered duplicate anchor tokens")
56
+ }
57
+ options._sxAnchor = parsed
58
+ continue
59
+ }
60
+
61
+ throw new Error(`pad options encountered unsupported token "${parsed.token}"`)
62
+ }
63
+
64
+ return options
65
+ }
66
+
67
+ get clearance(): PadOptionsClearanceType | undefined {
68
+ return this._sxClearance?.type
69
+ }
70
+
71
+ set clearance(value: PadOptionsClearanceType | undefined) {
72
+ this._sxClearance = value ? new PadOptionsClearance(value) : undefined
73
+ }
74
+
75
+ get anchor(): PadOptionsAnchorShape | undefined {
76
+ return this._sxAnchor?.shape
77
+ }
78
+
79
+ set anchor(value: PadOptionsAnchorShape | undefined) {
80
+ this._sxAnchor = value ? new PadOptionsAnchor(value) : undefined
81
+ }
82
+
83
+ override getChildren(): SxClass[] {
84
+ const children: SxClass[] = []
85
+ if (this._sxClearance) children.push(this._sxClearance)
86
+ if (this._sxAnchor) children.push(this._sxAnchor)
87
+ return children
88
+ }
89
+ }
90
+ SxClass.register(PadOptions)
91
+
92
+ class PadOptionsClearance extends SxClass {
93
+ static override token = "clearance"
94
+ static override parentToken = "options"
95
+ override token = "clearance"
96
+
97
+ private _type: PadOptionsClearanceType
98
+
99
+ constructor(type: PadOptionsClearanceType) {
100
+ super()
101
+ this._type = type
102
+ }
103
+
104
+ static override fromSexprPrimitives(
105
+ primitiveSexprs: PrimitiveSExpr[],
106
+ ): PadOptionsClearance {
107
+ const [raw] = primitiveSexprs
108
+ const stringValue = toStringValue(raw)
109
+ if (stringValue === undefined) {
110
+ throw new Error("pad options clearance requires a string value")
111
+ }
112
+ if (!CLEARANCE_TYPES.includes(stringValue as PadOptionsClearanceType)) {
113
+ throw new Error(
114
+ `pad options clearance must be one of ${CLEARANCE_TYPES.join(", ")}`,
115
+ )
116
+ }
117
+ return new PadOptionsClearance(stringValue as PadOptionsClearanceType)
118
+ }
119
+
120
+ get type(): PadOptionsClearanceType {
121
+ return this._type
122
+ }
123
+
124
+ set type(value: PadOptionsClearanceType) {
125
+ this._type = value
126
+ }
127
+
128
+ override getChildren(): SxClass[] {
129
+ return []
130
+ }
131
+
132
+ override getString(): string {
133
+ return `(clearance ${this._type})`
134
+ }
135
+ }
136
+ SxClass.register(PadOptionsClearance)
137
+
138
+ class PadOptionsAnchor extends SxClass {
139
+ static override token = "anchor"
140
+ static override parentToken = "options"
141
+ override token = "anchor"
142
+
143
+ private _shape: PadOptionsAnchorShape
144
+
145
+ constructor(shape: PadOptionsAnchorShape) {
146
+ super()
147
+ this._shape = shape
148
+ }
149
+
150
+ static override fromSexprPrimitives(
151
+ primitiveSexprs: PrimitiveSExpr[],
152
+ ): PadOptionsAnchor {
153
+ const [raw] = primitiveSexprs
154
+ const stringValue = toStringValue(raw)
155
+ if (stringValue === undefined) {
156
+ throw new Error("pad options anchor requires a string value")
157
+ }
158
+ if (!ANCHOR_SHAPES.includes(stringValue as PadOptionsAnchorShape)) {
159
+ throw new Error(
160
+ `pad options anchor must be one of ${ANCHOR_SHAPES.join(", ")}`,
161
+ )
162
+ }
163
+ return new PadOptionsAnchor(stringValue as PadOptionsAnchorShape)
164
+ }
165
+
166
+ get shape(): PadOptionsAnchorShape {
167
+ return this._shape
168
+ }
169
+
170
+ set shape(value: PadOptionsAnchorShape) {
171
+ this._shape = value
172
+ }
173
+
174
+ override getChildren(): SxClass[] {
175
+ return []
176
+ }
177
+
178
+ override getString(): string {
179
+ return `(anchor ${this._shape})`
180
+ }
181
+ }
182
+ SxClass.register(PadOptionsAnchor)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveString } from "../base-classes/SxPrimitiveString"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class PadPinFunction extends SxPrimitiveString {
5
+ static override token = "pinfunction"
6
+ static override parentToken = "pad"
7
+ token = "pinfunction"
8
+ }
9
+ SxClass.register(PadPinFunction)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveString } from "../base-classes/SxPrimitiveString"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class PadPinType extends SxPrimitiveString {
5
+ static override token = "pintype"
6
+ static override parentToken = "pad"
7
+ token = "pintype"
8
+ }
9
+ SxClass.register(PadPinType)