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,412 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import { printSExpr, type PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { quoteSExprString } from "../utils/quoteSExprString"
|
|
4
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
5
|
+
import { toStringValue } from "../utils/toStringValue"
|
|
6
|
+
import { Layer } from "./Layer"
|
|
7
|
+
import { TextEffects } from "./TextEffects"
|
|
8
|
+
import { Uuid } from "./Uuid"
|
|
9
|
+
import { Stroke } from "./Stroke"
|
|
10
|
+
import { Pts } from "./Pts"
|
|
11
|
+
import { RenderCache } from "./RenderCache"
|
|
12
|
+
|
|
13
|
+
function primitiveToString(value: PrimitiveSExpr | undefined): string {
|
|
14
|
+
if (value === undefined) return ""
|
|
15
|
+
const str = toStringValue(value)
|
|
16
|
+
if (str !== undefined) return str
|
|
17
|
+
return printSExpr(value)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const SUPPORTED_SINGLE_TOKENS = new Set([
|
|
21
|
+
"start",
|
|
22
|
+
"end",
|
|
23
|
+
"pts",
|
|
24
|
+
"angle",
|
|
25
|
+
"layer",
|
|
26
|
+
"uuid",
|
|
27
|
+
"effects",
|
|
28
|
+
"stroke",
|
|
29
|
+
"render_cache",
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
const SUPPORTED_MULTI_TOKENS = new Set<string>()
|
|
33
|
+
|
|
34
|
+
export class FpTextBox extends SxClass {
|
|
35
|
+
static override token = "fp_text_box"
|
|
36
|
+
token = "fp_text_box"
|
|
37
|
+
|
|
38
|
+
private _sxLocked?: FpTextBoxLocked
|
|
39
|
+
private _text = ""
|
|
40
|
+
private _sxStart?: FpTextBoxStart
|
|
41
|
+
private _sxEnd?: FpTextBoxEnd
|
|
42
|
+
private _sxPts?: Pts
|
|
43
|
+
private _sxAngle?: FpTextBoxAngle
|
|
44
|
+
private _sxLayer?: Layer
|
|
45
|
+
private _sxUuid?: Uuid
|
|
46
|
+
private _sxEffects?: TextEffects
|
|
47
|
+
private _sxStroke?: Stroke
|
|
48
|
+
private _sxRenderCache?: RenderCache
|
|
49
|
+
|
|
50
|
+
static override fromSexprPrimitives(
|
|
51
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
52
|
+
): FpTextBox {
|
|
53
|
+
const fpTextBox = new FpTextBox()
|
|
54
|
+
|
|
55
|
+
if (primitiveSexprs.length === 0) {
|
|
56
|
+
throw new Error("fp_text_box requires a text value")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let capturedText = false
|
|
60
|
+
let locked = false
|
|
61
|
+
const structuredPrimitives: PrimitiveSExpr[] = []
|
|
62
|
+
|
|
63
|
+
for (const primitive of primitiveSexprs) {
|
|
64
|
+
if (typeof primitive === "string") {
|
|
65
|
+
if (primitive === "locked") {
|
|
66
|
+
if (locked) {
|
|
67
|
+
throw new Error("fp_text_box encountered duplicate locked flags")
|
|
68
|
+
}
|
|
69
|
+
locked = true
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
if (!capturedText) {
|
|
73
|
+
fpTextBox._text = primitive
|
|
74
|
+
capturedText = true
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
throw new Error(
|
|
78
|
+
`fp_text_box encountered unsupported flag "${primitive}"`,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!capturedText) {
|
|
83
|
+
fpTextBox._text = primitiveToString(primitive)
|
|
84
|
+
capturedText = true
|
|
85
|
+
continue
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`fp_text_box encountered invalid child expression: ${JSON.stringify(primitive)}`,
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
structuredPrimitives.push(primitive)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!capturedText) {
|
|
98
|
+
throw new Error("fp_text_box did not include a text value")
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (locked) {
|
|
102
|
+
fpTextBox._sxLocked = new FpTextBoxLocked()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const { propertyMap, arrayPropertyMap } =
|
|
106
|
+
SxClass.parsePrimitivesToClassProperties(structuredPrimitives, this.token)
|
|
107
|
+
|
|
108
|
+
for (const token of Object.keys(propertyMap)) {
|
|
109
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`fp_text_box encountered unsupported child token "${token}"`,
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const [token, entries] of Object.entries(arrayPropertyMap)) {
|
|
117
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`fp_text_box encountered unsupported child token "${token}"`,
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
if (!SUPPORTED_MULTI_TOKENS.has(token) && entries.length > 1) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`fp_text_box does not support repeated child token "${token}"`,
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fpTextBox._sxStart = propertyMap.start as FpTextBoxStart | undefined
|
|
130
|
+
fpTextBox._sxEnd = propertyMap.end as FpTextBoxEnd | undefined
|
|
131
|
+
fpTextBox._sxPts = propertyMap.pts as Pts | undefined
|
|
132
|
+
fpTextBox._sxAngle = propertyMap.angle as FpTextBoxAngle | undefined
|
|
133
|
+
fpTextBox._sxLayer = propertyMap.layer as Layer | undefined
|
|
134
|
+
fpTextBox._sxUuid = propertyMap.uuid as Uuid | undefined
|
|
135
|
+
fpTextBox._sxEffects = propertyMap.effects as TextEffects | undefined
|
|
136
|
+
fpTextBox._sxStroke = propertyMap.stroke as Stroke | undefined
|
|
137
|
+
fpTextBox._sxRenderCache = propertyMap.render_cache as RenderCache | undefined
|
|
138
|
+
|
|
139
|
+
return fpTextBox
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get locked(): boolean {
|
|
143
|
+
return this._sxLocked !== undefined
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
set locked(value: boolean) {
|
|
147
|
+
this._sxLocked = value ? new FpTextBoxLocked() : undefined
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get text(): string {
|
|
151
|
+
return this._text
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
set text(value: string) {
|
|
155
|
+
this._text = value
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get start(): FpTextBoxStart | undefined {
|
|
159
|
+
return this._sxStart
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
set start(value: FpTextBoxStart | { x: number; y: number } | undefined) {
|
|
163
|
+
if (value === undefined) {
|
|
164
|
+
this._sxStart = undefined
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
this._sxStart = value instanceof FpTextBoxStart ? value : new FpTextBoxStart([value.x, value.y])
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get end(): FpTextBoxEnd | undefined {
|
|
171
|
+
return this._sxEnd
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
set end(value: FpTextBoxEnd | { x: number; y: number } | undefined) {
|
|
175
|
+
if (value === undefined) {
|
|
176
|
+
this._sxEnd = undefined
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
this._sxEnd = value instanceof FpTextBoxEnd ? value : new FpTextBoxEnd([value.x, value.y])
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
get pts(): Pts | undefined {
|
|
183
|
+
return this._sxPts
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
set pts(value: Pts | undefined) {
|
|
187
|
+
this._sxPts = value
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get angle(): FpTextBoxAngle | undefined {
|
|
191
|
+
return this._sxAngle
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
set angle(value: FpTextBoxAngle | number | undefined) {
|
|
195
|
+
if (value === undefined) {
|
|
196
|
+
this._sxAngle = undefined
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
this._sxAngle = value instanceof FpTextBoxAngle ? value : new FpTextBoxAngle([value])
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
get layer(): Layer | undefined {
|
|
203
|
+
return this._sxLayer
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
set layer(value: Layer | string | string[] | undefined) {
|
|
207
|
+
if (value === undefined) {
|
|
208
|
+
this._sxLayer = undefined
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
if (value instanceof Layer) {
|
|
212
|
+
this._sxLayer = value
|
|
213
|
+
} else {
|
|
214
|
+
const names = Array.isArray(value) ? value : [value]
|
|
215
|
+
this._sxLayer = new Layer(names)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
get effects(): TextEffects | undefined {
|
|
220
|
+
return this._sxEffects
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
set effects(value: TextEffects | undefined) {
|
|
224
|
+
this._sxEffects = value
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
get stroke(): Stroke | undefined {
|
|
228
|
+
return this._sxStroke
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
set stroke(value: Stroke | undefined) {
|
|
232
|
+
this._sxStroke = value
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
get uuid(): Uuid | undefined {
|
|
236
|
+
return this._sxUuid
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
set uuid(value: Uuid | string | undefined) {
|
|
240
|
+
if (value === undefined) {
|
|
241
|
+
this._sxUuid = undefined
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
get renderCache(): RenderCache | undefined {
|
|
248
|
+
return this._sxRenderCache
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
set renderCache(value: RenderCache | undefined) {
|
|
252
|
+
this._sxRenderCache = value
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
override getChildren(): SxClass[] {
|
|
256
|
+
const children: SxClass[] = []
|
|
257
|
+
if (this._sxLocked) children.push(this._sxLocked)
|
|
258
|
+
if (this._sxStart) children.push(this._sxStart)
|
|
259
|
+
if (this._sxEnd) children.push(this._sxEnd)
|
|
260
|
+
if (this._sxPts) children.push(this._sxPts)
|
|
261
|
+
if (this._sxAngle) children.push(this._sxAngle)
|
|
262
|
+
if (this._sxLayer) children.push(this._sxLayer)
|
|
263
|
+
if (this._sxEffects) children.push(this._sxEffects)
|
|
264
|
+
if (this._sxStroke) children.push(this._sxStroke)
|
|
265
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
266
|
+
if (this._sxRenderCache) children.push(this._sxRenderCache)
|
|
267
|
+
return children
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
override getString(): string {
|
|
271
|
+
const lines = ["(fp_text_box"]
|
|
272
|
+
|
|
273
|
+
if (this._sxLocked) {
|
|
274
|
+
lines.push(this._sxLocked.getStringIndented())
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
lines.push(` ${quoteSExprString(this._text)}`)
|
|
278
|
+
|
|
279
|
+
for (const child of this.getChildren()) {
|
|
280
|
+
if (child === this._sxLocked) continue
|
|
281
|
+
lines.push(child.getStringIndented())
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
lines.push(")")
|
|
285
|
+
return lines.join("\n")
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
SxClass.register(FpTextBox)
|
|
289
|
+
|
|
290
|
+
export class FpTextBoxStart extends SxClass {
|
|
291
|
+
static override token = "start"
|
|
292
|
+
static override parentToken = "fp_text_box"
|
|
293
|
+
token = "start"
|
|
294
|
+
|
|
295
|
+
x: number
|
|
296
|
+
y: number
|
|
297
|
+
|
|
298
|
+
constructor(args: [number, number]) {
|
|
299
|
+
super()
|
|
300
|
+
this.x = args[0]
|
|
301
|
+
this.y = args[1]
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static override fromSexprPrimitives(
|
|
305
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
306
|
+
): FpTextBoxStart {
|
|
307
|
+
const [rawX, rawY] = primitiveSexprs
|
|
308
|
+
const x = Number(rawX)
|
|
309
|
+
const y = Number(rawY)
|
|
310
|
+
return new FpTextBoxStart([
|
|
311
|
+
Number.isFinite(x) ? x : 0,
|
|
312
|
+
Number.isFinite(y) ? y : 0,
|
|
313
|
+
])
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
override getChildren(): SxClass[] {
|
|
317
|
+
return []
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
override getString(): string {
|
|
321
|
+
return `(start ${this.x} ${this.y})`
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
SxClass.register(FpTextBoxStart)
|
|
325
|
+
|
|
326
|
+
export class FpTextBoxEnd extends SxClass {
|
|
327
|
+
static override token = "end"
|
|
328
|
+
static override parentToken = "fp_text_box"
|
|
329
|
+
token = "end"
|
|
330
|
+
|
|
331
|
+
x: number
|
|
332
|
+
y: number
|
|
333
|
+
|
|
334
|
+
constructor(args: [number, number]) {
|
|
335
|
+
super()
|
|
336
|
+
this.x = args[0]
|
|
337
|
+
this.y = args[1]
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static override fromSexprPrimitives(
|
|
341
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
342
|
+
): FpTextBoxEnd {
|
|
343
|
+
const [rawX, rawY] = primitiveSexprs
|
|
344
|
+
const x = Number(rawX)
|
|
345
|
+
const y = Number(rawY)
|
|
346
|
+
return new FpTextBoxEnd([
|
|
347
|
+
Number.isFinite(x) ? x : 0,
|
|
348
|
+
Number.isFinite(y) ? y : 0,
|
|
349
|
+
])
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
override getChildren(): SxClass[] {
|
|
353
|
+
return []
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
override getString(): string {
|
|
357
|
+
return `(end ${this.x} ${this.y})`
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
SxClass.register(FpTextBoxEnd)
|
|
361
|
+
|
|
362
|
+
export class FpTextBoxAngle extends SxClass {
|
|
363
|
+
static override token = "angle"
|
|
364
|
+
static override parentToken = "fp_text_box"
|
|
365
|
+
token = "angle"
|
|
366
|
+
|
|
367
|
+
value: number
|
|
368
|
+
|
|
369
|
+
constructor(args: [number]) {
|
|
370
|
+
super()
|
|
371
|
+
this.value = args[0]
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static override fromSexprPrimitives(
|
|
375
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
376
|
+
): FpTextBoxAngle {
|
|
377
|
+
const [raw] = primitiveSexprs
|
|
378
|
+
const numeric =
|
|
379
|
+
typeof raw === "number"
|
|
380
|
+
? raw
|
|
381
|
+
: toNumberValue(raw as PrimitiveSExpr) ?? 0
|
|
382
|
+
return new FpTextBoxAngle([numeric])
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
override getChildren(): SxClass[] {
|
|
386
|
+
return []
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
override getString(): string {
|
|
390
|
+
return `(angle ${this.value})`
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
SxClass.register(FpTextBoxAngle)
|
|
394
|
+
|
|
395
|
+
class FpTextBoxLocked extends SxClass {
|
|
396
|
+
static override token = "locked"
|
|
397
|
+
static override parentToken = "fp_text_box"
|
|
398
|
+
token = "locked"
|
|
399
|
+
|
|
400
|
+
static override fromSexprPrimitives(): FpTextBoxLocked {
|
|
401
|
+
return new FpTextBoxLocked()
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
override getChildren(): SxClass[] {
|
|
405
|
+
return []
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
override getString(): string {
|
|
409
|
+
return "locked"
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
SxClass.register(FpTextBoxLocked)
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { Layer } from "./Layer"
|
|
4
|
+
import { Stroke } from "./Stroke"
|
|
5
|
+
import { Uuid } from "./Uuid"
|
|
6
|
+
import { Width } from "./Width"
|
|
7
|
+
import { GrLineStart } from "./GrLineStart"
|
|
8
|
+
import { GrLineEnd } from "./GrLineEnd"
|
|
9
|
+
import { GrLineAngle } from "./GrLineAngle"
|
|
10
|
+
import { GrLineLocked } from "./GrLineLocked"
|
|
11
|
+
|
|
12
|
+
export interface GrLinePoint {
|
|
13
|
+
x: number
|
|
14
|
+
y: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SUPPORTED_SINGLE_TOKENS = new Set([
|
|
18
|
+
"start",
|
|
19
|
+
"end",
|
|
20
|
+
"angle",
|
|
21
|
+
"layer",
|
|
22
|
+
"width",
|
|
23
|
+
"stroke",
|
|
24
|
+
"uuid",
|
|
25
|
+
"locked",
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
export class GrLine extends SxClass {
|
|
29
|
+
static override token = "gr_line"
|
|
30
|
+
override token = "gr_line"
|
|
31
|
+
|
|
32
|
+
private _sxStart?: GrLineStart
|
|
33
|
+
private _sxEnd?: GrLineEnd
|
|
34
|
+
private _sxAngle?: GrLineAngle
|
|
35
|
+
private _sxLayer?: Layer
|
|
36
|
+
private _sxWidth?: Width
|
|
37
|
+
private _sxStroke?: Stroke
|
|
38
|
+
private _sxUuid?: Uuid
|
|
39
|
+
private _sxLocked?: GrLineLocked
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
super()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static override fromSexprPrimitives(
|
|
46
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
47
|
+
): GrLine {
|
|
48
|
+
const grLine = new GrLine()
|
|
49
|
+
|
|
50
|
+
const { propertyMap, arrayPropertyMap } =
|
|
51
|
+
SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
|
|
52
|
+
|
|
53
|
+
const unexpectedTokens = new Set<string>()
|
|
54
|
+
for (const token of Object.keys(propertyMap)) {
|
|
55
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
56
|
+
unexpectedTokens.add(token)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (const token of Object.keys(arrayPropertyMap)) {
|
|
60
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
61
|
+
unexpectedTokens.add(token)
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
if (arrayPropertyMap[token]!.length > 1) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`gr_line does not support repeated child tokens: ${token}`,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (unexpectedTokens.size > 0) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Unsupported child tokens inside gr_line expression: ${[...unexpectedTokens].join(", ")}`,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const primitive of primitiveSexprs) {
|
|
78
|
+
if (Array.isArray(primitive)) continue
|
|
79
|
+
throw new Error(
|
|
80
|
+
`gr_line encountered unexpected primitive child: ${JSON.stringify(primitive)}`,
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
grLine._sxStart = propertyMap.start as GrLineStart | undefined
|
|
85
|
+
grLine._sxEnd = propertyMap.end as GrLineEnd | undefined
|
|
86
|
+
grLine._sxAngle = propertyMap.angle as GrLineAngle | undefined
|
|
87
|
+
grLine._sxLayer = propertyMap.layer as Layer | undefined
|
|
88
|
+
grLine._sxWidth = propertyMap.width as Width | undefined
|
|
89
|
+
grLine._sxStroke = propertyMap.stroke as Stroke | undefined
|
|
90
|
+
const locked = propertyMap.locked as GrLineLocked | undefined
|
|
91
|
+
grLine._sxLocked = locked && locked.value ? locked : undefined
|
|
92
|
+
grLine._sxUuid = propertyMap.uuid as Uuid | undefined
|
|
93
|
+
|
|
94
|
+
if (!grLine._sxStart) {
|
|
95
|
+
throw new Error("gr_line requires a start child token")
|
|
96
|
+
}
|
|
97
|
+
if (!grLine._sxEnd) {
|
|
98
|
+
throw new Error("gr_line requires an end child token")
|
|
99
|
+
}
|
|
100
|
+
if (!grLine._sxLayer) {
|
|
101
|
+
throw new Error("gr_line requires a layer child token")
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return grLine
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get start(): GrLineStart | undefined {
|
|
108
|
+
return this._sxStart
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
set start(value: GrLineStart | GrLinePoint | undefined) {
|
|
112
|
+
this._sxStart = this.normalizeStart(value)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get end(): GrLineEnd | undefined {
|
|
116
|
+
return this._sxEnd
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
set end(value: GrLineEnd | GrLinePoint | undefined) {
|
|
120
|
+
this._sxEnd = this.normalizeEnd(value)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
get startPoint(): GrLinePoint | undefined {
|
|
124
|
+
return this._sxStart?.toObject()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get endPoint(): GrLinePoint | undefined {
|
|
128
|
+
return this._sxEnd?.toObject()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get angle(): number | undefined {
|
|
132
|
+
return this._sxAngle?.value
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
set angle(value: number | undefined) {
|
|
136
|
+
if (value === undefined) {
|
|
137
|
+
this._sxAngle = undefined
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
this._sxAngle = new GrLineAngle(value)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get layer(): Layer | undefined {
|
|
144
|
+
return this._sxLayer
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
set layer(value: Layer | string | Array<string | number> | undefined) {
|
|
148
|
+
if (value === undefined) {
|
|
149
|
+
this._sxLayer = undefined
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
if (value instanceof Layer) {
|
|
153
|
+
this._sxLayer = value
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
const names = Array.isArray(value) ? value : [value]
|
|
157
|
+
this._sxLayer = new Layer(names)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
get width(): number | undefined {
|
|
161
|
+
return this._sxWidth?.value
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
set width(value: Width | number | undefined) {
|
|
165
|
+
if (value === undefined) {
|
|
166
|
+
this._sxWidth = undefined
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
this._sxWidth = value instanceof Width ? value : new Width(value)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
get widthClass(): Width | undefined {
|
|
173
|
+
return this._sxWidth
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
set widthClass(value: Width | undefined) {
|
|
177
|
+
this._sxWidth = value
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
get stroke(): Stroke | undefined {
|
|
181
|
+
return this._sxStroke
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
set stroke(value: Stroke | undefined) {
|
|
185
|
+
this._sxStroke = value
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get uuid(): Uuid | undefined {
|
|
189
|
+
return this._sxUuid
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
set uuid(value: Uuid | string | undefined) {
|
|
193
|
+
if (value === undefined) {
|
|
194
|
+
this._sxUuid = undefined
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
get locked(): boolean {
|
|
201
|
+
return this._sxLocked?.value ?? false
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
set locked(value: boolean) {
|
|
205
|
+
this._sxLocked = value ? new GrLineLocked(true) : undefined
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
override getChildren(): SxClass[] {
|
|
209
|
+
const children: SxClass[] = []
|
|
210
|
+
if (this._sxStart) children.push(this._sxStart)
|
|
211
|
+
if (this._sxEnd) children.push(this._sxEnd)
|
|
212
|
+
if (this._sxAngle) children.push(this._sxAngle)
|
|
213
|
+
if (this._sxStroke) children.push(this._sxStroke)
|
|
214
|
+
if (this._sxWidth) children.push(this._sxWidth)
|
|
215
|
+
if (this._sxLocked) children.push(this._sxLocked)
|
|
216
|
+
if (this._sxLayer) children.push(this._sxLayer)
|
|
217
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
218
|
+
return children
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private normalizeStart(
|
|
222
|
+
value: GrLineStart | GrLinePoint | undefined,
|
|
223
|
+
): GrLineStart | undefined {
|
|
224
|
+
if (value === undefined) {
|
|
225
|
+
return undefined
|
|
226
|
+
}
|
|
227
|
+
if (value instanceof GrLineStart) {
|
|
228
|
+
return value
|
|
229
|
+
}
|
|
230
|
+
return new GrLineStart(value.x, value.y)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private normalizeEnd(
|
|
234
|
+
value: GrLineEnd | GrLinePoint | undefined,
|
|
235
|
+
): GrLineEnd | undefined {
|
|
236
|
+
if (value === undefined) {
|
|
237
|
+
return undefined
|
|
238
|
+
}
|
|
239
|
+
if (value instanceof GrLineEnd) {
|
|
240
|
+
return value
|
|
241
|
+
}
|
|
242
|
+
return new GrLineEnd(value.x, value.y)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
SxClass.register(GrLine)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
2
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
3
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
4
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
5
|
+
|
|
6
|
+
export class GrLineAngle extends SxPrimitiveNumber {
|
|
7
|
+
static override token = "angle"
|
|
8
|
+
static override parentToken = "gr_line"
|
|
9
|
+
override token = "angle"
|
|
10
|
+
|
|
11
|
+
constructor(value: number) {
|
|
12
|
+
super(value)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static override fromSexprPrimitives(
|
|
16
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
17
|
+
): GrLineAngle {
|
|
18
|
+
const [rawAngle] = primitiveSexprs
|
|
19
|
+
const angle = toNumberValue(rawAngle)
|
|
20
|
+
|
|
21
|
+
if (angle === undefined) {
|
|
22
|
+
throw new Error("gr_line angle expects a numeric value")
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return new GrLineAngle(angle)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override getString(): string {
|
|
29
|
+
return `(angle ${this.value})`
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
SxClass.register(GrLineAngle)
|