seveibar/am3352-dev-board-4layer-dogbone

Defines PCB footprints and pin mappings for a TI AM3352ZCZ100 processor, JST GH connectors, and assembly-part lookup helpers for capacitors, resistors, and headers.

Version
0.1.5
License
unset
Stars
0

scripts/patch-endpoint-inference.mjs

/** Fix @tscircuit/checks endpoint inference: matching XY is insufficient across layers/nets. */
import fs from 'node:fs'
const replacement = `var addStartAndEndPortIdsIfMissing = (soup) => {
  // layerNetSafeEndpointTags: keep inferred contacts on the correct electrical net and layer.
  const parent = new Map();
  const find = (id) => { if (!parent.has(id)) parent.set(id,id); const p=parent.get(id); if(p!==id) parent.set(id,find(p)); return parent.get(id); };
  const join = (ids) => { const clean=ids.filter(Boolean); for(const id of clean.slice(1)) parent.set(find(id),find(clean[0])); };
  for(const e of soup) {
    if(e.type==='source_trace') join([e.source_trace_id,...(e.connected_source_port_ids||[]),...(e.connected_source_net_ids||[])]);
    if(e.type==='source_component') for(const ids of e.internally_connected_source_port_ids||[]) join(ids);
  }
  const ports=soup.filter(e=>e.type==='pcb_port');
  const pads=soup.filter(e=>e.type==='pcb_smtpad');
  const through=new Set(soup.filter(e=>e.type==='pcb_plated_hole').map(e=>e.pcb_port_id));
  const portById=new Map(ports.map(p=>[p.pcb_port_id,p]));
  const findContact=(point,trace,endpoint)=>{
    if(!trace.source_trace_id) return null;
    const root=find(trace.source_trace_id);
    const eligible=(p)=>p && find(p.source_port_id)===root && ((p.layers||[]).includes(point.layer)||through.has(p.pcb_port_id));
    const direct=ports.find(p=>eligible(p)&&Math.hypot(p.x-point.x,p.y-point.y)<.01);
    if(direct) return direct.pcb_port_id;
    if(!endpoint) return null;
    const pad=pads.find(p=>{
      if(p.layer!==point.layer||!eligible(portById.get(p.pcb_port_id)))return false;
      const dx=point.x-p.x,dy=point.y-p.y;
      if(p.shape==='circle')return Math.hypot(dx,dy)<p.radius;
      if(p.shape==='rect'||p.shape==='rotated_rect'){
        const a=-(p.ccw_rotation||0)*Math.PI/180;
        return Math.abs(dx*Math.cos(a)-dy*Math.sin(a))<p.width/2 && Math.abs(dx*Math.sin(a)+dy*Math.cos(a))<p.height/2;
      }
      return false;
    });
    return pad?.pcb_port_id||null;
  };
  for(const trace of soup.filter(e=>e.type==='pcb_trace')) {
    for(let i=0;i<trace.route.length;i++) {
      const p=trace.route[i]; if(p.route_type!=='wire')continue;
      if(i===0&&!p.start_pcb_port_id){const id=findContact(p,trace,true);if(id)p.start_pcb_port_id=id;}
      if(i===trace.route.length-1&&!p.end_pcb_port_id){const id=findContact(p,trace,true);if(id)p.end_pcb_port_id=id;}
    }
  }
};`;
const files=['node_modules/@tscircuit/checks/dist/index.js','node_modules/@tscircuit/cli/dist/cli/main.js','node_modules/@tscircuit/cli/dist/lib/index.js'];
let patched=0;
for(const file of files){
 if(!fs.existsSync(file))continue;
 const source=fs.readFileSync(file,'utf8');
 if(source.includes('layerNetSafeEndpointTags'))continue;
 const start=source.indexOf('var addStartAndEndPortIdsIfMissing = ');
 if(start<0)continue;
 const end=source.indexOf('\n};',start)+3;
 if(end<start)throw Error('Unrecognized endpoint helper in '+file);
 fs.writeFileSync(file,source.slice(0,start)+replacement+source.slice(end));patched++;
}
if(!fs.readFileSync(files[0],'utf8').includes('layerNetSafeEndpointTags'))throw Error('Endpoint inference patch was not installed');
console.log('Layer/net-aware endpoint inference installed:',patched,'files patched');