imrishabh18/nema-23-stepper-controller
A four-layer NEMA23 stepper motor controller PCB featuring an RP2040 MCU, DRV8452 dual-phase driver, USB‑C PD power input/protection, current and temperature sensing, status LED/buzzer, and optional magnetic encoder.
- Version
- 1.3.2
- License
- unset
- Stars
- 1
scripts/check-schematic-source.mjs
import ts from 'typescript'
import {readFileSync,readdirSync} from 'node:fs'
import {createHash} from 'node:crypto'
import assert from 'node:assert/strict'
const {nativeChipSymbols,nativeConnectorSymbols=[]}=JSON.parse(readFileSync('engineering/schematic-style.json'))
const files=['index.circuit.tsx','usb-pd-power.tsx','feature-parity.tsx','passives.tsx','schematic-section-notes.ts','usb-c-compat.ts','vendor/rp2040.js',...readdirSync('imports').filter(f=>f.endsWith('.tsx')).map(f=>'imports/'+f)]
for(const file of files){
const source=readFileSync(file,'utf8'),ast=ts.createSourceFile(file,source,ts.ScriptTarget.Latest,true,file.endsWith('.tsx')?ts.ScriptKind.TSX:ts.ScriptKind.JS)
function visit(n){
if(ts.isJsxAttribute(n)||ts.isPropertyAssignment(n)){
const key=n.name.getText(ast).replace(/["']/g,'')
assert.ok(!['schX','schY','schPinArrangement','schPinStyle'].includes(key),`${file}: fixed schematic placement ${key}`)
}
ts.forEachChild(n,visit)
}
visit(ast)
if(file.startsWith('imports/')) {
if([...nativeChipSymbols,...nativeConnectorSymbols].includes(file.split('/').at(-1).replace('.tsx','')))assert.ok(!/symbol=/.test(source),`${file}: IC or standard connector must use native styling`)
else assert.match(source,/symbol=\{\w+Symbol as CircuitJson\}/,`${file}: imported symbol is not used`)
}
}
for(const name of [...nativeChipSymbols,...nativeConnectorSymbols])assert.ok(!readFileSync('vendor/rp2040.js','utf8').includes(`symbol: ${name}Symbol`),`Vendored ${name}: imported IC symbol remains`)
const manifest=JSON.parse(readFileSync('engineering/easyeda/manifest.json'))
const flashLabels=JSON.parse(readFileSync('imports/pin-labels/W25Q16JVUXIQ.json'))
const flashImport=JSON.parse(readFileSync('engineering/easyeda/pin-labels-manifest.json'))
assert.equal(flashImport.converter,JSON.parse(readFileSync('package.json')).devDependencies.easyeda)
for(const [path,hash] of [['engineering/easyeda/C2843335.raweasy.json',flashImport.sourceSha256],['imports/pin-labels/W25Q16JVUXIQ.json',flashImport.pinLabelsSha256]])assert.equal(createHash('sha256').update(readFileSync(path)).digest('hex'),hash,`Regenerate flash labels: ${path}`)
assert.deepEqual(Object.values(flashLabels).map(labels=>labels[0]),['N_CS','DO_IO1','WP__IO2','GND','DI_IO0','CLK','HOLD_orRESET__IO3','VCC','EP'])
assert.match(readFileSync('vendor/rp2040.js','utf8'),/\.\.\.W25Q16JVUXIQPinLabels/,'Vendored flash must use the regenerated labels')
for(const [name,part] of Object.entries(manifest.parts)){
for(const [path,hash] of [[`engineering/easyeda/${part.lcsc}.raweasy.json`,part.sourceSha256],[`imports/symbols/${name}.tsx`,part.symbolSha256],[`imports/symbols/${name}.json`,part.circuitSymbolSha256]])assert.equal(createHash('sha256').update(readFileSync(path)).digest('hex'),hash,`Regenerate EasyEDA symbol: ${path}`)
const symbol=JSON.parse(readFileSync(`imports/symbols/${name}.json`))
assert.ok(symbol.some(e=>e.type==='schematic_port'),`${name}: missing symbol pins`)
assert.ok(symbol.some(e=>['schematic_path','schematic_rect','schematic_circle','schematic_line'].includes(e.type)),`${name}: missing artwork`)
}
console.log(`PASS: no fixed schematic component positions; ${Object.keys(manifest.parts).length} reproducible non-IC EasyEDA symbols; native yellow IC boxes and standard USB-C connectors.`)