kicadts 0.0.2 → 0.0.4

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.
Files changed (195) hide show
  1. package/dist/index.d.ts +4466 -0
  2. package/dist/index.js +14253 -0
  3. package/package.json +5 -2
  4. package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +0 -111
  5. package/.github/workflows/bun-formatcheck.yml +0 -26
  6. package/.github/workflows/bun-pver-release.yml +0 -70
  7. package/.github/workflows/bun-test.yml +0 -32
  8. package/.github/workflows/bun-typecheck.yml +0 -26
  9. package/.vscode/settings.json +0 -16
  10. package/AGENTS.md +0 -31
  11. package/TODO.md +0 -46
  12. package/biome.json +0 -93
  13. package/bunfig.toml +0 -5
  14. package/lib/index.ts +0 -1
  15. package/lib/sexpr/base-classes/SxClass.ts +0 -164
  16. package/lib/sexpr/base-classes/SxPrimitiveBoolean.ts +0 -35
  17. package/lib/sexpr/base-classes/SxPrimitiveNumber.ts +0 -26
  18. package/lib/sexpr/base-classes/SxPrimitiveString.ts +0 -26
  19. package/lib/sexpr/classes/At.ts +0 -53
  20. package/lib/sexpr/classes/Bus.ts +0 -103
  21. package/lib/sexpr/classes/BusEntry.ts +0 -169
  22. package/lib/sexpr/classes/Color.ts +0 -29
  23. package/lib/sexpr/classes/Dnp.ts +0 -8
  24. package/lib/sexpr/classes/EmbeddedFonts.ts +0 -68
  25. package/lib/sexpr/classes/ExcludeFromSim.ts +0 -8
  26. package/lib/sexpr/classes/FieldsAutoplaced.ts +0 -8
  27. package/lib/sexpr/classes/Footprint.ts +0 -849
  28. package/lib/sexpr/classes/FootprintAttr.ts +0 -104
  29. package/lib/sexpr/classes/FootprintAutoplaceCost180.ts +0 -9
  30. package/lib/sexpr/classes/FootprintAutoplaceCost90.ts +0 -9
  31. package/lib/sexpr/classes/FootprintClearance.ts +0 -9
  32. package/lib/sexpr/classes/FootprintDescr.ts +0 -44
  33. package/lib/sexpr/classes/FootprintLocked.ts +0 -32
  34. package/lib/sexpr/classes/FootprintModel.ts +0 -142
  35. package/lib/sexpr/classes/FootprintNetTiePadGroups.ts +0 -52
  36. package/lib/sexpr/classes/FootprintPad.ts +0 -857
  37. package/lib/sexpr/classes/FootprintPath.ts +0 -44
  38. package/lib/sexpr/classes/FootprintPlaced.ts +0 -32
  39. package/lib/sexpr/classes/FootprintPrivateLayers.ts +0 -56
  40. package/lib/sexpr/classes/FootprintSheetfile.ts +0 -44
  41. package/lib/sexpr/classes/FootprintSheetname.ts +0 -44
  42. package/lib/sexpr/classes/FootprintSolderMaskMargin.ts +0 -9
  43. package/lib/sexpr/classes/FootprintSolderPasteMargin.ts +0 -9
  44. package/lib/sexpr/classes/FootprintSolderPasteRatio.ts +0 -9
  45. package/lib/sexpr/classes/FootprintTags.ts +0 -44
  46. package/lib/sexpr/classes/FootprintTedit.ts +0 -21
  47. package/lib/sexpr/classes/FootprintThermalGap.ts +0 -9
  48. package/lib/sexpr/classes/FootprintThermalWidth.ts +0 -9
  49. package/lib/sexpr/classes/FootprintZoneConnect.ts +0 -9
  50. package/lib/sexpr/classes/FpArc.ts +0 -312
  51. package/lib/sexpr/classes/FpCircle.ts +0 -314
  52. package/lib/sexpr/classes/FpLine.ts +0 -316
  53. package/lib/sexpr/classes/FpPoly.ts +0 -286
  54. package/lib/sexpr/classes/FpPolyFill.ts +0 -48
  55. package/lib/sexpr/classes/FpPolyLocked.ts +0 -40
  56. package/lib/sexpr/classes/FpRect.ts +0 -314
  57. package/lib/sexpr/classes/FpText.ts +0 -375
  58. package/lib/sexpr/classes/FpTextBox.ts +0 -450
  59. package/lib/sexpr/classes/GrLine.ts +0 -264
  60. package/lib/sexpr/classes/GrLineAngle.ts +0 -32
  61. package/lib/sexpr/classes/GrLineEnd.ts +0 -61
  62. package/lib/sexpr/classes/GrLineLocked.ts +0 -40
  63. package/lib/sexpr/classes/GrLineStart.ts +0 -61
  64. package/lib/sexpr/classes/GrText.ts +0 -228
  65. package/lib/sexpr/classes/Image.ts +0 -283
  66. package/lib/sexpr/classes/InBom.ts +0 -8
  67. package/lib/sexpr/classes/Junction.ts +0 -166
  68. package/lib/sexpr/classes/KicadPcb.ts +0 -361
  69. package/lib/sexpr/classes/KicadSch.ts +0 -397
  70. package/lib/sexpr/classes/KicadSchGenerator.ts +0 -32
  71. package/lib/sexpr/classes/KicadSchGeneratorVersion.ts +0 -30
  72. package/lib/sexpr/classes/KicadSchVersion.ts +0 -22
  73. package/lib/sexpr/classes/Label.ts +0 -176
  74. package/lib/sexpr/classes/Layer.ts +0 -51
  75. package/lib/sexpr/classes/Layers.ts +0 -47
  76. package/lib/sexpr/classes/LibSymbols.ts +0 -61
  77. package/lib/sexpr/classes/NoConnect.ts +0 -90
  78. package/lib/sexpr/classes/OnBoard.ts +0 -8
  79. package/lib/sexpr/classes/PadChamfer.ts +0 -50
  80. package/lib/sexpr/classes/PadChamferRatio.ts +0 -9
  81. package/lib/sexpr/classes/PadClearance.ts +0 -9
  82. package/lib/sexpr/classes/PadDieLength.ts +0 -9
  83. package/lib/sexpr/classes/PadDrill.ts +0 -145
  84. package/lib/sexpr/classes/PadDrillOffset.ts +0 -54
  85. package/lib/sexpr/classes/PadLayers.ts +0 -71
  86. package/lib/sexpr/classes/PadNet.ts +0 -56
  87. package/lib/sexpr/classes/PadOptions.ts +0 -181
  88. package/lib/sexpr/classes/PadPinFunction.ts +0 -9
  89. package/lib/sexpr/classes/PadPinType.ts +0 -9
  90. package/lib/sexpr/classes/PadPrimitiveGrArc.ts +0 -272
  91. package/lib/sexpr/classes/PadPrimitiveGrCircle.ts +0 -298
  92. package/lib/sexpr/classes/PadPrimitiveGrLine.ts +0 -126
  93. package/lib/sexpr/classes/PadPrimitives.ts +0 -291
  94. package/lib/sexpr/classes/PadRectDelta.ts +0 -57
  95. package/lib/sexpr/classes/PadRoundrectRratio.ts +0 -9
  96. package/lib/sexpr/classes/PadSize.ts +0 -69
  97. package/lib/sexpr/classes/PadSolderMaskMargin.ts +0 -9
  98. package/lib/sexpr/classes/PadSolderPasteMargin.ts +0 -9
  99. package/lib/sexpr/classes/PadSolderPasteMarginRatio.ts +0 -9
  100. package/lib/sexpr/classes/PadTeardrops.ts +0 -210
  101. package/lib/sexpr/classes/PadThermalBridgeAngle.ts +0 -9
  102. package/lib/sexpr/classes/PadThermalGap.ts +0 -9
  103. package/lib/sexpr/classes/PadThermalWidth.ts +0 -9
  104. package/lib/sexpr/classes/PadZoneConnect.ts +0 -9
  105. package/lib/sexpr/classes/Paper.ts +0 -119
  106. package/lib/sexpr/classes/PcbGeneral.ts +0 -82
  107. package/lib/sexpr/classes/PcbGeneralLegacyTeardrops.ts +0 -44
  108. package/lib/sexpr/classes/PcbGeneralThickness.ts +0 -9
  109. package/lib/sexpr/classes/PcbGenerator.ts +0 -16
  110. package/lib/sexpr/classes/PcbGeneratorVersion.ts +0 -16
  111. package/lib/sexpr/classes/PcbLayerDefinition.ts +0 -106
  112. package/lib/sexpr/classes/PcbLayers.ts +0 -34
  113. package/lib/sexpr/classes/PcbNet.ts +0 -56
  114. package/lib/sexpr/classes/PcbVersion.ts +0 -9
  115. package/lib/sexpr/classes/Property.ts +0 -301
  116. package/lib/sexpr/classes/PropertyHide.ts +0 -9
  117. package/lib/sexpr/classes/PropertyUnlocked.ts +0 -9
  118. package/lib/sexpr/classes/Pts.ts +0 -67
  119. package/lib/sexpr/classes/RenderCache.ts +0 -221
  120. package/lib/sexpr/classes/SchematicText.ts +0 -171
  121. package/lib/sexpr/classes/Segment.ts +0 -243
  122. package/lib/sexpr/classes/SegmentEnd.ts +0 -59
  123. package/lib/sexpr/classes/SegmentLocked.ts +0 -33
  124. package/lib/sexpr/classes/SegmentNet.ts +0 -64
  125. package/lib/sexpr/classes/SegmentStart.ts +0 -59
  126. package/lib/sexpr/classes/Setup/PcbPlotParams.ts +0 -689
  127. package/lib/sexpr/classes/Setup/PcbPlotParamsBase.ts +0 -9
  128. package/lib/sexpr/classes/Setup/PcbPlotParamsNumericProperties.ts +0 -105
  129. package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesA.ts +0 -104
  130. package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesB.ts +0 -105
  131. package/lib/sexpr/classes/Setup/Setup.ts +0 -574
  132. package/lib/sexpr/classes/Setup/SetupPropertyTypes.ts +0 -119
  133. package/lib/sexpr/classes/Setup/Stackup.ts +0 -135
  134. package/lib/sexpr/classes/Setup/StackupLayer.ts +0 -233
  135. package/lib/sexpr/classes/Setup/StackupLayerProperties.ts +0 -80
  136. package/lib/sexpr/classes/Setup/StackupProperties.ts +0 -40
  137. package/lib/sexpr/classes/Setup/base.ts +0 -165
  138. package/lib/sexpr/classes/Setup/index.ts +0 -14
  139. package/lib/sexpr/classes/Setup/setupMultiValueProperties.ts +0 -53
  140. package/lib/sexpr/classes/Setup/setupNumericProperties.ts +0 -151
  141. package/lib/sexpr/classes/Setup/setupPropertyHandlers.ts +0 -90
  142. package/lib/sexpr/classes/Setup/setupStringProperties.ts +0 -75
  143. package/lib/sexpr/classes/Sheet.ts +0 -287
  144. package/lib/sexpr/classes/SheetFill.ts +0 -44
  145. package/lib/sexpr/classes/SheetInstances.ts +0 -168
  146. package/lib/sexpr/classes/SheetInstancesRoot.ts +0 -165
  147. package/lib/sexpr/classes/SheetPin.ts +0 -125
  148. package/lib/sexpr/classes/SheetProperty.ts +0 -115
  149. package/lib/sexpr/classes/SheetSize.ts +0 -44
  150. package/lib/sexpr/classes/Stroke.ts +0 -58
  151. package/lib/sexpr/classes/StrokeType.ts +0 -34
  152. package/lib/sexpr/classes/Symbol.ts +0 -1666
  153. package/lib/sexpr/classes/TextEffects.ts +0 -461
  154. package/lib/sexpr/classes/TitleBlock.ts +0 -369
  155. package/lib/sexpr/classes/Unit.ts +0 -28
  156. package/lib/sexpr/classes/Uuid.ts +0 -8
  157. package/lib/sexpr/classes/Via.ts +0 -363
  158. package/lib/sexpr/classes/ViaNet.ts +0 -60
  159. package/lib/sexpr/classes/Width.ts +0 -8
  160. package/lib/sexpr/classes/Wire.ts +0 -111
  161. package/lib/sexpr/classes/Xy.ts +0 -33
  162. package/lib/sexpr/classes/Zone.ts +0 -39
  163. package/lib/sexpr/index.ts +0 -130
  164. package/lib/sexpr/parseKicadSexpr.ts +0 -5
  165. package/lib/sexpr/parseToPrimitiveSExpr.ts +0 -245
  166. package/lib/sexpr/utils/indentLines.ts +0 -3
  167. package/lib/sexpr/utils/parseYesNo.ts +0 -12
  168. package/lib/sexpr/utils/quoteSExprString.ts +0 -8
  169. package/lib/sexpr/utils/strokeFromArgs.ts +0 -18
  170. package/lib/sexpr/utils/toNumberValue.ts +0 -13
  171. package/lib/sexpr/utils/toStringValue.ts +0 -11
  172. package/scripts/download-references.ts +0 -68
  173. package/tests/fixtures/expectEqualPrimitiveSExpr.ts +0 -199
  174. package/tests/fixtures/png-matcher.ts +0 -109
  175. package/tests/fixtures/preload.ts +0 -1
  176. package/tests/sexpr/KicadPcbDemos.test.ts +0 -48
  177. package/tests/sexpr/KicadSchDemos.test.ts +0 -49
  178. package/tests/sexpr/classes/Footprint.test.ts +0 -277
  179. package/tests/sexpr/classes/FootprintPad.test.ts +0 -78
  180. package/tests/sexpr/classes/FpArc.test.ts +0 -45
  181. package/tests/sexpr/classes/FpCircle.test.ts +0 -39
  182. package/tests/sexpr/classes/FpPoly.test.ts +0 -43
  183. package/tests/sexpr/classes/FpRect.test.ts +0 -40
  184. package/tests/sexpr/classes/FpTextBox.test.ts +0 -84
  185. package/tests/sexpr/classes/Image.test.ts +0 -58
  186. package/tests/sexpr/classes/KicadSch.test.ts +0 -95
  187. package/tests/sexpr/classes/Paper.test.ts +0 -30
  188. package/tests/sexpr/classes/Property.test.ts +0 -48
  189. package/tests/sexpr/classes/Setup.test.ts +0 -188
  190. package/tests/sexpr/classes/Sheet.test.ts +0 -107
  191. package/tests/sexpr/classes/Stroke.test.ts +0 -15
  192. package/tests/sexpr/classes/Symbol.test.ts +0 -96
  193. package/tests/sexpr/classes/TextEffects.test.ts +0 -56
  194. package/tests/sexpr/classes/TitleBlock.test.ts +0 -40
  195. package/tsconfig.json +0 -35
