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,102 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+
4
+ const FLAG_TOKENS = new Set([
5
+ "board_only",
6
+ "exclude_from_pos_files",
7
+ "exclude_from_bom",
8
+ ])
9
+
10
+ export class FootprintAttr extends SxClass {
11
+ static override token = "attr"
12
+ static override parentToken = "footprint"
13
+ token = "attr"
14
+
15
+ private _type?: string
16
+ private _boardOnly = false
17
+ private _excludeFromPosFiles = false
18
+ private _excludeFromBom = false
19
+
20
+ static override fromSexprPrimitives(
21
+ primitiveSexprs: PrimitiveSExpr[],
22
+ ): FootprintAttr {
23
+ const attr = new FootprintAttr()
24
+ for (const primitive of primitiveSexprs) {
25
+ if (typeof primitive !== "string") {
26
+ throw new Error(
27
+ `attr encountered unsupported child: ${JSON.stringify(primitive)}`,
28
+ )
29
+ }
30
+ if (FLAG_TOKENS.has(primitive)) {
31
+ attr.applyFlag(primitive)
32
+ continue
33
+ }
34
+ if (attr._type === undefined) {
35
+ attr._type = primitive
36
+ continue
37
+ }
38
+ throw new Error(`attr encountered duplicate or unknown token "${primitive}"`)
39
+ }
40
+ return attr
41
+ }
42
+
43
+ private applyFlag(flag: string) {
44
+ switch (flag) {
45
+ case "board_only":
46
+ this._boardOnly = true
47
+ break
48
+ case "exclude_from_pos_files":
49
+ this._excludeFromPosFiles = true
50
+ break
51
+ case "exclude_from_bom":
52
+ this._excludeFromBom = true
53
+ break
54
+ }
55
+ }
56
+
57
+ get type(): string | undefined {
58
+ return this._type
59
+ }
60
+
61
+ set type(value: string | undefined) {
62
+ this._type = value
63
+ }
64
+
65
+ get boardOnly(): boolean {
66
+ return this._boardOnly
67
+ }
68
+
69
+ set boardOnly(value: boolean) {
70
+ this._boardOnly = value
71
+ }
72
+
73
+ get excludeFromPosFiles(): boolean {
74
+ return this._excludeFromPosFiles
75
+ }
76
+
77
+ set excludeFromPosFiles(value: boolean) {
78
+ this._excludeFromPosFiles = value
79
+ }
80
+
81
+ get excludeFromBom(): boolean {
82
+ return this._excludeFromBom
83
+ }
84
+
85
+ set excludeFromBom(value: boolean) {
86
+ this._excludeFromBom = value
87
+ }
88
+
89
+ override getChildren(): SxClass[] {
90
+ return []
91
+ }
92
+
93
+ override getString(): string {
94
+ const tokens = ["attr"]
95
+ if (this._type) tokens.push(this._type)
96
+ if (this._boardOnly) tokens.push("board_only")
97
+ if (this._excludeFromPosFiles) tokens.push("exclude_from_pos_files")
98
+ if (this._excludeFromBom) tokens.push("exclude_from_bom")
99
+ return `(${tokens.join(" ")})`
100
+ }
101
+ }
102
+ SxClass.register(FootprintAttr)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class FootprintAutoplaceCost180 extends SxPrimitiveNumber {
5
+ static override token = "autoplace_cost180"
6
+ static override parentToken = "footprint"
7
+ token = "autoplace_cost180"
8
+ }
9
+ SxClass.register(FootprintAutoplaceCost180)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class FootprintAutoplaceCost90 extends SxPrimitiveNumber {
5
+ static override token = "autoplace_cost90"
6
+ static override parentToken = "footprint"
7
+ token = "autoplace_cost90"
8
+ }
9
+ SxClass.register(FootprintAutoplaceCost90)
@@ -0,0 +1,9 @@
1
+ import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
2
+ import { SxClass } from "../base-classes/SxClass"
3
+
4
+ export class FootprintClearance extends SxPrimitiveNumber {
5
+ static override token = "clearance"
6
+ static override parentToken = "footprint"
7
+ token = "clearance"
8
+ }
9
+ SxClass.register(FootprintClearance)
@@ -0,0 +1,44 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { quoteSExprString } from "../utils/quoteSExprString"
4
+ import { toStringValue } from "../utils/toStringValue"
5
+
6
+ export class FootprintDescr extends SxClass {
7
+ static override token = "descr"
8
+ static override parentToken = "footprint"
9
+ token = "descr"
10
+
11
+ private _value: string
12
+
13
+ constructor(value: string) {
14
+ super()
15
+ this._value = value
16
+ }
17
+
18
+ static override fromSexprPrimitives(
19
+ primitiveSexprs: PrimitiveSExpr[],
20
+ ): FootprintDescr {
21
+ const value = toStringValue(primitiveSexprs[0])
22
+ if (value === undefined) {
23
+ throw new Error("descr expects a string value")
24
+ }
25
+ return new FootprintDescr(value)
26
+ }
27
+
28
+ get value(): string {
29
+ return this._value
30
+ }
31
+
32
+ set value(value: string) {
33
+ this._value = value
34
+ }
35
+
36
+ override getChildren(): SxClass[] {
37
+ return []
38
+ }
39
+
40
+ override getString(): string {
41
+ return `(descr ${quoteSExprString(this._value)})`
42
+ }
43
+ }
44
+ SxClass.register(FootprintDescr)
@@ -0,0 +1,32 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
3
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
4
+ import { parseYesNo } from "../utils/parseYesNo"
5
+
6
+ export class FootprintLocked extends SxPrimitiveBoolean {
7
+ static override token = "locked"
8
+ static override parentToken = "footprint"
9
+ token = "locked"
10
+
11
+ constructor(value = true) {
12
+ super(value)
13
+ }
14
+
15
+ static override fromSexprPrimitives(
16
+ primitiveSexprs: PrimitiveSExpr[],
17
+ ): FootprintLocked {
18
+ if (primitiveSexprs.length === 0) {
19
+ return new FootprintLocked(true)
20
+ }
21
+
22
+ const parsed = parseYesNo(primitiveSexprs[0])
23
+ if (parsed === undefined) {
24
+ throw new Error(
25
+ `locked expects yes/no, received ${JSON.stringify(primitiveSexprs[0])}`,
26
+ )
27
+ }
28
+
29
+ return new FootprintLocked(parsed)
30
+ }
31
+ }
32
+ SxClass.register(FootprintLocked)
@@ -0,0 +1,145 @@
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 interface ModelVector {
8
+ x: number
9
+ y: number
10
+ z: number
11
+ }
12
+
13
+ const DEFAULT_VECTOR: ModelVector = { x: 0, y: 0, z: 0 }
14
+
15
+ export class FootprintModel extends SxClass {
16
+ static override token = "model"
17
+ static override parentToken = "footprint"
18
+ override token = "model"
19
+
20
+ private _path: string
21
+ private _offset?: ModelVector
22
+ private _scale?: ModelVector
23
+ private _rotate?: ModelVector
24
+
25
+ constructor(path: string) {
26
+ super()
27
+ this._path = path
28
+ }
29
+
30
+ static override fromSexprPrimitives(
31
+ primitiveSexprs: PrimitiveSExpr[],
32
+ ): FootprintModel {
33
+ if (primitiveSexprs.length === 0) {
34
+ throw new Error("model requires a path argument")
35
+ }
36
+
37
+ const [rawPath, ...rest] = primitiveSexprs
38
+ const path = toStringValue(rawPath)
39
+ if (path === undefined) {
40
+ throw new Error("model path must be a string value")
41
+ }
42
+
43
+ const model = new FootprintModel(path)
44
+
45
+ for (const primitive of rest) {
46
+ if (!Array.isArray(primitive) || primitive.length === 0) {
47
+ throw new Error(
48
+ `model encountered invalid child expression: ${JSON.stringify(primitive)}`,
49
+ )
50
+ }
51
+ const [token, ...args] = primitive
52
+ if (token === "offset") {
53
+ model._offset = parseVectorArgs(args, "offset")
54
+ continue
55
+ }
56
+ if (token === "scale") {
57
+ model._scale = parseVectorArgs(args, "scale")
58
+ continue
59
+ }
60
+ if (token === "rotate") {
61
+ model._rotate = parseVectorArgs(args, "rotate")
62
+ continue
63
+ }
64
+ throw new Error(`model encountered unsupported child token "${token}"`)
65
+ }
66
+
67
+ return model
68
+ }
69
+
70
+ get path(): string {
71
+ return this._path
72
+ }
73
+
74
+ set path(value: string) {
75
+ this._path = value
76
+ }
77
+
78
+ get offset(): ModelVector | undefined {
79
+ return this._offset ? { ...this._offset } : undefined
80
+ }
81
+
82
+ set offset(value: ModelVector | undefined) {
83
+ this._offset = value ? { ...value } : undefined
84
+ }
85
+
86
+ get scale(): ModelVector | undefined {
87
+ return this._scale ? { ...this._scale } : undefined
88
+ }
89
+
90
+ set scale(value: ModelVector | undefined) {
91
+ this._scale = value ? { ...value } : undefined
92
+ }
93
+
94
+ get rotate(): ModelVector | undefined {
95
+ return this._rotate ? { ...this._rotate } : undefined
96
+ }
97
+
98
+ set rotate(value: ModelVector | undefined) {
99
+ this._rotate = value ? { ...value } : undefined
100
+ }
101
+
102
+ override getChildren(): SxClass[] {
103
+ return []
104
+ }
105
+
106
+ override getString(): string {
107
+ const lines = [`(model ${quoteSExprString(this._path)}`]
108
+ if (this._offset) {
109
+ lines.push(renderVectorBlock("offset", this._offset))
110
+ }
111
+ if (this._scale) {
112
+ lines.push(renderVectorBlock("scale", this._scale))
113
+ }
114
+ if (this._rotate) {
115
+ lines.push(renderVectorBlock("rotate", this._rotate))
116
+ }
117
+ lines.push(")")
118
+ return lines.join("\n")
119
+ }
120
+ }
121
+ SxClass.register(FootprintModel)
122
+
123
+ function parseVectorArgs(
124
+ args: PrimitiveSExpr[],
125
+ token: string,
126
+ ): ModelVector {
127
+ if (args.length !== 1) {
128
+ throw new Error(`model ${token} expects a single xyz child`)
129
+ }
130
+ const [first] = args
131
+ if (!Array.isArray(first) || first.length !== 4 || first[0] !== "xyz") {
132
+ throw new Error(
133
+ `model ${token} expects (xyz x y z), received ${JSON.stringify(first)}`,
134
+ )
135
+ }
136
+ const [, rawX, rawY, rawZ] = first
137
+ const x = toNumberValue(rawX) ?? DEFAULT_VECTOR.x
138
+ const y = toNumberValue(rawY) ?? DEFAULT_VECTOR.y
139
+ const z = toNumberValue(rawZ) ?? DEFAULT_VECTOR.z
140
+ return { x, y, z }
141
+ }
142
+
143
+ function renderVectorBlock(label: string, vector: ModelVector): string {
144
+ return ` (${label}\n (xyz ${vector.x} ${vector.y} ${vector.z})\n )`
145
+ }
@@ -0,0 +1,50 @@
1
+ import { SxClass } from "../base-classes/SxClass"
2
+ import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
3
+ import { quoteSExprString } from "../utils/quoteSExprString"
4
+ import { toStringValue } from "../utils/toStringValue"
5
+
6
+ export class FootprintNetTiePadGroups extends SxClass {
7
+ static override token = "net_tie_pad_groups"
8
+ static override parentToken = "footprint"
9
+ token = "net_tie_pad_groups"
10
+
11
+ private _groups: string[] = []
12
+
13
+ constructor(groups: string[]) {
14
+ super()
15
+ this.groups = groups
16
+ }
17
+
18
+ static override fromSexprPrimitives(
19
+ primitiveSexprs: PrimitiveSExpr[],
20
+ ): FootprintNetTiePadGroups {
21
+ const groups = primitiveSexprs.map((primitive) => {
22
+ const value = toStringValue(primitive)
23
+ if (value === undefined) {
24
+ throw new Error(
25
+ `net_tie_pad_groups expects string group entries, received ${JSON.stringify(primitive)}`,
26
+ )
27
+ }
28
+ return value
29
+ })
30
+ return new FootprintNetTiePadGroups(groups)
31
+ }
32
+
33
+ get groups(): string[] {
34
+ return [...this._groups]
35
+ }
36
+
37
+ set groups(values: string[]) {
38
+ this._groups = values.map((value) => String(value))
39
+ }
40
+
41
+ override getChildren(): SxClass[] {
42
+ return []
43
+ }
44
+
45
+ override getString(): string {
46
+ const rendered = this._groups.map((group) => quoteSExprString(group)).join(" ")
47
+ return `(net_tie_pad_groups ${rendered})`
48
+ }
49
+ }
50
+ SxClass.register(FootprintNetTiePadGroups)