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 new file mode 100644 index 0000000..9541881 --- /dev/null +++ b/docs/PCB_COMPONENT_OVERVIEW.md @@ -0,0 +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 caba51e..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", @@ -14,6 +14,7 @@ "author": "", "license": "ISC", "devDependencies": { + "@anthropic-ai/sdk": "^0.27.3", "@biomejs/biome": "^1.9.2", "@types/convert-units": "^2.3.9", "esbuild": "^0.20.2", 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-template.md b/scripts/refactor-template.md new file mode 100644 index 0000000..8abf996 --- /dev/null +++ b/scripts/refactor-template.md @@ -0,0 +1,73 @@ +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 +- 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`. 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 +import { z } from "zod" +import { point, type Point, getZodPrefixedIdWithDefault } from "src/common" +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 = 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..317c155 --- /dev/null +++ b/scripts/refactor.ts @@ -0,0 +1,35 @@ +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 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") + + const msg = await anthropic.messages.create({ + model: "claude-3-5-sonnet-20240620", + 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/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 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) diff --git a/src/pcb/pcb_component.ts b/src/pcb/pcb_component.ts index 1fa1766..5c14499 100644 --- a/src/pcb/pcb_component.ts +++ b/src/pcb/pcb_component.ts @@ -1,8 +1,7 @@ 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/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 = z @@ -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..8b0da99 100644 --- a/src/pcb/pcb_fabrication_note_path.ts +++ b/src/pcb/pcb_fabrication_note_path.ts @@ -1,8 +1,13 @@ 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 { + 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" export const pcb_fabrication_note_path = z .object({ @@ -11,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(), @@ -20,7 +25,27 @@ 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 > +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..96e0e31 100644 --- a/src/pcb/pcb_fabrication_note_text.ts +++ b/src/pcb/pcb_fabrication_note_text.ts @@ -1,8 +1,13 @@ 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, + type VisibleLayer, +} from "src/pcb/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 +30,35 @@ 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 > +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: VisibleLayer + 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..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_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..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_port.ts b/src/pcb/pcb_port.ts index 4f15c66..9fba65a 100644 --- a/src/pcb/pcb_port.ts +++ b/src/pcb/pcb_port.ts @@ -1,11 +1,13 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./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 .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 +16,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..424f9e9 100644 --- a/src/pcb/pcb_port_not_matched_error.ts +++ b/src/pcb/pcb_port_not_matched_error.ts @@ -1,16 +1,34 @@ 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< +export type PcbPortNotMatchedErrorInput = z.input< typeof pcb_port_not_matched_error > -export type PCBPortNotMatchedError = z.infer +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..8c9de04 100644 --- a/src/pcb/pcb_silkscreen_circle.ts +++ b/src/pcb/pcb_silkscreen_circle.ts @@ -1,18 +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, + 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: z.string(), + pcb_silkscreen_circle_id: getZodPrefixedIdWithDefault( + "pcb_silkscreen_circle", + ), pcb_component_id: z.string(), center: point, - radius: distance, + radius: length, layer: visible_layer, }) .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: VisibleLayer +} + +expectTypesMatch(true) diff --git a/src/pcb/pcb_silkscreen_line.ts b/src/pcb/pcb_silkscreen_line.ts index 84c1b11..4f6cb36 100644 --- a/src/pcb/pcb_silkscreen_line.ts +++ b/src/pcb/pcb_silkscreen_line.ts @@ -1,11 +1,18 @@ 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, + type VisibleLayer, + visible_layer, +} from "src/pcb/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 +23,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: VisibleLayer +} + +/** + * @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..000f6e3 100644 --- a/src/pcb/pcb_silkscreen_oval.ts +++ b/src/pcb/pcb_silkscreen_oval.ts @@ -1,12 +1,18 @@ 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/pcb/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 +21,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..2969093 100644 --- a/src/pcb/pcb_silkscreen_path.ts +++ b/src/pcb/pcb_silkscreen_path.ts @@ -1,12 +1,16 @@ 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 VisibleLayerRef, +} 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_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 +18,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: VisibleLayerRef + 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..c16e987 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/pcb/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..8ee958d 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/pcb/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..97d6c80 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/pcb/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,32 @@ 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..4304ad7 100644 --- a/src/pcb/pcb_smtpad.ts +++ b/src/pcb/pcb_smtpad.ts @@ -1,36 +1,83 @@ 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" + +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: 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(), - }), - ]) + .union([pcb_smtpad_circle, pcb_smtpad_rect]) .describe("Defines an SMT pad on the PCB") export type PCBSMTPadInput = z.input -export type PCBSMTPad = z.infer +type PCBSMTPadCircle = z.infer +type PCBSMTPadRect = z.infer + +/** + * Defines an SMT pad on the PCB + */ +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: "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 + +/** + * @deprecated use PcbSmtPad + */ +export type PCBSMTPad = PcbSmtPad + +expectTypesMatch(true) +expectTypesMatch(true) diff --git a/src/pcb/pcb_text.ts b/src/pcb/pcb_text.ts index 965b933..3006c9a 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/pcb/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..b8d753b 100644 --- a/src/pcb/pcb_trace.ts +++ b/src/pcb/pcb_trace.ts @@ -1,38 +1,112 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" - -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(), - }), - ]), - ), +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 type PCBTraceInput = z.input -export type PCBTrace = z.output +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"), + 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 +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 + */ +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 +} + +/** + * @deprecated use PcbTrace + */ +export type PCBTrace = PcbTrace + +/** + * @deprecated use PcbTraceInput + */ +export type PCBTraceInput = PcbTraceInput + +expectTypesMatch(true) +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..5f31c42 100644 --- a/src/pcb/pcb_trace_hint.ts +++ b/src/pcb/pcb_trace_hint.ts @@ -1,16 +1,35 @@ 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" +import { expectTypesMatch } from "src/utils/expect-types-match" + +/** + * A hint that can be used during generation of 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()), + 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 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..af87999 100644 --- a/src/pcb/pcb_via.ts +++ b/src/pcb/pcb_via.ts @@ -1,10 +1,13 @@ import { z } from "zod" -import { distance } from "../units" -import { layer_ref } from "./properties/layer_ref" +import { distance, type Distance } from "src/units" +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 .object({ type: z.literal("pcb_via"), + pcb_via_id: getZodPrefixedIdWithDefault("pcb_via"), x: distance, y: distance, outer_diameter: distance.default("0.6mm"), @@ -17,5 +20,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) 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