@@ -1,199 +0,0 @@
1
- import { expect } from "bun:test"
2
- import type { PrimitiveSExpr } from "lib/sexpr/parseToPrimitiveSExpr"
3
-
4
- interface ExpectEqualPrimitiveSExprOptions {
5
- context?: Record<string, unknown>
6
- path?: string
7
- }
8
-
9
- type CanonicalPrimitiveSExpr =
10
- | string
11
- | number
12
- | boolean
13
- | null
14
- | CanonicalPrimitiveSExpr[]
15
-
16
- const ORDERED_TAGS = new Set(["xy"])
17
-
18
- const canonicalKey = (value: CanonicalPrimitiveSExpr): string =>
19
- JSON.stringify(value)
20
-
21
- const canonicalizePrimitiveSExpr = (
22
- value: PrimitiveSExpr,
23
- ): CanonicalPrimitiveSExpr => {
24
- if (!Array.isArray(value)) {
25
- return value
26
- }
27
-
28
- if (value.length === 0) {
29
- return []
30
- }
31
-
32
- const first = value[0]
33
-
34
- if (typeof first === "string") {
35
- return canonicalizeNode(value as CanonicalPrimitiveSExpr[])
36
- }
37
-
38
- if (Array.isArray(first)) {
39
- const canonicalChildren = value.map((child) =>
40
- canonicalizePrimitiveSExpr(child),
41
- ) as CanonicalPrimitiveSExpr[]
42
-
43
- canonicalChildren.sort((a, b) =>
44
- canonicalKey(a).localeCompare(canonicalKey(b)),
45
- )
46
-
47
- return canonicalChildren
48
- }
49
-
50
- return value.map((child) => canonicalizePrimitiveSExpr(child))
51
- }
52
-
53
- const canonicalizeNode = (
54
- list: CanonicalPrimitiveSExpr[],
55
- ): CanonicalPrimitiveSExpr => {
56
- const [head, ...tail] = list
57
-
58
- if (head === undefined) {
59
- return []
60
- }
61
-
62
- const positional: CanonicalPrimitiveSExpr[] = []
63
- const grouped = new Map<string, CanonicalPrimitiveSExpr[]>()
64
-
65
- for (const element of tail) {
66
- if (Array.isArray(element)) {
67
- const tag = element[0]
68
- if (typeof tag === "string" && !ORDERED_TAGS.has(tag)) {
69
- const canonicalChild = canonicalizePrimitiveSExpr(element)
70
- const bucket = grouped.get(tag)
71
- if (bucket) {
72
- bucket.push(canonicalChild)
73
- } else {
74
- grouped.set(tag, [canonicalChild])
75
- }
76
- continue
77
- }
78
- }
79
-
80
- positional.push(canonicalizePrimitiveSExpr(element))
81
- }
82
-
83
- const groupedValues: CanonicalPrimitiveSExpr[] = []
84
- const sortedTags = [...grouped.keys()].sort()
85
- for (const tag of sortedTags) {
86
- const items = grouped.get(tag)!
87
- items.sort((a, b) => canonicalKey(a).localeCompare(canonicalKey(b)))
88
- groupedValues.push(...items)
89
- }
90
-
91
- return [canonicalizePrimitiveSExpr(head), ...positional, ...groupedValues]
92
- }
93
-
94
- export const expectEqualPrimitiveSExpr = (
95
- actual: PrimitiveSExpr,
96
- expected: PrimitiveSExpr,
97
- options: ExpectEqualPrimitiveSExprOptions = {},
98
- ): void => {
99
- const normalizedActual = canonicalizePrimitiveSExpr(actual)
100
- const normalizedExpected = canonicalizePrimitiveSExpr(expected)
101
-
102
- const rootPath = options.path ?? "sexpr"
103
- const contextEntries = options.context ? Object.entries(options.context) : []
104
-
105
- const formatPath = (segments: readonly string[]): string => segments.join("")
106
-
107
- const buildPayload = (
108
- path: string,
109
- value: unknown,
110
- ): Record<string, unknown> => {
111
- if (contextEntries.length === 0) {
112
- return { path, value }
113
- }
114
-
115
- const payload: Record<string, unknown> = {}
116
- for (const [key, contextValue] of contextEntries) {
117
- payload[key] = contextValue
118
- }
119
- payload.path = path
120
- payload.value = value
121
- return payload
122
- }
123
-
124
- const expectWithPath = (
125
- segments: readonly string[],
126
- actualValue: unknown,
127
- expectedValue: unknown,
128
- ): void => {
129
- const path = formatPath(segments)
130
- expect(buildPayload(path, actualValue)).toEqual(
131
- buildPayload(path, expectedValue),
132
- )
133
- }
134
-
135
- const getNodeToken = (value: CanonicalPrimitiveSExpr): string | undefined => {
136
- if (!Array.isArray(value)) {
137
- return undefined
138
- }
139
-
140
- const [head] = value
141
- return typeof head === "string" ? head : undefined
142
- }
143
-
144
- const describePathSegment = (
145
- child: CanonicalPrimitiveSExpr,
146
- index: number,
147
- ): string => {
148
- const token = getNodeToken(child)
149
- if (token) {
150
- return `[${index}:${token}]`
151
- }
152
- return `[${index}]`
153
- }
154
-
155
- const describeType = (value: CanonicalPrimitiveSExpr): string => {
156
- if (Array.isArray(value)) {
157
- return "array"
158
- }
159
- if (value === null) {
160
- return "null"
161
- }
162
- return typeof value
163
- }
164
-
165
- const compare = (
166
- currentActual: CanonicalPrimitiveSExpr,
167
- currentExpected: CanonicalPrimitiveSExpr,
168
- path: readonly string[],
169
- ): void => {
170
- const actualType = describeType(currentActual)
171
- const expectedType = describeType(currentExpected)
172
-
173
- if (actualType !== expectedType) {
174
- expectWithPath([...path, ".type"], actualType, expectedType)
175
- return
176
- }
177
-
178
- if (Array.isArray(currentActual) && Array.isArray(currentExpected)) {
179
- expectWithPath(
180
- [...path, ".length"],
181
- currentActual.length,
182
- currentExpected.length,
183
- )
184
-
185
- const limit = Math.min(currentActual.length, currentExpected.length)
186
- for (let index = 0; index < limit; index += 1) {
187
- const childActual = currentActual[index]!
188
- const childExpected = currentExpected[index]!
189
- const childSegment = describePathSegment(childActual, index)
190
- compare(childActual, childExpected, [...path, childSegment])
191
- }
192
- return
193
- }
194
-
195
- expectWithPath(path, currentActual, currentExpected)
196
- }
197
-
198
- compare(normalizedActual, normalizedExpected, [rootPath])
199
- }
@@ -1,109 +0,0 @@
1
- import { expect, type MatcherResult } from "bun:test"
2
- import * as fs from "node:fs"
3
- import * as path from "node:path"
4
- import looksSame from "looks-same"
5
-
6
- /**
7
- * Matcher for PNG snapshot testing.
8
- *
9
- * Usage:
10
- * expect(pngBuffer).toMatchPngSnapshot(import.meta.path, "optionalName");
11
- */
12
- async function toMatchPngSnapshot(
13
- // biome-ignore lint/suspicious/noExplicitAny: bun doesn't expose
14
- this: any,
15
- receivedMaybePromise: Buffer | Uint8Array | Promise<Buffer | Uint8Array>,
16
- testPathOriginal: string,
17
- pngName?: string,
18
- ): Promise<MatcherResult> {
19
- const received = await receivedMaybePromise
20
- const testPath = testPathOriginal
21
- .replace(/\.test\.tsx?$/, "")
22
- .replace(/\.test\.ts$/, "")
23
- const snapshotDir = path.join(path.dirname(testPath), "__snapshots__")
24
- const snapshotName = pngName
25
- ? `${pngName}.snap.png`
26
- : `${path.basename(testPath)}.snap.png`
27
- const filePath = path.join(snapshotDir, snapshotName)
28
-
29
- if (!fs.existsSync(snapshotDir)) {
30
- fs.mkdirSync(snapshotDir, { recursive: true })
31
- }
32
-
33
- const updateSnapshot =
34
- process.argv.includes("--update-snapshots") ||
35
- process.argv.includes("-u") ||
36
- Boolean(process.env["BUN_UPDATE_SNAPSHOTS"])
37
- const forceUpdate = Boolean(process.env["FORCE_BUN_UPDATE_SNAPSHOTS"])
38
-
39
- const fileExists = fs.existsSync(filePath)
40
-
41
- if (!fileExists) {
42
- console.log("Writing PNG snapshot to", filePath)
43
- fs.writeFileSync(filePath, received)
44
- return {
45
- message: () => `PNG snapshot created at ${filePath}`,
46
- pass: true,
47
- }
48
- }
49
-
50
- const existingSnapshot = fs.readFileSync(filePath)
51
-
52
- const result: any = await looksSame(
53
- Buffer.from(received),
54
- Buffer.from(existingSnapshot),
55
- {
56
- strict: false,
57
- tolerance: 2,
58
- },
59
- )
60
-
61
- if (updateSnapshot) {
62
- if (!forceUpdate && result.equal) {
63
- return {
64
- message: () => "PNG snapshot matches",
65
- pass: true,
66
- }
67
- }
68
- console.log("Updating PNG snapshot at", filePath)
69
- fs.writeFileSync(filePath, received)
70
- return {
71
- message: () => `PNG snapshot updated at ${filePath}`,
72
- pass: true,
73
- }
74
- }
75
-
76
- if (result.equal) {
77
- return {
78
- message: () => "PNG snapshot matches",
79
- pass: true,
80
- }
81
- }
82
-
83
- const diffPath = filePath.replace(/\.snap\.png$/, ".diff.png")
84
- await looksSame.createDiff({
85
- reference: Buffer.from(existingSnapshot),
86
- current: Buffer.from(received),
87
- diff: diffPath,
88
- highlightColor: "#ff00ff",
89
- })
90
-
91
- return {
92
- message: () => `PNG snapshot does not match. Diff saved at ${diffPath}`,
93
- pass: false,
94
- }
95
- }
96
-
97
- // Register the matcher globally for Bun's expect
98
- expect.extend({
99
- toMatchPngSnapshot: toMatchPngSnapshot as any,
100
- })
101
-
102
- declare module "bun:test" {
103
- interface Matchers<T = unknown> {
104
- toMatchPngSnapshot(
105
- testPath: string,
106
- pngName?: string,
107
- ): Promise<MatcherResult>
108
- }
109
- }
@@ -1 +0,0 @@
1
- import "./png-matcher"
@@ -1,48 +0,0 @@
1
- import { expect, test } from "bun:test"
2
- import { KicadPcb, SxClass } from "lib/sexpr"
3
- import { parseToPrimitiveSExpr } from "lib/sexpr/parseToPrimitiveSExpr"
4
- import type { PrimitiveSExpr } from "lib/sexpr/parseToPrimitiveSExpr"
5
-
6
- import { expectEqualPrimitiveSExpr } from "../fixtures/expectEqualPrimitiveSExpr"
7
-
8
- const numericLike = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/
9
-
10
- const normalizePrimitive = (value: PrimitiveSExpr): PrimitiveSExpr => {
11
- if (Array.isArray(value)) {
12
- return value.map((item) => normalizePrimitive(item))
13
- }
14
- if (typeof value === "string" && numericLike.test(value)) {
15
- const parsed = Number(value)
16
- if (!Number.isNaN(parsed)) {
17
- return parsed
18
- }
19
- }
20
- return value
21
- }
22
-
23
- const demoPcbPaths = [
24
- "kicad-demos/demos/flat_hierarchy/flat_hierarchy.kicad_pcb",
25
- "kicad-demos/demos/custom_pads_test/custom_pads_test.kicad_pcb",
26
- ]
27
-
28
- test("kicad_pcb round-trips selected KiCad demo boards", async () => {
29
- for (const path of demoPcbPaths) {
30
- const original = await Bun.file(path).text()
31
- const classes = SxClass.parse(original)
32
-
33
- expect(classes).toHaveLength(1)
34
- expect(classes[0]).toBeInstanceOf(KicadPcb)
35
-
36
- const roundTrip = classes.map((instance) => instance.getString()).join("\n")
37
-
38
- const originalPrimitive = parseToPrimitiveSExpr(original).map((form) =>
39
- normalizePrimitive(form),
40
- )
41
-
42
- const roundTripPrimitive = parseToPrimitiveSExpr(roundTrip).map((form) =>
43
- normalizePrimitive(form),
44
- )
45
-
46
- expectEqualPrimitiveSExpr(roundTripPrimitive, originalPrimitive, { path })
47
- }
48
- })
@@ -1,49 +0,0 @@
1
- import { expect, test } from "bun:test"
2
- import { KicadSch, SxClass } from "lib/sexpr"
3
- import { parseToPrimitiveSExpr } from "lib/sexpr/parseToPrimitiveSExpr"
4
- import type { PrimitiveSExpr } from "lib/sexpr/parseToPrimitiveSExpr"
5
-
6
- import { expectEqualPrimitiveSExpr } from "../fixtures/expectEqualPrimitiveSExpr"
7
-
8
- const numericLike = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/
9
-
10
- const normalizePrimitive = (value: PrimitiveSExpr): PrimitiveSExpr => {
11
- if (Array.isArray(value)) {
12
- return value.map((item) => normalizePrimitive(item))
13
- }
14
- if (typeof value === "string" && numericLike.test(value)) {
15
- const parsed = Number(value)
16
- if (!Number.isNaN(parsed)) {
17
- return parsed
18
- }
19
- }
20
- return value
21
- }
22
-
23
- const demoSchematics = [
24
- "kicad-demos/demos/simulation/rectifier/rectifier.kicad_sch",
25
- "kicad-demos/demos/simulation/up-down-counter/up-down-c.kicad_sch",
26
- "kicad-demos/demos/simulation/analog-multiplier/a-multi.kicad_sch",
27
- ]
28
-
29
- test("kicad_sch round-trips kicad demo schematics", async () => {
30
- for (const path of demoSchematics) {
31
- const original = await Bun.file(path).text()
32
- const classes = SxClass.parse(original)
33
-
34
- expect(classes).toHaveLength(1)
35
- expect(classes[0]).toBeInstanceOf(KicadSch)
36
-
37
- const roundTrip = classes.map((instance) => instance.getString()).join("\n")
38
-
39
- const originalPrimitive = parseToPrimitiveSExpr(original).map((form) =>
40
- normalizePrimitive(form),
41
- )
42
-
43
- const roundTripPrimitive = parseToPrimitiveSExpr(roundTrip).map((form) =>
44
- normalizePrimitive(form),
45
- )
46
-
47
- expectEqualPrimitiveSExpr(roundTripPrimitive, originalPrimitive, { path })
48
- }
49
- })
@@ -1,277 +0,0 @@
1
- import {
2
- At,
3
- Footprint,
4
- FootprintAttr,
5
- FootprintPrivateLayers,
6
- FootprintSolderMaskMargin,
7
- FpArc,
8
- FpCircle,
9
- FpPoly,
10
- FpRect,
11
- FpText,
12
- FpTextBox,
13
- Layer,
14
- SxClass,
15
- } from "lib/sexpr"
16
- import { expect, test } from "bun:test"
17
-
18
- test("Footprint", () => {
19
- const [fp] = SxClass.parse(`
20
- (footprint "Resistor_SMD:R_0603"
21
- locked
22
- placed
23
- (layer F.Cu)
24
- (tedit 5E4C0E65)
25
- (uuid 12345678-1234-1234-1234-123456789abc)
26
- (at 10.16 5.08 90)
27
- (descr "0603 chip resistor")
28
- (tags "resistor smd")
29
- (property "Sheetfile" "example.kicad_sch")
30
- (path "/abcdef01")
31
- (autoplace_cost90 4)
32
- (solder_mask_margin 0.05)
33
- (attr smd exclude_from_bom)
34
- (private_layers F.CrtYd B.CrtYd)
35
- (net_tie_pad_groups "A,B" "C,D")
36
- (fp_text reference R1 (at 0 0) (layer F.SilkS)
37
- (effects (font (size 1 1) (thickness 0.15)))
38
- )
39
- (fp_text_box locked "Label"
40
- (start -1 -1)
41
- (end 1 1)
42
- (pts (xy -1 -1) (xy 1 -1) (xy 1 1) (xy -1 1))
43
- (layer F.SilkS)
44
- (effects (font (size 1.2 1.2) (thickness 0.18)))
45
- (uuid 99999999-aaaa-bbbb-cccc-dddddddddddd)
46
- )
47
- (fp_rect
48
- (start -2 -2)
49
- (end 2 2)
50
- (layer F.Cu)
51
- (stroke (width 0.1) (type solid) (color 0 0 0 1))
52
- (uuid 22222222-3333-4444-5555-666666666666)
53
- )
54
- (fp_circle locked
55
- (center 0 0)
56
- (end 1 0)
57
- (layer F.SilkS)
58
- (stroke (width 0.05) (type dash) (color 0.5 0.5 0.5 1))
59
- (uuid 77777777-8888-9999-aaaa-bbbbbbbbbbbb)
60
- )
61
- (fp_arc
62
- (start -3 0)
63
- (mid 0 1)
64
- (end 3 0)
65
- (layer F.SilkS)
66
- (stroke (width 0.08) (type solid) (color 0 0 0 1))
67
- (uuid 44444444-5555-6666-7777-888888888888)
68
- )
69
- (fp_poly
70
- (pts (xy 0 0) (xy 2 0) (xy 2 2) (xy 0 2))
71
- (layer F.Mask)
72
- (stroke (width 0.05) (type solid) (color 0 0 0 1))
73
- (fill yes)
74
- (uuid 99999999-aaaa-bbbb-cccc-eeeeeeeeeeee)
75
- )
76
- (pad "1" smd roundrect
77
- (at 0 0 90)
78
- (size 1.2 0.6)
79
- (layers F.Cu F.Paste F.Mask)
80
- (roundrect_rratio 0.25)
81
- (solder_mask_margin 0.05)
82
- (clearance 0.1)
83
- (net 1 "GND")
84
- (pinfunction "GND")
85
- (pintype "passive")
86
- (uuid 12121212-3434-5656-7878-909090909090)
87
- )
88
- )
89
- `)
90
-
91
- expect(fp).toBeInstanceOf(Footprint)
92
- const footprint = fp as Footprint
93
-
94
- expect(footprint.libraryLink).toBe("Resistor_SMD:R_0603")
95
- expect(footprint.locked).toBe(true)
96
- expect(footprint.placed).toBe(true)
97
- expect(footprint.layer).toBeInstanceOf(Layer)
98
- expect(footprint.tedit?.value).toBe("5E4C0E65")
99
- expect(footprint.uuid?.value).toBe("12345678-1234-1234-1234-123456789abc")
100
- const position = footprint.position
101
- expect(position).toBeDefined()
102
- expect(position?.x).toBe(10.16)
103
- expect(position?.y).toBe(5.08)
104
- expect(position).toBeInstanceOf(At)
105
- if (position instanceof At) {
106
- expect(position.angle).toBe(90)
107
- }
108
- expect(footprint.descr?.value).toBe("0603 chip resistor")
109
- expect(footprint.tags?.value).toBe("resistor smd")
110
- expect(footprint.properties[0]?.key).toBe("Sheetfile")
111
- expect(footprint.properties[0]?.value).toBe("example.kicad_sch")
112
- expect(footprint.path?.value).toBe("/abcdef01")
113
- expect(footprint.autoplaceCost90?.value).toBe(4)
114
- expect(footprint.solderMaskMargin?.value).toBe(0.05)
115
- expect(footprint.attr).toBeInstanceOf(FootprintAttr)
116
- expect(footprint.attr?.type).toBe("smd")
117
- expect(footprint.attr?.excludeFromBom).toBe(true)
118
- expect(footprint.privateLayers).toBeInstanceOf(FootprintPrivateLayers)
119
- expect(footprint.privateLayers?.layers).toEqual(["F.CrtYd", "B.CrtYd"])
120
- expect(footprint.netTiePadGroups?.groups).toEqual(["A,B", "C,D"])
121
- expect(footprint.fpTexts.length).toBe(1)
122
- const text = footprint.fpTexts[0] as FpText
123
- expect(text.type).toBe("reference")
124
- expect(text.text).toBe("R1")
125
- expect(text.layer?.names).toEqual(["F.SilkS"])
126
- expect(text.effects).toBeDefined()
127
- expect(footprint.fpTextBoxes.length).toBe(1)
128
- const textBox = footprint.fpTextBoxes[0] as FpTextBox
129
- expect(textBox.locked).toBe(true)
130
- expect(textBox.text).toBe("Label")
131
- expect(textBox.start?.x).toBe(-1)
132
- expect(textBox.end?.y).toBe(1)
133
- expect(footprint.fpRects.length).toBe(1)
134
- const rect = footprint.fpRects[0] as FpRect
135
- expect(rect.start?.x).toBe(-2)
136
- expect(rect.end?.y).toBe(2)
137
- expect(rect.layer?.names).toEqual(["F.Cu"])
138
- expect(rect.stroke).toBeDefined()
139
- expect(footprint.fpCircles.length).toBe(1)
140
- const circle = footprint.fpCircles[0] as FpCircle
141
- expect(circle.center?.x).toBe(0)
142
- expect(circle.end?.x).toBe(1)
143
- expect(footprint.fpArcs.length).toBe(1)
144
- const arc = footprint.fpArcs[0] as FpArc
145
- expect(arc.start?.x).toBe(-3)
146
- expect(arc.mid?.y).toBe(1)
147
- expect(arc.end?.x).toBe(3)
148
- expect(footprint.fpPolys.length).toBe(1)
149
- const poly = footprint.fpPolys[0] as FpPoly
150
- expect(poly.points?.points.length).toBe(4)
151
- expect(poly.fill?.filled).toBe(true)
152
- expect(footprint.fpPads.length).toBe(1)
153
- const pad = footprint.fpPads[0]!
154
- expect(pad.number).toBe("1")
155
- expect(pad.padType).toBe("smd")
156
- expect(pad.layers?.layers).toEqual(["F.Cu", "F.Paste", "F.Mask"])
157
- expect(pad.net?.name).toBe("GND")
158
-
159
- footprint.locked = false
160
- footprint.placed = false
161
- footprint.solderMaskMargin = new FootprintSolderMaskMargin(0.09)
162
-
163
- expect(footprint.getString()).toMatchInlineSnapshot(`
164
- "(footprint
165
- \"Resistor_SMD:R_0603\"
166
- (layer F.Cu)
167
- (tedit 5E4C0E65)
168
- (uuid 12345678-1234-1234-1234-123456789abc)
169
- (at 10.16 5.08 90)
170
- (descr \"0603 chip resistor\")
171
- (tags \"resistor smd\")
172
- (path \"/abcdef01\")
173
- (autoplace_cost90 4)
174
- (solder_mask_margin 0.09)
175
- (attr smd exclude_from_bom)
176
- (private_layers F.CrtYd B.CrtYd)
177
- (net_tie_pad_groups \"A,B\" \"C,D\")
178
- (property \"Sheetfile\" \"example.kicad_sch\"
179
- )
180
- (fp_text
181
- reference
182
- \"R1\"
183
- (at 0 0)
184
- (layer F.SilkS)
185
- (effects
186
- (font
187
- (size 1 1)
188
- (thickness 0.15)
189
- )
190
- )
191
- )
192
- (fp_text_box
193
- locked
194
- \"Label\"
195
- (start -1 -1)
196
- (end 1 1)
197
- (pts
198
- (xy -1 -1)
199
- (xy 1 -1)
200
- (xy 1 1)
201
- (xy -1 1)
202
- )
203
- (layer F.SilkS)
204
- (effects
205
- (font
206
- (size 1.2 1.2)
207
- (thickness 0.18)
208
- )
209
- )
210
- (uuid 99999999-aaaa-bbbb-cccc-dddddddddddd)
211
- )
212
- (fp_rect
213
- (start -2 -2)
214
- (end 2 2)
215
- (layer F.Cu)
216
- (stroke
217
- (width 0.1)
218
- (type solid)
219
- (color 0 0 0 1)
220
- )
221
- (uuid 22222222-3333-4444-5555-666666666666)
222
- )
223
- (fp_circle
224
- (center 0 0)
225
- (end 1 0)
226
- (layer F.SilkS)
227
- (stroke
228
- (width 0.05)
229
- (type dash)
230
- (color 0.5 0.5 0.5 1)
231
- )
232
- (uuid 77777777-8888-9999-aaaa-bbbbbbbbbbbb)
233
- locked
234
- )
235
- (fp_arc
236
- (start -3 0)
237
- (mid 0 1)
238
- (end 3 0)
239
- (layer F.SilkS)
240
- (stroke
241
- (width 0.08)
242
- (type solid)
243
- (color 0 0 0 1)
244
- )
245
- (uuid 44444444-5555-6666-7777-888888888888)
246
- )
247
- (fp_poly
248
- (pts
249
- (xy 0 0)
250
- (xy 2 0)
251
- (xy 2 2)
252
- (xy 0 2)
253
- )
254
- (layer F.Mask)
255
- (stroke
256
- (width 0.05)
257
- (type solid)
258
- (color 0 0 0 1)
259
- )
260
- (fill yes)
261
- (uuid 99999999-aaaa-bbbb-cccc-eeeeeeeeeeee)
262
- )
263
- (pad \"1\" smd roundrect
264
- (at 0 0 90)
265
- (size 1.2 0.6)
266
- (layers F.Cu F.Paste F.Mask)
267
- (roundrect_rratio 0.25)
268
- (net 1 \"GND\")
269
- (pinfunction GND)
270
- (pintype passive)
271
- (solder_mask_margin 0.05)
272
- (clearance 0.1)
273
- (uuid 12121212-3434-5656-7878-909090909090)
274
- )
275
- )"
276
- `)
277
- })