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.
- package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
- package/.vscode/settings.json +16 -0
- package/AGENTS.md +30 -0
- package/README.md +206 -0
- package/biome.json +93 -0
- package/bun.lock +48 -0
- package/bunfig.toml +5 -0
- package/lib/index.ts +1 -0
- package/lib/sexpr/base-classes/SxClass.ts +164 -0
- package/lib/sexpr/base-classes/SxPrimitiveBoolean.ts +35 -0
- package/lib/sexpr/base-classes/SxPrimitiveNumber.ts +26 -0
- package/lib/sexpr/base-classes/SxPrimitiveString.ts +26 -0
- package/lib/sexpr/classes/At.ts +38 -0
- package/lib/sexpr/classes/Bus.ts +83 -0
- package/lib/sexpr/classes/BusEntry.ts +142 -0
- package/lib/sexpr/classes/Color.ts +29 -0
- package/lib/sexpr/classes/Dnp.ts +8 -0
- package/lib/sexpr/classes/EmbeddedFonts.ts +70 -0
- package/lib/sexpr/classes/ExcludeFromSim.ts +8 -0
- package/lib/sexpr/classes/FieldsAutoplaced.ts +8 -0
- package/lib/sexpr/classes/Footprint.ts +719 -0
- package/lib/sexpr/classes/FootprintAttr.ts +102 -0
- package/lib/sexpr/classes/FootprintAutoplaceCost180.ts +9 -0
- package/lib/sexpr/classes/FootprintAutoplaceCost90.ts +9 -0
- package/lib/sexpr/classes/FootprintClearance.ts +9 -0
- package/lib/sexpr/classes/FootprintDescr.ts +44 -0
- package/lib/sexpr/classes/FootprintLocked.ts +32 -0
- package/lib/sexpr/classes/FootprintModel.ts +145 -0
- package/lib/sexpr/classes/FootprintNetTiePadGroups.ts +50 -0
- package/lib/sexpr/classes/FootprintPad.ts +705 -0
- package/lib/sexpr/classes/FootprintPath.ts +44 -0
- package/lib/sexpr/classes/FootprintPlaced.ts +32 -0
- package/lib/sexpr/classes/FootprintPrivateLayers.ts +56 -0
- package/lib/sexpr/classes/FootprintSheetfile.ts +44 -0
- package/lib/sexpr/classes/FootprintSheetname.ts +44 -0
- package/lib/sexpr/classes/FootprintSolderMaskMargin.ts +9 -0
- package/lib/sexpr/classes/FootprintSolderPasteMargin.ts +9 -0
- package/lib/sexpr/classes/FootprintSolderPasteRatio.ts +9 -0
- package/lib/sexpr/classes/FootprintTags.ts +44 -0
- package/lib/sexpr/classes/FootprintTedit.ts +21 -0
- package/lib/sexpr/classes/FootprintThermalGap.ts +9 -0
- package/lib/sexpr/classes/FootprintThermalWidth.ts +9 -0
- package/lib/sexpr/classes/FootprintZoneConnect.ts +9 -0
- package/lib/sexpr/classes/FpArc.ts +289 -0
- package/lib/sexpr/classes/FpCircle.ts +293 -0
- package/lib/sexpr/classes/FpLine.ts +288 -0
- package/lib/sexpr/classes/FpPoly.ts +266 -0
- package/lib/sexpr/classes/FpPolyFill.ts +48 -0
- package/lib/sexpr/classes/FpPolyLocked.ts +40 -0
- package/lib/sexpr/classes/FpRect.ts +293 -0
- package/lib/sexpr/classes/FpText.ts +341 -0
- package/lib/sexpr/classes/FpTextBox.ts +412 -0
- package/lib/sexpr/classes/GrLine.ts +245 -0
- package/lib/sexpr/classes/GrLineAngle.ts +32 -0
- package/lib/sexpr/classes/GrLineEnd.ts +61 -0
- package/lib/sexpr/classes/GrLineLocked.ts +40 -0
- package/lib/sexpr/classes/GrLineStart.ts +61 -0
- package/lib/sexpr/classes/GrText.ts +202 -0
- package/lib/sexpr/classes/Image.ts +256 -0
- package/lib/sexpr/classes/InBom.ts +8 -0
- package/lib/sexpr/classes/Junction.ts +134 -0
- package/lib/sexpr/classes/KicadPcb.ts +313 -0
- package/lib/sexpr/classes/KicadSch.ts +303 -0
- package/lib/sexpr/classes/KicadSchGenerator.ts +32 -0
- package/lib/sexpr/classes/KicadSchGeneratorVersion.ts +30 -0
- package/lib/sexpr/classes/KicadSchVersion.ts +22 -0
- package/lib/sexpr/classes/Label.ts +136 -0
- package/lib/sexpr/classes/Layer.ts +51 -0
- package/lib/sexpr/classes/Layers.ts +47 -0
- package/lib/sexpr/classes/LibSymbols.ts +61 -0
- package/lib/sexpr/classes/NoConnect.ts +73 -0
- package/lib/sexpr/classes/OnBoard.ts +8 -0
- package/lib/sexpr/classes/PadChamfer.ts +50 -0
- package/lib/sexpr/classes/PadChamferRatio.ts +9 -0
- package/lib/sexpr/classes/PadClearance.ts +9 -0
- package/lib/sexpr/classes/PadDieLength.ts +9 -0
- package/lib/sexpr/classes/PadDrill.ts +145 -0
- package/lib/sexpr/classes/PadDrillOffset.ts +54 -0
- package/lib/sexpr/classes/PadLayers.ts +59 -0
- package/lib/sexpr/classes/PadNet.ts +56 -0
- package/lib/sexpr/classes/PadOptions.ts +182 -0
- package/lib/sexpr/classes/PadPinFunction.ts +9 -0
- package/lib/sexpr/classes/PadPinType.ts +9 -0
- package/lib/sexpr/classes/PadPrimitiveGrArc.ts +254 -0
- package/lib/sexpr/classes/PadPrimitiveGrCircle.ts +279 -0
- package/lib/sexpr/classes/PadPrimitiveGrLine.ts +126 -0
- package/lib/sexpr/classes/PadPrimitives.ts +289 -0
- package/lib/sexpr/classes/PadRectDelta.ts +57 -0
- package/lib/sexpr/classes/PadRoundrectRratio.ts +9 -0
- package/lib/sexpr/classes/PadSize.ts +54 -0
- package/lib/sexpr/classes/PadSolderMaskMargin.ts +9 -0
- package/lib/sexpr/classes/PadSolderPasteMargin.ts +9 -0
- package/lib/sexpr/classes/PadSolderPasteMarginRatio.ts +9 -0
- package/lib/sexpr/classes/PadTeardrops.ts +208 -0
- package/lib/sexpr/classes/PadThermalBridgeAngle.ts +9 -0
- package/lib/sexpr/classes/PadThermalGap.ts +9 -0
- package/lib/sexpr/classes/PadThermalWidth.ts +9 -0
- package/lib/sexpr/classes/PadZoneConnect.ts +9 -0
- package/lib/sexpr/classes/Paper.ts +119 -0
- package/lib/sexpr/classes/PcbGeneral.ts +75 -0
- package/lib/sexpr/classes/PcbGeneralLegacyTeardrops.ts +44 -0
- package/lib/sexpr/classes/PcbGeneralThickness.ts +9 -0
- package/lib/sexpr/classes/PcbGenerator.ts +16 -0
- package/lib/sexpr/classes/PcbGeneratorVersion.ts +16 -0
- package/lib/sexpr/classes/PcbLayerDefinition.ts +102 -0
- package/lib/sexpr/classes/PcbLayers.ts +34 -0
- package/lib/sexpr/classes/PcbNet.ts +56 -0
- package/lib/sexpr/classes/PcbVersion.ts +9 -0
- package/lib/sexpr/classes/Property.ts +246 -0
- package/lib/sexpr/classes/PropertyHide.ts +9 -0
- package/lib/sexpr/classes/PropertyUnlocked.ts +9 -0
- package/lib/sexpr/classes/Pts.ts +65 -0
- package/lib/sexpr/classes/RenderCache.ts +221 -0
- package/lib/sexpr/classes/SchematicText.ts +141 -0
- package/lib/sexpr/classes/Segment.ts +222 -0
- package/lib/sexpr/classes/SegmentEnd.ts +59 -0
- package/lib/sexpr/classes/SegmentLocked.ts +33 -0
- package/lib/sexpr/classes/SegmentNet.ts +62 -0
- package/lib/sexpr/classes/SegmentStart.ts +59 -0
- package/lib/sexpr/classes/Setup/PcbPlotParams.ts +729 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsBase.ts +9 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsNumericProperties.ts +105 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesA.ts +104 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesB.ts +105 -0
- package/lib/sexpr/classes/Setup/Setup.ts +573 -0
- package/lib/sexpr/classes/Setup/SetupPropertyTypes.ts +119 -0
- package/lib/sexpr/classes/Setup/Stackup.ts +140 -0
- package/lib/sexpr/classes/Setup/StackupLayer.ts +233 -0
- package/lib/sexpr/classes/Setup/StackupLayerProperties.ts +78 -0
- package/lib/sexpr/classes/Setup/StackupProperties.ts +41 -0
- package/lib/sexpr/classes/Setup/base.ts +167 -0
- package/lib/sexpr/classes/Setup/index.ts +14 -0
- package/lib/sexpr/classes/Setup/setupMultiValueProperties.ts +54 -0
- package/lib/sexpr/classes/Setup/setupNumericProperties.ts +151 -0
- package/lib/sexpr/classes/Setup/setupPropertyHandlers.ts +90 -0
- package/lib/sexpr/classes/Setup/setupStringProperties.ts +75 -0
- package/lib/sexpr/classes/Sheet.ts +205 -0
- package/lib/sexpr/classes/SheetFill.ts +44 -0
- package/lib/sexpr/classes/SheetInstances.ts +168 -0
- package/lib/sexpr/classes/SheetInstancesRoot.ts +165 -0
- package/lib/sexpr/classes/SheetPin.ts +122 -0
- package/lib/sexpr/classes/SheetProperty.ts +115 -0
- package/lib/sexpr/classes/SheetSize.ts +44 -0
- package/lib/sexpr/classes/Stroke.ts +58 -0
- package/lib/sexpr/classes/StrokeType.ts +34 -0
- package/lib/sexpr/classes/Symbol.ts +1541 -0
- package/lib/sexpr/classes/TextEffects.ts +444 -0
- package/lib/sexpr/classes/TitleBlock.ts +352 -0
- package/lib/sexpr/classes/Unit.ts +28 -0
- package/lib/sexpr/classes/Uuid.ts +8 -0
- package/lib/sexpr/classes/Via.ts +328 -0
- package/lib/sexpr/classes/ViaNet.ts +59 -0
- package/lib/sexpr/classes/Width.ts +8 -0
- package/lib/sexpr/classes/Wire.ts +91 -0
- package/lib/sexpr/classes/Xy.ts +35 -0
- package/lib/sexpr/classes/Zone.ts +41 -0
- package/lib/sexpr/index.ts +130 -0
- package/lib/sexpr/parseKicadSexpr.ts +5 -0
- package/lib/sexpr/parseToPrimitiveSExpr.ts +240 -0
- package/lib/sexpr/utils/indentLines.ts +3 -0
- package/lib/sexpr/utils/parseYesNo.ts +12 -0
- package/lib/sexpr/utils/quoteSExprString.ts +8 -0
- package/lib/sexpr/utils/strokeFromArgs.ts +19 -0
- package/lib/sexpr/utils/toNumberValue.ts +13 -0
- package/lib/sexpr/utils/toStringValue.ts +10 -0
- package/package.json +26 -0
- package/scripts/download-references.ts +66 -0
- package/tests/fixtures/expectEqualPrimitiveSExpr.ts +200 -0
- package/tests/sexpr/KicadPcbDemos.test.ts +48 -0
- package/tests/sexpr/KicadSchDemos.test.ts +49 -0
- package/tests/sexpr/classes/Footprint.test.ts +277 -0
- package/tests/sexpr/classes/FootprintPad.test.ts +71 -0
- package/tests/sexpr/classes/FpArc.test.ts +45 -0
- package/tests/sexpr/classes/FpCircle.test.ts +39 -0
- package/tests/sexpr/classes/FpPoly.test.ts +43 -0
- package/tests/sexpr/classes/FpRect.test.ts +40 -0
- package/tests/sexpr/classes/FpTextBox.test.ts +84 -0
- package/tests/sexpr/classes/Image.test.ts +50 -0
- package/tests/sexpr/classes/KicadSch.test.ts +97 -0
- package/tests/sexpr/classes/Paper.test.ts +30 -0
- package/tests/sexpr/classes/Property.test.ts +48 -0
- package/tests/sexpr/classes/Setup.test.ts +189 -0
- package/tests/sexpr/classes/Sheet.test.ts +107 -0
- package/tests/sexpr/classes/Stroke.test.ts +15 -0
- package/tests/sexpr/classes/Symbol.test.ts +96 -0
- package/tests/sexpr/classes/TextEffects.test.ts +56 -0
- package/tests/sexpr/classes/TitleBlock.test.ts +40 -0
- package/tsconfig.json +35 -0
|
@@ -0,0 +1,246 @@
|
|
|
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
|
+
import { At } from "./At"
|
|
7
|
+
import { Layer } from "./Layer"
|
|
8
|
+
import { PropertyHide } from "./PropertyHide"
|
|
9
|
+
import { PropertyUnlocked } from "./PropertyUnlocked"
|
|
10
|
+
import { TextEffects } from "./TextEffects"
|
|
11
|
+
import { Uuid } from "./Uuid"
|
|
12
|
+
import { Xy } from "./Xy"
|
|
13
|
+
|
|
14
|
+
const SUPPORTED_SINGLE_CHILDREN = new Set([
|
|
15
|
+
"at",
|
|
16
|
+
"xy",
|
|
17
|
+
"layer",
|
|
18
|
+
"uuid",
|
|
19
|
+
"effects",
|
|
20
|
+
"unlocked",
|
|
21
|
+
"hide",
|
|
22
|
+
])
|
|
23
|
+
|
|
24
|
+
const ensureSingleChild = (
|
|
25
|
+
arrayPropertyMap: Record<string, SxClass[]>,
|
|
26
|
+
token: string,
|
|
27
|
+
) => {
|
|
28
|
+
const entries = arrayPropertyMap[token]
|
|
29
|
+
if (entries && entries.length > 1) {
|
|
30
|
+
throw new Error(`property does not support repeated "${token}" children`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const primitiveToString = (value: PrimitiveSExpr | undefined): string | undefined => {
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
return undefined
|
|
37
|
+
}
|
|
38
|
+
const asString = toStringValue(value)
|
|
39
|
+
if (asString !== undefined) {
|
|
40
|
+
return asString
|
|
41
|
+
}
|
|
42
|
+
return printSExpr(value)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class Property extends SxClass {
|
|
46
|
+
static override token = "property"
|
|
47
|
+
token = "property"
|
|
48
|
+
|
|
49
|
+
private _key = ""
|
|
50
|
+
private _value = ""
|
|
51
|
+
private _sxAt?: At
|
|
52
|
+
private _sxXy?: Xy
|
|
53
|
+
private _sxLayer?: Layer
|
|
54
|
+
private _sxUuid?: Uuid
|
|
55
|
+
private _sxEffects?: TextEffects
|
|
56
|
+
private _sxUnlocked?: PropertyUnlocked
|
|
57
|
+
private _sxHide?: PropertyHide
|
|
58
|
+
|
|
59
|
+
constructor(key = "", value = "") {
|
|
60
|
+
super()
|
|
61
|
+
this._key = key
|
|
62
|
+
this._value = value
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static override fromSexprPrimitives(
|
|
66
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
67
|
+
): Property {
|
|
68
|
+
if (primitiveSexprs.length < 2) {
|
|
69
|
+
throw new Error("property requires key and value arguments")
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const [rawKey, rawValue, ...rest] = primitiveSexprs
|
|
73
|
+
|
|
74
|
+
const key = primitiveToString(rawKey)
|
|
75
|
+
const value = primitiveToString(rawValue)
|
|
76
|
+
if (key === undefined) {
|
|
77
|
+
throw new Error("property key must be a printable value")
|
|
78
|
+
}
|
|
79
|
+
if (value === undefined) {
|
|
80
|
+
throw new Error("property value must be a printable value")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const primitive of rest) {
|
|
84
|
+
if (!Array.isArray(primitive)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`property encountered unexpected primitive child: ${JSON.stringify(primitive)}`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
if (primitive.length === 0 || typeof primitive[0] !== "string") {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`property encountered invalid child expression: ${JSON.stringify(primitive)}`,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const property = new Property(key, value)
|
|
97
|
+
|
|
98
|
+
const { propertyMap, arrayPropertyMap } =
|
|
99
|
+
SxClass.parsePrimitivesToClassProperties(rest, this.token)
|
|
100
|
+
|
|
101
|
+
for (const token of Object.keys(propertyMap)) {
|
|
102
|
+
if (!SUPPORTED_SINGLE_CHILDREN.has(token)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`property encountered unsupported child token "${token}"`,
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const token of Object.keys(arrayPropertyMap)) {
|
|
110
|
+
if (!SUPPORTED_SINGLE_CHILDREN.has(token)) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`property encountered unsupported child token "${token}"`,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
ensureSingleChild(arrayPropertyMap, token)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const at = propertyMap.at as At | undefined
|
|
119
|
+
const xy = propertyMap.xy as Xy | undefined
|
|
120
|
+
if (at && xy) {
|
|
121
|
+
throw new Error("property can't include both at and xy children")
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
property._sxAt = at
|
|
125
|
+
property._sxXy = xy
|
|
126
|
+
property._sxLayer = propertyMap.layer as Layer | undefined
|
|
127
|
+
property._sxUuid = propertyMap.uuid as Uuid | undefined
|
|
128
|
+
property._sxEffects = propertyMap.effects as TextEffects | undefined
|
|
129
|
+
property._sxUnlocked = propertyMap.unlocked as PropertyUnlocked | undefined
|
|
130
|
+
property._sxHide = propertyMap.hide as PropertyHide | undefined
|
|
131
|
+
|
|
132
|
+
return property
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
get key(): string {
|
|
136
|
+
return this._key
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
set key(value: string) {
|
|
140
|
+
this._key = value
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get value(): string {
|
|
144
|
+
return this._value
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
set value(value: string) {
|
|
148
|
+
this._value = value
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get position(): At | Xy | undefined {
|
|
152
|
+
return this._sxAt ?? this._sxXy
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
set position(value: At | Xy | undefined) {
|
|
156
|
+
if (value instanceof At) {
|
|
157
|
+
this._sxAt = value
|
|
158
|
+
this._sxXy = undefined
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
if (value instanceof Xy) {
|
|
162
|
+
this._sxXy = value
|
|
163
|
+
this._sxAt = undefined
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
this._sxAt = undefined
|
|
167
|
+
this._sxXy = undefined
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get layer(): Layer | undefined {
|
|
171
|
+
return this._sxLayer
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
set layer(value: Layer | Array<string | number> | string | undefined) {
|
|
175
|
+
if (value === undefined) {
|
|
176
|
+
this._sxLayer = undefined
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
if (value instanceof Layer) {
|
|
180
|
+
this._sxLayer = value
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
const names = Array.isArray(value) ? value : [value]
|
|
184
|
+
this._sxLayer = new Layer(names)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get uuid(): Uuid | undefined {
|
|
188
|
+
return this._sxUuid
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
set uuid(value: Uuid | string | undefined) {
|
|
192
|
+
if (value === undefined) {
|
|
193
|
+
this._sxUuid = undefined
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
get effects(): TextEffects | undefined {
|
|
200
|
+
return this._sxEffects
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
set effects(value: TextEffects | undefined) {
|
|
204
|
+
this._sxEffects = value
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
get unlocked(): boolean {
|
|
208
|
+
return this._sxUnlocked?.value ?? false
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
set unlocked(value: boolean) {
|
|
212
|
+
this._sxUnlocked = new PropertyUnlocked(value)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
get hidden(): boolean {
|
|
216
|
+
return this._sxHide?.value ?? false
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
set hidden(value: boolean) {
|
|
220
|
+
this._sxHide = new PropertyHide(value)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
override getChildren(): SxClass[] {
|
|
224
|
+
const children: SxClass[] = []
|
|
225
|
+
if (this._sxAt) children.push(this._sxAt)
|
|
226
|
+
if (this._sxXy) children.push(this._sxXy)
|
|
227
|
+
if (this._sxUnlocked) children.push(this._sxUnlocked)
|
|
228
|
+
if (this._sxLayer) children.push(this._sxLayer)
|
|
229
|
+
if (this._sxHide) children.push(this._sxHide)
|
|
230
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
231
|
+
if (this._sxEffects) children.push(this._sxEffects)
|
|
232
|
+
return children
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
override getString(): string {
|
|
236
|
+
const lines = [
|
|
237
|
+
`(property ${quoteSExprString(this._key)} ${quoteSExprString(this._value)}`,
|
|
238
|
+
]
|
|
239
|
+
for (const child of this.getChildren()) {
|
|
240
|
+
lines.push(child.getStringIndented())
|
|
241
|
+
}
|
|
242
|
+
lines.push(")")
|
|
243
|
+
return lines.join("\n")
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
SxClass.register(Property)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PropertyHide extends SxPrimitiveBoolean {
|
|
5
|
+
static override token = "hide"
|
|
6
|
+
static override parentToken = "property"
|
|
7
|
+
token = "hide"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PropertyHide)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PropertyUnlocked extends SxPrimitiveBoolean {
|
|
5
|
+
static override token = "unlocked"
|
|
6
|
+
static override parentToken = "property"
|
|
7
|
+
token = "unlocked"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PropertyUnlocked)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { printSExpr } from "../parseToPrimitiveSExpr"
|
|
4
|
+
import { Xy } from "./Xy"
|
|
5
|
+
|
|
6
|
+
export class Pts extends SxClass {
|
|
7
|
+
static override token = "pts"
|
|
8
|
+
token = "pts"
|
|
9
|
+
|
|
10
|
+
points: Array<Xy>
|
|
11
|
+
|
|
12
|
+
constructor(points: Array<Xy> = []) {
|
|
13
|
+
super()
|
|
14
|
+
this.points = points
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static override fromSexprPrimitives(
|
|
18
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
19
|
+
): Pts {
|
|
20
|
+
const points: Xy[] = []
|
|
21
|
+
|
|
22
|
+
for (const primitive of primitiveSexprs) {
|
|
23
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
24
|
+
throw new Error(`Unexpected primitive inside pts: ${printSExpr(primitive)}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const parsed = SxClass.parsePrimitiveSexpr(primitive, {
|
|
28
|
+
parentToken: this.token,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
if (parsed instanceof Xy) {
|
|
32
|
+
points.push(parsed)
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (parsed instanceof SxClass) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Unsupported child "${parsed.token}" inside pts expression`,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
throw new Error(`Unable to parse child inside pts: ${printSExpr(primitive)}`)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return new Pts(points)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override getChildren(): SxClass[] {
|
|
49
|
+
return [...this.points]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override getString(): string {
|
|
53
|
+
const lines = ["(pts"]
|
|
54
|
+
for (const point of this.points) {
|
|
55
|
+
const pointString = point.getString()
|
|
56
|
+
const segments = pointString.split("\n")
|
|
57
|
+
for (const segment of segments) {
|
|
58
|
+
lines.push(` ${segment}`)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
lines.push(")")
|
|
62
|
+
return lines.join("\n")
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
SxClass.register(Pts)
|
|
@@ -0,0 +1,221 @@
|
|
|
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
|
+
import { Pts } from "./Pts"
|
|
7
|
+
|
|
8
|
+
type RenderCacheElement = RenderCachePolygon
|
|
9
|
+
|
|
10
|
+
export class RenderCache extends SxClass {
|
|
11
|
+
static override token = "render_cache"
|
|
12
|
+
override token = "render_cache"
|
|
13
|
+
|
|
14
|
+
private _text: string
|
|
15
|
+
private _angle?: number
|
|
16
|
+
private _offsetX?: number
|
|
17
|
+
private _offsetY?: number
|
|
18
|
+
private _elements: RenderCacheElement[] = []
|
|
19
|
+
|
|
20
|
+
constructor(text = "") {
|
|
21
|
+
super()
|
|
22
|
+
this._text = text
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static override fromSexprPrimitives(
|
|
26
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
27
|
+
): RenderCache {
|
|
28
|
+
if (primitiveSexprs.length === 0) {
|
|
29
|
+
throw new Error("render_cache requires a text argument")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const [rawText, ...rest] = primitiveSexprs
|
|
33
|
+
const text = toStringValue(rawText)
|
|
34
|
+
if (text === undefined) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`render_cache text must be a string value, received ${JSON.stringify(rawText)}`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const renderCache = new RenderCache(text)
|
|
41
|
+
|
|
42
|
+
const numericParams: number[] = []
|
|
43
|
+
|
|
44
|
+
for (const primitive of rest) {
|
|
45
|
+
if (Array.isArray(primitive)) {
|
|
46
|
+
const parsed = SxClass.parsePrimitiveSexpr(primitive, {
|
|
47
|
+
parentToken: this.token,
|
|
48
|
+
})
|
|
49
|
+
if (!(parsed instanceof SxClass)) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`render_cache child did not resolve to an SxClass: ${JSON.stringify(primitive)}`,
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!(parsed instanceof RenderCachePolygon)) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`render_cache encountered unsupported child token "${parsed.token}"`,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
renderCache._elements.push(parsed)
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const numeric = toNumberValue(primitive)
|
|
66
|
+
if (numeric === undefined) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`render_cache encountered non-numeric parameter ${JSON.stringify(primitive)}`,
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
numericParams.push(numeric)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (numericParams.length > 0) {
|
|
75
|
+
renderCache._angle = numericParams[0]
|
|
76
|
+
}
|
|
77
|
+
if (numericParams.length > 1) {
|
|
78
|
+
renderCache._offsetX = numericParams[1]
|
|
79
|
+
}
|
|
80
|
+
if (numericParams.length > 2) {
|
|
81
|
+
renderCache._offsetY = numericParams[2]
|
|
82
|
+
}
|
|
83
|
+
if (numericParams.length > 3) {
|
|
84
|
+
throw new Error("render_cache supports at most three numeric parameters")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return renderCache
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get text(): string {
|
|
91
|
+
return this._text
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
set text(value: string) {
|
|
95
|
+
this._text = value
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get angle(): number | undefined {
|
|
99
|
+
return this._angle
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
set angle(value: number | undefined) {
|
|
103
|
+
this._angle = value
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get offsetX(): number | undefined {
|
|
107
|
+
return this._offsetX
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
set offsetX(value: number | undefined) {
|
|
111
|
+
this._offsetX = value
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get offsetY(): number | undefined {
|
|
115
|
+
return this._offsetY
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
set offsetY(value: number | undefined) {
|
|
119
|
+
this._offsetY = value
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get elements(): RenderCacheElement[] {
|
|
123
|
+
return [...this._elements]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
set elements(elements: RenderCacheElement[]) {
|
|
127
|
+
this._elements = [...elements]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
addElement(element: RenderCacheElement) {
|
|
131
|
+
this._elements.push(element)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
override getChildren(): SxClass[] {
|
|
135
|
+
return [...this._elements]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override getString(): string {
|
|
139
|
+
const headerParts: string[] = [quoteSExprString(this._text)]
|
|
140
|
+
if (this._angle !== undefined) {
|
|
141
|
+
headerParts.push(String(this._angle))
|
|
142
|
+
}
|
|
143
|
+
if (this._offsetX !== undefined) {
|
|
144
|
+
headerParts.push(String(this._offsetX))
|
|
145
|
+
}
|
|
146
|
+
if (this._offsetY !== undefined) {
|
|
147
|
+
headerParts.push(String(this._offsetY))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (this._elements.length === 0) {
|
|
151
|
+
return `(render_cache ${headerParts.join(" ")})`
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const lines = [`(render_cache ${headerParts.join(" ")}`]
|
|
155
|
+
for (const element of this._elements) {
|
|
156
|
+
lines.push(element.getStringIndented())
|
|
157
|
+
}
|
|
158
|
+
lines.push(")")
|
|
159
|
+
return lines.join("\n")
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
SxClass.register(RenderCache)
|
|
163
|
+
|
|
164
|
+
class RenderCachePolygon extends SxClass {
|
|
165
|
+
static override token = "polygon"
|
|
166
|
+
static override parentToken = "render_cache"
|
|
167
|
+
override token = "polygon"
|
|
168
|
+
|
|
169
|
+
private _contours: Pts[] = []
|
|
170
|
+
|
|
171
|
+
static override fromSexprPrimitives(
|
|
172
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
173
|
+
): RenderCachePolygon {
|
|
174
|
+
const polygon = new RenderCachePolygon()
|
|
175
|
+
|
|
176
|
+
for (const primitive of primitiveSexprs) {
|
|
177
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`render_cache polygon encountered invalid child: ${JSON.stringify(primitive)}`,
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const parsed = SxClass.parsePrimitiveSexpr(primitive, {
|
|
184
|
+
parentToken: this.token,
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
if (!(parsed instanceof SxClass)) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`render_cache polygon child did not resolve to an SxClass: ${JSON.stringify(primitive)}`,
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!(parsed instanceof Pts)) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`render_cache polygon encountered unsupported token "${parsed.token}"`,
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
polygon._contours.push(parsed)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (polygon._contours.length === 0) {
|
|
203
|
+
throw new Error("render_cache polygon requires at least one pts child")
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return polygon
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
get contours(): Pts[] {
|
|
210
|
+
return [...this._contours]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
set contours(value: Pts[]) {
|
|
214
|
+
this._contours = [...value]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
override getChildren(): SxClass[] {
|
|
218
|
+
return [...this._contours]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
SxClass.register(RenderCachePolygon)
|
|
@@ -0,0 +1,141 @@
|
|
|
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
|
+
import { At } from "./At"
|
|
6
|
+
import { ExcludeFromSim } from "./ExcludeFromSim"
|
|
7
|
+
import { TextEffects } from "./TextEffects"
|
|
8
|
+
import { Uuid } from "./Uuid"
|
|
9
|
+
|
|
10
|
+
const SUPPORTED_TOKENS = new Set([
|
|
11
|
+
"exclude_from_sim",
|
|
12
|
+
"at",
|
|
13
|
+
"effects",
|
|
14
|
+
"uuid",
|
|
15
|
+
])
|
|
16
|
+
|
|
17
|
+
export class SchematicText extends SxClass {
|
|
18
|
+
static override token = "text"
|
|
19
|
+
static override parentToken = "kicad_sch"
|
|
20
|
+
override token = "text"
|
|
21
|
+
|
|
22
|
+
private _value = ""
|
|
23
|
+
private _sxExcludeFromSim?: ExcludeFromSim
|
|
24
|
+
private _sxAt?: At
|
|
25
|
+
private _sxEffects?: TextEffects
|
|
26
|
+
private _sxUuid?: Uuid
|
|
27
|
+
|
|
28
|
+
static override fromSexprPrimitives(
|
|
29
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
30
|
+
): SchematicText {
|
|
31
|
+
const [textPrimitive, ...rest] = primitiveSexprs
|
|
32
|
+
const value = toStringValue(textPrimitive)
|
|
33
|
+
if (value === undefined) {
|
|
34
|
+
throw new Error("text expects a string value")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const text = new SchematicText()
|
|
38
|
+
text._value = value
|
|
39
|
+
|
|
40
|
+
const { propertyMap, arrayPropertyMap } =
|
|
41
|
+
SxClass.parsePrimitivesToClassProperties(rest, this.token)
|
|
42
|
+
|
|
43
|
+
const unsupportedTokens = Object.keys(propertyMap).filter(
|
|
44
|
+
(token) => !SUPPORTED_TOKENS.has(token),
|
|
45
|
+
)
|
|
46
|
+
if (unsupportedTokens.length > 0) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Unsupported child tokens inside text expression: ${unsupportedTokens.join(", ")}`,
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const [token, entries] of Object.entries(arrayPropertyMap)) {
|
|
53
|
+
if (!SUPPORTED_TOKENS.has(token)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Unsupported child tokens inside text expression: ${token}`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
if (entries.length > 1) {
|
|
59
|
+
throw new Error(`text does not support repeated child tokens: ${token}`)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
text._sxExcludeFromSim =
|
|
64
|
+
(arrayPropertyMap.exclude_from_sim?.[0] as ExcludeFromSim | undefined) ??
|
|
65
|
+
(propertyMap.exclude_from_sim as ExcludeFromSim | undefined)
|
|
66
|
+
text._sxAt =
|
|
67
|
+
(arrayPropertyMap.at?.[0] as At | undefined) ??
|
|
68
|
+
(propertyMap.at as At | undefined)
|
|
69
|
+
text._sxEffects =
|
|
70
|
+
(arrayPropertyMap.effects?.[0] as TextEffects | undefined) ??
|
|
71
|
+
(propertyMap.effects as TextEffects | undefined)
|
|
72
|
+
text._sxUuid =
|
|
73
|
+
(arrayPropertyMap.uuid?.[0] as Uuid | undefined) ??
|
|
74
|
+
(propertyMap.uuid as Uuid | undefined)
|
|
75
|
+
|
|
76
|
+
return text
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get value(): string {
|
|
80
|
+
return this._value
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
set value(newValue: string) {
|
|
84
|
+
this._value = newValue
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get excludeFromSim(): boolean {
|
|
88
|
+
return this._sxExcludeFromSim?.value ?? false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
set excludeFromSim(value: boolean) {
|
|
92
|
+
this._sxExcludeFromSim = value ? new ExcludeFromSim(true) : undefined
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get at(): At | undefined {
|
|
96
|
+
return this._sxAt
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
set at(value: At | undefined) {
|
|
100
|
+
this._sxAt = value
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get effects(): TextEffects | undefined {
|
|
104
|
+
return this._sxEffects
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
set effects(value: TextEffects | undefined) {
|
|
108
|
+
this._sxEffects = value
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get uuid(): Uuid | undefined {
|
|
112
|
+
return this._sxUuid
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
set uuid(value: Uuid | string | undefined) {
|
|
116
|
+
if (value === undefined) {
|
|
117
|
+
this._sxUuid = undefined
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override getChildren(): SxClass[] {
|
|
124
|
+
const children: SxClass[] = []
|
|
125
|
+
if (this._sxExcludeFromSim) children.push(this._sxExcludeFromSim)
|
|
126
|
+
if (this._sxAt) children.push(this._sxAt)
|
|
127
|
+
if (this._sxEffects) children.push(this._sxEffects)
|
|
128
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
129
|
+
return children
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
override getString(): string {
|
|
133
|
+
const lines = [`(text ${quoteSExprString(this._value)}`]
|
|
134
|
+
for (const child of this.getChildren()) {
|
|
135
|
+
lines.push(child.getStringIndented())
|
|
136
|
+
}
|
|
137
|
+
lines.push(")")
|
|
138
|
+
return lines.join("\n")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
SxClass.register(SchematicText)
|