From 1ca1a9821df5a178d03d0d0ff6526dcf8f6aa517 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 10:29:34 -0700 Subject: [PATCH 1/9] refactor script for better types --- package.json | 1 + scripts/refactor-template.md | 67 ++++++++++++++++++++++++++++++++++++ scripts/refactor.ts | 28 +++++++++++++++ src/common/index.ts | 1 + src/pcb/pcb_board.ts | 30 +++++++++++++--- 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 scripts/refactor-template.md create mode 100644 scripts/refactor.ts diff --git a/package.json b/package.json index caba51e..b510d7d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "license": "ISC", "devDependencies": { "@biomejs/biome": "^1.9.2", + "@anthropic-ai/sdk": "^0.27.3", "@types/convert-units": "^2.3.9", "esbuild": "^0.20.2", "ts-expect": "^1.3.0", diff --git a/scripts/refactor-template.md b/scripts/refactor-template.md new file mode 100644 index 0000000..52286d6 --- /dev/null +++ b/scripts/refactor-template.md @@ -0,0 +1,67 @@ +Refactor the "${PATHNAME}" file to reflect the new style of defining elements +for the Circuit Json specification. Follow the new rules. Please output the +entire new file in a code block. + +Some of the new rules: + +- Export a snake_case zod object from the file +- Export a type or interface in `PascalCase` (with abbreviations considered single words) +- Use the `expectTypesMatch` function to ensure the zod type and interface are the same +- Mark old exports as deprecated +- Prefer absolute imports from "src/" +- Use `getZodPrefixedIdWithDefault` to generate a unique id for the primary id of the object +- The main interface should have a `/**` multi-line comment describing the object + +```ts +// EXAMPLE FILE OF NEW CIRCUIT SPECIFICATION +import { z } from "zod" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { rotation, length, type Rotation, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" + +export const pcb_component = z + .object({ + type: z.literal("pcb_component"), + pcb_component_id: getZodPrefixedIdWithDefault("pcb_component"), + source_component_id: z.string(), + center: point, + layer: layer_ref, + rotation: rotation, + width: length, + height: length, + }) + .describe("Defines a component on the PCB") + +export type PCBComponentInput = z.input +type InferredPCBComponent = z.infer + +/** + * Defines a component on the PCB + */ +export interface PcbComponent { + type: "pcb_component" + pcb_component_id: string + source_component_id: string + center: Point + layer: LayerRef + rotation: Rotation + width: Length + height: Length +} + +/** + * @deprecated use PcbComponent + */ +export type PCBComponent = PcbComponent + +expectTypesMatch(true) +``` + +Here is the file to refactor: + +## ${PATHNAME} + +```ts +${FILECONTENTS} +``` diff --git a/scripts/refactor.ts b/scripts/refactor.ts new file mode 100644 index 0000000..8dde538 --- /dev/null +++ b/scripts/refactor.ts @@ -0,0 +1,28 @@ +import Anthropic from "@anthropic-ai/sdk" +// @ts-ignore +import refactorTemplate from "./refactor-template.md" with { type: "text" } +import fs from "node:fs" + +const anthropic = new Anthropic() + +const filePath = "./src/pcb/pcb_board.ts" +const fileContents = fs.readFileSync(filePath, "utf8") + +const msg = await anthropic.messages.create({ + model: "claude-3-sonnet-20240229", + max_tokens: 4000, + messages: [ + { + role: "user", + content: `${refactorTemplate.replace(/\$\{PATHNAME\}/g, filePath).replace(/\$\{FILECONTENTS\}/g, fileContents)}`, + }, + ], +}) + +const resText: string = (msg as any).content[0].text + .split("```")[1] + .replace(/^ts\n/, "") + +// Replace the file +console.log(`Replacing ${filePath} with ai-refactored version`) +fs.writeFileSync(filePath, resText) diff --git a/src/common/index.ts b/src/common/index.ts index 1257025..46bdfc1 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,3 +1,4 @@ export * from "./point" export * from "./point3" export * from "./size" +export * from "./getZodPrefixedIdWithDefault" diff --git a/src/pcb/pcb_board.ts b/src/pcb/pcb_board.ts index 768e26b..3b024a5 100644 --- a/src/pcb/pcb_board.ts +++ b/src/pcb/pcb_board.ts @@ -1,11 +1,12 @@ import { z } from "zod" -import { length } from "../units" -import { point } from "../common" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_board = z .object({ type: z.literal("pcb_board"), - pcb_board_id: z.string().default("pcb_board_0").optional(), + pcb_board_id: getZodPrefixedIdWithDefault("pcb_board"), width: length, height: length, center: point, @@ -13,5 +14,24 @@ export const pcb_board = z }) .describe("Defines the board outline of the PCB") -export type PCBBoardInput = z.input -export type PCBBoard = z.infer +/** + * Defines the board outline of the PCB + */ +export interface PcbBoard { + type: "pcb_board" + pcb_board_id: string + width: Length + height: Length + center: Point + outline?: Point[] +} + +export type PcbBoardInput = z.input +type InferredPcbBoard = z.infer + +/** + * @deprecated use PcbBoard + */ +export type PCBBoard = PcbBoard + +expectTypesMatch(true) From 53d5fda24c784de45d8fa731c5c710a2d943d56b Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 10:27:10 -0700 Subject: [PATCH 2/9] refactor all pcb elements --- scripts/refactor.ts | 67 +++++++++++---- src/pcb/pcb_component.ts | 18 ++-- src/pcb/pcb_fabrication_note_path.ts | 35 ++++++-- src/pcb/pcb_fabrication_note_text.ts | 36 ++++++-- src/pcb/pcb_hole.ts | 58 ++++++++----- src/pcb/pcb_keepout.ts | 70 +++++++++++----- src/pcb/pcb_placement_error.ts | 27 ++++-- src/pcb/pcb_plated_hole.ts | 84 +++++++++++++------ src/pcb/pcb_port.ts | 36 ++++++-- src/pcb/pcb_port_not_matched_error.ts | 32 +++++-- src/pcb/pcb_silkscreen_circle.ts | 34 ++++++-- src/pcb/pcb_silkscreen_line.ts | 32 ++++++- src/pcb/pcb_silkscreen_oval.ts | 31 +++++-- src/pcb/pcb_silkscreen_path.ts | 30 +++++-- src/pcb/pcb_silkscreen_pill.ts | 37 +++++++-- src/pcb/pcb_silkscreen_rect.ts | 37 +++++++-- src/pcb/pcb_silkscreen_text.ts | 34 ++++++-- src/pcb/pcb_smtpad.ts | 87 ++++++++++++------- src/pcb/pcb_text.ts | 42 ++++++++-- src/pcb/pcb_trace.ts | 115 ++++++++++++++++++-------- src/pcb/pcb_trace_error.ts | 33 ++++++-- src/pcb/pcb_trace_hint.ts | 26 +++++- src/pcb/pcb_via.ts | 34 +++++++- 23 files changed, 784 insertions(+), 251 deletions(-) diff --git a/scripts/refactor.ts b/scripts/refactor.ts index 8dde538..c3f76c9 100644 --- a/scripts/refactor.ts +++ b/scripts/refactor.ts @@ -5,24 +5,55 @@ import fs from "node:fs" const anthropic = new Anthropic() -const filePath = "./src/pcb/pcb_board.ts" -const fileContents = fs.readFileSync(filePath, "utf8") +const filePaths = [ + "./src/pcb/pcb_fabrication_note_path.ts", + "./src/pcb/pcb_component.ts", + "./src/pcb/pcb_port_not_matched_error.ts", + "./src/pcb/pcb_silkscreen_text.ts", + "./src/pcb/pcb_trace_error.ts", + "./src/pcb/pcb_silkscreen_pill.ts", + "./src/pcb/pcb_plated_hole.ts", + "./src/pcb/pcb_fabrication_note_text.ts", + "./src/pcb/pcb_silkscreen_circle.ts", + "./src/pcb/pcb_silkscreen_path.ts", + "./src/pcb/pcb_text.ts", + "./src/pcb/pcb_keepout.ts", + "./src/pcb/pcb_via.ts", + // "./src/pcb/properties/supplier_name.ts", + // "./src/pcb/properties/pcb_route_hints.ts", + // "./src/pcb/properties/layer_ref.ts", + // "./src/pcb/properties/route_hint_point.ts", + "./src/pcb/pcb_silkscreen_oval.ts", + "./src/pcb/pcb_placement_error.ts", + "./src/pcb/pcb_port.ts", + "./src/pcb/pcb_silkscreen_rect.ts", + "./src/pcb/pcb_trace_hint.ts", + "./src/pcb/pcb_smtpad.ts", + "./src/pcb/pcb_silkscreen_line.ts", + "./src/pcb/pcb_hole.ts", + "./src/pcb/pcb_trace.ts", + // "./src/pcb/pcb_board.ts", +] -const msg = await anthropic.messages.create({ - model: "claude-3-sonnet-20240229", - max_tokens: 4000, - messages: [ - { - role: "user", - content: `${refactorTemplate.replace(/\$\{PATHNAME\}/g, filePath).replace(/\$\{FILECONTENTS\}/g, fileContents)}`, - }, - ], -}) +for (const filePath of filePaths) { + const fileContents = fs.readFileSync(filePath, "utf8") -const resText: string = (msg as any).content[0].text - .split("```")[1] - .replace(/^ts\n/, "") + const msg = await anthropic.messages.create({ + model: "claude-3-sonnet-20240229", + max_tokens: 4000, + messages: [ + { + role: "user", + content: `${refactorTemplate.replace(/\$\{PATHNAME\}/g, filePath).replace(/\$\{FILECONTENTS\}/g, fileContents)}`, + }, + ], + }) -// Replace the file -console.log(`Replacing ${filePath} with ai-refactored version`) -fs.writeFileSync(filePath, resText) + const resText: string = (msg as any).content[0].text + .split("```")[1] + .replace(/^ts\n/, "") + + // Replace the file + console.log(`Replacing ${filePath} with ai-refactored version`) + fs.writeFileSync(filePath, resText) +} diff --git a/src/pcb/pcb_component.ts b/src/pcb/pcb_component.ts index 1fa1766..fac86d2 100644 --- a/src/pcb/pcb_component.ts +++ b/src/pcb/pcb_component.ts @@ -1,11 +1,10 @@ import { z } from "zod" -import { point, type Point } from "../common" -import { layer_ref, type LayerRef } from "./properties/layer_ref" -import { rotation, length, type Rotation, type Length } from "../units" -import { getZodPrefixedIdWithDefault } from "src/common/getZodPrefixedIdWithDefault" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { rotation, length, type Rotation, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_component = z +export const pcb_component_zod = z .object({ type: z.literal("pcb_component"), pcb_component_id: getZodPrefixedIdWithDefault("pcb_component"), @@ -18,9 +17,12 @@ export const pcb_component = z }) .describe("Defines a component on the PCB") -export type PCBComponentInput = z.input -type InferredPCBComponent = z.infer +export type PcbComponentInput = z.input +type InferredPcbComponent = z.infer +/** + * Defines a component on the PCB + */ export interface PcbComponent { type: "pcb_component" pcb_component_id: string @@ -37,4 +39,4 @@ export interface PcbComponent { */ export type PCBComponent = PcbComponent -expectTypesMatch(true) +expectTypesMatch(true) diff --git a/src/pcb/pcb_fabrication_note_path.ts b/src/pcb/pcb_fabrication_note_path.ts index a1f657c..ceafb88 100644 --- a/src/pcb/pcb_fabrication_note_path.ts +++ b/src/pcb/pcb_fabrication_note_path.ts @@ -1,8 +1,9 @@ import { z } from "zod" -import { getZodPrefixedIdWithDefault } from "src/common/getZodPrefixedIdWithDefault" -import { visible_layer } from "./properties/layer_ref" -import { point } from "src/common" -import { length } from "src/units" +import { getZodPrefixedIdWithDefault } from "src/common" +import { visible_layer, type LayerRef } from "src/properties/layer_ref" +import { point, type Point } from "src/common" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_fabrication_note_path = z .object({ @@ -20,7 +21,25 @@ export const pcb_fabrication_note_path = z "Defines a fabrication path on the PCB for fabricators or assemblers", ) -export type PcbFabricationNotePath = z.infer -export type PcbFabricationNotePathInput = z.input< - typeof pcb_fabrication_note_path -> +export type PcbFabricationNotePathInput = z.input +type InferredPcbFabricationNotePath = z.infer + +/** + * Defines a fabrication path on the PCB for fabricators or assemblers + */ +export interface PcbFabricationNotePath { + type: "pcb_fabrication_note_path" + pcb_fabrication_note_path_id: string + pcb_component_id: string + layer: LayerRef + route: Point[] + stroke_width: Length + color?: string +} + +/** + * @deprecated use PcbFabricationNotePath + */ +export type PCBFabricationNotePath = PcbFabricationNotePath + +expectTypesMatch(true) diff --git a/src/pcb/pcb_fabrication_note_text.ts b/src/pcb/pcb_fabrication_note_text.ts index acf1e08..60e48aa 100644 --- a/src/pcb/pcb_fabrication_note_text.ts +++ b/src/pcb/pcb_fabrication_note_text.ts @@ -1,8 +1,9 @@ import { z } from "zod" -import { visible_layer } from "./properties/layer_ref" -import { point } from "src/common" -import { distance } from "src/units" +import { point, type Point } from "src/common" +import { distance, type Length } from "src/units" +import { visible_layer, type LayerRef } from "src/properties/layer_ref" import { getZodPrefixedIdWithDefault } from "src/common/getZodPrefixedIdWithDefault" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_fabrication_note_text = z .object({ @@ -25,7 +26,28 @@ export const pcb_fabrication_note_text = z "Defines a fabrication note in text on the PCB, useful for leaving notes for assemblers or fabricators", ) -export type PcbFabricationNoteText = z.infer -export type PcbFabricationNoteTextInput = z.input< - typeof pcb_fabrication_note_text -> +export type PcbFabricationNoteTextInput = z.input +type InferredPcbFabricationNoteText = z.infer + +/** + * Defines a fabrication note in text on the PCB, useful for leaving notes for assemblers or fabricators + */ +export interface PcbFabricationNoteText { + type: "pcb_fabrication_note_text" + pcb_fabrication_note_text_id: string + font: "tscircuit2024" + font_size: Length + pcb_component_id: string + text: string + layer: LayerRef + anchor_position: Point + anchor_alignment: "center" | "top_left" | "top_right" | "bottom_left" | "bottom_right" + color?: string +} + +/** + * @deprecated use PcbFabricationNoteText + */ +export type PCBFabricationNoteText = PcbFabricationNoteText + +expectTypesMatch(true) diff --git a/src/pcb/pcb_hole.ts b/src/pcb/pcb_hole.ts index 763e36a..23fc325 100644 --- a/src/pcb/pcb_hole.ts +++ b/src/pcb/pcb_hole.ts @@ -1,9 +1,10 @@ import { z } from "zod" -import { distance } from "../units" +import { distance, type Distance } from "src/units" +import { getZodPrefixedIdWithDefault } from "src/utils/get-zod-prefixed-id-with-default" +import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_hole = z - .object({ - pcb_hole_id: z.string(), +export const pcb_hole = z.union([ + z.object({ type: z.literal("pcb_hole"), hole_shape: z .enum(["circle", "square", "round"]) @@ -15,19 +16,38 @@ export const pcb_hole = z hole_diameter: z.number(), x: distance, y: distance, - }) - .or( - z.object({ - pcb_hole_id: z.string(), - type: z.literal("pcb_hole"), - hole_shape: z.literal("oval"), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - }), - ) - .describe("Defines a hole on the PCB") + }), + z.object({ + type: z.literal("pcb_hole"), + pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), + hole_shape: z.literal("oval"), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + }), +]) + +export type PcbHoleInput = z.input +type InferredPcbHole = z.infer + +/** + * Defines a hole on the PCB + */ +export interface PcbHole { + type: "pcb_hole" + pcb_hole_id: string + hole_shape: "round" | "square" | "oval" + hole_diameter?: number + hole_width?: number + hole_height?: number + x: Distance + y: Distance +} + +/** + * @deprecated use PcbHole + */ +export type PCBHole = PcbHole -export type PCBHoleInput = z.input -export type PCBHole = z.infer +expectTypesMatch(true) diff --git a/src/pcb/pcb_keepout.ts b/src/pcb/pcb_keepout.ts index 5228276..eda9dc9 100644 --- a/src/pcb/pcb_keepout.ts +++ b/src/pcb/pcb_keepout.ts @@ -1,29 +1,61 @@ import { z } from "zod" -import { point } from "../common" -import { distance } from "../units" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { distance, type Distance } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_keepout = z - .object({ +export const pcb_keepout = z.union([ + z.object({ type: z.literal("pcb_keepout"), shape: z.literal("rect"), + pcb_keepout_id: getZodPrefixedIdWithDefault("pcb_keepout"), center: point, width: distance, height: distance, - pcb_keepout_id: z.string(), layers: z.array(z.string()), // Specify layers where the keepout applies description: z.string().optional(), // Optional description of the keepout - }) - .or( - z.object({ - type: z.literal("pcb_keepout"), - shape: z.literal("circle"), - center: point, - radius: distance, - pcb_keepout_id: z.string(), - layers: z.array(z.string()), // Specify layers where the keepout applies - description: z.string().optional(), // Optional description of the keepout - }), - ) + }), + z.object({ + type: z.literal("pcb_keepout"), + shape: z.literal("circle"), + pcb_keepout_id: getZodPrefixedIdWithDefault("pcb_keepout"), + center: point, + radius: distance, + layers: z.array(z.string()), // Specify layers where the keepout applies + description: z.string().optional(), // Optional description of the keepout + }), +]) + +export type PcbKeepoutInput = z.input +type InferredPcbKeepout = z.infer + +/** + * Defines a keepout area on the PCB, which can be either a rectangle or a circle. + * The keepout area is specified for one or more layers, and an optional description can be provided. + */ +export interface PcbKeepout { + type: "pcb_keepout" + pcb_keepout_id: string + center: Point + layers: string[] + description?: string +} + +// Rectangular Keepout +export interface PcbKeepoutRect extends PcbKeepout { + shape: "rect" + width: Distance + height: Distance +} + +// Circular Keepout +export interface PcbKeepoutCircle extends PcbKeepout { + shape: "circle" + radius: Distance +} + +/** + * @deprecated use PcbKeepout + */ +export type PCBKeepout = PcbKeepout -export type PCBKeepoutInput = z.input -export type PCBKeepout = z.infer +expectTypesMatch(true) diff --git a/src/pcb/pcb_placement_error.ts b/src/pcb/pcb_placement_error.ts index 9497238..e99ab8e 100644 --- a/src/pcb/pcb_placement_error.ts +++ b/src/pcb/pcb_placement_error.ts @@ -1,13 +1,30 @@ import { z } from "zod" +import { getZodPrefixedIdWithDefault } from "src/common" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_placement_error = z .object({ - pcb_error_id: z.string(), - type: z.literal("pcb_error"), - error_type: z.literal("pcb_placement_error"), + type: z.literal("pcb_placement_error"), + pcb_placement_error_id: getZodPrefixedIdWithDefault("pcb_placement_error"), message: z.string(), }) .describe("Defines a placement error on the PCB") -export type PCBPlacementErrorInput = z.input -export type PCBPlacementError = z.infer +export type PcbPlacementErrorInput = z.input +type InferredPcbPlacementError = z.infer + +/** + * Defines a placement error on the PCB + */ +export interface PcbPlacementError { + type: "pcb_placement_error" + pcb_placement_error_id: string + message: string +} + +/** + * @deprecated use PcbPlacementError + */ +export type PCBPlacementError = PcbPlacementError + +expectTypesMatch(true) diff --git a/src/pcb/pcb_plated_hole.ts b/src/pcb/pcb_plated_hole.ts index 8c949a0..4799364 100644 --- a/src/pcb/pcb_plated_hole.ts +++ b/src/pcb/pcb_plated_hole.ts @@ -1,9 +1,11 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" +import { distance, type Distance } from "src/units" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" +import { getZodPrefixedIdWithDefault } from "src/common" +import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_plated_hole = z - .object({ +export const pcb_plated_hole = z.union([ + z.object({ type: z.literal("pcb_plated_hole"), shape: z.literal("circle"), outer_diameter: z.number(), @@ -14,26 +16,58 @@ export const pcb_plated_hole = z port_hints: z.array(z.string()).optional(), pcb_component_id: z.string().optional(), pcb_port_id: z.string().optional(), - pcb_plated_hole_id: z.string(), - }) - .or( - z.object({ - type: z.literal("pcb_plated_hole"), - shape: z.enum(["oval", "pill"]), - outer_width: z.number(), - outer_height: z.number(), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - layers: z.array(layer_ref), - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - pcb_plated_hole_id: z.string(), - }), - ) + pcb_plated_hole_id: getZodPrefixedIdWithDefault("pcb_plated_hole"), + }), + z.object({ + type: z.literal("pcb_plated_hole"), + shape: z.enum(["oval", "pill"]), + outer_width: z.number(), + outer_height: z.number(), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + layers: z.array(layer_ref), + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + pcb_plated_hole_id: getZodPrefixedIdWithDefault("pcb_plated_hole"), + }), +]) .describe("Defines a plated hole on the PCB") -export type PCBPlatedHoleInput = z.input -export type PCBPlatedHole = z.infer +export type PcbPlatedHoleInput = z.input +type InferredPcbPlatedHole = z.infer + +/** + * Defines a plated hole on the PCB + */ +export interface PcbPlatedHole { + type: "pcb_plated_hole" + shape: "circle" | "oval" | "pill" + outer_diameter?: number + outer_width?: number + outer_height?: number + hole_diameter?: number + hole_width?: number + hole_height?: number + x: Distance + y: Distance + layers: LayerRef[] + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string + pcb_plated_hole_id: string +} + +/** + * @deprecated use PcbPlatedHole + */ +export type PCBPlatedHole = PcbPlatedHole + +/** + * @deprecated use PcbPlatedHoleInput + */ +export type PCBPlatedHoleInput = PcbPlatedHoleInput + +expectTypesMatch(true) diff --git a/src/pcb/pcb_port.ts b/src/pcb/pcb_port.ts index 4f15c66..ecd4167 100644 --- a/src/pcb/pcb_port.ts +++ b/src/pcb/pcb_port.ts @@ -1,11 +1,12 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" +import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_port = z .object({ type: z.literal("pcb_port"), - pcb_port_id: z.string(), + pcb_port_id: getZodPrefixedIdWithDefault("pcb_port"), source_port_id: z.string(), pcb_component_id: z.string(), x: distance, @@ -14,5 +15,30 @@ export const pcb_port = z }) .describe("Defines a port on the PCB") -export type PCBPort = z.infer -export type PCBPortInput = z.input +export type PcbPortInput = z.input +type InferredPcbPort = z.infer + +/** + * Defines a port on the PCB + */ +export interface PcbPort { + type: "pcb_port" + pcb_port_id: string + source_port_id: string + pcb_component_id: string + x: Distance + y: Distance + layers: LayerRef[] +} + +/** + * @deprecated use PcbPort + */ +export type PCBPort = PcbPort + +/** + * @deprecated use PcbPortInput + */ +export type PCBPortInput = PcbPortInput + +expectTypesMatch(true) diff --git a/src/pcb/pcb_port_not_matched_error.ts b/src/pcb/pcb_port_not_matched_error.ts index 4933c0f..5373f32 100644 --- a/src/pcb/pcb_port_not_matched_error.ts +++ b/src/pcb/pcb_port_not_matched_error.ts @@ -1,16 +1,32 @@ import { z } from "zod" +import { getZodPrefixedIdWithDefault } from "src/common" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_port_not_matched_error = z .object({ - pcb_error_id: z.string(), - type: z.literal("pcb_error"), - error_type: z.literal("pcb_port_not_matched_error"), + type: z.literal("pcb_port_not_matched_error"), + pcb_error_id: getZodPrefixedIdWithDefault("pcb_error"), message: z.string(), pcb_component_ids: z.array(z.string()), }) - .describe("Defines a trace error on the PCB") + .describe("Defines a trace error on the PCB where a port is not matched") -export type PCBPortNotMatchedErrorInput = z.input< - typeof pcb_port_not_matched_error -> -export type PCBPortNotMatchedError = z.infer +export type PcbPortNotMatchedErrorInput = z.input +type InferredPcbPortNotMatchedError = z.infer + +/** + * Defines a trace error on the PCB where a port is not matched + */ +export interface PcbPortNotMatchedError { + type: "pcb_port_not_matched_error" + pcb_error_id: string + message: string + pcb_component_ids: string[] +} + +/** + * @deprecated use PcbPortNotMatchedError + */ +export type PCBPortNotMatchedError = PcbPortNotMatchedError + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_circle.ts b/src/pcb/pcb_silkscreen_circle.ts index f1facb4..836826e 100644 --- a/src/pcb/pcb_silkscreen_circle.ts +++ b/src/pcb/pcb_silkscreen_circle.ts @@ -1,18 +1,38 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref, visible_layer } from "./properties/layer_ref" -import { point } from "src/common/point" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_circle = z .object({ type: z.literal("pcb_silkscreen_circle"), - pcb_silkscreen_circle_id: z.string(), + pcb_silkscreen_circle_id: getZodPrefixedIdWithDefault("pcb_silkscreen_circle"), pcb_component_id: z.string(), center: point, - radius: distance, - layer: visible_layer, + radius: length, + layer: layer_ref, }) .describe("Defines a silkscreen circle on the PCB") -export type PcbSilkscreenCircle = z.infer export type PcbSilkscreenCircleInput = z.input +type InferredPcbSilkscreenCircle = z.infer + +/** + * Defines a silkscreen circle on the PCB + */ +export interface PcbSilkscreenCircle { + type: "pcb_silkscreen_circle" + pcb_silkscreen_circle_id: string + pcb_component_id: string + center: Point + radius: Length + layer: LayerRef +} + +/** + * @deprecated use PcbSilkscreenCircle + */ +export type PcbSilkscreenCircleInput = PcbSilkscreenCircleInput + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_line.ts b/src/pcb/pcb_silkscreen_line.ts index 84c1b11..07895a6 100644 --- a/src/pcb/pcb_silkscreen_line.ts +++ b/src/pcb/pcb_silkscreen_line.ts @@ -1,11 +1,13 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref, visible_layer } from "./properties/layer_ref" +import { distance, type Distance } from "src/units" +import { layer_ref, type LayerRef, visible_layer } from "src/properties/layer_ref" +import { getZodPrefixedIdWithDefault } from "src/common" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_line = z .object({ type: z.literal("pcb_silkscreen_line"), - pcb_silkscreen_line_id: z.string(), + pcb_silkscreen_line_id: getZodPrefixedIdWithDefault("pcb_silkscreen_line"), pcb_component_id: z.string(), stroke_width: distance.default("0.1mm"), x1: distance, @@ -16,5 +18,27 @@ export const pcb_silkscreen_line = z }) .describe("Defines a silkscreen line on the PCB") -export type PcbSilkscreenLine = z.infer export type PcbSilkscreenLineInput = z.input +type InferredPcbSilkscreenLine = z.infer + +/** + * Defines a silkscreen line on the PCB + */ +export interface PcbSilkscreenLine { + type: "pcb_silkscreen_line" + pcb_silkscreen_line_id: string + pcb_component_id: string + stroke_width: Distance + x1: Distance + y1: Distance + x2: Distance + y2: Distance + layer: LayerRef +} + +/** + * @deprecated use PcbSilkscreenLine + */ +export type PCBSilkscreenLine = PcbSilkscreenLine + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_oval.ts b/src/pcb/pcb_silkscreen_oval.ts index dbd47c6..eb76872 100644 --- a/src/pcb/pcb_silkscreen_oval.ts +++ b/src/pcb/pcb_silkscreen_oval.ts @@ -1,12 +1,13 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref, visible_layer } from "./properties/layer_ref" -import { point } from "src/common/point" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef, visible_layer, type VisibleLayer } from "src/properties/layer_ref" +import { distance, type Distance } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_oval = z .object({ type: z.literal("pcb_silkscreen_oval"), - pcb_silkscreen_oval_id: z.string(), + pcb_silkscreen_oval_id: getZodPrefixedIdWithDefault("pcb_silkscreen_oval"), pcb_component_id: z.string(), center: point, radius_x: distance, @@ -15,5 +16,25 @@ export const pcb_silkscreen_oval = z }) .describe("Defines a silkscreen oval on the PCB") -export type PcbSilkscreenOval = z.infer export type PcbSilkscreenOvalInput = z.input +type InferredPcbSilkscreenOval = z.infer + +/** + * Defines a silkscreen oval on the PCB + */ +export interface PcbSilkscreenOval { + type: "pcb_silkscreen_oval" + pcb_silkscreen_oval_id: string + pcb_component_id: string + center: Point + radius_x: Distance + radius_y: Distance + layer: VisibleLayer +} + +/** + * @deprecated use PcbSilkscreenOval + */ +export type PcbSilkscreenOvalDeprecated = PcbSilkscreenOval + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_path.ts b/src/pcb/pcb_silkscreen_path.ts index e9b33e9..d33cfd6 100644 --- a/src/pcb/pcb_silkscreen_path.ts +++ b/src/pcb/pcb_silkscreen_path.ts @@ -1,12 +1,13 @@ import { z } from "zod" -import { visible_layer } from "./properties/layer_ref" -import { point } from "src/common" -import { length } from "src/units" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { visible_layer, type LayerRef } from "src/properties/layer_ref" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_path = z .object({ type: z.literal("pcb_silkscreen_path"), - pcb_silkscreen_path_id: z.string(), + pcb_silkscreen_path_id: getZodPrefixedIdWithDefault("pcb_silkscreen_path"), pcb_component_id: z.string(), layer: visible_layer, route: z.array(point), @@ -14,5 +15,24 @@ export const pcb_silkscreen_path = z }) .describe("Defines a silkscreen path on the PCB") -export type PcbSilkscreenPath = z.infer export type PcbSilkscreenPathInput = z.input +type InferredPcbSilkscreenPath = z.infer + +/** + * Defines a silkscreen path on the PCB + */ +export interface PcbSilkscreenPath { + type: "pcb_silkscreen_path" + pcb_silkscreen_path_id: string + pcb_component_id: string + layer: LayerRef + route: Point[] + stroke_width: Length +} + +/** + * @deprecated use PcbSilkscreenPath + */ +export type PcbSilkscreenPathDeprecated = PcbSilkscreenPath + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_pill.ts b/src/pcb/pcb_silkscreen_pill.ts index 8e7cb43..415d269 100644 --- a/src/pcb/pcb_silkscreen_pill.ts +++ b/src/pcb/pcb_silkscreen_pill.ts @@ -1,19 +1,40 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref, visible_layer } from "./properties/layer_ref" -import { point } from "src/common/point" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_pill = z .object({ type: z.literal("pcb_silkscreen_pill"), - pcb_silkscreen_pill_id: z.string(), + pcb_silkscreen_pill_id: getZodPrefixedIdWithDefault("pcb_silkscreen_pill"), pcb_component_id: z.string(), center: point, - width: distance, - height: distance, - layer: visible_layer, + width: length, + height: length, + layer: layer_ref, }) .describe("Defines a silkscreen pill on the PCB") -export type PcbSilkscreenPill = z.infer export type PcbSilkscreenPillInput = z.input +type InferredPcbSilkscreenPill = z.infer + +/** + * Defines a silkscreen pill on the PCB + */ +export interface PcbSilkscreenPill { + type: "pcb_silkscreen_pill" + pcb_silkscreen_pill_id: string + pcb_component_id: string + center: Point + width: Length + height: Length + layer: LayerRef +} + +/** + * @deprecated use PcbSilkscreenPill + */ +export type PcbSilkscreenPillDeprecated = PcbSilkscreenPill + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_rect.ts b/src/pcb/pcb_silkscreen_rect.ts index d1ae153..37dc9f3 100644 --- a/src/pcb/pcb_silkscreen_rect.ts +++ b/src/pcb/pcb_silkscreen_rect.ts @@ -1,19 +1,40 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref, visible_layer } from "./properties/layer_ref" -import { point } from "src/common/point" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_rect = z .object({ type: z.literal("pcb_silkscreen_rect"), - pcb_silkscreen_rect_id: z.string(), + pcb_silkscreen_rect_id: getZodPrefixedIdWithDefault("pcb_silkscreen_rect"), pcb_component_id: z.string(), center: point, - width: distance, - height: distance, - layer: visible_layer, + width: length, + height: length, + layer: layer_ref, }) .describe("Defines a silkscreen rect on the PCB") -export type PcbSilkscreenRect = z.infer export type PcbSilkscreenRectInput = z.input +type InferredPcbSilkscreenRect = z.infer + +/** + * Defines a silkscreen rect on the PCB + */ +export interface PcbSilkscreenRect { + type: "pcb_silkscreen_rect" + pcb_silkscreen_rect_id: string + pcb_component_id: string + center: Point + width: Length + height: Length + layer: LayerRef +} + +/** + * @deprecated use PcbSilkscreenRect + */ +export type PcbSilkscreenRectOld = PcbSilkscreenRect + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_text.ts b/src/pcb/pcb_silkscreen_text.ts index 93ee5c4..8ebf1c6 100644 --- a/src/pcb/pcb_silkscreen_text.ts +++ b/src/pcb/pcb_silkscreen_text.ts @@ -1,16 +1,18 @@ import { z } from "zod" -import { visible_layer } from "./properties/layer_ref" -import { point } from "src/common" -import { distance } from "src/units" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { distance, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_text = z .object({ type: z.literal("pcb_silkscreen_text"), + pcb_silkscreen_text_id: getZodPrefixedIdWithDefault("pcb_silkscreen_text"), font: z.literal("tscircuit2024").default("tscircuit2024"), font_size: distance.default("0.2mm"), pcb_component_id: z.string(), text: z.string(), - layer: visible_layer, + layer: layer_ref, anchor_position: point.default({ x: 0, y: 0 }), anchor_alignment: z .enum(["center", "top_left", "top_right", "bottom_left", "bottom_right"]) @@ -18,5 +20,27 @@ export const pcb_silkscreen_text = z }) .describe("Defines silkscreen text on the PCB") -export type PcbSilkscreenText = z.infer export type PcbSilkscreenTextInput = z.input +type InferredPcbSilkscreenText = z.infer + +/** + * Defines silkscreen text on the PCB + */ +export interface PcbSilkscreenText { + type: "pcb_silkscreen_text" + pcb_silkscreen_text_id: string + font: "tscircuit2024" + font_size: Length + pcb_component_id: string + text: string + layer: LayerRef + anchor_position: Point + anchor_alignment: "center" | "top_left" | "top_right" | "bottom_left" | "bottom_right" +} + +/** + * @deprecated use PcbSilkscreenText + */ +export type PCBSilkscreenText = PcbSilkscreenText + +expectTypesMatch(true) diff --git a/src/pcb/pcb_smtpad.ts b/src/pcb/pcb_smtpad.ts index b0955da..940ec27 100644 --- a/src/pcb/pcb_smtpad.ts +++ b/src/pcb/pcb_smtpad.ts @@ -1,36 +1,61 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" +import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_smtpad = z - .union([ - z.object({ - pcb_smtpad_id: z.string(), - type: z.literal("pcb_smtpad"), - shape: z.literal("circle"), - x: distance, - y: distance, - radius: z.number(), - layer: layer_ref, - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - }), - z.object({ - pcb_smtpad_id: z.string(), - type: z.literal("pcb_smtpad"), - shape: z.literal("rect"), - x: distance, - y: distance, - width: z.number(), - height: z.number(), - layer: layer_ref, - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - }), - ]) +export const pcb_smtpad = z.union([ + z.object({ + pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), + type: z.literal("pcb_smtpad"), + shape: z.literal("circle"), + x: distance, + y: distance, + radius: z.number(), + layer: layer_ref, + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + }), + z.object({ + pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), + type: z.literal("pcb_smtpad"), + shape: z.literal("rect"), + x: distance, + y: distance, + width: z.number(), + height: z.number(), + layer: layer_ref, + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + }), +]) .describe("Defines an SMT pad on the PCB") export type PCBSMTPadInput = z.input -export type PCBSMTPad = z.infer +type InferredPCBSMTPad = z.infer + +/** + * Defines an SMT pad on the PCB + */ +export interface PcbSmtPad { + pcb_smtpad_id: string + type: "pcb_smtpad" + shape: "circle" | "rect" + x: Distance + y: Distance + radius?: number + width?: number + height?: number + layer: LayerRef + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string +} + +/** + * @deprecated use PcbSmtPad + */ +export type PCBSMTPad = PcbSmtPad + +expectTypesMatch(true) diff --git a/src/pcb/pcb_text.ts b/src/pcb/pcb_text.ts index 965b933..1bf5109 100644 --- a/src/pcb/pcb_text.ts +++ b/src/pcb/pcb_text.ts @@ -1,18 +1,44 @@ import { z } from "zod" -import { distance } from "../units" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { length, type Length } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_text = z .object({ type: z.literal("pcb_text"), + pcb_text_id: getZodPrefixedIdWithDefault("pcb_text"), text: z.string(), - x: distance, - y: distance, - align: z.enum(["bottom-left"]), - width: distance, - height: distance, + center: point, + layer: layer_ref, + width: length, + height: length, lines: z.number(), + align: z.enum(["bottom-left"]), }) .describe("Defines text on the PCB") -export type PCBTextInput = z.input -export type PCBText = z.infer +export type PcbTextInput = z.input +type InferredPcbText = z.infer + +/** + * Defines text on the PCB + */ +export interface PcbText { + type: "pcb_text" + pcb_text_id: string + text: string + center: Point + layer: LayerRef + width: Length + height: Length + lines: number + align: "bottom-left" +} + +/** + * @deprecated use PcbText + */ +export type PCBText = PcbText + +expectTypesMatch(true) diff --git a/src/pcb/pcb_trace.ts b/src/pcb/pcb_trace.ts index 434552a..24338a4 100644 --- a/src/pcb/pcb_trace.ts +++ b/src/pcb/pcb_trace.ts @@ -1,38 +1,83 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" +import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" +import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_trace = z.object({ - type: z.literal("pcb_trace"), - source_trace_id: z.string().optional(), - pcb_component_id: z.string().optional(), - pcb_trace_id: z.string(), - route_thickness_mode: z - .enum(["constant", "interpolated"]) - .default("constant") - .optional(), - should_round_corners: z.boolean().optional(), - route: z.array( - z.union([ - z.object({ - route_type: z.literal("wire"), - x: distance, - y: distance, - width: distance, - start_pcb_port_id: z.string().optional(), - end_pcb_port_id: z.string().optional(), - layer: layer_ref, - }), - z.object({ - route_type: z.literal("via"), - x: distance, - y: distance, - from_layer: z.string(), - to_layer: z.string(), - }), - ]), - ), -}) +export const pcb_trace = z + .object({ + type: z.literal("pcb_trace"), + source_trace_id: z.string().optional(), + pcb_component_id: z.string().optional(), + pcb_trace_id: getZodPrefixedIdWithDefault("pcb_trace"), + route_thickness_mode: z + .enum(["constant", "interpolated"]) + .default("constant") + .optional(), + should_round_corners: z.boolean().optional(), + route: z.array( + z.union([ + z.object({ + route_type: z.literal("wire"), + x: distance, + y: distance, + width: distance, + start_pcb_port_id: z.string().optional(), + end_pcb_port_id: z.string().optional(), + layer: layer_ref, + }), + z.object({ + route_type: z.literal("via"), + x: distance, + y: distance, + from_layer: z.string(), + to_layer: z.string(), + }), + ]), + ), + }) + .describe("Defines a trace on the PCB") -export type PCBTraceInput = z.input -export type PCBTrace = z.output +export type PcbTraceInput = z.input +type InferredPcbTrace = z.infer + +/** + * Defines a trace on the PCB + */ +export interface PcbTrace { + type: "pcb_trace" + source_trace_id?: string + pcb_component_id?: string + pcb_trace_id: string + route_thickness_mode?: "constant" | "interpolated" + should_round_corners?: boolean + route: Array< + | { + route_type: "wire" + x: Distance + y: Distance + width: Distance + start_pcb_port_id?: string + end_pcb_port_id?: string + layer: LayerRef + } + | { + route_type: "via" + x: Distance + y: Distance + from_layer: string + to_layer: string + } + > +} + +/** + * @deprecated use PcbTrace + */ +export type PCBTrace = PcbTrace + +/** + * @deprecated use PcbTraceInput + */ +export type PCBTraceInput = PcbTraceInput + +expectTypesMatch(true) diff --git a/src/pcb/pcb_trace_error.ts b/src/pcb/pcb_trace_error.ts index f609011..101ac5f 100644 --- a/src/pcb/pcb_trace_error.ts +++ b/src/pcb/pcb_trace_error.ts @@ -1,10 +1,11 @@ -import { point } from "src/common" import { z } from "zod" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_trace_error = z .object({ - pcb_error_id: z.string(), - type: z.literal("pcb_error"), + type: z.literal("pcb_trace_error"), + pcb_trace_error_id: getZodPrefixedIdWithDefault("pcb_trace_error"), error_type: z.literal("pcb_trace_error"), message: z.string(), center: point.optional(), @@ -15,5 +16,27 @@ export const pcb_trace_error = z }) .describe("Defines a trace error on the PCB") -export type PCBTraceErrorInput = z.input -export type PCBTraceError = z.infer +export type PcbTraceErrorInput = z.input +type InferredPcbTraceError = z.infer + +/** + * Defines a trace error on the PCB + */ +export interface PcbTraceError { + type: "pcb_trace_error" + pcb_trace_error_id: string + error_type: "pcb_trace_error" + message: string + center?: Point + pcb_trace_id: string + source_trace_id: string + pcb_component_ids: string[] + pcb_port_ids: string[] +} + +/** + * @deprecated use PcbTraceError + */ +export type PCBTraceError = PcbTraceError + +expectTypesMatch(true) diff --git a/src/pcb/pcb_trace_hint.ts b/src/pcb/pcb_trace_hint.ts index 387ff44..4edda7f 100644 --- a/src/pcb/pcb_trace_hint.ts +++ b/src/pcb/pcb_trace_hint.ts @@ -1,16 +1,34 @@ import { z } from "zod" -import { distance } from "../units" -import { route_hint_point } from "./index" +import { getZodPrefixedIdWithDefault } from "src/common" +import { route_hint_point, type RouteHintPoint } from "src/pcb" + +/** + * A hint that can be used to generate a PCB trace. + */ +export interface PcbTraceHint { + type: "pcb_trace_hint" + pcb_trace_hint_id: string + pcb_port_id: string + pcb_component_id: string + route: RouteHintPoint[] +} export const pcb_trace_hint = z .object({ - pcb_trace_hint_id: z.string(), type: z.literal("pcb_trace_hint"), + pcb_trace_hint_id: getZodPrefixedIdWithDefault("pcb_trace_hint"), pcb_port_id: z.string(), pcb_component_id: z.string(), route: z.array(route_hint_point.optional()), }) .describe("A hint that can be used to generate a PCB trace") -export type PcbTraceHint = z.infer export type PcbTraceHintInput = z.input +type InferredPcbTraceHint = z.infer + +/** + * @deprecated use PcbTraceHint + */ +export type PCBTraceHint = PcbTraceHint + +expectTypesMatch(true) diff --git a/src/pcb/pcb_via.ts b/src/pcb/pcb_via.ts index 6dcf6bc..7eecc1f 100644 --- a/src/pcb/pcb_via.ts +++ b/src/pcb/pcb_via.ts @@ -1,10 +1,12 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" +import { distance, type Distance } from "src/units" +import { layer_ref, type LayerRef, getZodPrefixedIdWithDefault } from "src/properties/layer_ref" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_via = z .object({ type: z.literal("pcb_via"), + pcb_via_id: getZodPrefixedIdWithDefault("pcb_via"), x: distance, y: distance, outer_diameter: distance.default("0.6mm"), @@ -17,5 +19,29 @@ export const pcb_via = z }) .describe("Defines a via on the PCB") -export type PCBViaInput = z.input -export type PCBVia = z.infer +export type PcbViaInput = z.input +type InferredPcbVia = z.infer + +/** + * Defines a via on the PCB + */ +export interface PcbVia { + type: "pcb_via" + pcb_via_id: string + x: Distance + y: Distance + outer_diameter: Distance + hole_diameter: Distance + /** @deprecated */ + from_layer?: LayerRef + /** @deprecated */ + to_layer?: LayerRef + layers: LayerRef[] +} + +/** + * @deprecated use PcbVia + */ +export type PCBVia = PcbVia + +expectTypesMatch(true) From 0f4cdfd119c4d313d4e5b7e5259c563c34c60384 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 10:29:08 -0700 Subject: [PATCH 3/9] revert pcb_hole --- src/pcb/pcb_hole.ts | 58 +++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/src/pcb/pcb_hole.ts b/src/pcb/pcb_hole.ts index 23fc325..763e36a 100644 --- a/src/pcb/pcb_hole.ts +++ b/src/pcb/pcb_hole.ts @@ -1,10 +1,9 @@ import { z } from "zod" -import { distance, type Distance } from "src/units" -import { getZodPrefixedIdWithDefault } from "src/utils/get-zod-prefixed-id-with-default" -import { expectTypesMatch } from "src/utils/expect-types-match" +import { distance } from "../units" -export const pcb_hole = z.union([ - z.object({ +export const pcb_hole = z + .object({ + pcb_hole_id: z.string(), type: z.literal("pcb_hole"), hole_shape: z .enum(["circle", "square", "round"]) @@ -16,38 +15,19 @@ export const pcb_hole = z.union([ hole_diameter: z.number(), x: distance, y: distance, - }), - z.object({ - type: z.literal("pcb_hole"), - pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), - hole_shape: z.literal("oval"), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - }), -]) - -export type PcbHoleInput = z.input -type InferredPcbHole = z.infer - -/** - * Defines a hole on the PCB - */ -export interface PcbHole { - type: "pcb_hole" - pcb_hole_id: string - hole_shape: "round" | "square" | "oval" - hole_diameter?: number - hole_width?: number - hole_height?: number - x: Distance - y: Distance -} - -/** - * @deprecated use PcbHole - */ -export type PCBHole = PcbHole + }) + .or( + z.object({ + pcb_hole_id: z.string(), + type: z.literal("pcb_hole"), + hole_shape: z.literal("oval"), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + }), + ) + .describe("Defines a hole on the PCB") -expectTypesMatch(true) +export type PCBHoleInput = z.input +export type PCBHole = z.infer From a83df514936c45ce84253b5914de4dd771c4bce2 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 10:52:30 -0700 Subject: [PATCH 4/9] progress towards complete refactor of pcb elements --- scripts/refactor-template.md | 3 + scripts/refactor.ts | 2 +- src/pcb/pcb_hole.ts | 92 +++++++++++++++++++-------- src/pcb/pcb_plated_hole.ts | 84 ++++++++---------------- src/pcb/pcb_port.ts | 5 +- src/pcb/pcb_port_not_matched_error.ts | 4 +- src/pcb/pcb_silkscreen_circle.ts | 20 +++--- src/pcb/pcb_silkscreen_line.ts | 9 ++- src/pcb/pcb_silkscreen_oval.ts | 7 +- src/pcb/pcb_silkscreen_path.ts | 7 +- src/pcb/properties/layer_ref.ts | 1 + src/units/index.ts | 1 + 12 files changed, 130 insertions(+), 105 deletions(-) diff --git a/scripts/refactor-template.md b/scripts/refactor-template.md index 52286d6..d0353c9 100644 --- a/scripts/refactor-template.md +++ b/scripts/refactor-template.md @@ -11,6 +11,9 @@ Some of the new rules: - Prefer absolute imports from "src/" - Use `getZodPrefixedIdWithDefault` to generate a unique id for the primary id of the object - The main interface should have a `/**` multi-line comment describing the object +- If the zod type is a union or `or` type, then export interfaces for each of the + of the types in the union, then define a union type for each of the exported + interfaces `export type MainInterface = SomeInterface1 | SomeInterface2`. ```ts // EXAMPLE FILE OF NEW CIRCUIT SPECIFICATION diff --git a/scripts/refactor.ts b/scripts/refactor.ts index c3f76c9..1e3119d 100644 --- a/scripts/refactor.ts +++ b/scripts/refactor.ts @@ -5,7 +5,7 @@ import fs from "node:fs" const anthropic = new Anthropic() -const filePaths = [ +const filePaths = ["./src/pcb/pcb_hole.ts"] || [ "./src/pcb/pcb_fabrication_note_path.ts", "./src/pcb/pcb_component.ts", "./src/pcb/pcb_port_not_matched_error.ts", diff --git a/src/pcb/pcb_hole.ts b/src/pcb/pcb_hole.ts index 763e36a..56cd628 100644 --- a/src/pcb/pcb_hole.ts +++ b/src/pcb/pcb_hole.ts @@ -1,33 +1,69 @@ import { z } from "zod" -import { distance } from "../units" +import { distance, type Length, getZodPrefixedIdWithDefault } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_hole = z - .object({ - pcb_hole_id: z.string(), - type: z.literal("pcb_hole"), - hole_shape: z - .enum(["circle", "square", "round"]) - .default("circle") - .transform((shape) => { - if (shape === "round") return "circle" - return shape as "circle" | "square" - }), - hole_diameter: z.number(), - x: distance, - y: distance, - }) - .or( - z.object({ - pcb_hole_id: z.string(), - type: z.literal("pcb_hole"), - hole_shape: z.literal("oval"), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - }), - ) + .union([ + z + .object({ + type: z.literal("pcb_hole"), + pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), + hole_shape: z + .enum(["circle", "square", "round"]) + .default("circle") + .transform((shape) => { + if (shape === "round") return "circle" + return shape as "circle" | "square" + }), + hole_diameter: z.number(), + x: distance, + y: distance, + }) + .describe("Defines a circular or square hole on the PCB"), + z + .object({ + type: z.literal("pcb_hole"), + pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), + hole_shape: z.literal("oval"), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + }) + .describe("Defines an oval hole on the PCB"), + ]) .describe("Defines a hole on the PCB") -export type PCBHoleInput = z.input -export type PCBHole = z.infer +export type PcbHoleInput = z.input +type InferredPcbHole = z.infer + +/** + * Defines a hole on the PCB + */ +export interface PcbHole { + type: "pcb_hole" + pcb_hole_id: string + hole_shape: "circle" | "square" | "oval" + x: Length + y: Length +} + +interface PcbCircularOrSquareHole extends PcbHole { + hole_shape: "circle" | "square" + hole_diameter: number +} + +interface PcbOvalHole extends PcbHole { + hole_shape: "oval" + hole_width: number + hole_height: number +} + +export type PcbHole = PcbCircularOrSquareHole | PcbOvalHole + +/** + * @deprecated use PcbHole + */ +export type PCBHole = PcbHole + +expectTypesMatch(true) diff --git a/src/pcb/pcb_plated_hole.ts b/src/pcb/pcb_plated_hole.ts index 4799364..8c949a0 100644 --- a/src/pcb/pcb_plated_hole.ts +++ b/src/pcb/pcb_plated_hole.ts @@ -1,11 +1,9 @@ import { z } from "zod" -import { distance, type Distance } from "src/units" -import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" -import { getZodPrefixedIdWithDefault } from "src/common" -import { expectTypesMatch } from "src/utils/expect-types-match" +import { distance } from "../units" +import { layer_ref } from "./properties/layer_ref" -export const pcb_plated_hole = z.union([ - z.object({ +export const pcb_plated_hole = z + .object({ type: z.literal("pcb_plated_hole"), shape: z.literal("circle"), outer_diameter: z.number(), @@ -16,58 +14,26 @@ export const pcb_plated_hole = z.union([ port_hints: z.array(z.string()).optional(), pcb_component_id: z.string().optional(), pcb_port_id: z.string().optional(), - pcb_plated_hole_id: getZodPrefixedIdWithDefault("pcb_plated_hole"), - }), - z.object({ - type: z.literal("pcb_plated_hole"), - shape: z.enum(["oval", "pill"]), - outer_width: z.number(), - outer_height: z.number(), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - layers: z.array(layer_ref), - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - pcb_plated_hole_id: getZodPrefixedIdWithDefault("pcb_plated_hole"), - }), -]) + pcb_plated_hole_id: z.string(), + }) + .or( + z.object({ + type: z.literal("pcb_plated_hole"), + shape: z.enum(["oval", "pill"]), + outer_width: z.number(), + outer_height: z.number(), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + layers: z.array(layer_ref), + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + pcb_plated_hole_id: z.string(), + }), + ) .describe("Defines a plated hole on the PCB") -export type PcbPlatedHoleInput = z.input -type InferredPcbPlatedHole = z.infer - -/** - * Defines a plated hole on the PCB - */ -export interface PcbPlatedHole { - type: "pcb_plated_hole" - shape: "circle" | "oval" | "pill" - outer_diameter?: number - outer_width?: number - outer_height?: number - hole_diameter?: number - hole_width?: number - hole_height?: number - x: Distance - y: Distance - layers: LayerRef[] - port_hints?: string[] - pcb_component_id?: string - pcb_port_id?: string - pcb_plated_hole_id: string -} - -/** - * @deprecated use PcbPlatedHole - */ -export type PCBPlatedHole = PcbPlatedHole - -/** - * @deprecated use PcbPlatedHoleInput - */ -export type PCBPlatedHoleInput = PcbPlatedHoleInput - -expectTypesMatch(true) +export type PCBPlatedHoleInput = z.input +export type PCBPlatedHole = z.infer diff --git a/src/pcb/pcb_port.ts b/src/pcb/pcb_port.ts index ecd4167..9fba65a 100644 --- a/src/pcb/pcb_port.ts +++ b/src/pcb/pcb_port.ts @@ -1,6 +1,7 @@ import { z } from "zod" -import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { getZodPrefixedIdWithDefault } from "src/common" +import { distance, type Distance } from "src/units" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_port = z diff --git a/src/pcb/pcb_port_not_matched_error.ts b/src/pcb/pcb_port_not_matched_error.ts index 5373f32..424f9e9 100644 --- a/src/pcb/pcb_port_not_matched_error.ts +++ b/src/pcb/pcb_port_not_matched_error.ts @@ -11,7 +11,9 @@ export const pcb_port_not_matched_error = z }) .describe("Defines a trace error on the PCB where a port is not matched") -export type PcbPortNotMatchedErrorInput = z.input +export type PcbPortNotMatchedErrorInput = z.input< + typeof pcb_port_not_matched_error +> type InferredPcbPortNotMatchedError = z.infer /** diff --git a/src/pcb/pcb_silkscreen_circle.ts b/src/pcb/pcb_silkscreen_circle.ts index 836826e..8c9de04 100644 --- a/src/pcb/pcb_silkscreen_circle.ts +++ b/src/pcb/pcb_silkscreen_circle.ts @@ -1,17 +1,24 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { + layer_ref, + visible_layer, + type LayerRef, + type VisibleLayer, +} from "src/pcb/properties/layer_ref" import { length, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_silkscreen_circle = z .object({ type: z.literal("pcb_silkscreen_circle"), - pcb_silkscreen_circle_id: getZodPrefixedIdWithDefault("pcb_silkscreen_circle"), + pcb_silkscreen_circle_id: getZodPrefixedIdWithDefault( + "pcb_silkscreen_circle", + ), pcb_component_id: z.string(), center: point, radius: length, - layer: layer_ref, + layer: visible_layer, }) .describe("Defines a silkscreen circle on the PCB") @@ -27,12 +34,7 @@ export interface PcbSilkscreenCircle { pcb_component_id: string center: Point radius: Length - layer: LayerRef + layer: VisibleLayer } -/** - * @deprecated use PcbSilkscreenCircle - */ -export type PcbSilkscreenCircleInput = PcbSilkscreenCircleInput - expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_line.ts b/src/pcb/pcb_silkscreen_line.ts index 07895a6..4f6cb36 100644 --- a/src/pcb/pcb_silkscreen_line.ts +++ b/src/pcb/pcb_silkscreen_line.ts @@ -1,6 +1,11 @@ import { z } from "zod" import { distance, type Distance } from "src/units" -import { layer_ref, type LayerRef, visible_layer } from "src/properties/layer_ref" +import { + layer_ref, + type LayerRef, + type VisibleLayer, + visible_layer, +} from "src/pcb/properties/layer_ref" import { getZodPrefixedIdWithDefault } from "src/common" import { expectTypesMatch } from "src/utils/expect-types-match" @@ -33,7 +38,7 @@ export interface PcbSilkscreenLine { y1: Distance x2: Distance y2: Distance - layer: LayerRef + layer: VisibleLayer } /** diff --git a/src/pcb/pcb_silkscreen_oval.ts b/src/pcb/pcb_silkscreen_oval.ts index eb76872..000f6e3 100644 --- a/src/pcb/pcb_silkscreen_oval.ts +++ b/src/pcb/pcb_silkscreen_oval.ts @@ -1,6 +1,11 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef, visible_layer, type VisibleLayer } from "src/properties/layer_ref" +import { + layer_ref, + type LayerRef, + visible_layer, + type VisibleLayer, +} from "src/pcb/properties/layer_ref" import { distance, type Distance } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" diff --git a/src/pcb/pcb_silkscreen_path.ts b/src/pcb/pcb_silkscreen_path.ts index d33cfd6..2969093 100644 --- a/src/pcb/pcb_silkscreen_path.ts +++ b/src/pcb/pcb_silkscreen_path.ts @@ -1,6 +1,9 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { visible_layer, type LayerRef } from "src/properties/layer_ref" +import { + visible_layer, + type VisibleLayerRef, +} from "src/pcb/properties/layer_ref" import { length, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" @@ -25,7 +28,7 @@ export interface PcbSilkscreenPath { type: "pcb_silkscreen_path" pcb_silkscreen_path_id: string pcb_component_id: string - layer: LayerRef + layer: VisibleLayerRef route: Point[] stroke_width: Length } diff --git a/src/pcb/properties/layer_ref.ts b/src/pcb/properties/layer_ref.ts index 96a4fe7..00473d1 100644 --- a/src/pcb/properties/layer_ref.ts +++ b/src/pcb/properties/layer_ref.ts @@ -31,3 +31,4 @@ export type LayerRef = z.output export const visible_layer = z.enum(["top", "bottom"]) export type VisibleLayerRef = z.infer +export type VisibleLayer = z.infer diff --git a/src/units/index.ts b/src/units/index.ts index 4abe582..643f0d8 100644 --- a/src/units/index.ts +++ b/src/units/index.ts @@ -81,6 +81,7 @@ export const length = z * Length in meters */ export type Length = number +export type Distance = number export const distance = length From 03edfc4a6625c4f61084ec787bfdcd8020cac0f4 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 10:57:19 -0700 Subject: [PATCH 5/9] reverts and corrections to refactor --- scripts/refactor-template.md | 9 +-- src/pcb/pcb_component.ts | 2 +- src/pcb/pcb_fabrication_note_path.ts | 12 +++- src/pcb/pcb_fabrication_note_text.ts | 13 +++- src/pcb/pcb_hole.ts | 92 +++++++++------------------- src/pcb/pcb_keepout.ts | 70 ++++++--------------- src/pcb/pcb_silkscreen_pill.ts | 2 +- src/pcb/pcb_silkscreen_rect.ts | 2 +- src/pcb/pcb_silkscreen_text.ts | 9 ++- src/pcb/pcb_smtpad.ts | 57 ++++++++--------- src/pcb/pcb_text.ts | 2 +- src/pcb/pcb_trace.ts | 2 +- src/pcb/pcb_trace_hint.ts | 7 ++- src/pcb/pcb_via.ts | 6 +- 14 files changed, 121 insertions(+), 164 deletions(-) diff --git a/scripts/refactor-template.md b/scripts/refactor-template.md index d0353c9..db0621f 100644 --- a/scripts/refactor-template.md +++ b/scripts/refactor-template.md @@ -11,15 +11,16 @@ Some of the new rules: - Prefer absolute imports from "src/" - Use `getZodPrefixedIdWithDefault` to generate a unique id for the primary id of the object - The main interface should have a `/**` multi-line comment describing the object -- If the zod type is a union or `or` type, then export interfaces for each of the - of the types in the union, then define a union type for each of the exported - interfaces `export type MainInterface = SomeInterface1 | SomeInterface2`. +- If the zod type is a union or `or` type, then it into separate zod types + and export interfaces for each of the of the types in the union, then define a + union type for each of the exported interfaces + `export type MainInterface = SomeInterface1 | SomeInterface2`. ```ts // EXAMPLE FILE OF NEW CIRCUIT SPECIFICATION import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { rotation, length, type Rotation, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" diff --git a/src/pcb/pcb_component.ts b/src/pcb/pcb_component.ts index fac86d2..4a671e0 100644 --- a/src/pcb/pcb_component.ts +++ b/src/pcb/pcb_component.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { rotation, length, type Rotation, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" diff --git a/src/pcb/pcb_fabrication_note_path.ts b/src/pcb/pcb_fabrication_note_path.ts index ceafb88..8b0da99 100644 --- a/src/pcb/pcb_fabrication_note_path.ts +++ b/src/pcb/pcb_fabrication_note_path.ts @@ -1,6 +1,10 @@ import { z } from "zod" import { getZodPrefixedIdWithDefault } from "src/common" -import { visible_layer, type LayerRef } from "src/properties/layer_ref" +import { + layer_ref, + visible_layer, + type LayerRef, +} from "src/pcb/properties/layer_ref" import { point, type Point } from "src/common" import { length, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" @@ -12,7 +16,7 @@ export const pcb_fabrication_note_path = z "pcb_fabrication_note_path", ), pcb_component_id: z.string(), - layer: visible_layer, + layer: layer_ref, route: z.array(point), stroke_width: length, color: z.string().optional(), @@ -21,7 +25,9 @@ export const pcb_fabrication_note_path = z "Defines a fabrication path on the PCB for fabricators or assemblers", ) -export type PcbFabricationNotePathInput = z.input +export type PcbFabricationNotePathInput = z.input< + typeof pcb_fabrication_note_path +> type InferredPcbFabricationNotePath = z.infer /** diff --git a/src/pcb/pcb_fabrication_note_text.ts b/src/pcb/pcb_fabrication_note_text.ts index 60e48aa..fd0be96 100644 --- a/src/pcb/pcb_fabrication_note_text.ts +++ b/src/pcb/pcb_fabrication_note_text.ts @@ -1,7 +1,7 @@ import { z } from "zod" import { point, type Point } from "src/common" import { distance, type Length } from "src/units" -import { visible_layer, type LayerRef } from "src/properties/layer_ref" +import { visible_layer, type LayerRef } from "src/pcb/properties/layer_ref" import { getZodPrefixedIdWithDefault } from "src/common/getZodPrefixedIdWithDefault" import { expectTypesMatch } from "src/utils/expect-types-match" @@ -26,7 +26,9 @@ export const pcb_fabrication_note_text = z "Defines a fabrication note in text on the PCB, useful for leaving notes for assemblers or fabricators", ) -export type PcbFabricationNoteTextInput = z.input +export type PcbFabricationNoteTextInput = z.input< + typeof pcb_fabrication_note_text +> type InferredPcbFabricationNoteText = z.infer /** @@ -41,7 +43,12 @@ export interface PcbFabricationNoteText { text: string layer: LayerRef anchor_position: Point - anchor_alignment: "center" | "top_left" | "top_right" | "bottom_left" | "bottom_right" + anchor_alignment: + | "center" + | "top_left" + | "top_right" + | "bottom_left" + | "bottom_right" color?: string } diff --git a/src/pcb/pcb_hole.ts b/src/pcb/pcb_hole.ts index 56cd628..763e36a 100644 --- a/src/pcb/pcb_hole.ts +++ b/src/pcb/pcb_hole.ts @@ -1,69 +1,33 @@ import { z } from "zod" -import { distance, type Length, getZodPrefixedIdWithDefault } from "src/units" -import { expectTypesMatch } from "src/utils/expect-types-match" +import { distance } from "../units" export const pcb_hole = z - .union([ - z - .object({ - type: z.literal("pcb_hole"), - pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), - hole_shape: z - .enum(["circle", "square", "round"]) - .default("circle") - .transform((shape) => { - if (shape === "round") return "circle" - return shape as "circle" | "square" - }), - hole_diameter: z.number(), - x: distance, - y: distance, - }) - .describe("Defines a circular or square hole on the PCB"), - z - .object({ - type: z.literal("pcb_hole"), - pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), - hole_shape: z.literal("oval"), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - }) - .describe("Defines an oval hole on the PCB"), - ]) + .object({ + pcb_hole_id: z.string(), + type: z.literal("pcb_hole"), + hole_shape: z + .enum(["circle", "square", "round"]) + .default("circle") + .transform((shape) => { + if (shape === "round") return "circle" + return shape as "circle" | "square" + }), + hole_diameter: z.number(), + x: distance, + y: distance, + }) + .or( + z.object({ + pcb_hole_id: z.string(), + type: z.literal("pcb_hole"), + hole_shape: z.literal("oval"), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + }), + ) .describe("Defines a hole on the PCB") -export type PcbHoleInput = z.input -type InferredPcbHole = z.infer - -/** - * Defines a hole on the PCB - */ -export interface PcbHole { - type: "pcb_hole" - pcb_hole_id: string - hole_shape: "circle" | "square" | "oval" - x: Length - y: Length -} - -interface PcbCircularOrSquareHole extends PcbHole { - hole_shape: "circle" | "square" - hole_diameter: number -} - -interface PcbOvalHole extends PcbHole { - hole_shape: "oval" - hole_width: number - hole_height: number -} - -export type PcbHole = PcbCircularOrSquareHole | PcbOvalHole - -/** - * @deprecated use PcbHole - */ -export type PCBHole = PcbHole - -expectTypesMatch(true) +export type PCBHoleInput = z.input +export type PCBHole = z.infer diff --git a/src/pcb/pcb_keepout.ts b/src/pcb/pcb_keepout.ts index eda9dc9..5228276 100644 --- a/src/pcb/pcb_keepout.ts +++ b/src/pcb/pcb_keepout.ts @@ -1,61 +1,29 @@ import { z } from "zod" -import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { distance, type Distance } from "src/units" -import { expectTypesMatch } from "src/utils/expect-types-match" +import { point } from "../common" +import { distance } from "../units" -export const pcb_keepout = z.union([ - z.object({ +export const pcb_keepout = z + .object({ type: z.literal("pcb_keepout"), shape: z.literal("rect"), - pcb_keepout_id: getZodPrefixedIdWithDefault("pcb_keepout"), center: point, width: distance, height: distance, + pcb_keepout_id: z.string(), layers: z.array(z.string()), // Specify layers where the keepout applies description: z.string().optional(), // Optional description of the keepout - }), - z.object({ - type: z.literal("pcb_keepout"), - shape: z.literal("circle"), - pcb_keepout_id: getZodPrefixedIdWithDefault("pcb_keepout"), - center: point, - radius: distance, - layers: z.array(z.string()), // Specify layers where the keepout applies - description: z.string().optional(), // Optional description of the keepout - }), -]) - -export type PcbKeepoutInput = z.input -type InferredPcbKeepout = z.infer - -/** - * Defines a keepout area on the PCB, which can be either a rectangle or a circle. - * The keepout area is specified for one or more layers, and an optional description can be provided. - */ -export interface PcbKeepout { - type: "pcb_keepout" - pcb_keepout_id: string - center: Point - layers: string[] - description?: string -} - -// Rectangular Keepout -export interface PcbKeepoutRect extends PcbKeepout { - shape: "rect" - width: Distance - height: Distance -} - -// Circular Keepout -export interface PcbKeepoutCircle extends PcbKeepout { - shape: "circle" - radius: Distance -} - -/** - * @deprecated use PcbKeepout - */ -export type PCBKeepout = PcbKeepout + }) + .or( + z.object({ + type: z.literal("pcb_keepout"), + shape: z.literal("circle"), + center: point, + radius: distance, + pcb_keepout_id: z.string(), + layers: z.array(z.string()), // Specify layers where the keepout applies + description: z.string().optional(), // Optional description of the keepout + }), + ) -expectTypesMatch(true) +export type PCBKeepoutInput = z.input +export type PCBKeepout = z.infer diff --git a/src/pcb/pcb_silkscreen_pill.ts b/src/pcb/pcb_silkscreen_pill.ts index 415d269..c16e987 100644 --- a/src/pcb/pcb_silkscreen_pill.ts +++ b/src/pcb/pcb_silkscreen_pill.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { length, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" diff --git a/src/pcb/pcb_silkscreen_rect.ts b/src/pcb/pcb_silkscreen_rect.ts index 37dc9f3..8ee958d 100644 --- a/src/pcb/pcb_silkscreen_rect.ts +++ b/src/pcb/pcb_silkscreen_rect.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { length, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" diff --git a/src/pcb/pcb_silkscreen_text.ts b/src/pcb/pcb_silkscreen_text.ts index 8ebf1c6..97d6c80 100644 --- a/src/pcb/pcb_silkscreen_text.ts +++ b/src/pcb/pcb_silkscreen_text.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { distance, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" @@ -35,7 +35,12 @@ export interface PcbSilkscreenText { text: string layer: LayerRef anchor_position: Point - anchor_alignment: "center" | "top_left" | "top_right" | "bottom_left" | "bottom_right" + anchor_alignment: + | "center" + | "top_left" + | "top_right" + | "bottom_left" + | "bottom_right" } /** diff --git a/src/pcb/pcb_smtpad.ts b/src/pcb/pcb_smtpad.ts index 940ec27..51a2ab9 100644 --- a/src/pcb/pcb_smtpad.ts +++ b/src/pcb/pcb_smtpad.ts @@ -1,35 +1,36 @@ import { z } from "zod" import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_smtpad = z.union([ - z.object({ - pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), - type: z.literal("pcb_smtpad"), - shape: z.literal("circle"), - x: distance, - y: distance, - radius: z.number(), - layer: layer_ref, - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - }), - z.object({ - pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), - type: z.literal("pcb_smtpad"), - shape: z.literal("rect"), - x: distance, - y: distance, - width: z.number(), - height: z.number(), - layer: layer_ref, - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - }), -]) +export const pcb_smtpad = z + .union([ + z.object({ + pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), + type: z.literal("pcb_smtpad"), + shape: z.literal("circle"), + x: distance, + y: distance, + radius: z.number(), + layer: layer_ref, + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + }), + z.object({ + pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), + type: z.literal("pcb_smtpad"), + shape: z.literal("rect"), + x: distance, + y: distance, + width: z.number(), + height: z.number(), + layer: layer_ref, + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + }), + ]) .describe("Defines an SMT pad on the PCB") export type PCBSMTPadInput = z.input diff --git a/src/pcb/pcb_text.ts b/src/pcb/pcb_text.ts index 1bf5109..3006c9a 100644 --- a/src/pcb/pcb_text.ts +++ b/src/pcb/pcb_text.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { length, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" diff --git a/src/pcb/pcb_trace.ts b/src/pcb/pcb_trace.ts index 24338a4..9be373a 100644 --- a/src/pcb/pcb_trace.ts +++ b/src/pcb/pcb_trace.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" -import { layer_ref, type LayerRef } from "src/properties/layer_ref" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_trace = z diff --git a/src/pcb/pcb_trace_hint.ts b/src/pcb/pcb_trace_hint.ts index 4edda7f..5f31c42 100644 --- a/src/pcb/pcb_trace_hint.ts +++ b/src/pcb/pcb_trace_hint.ts @@ -1,9 +1,10 @@ import { z } from "zod" import { getZodPrefixedIdWithDefault } from "src/common" import { route_hint_point, type RouteHintPoint } from "src/pcb" +import { expectTypesMatch } from "src/utils/expect-types-match" /** - * A hint that can be used to generate a PCB trace. + * A hint that can be used during generation of a PCB trace. */ export interface PcbTraceHint { type: "pcb_trace_hint" @@ -19,9 +20,9 @@ export const pcb_trace_hint = z pcb_trace_hint_id: getZodPrefixedIdWithDefault("pcb_trace_hint"), pcb_port_id: z.string(), pcb_component_id: z.string(), - route: z.array(route_hint_point.optional()), + route: z.array(route_hint_point), }) - .describe("A hint that can be used to generate a PCB trace") + .describe("A hint that can be used during generation of a PCB trace") export type PcbTraceHintInput = z.input type InferredPcbTraceHint = z.infer diff --git a/src/pcb/pcb_via.ts b/src/pcb/pcb_via.ts index 7eecc1f..7dfb7d2 100644 --- a/src/pcb/pcb_via.ts +++ b/src/pcb/pcb_via.ts @@ -1,6 +1,10 @@ import { z } from "zod" import { distance, type Distance } from "src/units" -import { layer_ref, type LayerRef, getZodPrefixedIdWithDefault } from "src/properties/layer_ref" +import { + layer_ref, + type LayerRef, + getZodPrefixedIdWithDefault, +} from "src/pcb/properties/layer_ref" import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_via = z From e3e5a380bad6bb8e563f8bcf57927afcefd62b7d Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 11:08:12 -0700 Subject: [PATCH 6/9] progress on refactoring --- docs/PCB_COMPONENT_OVERVIEW.md | 1 + scripts/refactor-template.md | 6 +- scripts/refactor.ts | 34 ++------- src/pcb/pcb_hole.ts | 105 +++++++++++++++++++-------- src/pcb/pcb_plated_hole.ts | 126 +++++++++++++++++++++++---------- src/pcb/pcb_smtpad.ts | 91 +++++++++++++++--------- 6 files changed, 233 insertions(+), 130 deletions(-) create mode 100644 docs/PCB_COMPONENT_OVERVIEW.md diff --git a/docs/PCB_COMPONENT_OVERVIEW.md b/docs/PCB_COMPONENT_OVERVIEW.md new file mode 100644 index 0000000..2d66f03 --- /dev/null +++ b/docs/PCB_COMPONENT_OVERVIEW.md @@ -0,0 +1 @@ +# Circuit JSON Specification: PCB Component Overview diff --git a/scripts/refactor-template.md b/scripts/refactor-template.md index db0621f..8abf996 100644 --- a/scripts/refactor-template.md +++ b/scripts/refactor-template.md @@ -11,10 +11,12 @@ Some of the new rules: - Prefer absolute imports from "src/" - Use `getZodPrefixedIdWithDefault` to generate a unique id for the primary id of the object - The main interface should have a `/**` multi-line comment describing the object -- If the zod type is a union or `or` type, then it into separate zod types +- If the zod type is a union or `or` type, then it into separate zod definitions and export interfaces for each of the of the types in the union, then define a union type for each of the exported interfaces - `export type MainInterface = SomeInterface1 | SomeInterface2`. + `export type MainInterface = SomeInterface1 | SomeInterface2`. Make sure to + use the `expectTypesMatch` function to ensure the zod type and each interface + are the same. ```ts // EXAMPLE FILE OF NEW CIRCUIT SPECIFICATION diff --git a/scripts/refactor.ts b/scripts/refactor.ts index 1e3119d..653afb8 100644 --- a/scripts/refactor.ts +++ b/scripts/refactor.ts @@ -5,35 +5,11 @@ import fs from "node:fs" const anthropic = new Anthropic() -const filePaths = ["./src/pcb/pcb_hole.ts"] || [ - "./src/pcb/pcb_fabrication_note_path.ts", - "./src/pcb/pcb_component.ts", - "./src/pcb/pcb_port_not_matched_error.ts", - "./src/pcb/pcb_silkscreen_text.ts", - "./src/pcb/pcb_trace_error.ts", - "./src/pcb/pcb_silkscreen_pill.ts", - "./src/pcb/pcb_plated_hole.ts", - "./src/pcb/pcb_fabrication_note_text.ts", - "./src/pcb/pcb_silkscreen_circle.ts", - "./src/pcb/pcb_silkscreen_path.ts", - "./src/pcb/pcb_text.ts", - "./src/pcb/pcb_keepout.ts", - "./src/pcb/pcb_via.ts", - // "./src/pcb/properties/supplier_name.ts", - // "./src/pcb/properties/pcb_route_hints.ts", - // "./src/pcb/properties/layer_ref.ts", - // "./src/pcb/properties/route_hint_point.ts", - "./src/pcb/pcb_silkscreen_oval.ts", - "./src/pcb/pcb_placement_error.ts", - "./src/pcb/pcb_port.ts", - "./src/pcb/pcb_silkscreen_rect.ts", - "./src/pcb/pcb_trace_hint.ts", - "./src/pcb/pcb_smtpad.ts", - "./src/pcb/pcb_silkscreen_line.ts", - "./src/pcb/pcb_hole.ts", - "./src/pcb/pcb_trace.ts", - // "./src/pcb/pcb_board.ts", -] +const filePaths = [ + // "./src/pcb/pcb_hole.ts", + // "./src/pcb/pcb_plated_hole.ts", + // "./src/pcb/pcb_smtpad.ts", +].slice(0, 1) for (const filePath of filePaths) { const fileContents = fs.readFileSync(filePath, "utf8") diff --git a/src/pcb/pcb_hole.ts b/src/pcb/pcb_hole.ts index 763e36a..4cba3d1 100644 --- a/src/pcb/pcb_hole.ts +++ b/src/pcb/pcb_hole.ts @@ -1,33 +1,82 @@ import { z } from "zod" -import { distance } from "../units" - -export const pcb_hole = z - .object({ - pcb_hole_id: z.string(), - type: z.literal("pcb_hole"), - hole_shape: z - .enum(["circle", "square", "round"]) - .default("circle") - .transform((shape) => { - if (shape === "round") return "circle" - return shape as "circle" | "square" - }), - hole_diameter: z.number(), - x: distance, - y: distance, - }) - .or( - z.object({ - pcb_hole_id: z.string(), - type: z.literal("pcb_hole"), - hole_shape: z.literal("oval"), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - }), +import { getZodPrefixedIdWithDefault } from "src/common" +import { distance, type Distance } from "src/units" +import { expectTypesMatch } from "src/utils/expect-types-match" + +const pcb_hole_circle_or_square = z.object({ + type: z.literal("pcb_hole"), + pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), + hole_shape: z.enum(["circle", "square"]), + hole_diameter: z.number(), + x: distance, + y: distance, +}) + +export const pcb_hole_circle_or_square_shape = + pcb_hole_circle_or_square.describe( + "Defines a circular or square hole on the PCB", ) - .describe("Defines a hole on the PCB") +export type PcbHoleCircleOrSquareInput = z.input< + typeof pcb_hole_circle_or_square +> +type InferredPcbHoleCircleOrSquare = z.infer + +/** + * Defines a circular or square hole on the PCB + */ +export interface PcbHoleCircleOrSquare { + type: "pcb_hole" + pcb_hole_id: string + hole_shape: "circle" | "square" + hole_diameter: number + x: Distance + y: Distance +} + +expectTypesMatch(true) + +const pcb_hole_oval = z.object({ + type: z.literal("pcb_hole"), + pcb_hole_id: getZodPrefixedIdWithDefault("pcb_hole"), + hole_shape: z.literal("oval"), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, +}) + +export const pcb_hole_oval_shape = pcb_hole_oval.describe( + "Defines an oval hole on the PCB", +) + +export type PcbHoleOvalInput = z.input +type InferredPcbHoleOval = z.infer + +/** + * Defines an oval hole on the PCB + */ +export interface PcbHoleOval { + type: "pcb_hole" + pcb_hole_id: string + hole_shape: "oval" + hole_width: number + hole_height: number + x: Distance + y: Distance +} + +expectTypesMatch(true) + +export const pcb_hole = pcb_hole_circle_or_square.or(pcb_hole_oval) + +/** + * @deprecated Use PcbHoleCircleOrSquare or PcbHoleOval + */ export type PCBHoleInput = z.input +/** + * @deprecated Use PcbHoleCircleOrSquare or PcbHoleOval + */ export type PCBHole = z.infer + +export type PcbHole = PcbHoleCircleOrSquare | PcbHoleOval diff --git a/src/pcb/pcb_plated_hole.ts b/src/pcb/pcb_plated_hole.ts index 8c949a0..a6042bf 100644 --- a/src/pcb/pcb_plated_hole.ts +++ b/src/pcb/pcb_plated_hole.ts @@ -1,39 +1,93 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" - -export const pcb_plated_hole = z - .object({ - type: z.literal("pcb_plated_hole"), - shape: z.literal("circle"), - outer_diameter: z.number(), - hole_diameter: z.number(), - x: distance, - y: distance, - layers: z.array(layer_ref), - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - pcb_plated_hole_id: z.string(), - }) - .or( - z.object({ - type: z.literal("pcb_plated_hole"), - shape: z.enum(["oval", "pill"]), - outer_width: z.number(), - outer_height: z.number(), - hole_width: z.number(), - hole_height: z.number(), - x: distance, - y: distance, - layers: z.array(layer_ref), - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - pcb_plated_hole_id: z.string(), - }), - ) - .describe("Defines a plated hole on the PCB") +import { distance, type Distance } from "src/units" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" +import { getZodPrefixedIdWithDefault } from "src/common" +import { expectTypesMatch } from "src/utils/expect-types-match" +const pcb_plated_hole_circle = z.object({ + type: z.literal("pcb_plated_hole"), + shape: z.literal("circle"), + outer_diameter: z.number(), + hole_diameter: z.number(), + x: distance, + y: distance, + layers: z.array(layer_ref), + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + pcb_plated_hole_id: getZodPrefixedIdWithDefault("pcb_plated_hole"), +}) + +/** + * Defines a circular plated hole on the PCB + */ +export interface PcbPlatedHoleCircle { + type: "pcb_plated_hole" + shape: "circle" + outer_diameter: number + hole_diameter: number + x: Distance + y: Distance + layers: LayerRef[] + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string + pcb_plated_hole_id: string +} + +const pcb_plated_hole_oval = z.object({ + type: z.literal("pcb_plated_hole"), + shape: z.enum(["oval", "pill"]), + outer_width: z.number(), + outer_height: z.number(), + hole_width: z.number(), + hole_height: z.number(), + x: distance, + y: distance, + layers: z.array(layer_ref), + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), + pcb_plated_hole_id: getZodPrefixedIdWithDefault("pcb_plated_hole"), +}) + +/** + * Defines an oval or pill-shaped plated hole on the PCB + */ +export interface PcbPlatedHoleOval { + type: "pcb_plated_hole" + shape: "oval" | "pill" + outer_width: number + outer_height: number + hole_width: number + hole_height: number + x: Distance + y: Distance + layers: LayerRef[] + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string + pcb_plated_hole_id: string +} + +export const pcb_plated_hole = z.union([ + pcb_plated_hole_circle, + pcb_plated_hole_oval, +]) +export type PcbPlatedHole = PcbPlatedHoleCircle | PcbPlatedHoleOval + +expectTypesMatch>( + true, +) +expectTypesMatch>(true) + +/** + * @deprecated use PcbPlatedHole + */ +export type PCBPlatedHole = PcbPlatedHole + +/** + * @deprecated use PcbPlatedHoleInput + */ export type PCBPlatedHoleInput = z.input -export type PCBPlatedHole = z.infer +export type PcbPlatedHoleInput = z.input diff --git a/src/pcb/pcb_smtpad.ts b/src/pcb/pcb_smtpad.ts index 51a2ab9..4304ad7 100644 --- a/src/pcb/pcb_smtpad.ts +++ b/src/pcb/pcb_smtpad.ts @@ -1,62 +1,83 @@ import { z } from "zod" -import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" +import { distance, type Distance } from "src/units" import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" +import { getZodPrefixedIdWithDefault } from "src/common" import { expectTypesMatch } from "src/utils/expect-types-match" +const pcb_smtpad_circle = z.object({ + type: z.literal("pcb_smtpad"), + shape: z.literal("circle"), + pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), + x: distance, + y: distance, + radius: z.number(), + layer: layer_ref, + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), +}) + +const pcb_smtpad_rect = z.object({ + type: z.literal("pcb_smtpad"), + shape: z.literal("rect"), + pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), + x: distance, + y: distance, + width: z.number(), + height: z.number(), + layer: layer_ref, + port_hints: z.array(z.string()).optional(), + pcb_component_id: z.string().optional(), + pcb_port_id: z.string().optional(), +}) + export const pcb_smtpad = z - .union([ - z.object({ - pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), - type: z.literal("pcb_smtpad"), - shape: z.literal("circle"), - x: distance, - y: distance, - radius: z.number(), - layer: layer_ref, - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - }), - z.object({ - pcb_smtpad_id: getZodPrefixedIdWithDefault("pcb_smtpad"), - type: z.literal("pcb_smtpad"), - shape: z.literal("rect"), - x: distance, - y: distance, - width: z.number(), - height: z.number(), - layer: layer_ref, - port_hints: z.array(z.string()).optional(), - pcb_component_id: z.string().optional(), - pcb_port_id: z.string().optional(), - }), - ]) + .union([pcb_smtpad_circle, pcb_smtpad_rect]) .describe("Defines an SMT pad on the PCB") export type PCBSMTPadInput = z.input -type InferredPCBSMTPad = z.infer +type PCBSMTPadCircle = z.infer +type PCBSMTPadRect = z.infer /** * Defines an SMT pad on the PCB */ -export interface PcbSmtPad { +export interface PcbSmtPadCircle { + type: "pcb_smtpad" + shape: "circle" pcb_smtpad_id: string + x: Distance + y: Distance + radius: number + layer: LayerRef + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string +} + +/** + * Defines an SMT pad on the PCB + */ +export interface PcbSmtPadRect { type: "pcb_smtpad" - shape: "circle" | "rect" + shape: "rect" + pcb_smtpad_id: string x: Distance y: Distance - radius?: number - width?: number - height?: number + width: number + height: number layer: LayerRef port_hints?: string[] pcb_component_id?: string pcb_port_id?: string } +export type PcbSmtPad = PcbSmtPadCircle | PcbSmtPadRect + /** * @deprecated use PcbSmtPad */ export type PCBSMTPad = PcbSmtPad -expectTypesMatch(true) +expectTypesMatch(true) +expectTypesMatch(true) From 55d83814b8a1e06605e3c2b2a52cabe9d17f2a41 Mon Sep 17 00:00:00 2001 From: tscircuitbot Date: Fri, 20 Sep 2024 18:08:45 +0000 Subject: [PATCH 7/9] formatbot: Automatically format code --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b510d7d..407e859 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "author": "", "license": "ISC", "devDependencies": { - "@biomejs/biome": "^1.9.2", "@anthropic-ai/sdk": "^0.27.3", + "@biomejs/biome": "^1.9.2", "@types/convert-units": "^2.3.9", "esbuild": "^0.20.2", "ts-expect": "^1.3.0", From c5f7d7816fd5c95f02d24f7eae58c5182ddeb018 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 11:14:44 -0700 Subject: [PATCH 8/9] improve pcb trace definitions --- src/pcb/pcb_component.ts | 6 +-- src/pcb/pcb_fabrication_note_text.ts | 8 +++- src/pcb/pcb_trace.ts | 67 ++++++++++++++++++++-------- src/pcb/pcb_via.ts | 7 +-- 4 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/pcb/pcb_component.ts b/src/pcb/pcb_component.ts index 4a671e0..5c14499 100644 --- a/src/pcb/pcb_component.ts +++ b/src/pcb/pcb_component.ts @@ -4,7 +4,7 @@ import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { rotation, length, type Rotation, type Length } from "src/units" import { expectTypesMatch } from "src/utils/expect-types-match" -export const pcb_component_zod = z +export const pcb_component = z .object({ type: z.literal("pcb_component"), pcb_component_id: getZodPrefixedIdWithDefault("pcb_component"), @@ -17,8 +17,8 @@ export const pcb_component_zod = z }) .describe("Defines a component on the PCB") -export type PcbComponentInput = z.input -type InferredPcbComponent = z.infer +export type PcbComponentInput = z.input +type InferredPcbComponent = z.infer /** * Defines a component on the PCB diff --git a/src/pcb/pcb_fabrication_note_text.ts b/src/pcb/pcb_fabrication_note_text.ts index fd0be96..96e0e31 100644 --- a/src/pcb/pcb_fabrication_note_text.ts +++ b/src/pcb/pcb_fabrication_note_text.ts @@ -1,7 +1,11 @@ import { z } from "zod" import { point, type Point } from "src/common" import { distance, type Length } from "src/units" -import { visible_layer, type LayerRef } from "src/pcb/properties/layer_ref" +import { + visible_layer, + type LayerRef, + type VisibleLayer, +} from "src/pcb/properties/layer_ref" import { getZodPrefixedIdWithDefault } from "src/common/getZodPrefixedIdWithDefault" import { expectTypesMatch } from "src/utils/expect-types-match" @@ -41,7 +45,7 @@ export interface PcbFabricationNoteText { font_size: Length pcb_component_id: string text: string - layer: LayerRef + layer: VisibleLayer anchor_position: Point anchor_alignment: | "center" diff --git a/src/pcb/pcb_trace.ts b/src/pcb/pcb_trace.ts index 9be373a..b8d753b 100644 --- a/src/pcb/pcb_trace.ts +++ b/src/pcb/pcb_trace.ts @@ -1,8 +1,33 @@ import { z } from "zod" -import { distance, type Distance, getZodPrefixedIdWithDefault } from "src/units" +import { getZodPrefixedIdWithDefault } from "src/common" +import { distance, type Distance } from "src/units" import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { expectTypesMatch } from "src/utils/expect-types-match" +export const pcb_trace_route_point_wire = z.object({ + route_type: z.literal("wire"), + x: distance, + y: distance, + width: distance, + start_pcb_port_id: z.string().optional(), + end_pcb_port_id: z.string().optional(), + layer: layer_ref, +}) + +export const pcb_trace_route_point_via = z.object({ + route_type: z.literal("via"), + x: distance, + y: distance, + from_layer: z.string(), + to_layer: z.string(), +}) + +export const pcb_trace_route_point = z.union([ + pcb_trace_route_point_wire, + pcb_trace_route_point_via, +]) +type InferredPcbTraceRoutePoint = z.infer + export const pcb_trace = z .object({ type: z.literal("pcb_trace"), @@ -40,6 +65,26 @@ export const pcb_trace = z export type PcbTraceInput = z.input type InferredPcbTrace = z.infer +export interface PcbTraceRoutePointWire { + route_type: "wire" + x: Distance + y: Distance + width: Distance + start_pcb_port_id?: string + end_pcb_port_id?: string + layer: LayerRef +} + +export interface PcbTraceRoutePointVia { + route_type: "via" + x: Distance + y: Distance + from_layer: string + to_layer: string +} + +export type PcbTraceRoutePoint = PcbTraceRoutePointWire | PcbTraceRoutePointVia + /** * Defines a trace on the PCB */ @@ -50,24 +95,7 @@ export interface PcbTrace { pcb_trace_id: string route_thickness_mode?: "constant" | "interpolated" should_round_corners?: boolean - route: Array< - | { - route_type: "wire" - x: Distance - y: Distance - width: Distance - start_pcb_port_id?: string - end_pcb_port_id?: string - layer: LayerRef - } - | { - route_type: "via" - x: Distance - y: Distance - from_layer: string - to_layer: string - } - > + route: Array } /** @@ -80,4 +108,5 @@ export type PCBTrace = PcbTrace */ export type PCBTraceInput = PcbTraceInput +expectTypesMatch(true) expectTypesMatch(true) diff --git a/src/pcb/pcb_via.ts b/src/pcb/pcb_via.ts index 7dfb7d2..af87999 100644 --- a/src/pcb/pcb_via.ts +++ b/src/pcb/pcb_via.ts @@ -1,10 +1,7 @@ import { z } from "zod" import { distance, type Distance } from "src/units" -import { - layer_ref, - type LayerRef, - getZodPrefixedIdWithDefault, -} from "src/pcb/properties/layer_ref" +import { getZodPrefixedIdWithDefault } from "src/common" +import { layer_ref, type LayerRef } from "src/pcb/properties/layer_ref" import { expectTypesMatch } from "src/utils/expect-types-match" export const pcb_via = z From 8522eea2f135c927be0eac71c4a3ebeca4c45099 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 20 Sep 2024 11:37:41 -0700 Subject: [PATCH 9/9] generate pcb component overview docfile --- README.md | 6 +- docs/PCB_COMPONENT_OVERVIEW.md | 292 +++++++++++++++++++++ package.json | 2 +- scripts/generate-pcb-component-overview.ts | 60 +++++ scripts/refactor.ts | 2 +- src/pcb/index.ts | 40 +++ 6 files changed, 397 insertions(+), 5 deletions(-) create mode 100644 scripts/generate-pcb-component-overview.ts diff --git a/README.md b/README.md index 9515e61..67a32bd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @tscircuit/soup (Circuit JSON Specification) +# Circuit JSON Specification `circuit-json` [tscircuit](https://github.com/tscircuit/tscircuit) ยท [Soup Specification Docs](https://docs.tscircuit.com/api-reference/advanced/soup) @@ -12,8 +12,8 @@ This module has the zod definitions and conversion functions for using tscircuit > This is mostly an internal module, you probably want to use the [main tscircuit library](https://github.com/tscircuit/tscircuit) instead. ```ts -import { any_circuit_element, simple_source_resistor } from "@tscircuit/soup" -import type { SourceSimpleResistor } from "@tscircuit/soup" +import { any_circuit_element, simple_source_resistor } from "circuit-json" +import type { SourceSimpleResistor } from "circuit-json" const resistor: SourceSimpleResistor = simple_source_resistor.parse({ type: "source_component", diff --git a/docs/PCB_COMPONENT_OVERVIEW.md b/docs/PCB_COMPONENT_OVERVIEW.md index 2d66f03..9541881 100644 --- a/docs/PCB_COMPONENT_OVERVIEW.md +++ b/docs/PCB_COMPONENT_OVERVIEW.md @@ -1 +1,293 @@ # Circuit JSON Specification: PCB Component Overview + +> Created at 2024-09-20T18:37:19.158Z +> Latest Version: https://github.com/tscircuit/circuit-json/blob/main/docs/PCB_COMPONENT_OVERVIEW.md + +Any type below can be imported from `circuit-json`. Every type has a corresponding +snake_case version which is a zod type that can be used to parse unknown json, +for example `PcbComponent` has a `pcb_component.parse` function that you +can also import. + +```ts +export interface PcbFabricationNotePath { + type: "pcb_fabrication_note_path" + pcb_fabrication_note_path_id: string + pcb_component_id: string + layer: LayerRef + route: Point[] + stroke_width: Length + color?: string +} + +export interface PcbComponent { + type: "pcb_component" + pcb_component_id: string + source_component_id: string + center: Point + layer: LayerRef + rotation: Rotation + width: Length + height: Length +} + +export interface PcbPortNotMatchedError { + type: "pcb_port_not_matched_error" + pcb_error_id: string + message: string + pcb_component_ids: string[] +} + +export interface PcbSilkscreenText { + type: "pcb_silkscreen_text" + pcb_silkscreen_text_id: string + font: "tscircuit2024" + font_size: Length + pcb_component_id: string + text: string + layer: LayerRef + anchor_position: Point + anchor_alignment: + | "center" + | "top_left" + | "top_right" + | "bottom_left" + | "bottom_right" +} + +export interface PcbSilkscreenPill { + type: "pcb_silkscreen_pill" + pcb_silkscreen_pill_id: string + pcb_component_id: string + center: Point + width: Length + height: Length + layer: LayerRef +} + +export interface PcbPlatedHoleCircle { + type: "pcb_plated_hole" + shape: "circle" + outer_diameter: number + hole_diameter: number + x: Distance + y: Distance + layers: LayerRef[] + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string + pcb_plated_hole_id: string +} + +export interface PcbPlatedHoleOval { + type: "pcb_plated_hole" + shape: "oval" | "pill" + outer_width: number + outer_height: number + hole_width: number + hole_height: number + x: Distance + y: Distance + layers: LayerRef[] + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string + pcb_plated_hole_id: string +} + +export type PcbPlatedHole = PcbPlatedHoleCircle | PcbPlatedHoleOval + +export interface PcbFabricationNoteText { + type: "pcb_fabrication_note_text" + pcb_fabrication_note_text_id: string + font: "tscircuit2024" + font_size: Length + pcb_component_id: string + text: string + layer: VisibleLayer + anchor_position: Point + anchor_alignment: + | "center" + | "top_left" + | "top_right" + | "bottom_left" + | "bottom_right" + color?: string +} + +export interface PcbSilkscreenCircle { + type: "pcb_silkscreen_circle" + pcb_silkscreen_circle_id: string + pcb_component_id: string + center: Point + radius: Length + layer: VisibleLayer +} + +export interface PcbSilkscreenPath { + type: "pcb_silkscreen_path" + pcb_silkscreen_path_id: string + pcb_component_id: string + layer: VisibleLayerRef + route: Point[] + stroke_width: Length +} + +export interface PcbText { + type: "pcb_text" + pcb_text_id: string + text: string + center: Point + layer: LayerRef + width: Length + height: Length + lines: number + align: "bottom-left" +} + +export type PCBKeepout = z.infer + +export interface PcbVia { + type: "pcb_via" + pcb_via_id: string + x: Distance + y: Distance + outer_diameter: Distance + hole_diameter: Distance + layers: LayerRef[] +} + +export interface PcbSilkscreenOval { + type: "pcb_silkscreen_oval" + pcb_silkscreen_oval_id: string + pcb_component_id: string + center: Point + radius_x: Distance + radius_y: Distance + layer: VisibleLayer +} + +export interface PcbPlacementError { + type: "pcb_placement_error" + pcb_placement_error_id: string + message: string +} + +export interface PcbPort { + type: "pcb_port" + pcb_port_id: string + source_port_id: string + pcb_component_id: string + x: Distance + y: Distance + layers: LayerRef[] +} + +export interface PcbTraceHint { + type: "pcb_trace_hint" + pcb_trace_hint_id: string + pcb_port_id: string + pcb_component_id: string + route: RouteHintPoint[] +} + +export interface PcbSmtPadCircle { + type: "pcb_smtpad" + shape: "circle" + pcb_smtpad_id: string + x: Distance + y: Distance + radius: number + layer: LayerRef + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string +} + +export interface PcbSmtPadRect { + type: "pcb_smtpad" + shape: "rect" + pcb_smtpad_id: string + x: Distance + y: Distance + width: number + height: number + layer: LayerRef + port_hints?: string[] + pcb_component_id?: string + pcb_port_id?: string +} + +export type PcbSmtPad = PcbSmtPadCircle | PcbSmtPadRect + +export interface PcbSilkscreenLine { + type: "pcb_silkscreen_line" + pcb_silkscreen_line_id: string + pcb_component_id: string + stroke_width: Distance + x1: Distance + y1: Distance + x2: Distance + y2: Distance + layer: VisibleLayer +} + +export interface PcbHoleCircleOrSquare { + type: "pcb_hole" + pcb_hole_id: string + hole_shape: "circle" | "square" + hole_diameter: number + x: Distance + y: Distance +} + +export interface PcbHoleOval { + type: "pcb_hole" + pcb_hole_id: string + hole_shape: "oval" + hole_width: number + hole_height: number + x: Distance + y: Distance +} + +export type PcbHole = PcbHoleCircleOrSquare | PcbHoleOval + +export interface PcbTraceRoutePointWire { + route_type: "wire" + x: Distance + y: Distance + width: Distance + start_pcb_port_id?: string + end_pcb_port_id?: string + layer: LayerRef +} + +export interface PcbTraceRoutePointVia { + route_type: "via" + x: Distance + y: Distance + from_layer: string + to_layer: string +} + +export type PcbTraceRoutePoint = PcbTraceRoutePointWire | PcbTraceRoutePointVia + +export interface PcbTrace { + type: "pcb_trace" + source_trace_id?: string + pcb_component_id?: string + pcb_trace_id: string + route_thickness_mode?: "constant" | "interpolated" + should_round_corners?: boolean + route: Array +} + +export interface PcbBoard { + type: "pcb_board" + pcb_board_id: string + width: Length + height: Length + center: Point + outline?: Point[] +} +``` diff --git a/package.json b/package.json index 407e859..c0ed77f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@tscircuit/soup", + "name": "circuit-json", "version": "0.0.71", "description": "Definitions for the tscircuit intermediary JSON format", "main": "dist/index.js", diff --git a/scripts/generate-pcb-component-overview.ts b/scripts/generate-pcb-component-overview.ts new file mode 100644 index 0000000..6d42863 --- /dev/null +++ b/scripts/generate-pcb-component-overview.ts @@ -0,0 +1,60 @@ +import Anthropic from "@anthropic-ai/sdk" +import fs from "node:fs" +import path from "node:path" + +// Read all the files in the src/pcb directory +const pcbDir = path.join(__dirname, "../src/pcb") +const fileContents = fs + .readdirSync(pcbDir) + .map((file) => path.join(pcbDir, file)) + .filter((file) => file.endsWith(".ts")) + .map((file) => + fs + .readFileSync(file, "utf8") + // remove any lines that import + .replace(/^import .*;$/gm, "") + // remove any lines with z.infer, z.input, or z.output + .replace(/^type .*=.*z\.(infer|input|output)<.*>$/gm, ""), + ) + +// Extract the type definitions from the file contents +const anthropic = new Anthropic() + +const msg = await anthropic.messages.create({ + model: "claude-3-5-sonnet-20240620", + max_tokens: 4096, + messages: [ + { + role: "user", + content: `Extract all the exported type definitions from the following file contents. Do not include deprecated types. Return as a \`\`\`ts codeblock.\n\n${fileContents.join("\n")}`, + }, + ], +}) + +const resText: string = (msg as any).content[0].text + +const codefence = resText + .split("```")[1]! + .replace(/^ts\n/, "") + .replace(/^typescript\n/, "") + +// Write to docs/PCB_COMPONENT_OVERVIEW.md +const template = `# Circuit JSON Specification: PCB Component Overview + +> Created at ${new Date().toISOString()} +> Latest Version: https://github.com/tscircuit/circuit-json/blob/main/docs/PCB_COMPONENT_OVERVIEW.md + +Any type below can be imported from \`circuit-json\`. Every type has a corresponding +snake_case version which is a zod type that can be used to parse unknown json, +for example \`PcbComponent\` has a \`pcb_component.parse\` function that you +can also import. + +\`\`\`ts +${codefence} +\`\`\` +`.trim() + +fs.writeFileSync( + path.join(__dirname, "../docs/PCB_COMPONENT_OVERVIEW.md"), + template, +) diff --git a/scripts/refactor.ts b/scripts/refactor.ts index 653afb8..317c155 100644 --- a/scripts/refactor.ts +++ b/scripts/refactor.ts @@ -15,7 +15,7 @@ for (const filePath of filePaths) { const fileContents = fs.readFileSync(filePath, "utf8") const msg = await anthropic.messages.create({ - model: "claude-3-sonnet-20240229", + model: "claude-3-5-sonnet-20240620", max_tokens: 4000, messages: [ { diff --git a/src/pcb/index.ts b/src/pcb/index.ts index 49f29fd..eada66d 100644 --- a/src/pcb/index.ts +++ b/src/pcb/index.ts @@ -25,3 +25,43 @@ export * from "./pcb_silkscreen_oval" export * from "./pcb_fabrication_note_text" export * from "./pcb_fabrication_note_path" export * from "./pcb_keepout" + +// Define PcbCircuitElement which is a union of all the Pcb* elements +import type { PcbComponent } from "./pcb_component" +import type { PcbHole } from "./pcb_hole" +import type { PcbPlatedHole } from "./pcb_plated_hole" +import type { PcbPort } from "./pcb_port" +import type { PcbSmtPad } from "./pcb_smtpad" +import type { PcbText } from "./pcb_text" +import type { PcbTrace } from "./pcb_trace" +import type { PcbTraceError } from "./pcb_trace_error" +import type { PcbPortNotMatchedError } from "./pcb_port_not_matched_error" +import type { PcbVia } from "./pcb_via" +import type { PcbBoard } from "./pcb_board" +import type { PcbPlacementError } from "./pcb_placement_error" +import type { PcbTraceHint } from "./pcb_trace_hint" +import type { PcbSilkscreenLine } from "./pcb_silkscreen_line" +import type { PcbSilkscreenPath } from "./pcb_silkscreen_path" +import type { PcbSilkscreenText } from "./pcb_silkscreen_text" +import type { PcbSilkscreenRect } from "./pcb_silkscreen_rect" +import type { PcbSilkscreenCircle } from "./pcb_silkscreen_circle" + +export type PcbCircuitElement = + | PcbComponent + | PcbHole + | PcbPlatedHole + | PcbPort + | PcbSmtPad + | PcbText + | PcbTrace + | PcbTraceError + | PcbPortNotMatchedError + | PcbVia + | PcbBoard + | PcbPlacementError + | PcbTraceHint + | PcbSilkscreenLine + | PcbSilkscreenPath + | PcbSilkscreenText + | PcbSilkscreenRect + | PcbSilkscreenCircle