MustafaMulla29/stride-pedometer

This code defines schematic symbols and 3D footprints for various hardware components such as antennas, sensors, regulators, and connectors used in electronic circuit design.

Version
1.0.4
License
unset
Stars
0

scripts/export-review.ts

import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
import { resolve } from 'node:path'

// Run from the project root after tsci build. CSV coordinates share the
// circuit.json origin at board center; verify rotations with the assembler.
const data = JSON.parse(readFileSync('dist/index/circuit.json', 'utf8')) as any[]
const source = readFileSync('index.circuit.tsx', 'utf8')
const customRoutingCallback = /\balgorithmFn\s*[:=]/.test(source)
const explicitViaElements = (source.match(/<via(?=[\s/>])/g) ?? []).length
const routingPhases = [...source.matchAll(/<autoroutingphase\b[^>]*\bname="([^"]+)"/g)].map(m => m[1])
const runtimeVersions = Object.fromEntries(['tscircuit','@tscircuit/core','@tscircuit/capacity-autorouter'].map(name => [name,
  JSON.parse(readFileSync(`node_modules/${name}/package.json`, 'utf8')).version]))
const rows = [...source.matchAll(/\['([CRL]\d+)','([^']*)','([^']*)','([^']*)',([^\]]+)\]/g)]
const passive = new Map(rows.map(m => [m[1], {
  value: m[2], footprint: m[3], lcsc: m[4], dnp: m[5].includes('true')
}]))
const packages: Record<string, string> = {
  U1:'QFN-40-EP 5x5mm 0.4mm', U2:'DSBGA-20 0.4mm', U3:'DSBGA-9 0.5mm',
  U4:'LGA-12 2x2mm', U5:'SOT-23-5', U6:'DSBGA-6 0.4mm',
  DS1:'FPC-14 0.62mm, hand install', ANT1:'1206 antenna',
  Y1:'3225-4 crystal', Y2:'3215-2 crystal', SW1:'TS-1088', D1:'X2SON-2',
}
const pcbs = new Map(data.filter(x => x.type==='pcb_component').map(x => [x.source_component_id,x]))
const sorted = data.filter(x => x.type==='source_component')
  .sort((a,b)=>a.name.localeCompare(b.name,undefined,{numeric:true}))
const quote = (x:unknown)=>`"${String(x??'').replace(/"/g,'""')}"`
const csv = (table:unknown[][])=>table.map(r=>r.map(quote).join(',')).join('\n')+'\n'
const bom:unknown[][]=[['Designator','Value / MPN','Footprint','LCSC Part','Assembly']]
const jlc:unknown[][]=[['Comment','Designator','Footprint','LCSC Part #']]
const pnp:unknown[][]=[['Designator','Mid X','Mid Y','Layer','Rotation']]
for(const c of sorted){
  const p=passive.get(c.name)
  const lcsc=p?.lcsc??c.supplier_part_numbers?.jlcpcb?.[0]??''
  const value=p?.value??c.manufacturer_part_number??'Copper contact'
  const footprint=packages[c.name]??p?.footprint??'PCB copper'
  const assembly=p?.dnp?'DNP':c.name==='DS1'?'HAND INSTALL':lcsc?'PCBA':'PCB FEATURE'
  bom.push([c.name,value,footprint,lcsc,assembly])
  if(assembly!=='PCBA')continue
  jlc.push([value,c.name,footprint,lcsc])
  const pc=pcbs.get(c.source_component_id)
  if(!pc)throw new Error(`Missing placement: ${c.name}`)
  pnp.push([c.name,`${pc.center.x.toFixed(4)}mm`,`${pc.center.y.toFixed(4)}mm`,pc.layer,pc.rotation??0])
}
mkdirSync('review',{recursive:true})
writeFileSync('review/bom-all.csv',csv(bom))
writeFileSync('review/jlcpcb-bom.csv',csv(jlc))
writeFileSync('review/placement-review.csv',csv(pnp))
const errors=data.filter(x=>x.type.endsWith('_error'))
const warnings=data.filter(x=>x.type.endsWith('_warning'))
const count=(items:any[])=>items.reduce((a,x)=>(a[x.type]=(a[x.type]??0)+1,a),{} as Record<string,number>)
writeFileSync('review/validation.json',JSON.stringify({
  fabricationReleased:false,
  routingEngine:customRoutingCallback?'custom callback':/\bautorouterVersion\s*=/.test(source)?'configured built-in version':'tscircuit default built-in autorouter',
  customRoutingCallback,
  explicitViaElements,
  routingPhases,
  runtimeVersions,
  note:'Engineering review outputs. Release also requires fabricator stackup/DFM, footprint and RF review, plus physical verification.',
  sourceComponents:sorted.length,pcbaPlacements:pnp.length-1,
  traces:data.filter(x=>x.type==='pcb_trace').length,
  generatedViaRecords:data.filter(x=>x.type==='pcb_via').length,
  errorCounts:count(errors),warningCounts:count(warnings),errors,warnings
},null,2)+'\n')
console.log(`Exported ${bom.length-1} design items, ${pnp.length-1} PCBA placements; ${errors.length} circuit errors.`)
console.log(resolve('review'))