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,61 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
4
|
+
|
|
5
|
+
export class GrLineEnd extends SxClass {
|
|
6
|
+
static override token = "end"
|
|
7
|
+
static override parentToken = "gr_line"
|
|
8
|
+
override token = "end"
|
|
9
|
+
|
|
10
|
+
private _x: number
|
|
11
|
+
private _y: number
|
|
12
|
+
|
|
13
|
+
constructor(x: number, y: number) {
|
|
14
|
+
super()
|
|
15
|
+
this._x = x
|
|
16
|
+
this._y = y
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static override fromSexprPrimitives(
|
|
20
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
21
|
+
): GrLineEnd {
|
|
22
|
+
const [rawX, rawY] = primitiveSexprs
|
|
23
|
+
const x = toNumberValue(rawX)
|
|
24
|
+
const y = toNumberValue(rawY)
|
|
25
|
+
|
|
26
|
+
if (x === undefined || y === undefined) {
|
|
27
|
+
throw new Error("gr_line end expects two numeric arguments")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new GrLineEnd(x, y)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get x(): number {
|
|
34
|
+
return this._x
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set x(value: number) {
|
|
38
|
+
this._x = value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get y(): number {
|
|
42
|
+
return this._y
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set y(value: number) {
|
|
46
|
+
this._y = value
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toObject(): { x: number; y: number } {
|
|
50
|
+
return { x: this._x, y: this._y }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override getChildren(): SxClass[] {
|
|
54
|
+
return []
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override getString(): string {
|
|
58
|
+
return `(end ${this._x} ${this._y})`
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
SxClass.register(GrLineEnd)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
|
|
3
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
4
|
+
|
|
5
|
+
const truthyStrings = new Set(["true", "yes", "1"])
|
|
6
|
+
|
|
7
|
+
export class GrLineLocked extends SxPrimitiveBoolean {
|
|
8
|
+
static override token = "locked"
|
|
9
|
+
static override parentToken = "gr_line"
|
|
10
|
+
override token = "locked"
|
|
11
|
+
|
|
12
|
+
constructor(value: boolean) {
|
|
13
|
+
super(value)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static override fromSexprPrimitives(
|
|
17
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
18
|
+
): GrLineLocked {
|
|
19
|
+
const [rawValue] = primitiveSexprs
|
|
20
|
+
|
|
21
|
+
if (rawValue === undefined) {
|
|
22
|
+
return new GrLineLocked(true)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (typeof rawValue === "boolean") {
|
|
26
|
+
return new GrLineLocked(rawValue)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (typeof rawValue === "string") {
|
|
30
|
+
return new GrLineLocked(truthyStrings.has(rawValue.toLowerCase()))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return new GrLineLocked(false)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override getString(): string {
|
|
37
|
+
return `(locked ${this.value ? "yes" : "no"})`
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
SxClass.register(GrLineLocked)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
4
|
+
|
|
5
|
+
export class GrLineStart extends SxClass {
|
|
6
|
+
static override token = "start"
|
|
7
|
+
static override parentToken = "gr_line"
|
|
8
|
+
override token = "start"
|
|
9
|
+
|
|
10
|
+
private _x: number
|
|
11
|
+
private _y: number
|
|
12
|
+
|
|
13
|
+
constructor(x: number, y: number) {
|
|
14
|
+
super()
|
|
15
|
+
this._x = x
|
|
16
|
+
this._y = y
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static override fromSexprPrimitives(
|
|
20
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
21
|
+
): GrLineStart {
|
|
22
|
+
const [rawX, rawY] = primitiveSexprs
|
|
23
|
+
const x = toNumberValue(rawX)
|
|
24
|
+
const y = toNumberValue(rawY)
|
|
25
|
+
|
|
26
|
+
if (x === undefined || y === undefined) {
|
|
27
|
+
throw new Error("gr_line start expects two numeric arguments")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new GrLineStart(x, y)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get x(): number {
|
|
34
|
+
return this._x
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set x(value: number) {
|
|
38
|
+
this._x = value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get y(): number {
|
|
42
|
+
return this._y
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set y(value: number) {
|
|
46
|
+
this._y = value
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toObject(): { x: number; y: number } {
|
|
50
|
+
return { x: this._x, y: this._y }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override getChildren(): SxClass[] {
|
|
54
|
+
return []
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override getString(): string {
|
|
58
|
+
return `(start ${this._x} ${this._y})`
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
SxClass.register(GrLineStart)
|
|
@@ -0,0 +1,202 @@
|
|
|
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 { Xy } from "./Xy"
|
|
7
|
+
import { Layer } from "./Layer"
|
|
8
|
+
import { TextEffects } from "./TextEffects"
|
|
9
|
+
import { Uuid } from "./Uuid"
|
|
10
|
+
|
|
11
|
+
export interface GrTextPosition {
|
|
12
|
+
x: number
|
|
13
|
+
y: number
|
|
14
|
+
angle?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SUPPORTED_SINGLE_TOKENS = new Set([
|
|
18
|
+
"at",
|
|
19
|
+
"xy",
|
|
20
|
+
"layer",
|
|
21
|
+
"uuid",
|
|
22
|
+
"effects",
|
|
23
|
+
])
|
|
24
|
+
|
|
25
|
+
export class GrText extends SxClass {
|
|
26
|
+
static override token = "gr_text"
|
|
27
|
+
override token = "gr_text"
|
|
28
|
+
|
|
29
|
+
private _text = ""
|
|
30
|
+
private _sxPosition?: At | Xy
|
|
31
|
+
private _sxLayer?: Layer
|
|
32
|
+
private _sxUuid?: Uuid
|
|
33
|
+
private _sxEffects?: TextEffects
|
|
34
|
+
|
|
35
|
+
constructor(text = "") {
|
|
36
|
+
super()
|
|
37
|
+
this.text = text
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static override fromSexprPrimitives(
|
|
41
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
42
|
+
): GrText {
|
|
43
|
+
if (primitiveSexprs.length === 0) {
|
|
44
|
+
throw new Error("gr_text requires a text argument")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const [rawText, ...rest] = primitiveSexprs
|
|
48
|
+
const text = toStringValue(rawText)
|
|
49
|
+
if (text === undefined) {
|
|
50
|
+
throw new Error("gr_text text must be a string value")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const grText = new GrText(text)
|
|
54
|
+
|
|
55
|
+
const { propertyMap, arrayPropertyMap } =
|
|
56
|
+
SxClass.parsePrimitivesToClassProperties(rest, this.token)
|
|
57
|
+
|
|
58
|
+
const unexpectedTokens = new Set<string>()
|
|
59
|
+
for (const token of Object.keys(propertyMap)) {
|
|
60
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
61
|
+
unexpectedTokens.add(token)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const token of Object.keys(arrayPropertyMap)) {
|
|
65
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
66
|
+
unexpectedTokens.add(token)
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
if (arrayPropertyMap[token]!.length > 1) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`gr_text does not support repeated child tokens: ${token}`,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (unexpectedTokens.size > 0) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Unsupported child tokens inside gr_text expression: ${[...unexpectedTokens].join(", ")}`,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const primitive of rest) {
|
|
83
|
+
if (Array.isArray(primitive)) continue
|
|
84
|
+
throw new Error(
|
|
85
|
+
`gr_text encountered unexpected primitive child: ${JSON.stringify(primitive)}`,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const atInstance = propertyMap.at as At | undefined
|
|
90
|
+
const xyInstance = propertyMap.xy as Xy | undefined
|
|
91
|
+
if (atInstance && xyInstance) {
|
|
92
|
+
throw new Error("gr_text cannot include both at and xy tokens")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
grText._sxPosition = atInstance ?? xyInstance
|
|
96
|
+
grText._sxLayer = propertyMap.layer as Layer | undefined
|
|
97
|
+
grText._sxUuid = propertyMap.uuid as Uuid | undefined
|
|
98
|
+
grText._sxEffects = propertyMap.effects as TextEffects | undefined
|
|
99
|
+
|
|
100
|
+
if (!grText._sxPosition) {
|
|
101
|
+
throw new Error("gr_text requires a position child token")
|
|
102
|
+
}
|
|
103
|
+
if (!grText._sxLayer) {
|
|
104
|
+
throw new Error("gr_text requires a layer child token")
|
|
105
|
+
}
|
|
106
|
+
if (!grText._sxUuid) {
|
|
107
|
+
throw new Error("gr_text requires a uuid child token")
|
|
108
|
+
}
|
|
109
|
+
if (!grText._sxEffects) {
|
|
110
|
+
throw new Error("gr_text requires an effects child token")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return grText
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
get text(): string {
|
|
117
|
+
return this._text
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
set text(value: string) {
|
|
121
|
+
this._text = value
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get position(): At | Xy | undefined {
|
|
125
|
+
return this._sxPosition
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
set position(
|
|
129
|
+
value: At | Xy | GrTextPosition | undefined,
|
|
130
|
+
) {
|
|
131
|
+
if (value === undefined) {
|
|
132
|
+
this._sxPosition = undefined
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
if (value instanceof At || value instanceof Xy) {
|
|
136
|
+
this._sxPosition = value
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
const { x, y, angle } = value
|
|
140
|
+
if (angle !== undefined) {
|
|
141
|
+
this._sxPosition = new At([x, y, angle])
|
|
142
|
+
} else {
|
|
143
|
+
this._sxPosition = new Xy(x, y)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
get layer(): Layer | undefined {
|
|
148
|
+
return this._sxLayer
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
set layer(value: Layer | string | Array<string | number> | undefined) {
|
|
152
|
+
if (value === undefined) {
|
|
153
|
+
this._sxLayer = undefined
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
if (value instanceof Layer) {
|
|
157
|
+
this._sxLayer = value
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
const names = Array.isArray(value) ? value : [value]
|
|
161
|
+
this._sxLayer = new Layer(names)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
get uuid(): Uuid | undefined {
|
|
165
|
+
return this._sxUuid
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
set uuid(value: Uuid | string | undefined) {
|
|
169
|
+
if (value === undefined) {
|
|
170
|
+
this._sxUuid = undefined
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get effects(): TextEffects | undefined {
|
|
177
|
+
return this._sxEffects
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
set effects(value: TextEffects | undefined) {
|
|
181
|
+
this._sxEffects = value
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
override getChildren(): SxClass[] {
|
|
185
|
+
const children: SxClass[] = []
|
|
186
|
+
if (this._sxPosition) children.push(this._sxPosition)
|
|
187
|
+
if (this._sxLayer) children.push(this._sxLayer)
|
|
188
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
189
|
+
if (this._sxEffects) children.push(this._sxEffects)
|
|
190
|
+
return children
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
override getString(): string {
|
|
194
|
+
const lines = ["(gr_text", ` ${quoteSExprString(this._text)}`]
|
|
195
|
+
for (const child of this.getChildren()) {
|
|
196
|
+
lines.push(child.getStringIndented())
|
|
197
|
+
}
|
|
198
|
+
lines.push(")")
|
|
199
|
+
return lines.join("\n")
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
SxClass.register(GrText)
|
|
@@ -0,0 +1,256 @@
|
|
|
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 { Uuid } from "./Uuid"
|
|
8
|
+
import { At } from "./At"
|
|
9
|
+
import { Xy } from "./Xy"
|
|
10
|
+
|
|
11
|
+
const SUPPORTED_SINGLE_TOKENS = new Set([
|
|
12
|
+
"at",
|
|
13
|
+
"xy",
|
|
14
|
+
"scale",
|
|
15
|
+
"layer",
|
|
16
|
+
"uuid",
|
|
17
|
+
"data",
|
|
18
|
+
])
|
|
19
|
+
|
|
20
|
+
const SUPPORTED_MULTI_TOKENS = new Set<string>()
|
|
21
|
+
|
|
22
|
+
export class Image extends SxClass {
|
|
23
|
+
static override token = "image"
|
|
24
|
+
token = "image"
|
|
25
|
+
|
|
26
|
+
private _sxPosition?: At | Xy
|
|
27
|
+
private _sxScale?: ImageScale
|
|
28
|
+
private _sxLayer?: Layer
|
|
29
|
+
private _sxUuid?: Uuid
|
|
30
|
+
private _sxData?: ImageData
|
|
31
|
+
|
|
32
|
+
static override fromSexprPrimitives(
|
|
33
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
34
|
+
): Image {
|
|
35
|
+
const image = new Image()
|
|
36
|
+
|
|
37
|
+
const structuredPrimitives: PrimitiveSExpr[] = []
|
|
38
|
+
|
|
39
|
+
for (const primitive of primitiveSexprs) {
|
|
40
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`image encountered invalid child expression: ${JSON.stringify(primitive)}`,
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
structuredPrimitives.push(primitive)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { propertyMap, arrayPropertyMap } =
|
|
50
|
+
SxClass.parsePrimitivesToClassProperties(structuredPrimitives, this.token)
|
|
51
|
+
|
|
52
|
+
for (const token of Object.keys(propertyMap)) {
|
|
53
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`image encountered unsupported child token "${token}"`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const [token, entries] of Object.entries(arrayPropertyMap)) {
|
|
61
|
+
if (!SUPPORTED_SINGLE_TOKENS.has(token)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`image encountered unsupported child token "${token}"`,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
if (!SUPPORTED_MULTI_TOKENS.has(token) && entries.length > 1) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`image does not support repeated child token "${token}"`,
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const atInstance = propertyMap.at as At | undefined
|
|
74
|
+
const xyInstance = propertyMap.xy as Xy | undefined
|
|
75
|
+
if (atInstance && xyInstance) {
|
|
76
|
+
throw new Error("image cannot include both at and xy child tokens")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
image._sxPosition = atInstance ?? xyInstance
|
|
80
|
+
image._sxScale = propertyMap.scale as ImageScale | undefined
|
|
81
|
+
image._sxLayer = propertyMap.layer as Layer | undefined
|
|
82
|
+
image._sxUuid = propertyMap.uuid as Uuid | undefined
|
|
83
|
+
image._sxData = propertyMap.data as ImageData | undefined
|
|
84
|
+
|
|
85
|
+
return image
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get position(): At | Xy | undefined {
|
|
89
|
+
return this._sxPosition
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
set position(value: At | Xy | undefined) {
|
|
93
|
+
this._sxPosition = value
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get scale(): ImageScale | undefined {
|
|
97
|
+
return this._sxScale
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
set scale(value: ImageScale | number | undefined) {
|
|
101
|
+
if (value === undefined) {
|
|
102
|
+
this._sxScale = undefined
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
this._sxScale = value instanceof ImageScale ? value : new ImageScale(value)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get layer(): Layer | undefined {
|
|
109
|
+
return this._sxLayer
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
set layer(value: Layer | string | string[] | undefined) {
|
|
113
|
+
if (value === undefined) {
|
|
114
|
+
this._sxLayer = undefined
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
if (value instanceof Layer) {
|
|
118
|
+
this._sxLayer = value
|
|
119
|
+
} else {
|
|
120
|
+
const names = Array.isArray(value) ? value : [value]
|
|
121
|
+
this._sxLayer = new Layer(names)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get uuid(): Uuid | undefined {
|
|
126
|
+
return this._sxUuid
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
set uuid(value: Uuid | string | undefined) {
|
|
130
|
+
if (value === undefined) {
|
|
131
|
+
this._sxUuid = undefined
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get data(): ImageData | undefined {
|
|
138
|
+
return this._sxData
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
set data(value: ImageData | string | string[] | undefined) {
|
|
142
|
+
if (value === undefined) {
|
|
143
|
+
this._sxData = undefined
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
if (value instanceof ImageData) {
|
|
147
|
+
this._sxData = value
|
|
148
|
+
} else if (Array.isArray(value)) {
|
|
149
|
+
this._sxData = ImageData.fromStrings(value)
|
|
150
|
+
} else {
|
|
151
|
+
this._sxData = ImageData.fromStrings([value])
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
override getChildren(): SxClass[] {
|
|
156
|
+
const children: SxClass[] = []
|
|
157
|
+
if (this._sxPosition) children.push(this._sxPosition)
|
|
158
|
+
if (this._sxScale) children.push(this._sxScale)
|
|
159
|
+
if (this._sxLayer) children.push(this._sxLayer)
|
|
160
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
161
|
+
if (this._sxData) children.push(this._sxData)
|
|
162
|
+
return children
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
SxClass.register(Image)
|
|
166
|
+
|
|
167
|
+
export class ImageScale extends SxClass {
|
|
168
|
+
static override token = "scale"
|
|
169
|
+
static override parentToken = "image"
|
|
170
|
+
token = "scale"
|
|
171
|
+
|
|
172
|
+
value: number
|
|
173
|
+
|
|
174
|
+
constructor(value: number) {
|
|
175
|
+
super()
|
|
176
|
+
this.value = value
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static override fromSexprPrimitives(
|
|
180
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
181
|
+
): ImageScale {
|
|
182
|
+
const [raw] = primitiveSexprs
|
|
183
|
+
const numeric = toNumberValue(raw)
|
|
184
|
+
return new ImageScale(numeric ?? 1)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
override getChildren(): SxClass[] {
|
|
188
|
+
return []
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
override getString(): string {
|
|
192
|
+
return `(scale ${this.value})`
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
SxClass.register(ImageScale)
|
|
196
|
+
|
|
197
|
+
export class ImageData extends SxClass {
|
|
198
|
+
static override token = "data"
|
|
199
|
+
static override parentToken = "image"
|
|
200
|
+
token = "data"
|
|
201
|
+
|
|
202
|
+
private _chunks: string[]
|
|
203
|
+
|
|
204
|
+
constructor(chunks: string[] = []) {
|
|
205
|
+
super()
|
|
206
|
+
this._chunks = chunks
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static override fromSexprPrimitives(
|
|
210
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
211
|
+
): ImageData {
|
|
212
|
+
const chunks = primitiveSexprs.map((primitive) => primitiveToChunk(primitive))
|
|
213
|
+
return new ImageData(chunks)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static fromStrings(values: string[]): ImageData {
|
|
217
|
+
return new ImageData(values)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
get chunks(): string[] {
|
|
221
|
+
return [...this._chunks]
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
set chunks(values: string[]) {
|
|
225
|
+
this._chunks = [...values]
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
get value(): string {
|
|
229
|
+
return this._chunks.join("")
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
set value(data: string) {
|
|
233
|
+
this._chunks = [data]
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
override getChildren(): SxClass[] {
|
|
237
|
+
return []
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
override getString(): string {
|
|
241
|
+
if (this._chunks.length === 0) {
|
|
242
|
+
return "(data)"
|
|
243
|
+
}
|
|
244
|
+
const rendered = this._chunks.map((chunk) => quoteSExprString(chunk)).join(" ")
|
|
245
|
+
return `(data ${rendered})`
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
SxClass.register(ImageData)
|
|
249
|
+
|
|
250
|
+
function primitiveToChunk(value: PrimitiveSExpr): string {
|
|
251
|
+
const stringValue = toStringValue(value)
|
|
252
|
+
if (stringValue !== undefined) {
|
|
253
|
+
return stringValue
|
|
254
|
+
}
|
|
255
|
+
return printSExpr(value)
|
|
256
|
+
}
|