kicadts 0.0.1 → 0.0.2
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.
- package/.github/workflows/bun-formatcheck.yml +26 -0
- package/.github/workflows/bun-pver-release.yml +70 -0
- package/.github/workflows/bun-test.yml +32 -0
- package/.github/workflows/bun-typecheck.yml +26 -0
- package/.vscode/settings.json +1 -1
- package/AGENTS.md +1 -0
- package/LICENSE +21 -0
- package/README.md +101 -91
- package/TODO.md +46 -0
- package/bunfig.toml +2 -2
- package/lib/sexpr/classes/At.ts +15 -0
- package/lib/sexpr/classes/Bus.ts +23 -3
- package/lib/sexpr/classes/BusEntry.ts +30 -3
- package/lib/sexpr/classes/EmbeddedFonts.ts +1 -3
- package/lib/sexpr/classes/Footprint.ts +157 -27
- package/lib/sexpr/classes/FootprintAttr.ts +3 -1
- package/lib/sexpr/classes/FootprintModel.ts +1 -4
- package/lib/sexpr/classes/FootprintNetTiePadGroups.ts +3 -1
- package/lib/sexpr/classes/FootprintPad.ts +206 -54
- package/lib/sexpr/classes/FpArc.ts +23 -0
- package/lib/sexpr/classes/FpCircle.ts +24 -3
- package/lib/sexpr/classes/FpLine.ts +31 -3
- package/lib/sexpr/classes/FpPoly.ts +24 -4
- package/lib/sexpr/classes/FpRect.ts +24 -3
- package/lib/sexpr/classes/FpText.ts +43 -9
- package/lib/sexpr/classes/FpTextBox.ts +43 -5
- package/lib/sexpr/classes/GrLine.ts +20 -1
- package/lib/sexpr/classes/GrText.ts +38 -12
- package/lib/sexpr/classes/Image.ts +38 -11
- package/lib/sexpr/classes/Junction.ts +36 -4
- package/lib/sexpr/classes/KicadPcb.ts +49 -1
- package/lib/sexpr/classes/KicadSch.ts +119 -25
- package/lib/sexpr/classes/Label.ts +45 -5
- package/lib/sexpr/classes/NoConnect.ts +20 -3
- package/lib/sexpr/classes/PadLayers.ts +13 -1
- package/lib/sexpr/classes/PadOptions.ts +4 -5
- package/lib/sexpr/classes/PadPrimitiveGrArc.ts +22 -4
- package/lib/sexpr/classes/PadPrimitiveGrCircle.ts +23 -4
- package/lib/sexpr/classes/PadPrimitives.ts +3 -1
- package/lib/sexpr/classes/PadSize.ts +15 -0
- package/lib/sexpr/classes/PadTeardrops.ts +3 -1
- package/lib/sexpr/classes/PcbGeneral.ts +14 -7
- package/lib/sexpr/classes/PcbLayerDefinition.ts +5 -1
- package/lib/sexpr/classes/Property.ts +64 -9
- package/lib/sexpr/classes/Pts.ts +7 -5
- package/lib/sexpr/classes/SchematicText.ts +39 -9
- package/lib/sexpr/classes/Segment.ts +21 -0
- package/lib/sexpr/classes/SegmentNet.ts +3 -1
- package/lib/sexpr/classes/Setup/PcbPlotParams.ts +10 -50
- package/lib/sexpr/classes/Setup/Setup.ts +12 -11
- package/lib/sexpr/classes/Setup/Stackup.ts +14 -19
- package/lib/sexpr/classes/Setup/StackupLayerProperties.ts +3 -1
- package/lib/sexpr/classes/Setup/StackupProperties.ts +0 -1
- package/lib/sexpr/classes/Setup/base.ts +1 -3
- package/lib/sexpr/classes/Setup/setupMultiValueProperties.ts +0 -1
- package/lib/sexpr/classes/Sheet.ts +85 -3
- package/lib/sexpr/classes/SheetPin.ts +4 -1
- package/lib/sexpr/classes/Symbol.ts +176 -51
- package/lib/sexpr/classes/TextEffects.ts +25 -8
- package/lib/sexpr/classes/TitleBlock.ts +21 -4
- package/lib/sexpr/classes/Via.ts +38 -3
- package/lib/sexpr/classes/ViaNet.ts +2 -1
- package/lib/sexpr/classes/Wire.ts +23 -3
- package/lib/sexpr/classes/Xy.ts +1 -3
- package/lib/sexpr/classes/Zone.ts +1 -3
- package/lib/sexpr/parseToPrimitiveSExpr.ts +6 -1
- package/lib/sexpr/utils/strokeFromArgs.ts +5 -6
- package/lib/sexpr/utils/toStringValue.ts +2 -1
- package/package.json +2 -1
- package/scripts/download-references.ts +24 -22
- package/tests/fixtures/expectEqualPrimitiveSExpr.ts +6 -7
- package/tests/fixtures/png-matcher.ts +109 -0
- package/tests/fixtures/preload.ts +1 -0
- package/tests/sexpr/classes/FootprintPad.test.ts +8 -1
- package/tests/sexpr/classes/Image.test.ts +9 -1
- package/tests/sexpr/classes/KicadSch.test.ts +1 -3
- package/tests/sexpr/classes/Setup.test.ts +0 -1
- package/bun.lock +0 -48
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SxClass } from "../base-classes/SxClass"
|
|
2
2
|
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
3
|
import { quoteSExprString } from "../utils/quoteSExprString"
|
|
4
|
-
import { At } from "./At"
|
|
4
|
+
import { At, type AtInput } from "./At"
|
|
5
5
|
import { FootprintAttr } from "./FootprintAttr"
|
|
6
6
|
import { FootprintAutoplaceCost180 } from "./FootprintAutoplaceCost180"
|
|
7
7
|
import { FootprintAutoplaceCost90 } from "./FootprintAutoplaceCost90"
|
|
@@ -80,6 +80,43 @@ const MULTI_TOKENS = new Set([
|
|
|
80
80
|
|
|
81
81
|
const SUPPORTED_TOKENS = new Set([...SINGLE_TOKENS, ...MULTI_TOKENS])
|
|
82
82
|
|
|
83
|
+
export interface FootprintConstructorParams {
|
|
84
|
+
libraryLink?: string
|
|
85
|
+
locked?: boolean
|
|
86
|
+
placed?: boolean
|
|
87
|
+
layer?: Layer | string | string[]
|
|
88
|
+
uuid?: Uuid | string
|
|
89
|
+
at?: AtInput | Xy
|
|
90
|
+
descr?: string | FootprintDescr
|
|
91
|
+
tags?: string | string[] | FootprintTags
|
|
92
|
+
path?: string | FootprintPath
|
|
93
|
+
autoplaceCost90?: number | FootprintAutoplaceCost90
|
|
94
|
+
autoplaceCost180?: number | FootprintAutoplaceCost180
|
|
95
|
+
solderMaskMargin?: number | FootprintSolderMaskMargin
|
|
96
|
+
solderPasteMargin?: number | FootprintSolderPasteMargin
|
|
97
|
+
solderPasteRatio?: number | FootprintSolderPasteRatio
|
|
98
|
+
clearance?: number | FootprintClearance
|
|
99
|
+
zoneConnect?: number | FootprintZoneConnect
|
|
100
|
+
thermalWidth?: number | FootprintThermalWidth
|
|
101
|
+
thermalGap?: number | FootprintThermalGap
|
|
102
|
+
attr?: FootprintAttr
|
|
103
|
+
privateLayers?: FootprintPrivateLayers
|
|
104
|
+
netTiePadGroups?: FootprintNetTiePadGroups
|
|
105
|
+
sheetname?: string | FootprintSheetname
|
|
106
|
+
sheetfile?: string | FootprintSheetfile
|
|
107
|
+
embeddedFonts?: EmbeddedFonts
|
|
108
|
+
properties?: Property[]
|
|
109
|
+
fpTexts?: FpText[]
|
|
110
|
+
fpTextBoxes?: FpTextBox[]
|
|
111
|
+
fpLines?: FpLine[]
|
|
112
|
+
fpRects?: FpRect[]
|
|
113
|
+
fpCircles?: FpCircle[]
|
|
114
|
+
fpArcs?: FpArc[]
|
|
115
|
+
fpPolys?: FpPoly[]
|
|
116
|
+
pads?: FootprintPad[]
|
|
117
|
+
models?: FootprintModel[]
|
|
118
|
+
}
|
|
119
|
+
|
|
83
120
|
export class Footprint extends SxClass {
|
|
84
121
|
static override token = "footprint"
|
|
85
122
|
token = "footprint"
|
|
@@ -87,7 +124,7 @@ export class Footprint extends SxClass {
|
|
|
87
124
|
private _libraryLink?: string
|
|
88
125
|
private _sxLocked?: FootprintLocked
|
|
89
126
|
private _sxPlaced?: FootprintPlaced
|
|
90
|
-
|
|
127
|
+
|
|
91
128
|
private _sxLayer?: Layer
|
|
92
129
|
private _sxTedit?: FootprintTedit
|
|
93
130
|
private _sxUuid?: Uuid
|
|
@@ -123,6 +160,53 @@ export class Footprint extends SxClass {
|
|
|
123
160
|
private _fpPads: FootprintPad[] = []
|
|
124
161
|
private _models: FootprintModel[] = []
|
|
125
162
|
|
|
163
|
+
constructor(params: FootprintConstructorParams = {}) {
|
|
164
|
+
super()
|
|
165
|
+
if (params.libraryLink !== undefined) this.libraryLink = params.libraryLink
|
|
166
|
+
if (params.locked !== undefined) this.locked = params.locked
|
|
167
|
+
if (params.placed !== undefined) this.placed = params.placed
|
|
168
|
+
if (params.layer !== undefined) this.layer = params.layer
|
|
169
|
+
if (params.uuid !== undefined) this.uuid = params.uuid
|
|
170
|
+
if (params.at !== undefined) this.position = params.at
|
|
171
|
+
if (params.descr !== undefined) this.descr = params.descr
|
|
172
|
+
if (params.tags !== undefined) this.tags = params.tags
|
|
173
|
+
if (params.path !== undefined) this.path = params.path
|
|
174
|
+
if (params.autoplaceCost90 !== undefined)
|
|
175
|
+
this.autoplaceCost90 = params.autoplaceCost90
|
|
176
|
+
if (params.autoplaceCost180 !== undefined)
|
|
177
|
+
this.autoplaceCost180 = params.autoplaceCost180
|
|
178
|
+
if (params.solderMaskMargin !== undefined)
|
|
179
|
+
this.solderMaskMargin = params.solderMaskMargin
|
|
180
|
+
if (params.solderPasteMargin !== undefined)
|
|
181
|
+
this.solderPasteMargin = params.solderPasteMargin
|
|
182
|
+
if (params.solderPasteRatio !== undefined)
|
|
183
|
+
this.solderPasteRatio = params.solderPasteRatio
|
|
184
|
+
if (params.clearance !== undefined) this.clearance = params.clearance
|
|
185
|
+
if (params.zoneConnect !== undefined) this.zoneConnect = params.zoneConnect
|
|
186
|
+
if (params.thermalWidth !== undefined)
|
|
187
|
+
this.thermalWidth = params.thermalWidth
|
|
188
|
+
if (params.thermalGap !== undefined) this.thermalGap = params.thermalGap
|
|
189
|
+
if (params.attr !== undefined) this.attr = params.attr
|
|
190
|
+
if (params.privateLayers !== undefined)
|
|
191
|
+
this.privateLayers = params.privateLayers
|
|
192
|
+
if (params.netTiePadGroups !== undefined)
|
|
193
|
+
this.netTiePadGroups = params.netTiePadGroups
|
|
194
|
+
if (params.sheetname !== undefined) this.sheetname = params.sheetname
|
|
195
|
+
if (params.sheetfile !== undefined) this.sheetfile = params.sheetfile
|
|
196
|
+
if (params.embeddedFonts !== undefined)
|
|
197
|
+
this.embeddedFonts = params.embeddedFonts
|
|
198
|
+
if (params.properties !== undefined) this.properties = params.properties
|
|
199
|
+
if (params.fpTexts !== undefined) this.fpTexts = params.fpTexts
|
|
200
|
+
if (params.fpTextBoxes !== undefined) this.fpTextBoxes = params.fpTextBoxes
|
|
201
|
+
if (params.fpLines !== undefined) this.fpLines = params.fpLines
|
|
202
|
+
if (params.fpRects !== undefined) this.fpRects = params.fpRects
|
|
203
|
+
if (params.fpCircles !== undefined) this.fpCircles = params.fpCircles
|
|
204
|
+
if (params.fpArcs !== undefined) this.fpArcs = params.fpArcs
|
|
205
|
+
if (params.fpPolys !== undefined) this.fpPolys = params.fpPolys
|
|
206
|
+
if (params.pads !== undefined) this.fpPads = params.pads
|
|
207
|
+
if (params.models !== undefined) this.models = params.models
|
|
208
|
+
}
|
|
209
|
+
|
|
126
210
|
static override fromSexprPrimitives(
|
|
127
211
|
primitiveSexprs: PrimitiveSExpr[],
|
|
128
212
|
): Footprint {
|
|
@@ -156,16 +240,22 @@ export class Footprint extends SxClass {
|
|
|
156
240
|
|
|
157
241
|
for (const token of Object.keys(propertyMap)) {
|
|
158
242
|
if (!SUPPORTED_TOKENS.has(token)) {
|
|
159
|
-
throw new Error(
|
|
243
|
+
throw new Error(
|
|
244
|
+
`footprint encountered unsupported child token "${token}"`,
|
|
245
|
+
)
|
|
160
246
|
}
|
|
161
247
|
}
|
|
162
248
|
|
|
163
249
|
for (const [token, entries] of Object.entries(arrayPropertyMap)) {
|
|
164
250
|
if (!SUPPORTED_TOKENS.has(token)) {
|
|
165
|
-
throw new Error(
|
|
251
|
+
throw new Error(
|
|
252
|
+
`footprint encountered unsupported child token "${token}"`,
|
|
253
|
+
)
|
|
166
254
|
}
|
|
167
255
|
if (!MULTI_TOKENS.has(token) && entries.length > 1) {
|
|
168
|
-
throw new Error(
|
|
256
|
+
throw new Error(
|
|
257
|
+
`footprint does not support repeated child token "${token}"`,
|
|
258
|
+
)
|
|
169
259
|
}
|
|
170
260
|
}
|
|
171
261
|
|
|
@@ -203,14 +293,18 @@ export class Footprint extends SxClass {
|
|
|
203
293
|
footprint._sxSolderPasteRatio = propertyMap.solder_paste_ratio as
|
|
204
294
|
| FootprintSolderPasteRatio
|
|
205
295
|
| undefined
|
|
206
|
-
footprint._sxClearance = propertyMap.clearance as
|
|
296
|
+
footprint._sxClearance = propertyMap.clearance as
|
|
297
|
+
| FootprintClearance
|
|
298
|
+
| undefined
|
|
207
299
|
footprint._sxZoneConnect = propertyMap.zone_connect as
|
|
208
300
|
| FootprintZoneConnect
|
|
209
301
|
| undefined
|
|
210
302
|
footprint._sxThermalWidth = propertyMap.thermal_width as
|
|
211
303
|
| FootprintThermalWidth
|
|
212
304
|
| undefined
|
|
213
|
-
footprint._sxThermalGap = propertyMap.thermal_gap as
|
|
305
|
+
footprint._sxThermalGap = propertyMap.thermal_gap as
|
|
306
|
+
| FootprintThermalGap
|
|
307
|
+
| undefined
|
|
214
308
|
footprint._sxAttr = propertyMap.attr as FootprintAttr | undefined
|
|
215
309
|
footprint._sxPrivateLayers = propertyMap.private_layers as
|
|
216
310
|
| FootprintPrivateLayers
|
|
@@ -218,9 +312,15 @@ export class Footprint extends SxClass {
|
|
|
218
312
|
footprint._sxNetTiePadGroups = propertyMap.net_tie_pad_groups as
|
|
219
313
|
| FootprintNetTiePadGroups
|
|
220
314
|
| undefined
|
|
221
|
-
footprint._sxSheetname = propertyMap.sheetname as
|
|
222
|
-
|
|
223
|
-
|
|
315
|
+
footprint._sxSheetname = propertyMap.sheetname as
|
|
316
|
+
| FootprintSheetname
|
|
317
|
+
| undefined
|
|
318
|
+
footprint._sxSheetfile = propertyMap.sheetfile as
|
|
319
|
+
| FootprintSheetfile
|
|
320
|
+
| undefined
|
|
321
|
+
footprint._sxEmbeddedFonts = propertyMap.embedded_fonts as
|
|
322
|
+
| EmbeddedFonts
|
|
323
|
+
| undefined
|
|
224
324
|
|
|
225
325
|
footprint._properties = (arrayPropertyMap.property as Property[]) ?? []
|
|
226
326
|
footprint._fpTexts = (arrayPropertyMap["fp_text"] as FpText[]) ?? []
|
|
@@ -321,7 +421,8 @@ export class Footprint extends SxClass {
|
|
|
321
421
|
this._sxTedit = undefined
|
|
322
422
|
return
|
|
323
423
|
}
|
|
324
|
-
this._sxTedit =
|
|
424
|
+
this._sxTedit =
|
|
425
|
+
value instanceof FootprintTedit ? value : new FootprintTedit(value)
|
|
325
426
|
}
|
|
326
427
|
|
|
327
428
|
get uuid(): Uuid | undefined {
|
|
@@ -340,9 +441,9 @@ export class Footprint extends SxClass {
|
|
|
340
441
|
return this._sxAt ?? this._sxXy
|
|
341
442
|
}
|
|
342
443
|
|
|
343
|
-
set position(value:
|
|
344
|
-
if (value
|
|
345
|
-
this._sxAt =
|
|
444
|
+
set position(value: AtInput | Xy | undefined) {
|
|
445
|
+
if (value === undefined) {
|
|
446
|
+
this._sxAt = undefined
|
|
346
447
|
this._sxXy = undefined
|
|
347
448
|
return
|
|
348
449
|
}
|
|
@@ -351,7 +452,8 @@ export class Footprint extends SxClass {
|
|
|
351
452
|
this._sxAt = undefined
|
|
352
453
|
return
|
|
353
454
|
}
|
|
354
|
-
|
|
455
|
+
// Handle AtInput (At, array, or object)
|
|
456
|
+
this._sxAt = At.from(value as AtInput)
|
|
355
457
|
this._sxXy = undefined
|
|
356
458
|
}
|
|
357
459
|
|
|
@@ -364,19 +466,25 @@ export class Footprint extends SxClass {
|
|
|
364
466
|
this._sxDescr = undefined
|
|
365
467
|
return
|
|
366
468
|
}
|
|
367
|
-
this._sxDescr =
|
|
469
|
+
this._sxDescr =
|
|
470
|
+
value instanceof FootprintDescr ? value : new FootprintDescr(value)
|
|
368
471
|
}
|
|
369
472
|
|
|
370
473
|
get tags(): FootprintTags | undefined {
|
|
371
474
|
return this._sxTags
|
|
372
475
|
}
|
|
373
476
|
|
|
374
|
-
set tags(value:
|
|
477
|
+
set tags(value: string | string[] | FootprintTags | undefined) {
|
|
375
478
|
if (value === undefined) {
|
|
376
479
|
this._sxTags = undefined
|
|
377
480
|
return
|
|
378
481
|
}
|
|
379
|
-
|
|
482
|
+
if (value instanceof FootprintTags) {
|
|
483
|
+
this._sxTags = value
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
const tagString = Array.isArray(value) ? value.join(" ") : value
|
|
487
|
+
this._sxTags = new FootprintTags(tagString)
|
|
380
488
|
}
|
|
381
489
|
|
|
382
490
|
get path(): FootprintPath | undefined {
|
|
@@ -388,7 +496,8 @@ export class Footprint extends SxClass {
|
|
|
388
496
|
this._sxPath = undefined
|
|
389
497
|
return
|
|
390
498
|
}
|
|
391
|
-
this._sxPath =
|
|
499
|
+
this._sxPath =
|
|
500
|
+
value instanceof FootprintPath ? value : new FootprintPath(value)
|
|
392
501
|
}
|
|
393
502
|
|
|
394
503
|
get autoplaceCost90(): FootprintAutoplaceCost90 | undefined {
|
|
@@ -440,7 +549,10 @@ export class Footprint extends SxClass {
|
|
|
440
549
|
return this._sxSolderPasteMargin
|
|
441
550
|
}
|
|
442
551
|
|
|
443
|
-
set solderPasteMargin(value:
|
|
552
|
+
set solderPasteMargin(value:
|
|
553
|
+
| FootprintSolderPasteMargin
|
|
554
|
+
| number
|
|
555
|
+
| undefined) {
|
|
444
556
|
if (value === undefined) {
|
|
445
557
|
this._sxSolderPasteMargin = undefined
|
|
446
558
|
return
|
|
@@ -476,7 +588,9 @@ export class Footprint extends SxClass {
|
|
|
476
588
|
return
|
|
477
589
|
}
|
|
478
590
|
this._sxClearance =
|
|
479
|
-
value instanceof FootprintClearance
|
|
591
|
+
value instanceof FootprintClearance
|
|
592
|
+
? value
|
|
593
|
+
: new FootprintClearance(value)
|
|
480
594
|
}
|
|
481
595
|
|
|
482
596
|
get zoneConnect(): FootprintZoneConnect | undefined {
|
|
@@ -489,7 +603,9 @@ export class Footprint extends SxClass {
|
|
|
489
603
|
return
|
|
490
604
|
}
|
|
491
605
|
this._sxZoneConnect =
|
|
492
|
-
value instanceof FootprintZoneConnect
|
|
606
|
+
value instanceof FootprintZoneConnect
|
|
607
|
+
? value
|
|
608
|
+
: new FootprintZoneConnect(value)
|
|
493
609
|
}
|
|
494
610
|
|
|
495
611
|
get thermalWidth(): FootprintThermalWidth | undefined {
|
|
@@ -517,7 +633,9 @@ export class Footprint extends SxClass {
|
|
|
517
633
|
return
|
|
518
634
|
}
|
|
519
635
|
this._sxThermalGap =
|
|
520
|
-
value instanceof FootprintThermalGap
|
|
636
|
+
value instanceof FootprintThermalGap
|
|
637
|
+
? value
|
|
638
|
+
: new FootprintThermalGap(value)
|
|
521
639
|
}
|
|
522
640
|
|
|
523
641
|
get attr(): FootprintAttr | undefined {
|
|
@@ -562,18 +680,30 @@ export class Footprint extends SxClass {
|
|
|
562
680
|
return this._sxSheetname?.value
|
|
563
681
|
}
|
|
564
682
|
|
|
565
|
-
set sheetname(value: string | undefined) {
|
|
683
|
+
set sheetname(value: string | FootprintSheetname | undefined) {
|
|
684
|
+
if (value === undefined) {
|
|
685
|
+
this._sxSheetname = undefined
|
|
686
|
+
return
|
|
687
|
+
}
|
|
566
688
|
this._sxSheetname =
|
|
567
|
-
value
|
|
689
|
+
value instanceof FootprintSheetname
|
|
690
|
+
? value
|
|
691
|
+
: new FootprintSheetname(value)
|
|
568
692
|
}
|
|
569
693
|
|
|
570
694
|
get sheetfile(): string | undefined {
|
|
571
695
|
return this._sxSheetfile?.value
|
|
572
696
|
}
|
|
573
697
|
|
|
574
|
-
set sheetfile(value: string | undefined) {
|
|
698
|
+
set sheetfile(value: string | FootprintSheetfile | undefined) {
|
|
699
|
+
if (value === undefined) {
|
|
700
|
+
this._sxSheetfile = undefined
|
|
701
|
+
return
|
|
702
|
+
}
|
|
575
703
|
this._sxSheetfile =
|
|
576
|
-
value
|
|
704
|
+
value instanceof FootprintSheetfile
|
|
705
|
+
? value
|
|
706
|
+
: new FootprintSheetfile(value)
|
|
577
707
|
}
|
|
578
708
|
|
|
579
709
|
get embeddedFonts(): EmbeddedFonts | undefined {
|
|
@@ -35,7 +35,9 @@ export class FootprintAttr extends SxClass {
|
|
|
35
35
|
attr._type = primitive
|
|
36
36
|
continue
|
|
37
37
|
}
|
|
38
|
-
throw new Error(
|
|
38
|
+
throw new Error(
|
|
39
|
+
`attr encountered duplicate or unknown token "${primitive}"`,
|
|
40
|
+
)
|
|
39
41
|
}
|
|
40
42
|
return attr
|
|
41
43
|
}
|
|
@@ -120,10 +120,7 @@ export class FootprintModel extends SxClass {
|
|
|
120
120
|
}
|
|
121
121
|
SxClass.register(FootprintModel)
|
|
122
122
|
|
|
123
|
-
function parseVectorArgs(
|
|
124
|
-
args: PrimitiveSExpr[],
|
|
125
|
-
token: string,
|
|
126
|
-
): ModelVector {
|
|
123
|
+
function parseVectorArgs(args: PrimitiveSExpr[], token: string): ModelVector {
|
|
127
124
|
if (args.length !== 1) {
|
|
128
125
|
throw new Error(`model ${token} expects a single xyz child`)
|
|
129
126
|
}
|
|
@@ -43,7 +43,9 @@ export class FootprintNetTiePadGroups extends SxClass {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
override getString(): string {
|
|
46
|
-
const rendered = this._groups
|
|
46
|
+
const rendered = this._groups
|
|
47
|
+
.map((group) => quoteSExprString(group))
|
|
48
|
+
.join(" ")
|
|
47
49
|
return `(net_tie_pad_groups ${rendered})`
|
|
48
50
|
}
|
|
49
51
|
}
|