UNPKG

yarn-audit-fix

Version:
12 lines (9 loc) 12 kB
#!/usr/bin/env node import xe from"node:process";import{Command as ot,Option as T}from"commander";import{join as Qe}from"node:path";import et from"chalk";import{dirname as Ke,join as c,relative as ze}from"node:path";import l from"fs-extra";import k from"semver";import de from"synp";import A from"semver";import X from"@yarnpkg/lockfile";import{keyBy as Me}from"lodash-es";import be from"node:crypto";import{createRequire as Fe}from"node:module";import v,{dirname as _e,resolve as Se}from"node:path";import{fileURLToPath as we}from"node:url";import Le from"node:os";import Ae from"chalk";import S from"fs-extra";import Oe from"fast-glob";import N from"js-yaml";import{reduce as je}from"lodash-es";var Re=Oe.sync,Ee=Fe(import.meta.url)("child_process"),{ensureDirSync:Ce,readFileSync:Ye}=S,De=_e(we(import.meta.url)),u=(e,t,o,n=!1,r=!0,s=!1)=>{!n&&console.log(Ae.bold("invoke"),e,...t);let i=r?["inherit","inherit","inherit"]:[null,null,null],a=Ee.spawnSync(e,t,{cwd:o,stdio:i,shell:!0});if(!s&&(a.error||a.status))throw a;return String(a.stdout?.toString().trim())},$e=(e,t,o,n)=>t!=="false"&&!o.includes(e)&&(n.length===0||n.includes(e)),Pe=e=>(e.length===1?"-":"--")+e,Ne=e=>e.replace(/([\da-z]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),V=e=>Object.keys(e).reduce((t,o)=>(t[Ne(o)]=e[o],t),{}),g=(e,...t)=>Object.keys(e).reduce((o,n)=>{let r=["_","--"],s=e[n],i=Pe(n);return $e(n,s,r,t)&&(Array.isArray(s)?s.forEach(a=>{o.push(i,String(a))}):(o.push(i),s!==!0&&o.push(String(s)))),o},[]),x=(e,t)=>je(e,(o,n,r)=>{let s=t[r],i=r,a=n;return s&&(typeof s=="string"?i=s:(i=s?.key??i,a=s?.value??s?.values?.[n]??a)),o[i]=a,o},{}),w=()=>process.platform==="win32"||/^(msys|cygwin)$/.test(process.env.OSTYPE),I=e=>e||(w()?"junction":"dir"),M=()=>w()?"yarn.cmd":"yarn",Ve=e=>z(`./node_modules/.bin/${e}`),G=(e="system",t=w())=>{let o=t?"npm.cmd":"npm";return e==="system"?o:e==="local"?Ve(o):e},B=(e,t)=>{let o=t.workspaces;return o&&o.packages&&(o=o.packages),!o||o.length===0?[]:Re(o.map(n=>n.replace(/\/?$/,"/package.json")),{cwd:e,onlyFiles:!0,absolute:!0,gitignore:!0})},L=e=>JSON.parse(Ye(e).toString("utf-8").trim()),Ie=e=>(Ce(e),e),U=(e,t)=>t?Ie(Se(e,t)):S.mkdtempSync(v.join(Le.tmpdir(),`tempy-${be.randomBytes(16).toString("hex")}`)),J=e=>{try{return e()}catch{return null}},W=e=>{try{return N.load(e)}catch(t){throw new Error(`YAML required: ${t}`)}},q=N.dump,b=(e,t=process.cwd())=>u(e,["--version"],t,!0,!1),F=()=>L(z("package.json")),H=(e,t,o)=>Object.defineProperty(e,t,{value:o,enumerable:!1}),K=(e,t)=>{if(S.existsSync(v.join(e,t)))return e;let o=v.resolve(e,"..");return e===o?null:K(o,t)},z=(e,t=De)=>{let o=K(t,e);return o?v.join(o,e):null},Z=e=>e&&Object.keys(e).sort((t,o)=>t.localeCompare(o)).reduce((t,o)=>(t[o]=e[o],t),Object.create(null));var Q=e=>{let t=X.parse(e);if(t.type!=="success")throw new Error("Merge conflict in yarn lockfile, aborting");return t.object},ee=(e,t,o)=>(e.version=o,e.dependencies={},e.integrity="",e.resolved="",e),te=e=>X.stringify(e),oe=(e,t,o)=>{let n=e.reporter==="npm"?o.npm:o.yarn,s=g(x(e,{"audit-level":"level",only:{key:"groups",values:{prod:"dependencies",dev:"devDependencies"}}}),"groups","verbose","level"),i=u(n,["audit","--json",...s],t,!!e.silent,!1,!0);return Ge(i)},Ge=e=>Me(e.toString().split(` `).map(t=>J(()=>JSON.parse(t))).map(t=>t?.data?.advisory).filter(t=>t!==void 0).map(t=>({module_name:t.module_name,vulnerable_versions:t.vulnerable_versions,patched_versions:t.patched_versions})),t=>t.module_name);var ne=e=>{let t=W(e),{__metadata:o}=t;return delete t.__metadata,Object.entries(t).reduce((n,[r,s])=>(r.split(", ").forEach(i=>{n[i]=s}),n),H({},"__metadata",o))},re=(e,t,o,n)=>(e.version=o,e.resolution=`${t}@npm:${o}`,e.dependencies=Z(JSON.parse(u(n,["view",`${t}@${o}`,"dependencies","--json"],process.cwd(),!0,!1)||"null")||void 0),delete e.checksum,e),se=e=>{let t=Object.entries(e).reduce((n,[r,{resolution:s}])=>((n[s]||(n[s]=[])).push(r),n),{}),o=Object.values(e).reduce((n,r)=>{let s=t[r.resolution].join(", ");return n[s]=r,n},{__metadata:e.__metadata||{version:5,cacheKey:8}});return`# This file is generated by running "yarn install" inside your project. # Manual changes might be lost - proceed with caution! ${q(o,{quotingType:'"',flowLevel:-1,lineWidth:-1}).replace(/\n([^\s"].+):\n/g,` "$1": `).replace(/\n(\S)/g,` $1`).replace(/resolution: ([^\n"]+)/g,'resolution: "$1"')}`},ie=(e,t,o)=>{let r=g(x(e,{"audit-level":"severity",level:"severity",groups:{key:"environment",values:{dependencies:"production"}},only:{key:"environment",values:{prod:"production"}}}),"exclude","ignore","groups","verbose"),s=u(o.yarn,["npm","audit","--all","--json","--recursive",...r],t,!!e.silent,!1,!1);return Be(s)},Be=e=>Object.values(JSON.parse(e).advisories).reduce((t,{vulnerable_versions:o,module_name:n,patched_versions:r})=>(t[n]={patched_versions:r,vulnerable_versions:o,module_name:n},t),{});var ae=e=>{if(e.includes("yarn lockfile v1"))return"yarn1";if(e.includes("__metadata"))return"yarn2"},Ue=(e,t)=>{if(t===void 0)throw new Error("Unsupported lockfile format");return t==="yarn2"?ne(e):Q(e)},Je=(e,t)=>t==="yarn2"?se(e):te(e),We=(e,t,{flags:o,bins:n},r)=>{if(Object.keys(t).length===0)return!o.silent&&console.log("Audit check found no issues"),e;let s=[];for(let i of Object.keys(e)){let[,a,h]=/^(@?[^@]+)@(?:\w+:)?(.+)$/.exec(i)||[],d=t[a];if(!d)continue;let m=e[i];if(A.satisfies(m.version,d.vulnerable_versions)){let y=A.minVersion(d.patched_versions)?.format();if(y===void 0){console.error("Can't find satisfactory version for",d.module_name,d.patched_versions);continue}if(!A.satisfies(y,h)&&!o.force){console.error("Can't find patched version that satisfies",i,"in",d.patched_versions);continue}s.push(`${a}@${y}`),r==="yarn1"?ee(m,a,y):re(m,a,y,n.npm)}}return!o.silent&&console.log("Upgraded deps:",s.length>0?s.join(", "):"<none>"),e},qe=({flags:e,temp:t,bins:o},n)=>n==="yarn2"?ie(e,t,o):oe(e,t,o),_={_parse:Ue,_audit:qe,_patch:We,_format:Je},ce=(...e)=>_._parse(...e),le=(...e)=>_._audit(...e),pe=(...e)=>_._patch(...e),ue=(...e)=>_._format(...e);var O=({ctx:e,flags:t})=>{let o=F();e.bins={yarn:M(),npm:G(t["npm-path"])},e.versions={node:b("node"),npm:b(e.bins.npm),yarn:b(e.bins.yarn),yaf:o.version,yafLatest:u(e.bins.npm,["view",o.name,"version"],process.cwd(),!0,!1)}},j=({temp:e,cwd:t,flags:o,bins:n,versions:r,manifest:s})=>{if(o.silent)return;let i=!!s.workspaces;i&&k.parse(r.npm)?.major<7&&console.warn("This project looks like monorepo, so it's recommended to use `npm v7+` to process workspaces"),k.gt("3.3.0",r.yarn)&&(o.exclude||o.ignore)&&console.warn(`This project yarn version ${r.yarn} doesn't support the 'exclude' and 'ignore' flags. Please upgrade to yarn 3.3.0 or higher to use those flags`),k.gt(r.yafLatest,r.yaf)&&console.warn(`yarn-audit-fix version ${r.yaf} is out of date. Install the latest ${r.yafLatest} for better results`),console.log(JSON.stringify({isMonorepo:i,bins:n,versions:r,temp:e,cwd:t,flags:o},void 0,2).replace(/[",:{}]/g,""))},R=({cwd:e,temp:t})=>{l.copyFileSync(c(e,"yarn.lock"),c(t,"yarn.lock")),l.copyFileSync(c(e,"package.json"),c(t,"package.json")),l.existsSync(c(e,".npmrc"))&&l.copyFileSync(c(e,".npmrc"),c(t,".npmrc")),l.existsSync(c(e,".yarnrc"))&&l.copyFileSync(c(e,".yarnrc"),c(t,".yarnrc"))},E=({temp:e,flags:t,cwd:o,manifest:n})=>{let r=I(t.symlink),s=B(o,n);[c(o,"node_modules"),c(o,".yarn"),...s.map(a=>Ke(a))].forEach(a=>{let h=ze(o,a),d=c(o,h),m=c(e,h);l.existsSync(d)&&l.createSymlinkSync(d,m,r)})},ge=({temp:e,flags:t})=>{let o=de.yarnToNpm(e,!0);l.writeFileSync(c(e,"package-lock.json"),o),t.flow!=="patch"&&l.removeSync(c(e,"yarn.lock"))},fe=({temp:e,flags:t,bins:o})=>{let s=["audit","fix",...g({...{"package-lock-only":!0},...t},"audit-level","dry-run","exclude","force","ignore","loglevel","legacy-peer-deps","only","package-lock-only","registry","silent","verbose"),"--prefix",e];u(o.npm,s,e,t.silent)},me=({temp:e})=>{let t=de.npmToYarn(e,!0);l.writeFileSync(c(e,"yarn.lock"),t)},C=({temp:e,flags:t})=>{t.dryRun||l.copyFileSync(c(e,"yarn.lock"),"yarn.lock")},Y=({cwd:e,flags:t,versions:o,bins:n})=>{t.dryRun||(k.gte(o.yarn,"2.0.0")?u(n.yarn,["install","--mode=update-lockfile"],e,t.silent):u(n.yarn,["install","--update-checksums",...g(t,"verbose","silent","registry","ignore-engines")],e,t.silent))},f=({temp:e})=>l.emptyDirSync(e),D=({flags:e,err:t})=>{!e.silent&&console.error(t),process.exitCode=t?.status|0||1},ye=({temp:e,ctx:t})=>{let o=c(e,"yarn.lock"),n=l.readFileSync(o,"utf-8"),r=ae(n),s=ce(n,r),i=le(t,r),a=pe(s,i,t,r);l.writeFileSync(o,ue(a,r))},$=({cwd:e,versions:t,flags:o})=>{let n=["yarn.lock","package.json"];(o.flow==="convert"||k.lt(t.yarn,"2.0.0"))&&n.push("node_modules"),n.forEach(r=>{if(!l.existsSync(c(e,r)))throw new Error(`not found: ${r}`)})};var Ze={main:["Resolve bins",O,"Runtime digest",j,"Verifying package structure...",$,"Preparing temp assets...",f,R,E,"Generating package-lock.json from yarn.lock...",ge,"Applying npm audit fix...",fe,["Updating yarn.lock from package-lock.json...",me,C,f],"Installing deps update...",Y,"Done"],fallback:["Failure!",f,D]},Xe={main:["Resolve bins",O,"Runtime digest",j,"Verifying package structure...",$,"Preparing temp assets...",f,R,E,["Patching yarn.lock with audit data...",ye,C,f],"Installing deps update...",Y,"Done"],fallback:["Failure!",f,D]},ke=(e="patch")=>{if(e==="convert")return Ze;if(e==="patch")return Xe;throw new Error(`Unsupported flow: ${e}`)};var tt=(e={})=>{let t=e.cwd||process.cwd(),o=L(Qe(t,"package.json")),n=U(t,e.temp),r={cwd:t,temp:n,flags:e,manifest:o,versions:{},bins:{}};return r.ctx=r,r},Te=(e,t)=>{for(let o of e.flat(5))typeof o=="string"?!t.flags.silent&&console.log(et.bold(o)):typeof o=="function"&&o(t)},he=(e={},t)=>{if(e.V){console.log(F().version);return}let o=V(e),n=tt(o),r=t||ke(o.flow);try{Te(r.main,n)}catch(s){throw n.err=s,!o.silent&&console.error(s.stderr?.toString?.()||s.stdout?.toString?.()||s.error||s.status||s),Te(r.fallback,n),s}},P=(e={},t)=>new Promise((o,n)=>{try{he(e,t),o()}catch(r){n(r)}});P.sync=he;var ve=(e,t)=>t?[t,e].flat():e,p=xe.env,nt=new ot().addOption(new T("--audit-level [level]","Include only vulnerabilities with the specified level or higher").choices(["low","moderate","high","critical"]).default(p.YAF_AUDIT_LEVEL)).option("--cwd [path]","CWD. Defaults to `process.cwd()`",p.YAF_CWD).option("--dry-run [bool]","Get an idea of what audit fix will do",p.YAF_DRY_RUN).option("--exclude <path>","Array of glob patterns of packages to exclude from audit",ve,p.YAF_EXCLUDE).addOption(new T("--flow [flow]","Define how `yarn.lock` is modified").choices(["convert","patch"]).default(p.YAF_FLOW||"patch")).option("--force [bool]","Have audit fix install semver-major updates to toplevel dependencies, not just semver-compatible ones",p.YAF_FORCE).option("--ignore <id>","Array of glob patterns of advisory IDs to ignore in the audit report",ve,p.YAF_IGNORE).option("--ignore-engines [bool]","Ignore engines check",p.YAF_IGNORE_ENGINES).option("--loglevel [level]","Set custom log level",p.YAF_LOGLEVEL).option("--legacy-peer-deps [bool]","Accept an incorrect (potentially broken) deps resolution",p.YAF_LEGACY_PEER_DEPS).addOption(new T("--npm-path [path]","Switch to system default version of npm instead of package's own.").choices(["system","local"]).default(p.YAF_NPM_PATH||"system")).addOption(new T("--only [scope]","Set package updating scope").choices(["prod","dev"]).default(p.YAF_ONLY)).option("--package-lock-only [bool]","Run audit fix without modifying `node_modules`.",p.YAF_PACKAGE_LOCK_ONLY).option("--registry [registry]","Custom registry url",p.YAF_REGISTRY).option("--silent [bool]","Disable log output",p.YAF_SILENT).addOption(new T("--symlink","Define symlink type for `node_modules` assets").choices(["junction","dir"])).option("--temp [dir]","Directory for temporary assets").option("--verbose [bool]","Switch log level to verbose/debug",p.YAF_VERBOSE).option("--version, -v","Print current yarn-audit-fix version").allowUnknownOption().parse(xe.argv).opts();P.sync(nt); //# sourceMappingURL=cli.mjs.map