AnasSarkiz/ble-pedometer

This code defines and configures various electronic hardware components such as surface-mount resistors, crystals, diodes, transistors, connectors, and switches with their physical footprints, schematic symbols, and 3D CAD models for PCB assembly.

Version
1.0.7
License
unset
Stars
0

lib/get-fabrication-blockers.ts

import { pcb_via } from "circuit-json"
import { z } from "zod"

// Validate the envelope plus the geometry this gate consumes. Unrelated render
// metadata is intentionally not a fabrication rule (for example font styling).
const circuitGeometryEnvelope = z.array(z.object({ type: z.string() }).passthrough())

/** Geometry gate only; this does not certify RF, assembly, or electrical safety. */
export function getFabricationBlockers(circuitJson: unknown) {
  const blockers: string[] = []
  const envelope = circuitGeometryEnvelope.safeParse(circuitJson)
  if (!envelope.success) return ["Invalid Circuit JSON element array"]
  const elements = envelope.data
  const board = elements.find((element) => element.type === "pcb_board")
  if (!board || board.num_layers !== 4) {
    blockers.push("Expected the four-layer pedometer board")
  }
  if (!elements.some((element) => element.type === "pcb_trace")) {
    blockers.push("No routed PCB traces: placement-only output is not fabrication-ready")
  }
  for (const element of elements) {
    if (element.type.endsWith("_error")) {
      blockers.push(`Unresolved ${element.type}`)
    }
    if (element.type !== "pcb_via") continue
    const parsedVia = pcb_via.safeParse(element)
    if (!parsedVia.success) {
      blockers.push(`Invalid via geometry: ${parsedVia.error.issues.map((issue) => issue.path.join(".")).join(", ")}`)
      continue
    }
    const via = parsedVia.data
    if (!Number.isFinite(via.hole_diameter) || via.hole_diameter < 0.3) {
      blockers.push(`${via.pcb_via_id}: hole must be at least 0.30 mm`)
    }
    if (!Number.isFinite(via.outer_diameter) || via.outer_diameter < 0.45) {
      blockers.push(`${via.pcb_via_id}: pad must be at least 0.45 mm`)
    }
    if (via.outer_diameter <= via.hole_diameter) {
      blockers.push(`${via.pcb_via_id}: missing annular ring`)
    }
    const copperLayers = ["top", "inner1", "inner2", "bottom"]
    if (copperLayers.some((layer) => !via.layers.some((viaLayer) => viaLayer === layer))) {
      blockers.push(`${via.pcb_via_id}: not a full-stack through via`)
    }
    // circuit-json-to-gerber >=0.0.104 drills the physical layers, not legacy
    // routing transition endpoints. Actual exported spans are checked separately
    // by getManufacturingReview; do not use the old bundled tsci export command.
  }
  return blockers
}