UNPKG

@donedeal0/codefather

Version:

Codefather protects your codebase by controlling who can change what. Set authorization levels, lock down files, and enforce your rules—offline via CLI or online with GitHub Actions.

11 lines (9 loc) • 3.07 kB
#!/usr/bin/env node import g from'fs';import m from'path';var s={success:"\x1B[32m",error:"\x1B[31m",warning:"\x1B[33m",info:"\x1B[37m"};function w(e){try{return JSON.parse(e)}catch{throw new Error("Your codefather.json file is invalid. You gotta respect the rules if you want my help.")}}function b(e){return e.startsWith("@")&&e.includes("/")}function x(e){let o=e.replace(/^@/,"").split("/");return o.length>1?o[1]:o[0]||e}function y(e){return e.replace(/^@+/,"").split("/")[0]||e}async function R(e){let t=(await g.promises.readFile(e,"utf-8")).split(` `),r=new Map;for(let d of t){let u=d.trim();if(u.startsWith("#"))continue;let[i,...n]=u.split(/\s+/);if(i&&n.length>0){let a=n.sort().join(",");if(!r.has(a))r.set(a,[i]);else {let c=r.get(a)||[];r.set(a,[...c,i]);}}}let l=[];for(let[d,u]of r.entries()){let i=[],n=[];d.split(",").forEach(a=>{let c=a.trim();b(c)?i.push(x(c)):n.push({name:y(c)});}),l.push({match:u,goodfellas:n,...i.length>0?{crews:i}:{}});}return l}function S(e,o){return {rules:e,codeReviews:{autoAssignGoodfellas:true},crews:o.reduce((t,r)=>({...t,[r]:[]}),{})}}async function C(e){try{let o=await R(e),t=[...new Set(o.flatMap(r=>r.crews).filter(Boolean))];return {config:S(o,t),crews:t}}catch{throw new Error("\u{10102} Your CODEOWNER file is invalid.")}}function O(e,o,t,r){r?console.log(s.info,`- A new ${e} config file has been created, your former config was overwritten.`):console.log(s.info,`- A ${e} config file has been created.`),o&&(console.log(s.info,"- The rules were filled with your CODEOWNER file."),t?.length>0&&console.log(s.warning,`- The following crews were detected: ${t.map(l=>` - ${l}`).join(` `)} \u2699\uFE0F Please specify their members in the codefather config for CLI enforcement. `));}async function j(){try{let e=process.argv.slice(2),o=e.includes("json"),t=e.includes("overwrite"),r=process.cwd(),l=m.join(r,"./.github/CODEOWNERS"),d={rules:[]},u=!1,i=[];if(g.existsSync(l)){let f=await C(l);d=f.config,u=!0,i.push(...f.crews);}let n=m.join(r,o?"codefather.json":"codefather.ts"),a=m.join(r,"package.json"),c=JSON.stringify(d,null,2);if(!g.existsSync(n)||t?(o?g.writeFileSync(n,c):g.writeFileSync(n,`import type { CodefatherConfig } from "@donedeal0/codefather"; export default ${c} satisfies CodefatherConfig; `),O(m.basename(n),u,i,t)):console.log(s.info,`- A ${m.basename(n)} file already exists.`),g.existsSync(a)){let f=w(g.readFileSync(a,"utf-8"));f.scripts=f.scripts||{},f.scripts.codefather?console.log(s.info,"- A codefather script already exists in your package.json."):(f.scripts.codefather="codefather",g.writeFileSync(a,JSON.stringify(f,null,2)),console.log(s.info,"- A codefather script has been added to your package.json."));}else return console.log(s.error,"\u26A0 No package.json found in the project root. Skipping script setup.");return console.log(s.success,"\n\u2713 Setup complete. Run `npm run codefather` to enforce your rules.")}catch(e){return console.log(s.error,e instanceof Error?e.message:String(e))}}import.meta.url===new URL(import.meta.url).href&&j();export{j as runInit};