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,59 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { quoteSExprString } from "../utils/quoteSExprString"
|
|
4
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
5
|
+
import { toStringValue } from "../utils/toStringValue"
|
|
6
|
+
|
|
7
|
+
export class ViaNet extends SxClass {
|
|
8
|
+
static override token = "net"
|
|
9
|
+
static override parentToken = "via"
|
|
10
|
+
token = "net"
|
|
11
|
+
|
|
12
|
+
private _id: number
|
|
13
|
+
private _name?: string
|
|
14
|
+
|
|
15
|
+
constructor(id: number, name?: string) {
|
|
16
|
+
super()
|
|
17
|
+
this._id = id
|
|
18
|
+
this._name = name
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static override fromSexprPrimitives(
|
|
22
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
23
|
+
): ViaNet {
|
|
24
|
+
const id = toNumberValue(primitiveSexprs[0])
|
|
25
|
+
if (id === undefined) {
|
|
26
|
+
throw new Error("via net requires a numeric id")
|
|
27
|
+
}
|
|
28
|
+
const name = primitiveSexprs.length > 1 ? toStringValue(primitiveSexprs[1]) : undefined
|
|
29
|
+
return new ViaNet(id, name)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get id(): number {
|
|
33
|
+
return this._id
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
set id(value: number) {
|
|
37
|
+
this._id = value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get name(): string | undefined {
|
|
41
|
+
return this._name
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
set name(value: string | undefined) {
|
|
45
|
+
this._name = value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override getChildren(): SxClass[] {
|
|
49
|
+
return []
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override getString(): string {
|
|
53
|
+
if (this._name !== undefined) {
|
|
54
|
+
return `(net ${this._id} ${quoteSExprString(this._name)})`
|
|
55
|
+
}
|
|
56
|
+
return `(net ${this._id})`
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
SxClass.register(ViaNet)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { Pts } from "./Pts"
|
|
4
|
+
import { Stroke } from "./Stroke"
|
|
5
|
+
import { Uuid } from "./Uuid"
|
|
6
|
+
|
|
7
|
+
const SUPPORTED_TOKENS = new Set(["pts", "stroke", "uuid"])
|
|
8
|
+
|
|
9
|
+
export class Wire extends SxClass {
|
|
10
|
+
static override token = "wire"
|
|
11
|
+
static override parentToken = "kicad_sch"
|
|
12
|
+
override token = "wire"
|
|
13
|
+
|
|
14
|
+
private _sxPts?: Pts
|
|
15
|
+
private _sxStroke?: Stroke
|
|
16
|
+
private _sxUuid?: Uuid
|
|
17
|
+
|
|
18
|
+
static override fromSexprPrimitives(
|
|
19
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
20
|
+
): Wire {
|
|
21
|
+
const wire = new Wire()
|
|
22
|
+
|
|
23
|
+
const { propertyMap, arrayPropertyMap } =
|
|
24
|
+
SxClass.parsePrimitivesToClassProperties(primitiveSexprs, this.token)
|
|
25
|
+
|
|
26
|
+
for (const [token, entries] of Object.entries(arrayPropertyMap)) {
|
|
27
|
+
if (!SUPPORTED_TOKENS.has(token)) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Unsupported child tokens inside wire expression: ${token}`,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
if (entries.length > 1) {
|
|
33
|
+
throw new Error(`wire does not support repeated child tokens: ${token}`)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const unsupportedTokens = Object.keys(propertyMap).filter(
|
|
38
|
+
(token) => !SUPPORTED_TOKENS.has(token),
|
|
39
|
+
)
|
|
40
|
+
if (unsupportedTokens.length > 0) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Unsupported child tokens inside wire expression: ${unsupportedTokens.join(", ")}`,
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
wire._sxPts =
|
|
47
|
+
(arrayPropertyMap.pts?.[0] as Pts | undefined) ??
|
|
48
|
+
(propertyMap.pts as Pts | undefined)
|
|
49
|
+
wire._sxStroke = propertyMap.stroke as Stroke | undefined
|
|
50
|
+
wire._sxUuid = propertyMap.uuid as Uuid | undefined
|
|
51
|
+
|
|
52
|
+
return wire
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get points(): Pts | undefined {
|
|
56
|
+
return this._sxPts
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set points(value: Pts | undefined) {
|
|
60
|
+
this._sxPts = value
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get stroke(): Stroke | undefined {
|
|
64
|
+
return this._sxStroke
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
set stroke(value: Stroke | undefined) {
|
|
68
|
+
this._sxStroke = value
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get uuid(): Uuid | undefined {
|
|
72
|
+
return this._sxUuid
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
set uuid(value: Uuid | string | undefined) {
|
|
76
|
+
if (value === undefined) {
|
|
77
|
+
this._sxUuid = undefined
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
this._sxUuid = value instanceof Uuid ? value : new Uuid(value)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override getChildren(): SxClass[] {
|
|
84
|
+
const children: SxClass[] = []
|
|
85
|
+
if (this._sxPts) children.push(this._sxPts)
|
|
86
|
+
if (this._sxStroke) children.push(this._sxStroke)
|
|
87
|
+
if (this._sxUuid) children.push(this._sxUuid)
|
|
88
|
+
return children
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
SxClass.register(Wire)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
4
|
+
|
|
5
|
+
export class Xy extends SxClass {
|
|
6
|
+
static override token = "xy"
|
|
7
|
+
token = "xy"
|
|
8
|
+
|
|
9
|
+
x: number
|
|
10
|
+
y: number
|
|
11
|
+
|
|
12
|
+
constructor(x: number, y: number) {
|
|
13
|
+
super()
|
|
14
|
+
this.x = x
|
|
15
|
+
this.y = y
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static override fromSexprPrimitives(
|
|
19
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
20
|
+
): Xy {
|
|
21
|
+
const [rawX, rawY] = primitiveSexprs
|
|
22
|
+
const x = toNumberValue(rawX) ?? 0
|
|
23
|
+
const y = toNumberValue(rawY) ?? 0
|
|
24
|
+
return new Xy(x, y)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override getChildren(): SxClass[] {
|
|
28
|
+
return []
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override getString(): string {
|
|
32
|
+
return `(xy ${this.x} ${this.y})`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
SxClass.register(Xy)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import { printSExpr, type PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
|
|
4
|
+
export class Zone extends SxClass {
|
|
5
|
+
static override token = "zone"
|
|
6
|
+
token = "zone"
|
|
7
|
+
|
|
8
|
+
private _rawChildren: PrimitiveSExpr[] = []
|
|
9
|
+
|
|
10
|
+
static override fromSexprPrimitives(
|
|
11
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
12
|
+
): Zone {
|
|
13
|
+
const zone = new Zone()
|
|
14
|
+
zone._rawChildren = [...primitiveSexprs]
|
|
15
|
+
return zone
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get rawChildren(): PrimitiveSExpr[] {
|
|
19
|
+
return [...this._rawChildren]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
set rawChildren(children: PrimitiveSExpr[]) {
|
|
23
|
+
this._rawChildren = [...children]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override getChildren(): SxClass[] {
|
|
27
|
+
return []
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override getString(): string {
|
|
31
|
+
const lines = ["(zone"]
|
|
32
|
+
|
|
33
|
+
for (const arg of this._rawChildren) {
|
|
34
|
+
lines.push(` ${printSExpr(arg)}`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
lines.push(")")
|
|
38
|
+
return lines.join("\n")
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
SxClass.register(Zone)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export * from "./base-classes/SxClass"
|
|
2
|
+
export * from "./classes/Stroke"
|
|
3
|
+
export * from "./classes/Width"
|
|
4
|
+
export * from "./classes/Unit"
|
|
5
|
+
export * from "./classes/InBom"
|
|
6
|
+
export * from "./classes/OnBoard"
|
|
7
|
+
export * from "./classes/StrokeType"
|
|
8
|
+
export * from "./classes/Color"
|
|
9
|
+
export * from "./classes/Pts"
|
|
10
|
+
export * from "./classes/At"
|
|
11
|
+
export * from "./classes/Xy"
|
|
12
|
+
export * from "./classes/TextEffects"
|
|
13
|
+
export * from "./classes/TitleBlock"
|
|
14
|
+
export * from "./classes/Paper"
|
|
15
|
+
export * from "./classes/Image"
|
|
16
|
+
export * from "./classes/RenderCache"
|
|
17
|
+
export * from "./classes/Uuid"
|
|
18
|
+
export * from "./classes/KicadSchGenerator"
|
|
19
|
+
export * from "./classes/KicadSchVersion"
|
|
20
|
+
export * from "./classes/KicadSchGeneratorVersion"
|
|
21
|
+
export * from "./classes/LibSymbols"
|
|
22
|
+
export * from "./classes/Wire"
|
|
23
|
+
export * from "./classes/Bus"
|
|
24
|
+
export * from "./classes/Junction"
|
|
25
|
+
export * from "./classes/NoConnect"
|
|
26
|
+
export * from "./classes/BusEntry"
|
|
27
|
+
export * from "./classes/Label"
|
|
28
|
+
export * from "./classes/SchematicText"
|
|
29
|
+
export * from "./classes/KicadSch"
|
|
30
|
+
export * from "./classes/Property"
|
|
31
|
+
export * from "./classes/PropertyUnlocked"
|
|
32
|
+
export * from "./classes/PropertyHide"
|
|
33
|
+
export * from "./classes/Footprint"
|
|
34
|
+
export * from "./classes/FootprintLocked"
|
|
35
|
+
export * from "./classes/FootprintPlaced"
|
|
36
|
+
export * from "./classes/FootprintTedit"
|
|
37
|
+
export * from "./classes/FootprintDescr"
|
|
38
|
+
export * from "./classes/FootprintTags"
|
|
39
|
+
export * from "./classes/FootprintSheetname"
|
|
40
|
+
export * from "./classes/FootprintSheetfile"
|
|
41
|
+
export * from "./classes/FootprintPath"
|
|
42
|
+
export * from "./classes/FootprintAutoplaceCost90"
|
|
43
|
+
export * from "./classes/FootprintAutoplaceCost180"
|
|
44
|
+
export * from "./classes/FootprintSolderMaskMargin"
|
|
45
|
+
export * from "./classes/FootprintSolderPasteMargin"
|
|
46
|
+
export * from "./classes/FootprintSolderPasteRatio"
|
|
47
|
+
export * from "./classes/FootprintClearance"
|
|
48
|
+
export * from "./classes/FootprintZoneConnect"
|
|
49
|
+
export * from "./classes/FootprintThermalWidth"
|
|
50
|
+
export * from "./classes/FootprintThermalGap"
|
|
51
|
+
export * from "./classes/FootprintAttr"
|
|
52
|
+
export * from "./classes/FootprintPrivateLayers"
|
|
53
|
+
export * from "./classes/FootprintNetTiePadGroups"
|
|
54
|
+
export * from "./classes/GrLine"
|
|
55
|
+
export * from "./classes/GrLineStart"
|
|
56
|
+
export * from "./classes/GrLineEnd"
|
|
57
|
+
export * from "./classes/GrLineAngle"
|
|
58
|
+
export * from "./classes/GrLineLocked"
|
|
59
|
+
export * from "./classes/GrText"
|
|
60
|
+
export * from "./classes/Segment"
|
|
61
|
+
export * from "./classes/SegmentStart"
|
|
62
|
+
export * from "./classes/SegmentEnd"
|
|
63
|
+
export * from "./classes/SegmentNet"
|
|
64
|
+
export * from "./classes/SegmentLocked"
|
|
65
|
+
export * from "./classes/Zone"
|
|
66
|
+
export * from "./classes/EmbeddedFonts"
|
|
67
|
+
export * from "./classes/Layers"
|
|
68
|
+
export * from "./classes/Layer"
|
|
69
|
+
export * from "./classes/FpText"
|
|
70
|
+
export * from "./classes/FpTextBox"
|
|
71
|
+
export * from "./classes/FpLine"
|
|
72
|
+
export * from "./classes/FpRect"
|
|
73
|
+
export * from "./classes/FpCircle"
|
|
74
|
+
export * from "./classes/FpArc"
|
|
75
|
+
export * from "./classes/FpPoly"
|
|
76
|
+
export * from "./classes/FpPolyFill"
|
|
77
|
+
export * from "./classes/FpPolyLocked"
|
|
78
|
+
export * from "./classes/FootprintPad"
|
|
79
|
+
export * from "./classes/FootprintModel"
|
|
80
|
+
export * from "./classes/PadSize"
|
|
81
|
+
export * from "./classes/PadDrill"
|
|
82
|
+
export * from "./classes/PadDrillOffset"
|
|
83
|
+
export * from "./classes/PadLayers"
|
|
84
|
+
export * from "./classes/PadRoundrectRratio"
|
|
85
|
+
export * from "./classes/PadRectDelta"
|
|
86
|
+
export * from "./classes/PadChamferRatio"
|
|
87
|
+
export * from "./classes/PadChamfer"
|
|
88
|
+
export * from "./classes/PadNet"
|
|
89
|
+
export * from "./classes/PadPinFunction"
|
|
90
|
+
export * from "./classes/PadPinType"
|
|
91
|
+
export * from "./classes/PadDieLength"
|
|
92
|
+
export * from "./classes/PadSolderMaskMargin"
|
|
93
|
+
export * from "./classes/PadSolderPasteMargin"
|
|
94
|
+
export * from "./classes/PadSolderPasteMarginRatio"
|
|
95
|
+
export * from "./classes/PadClearance"
|
|
96
|
+
export * from "./classes/PadZoneConnect"
|
|
97
|
+
export * from "./classes/PadThermalWidth"
|
|
98
|
+
export * from "./classes/PadThermalGap"
|
|
99
|
+
export * from "./classes/PadThermalBridgeAngle"
|
|
100
|
+
export * from "./classes/PadOptions"
|
|
101
|
+
export * from "./classes/PadPrimitives"
|
|
102
|
+
export * from "./classes/PadPrimitiveGrLine"
|
|
103
|
+
export * from "./classes/PadPrimitiveGrArc"
|
|
104
|
+
export * from "./classes/PadPrimitiveGrCircle"
|
|
105
|
+
export * from "./classes/PadTeardrops"
|
|
106
|
+
export * from "./classes/Symbol"
|
|
107
|
+
export * from "./classes/Sheet"
|
|
108
|
+
export * from "./classes/SheetPin"
|
|
109
|
+
export * from "./classes/SheetProperty"
|
|
110
|
+
export * from "./classes/SheetInstances"
|
|
111
|
+
export * from "./classes/SheetInstancesRoot"
|
|
112
|
+
export * from "./classes/SheetFill"
|
|
113
|
+
export * from "./classes/SheetSize"
|
|
114
|
+
export * from "./classes/FieldsAutoplaced"
|
|
115
|
+
export * from "./classes/ExcludeFromSim"
|
|
116
|
+
export * from "./classes/Dnp"
|
|
117
|
+
export * from "./classes/Setup"
|
|
118
|
+
export * from "./classes/PcbGeneral"
|
|
119
|
+
export * from "./classes/PcbGeneralThickness"
|
|
120
|
+
export * from "./classes/PcbGeneralLegacyTeardrops"
|
|
121
|
+
export * from "./classes/PcbLayers"
|
|
122
|
+
export * from "./classes/PcbLayerDefinition"
|
|
123
|
+
export * from "./classes/PcbNet"
|
|
124
|
+
export * from "./classes/PcbVersion"
|
|
125
|
+
export * from "./classes/PcbGenerator"
|
|
126
|
+
export * from "./classes/PcbGeneratorVersion"
|
|
127
|
+
export * from "./classes/KicadPcb"
|
|
128
|
+
export * from "./classes/Via"
|
|
129
|
+
export * from "./classes/ViaNet"
|
|
130
|
+
export * from "./parseKicadSexpr"
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// s_expr_parser.ts
|
|
2
|
+
export type PrimitiveSExpr =
|
|
3
|
+
| string // symbols and string literals (distinct via `type` guard if you want)
|
|
4
|
+
| number
|
|
5
|
+
| boolean
|
|
6
|
+
| null
|
|
7
|
+
| PrimitiveSExpr[] // lists
|
|
8
|
+
|
|
9
|
+
type Token =
|
|
10
|
+
| { type: "lparen" }
|
|
11
|
+
| { type: "rparen" }
|
|
12
|
+
| { type: "number"; value: number }
|
|
13
|
+
| { type: "string"; value: string }
|
|
14
|
+
| { type: "boolean"; value: boolean }
|
|
15
|
+
| { type: "nil" }
|
|
16
|
+
| { type: "symbol"; value: string }
|
|
17
|
+
|
|
18
|
+
export function tokenize(input: string): Token[] {
|
|
19
|
+
const tokens: Token[] = []
|
|
20
|
+
let i = 0
|
|
21
|
+
|
|
22
|
+
const isWhitespace = (ch: string) => /\s/.test(ch)
|
|
23
|
+
const isSymbolInitial = (ch: string) => /[^\s()"]/u.test(ch) // anything except ws, parens, quote
|
|
24
|
+
const peek = () => (i < input.length ? input[i]! : undefined)
|
|
25
|
+
const advance = () => {
|
|
26
|
+
if (i >= input.length) {
|
|
27
|
+
throw new SyntaxError("Unexpected end of input")
|
|
28
|
+
}
|
|
29
|
+
return input[i++]!
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
while (i < input.length) {
|
|
33
|
+
const ch = peek()
|
|
34
|
+
if (ch === undefined) {
|
|
35
|
+
break
|
|
36
|
+
}
|
|
37
|
+
const current: string = ch
|
|
38
|
+
|
|
39
|
+
// Skip whitespace
|
|
40
|
+
if (isWhitespace(current)) {
|
|
41
|
+
i++
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Comments ;...<EOL>
|
|
46
|
+
if (current === ";") {
|
|
47
|
+
while (i < input.length && input[i] !== "\n") i++
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (current === "(") {
|
|
52
|
+
tokens.push({ type: "lparen" })
|
|
53
|
+
i++
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
if (current === ")") {
|
|
57
|
+
tokens.push({ type: "rparen" })
|
|
58
|
+
i++
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// String literal
|
|
63
|
+
if (current === '"') {
|
|
64
|
+
i++ // skip opening quote
|
|
65
|
+
let out = ""
|
|
66
|
+
while (i < input.length) {
|
|
67
|
+
const c = advance()
|
|
68
|
+
if (c === '"') break
|
|
69
|
+
if (c === "\\") {
|
|
70
|
+
if (i >= input.length)
|
|
71
|
+
throw new SyntaxError("Unterminated escape in string")
|
|
72
|
+
const e = advance()
|
|
73
|
+
switch (e) {
|
|
74
|
+
case "n":
|
|
75
|
+
out += "\n"
|
|
76
|
+
break
|
|
77
|
+
case "r":
|
|
78
|
+
out += "\r"
|
|
79
|
+
break
|
|
80
|
+
case "t":
|
|
81
|
+
out += "\t"
|
|
82
|
+
break
|
|
83
|
+
case '"':
|
|
84
|
+
out += '"'
|
|
85
|
+
break
|
|
86
|
+
case "\\":
|
|
87
|
+
out += "\\"
|
|
88
|
+
break
|
|
89
|
+
default:
|
|
90
|
+
out += e
|
|
91
|
+
break // unknown escapes: keep raw
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
out += c
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (input[i - 1] !== '"')
|
|
98
|
+
throw new SyntaxError("Unterminated string literal")
|
|
99
|
+
tokens.push({ type: "string", value: out })
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Number or symbol
|
|
104
|
+
if (isSymbolInitial(current) || current === "-" || current === "+" || current === ".") {
|
|
105
|
+
// read a maximal token until delimiter
|
|
106
|
+
let start = i
|
|
107
|
+
while (i < input.length) {
|
|
108
|
+
const nextChar = input[i]!
|
|
109
|
+
if (
|
|
110
|
+
isWhitespace(nextChar) ||
|
|
111
|
+
nextChar === "(" ||
|
|
112
|
+
nextChar === ")" ||
|
|
113
|
+
nextChar === '"'
|
|
114
|
+
) {
|
|
115
|
+
break
|
|
116
|
+
}
|
|
117
|
+
i++
|
|
118
|
+
}
|
|
119
|
+
const raw = input.slice(start, i)
|
|
120
|
+
|
|
121
|
+
// Booleans
|
|
122
|
+
if (raw === "#t") {
|
|
123
|
+
tokens.push({ type: "boolean", value: true })
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
if (raw === "#f") {
|
|
127
|
+
tokens.push({ type: "boolean", value: false })
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// nil
|
|
132
|
+
if (raw === "nil") {
|
|
133
|
+
tokens.push({ type: "nil" })
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Numbers (int/float), allow leading +/-, decimals, exponent
|
|
138
|
+
if (/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/u.test(raw)) {
|
|
139
|
+
tokens.push({ type: "number", value: Number(raw) })
|
|
140
|
+
} else {
|
|
141
|
+
tokens.push({ type: "symbol", value: raw })
|
|
142
|
+
}
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
throw new SyntaxError(`Unexpected character: ${JSON.stringify(ch)} at ${i}`)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return tokens
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function parseToPrimitiveSExpr(input: string): PrimitiveSExpr[] {
|
|
153
|
+
const toks = tokenize(input)
|
|
154
|
+
let idx = 0
|
|
155
|
+
|
|
156
|
+
const peekToken = () => (idx < toks.length ? toks[idx]! : undefined)
|
|
157
|
+
const advanceToken = () => {
|
|
158
|
+
if (idx >= toks.length) {
|
|
159
|
+
throw new SyntaxError("Unexpected end of input")
|
|
160
|
+
}
|
|
161
|
+
return toks[idx++]!
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function readForm(): PrimitiveSExpr {
|
|
165
|
+
const t = advanceToken()
|
|
166
|
+
|
|
167
|
+
switch (t.type) {
|
|
168
|
+
case "lparen": {
|
|
169
|
+
const list: PrimitiveSExpr[] = []
|
|
170
|
+
while (true) {
|
|
171
|
+
const next = peekToken()
|
|
172
|
+
if (!next) {
|
|
173
|
+
throw new SyntaxError("Unmatched '('")
|
|
174
|
+
}
|
|
175
|
+
if (next.type === "rparen") break
|
|
176
|
+
list.push(readForm())
|
|
177
|
+
}
|
|
178
|
+
advanceToken() // consume rparen
|
|
179
|
+
return list
|
|
180
|
+
}
|
|
181
|
+
case "rparen":
|
|
182
|
+
throw new SyntaxError("Unmatched ')'")
|
|
183
|
+
case "number":
|
|
184
|
+
return t.value
|
|
185
|
+
case "string":
|
|
186
|
+
return t.value
|
|
187
|
+
case "boolean":
|
|
188
|
+
return t.value
|
|
189
|
+
case "nil":
|
|
190
|
+
return null
|
|
191
|
+
case "symbol":
|
|
192
|
+
return t.value // represent symbols as strings
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const forms: PrimitiveSExpr[] = []
|
|
197
|
+
while (peekToken()) forms.push(readForm())
|
|
198
|
+
return forms
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* -------------------------
|
|
202
|
+
Tiny helper utilities
|
|
203
|
+
--------------------------*/
|
|
204
|
+
|
|
205
|
+
export function printSExpr(x: PrimitiveSExpr): string {
|
|
206
|
+
if (x === null) return "nil"
|
|
207
|
+
if (typeof x === "boolean") return x ? "#t" : "#f"
|
|
208
|
+
if (typeof x === "number") return Number.isFinite(x) ? String(x) : "nan"
|
|
209
|
+
if (typeof x === "string") {
|
|
210
|
+
// naive: treat as symbol if it looks like a symbol; otherwise quote
|
|
211
|
+
if (/^[^\s()"]+$/u.test(x) && x !== "nil" && x !== "#t" && x !== "#f")
|
|
212
|
+
return x
|
|
213
|
+
return `"${x.replace(/["\\\n\r\t]/g, (m) =>
|
|
214
|
+
m === '"'
|
|
215
|
+
? '\\"'
|
|
216
|
+
: m === "\\"
|
|
217
|
+
? "\\\\"
|
|
218
|
+
: m === "\n"
|
|
219
|
+
? "\\n"
|
|
220
|
+
: m === "\r"
|
|
221
|
+
? "\\r"
|
|
222
|
+
: "\\t",
|
|
223
|
+
)}"`
|
|
224
|
+
}
|
|
225
|
+
if (Array.isArray(x)) {
|
|
226
|
+
return `(${x.map(printSExpr).join(" ")})`
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
throw new Error(`Unsupported S-expression value: ${JSON.stringify(x)}`)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Quick example:
|
|
233
|
+
// const program = `
|
|
234
|
+
// ; define square
|
|
235
|
+
// (define (square x) (* x x))
|
|
236
|
+
// (list 1 2.5 "hi" #t nil foo-bar)
|
|
237
|
+
// `;
|
|
238
|
+
// const ast = parseSExpr(program);
|
|
239
|
+
// console.log(JSON.stringify(ast, null, 2));
|
|
240
|
+
// console.log(ast.map(printSExpr).join("\n"));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
2
|
+
import { toStringValue } from "./toStringValue"
|
|
3
|
+
|
|
4
|
+
export const parseYesNo = (
|
|
5
|
+
value: PrimitiveSExpr | undefined,
|
|
6
|
+
): boolean | undefined => {
|
|
7
|
+
const str = toStringValue(value)
|
|
8
|
+
if (!str) return undefined
|
|
9
|
+
if (str === "yes" || str === "true") return true
|
|
10
|
+
if (str === "no" || str === "false") return false
|
|
11
|
+
return undefined
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { Stroke } from "../classes/Stroke"
|
|
4
|
+
|
|
5
|
+
export const strokeFromArgs = (
|
|
6
|
+
args: PrimitiveSExpr[],
|
|
7
|
+
): Stroke | undefined => {
|
|
8
|
+
try {
|
|
9
|
+
const parsed = SxClass.parsePrimitiveSexpr(
|
|
10
|
+
["stroke", ...args] as PrimitiveSExpr,
|
|
11
|
+
)
|
|
12
|
+
if (parsed instanceof Stroke) {
|
|
13
|
+
return parsed
|
|
14
|
+
}
|
|
15
|
+
} catch {
|
|
16
|
+
// Ignore parse errors and defer to caller
|
|
17
|
+
}
|
|
18
|
+
return undefined
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
2
|
+
|
|
3
|
+
export const toNumberValue = (
|
|
4
|
+
value: PrimitiveSExpr | undefined,
|
|
5
|
+
): number | undefined => {
|
|
6
|
+
if (value === undefined) return undefined
|
|
7
|
+
if (typeof value === "number") return value
|
|
8
|
+
if (typeof value === "string") {
|
|
9
|
+
const parsed = Number(value)
|
|
10
|
+
return Number.isNaN(parsed) ? undefined : parsed
|
|
11
|
+
}
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
2
|
+
|
|
3
|
+
export const toStringValue = (
|
|
4
|
+
value: PrimitiveSExpr | undefined,
|
|
5
|
+
): string | undefined => {
|
|
6
|
+
if (value === undefined) return undefined
|
|
7
|
+
if (typeof value === "string") return value
|
|
8
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value)
|
|
9
|
+
return undefined
|
|
10
|
+
}
|