@visulima/vis 1.0.0-alpha.10 → 1.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +95 -42
- package/LICENSE.md +213 -0
- package/README.md +8 -4
- package/dist/bin.js +9 -1
- package/dist/config/index.d.ts +1818 -0
- package/dist/config/index.js +2 -0
- package/dist/generate/index.d.ts +1 -1
- package/dist/generate/index.js +3 -1
- package/dist/packem_chunks/applyDefaults.js +336 -0
- package/dist/packem_chunks/bin.js +9554 -64
- package/dist/packem_chunks/doctor-probe.js +112 -0
- package/dist/packem_chunks/fix.js +229 -48
- package/dist/packem_chunks/handler.js +99 -1
- package/dist/packem_chunks/handler10.js +53 -1
- package/dist/packem_chunks/handler11.js +32 -1
- package/dist/packem_chunks/handler12.js +100 -2
- package/dist/packem_chunks/handler13.js +25 -1
- package/dist/packem_chunks/handler14.js +916 -5
- package/dist/packem_chunks/handler15.js +206 -1
- package/dist/packem_chunks/handler16.js +122 -18
- package/dist/packem_chunks/handler17.js +13 -1
- package/dist/packem_chunks/handler18.js +106 -1
- package/dist/packem_chunks/handler19.js +19 -1
- package/dist/packem_chunks/handler2.js +75 -1
- package/dist/packem_chunks/handler20.js +29 -1
- package/dist/packem_chunks/handler21.js +222 -1
- package/dist/packem_chunks/handler22.js +237 -5
- package/dist/packem_chunks/handler23.js +101 -1
- package/dist/packem_chunks/handler24.js +110 -1
- package/dist/packem_chunks/handler25.js +402 -5
- package/dist/packem_chunks/handler26.js +13 -1
- package/dist/packem_chunks/handler27.js +63 -3
- package/dist/packem_chunks/handler28.js +34 -1
- package/dist/packem_chunks/handler29.js +458 -7
- package/dist/packem_chunks/handler3.js +95 -2
- package/dist/packem_chunks/handler30.js +168 -21
- package/dist/packem_chunks/handler31.js +530 -3
- package/dist/packem_chunks/handler32.js +214 -2
- package/dist/packem_chunks/handler33.js +119 -24
- package/dist/packem_chunks/handler34.js +630 -2
- package/dist/packem_chunks/handler35.js +283 -19
- package/dist/packem_chunks/handler36.js +521 -407
- package/dist/packem_chunks/handler37.js +762 -22
- package/dist/packem_chunks/handler38.js +989 -22
- package/dist/packem_chunks/handler39.js +574 -22
- package/dist/packem_chunks/handler4.js +90 -4
- package/dist/packem_chunks/handler40.js +1685 -3
- package/dist/packem_chunks/handler41.js +1088 -10
- package/dist/packem_chunks/handler42.js +785 -141
- package/dist/packem_chunks/handler43.js +2658 -42
- package/dist/packem_chunks/handler44.js +3886 -3
- package/dist/packem_chunks/handler45.js +2568 -21
- package/dist/packem_chunks/handler46.js +3769 -0
- package/dist/packem_chunks/handler47.js +1491 -0
- package/dist/packem_chunks/handler5.js +174 -2
- package/dist/packem_chunks/handler6.js +95 -13
- package/dist/packem_chunks/handler7.js +115 -8
- package/dist/packem_chunks/handler8.js +12 -1
- package/dist/packem_chunks/handler9.js +29 -1
- package/dist/packem_chunks/heal-accept.js +522 -0
- package/dist/packem_chunks/heal.js +673 -0
- package/dist/packem_chunks/index.js +873 -7
- package/dist/packem_chunks/loader.js +23 -1
- package/dist/packem_shared/VisUpdateApp-D-Yz_wvg.js +1316 -0
- package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +5 -0
- package/dist/packem_shared/ai-analysis-CHeB1joD.js +367 -0
- package/dist/packem_shared/ai-cache-Be_jexe4.js +142 -0
- package/dist/packem_shared/ai-fix-B9iQVcD2.js +379 -0
- package/dist/packem_shared/cache-directory-2qvs4goY.js +98 -0
- package/dist/packem_shared/catalog-BJTtyi-O.js +1371 -0
- package/dist/packem_shared/dependency-scan-A0KSklpG.js +188 -0
- package/dist/packem_shared/docker-2iZzc280.js +181 -0
- package/dist/packem_shared/failure-log-Cz3Z4SKL.js +100 -0
- package/dist/packem_shared/flakiness-goTxXuCX.js +180 -0
- package/dist/packem_shared/otel-DCvqCTz_.js +158 -0
- package/dist/packem_shared/otelPlugin-DFaLDvJf.js +3 -0
- package/dist/packem_shared/registry-CbqXI0rc.js +272 -0
- package/dist/packem_shared/run-summary-utils-PVMl4aIh.js +130 -0
- package/dist/packem_shared/runtime-check-Cobi3p6l.js +127 -0
- package/dist/packem_shared/selectors-SM69TfqC.js +194 -0
- package/dist/packem_shared/symbols-Ta7g2nU-.js +14 -0
- package/dist/packem_shared/toolchain-BdZd9eBi.js +975 -0
- package/dist/packem_shared/typosquats-C-bCh3PX.js +1210 -0
- package/dist/packem_shared/use-measured-height-CNP0vT4M.js +20 -0
- package/dist/packem_shared/utils-CthVdBPS.js +40 -0
- package/dist/packem_shared/xxh3-Ck8mXNg1.js +239 -0
- package/index.js +727 -555
- package/package.json +35 -17
- package/schemas/project.schema.json +8 -10
- package/schemas/vis-config.schema.json +132 -8
- package/skills/vis/SKILL.md +96 -0
- package/templates/buildkite-ci/.buildkite/pipeline.yml.tera +85 -0
- package/templates/buildkite-ci/template.yml +20 -0
- package/dist/errors/index.d.ts +0 -26
- package/dist/errors/index.js +0 -1
- package/dist/packem_chunks/config.js +0 -2
- package/dist/packem_shared/VisConfigCycleError-CAYNC7d-.js +0 -1
- package/dist/packem_shared/VisConfigError-B5LP1zRf.js +0 -1
- package/dist/packem_shared/VisConfigLoadError-CeqBSd2Z.js +0 -2
- package/dist/packem_shared/VisConfigNotFoundError-DZ9KC527.js +0 -5
- package/dist/packem_shared/VisUpdateApp-D-L4_-Iu.js +0 -1
- package/dist/packem_shared/_commonjsHelpers-D6W6KoPK.js +0 -1
- package/dist/packem_shared/ai-analysis-CGuy7dfE.js +0 -67
- package/dist/packem_shared/ai-cache-Bynt6Y9x.js +0 -1
- package/dist/packem_shared/cache-directory-D72ZEag2.js +0 -1
- package/dist/packem_shared/catalog-BVPerCwG.js +0 -12
- package/dist/packem_shared/dependency-scan-Du0tBu64.js +0 -2
- package/dist/packem_shared/docker-BcfqH4Av.js +0 -2
- package/dist/packem_shared/failure-log-DqYen0LC.js +0 -2
- package/dist/packem_shared/flakiness-DSIHZGBT.js +0 -1
- package/dist/packem_shared/run-summary-utils-C24Aaf9E.js +0 -1
- package/dist/packem_shared/runtime-check-CGHal8SO.js +0 -1
- package/dist/packem_shared/selectors-CfH9ZY08.js +0 -3
- package/dist/packem_shared/symbols-CQmER5MT.js +0 -1
- package/dist/packem_shared/target-merge-DNa-6eWu.js +0 -1
- package/dist/packem_shared/toolchain-DQfTQY8E.js +0 -5
- package/dist/packem_shared/typosquats-DOR8izpX.js +0 -1
- package/dist/packem_shared/use-measured-height-DjYgUOKk.js +0 -1
- package/dist/packem_shared/utils-DrNg0XTR.js +0 -1
- package/dist/packem_shared/xxh3-DrAUNq4n.js +0 -1
|
@@ -1,10 +1,1088 @@
|
|
|
1
|
-
|
|
2
|
-
`)){if(s.length===0)continue;const o=/^\s*(\d+)\s+(.+)$/.exec(s);if(!o)continue;const l=Number.parseInt(o[1]??"",10),d=(o[2]??"").toLowerCase();!Number.isFinite(l)||l===e||(/(?:^|[ /])vis-native(?:\s|$|[-.])/.test(d)||/(?:^|[ /])vis\s+run\b/.test(d)||/(?:^|[ /])task-runner(?:\s|$|[-.])/.test(d))&&i.push(l)}return i},"listOrphansUnix"),ft=_(e=>{const t=pt("tasklist",["/FO","CSV","/NH"]),i=[];for(const s of t.split(/\r?\n/)){if(s.length===0)continue;const o=s.split(/","/).map(p=>p.replaceAll(/^"|"$/g,"")),l=(o[0]??"").toLowerCase(),d=Number.parseInt(o[1]??"",10);!Number.isFinite(d)||d===e||(l==="vis.exe"||l.startsWith("vis-native")||l.includes("task-runner"))&&i.push(d)}return i},"listOrphansWindows"),Oi=_(()=>[Si(),$i(),xi()],"runRuntimeDiagnostics");var Ni=Object.defineProperty,ye=N((e,t)=>Ni(e,"name",{value:t,configurable:!0}),"s$2");const me=[{id:"dependencies",label:"Deps"},{id:"security",label:"Security"},{id:"optimization",label:"Optimize"},{id:"runtime",label:"Runtime"}],Me=["dependencies","security","optimization","runtime"],ge=ye(e=>{const t=new Map;for(const i of Me)t.set(i,[]);for(const i of e)t.get(i.section).push(i);for(const[i,s]of t)s.length===0&&t.delete(i);return t},"groupBySection"),fe=ye((e,t,i,s)=>{let o=e.filter(l=>l.section===t);if(s&&(o=o.filter(l=>l.severity===s)),i){const l=i.toLowerCase();o=o.filter(d=>d.title.toLowerCase().includes(l))}return[...o]},"filterFindings"),Mi=ye(e=>{const t={dependencies:"idle",optimization:"idle",runtime:"idle",security:"idle"};for(const i of Me)e.has(i)&&(t[i]="idle");return t},"initialStatus");class et{static{N(this,"DoctorStore")}static{ye(this,"DoctorStore")}#e;#i=new Set;constructor(t=[]){const i=Array.isArray(t)?{findings:t}:t,s=i.findings??[],o=i.activeSections??new Set(Me),l=Me.find(c=>o.has(c))??"dependencies",d=fe(s,l,"",void 0),p=Mi(o);if(s.length>0)for(const c of s)p[c.section]="done";this.#e={all:s,entries:d,filterActive:!1,filterText:"",filterType:l,focusedPanel:"list",grouped:ge(d),pendingAction:void 0,sectionError:{},sectionMessage:{},sectionStatus:p,selectedIndex:0,severityFilter:void 0}}getSnapshot=ye(()=>this.#e,"getSnapshot");subscribe=ye(t=>(this.#i.add(t),()=>{this.#i.delete(t)}),"subscribe");setSelectedIndex(t){const i=Math.max(0,Math.min(t,this.#e.entries.length-1));i!==this.#e.selectedIndex&&this.#t({...this.#e,selectedIndex:i})}setFocusedPanel(t){t!==this.#e.focusedPanel&&this.#t({...this.#e,focusedPanel:t})}setFilterType(t){if(t===this.#e.filterType)return;const i=fe(this.#e.all,t,this.#e.filterText,this.#e.severityFilter);this.#t({...this.#e,entries:i,filterType:t,grouped:ge(i),selectedIndex:0})}setFilter(t){const i=fe(this.#e.all,this.#e.filterType,t,this.#e.severityFilter);this.#t({...this.#e,entries:i,filterText:t,grouped:ge(i),selectedIndex:0})}setFilterActive(t){if(t===this.#e.filterActive)return;if(t){this.#t({...this.#e,filterActive:!0});return}const i=fe(this.#e.all,this.#e.filterType,"",this.#e.severityFilter);this.#t({...this.#e,entries:i,filterActive:!1,filterText:"",grouped:ge(i),selectedIndex:0})}setPendingAction(t){this.#t({...this.#e,pendingAction:t})}setSeverityFilter(t){if(t===this.#e.severityFilter)return;const i=fe(this.#e.all,this.#e.filterType,this.#e.filterText,t);this.#t({...this.#e,entries:i,grouped:ge(i),selectedIndex:0,severityFilter:t})}startSection(t,i){this.#t({...this.#e,sectionMessage:{...this.#e.sectionMessage,[t]:i},sectionStatus:{...this.#e.sectionStatus,[t]:"running"}})}completeSection(t,i){const s=[...this.#e.all,...i],o=fe(s,this.#e.filterType,this.#e.filterText,this.#e.severityFilter),l={...this.#e.sectionMessage};delete l[t],this.#t({...this.#e,all:s,entries:o,grouped:ge(o),sectionMessage:l,sectionStatus:{...this.#e.sectionStatus,[t]:"done"}})}failSection(t,i){this.#t({...this.#e,sectionError:{...this.#e.sectionError,[t]:i},sectionStatus:{...this.#e.sectionStatus,[t]:"error"}})}#t(t){this.#e=t;for(const i of this.#i)try{i()}catch{}}}var Fi=Object.defineProperty,mt=N((e,t)=>Fi(e,"name",{value:t,configurable:!0}),"r$1");const tt={error:0,warn:1},zi=mt(e=>!!e.acceptedRisk,"isAcknowledged"),yt=mt(e=>{const t=[];if(e.sections.has("dependencies")){for(const i of e.outdated)t.push({entry:i,id:`outdated:${i.packageName}`,kind:"outdated",section:"dependencies",severity:"warn",subtitle:`${i.currentRange} → ${i.newRange} (${i.updateType})`,title:i.packageName});for(const i of e.duplicates)t.push({id:`duplicate:${i.name}`,kind:"duplicate",pkg:i,section:"dependencies",severity:"warn",subtitle:`${String(i.versions.length)} versions installed`,title:i.name})}if(e.sections.has("security"))for(const i of e.outdated){if(i.vulnerabilities&&i.vulnerabilities.length>0){const s=i.vulnerabilities[0],o=zi(i)?"warn":"error",l=i.vulnerabilities.length;t.push({entry:i,id:`vuln:${i.packageName}`,kind:"vulnerability",packageName:i.packageName,section:"security",severity:o,subtitle:l===1?`${s.severity} · ${s.id}`:`${String(l)} advisories · top: ${s.severity} ${s.id}`,title:i.packageName})}if(i.socketReport&&i.socketReport.alerts.length>0){const s=Math.round(i.socketReport.score.overall*100);t.push({entry:i,id:`socket:${i.packageName}`,kind:"socket",packageName:i.packageName,section:"security",severity:"warn",subtitle:`${String(i.socketReport.alerts.length)} alert${i.socketReport.alerts.length===1?"":"s"} · score ${String(s)}%`,title:i.packageName})}}if(e.sections.has("optimization"))for(const i of e.optimizations)t.push({entry:i,id:`opt:${i.packageName}`,kind:"optimization",section:"optimization",severity:"warn",subtitle:`${i.category} → ${i.replacement}`,title:i.packageName});if(e.sections.has("runtime"))for(const i of e.runtime)i.status==="warn"&&t.push({diagnostic:i,id:`runtime:${i.id}`,kind:"runtime",section:"runtime",severity:"warn",title:i.message});return t.sort((i,s)=>{if(i.section!==s.section){const o=["dependencies","security","optimization","runtime"];return o.indexOf(i.section)-o.indexOf(s.section)}return tt[i.severity]-tt[s.severity]}),t},"flattenFindings"),kt={dependencies:"Dependencies",optimization:"Optimization",runtime:"Runtime",security:"Security"};var ji=Object.defineProperty,Ei=N((e,t)=>ji(e,"name",{value:t,configurable:!0}),"i$1");const Bi={error:"red",warn:"yellow"},Li={error:"✖",warn:"⚠"},_i={error:" ERROR ",warn:" WARN "},Vi=Ei(({children:e,hint:t,message:i,severity:s,title:o})=>{const l=Bi[s];return a(h,{borderColor:l,borderStyle:"single",flexDirection:"column",flexShrink:0,paddingX:1,children:[a(h,{gap:1,children:[r(n,{backgroundColor:l,bold:!0,color:"black",children:_i[s]}),r(n,{bold:!0,color:l,children:Li[s]}),r(n,{bold:!0,wrap:"truncate-end",children:o})]}),r(n,{wrap:"truncate-end",children:i}),t?r(n,{dimColor:!0,wrap:"truncate-end",children:t}):null,e]})},"ConfigBanner");var Ui=Object.defineProperty,te=N((e,t)=>Ui(e,"name",{value:t,configurable:!0}),"d");const Hi={CRITICAL:"red",HIGH:"red",LOW:"gray",MODERATE:"yellow",UNKNOWN:"gray"},Gi={critical:"red",high:"red",low:"gray",medium:"yellow"},Yi={major:"red",minor:"yellow",patch:"green"},T=te(({children:e,label:t,width:i=14})=>a(h,{children:[r(h,{width:i,children:a(n,{dimColor:!0,children:[t,":"]})}),typeof e=="string"?r(n,{children:e}):e]}),"FieldRow"),oe=te(({children:e})=>r(h,{marginTop:1,children:r(n,{bold:!0,color:"white",children:e})}),"SectionTitle"),Ki=te(({finding:e})=>{const{entry:t}=e,i=Yi[t.updateType]??"white";return a(h,{flexDirection:"column",children:[r(T,{label:"Current",children:t.currentRange}),a(T,{label:"Target",children:[r(n,{children:t.newRange}),a(n,{bold:!0,color:i,children:[" (",t.updateType,")"]})]}),r(T,{label:"Catalog",children:t.catalogName}),t.acceptedRisk?r(T,{label:"Risk ack",children:r(n,{dimColor:!0,children:t.acceptedRisk.reason??"(no reason recorded)"})}):null,r(oe,{children:"Action"}),a(n,{dimColor:!0,children:["Run"," ",r(n,{bold:!0,color:"white",children:"vis update"})," ","to apply this change."]})]})},"OutdatedDetail"),Ji=te(({finding:e})=>a(h,{flexDirection:"column",children:[r(T,{label:"Versions",children:r(n,{children:String(e.pkg.versions.length)})}),r(oe,{children:"Installed versions"}),e.pkg.versions.map(t=>a(n,{children:[" · ",t]},t)),r(oe,{children:"Action"}),a(n,{dimColor:!0,children:["Run"," ",r(n,{bold:!0,color:"white",children:"vis dedupe"})," ","to consolidate to a single resolution."]})]}),"DuplicateDetail"),qi=te(({finding:e})=>{const t=e.entry.vulnerabilities??[];return a(h,{flexDirection:"column",children:[r(T,{label:"Package",children:e.packageName}),r(T,{label:"Current",children:e.entry.currentRange}),r(T,{label:"Advisories",children:String(t.length)}),e.entry.acceptedRisk?r(T,{label:"Risk ack",children:r(n,{dimColor:!0,children:e.entry.acceptedRisk.reason??"(no reason recorded)"})}):null,t.map(i=>{const s=Hi[i.severity]??"gray";return a(h,{flexDirection:"column",marginTop:1,children:[a(h,{children:[r(n,{bold:!0,color:s,children:i.severity}),r(n,{children:" "}),r(n,{children:i.id}),typeof i.cvssScore=="number"?a(n,{dimColor:!0,children:[" · CVSS ",i.cvssScore.toFixed(1)]}):null]}),r(n,{wrap:"wrap",children:i.summary}),i.fixedVersions.length>0?a(n,{dimColor:!0,children:["Fixed in: ",i.fixedVersions.join(", ")]}):null,i.aliases&&i.aliases.length>0?a(n,{dimColor:!0,children:["Aliases: ",i.aliases.join(", ")]}):null]},i.id)})]})},"VulnerabilityDetail"),Xi=te(({finding:e})=>{const t=e.entry.socketReport;if(!t)return r(n,{dimColor:!0,children:"No Socket report attached."});const i=Math.round(t.score.overall*100),s=Ke(t.score.overall);return a(h,{flexDirection:"column",children:[r(T,{label:"Package",children:e.packageName}),r(T,{label:"Overall",children:a(n,{color:s,children:[String(i),"%"]})}),r(T,{label:"Alerts",children:String(t.alerts.length)}),e.entry.acceptedRisk?r(T,{label:"Risk ack",children:r(n,{dimColor:!0,children:e.entry.acceptedRisk.reason??"(no reason recorded)"})}):null,r(oe,{children:"Score breakdown"}),Object.entries(t.score).map(([o,l])=>{if(o==="overall")return null;const d=typeof l=="number"?l:0,p=Math.round(d*100),c=Ke(d);return a(h,{children:[r(h,{width:14,children:a(n,{dimColor:!0,children:[o,":"]})}),a(n,{color:c,children:[String(p),"%"]})]},o)}),r(oe,{children:"Alerts"}),t.alerts.map((o,l)=>{const d=Gi[o.severity]??"gray";return a(h,{flexDirection:"column",marginBottom:1,children:[a(h,{children:[r(n,{bold:!0,color:d,children:o.severity}),r(n,{children:" "}),r(n,{children:o.type})]}),o.props?r(n,{dimColor:!0,wrap:"wrap",children:JSON.stringify(o.props)}):null]},`${o.type}-${String(l)}`)})]})},"SocketDetail"),Wi=te(({finding:e})=>{const{entry:t}=e;return a(h,{flexDirection:"column",children:[r(T,{label:"Package",children:t.packageName}),r(T,{label:"Category",children:t.category}),r(T,{label:"Replacement",children:t.replacement}),t.overrideSpec?r(T,{label:"Override",children:t.overrideSpec}):null,r(T,{label:"Codemod",children:r(n,{color:t.hasCodemod?"green":"gray",children:t.hasCodemod?"available":"not available"})}),t.docUrl?r(T,{label:"Guide",children:r(n,{color:"cyan",underline:!0,children:t.docUrl})}):null,r(oe,{children:"Action"}),t.hasCodemod?a(n,{dimColor:!0,children:["Run"," ",r(n,{bold:!0,color:"white",children:"vis optimize"})," ","to apply the codemod interactively."]}):t.overrideSpec?a(n,{dimColor:!0,children:["Run"," ",r(n,{bold:!0,color:"white",children:"vis optimize"})," ","to install the package override."]}):t.docUrl?r(n,{dimColor:!0,children:"No automated codemod. Open the migration guide above for the recommended alternative and steps."}):r(n,{dimColor:!0,children:"No automated codemod. Consult the package's docs or the e18e module-replacements guide for an alternative."})]})},"OptimizationDetail"),Qi=te(({finding:e})=>{const{diagnostic:t}=e,i=t.status==="warn"?"yellow":t.status==="ok"?"green":"gray";return a(h,{flexDirection:"column",children:[r(T,{label:"Check",children:t.id}),r(T,{label:"Status",children:r(n,{color:i,children:t.status})}),r(oe,{children:"Message"}),r(n,{wrap:"wrap",children:t.message}),t.detail&&Object.keys(t.detail).length>0?a(di,{children:[r(oe,{children:"Details"}),Object.entries(t.detail).map(([s,o])=>a(h,{children:[r(h,{width:20,children:a(n,{dimColor:!0,children:[s,":"]})}),r(n,{children:String(o)})]},s))]}):null]})},"RuntimeDetail"),Zi=te(({finding:e,focused:t,scrollRef:i})=>{const s=t?"white":"gray";if(!e)return r(h,{alignItems:"center",borderColor:"gray",borderStyle:"single",flexDirection:"column",flexGrow:1,justifyContent:"center",children:r(n,{dimColor:!0,children:"No finding selected"})});let o;switch(e.kind){case"duplicate":{o=r(Ji,{finding:e});break}case"optimization":{o=r(Wi,{finding:e});break}case"outdated":{o=r(Ki,{finding:e});break}case"runtime":{o=r(Qi,{finding:e});break}case"socket":{o=r(Xi,{finding:e});break}case"vulnerability":{o=r(qi,{finding:e});break}default:{o=r(n,{dimColor:!0,children:"Unknown finding kind."});break}}return a(h,{borderColor:s,borderStyle:"single",flexDirection:"column",flexGrow:1,children:[a(h,{flexShrink:0,paddingTop:1,paddingX:2,children:[r(n,{bold:!0,color:"white",children:e.title}),a(n,{dimColor:!0,children:[" ",kt[e.section]]})]}),a(Dt,{flexGrow:1,flexShrink:1,paddingX:2,ref:i,scrollbar:!0,scrollbarColor:"gray",scrollbarStyle:"block",children:[r(n,{}),o]})]})},"DoctorDetailPanel");var er=Object.defineProperty,Ie=N((e,t)=>er(e,"name",{value:t,configurable:!0}),"c$1");const wt={error:"red",warn:"yellow"},tr={error:"✖",warn:"⚠"},ir=Ie(e=>e.kind==="outdated"||e.kind==="vulnerability"||e.kind==="socket"?!!e.entry.acceptedRisk:!1,"hasAcceptedRisk"),rr=Ie(({finding:e,isSelected:t})=>{const i=wt[e.severity],s=ir(e);return a(h,{flexShrink:0,height:1,children:[r(n,{children:t?">":" "}),a(n,{color:i,children:[" ",tr[e.severity]," "]}),r(h,{flexGrow:1,children:r(n,{bold:t,inverse:t,wrap:"truncate",children:e.title})}),s?r(n,{color:"cyan",children:" ack"}):null,e.subtitle?a(n,{dimColor:!0,wrap:"truncate",children:[" ",e.subtitle]}):null]})},"FindingRow"),nr=Ie(({count:e,section:t})=>a(h,{flexShrink:0,height:1,marginTop:1,children:[a(n,{dimColor:!0,children:["▼"," "]}),r(n,{bold:!0,color:"white",children:kt[t].toUpperCase()}),a(n,{dimColor:!0,children:[" (",e,")"]})]}),"SectionHeader"),or=Ie(({count:e,label:t,status:i})=>a(n,{children:[t,i==="running"?a(n,{children:[" ",r(lt,{type:"dots"})]}):null,i==="error"?r(n,{bold:!0,color:"red",children:" ✖"}):a(n,{dimColor:!0,children:[" (",String(e),")"]})]}),"TabLabel"),sr=Ie(({elapsedMs:e,entries:t,filterActive:i,filterText:s,filterType:o,focused:l,fromCache:d=!1,grouped:p,onViewportHeightChange:c,scrollOffset:$,sectionCounts:x,sectionMessage:b,sectionStatus:I,selectedIndex:f,severityFilter:w,totalAll:E,viewportHeight:Z})=>{const q=l?"white":"gray",{measuredHeight:B,ref:M}=ui(Z,c);let P=0,L=0;for(const v of t)v.severity==="error"?P+=1:v.severity==="warn"&&(L+=1);const X=[];P>0&&X.push(`${String(P)} error${P===1?"":"s"}`),L>0&&X.push(`${String(L)} warn${L===1?"":"s"}`);const ie=X.length>0?` (${X.join(", ")})`:"",G=(e/1e3).toFixed(1),D=[];for(const[v,A]of p){D.push(r(nr,{count:A.length,section:v},`hdr-${v}`));for(const R of A){const U=t.indexOf(R);D.push(r(rr,{finding:R,isSelected:U===f},R.id))}}let V=0;for(const[,v]of p)V+=2+v.length;const Y=V>B&&B>0;return a(h,{borderColor:q,borderStyle:"single",flexDirection:"column",flexGrow:1,children:[a(h,{flexShrink:0,gap:1,paddingX:1,children:[r(n,{bold:!0,inverse:!0,children:" DOCTOR "}),a(n,{wrap:"truncate",children:[t.length,t.length===E?"":`/${String(E)}`," finding",t.length===1?"":"s",ie]}),w?r(n,{bold:!0,color:wt[w],inverse:!0,children:` ${w.toUpperCase()} ONLY `}):null,d?r(n,{bold:!0,color:"cyan",inverse:!0,children:" CACHED "}):null,a(n,{dimColor:!0,children:[" · ",G,"s"]})]}),r(h,{flexShrink:0,paddingX:1,paddingY:1,children:r(Ot,{isFocused:l,keyMap:{next:[],previous:[],useNumbers:!1,useTab:!1},onChange:N(()=>{},"onChange"),showIndex:!1,value:o,children:me.map(({id:v,label:A})=>r(Nt,{name:v,children:r(or,{count:x[v],label:A,status:I[v]})},v))})}),(()=>{const v=Object.keys(I).filter(A=>I[A]==="running"&&b[A]).map(A=>b[A]);return v.length===0?null:r(h,{flexShrink:0,paddingX:1,children:a(n,{dimColor:!0,wrap:"truncate",children:[r(lt,{type:"dots"})," ",v.join(" · ")]})})})(),i&&a(h,{flexShrink:0,paddingX:1,children:[r(n,{bold:!0,color:"white",children:"/ "}),r(n,{children:s}),r(n,{inverse:!0,children:" "})]}),a(h,{flexDirection:"row",flexGrow:1,overflow:"hidden",ref:M,children:[r(h,{flexDirection:"column",flexGrow:1,overflow:"hidden",paddingLeft:1,children:r(h,{flexDirection:"column",marginTop:-$,children:D.length>0?D:r(h,{marginTop:1,children:r(n,{dimColor:!0,children:"No findings match the current filter."})})})}),Y&&r(h,{flexShrink:0,marginLeft:1,marginRight:1,children:r(Mt,{contentHeight:V,placement:"inset",scrollOffset:$,style:"block",viewportHeight:B})})]},`list-${o}-${s}`)]})},"DoctorListPanel");var lr=Object.defineProperty,ze=N((e,t)=>lr(e,"name",{value:t,configurable:!0}),"g$1");const ar=ze(e=>{if(e.kind==="outdated")return{command:`vis update ${e.entry.packageName}`,description:`Update ${e.entry.packageName} to ${e.entry.newRange}`};if(e.kind==="duplicate")return{command:`vis dedupe ${e.pkg.name}`,description:`Dedupe ${e.pkg.name} (${String(e.pkg.versions.length)} versions)`}},"buildUpdateAction"),cr=ze(e=>{if(e.kind==="optimization")return{command:`vis optimize ${e.entry.packageName}`,description:`Replace ${e.entry.packageName} with ${e.entry.replacement}`}},"buildOptimizeAction"),dr=ze(e=>{if(e.kind!=="outdated"&&e.kind!=="vulnerability"&&e.kind!=="socket")return;const t=e.kind==="outdated"?e.entry.packageName:e.packageName,i=["// Add to vis.config.ts:","security: {"," acceptedRisks: {",` "${t}": {`,' reason: "explain why this risk is acceptable",',' expiresAt: "YYYY-MM-DD",'," },"," },","},"].join(`
|
|
3
|
-
`);return{command:i,configSnippet:i,description:`Acknowledge risk for ${t}`}},"buildAckAction"),ur=100,hr=40,pr=10,gr=ze(({autoExitSeconds:e=0,banner:t,fromCache:i=!1,startedAt:s,store:o})=>{const{exit:l}=Ft(),{columns:d,rows:p}=zt(),c=Ht(o.subscribe,o.getSnapshot),[$,x]=xe(!1),[b,I]=xe(!1),[f,w]=xe(0),[E,Z]=xe(()=>Date.now());Ee(()=>{const y=setInterval(()=>{Z(Date.now())},1e3);return()=>{clearInterval(y)}},[]);const q=E-s,B=qe(null),M=qe(null),P=c.entries[c.selectedIndex]??null,L=Pe(()=>{const y={dependencies:0,optimization:0,runtime:0,security:0};for(const m of c.all)y[m.section]+=1;return y},[c.all]),X=t?t.hint?5:4:0,ie=Pe(()=>{for(const y of Object.keys(c.sectionStatus))if(c.sectionStatus[y]==="running"&&c.sectionMessage[y])return 1;return 0},[c.sectionStatus,c.sectionMessage]),G=d>=ur,D=G?Math.max(1,p-X-2):Math.floor(p*.55),V=Pe(()=>Math.max(1,D-6-ie-(c.filterActive?1:0)),[D,ie,c.filterActive]),[Y,v]=xe(V),A=Y>0?Y:V,R=Pe(()=>{let y=0;for(const[,m]of c.grouped)y+=2+m.length;return y},[c.grouped]),U=Math.max(0,R-A);Ee(()=>{w(y=>Math.min(y,U))},[U]);const ce=Xe(y=>{let m=0,k=0;for(const[,Se]of c.grouped){m+=2;for(const $e of Se){if(k===y)return m;m+=1,k+=1}}return m},[c.grouped]),O=Xe(y=>{const m=ce(y);w(k=>m>k+A-2?Math.min(U,Math.max(0,m-A+2)):m<k+1?Math.max(0,m-1):k)},[ce,A,U]);if(Ee(()=>{M.current?.scrollToTop()},[P?.id]),jt((y,m)=>{if(y==="c"&&m.ctrl){l();return}if(!b){if($){m.escape||y==="?"?x(!1):y==="q"?(x(!1),I(!0)):m.downArrow||y==="j"?B.current?.scrollBy(1):(m.upArrow||y==="k")&&B.current?.scrollBy(-1);return}if(y==="?"){x(!0);return}if(y==="q"){I(!0);return}if(m.tab){o.setFocusedPanel(c.focusedPanel==="list"?"detail":"list");return}if(c.filterActive){if(m.escape||m.return){o.setFilterActive(!1);return}if(m.backspace){w(0),o.setFilter(c.filterText.slice(0,-1));return}y&&!m.ctrl&&!m.meta&&(w(0),o.setFilter(c.filterText+y));return}if(c.focusedPanel==="list"&&(m.leftArrow||m.rightArrow)){const k=me.findIndex($e=>$e.id===c.filterType),Se=m.rightArrow?(k+1)%me.length:(k-1+me.length)%me.length;w(0),M.current?.scrollToTop(),o.setFilterType(me[Se].id);return}if(c.focusedPanel==="list"){if(m.downArrow||y==="j"){const k=Math.min(c.selectedIndex+1,c.entries.length-1);o.setSelectedIndex(k),O(k);return}if(m.upArrow||y==="k"){const k=Math.max(c.selectedIndex-1,0);o.setSelectedIndex(k),O(k);return}if(m.pageDown){const k=Math.min(c.selectedIndex+10,c.entries.length-1);o.setSelectedIndex(k),O(k);return}if(m.pageUp){const k=Math.max(c.selectedIndex-10,0);o.setSelectedIndex(k),O(k);return}if(m.home){o.setSelectedIndex(0),w(0);return}if(m.end){const k=c.entries.length-1;o.setSelectedIndex(k),O(k);return}if(y==="/"){o.setFilterActive(!0);return}if(y==="e"){o.setSeverityFilter(c.severityFilter==="error"?void 0:"error"),w(0);return}if(y==="w"){o.setSeverityFilter(c.severityFilter==="warn"?void 0:"warn"),w(0);return}if(y==="u"&&P){const k=ar(P);k&&(o.setPendingAction(k),l());return}if(y==="o"&&P){const k=cr(P);k&&(o.setPendingAction(k),l());return}if(y==="a"&&P){const k=dr(P);k&&(o.setPendingAction(k),l());return}if(y==="d"){o.setFocusedPanel("detail");return}return}if(m.escape||m.leftArrow){o.setFocusedPanel("list");return}if(m.downArrow||y==="j"){M.current?.scrollBy(1);return}if(m.upArrow||y==="k"){M.current?.scrollBy(-1);return}if(m.pageDown){M.current?.scrollBy(10);return}if(m.pageUp){M.current?.scrollBy(-10);return}if(m.home){M.current?.scrollToTop();return}m.end&&M.current?.scrollToBottom()}},{isActive:!0}),d<hr||p<pr)return r(h,{alignItems:"center",height:p,justifyContent:"center",width:d,children:a(n,{color:"yellow",children:["Terminal too small (",d,"x",p,")"]})});const W=c.focusedPanel==="detail",ee=[a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"q"}),r(n,{dimColor:!0,children:"QUIT"})]},"q"),a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"?"}),r(n,{dimColor:!0,children:"HELP"})]},"?"),a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"↑↓"}),r(n,{dimColor:!0,children:W?"SCROLL":"NAV"})]},"nav"),W?a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"←/Esc"}),r(n,{dimColor:!0,children:"LIST"})]},"lr"):a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"←→"}),r(n,{dimColor:!0,children:"SECTION"})]},"lr"),a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"/"}),r(n,{dimColor:!0,children:"SEARCH"})]},"search"),a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"e/w"}),r(n,{dimColor:!0,children:"SEVERITY"})]},"sev"),a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"u/o/a"}),r(n,{dimColor:!0,children:"ACTION"})]},"actions"),a(h,{gap:1,children:[r(n,{bold:!0,color:"white",children:"Tab"}),r(n,{dimColor:!0,children:"PANEL"})]},"tab")],de=r(h,{borderBottom:!1,borderColor:"gray",borderLeft:!1,borderRight:!1,borderStyle:"single",flexShrink:0,children:r(h,{gap:2,overflow:"hidden",paddingX:1,children:ee})}),ue=a(Et,{footer:a(n,{dimColor:!0,children:[r(n,{bold:!0,color:"white",children:"↑↓"})," scroll ",r(n,{bold:!0,color:"white",children:"?"}),"/",r(n,{bold:!0,color:"white",children:"Esc"})," close"]}),scrollRef:B,title:"DOCTOR — KEYBOARD SHORTCUTS",visible:$,width:56,children:[a(h,{flexDirection:"column",marginBottom:1,children:[a(h,{marginBottom:1,children:[r(n,{dimColor:!0,children:"── "}),r(n,{bold:!0,color:"white",children:"NAVIGATION"})]}),a(h,{children:[r(h,{width:26,children:a(n,{children:[r(n,{bold:!0,color:"white",children:" ↑/k "}),r(n,{dimColor:!0,children:"Move up"})]})}),a(n,{children:[r(n,{bold:!0,color:"white",children:" ↓/j "}),r(n,{dimColor:!0,children:"Move down"})]})]}),a(h,{children:[r(h,{width:26,children:a(n,{children:[r(n,{bold:!0,color:"white",children:" PgUp"}),r(n,{dimColor:!0,children:" Jump up 10"})]})}),a(n,{children:[r(n,{bold:!0,color:"white",children:" PgDn"}),r(n,{dimColor:!0,children:" Jump down 10"})]})]}),a(h,{children:[r(h,{width:26,children:a(n,{children:[r(n,{bold:!0,color:"white",children:" Home"}),r(n,{dimColor:!0,children:" Jump to top"})]})}),a(n,{children:[r(n,{bold:!0,color:"white",children:" End"}),r(n,{dimColor:!0,children:" Jump to bottom"})]})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" Tab"}),r(n,{dimColor:!0,children:" Switch panel"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" →/←"}),r(n,{dimColor:!0,children:" Section tabs (list) / Focus list (detail)"})]})]}),a(h,{flexDirection:"column",marginBottom:1,children:[a(h,{marginBottom:1,children:[r(n,{dimColor:!0,children:"── "}),r(n,{bold:!0,color:"white",children:"FILTER"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" /"}),r(n,{dimColor:!0,children:" Open text filter (Esc/Enter to close)"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" e"}),r(n,{dimColor:!0,children:" Toggle errors-only filter"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" w"}),r(n,{dimColor:!0,children:" Toggle warns-only filter"})]})]}),a(h,{flexDirection:"column",marginBottom:1,children:[a(h,{marginBottom:1,children:[r(n,{dimColor:!0,children:"── "}),r(n,{bold:!0,color:"white",children:"ACTIONS"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" u"}),r(n,{dimColor:!0,children:" Exit + suggest update / dedupe command"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" o"}),r(n,{dimColor:!0,children:" Exit + suggest optimize command"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" a"}),r(n,{dimColor:!0,children:" Exit + print risk-ack snippet"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" d"}),r(n,{dimColor:!0,children:" Focus detail panel"})]})]}),a(h,{flexDirection:"column",children:[a(h,{marginBottom:1,children:[r(n,{dimColor:!0,children:"── "}),r(n,{bold:!0,color:"white",children:"EXIT"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" q"}),r(n,{dimColor:!0,children:" Quit (with countdown)"})]}),a(n,{children:[r(n,{bold:!0,color:"white",children:" Ctrl+C"}),r(n,{dimColor:!0,children:" Quit immediately"})]})]})]}),he=r(sr,{elapsedMs:q,entries:c.entries,filterActive:c.filterActive,filterText:c.filterText,filterType:c.filterType,focused:c.focusedPanel==="list",fromCache:i,grouped:c.grouped,onViewportHeightChange:v,scrollOffset:f,sectionCounts:L,sectionMessage:c.sectionMessage,sectionStatus:c.sectionStatus,selectedIndex:c.selectedIndex,severityFilter:c.severityFilter,totalAll:c.all.length,viewportHeight:A}),pe=t?r(Vi,{hint:t.hint,message:t.message,severity:t.severity,title:t.title}):null,be=r(Zi,{finding:P,focused:c.focusedPanel==="detail",scrollRef:M});if(G){const y=Math.floor(d*.4);return a(h,{flexDirection:"column",height:p,width:d,children:[pe,a(h,{flexDirection:"row",flexGrow:1,children:[r(h,{flexGrow:1,children:he}),r(h,{width:y,children:be})]}),de,r(Je,{autoExitSeconds:e||3,onCancel:N(()=>{I(!1)},"onCancel"),visible:b}),ue]})}return a(h,{flexDirection:"column",height:p,width:d,children:[pe,r(h,{height:D,children:he}),r(h,{flexGrow:1,children:be}),de,r(Je,{autoExitSeconds:e||3,onCancel:N(()=>{I(!1)},"onCancel"),visible:b}),ue]})},"VisDoctorApp");var fr=Object.defineProperty,we=N((e,t)=>fr(e,"name",{value:t,configurable:!0}),"n$1");const mr=we(e=>e.replaceAll(/[$()+.?[\\\]^{|}]/g,String.raw`\$&`),"escapeRegex"),yr=we(e=>{const t=e.split("*").map(mr);return new RegExp(`^${t.join(".*")}$`,"i")},"compilePattern"),kr=we(e=>e?e.split(",").map(t=>t.trim()).filter(t=>t.length>0).map(yr):[],"parseFilterPatterns"),Ne=we((e,t)=>{for(const i of t)if(i.test(e))return!0;return!1},"matchesAny"),wr=we((e,t)=>{if(t.length===0)return e;const i=e.outdated.filter(c=>Ne(c.packageName,t)),s=e.duplicates.filter(c=>Ne(c.name,t)),o=e.optimizations.filter(c=>Ne(c.packageName,t));let l=0,d=0,p=0;for(const c of i)c.vulnerabilities&&(l+=c.vulnerabilities.length),c.socketReport&&(d+=c.socketReport.alerts.length,c.socketReport.score.overall<Be&&(p+=1));return{...e,duplicates:s,optimizations:o,outdated:i,socketIssues:{alerts:d,lowScore:p},vulnCount:l}},"applyFilter"),vt=we((e,t)=>t.length===0?[...e]:e.filter(i=>{if(i.kind==="runtime")return!0;const s=i.kind==="duplicate"?i.pkg.name:i.kind==="outdated"||i.kind==="optimization"?i.entry.packageName:i.packageName;return Ne(s,t)}),"filterFindingsByPattern");var vr=Object.defineProperty,ve=N((e,t)=>vr(e,"name",{value:t,configurable:!0}),"r");const bt=["dependencies","security","optimization","runtime"],it=ve(e=>{const t=new Set;if(!e)return t;for(const i of e.split(",")){const s=i.trim().toLowerCase();bt.includes(s)&&t.add(s)}return t},"parseSectionList"),br=ve((e,t)=>{if(e!==void 0&&e!=="")return it(e);const i=it(t);return new Set(bt.filter(s=>!i.has(s)))},"resolveSections"),St=ve(e=>{const t={micro:0,native:0,preferred:0,socket:0,total:e.length};for(const i of e)switch(i.category){case"micro-utility":{t.micro+=1;break}case"native":{t.native+=1;break}case"preferred":{t.preferred+=1;break}case"socket":{t.socket+=1;break}}return t},"summarizeOptimizations"),ne=ve((e,t)=>{if(!e.sections.has(t))return"skip";switch(t){case"dependencies":return e.outdated.length>0||e.duplicates.length>0?"warn":"ok";case"optimization":return e.optimizations.length>0?"warn":"ok";case"runtime":return e.runtime.some(i=>i.status==="warn")?"warn":"ok";case"security":return e.vulnCount>0||e.socketIssues.alerts>0?"error":e.socketIssues.lowScore>0?"warn":"ok";default:return"ok"}},"sectionStatus"),Sr=ve((e,t)=>{const i=St(e.optimizations),s={dependencies:ne(e,"dependencies"),optimization:ne(e,"optimization"),runtime:ne(e,"runtime"),security:ne(e,"security")},o=new Set([...Object.values(s),e.supplyChain.status]),l=o.has("error")?"error":o.has("warn")?"warn":"ok";return{dependencies:{duplicates:e.duplicates.length,installed:e.installedCount,outdated:e.outdated.length,status:s.dependencies},elapsedMs:e.elapsedMs,optimizations:{microUtilities:i.micro,native:i.native,preferred:i.preferred,socket:i.socket,status:s.optimization,total:i.total},packageManager:t,runtime:e.runtime.map(d=>({detail:d.detail,id:d.id,message:d.message,status:d.status})),runtimeStatus:s.runtime,security:{alerts:e.socketIssues.alerts,lowScorePackages:e.socketIssues.lowScore,status:s.security,vulnerabilities:e.vulnCount},status:l,supplyChain:{findings:e.supplyChain.findings.map(d=>({detail:d.detail,label:d.label,severity:d.severity})),status:e.supplyChain.status},workspaces:e.workspaceCount}},"buildJsonPayload"),rt=ve((e,t)=>{const i=e.runtime.some(o=>o.status==="warn"),s=e.vulnCount>0||e.socketIssues.alerts>0;return t?s||e.outdated.length>0||e.duplicates.length>0||i:s},"shouldFail");var $r=Object.defineProperty,$t=N((e,t)=>$r(e,"name",{value:t,configurable:!0}),"l");const nt=$t(e=>e.some(t=>t.severity==="error")?"error":e.some(t=>t.severity==="warn")?"warn":"ok","rollUpStatus"),Cr=$t(e=>{const t=[],i=e?.security;if(!i)return t.push({detail:"Use defineConfig() from '@visulima/vis/config' to apply secure defaults.",label:"No security config — running with the PM's native defaults",severity:"warn"}),{findings:t,status:nt(t)};i.minimumReleaseAge===void 0?t.push({detail:"Set security.minimumReleaseAge to block packages published in the last N minutes (mitigates supply-chain attacks).",label:"minimumReleaseAge is not set",severity:"warn"}):i.minimumReleaseAge===0?t.push({detail:"New packages can be installed immediately after publishing. Consider setting a non-zero cooldown.",label:"minimumReleaseAge is explicitly 0",severity:"warn"}):t.push({label:`minimumReleaseAge: ${String(i.minimumReleaseAge)} minutes`,severity:"ok"}),i.trustPolicy===void 0||i.trustPolicy==="off"?t.push({detail:"Packages whose trust level has decreased will not be blocked. Consider 'no-downgrade'.",label:`trustPolicy: ${i.trustPolicy??"not set"}`,severity:"warn"}):t.push({label:`trustPolicy: ${i.trustPolicy}`,severity:"ok"}),i.blockExoticSubdeps===void 0||!i.blockExoticSubdeps?t.push({detail:"Transitive dependencies can pull code from git repos or tarball URLs. Set to true to block.",label:`blockExoticSubdeps: ${String(i.blockExoticSubdeps??!1)}`,severity:"warn"}):t.push({label:"blockExoticSubdeps: true",severity:"ok"});const s=i.allowBuilds?Object.keys(i.allowBuilds).length:0;return s===0?t.push({detail:"Lifecycle scripts are blocked by default. List trusted packages here to opt them back in (e.g. esbuild, @prisma/client).",label:"allowBuilds: not configured",severity:"warn"}):t.push({label:`allowBuilds: ${String(s)} ${s===1?"entry":"entries"}`,severity:"ok"}),i.strictDepBuilds&&s===0&&t.push({detail:"All dependencies with build scripts will be blocked. Run 'vis approve-builds' to populate allowBuilds.",label:"strictDepBuilds is on but allowBuilds is empty",severity:"error"}),{findings:t,status:nt(t)}},"buildSupplyChainPosture");var xr=Object.defineProperty,C=N((e,t)=>xr(e,"name",{value:t,configurable:!0}),"u");const H=C(e=>e>=1e3?`${(e/1e3).toFixed(1)}s`:`${String(Math.round(e))}ms`,"fmtDuration"),De=C(async(e,t,i,s)=>{if(!e)return i();e.start(t);const o=Date.now();try{const l=await i(),d=Date.now()-o,{status:p,summary:c}=s(l,d);return e.finish(t,p,c),l}catch(l){const d=Date.now()-o,p=l instanceof Error?l.message:String(l);throw e.finish(t,"error",`${p} (${H(d)})`),l}},"tracked"),Rr=C((e,t)=>{const i={duplicates:t.duplicates,elapsedMs:0,installedCount:0,optimizations:t.optimizations,outdated:t.outdated,runtime:t.runtime,sections:new Set([e]),socketIssues:{alerts:0,lowScore:0},supplyChain:{findings:[],status:"ok"},vulnCount:0,workspaceCount:0};return yt(i)},"buildSectionFindings"),ot=C(async e=>{const{filterPatterns:t,installed:i,progress:s,resolveCodemods:o,sections:l,store:d,visConfig:p,workspaceRoot:c}=e,$=l.has("dependencies"),x=l.has("security"),b=l.has("optimization"),I=l.has("runtime"),f=C((g,F)=>vt(Rr(g,F),t),"sectionFindings"),w=at(c),{packageManager:E}=st(c),Z=Qe(le(c,"package.json"),!1),q=dt(c),B=new Set(Z);for(const g of q){const F=Qe(le(Pt(c,g),"package.json"),!1);for(const z of F)B.add(z)}const M=hi(c),P=ht(c,E),L=ct(p?.security?.socket),X=p?.security?.socket?.acceptedRisks,ie=ei(c,w.name),G={exclude:[],ignore:[],include:[],includeLocked:!1,includePrerelease:!1,security:!0,target:"latest"},D=$?li(c,w.name):[],V=b?ti(B):[],Y=b?ii(B,ie,w,!1):[],v=new Set(V.map(g=>g.packageName)),A=Y.filter(g=>!v.has(g.packageName)),R=[...V,...A],U=I?Oi():[];d&&($&&d.startSection("dependencies",P.size>0?"checking outdated catalog dependencies":"scanning duplicates"),x&&d.startSection("security",i.length>0?`scanning ${String(i.length)} packages for advisories`:"no installed packages to scan"),b&&d.startSection("optimization","matching e18e + socket overrides"),I&&d.startSection("runtime","running runtime diagnostics")),d&&I&&d.completeSection("runtime",f("runtime",{duplicates:[],optimizations:[],outdated:[],runtime:U}));const ce=($||x)&&P.size>0?De(s,"outdated",()=>pi(P,G,M,void 0,c,L,X),(g,F)=>{const z=g.outdated.length;return{status:z>0?"warn":"ok",summary:z>0?`${String(z)} outdated · ${H(F)}`:`up to date · ${H(F)}`}}):Promise.resolve({failed:[],ignored:[],outdated:[]}),O=x&&i.length>0?De(s,"vulnerabilities",()=>gi(i.map(g=>({name:g.name,version:g.version}))),(g,F)=>{let z=0;for(const re of g.values())z+=re.length;return{status:z>0?"error":"ok",summary:z>0?`${String(z)} found · ${H(F)}`:`none found · ${H(F)}`}}):Promise.resolve(new Map),W=x&&L&&i.length>0?De(s,"socket",()=>Lt(i.map(g=>({name:g.name,version:g.version})),L),(g,F)=>{let z=0,re=0;for(const Ye of g.values())z+=Ye.alerts.length,Ye.score.overall<Be&&(re+=1);const Ge=z+re;return{status:Ge>0?"warn":"ok",summary:Ge>0?`${String(z)} alert${z===1?"":"s"}, ${String(re)} low-score · ${H(F)}`:`clean · ${H(F)}`}}):Promise.resolve(new Map);let ee,de,ue,he;const pe=ce.catch(g=>(ee=g instanceof Error?g.message:String(g),d||u.warn(`Outdated scan failed: ${ee}`),{failed:[],ignored:[],outdated:[]})),be=O.catch(g=>(de=g instanceof Error?g.message:String(g),d||u.warn(`Vulnerability scan failed: ${de}`),new Map)),y=W.catch(g=>(ue=g instanceof Error?g.message:String(g),d||u.warn(`Socket scan failed: ${ue}`),new Map)),m=d&&$?pe.then(g=>{if(ee){d.failSection("dependencies",ee);return}d.completeSection("dependencies",f("dependencies",{duplicates:D,optimizations:[],outdated:g.outdated,runtime:[]}))}):void 0,k=d&&x?Promise.all([pe,be,y]).then(([g])=>{const F=ee??de??ue;if(F){d.failSection("security",F);return}d.completeSection("security",f("security",{duplicates:[],optimizations:[],outdated:g.outdated,runtime:[]}))}):void 0,Se=(async()=>{if(o&&b&&R.length>0&&await De(s,"codemods",async()=>(await ri(R),R),(g,F)=>{const z=g.filter(re=>re.hasCodemod||re.category==="socket").length;return{status:"ok",summary:`${String(z)} auto-fixable · ${H(F)}`}}).catch(g=>{he=g instanceof Error?g.message:String(g)}),d&&b){if(he){d.failSection("optimization",he);return}d.completeSection("optimization",f("optimization",{duplicates:[],optimizations:R,outdated:[],runtime:[]}))}})(),[$e,xt,Rt]=await Promise.all([pe,be,y]);await Promise.all([m,k,Se]);let Ue=0,He=0;if(x&&L)for(const g of Rt.values())Ue+=g.alerts.length,g.score.overall<Be&&(He+=1);let je=0;if(x){for(const g of $e.outdated)g.vulnerabilities&&g.vulnerabilities.length>0&&(je+=g.vulnerabilities.length);for(const g of xt.values())je+=g.length}return{duplicates:D,installedCount:i.length,optimizations:b?R:[],outdated:$?$e.outdated:[],runtime:U,sections:l,socketIssues:{alerts:Ue,lowScore:He},supplyChain:Cr(p),vulnCount:je,workspaceCount:q.length}},"streamScans"),Tr=C(e=>{switch(e){case"error":return Re(j.failure);case"skip":return S(j.dash);case"warn":return Fe(j.warning);default:return ke(j.success)}},"sectionIcon"),ae=C((e,t)=>{const i=process.stderr.columns??80,s=Math.max(20,Math.min(i-2,60)),o=j.dash.repeat(2),l=`${Tr(t)} ${se(e)}`,d=l.replaceAll(/\[[0-9;]*m/g,"").length,p=Math.max(0,s-d-o.length-2);return`${o} ${l} ${S(j.dash.repeat(p))}`},"heading"),J=C(e=>` ${ke(j.success)} ${e}`,"itemOk"),Q=C(e=>` ${Fe(j.warning)} ${e}`,"itemWarn"),Ve=C(e=>` ${Re(j.failure)} ${e}`,"itemError"),Ct=C(e=>` ${S(j.dash)} ${S(e)}`,"itemSkip"),K=C((e,t,i)=>{const s=`${se(String(e))} ${S(t)}`;return i?`${s} ${S(`(${i})`)}`:s},"countLine"),Ar=C(e=>{if(e.sections.has("dependencies")){if(u.log(""),u.log(ae("Dependencies",ne(e,"dependencies"))),u.log(J(K(e.installedCount,"packages installed"))),e.outdated.length>0){const t=e.outdated.filter(l=>l.updateType==="major").length,i=e.outdated.filter(l=>l.updateType==="minor").length,s=e.outdated.filter(l=>l.updateType==="patch").length,o=[];t>0&&o.push(`${String(t)} major`),i>0&&o.push(`${String(i)} minor`),s>0&&o.push(`${String(s)} patch`),u.log(Q(K(e.outdated.length,"outdated",o.join(", "))))}else u.log(J("All dependencies up to date"));e.duplicates.length>0?u.log(Q(K(e.duplicates.length,"packages with duplicate versions"))):u.log(J("No duplicate dependencies"))}},"displayDependencies"),Ir=C(e=>{e.sections.has("security")&&(u.log(""),u.log(ae("Security",ne(e,"security"))),e.vulnCount>0?u.log(Ve(K(e.vulnCount,`vulnerabilit${e.vulnCount===1?"y":"ies"} found`))):u.log(J("No known vulnerabilities")),e.socketIssues.alerts>0&&u.log(Q(K(e.socketIssues.alerts,`Socket.dev security alert${e.socketIssues.alerts===1?"":"s"}`))),e.socketIssues.lowScore>0&&u.log(Q(K(e.socketIssues.lowScore,`package${e.socketIssues.lowScore===1?"":"s"} with low security score`))),e.socketIssues.alerts===0&&e.socketIssues.lowScore===0&&e.vulnCount===0&&u.log(J("No security issues detected")))},"displaySecurity"),Pr=C(e=>{if(!e.sections.has("optimization"))return;u.log(""),u.log(ae("Optimization",ne(e,"optimization")));const t=St(e.optimizations);if(t.total===0){u.log(J("No optimizations available"));return}t.native>0&&u.log(Q(K(t.native,"replaceable with native APIs"))),t.preferred>0&&u.log(Q(K(t.preferred,"with lighter alternatives"))),t.micro>0&&u.log(Q(K(t.micro,"trivial micro-utilities"))),t.socket>0&&u.log(Q(K(t.socket,"@socketregistry overrides available")))},"displayOptimization"),Dr=C(e=>{u.log(""),u.log(ae("Supply Chain",e.supplyChain.status));for(const t of e.supplyChain.findings){const i=t.severity==="ok"?J(t.label):t.severity==="error"?Ve(t.label):Q(t.label);u.log(i),t.detail&&u.log(` ${S(j.arrow)} ${S(t.detail)}`)}e.supplyChain.status!=="ok"&&u.log(` ${S(j.arrow)} ${S("Configure with security.* in vis.config.ts. See `vis check --security-config` for details.")}`)},"displaySupplyChain"),Or=C(e=>{if(e.sections.has("runtime")){u.log(""),u.log(ae("Runtime",ne(e,"runtime")));for(const t of e.runtime)t.status==="ok"?u.log(J(t.message)):t.status==="skip"?u.log(Ct(t.message)):u.log(Q(t.message))}},"displayRuntime"),Nr=C((e,t)=>{const i=e.vulnCount,s=e.runtime.filter(l=>l.status==="warn").length,o=e.outdated.length+e.duplicates.length+e.optimizations.length+s;if(t){if(i===0&&o===0)u.success(`Everything looks good! ${S(`(${H(e.elapsedMs)})`)}`);else{const l=[];i>0&&l.push(Re(`${String(i)} security`)),o>0&&l.push(Fe(`${String(o)} improvement${o===1?"":"s"}`)),u.log(`${Re(j.failure)} ${l.join(", ")} ${S(`(${H(e.elapsedMs)})`)}`)}return}u.log(""),u.log(ae("Summary","ok")),i===0&&o===0?u.success(`Everything looks good! ${S(`(${H(e.elapsedMs)})`)}`):(i>0&&u.error(`${String(i)} security issue${i===1?"":"s"}`),o>0&&u.log(` ${Te(j.arrow)} ${se(String(o))} ${S(`improvement${o===1?"":"s"} available`)} ${S(`(${H(e.elapsedMs)})`)}`))},"displaySummary"),Mr=C(e=>{const t=[];if(e.outdated.length>0&&t.push("vis update — update outdated dependencies"),(e.vulnCount>0||e.socketIssues.alerts>0)&&t.push("vis audit — detailed security analysis"),e.optimizations.length>0&&t.push("vis optimize — apply optimizations interactively"),e.duplicates.length>0&&t.push("vis dedupe — reduce duplicate versions"),t.length>0){u.log(""),u.log(se("Next steps:"));for(const i of t)u.log(` ${S(j.arrow)} ${i}`)}u.log("")},"displayActions"),Fr=C((e,t)=>{t||(Ar(e),Ir(e),Pr(e),Or(e),Dr(e)),Nr(e,t)},"displayResults"),zr=C((e,t,i,s,o)=>{const l=[],d=e.has("dependencies"),p=e.has("security"),c=e.has("optimization");return(d||p)&&t>0&&l.push({id:"outdated",label:"Outdated catalog dependencies"}),p&&s>0&&l.push({id:"vulnerabilities",label:"Known vulnerabilities (OSV)"}),p&&i&&s>0&&l.push({id:"socket",label:"Socket.dev supply-chain reports"}),c&&o&&l.push({id:"codemods",label:"Codemod availability"}),l},"planScanTasks"),jr=C(e=>{if(u.log(""),u.log(`${se(Te("vis doctor"))} ${S("— project health check")}`),u.log(J(`Detected ${e.packageManagerName} v${e.packageManagerVersion}`)),e.workspaceCount!==void 0&&e.workspaceCount>0&&u.log(J(K(e.workspaceCount,`workspace package${e.workspaceCount===1?"":"s"}`))),e.runtimeFindings.length===0)u.log(J(`Node.js ${e.nodeVersion}`));else{for(const t of e.runtimeFindings){const i=t.severity==="error"?Re:Fe;u.log(Ve(`Runtime: ${i(t.message)}`))}u.log(` ${S(j.arrow)} Run ${ke("vis toolchain install")} to install pinned versions, or ${ke("vis toolchain status")} for the per-tool breakdown.`)}u.log("")},"printBanner"),rn=C(async({logger:e,options:t,visConfig:i,visConfigError:s,workspaceRoot:o})=>{if(!o)throw new Error("Could not determine workspace root.");const l=t.format==="json"||t.json===!0,d=br(t.only,t.skip),p=!!t.quiet,c=!!t.noProgress,$=kr(t.filter);if(d.size===0){u.error("No sections selected. Check your --only / --skip values."),process.exitCode=2;return}const x=Date.now(),b=at(o),I=si(o),f=!!process.stdout.isTTY,w=!l&&f&&!_t&&!p&&!c;!l&&!w&&jr({nodeVersion:process.versions.node,packageManagerName:b.name,packageManagerVersion:b.version,runtimeFindings:I,workspaceCount:void 0});const E=ht(o,st(o).packageManager),Z=ai(o,b.name),q=Z.length,B=!!ct(i?.security?.socket),M=dt(o);if(!l&&!p&&!w){const O=M.length>0?S(` · ${String(M.length)} workspace package${M.length===1?"":"s"}`):"";u.log(`${S("·")} ${S("Found")} ${se(String(q))} ${S(`installed package${q===1?"":"s"}`)}${O}`)}const P=s?{hint:s.file?`Continuing with default settings — fix or regenerate ${s.file} (vis init --force).`:"Continuing with default settings.",message:s.message,severity:"error",title:s.file?`Failed to load ${s.file}`:"Failed to load vis.config"}:void 0,L={bun:"bun.lock",npm:"package-lock.json",pnpm:"pnpm-lock.yaml",yarn:"yarn.lock"}[b.name],X=L?le(o,L):void 0,ie=Zt(o),G=!t.noCache&&!t.fix?ki({configPath:ie,lockfilePath:X,sections:d,socketEnabled:B,workspaceRoot:o}):void 0,D=G?wi(G):void 0,V=D!==void 0;let Y,v;if(w){const O=D?new et({activeSections:d,findings:vt(yt(D),$)}):new et({activeSections:d}),W=Bt(Ut.createElement(gr,{banner:P,fromCache:V,startedAt:x,store:O}),{alternateScreen:!0,exitOnCtrlC:!1,interactive:!0,patchConsole:!0});try{Y=D??await ot({filterPatterns:$,installed:Z,resolveCodemods:!!t.fix,sections:d,store:O,visConfig:i,workspaceRoot:o})}catch(ee){throw W.unmount(),ee}await W.waitUntilExit(),v=O.getSnapshot().pendingAction}else if(D)Y=D;else{const O=zr(d,E.size,B,q,!!t.fix),W=ci(O,{live:!l&&!p&&!c});try{Y=await ot({filterPatterns:$,installed:Z,progress:W,resolveCodemods:!!t.fix,sections:d,visConfig:i,workspaceRoot:o})}finally{W.stop()}}const A={...Y,elapsedMs:Date.now()-x};if(G&&!V)try{vi(G,A)}catch{}const R=wr(A,$);if(l){process.stdout.write(`${JSON.stringify(Sr(R,b.name),void 0,2)}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { createRequire as __cjs_createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const __cjs_require = __cjs_createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
|
|
6
|
+
|
|
7
|
+
const __cjs_getBuiltinModule = (module) => {
|
|
8
|
+
// Check if we're in Node.js and version supports getBuiltinModule
|
|
9
|
+
if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
|
|
10
|
+
const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
|
|
11
|
+
// Node.js 20.16.0+ and 22.3.0+
|
|
12
|
+
if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
|
|
13
|
+
return __cjs_getProcess.getBuiltinModule(module);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Fallback to createRequire
|
|
17
|
+
return __cjs_require(module);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
writeFileSync: writeFileSync$1
|
|
22
|
+
} = __cjs_getBuiltinModule("node:fs");
|
|
23
|
+
import { getManifestData } from '@socketsecurity/registry';
|
|
24
|
+
import { readFileSync, isAccessibleSync, writeFileSync, readJsonSync, glob } from '@visulima/fs';
|
|
25
|
+
import { join, resolve } from '@visulima/path';
|
|
26
|
+
import { Box, Text, ScrollView, ScrollBar, useApp, useWindowSize, useInput, render } from '@visulima/tui';
|
|
27
|
+
import { _ as QuitDialog, c as detectPm, p as pail, x as runInstall, q as readPnpmWorkspacePatterns, o as resolveWorkspacePatterns, i as isInCi } from './bin.js';
|
|
28
|
+
import microUtilitiesManifest from 'module-replacements/manifests/micro-utilities.json' with { type: 'json' };
|
|
29
|
+
import nativeManifest from 'module-replacements/manifests/native.json' with { type: 'json' };
|
|
30
|
+
import preferredManifest from 'module-replacements/manifests/preferred.json' with { type: 'json' };
|
|
31
|
+
import React, { useSyncExternalStore, useRef, useState, useCallback } from 'react';
|
|
32
|
+
import { coerce } from 'semver';
|
|
33
|
+
import { readYamlSync } from '@visulima/fs/yaml';
|
|
34
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
35
|
+
|
|
36
|
+
const DEP_FIELDS = ["dependencies", "devDependencies", "peerDependencies", "peerDependenciesMeta", "optionalDependencies", "bundleDependencies"];
|
|
37
|
+
const OVERRIDE_FIELDS = ["overrides", "pnpm", "resolutions"];
|
|
38
|
+
const AFTER_FIELDS = ["engines", "files"];
|
|
39
|
+
const isPnpmV10Plus = (version) => {
|
|
40
|
+
const major = coerce(version)?.major;
|
|
41
|
+
return major !== void 0 && major >= 10;
|
|
42
|
+
};
|
|
43
|
+
const readPnpmWorkspaceOverrides = (workspaceRoot) => {
|
|
44
|
+
const filePath = join(workspaceRoot, "pnpm-workspace.yaml");
|
|
45
|
+
if (!isAccessibleSync(filePath)) {
|
|
46
|
+
return { overrides: {}, source: "pnpm-workspace.yaml" };
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const data = readYamlSync(filePath);
|
|
50
|
+
return { overrides: data?.overrides ?? {}, source: "pnpm-workspace.yaml" };
|
|
51
|
+
} catch {
|
|
52
|
+
return { overrides: {}, source: "pnpm-workspace.yaml" };
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const readPkgJsonOverrides = (pkgJson, pm) => {
|
|
56
|
+
let overrides = {};
|
|
57
|
+
if (pm === "pnpm") {
|
|
58
|
+
overrides = pkgJson.pnpm?.overrides ?? {};
|
|
59
|
+
} else if (pm === "yarn" || pm === "bun") {
|
|
60
|
+
overrides = pkgJson.resolutions ?? {};
|
|
61
|
+
} else {
|
|
62
|
+
overrides = pkgJson.overrides ?? {};
|
|
63
|
+
}
|
|
64
|
+
return { overrides, source: "package.json" };
|
|
65
|
+
};
|
|
66
|
+
const readOverrides = (workspaceRoot, pkgJson, pm) => {
|
|
67
|
+
if (pm.name === "pnpm" && isPnpmV10Plus(pm.version)) {
|
|
68
|
+
return readPnpmWorkspaceOverrides(workspaceRoot);
|
|
69
|
+
}
|
|
70
|
+
return readPkgJsonOverrides(pkgJson, pm.name);
|
|
71
|
+
};
|
|
72
|
+
const findInsertIndex = (keys, field) => {
|
|
73
|
+
const simpleField = field;
|
|
74
|
+
for (const f of OVERRIDE_FIELDS) {
|
|
75
|
+
const index = keys.indexOf(f);
|
|
76
|
+
if (index !== -1 && f !== simpleField) {
|
|
77
|
+
return simpleField === "overrides" ? index : index + 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
let highest = -1;
|
|
81
|
+
for (const f of DEP_FIELDS) {
|
|
82
|
+
const index = keys.indexOf(f);
|
|
83
|
+
if (index > highest) {
|
|
84
|
+
highest = index;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (highest !== -1) {
|
|
88
|
+
return highest + 1;
|
|
89
|
+
}
|
|
90
|
+
for (const f of AFTER_FIELDS) {
|
|
91
|
+
const index = keys.indexOf(f);
|
|
92
|
+
if (index !== -1) {
|
|
93
|
+
return index;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return keys.length;
|
|
97
|
+
};
|
|
98
|
+
const detectIndent = (content) => {
|
|
99
|
+
const match = /\n(\s+)/.exec(content);
|
|
100
|
+
return match?.[1] ?? " ";
|
|
101
|
+
};
|
|
102
|
+
const writePnpmWorkspaceOverrides = (workspaceRoot, sorted) => {
|
|
103
|
+
const filePath = join(workspaceRoot, "pnpm-workspace.yaml");
|
|
104
|
+
if (!isAccessibleSync(filePath)) {
|
|
105
|
+
throw new Error(`pnpm-workspace.yaml not found at ${filePath}. Cannot write overrides for pnpm v10+.`);
|
|
106
|
+
}
|
|
107
|
+
let content = readFileSync(filePath);
|
|
108
|
+
const overrideLines = Object.entries(sorted).map(([key, value]) => ` '${key}': '${value}'`).join("\n");
|
|
109
|
+
const overridesBlock = `overrides:
|
|
110
|
+
${overrideLines}
|
|
111
|
+
`;
|
|
112
|
+
content = /^overrides:\s*$/m.test(content) || /^overrides:\s*\n/m.test(content) ? content.replace(/^overrides:\s*\n(?:(?:[ \t].*)?\n)*/m, overridesBlock) : `${content.trimEnd()}
|
|
113
|
+
|
|
114
|
+
${overridesBlock}`;
|
|
115
|
+
writeFileSync(filePath, content);
|
|
116
|
+
};
|
|
117
|
+
const writePkgJsonOverrides = (pkgJsonPath, pkgJson, sorted, pm) => {
|
|
118
|
+
const raw = readFileSync(pkgJsonPath);
|
|
119
|
+
const indent = detectIndent(raw);
|
|
120
|
+
if (pm === "pnpm") {
|
|
121
|
+
const pnpmObject = pkgJson.pnpm ?? {};
|
|
122
|
+
pnpmObject.overrides = sorted;
|
|
123
|
+
if (pkgJson.pnpm) {
|
|
124
|
+
pkgJson.pnpm = pnpmObject;
|
|
125
|
+
writeFileSync(pkgJsonPath, `${JSON.stringify(pkgJson, null, indent)}
|
|
126
|
+
`);
|
|
127
|
+
} else {
|
|
128
|
+
const keys = Object.keys(pkgJson);
|
|
129
|
+
const index = findInsertIndex(keys, "pnpm");
|
|
130
|
+
const jsonEntries = Object.entries(pkgJson);
|
|
131
|
+
jsonEntries.splice(index, 0, ["pnpm", pnpmObject]);
|
|
132
|
+
writeFileSync(pkgJsonPath, `${JSON.stringify(Object.fromEntries(jsonEntries), null, indent)}
|
|
133
|
+
`);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
const field = pm === "yarn" || pm === "bun" ? "resolutions" : "overrides";
|
|
137
|
+
if (pkgJson[field]) {
|
|
138
|
+
pkgJson[field] = sorted;
|
|
139
|
+
writeFileSync(pkgJsonPath, `${JSON.stringify(pkgJson, null, indent)}
|
|
140
|
+
`);
|
|
141
|
+
} else {
|
|
142
|
+
const keys = Object.keys(pkgJson);
|
|
143
|
+
const index = findInsertIndex(keys, field);
|
|
144
|
+
const jsonEntries = Object.entries(pkgJson);
|
|
145
|
+
jsonEntries.splice(index, 0, [field, sorted]);
|
|
146
|
+
writeFileSync(pkgJsonPath, `${JSON.stringify(Object.fromEntries(jsonEntries), null, indent)}
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const applyOverrides = (workspaceRoot, pkgJsonPath, entries, pm) => {
|
|
152
|
+
const raw = readFileSync(pkgJsonPath);
|
|
153
|
+
const pkgJson = JSON.parse(raw);
|
|
154
|
+
const { overrides: existing, source } = readOverrides(workspaceRoot, pkgJson, pm);
|
|
155
|
+
const added = [];
|
|
156
|
+
const updated = [];
|
|
157
|
+
const directDeps = /* @__PURE__ */ new Set();
|
|
158
|
+
if (pm.name === "npm") {
|
|
159
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
160
|
+
const deps = pkgJson[field];
|
|
161
|
+
if (deps) {
|
|
162
|
+
for (const name of Object.keys(deps)) {
|
|
163
|
+
directDeps.add(name);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
const oldSpec = existing[entry.original];
|
|
170
|
+
if (typeof oldSpec === "object") {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
let newSpec = entry.spec;
|
|
174
|
+
if (pm.name === "npm" && directDeps.has(entry.original)) {
|
|
175
|
+
newSpec = `$${entry.original}`;
|
|
176
|
+
}
|
|
177
|
+
if (oldSpec === newSpec) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (oldSpec) {
|
|
181
|
+
updated.push(entry.original);
|
|
182
|
+
} else {
|
|
183
|
+
added.push(entry.original);
|
|
184
|
+
}
|
|
185
|
+
existing[entry.original] = newSpec;
|
|
186
|
+
}
|
|
187
|
+
if (added.length === 0 && updated.length === 0) {
|
|
188
|
+
return { added, updated };
|
|
189
|
+
}
|
|
190
|
+
const sorted = Object.fromEntries(Object.entries(existing).sort(([a], [b]) => a.localeCompare(b)));
|
|
191
|
+
if (source === "pnpm-workspace.yaml") {
|
|
192
|
+
writePnpmWorkspaceOverrides(workspaceRoot, sorted);
|
|
193
|
+
} else {
|
|
194
|
+
writePkgJsonOverrides(pkgJsonPath, pkgJson, sorted, pm.name);
|
|
195
|
+
}
|
|
196
|
+
return { added, updated };
|
|
197
|
+
};
|
|
198
|
+
const readLockfileText = (workspaceRoot, pm) => {
|
|
199
|
+
const lockfileNames = {
|
|
200
|
+
bun: ["bun.lock"],
|
|
201
|
+
npm: ["npm-shrinkwrap.json", "package-lock.json"],
|
|
202
|
+
pnpm: ["pnpm-lock.yaml"],
|
|
203
|
+
yarn: ["yarn.lock"]
|
|
204
|
+
};
|
|
205
|
+
for (const name of lockfileNames[pm] ?? []) {
|
|
206
|
+
const filePath = join(workspaceRoot, name);
|
|
207
|
+
try {
|
|
208
|
+
return readFileSync(filePath);
|
|
209
|
+
} catch {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return "";
|
|
214
|
+
};
|
|
215
|
+
const lockfileContainsPackage = (lockText, packageName, pm) => {
|
|
216
|
+
if (!lockText) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
const escaped = packageName.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
220
|
+
switch (pm) {
|
|
221
|
+
case "bun": {
|
|
222
|
+
return lockText.includes(`"${packageName}":`) || new RegExp(String.raw`(^|\s|[",])${escaped}@`, "m").test(lockText);
|
|
223
|
+
}
|
|
224
|
+
case "npm": {
|
|
225
|
+
return lockText.includes(`"${packageName}":`) || lockText.includes(`"node_modules/${packageName}":`);
|
|
226
|
+
}
|
|
227
|
+
case "pnpm": {
|
|
228
|
+
return new RegExp(String.raw`(^|\s|['"/])${escaped}(@|['"]?:)`, "m").test(lockText);
|
|
229
|
+
}
|
|
230
|
+
case "yarn": {
|
|
231
|
+
return new RegExp(String.raw`(^|\s|[",])${escaped}@`, "m").test(lockText);
|
|
232
|
+
}
|
|
233
|
+
default: {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const filterEntries = (entries, filterType, filterText) => {
|
|
240
|
+
let filtered = entries;
|
|
241
|
+
if (filterType !== "all") {
|
|
242
|
+
filtered = filtered.filter((e) => e.category === filterType);
|
|
243
|
+
}
|
|
244
|
+
if (filterText) {
|
|
245
|
+
const lower = filterText.toLowerCase();
|
|
246
|
+
filtered = filtered.filter((e) => e.packageName.toLowerCase().includes(lower));
|
|
247
|
+
}
|
|
248
|
+
return filtered;
|
|
249
|
+
};
|
|
250
|
+
class OptimizeStore {
|
|
251
|
+
#state;
|
|
252
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
253
|
+
constructor(entries) {
|
|
254
|
+
this.#state = {
|
|
255
|
+
applyProgress: null,
|
|
256
|
+
checkedEntries: /* @__PURE__ */ new Set(),
|
|
257
|
+
entries,
|
|
258
|
+
error: null,
|
|
259
|
+
filterActive: false,
|
|
260
|
+
filterText: "",
|
|
261
|
+
filterType: "all",
|
|
262
|
+
focusedPanel: "list",
|
|
263
|
+
phase: "browsing",
|
|
264
|
+
selectedIndex: 0
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
getSnapshot = () => this.#state;
|
|
268
|
+
subscribe = (listener) => {
|
|
269
|
+
this.#listeners.add(listener);
|
|
270
|
+
return () => {
|
|
271
|
+
this.#listeners.delete(listener);
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
getFilteredEntries = () => filterEntries(this.#state.entries, this.#state.filterType, this.#state.filterText);
|
|
275
|
+
#notify() {
|
|
276
|
+
this.#state = { ...this.#state };
|
|
277
|
+
for (const listener of this.#listeners) {
|
|
278
|
+
listener();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
select(index) {
|
|
282
|
+
const filtered = this.getFilteredEntries();
|
|
283
|
+
this.#state.selectedIndex = filtered.length === 0 ? -1 : Math.max(0, Math.min(index, filtered.length - 1));
|
|
284
|
+
this.#notify();
|
|
285
|
+
}
|
|
286
|
+
toggleCheck(packageName) {
|
|
287
|
+
const checked = new Set(this.#state.checkedEntries);
|
|
288
|
+
if (checked.has(packageName)) {
|
|
289
|
+
checked.delete(packageName);
|
|
290
|
+
} else {
|
|
291
|
+
checked.add(packageName);
|
|
292
|
+
}
|
|
293
|
+
this.#state.checkedEntries = checked;
|
|
294
|
+
this.#notify();
|
|
295
|
+
}
|
|
296
|
+
toggleAll() {
|
|
297
|
+
const filtered = this.getFilteredEntries();
|
|
298
|
+
const checked = new Set(this.#state.checkedEntries);
|
|
299
|
+
const allChecked = filtered.every((e) => checked.has(e.packageName));
|
|
300
|
+
if (allChecked) {
|
|
301
|
+
for (const e of filtered) {
|
|
302
|
+
checked.delete(e.packageName);
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
for (const e of filtered) {
|
|
306
|
+
checked.add(e.packageName);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
this.#state.checkedEntries = checked;
|
|
310
|
+
this.#notify();
|
|
311
|
+
}
|
|
312
|
+
setFilter(type) {
|
|
313
|
+
this.#state.filterType = type;
|
|
314
|
+
this.#state.selectedIndex = 0;
|
|
315
|
+
this.#notify();
|
|
316
|
+
}
|
|
317
|
+
setFilterText(text) {
|
|
318
|
+
this.#state.filterText = text;
|
|
319
|
+
this.#state.selectedIndex = 0;
|
|
320
|
+
this.#notify();
|
|
321
|
+
}
|
|
322
|
+
setFilterActive(active) {
|
|
323
|
+
this.#state.filterActive = active;
|
|
324
|
+
this.#notify();
|
|
325
|
+
}
|
|
326
|
+
setFocusedPanel(panel) {
|
|
327
|
+
this.#state.focusedPanel = panel;
|
|
328
|
+
this.#notify();
|
|
329
|
+
}
|
|
330
|
+
setPhase(phase) {
|
|
331
|
+
this.#state.phase = phase;
|
|
332
|
+
this.#notify();
|
|
333
|
+
}
|
|
334
|
+
setProgress(current, total) {
|
|
335
|
+
this.#state.applyProgress = { current, total };
|
|
336
|
+
this.#notify();
|
|
337
|
+
}
|
|
338
|
+
setError(error) {
|
|
339
|
+
this.#state.error = error;
|
|
340
|
+
this.#state.phase = "error";
|
|
341
|
+
this.#notify();
|
|
342
|
+
}
|
|
343
|
+
getCheckedEntries() {
|
|
344
|
+
return this.#state.entries.filter((e) => this.#state.checkedEntries.has(e.packageName));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const CATEGORY_COLORS = {
|
|
349
|
+
"micro-utility": "gray",
|
|
350
|
+
native: "green",
|
|
351
|
+
preferred: "yellow",
|
|
352
|
+
socket: "cyan"
|
|
353
|
+
};
|
|
354
|
+
const CATEGORY_LABELS = {
|
|
355
|
+
"micro-utility": "MICRO",
|
|
356
|
+
native: "NATIVE",
|
|
357
|
+
preferred: "PREF",
|
|
358
|
+
socket: "SOCKET"
|
|
359
|
+
};
|
|
360
|
+
const CATEGORY_DESCRIPTIONS = {
|
|
361
|
+
"micro-utility": "Trivial utility package that can be replaced with inline code.",
|
|
362
|
+
native: "Polyfill for a native JS/Node.js API. Use the built-in instead.",
|
|
363
|
+
preferred: "A lighter or faster alternative package exists.",
|
|
364
|
+
socket: "Security-hardened replacement from Socket.dev's @socketregistry."
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
const OptimizeDetailPanel = ({ entry, focused, scrollRef }) => {
|
|
368
|
+
const borderColor = focused ? "white" : "gray";
|
|
369
|
+
if (!entry) {
|
|
370
|
+
return jsx(Box, { alignItems: "center", borderColor: "gray", borderStyle: "single", flexDirection: "column", flexGrow: 1, justifyContent: "center", children: jsx(Text, { dimColor: true, children: "No entry selected" }) });
|
|
371
|
+
}
|
|
372
|
+
const categoryColor = CATEGORY_COLORS[entry.category] ?? "gray";
|
|
373
|
+
return jsxs(Box, { borderColor, borderStyle: "single", flexDirection: "column", flexGrow: 1, children: [
|
|
374
|
+
jsx(Box, { flexShrink: 0, paddingTop: 1, paddingX: 2, children: jsx(Text, { bold: true, color: "white", children: entry.packageName }) }),
|
|
375
|
+
jsxs(ScrollView, { flexGrow: 1, flexShrink: 1, paddingX: 2, ref: scrollRef, scrollbar: true, scrollbarColor: "gray", children: [
|
|
376
|
+
jsx(Text, {}),
|
|
377
|
+
jsxs(Box, { children: [
|
|
378
|
+
jsx(Box, { width: 14, children: jsx(Text, { dimColor: true, children: "Category:" }) }),
|
|
379
|
+
jsx(Text, { bold: true, color: categoryColor, children: entry.category })
|
|
380
|
+
] }),
|
|
381
|
+
jsxs(Box, { children: [
|
|
382
|
+
jsx(Box, { width: 14, children: jsx(Text, { dimColor: true, children: "Replace with:" }) }),
|
|
383
|
+
jsx(Text, { children: entry.replacement })
|
|
384
|
+
] }),
|
|
385
|
+
entry.overrideSpec && jsxs(Box, { children: [
|
|
386
|
+
jsx(Box, { width: 14, children: jsx(Text, { dimColor: true, children: "Override:" }) }),
|
|
387
|
+
jsx(Text, { color: "cyan", children: entry.overrideSpec })
|
|
388
|
+
] }),
|
|
389
|
+
jsxs(Box, { children: [
|
|
390
|
+
jsx(Box, { width: 14, children: jsx(Text, { dimColor: true, children: "Codemod:" }) }),
|
|
391
|
+
jsx(Text, { color: entry.hasCodemod ? "green" : "gray", children: entry.hasCodemod ? "available ⚙" : "not available" })
|
|
392
|
+
] }),
|
|
393
|
+
jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
394
|
+
jsx(Text, { dimColor: true, children: "── " }),
|
|
395
|
+
jsx(Text, { bold: true, color: "white", children: "DESCRIPTION" }),
|
|
396
|
+
jsx(Box, { marginTop: 1, paddingLeft: 2, children: jsx(Text, { children: CATEGORY_DESCRIPTIONS[entry.category] ?? "" }) })
|
|
397
|
+
] }),
|
|
398
|
+
entry.category === "native" && jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
399
|
+
jsx(Text, { dimColor: true, children: "── " }),
|
|
400
|
+
jsx(Text, { bold: true, color: "green", children: "ACTION" }),
|
|
401
|
+
jsx(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, children: entry.hasCodemod ? jsxs(Fragment, { children: [
|
|
402
|
+
jsxs(Text, { color: "green", children: [
|
|
403
|
+
"✓",
|
|
404
|
+
" Codemod will rewrite imports to use native API."
|
|
405
|
+
] }),
|
|
406
|
+
jsx(Text, { dimColor: true, children: " The package can then be removed from dependencies." })
|
|
407
|
+
] }) : jsxs(Fragment, { children: [
|
|
408
|
+
jsxs(Text, { color: "yellow", children: [
|
|
409
|
+
"ℹ",
|
|
410
|
+
" No automated codemod available."
|
|
411
|
+
] }),
|
|
412
|
+
jsx(Text, { dimColor: true, children: " Manual migration required — replace usage with native equivalent." })
|
|
413
|
+
] }) })
|
|
414
|
+
] }),
|
|
415
|
+
entry.category === "socket" && jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
416
|
+
jsx(Text, { dimColor: true, children: "── " }),
|
|
417
|
+
jsx(Text, { bold: true, color: "cyan", children: "ACTION" }),
|
|
418
|
+
jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, children: [
|
|
419
|
+
jsxs(Text, { color: "cyan", children: [
|
|
420
|
+
"✓",
|
|
421
|
+
" Override will redirect resolution to the hardened package."
|
|
422
|
+
] }),
|
|
423
|
+
jsx(Text, { dimColor: true, children: " No source code changes needed — drop-in replacement." })
|
|
424
|
+
] })
|
|
425
|
+
] }),
|
|
426
|
+
(entry.category === "preferred" || entry.category === "micro-utility") && jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
427
|
+
jsx(Text, { dimColor: true, children: "── " }),
|
|
428
|
+
jsx(Text, { bold: true, color: "yellow", children: "ACTION" }),
|
|
429
|
+
jsx(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, children: entry.hasCodemod ? jsxs(Fragment, { children: [
|
|
430
|
+
jsxs(Text, { color: "green", children: [
|
|
431
|
+
"✓",
|
|
432
|
+
" Codemod will rewrite imports to the recommended alternative."
|
|
433
|
+
] }),
|
|
434
|
+
jsx(Text, { dimColor: true, children: " The original package can then be removed from dependencies." })
|
|
435
|
+
] }) : jsxs(Fragment, { children: [
|
|
436
|
+
jsxs(Text, { color: "yellow", children: [
|
|
437
|
+
"ℹ",
|
|
438
|
+
" Manual migration required."
|
|
439
|
+
] }),
|
|
440
|
+
entry.docUrl ? jsx(Text, { dimColor: true, children: " Open the migration guide below for the recommended alternative and steps." }) : jsx(Text, { dimColor: true, children: " Consult the package's docs or the e18e module-replacements guide for an alternative." })
|
|
441
|
+
] }) })
|
|
442
|
+
] }),
|
|
443
|
+
jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
444
|
+
jsx(Text, { dimColor: true, children: "── " }),
|
|
445
|
+
jsx(Text, { bold: true, color: "white", children: "LINKS" }),
|
|
446
|
+
jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, children: [
|
|
447
|
+
jsxs(Text, { color: "cyan", underline: true, children: [
|
|
448
|
+
"https://npmx.dev/",
|
|
449
|
+
entry.packageName
|
|
450
|
+
] }),
|
|
451
|
+
entry.docUrl && jsx(Text, { color: "cyan", underline: true, children: entry.docUrl })
|
|
452
|
+
] })
|
|
453
|
+
] })
|
|
454
|
+
] })
|
|
455
|
+
] });
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const FILTER_LABELS = [
|
|
459
|
+
{ key: "all", label: "All", shortcut: "1" },
|
|
460
|
+
{ key: "native", label: "Native", shortcut: "2" },
|
|
461
|
+
{ key: "preferred", label: "Preferred", shortcut: "3" },
|
|
462
|
+
{ key: "micro-utility", label: "Micro", shortcut: "4" },
|
|
463
|
+
{ key: "socket", label: "Socket", shortcut: "5" }
|
|
464
|
+
];
|
|
465
|
+
const EntryRow = ({ checked, entry, isSelected }) => {
|
|
466
|
+
const catColor = CATEGORY_COLORS[entry.category] ?? "white";
|
|
467
|
+
const catLabel = CATEGORY_LABELS[entry.category] ?? entry.category;
|
|
468
|
+
const checkbox = checked ? "☑" : "☐";
|
|
469
|
+
const codemodBadge = entry.hasCodemod ? "⚙" : " ";
|
|
470
|
+
return jsxs(Box, { flexShrink: 0, height: 1, children: [
|
|
471
|
+
jsx(Text, { children: isSelected ? ">" : " " }),
|
|
472
|
+
jsxs(Text, { color: checked ? "white" : "gray", children: [
|
|
473
|
+
" ",
|
|
474
|
+
checkbox,
|
|
475
|
+
" "
|
|
476
|
+
] }),
|
|
477
|
+
jsx(Text, { bold: true, color: catColor, children: `[${catLabel}]`.padEnd(9) }),
|
|
478
|
+
jsxs(Text, { children: [
|
|
479
|
+
" ",
|
|
480
|
+
codemodBadge,
|
|
481
|
+
" "
|
|
482
|
+
] }),
|
|
483
|
+
jsx(Box, { flexGrow: 1, children: jsx(Text, { bold: isSelected, inverse: isSelected, wrap: "truncate", children: entry.packageName }) }),
|
|
484
|
+
jsx(Text, { dimColor: true, children: " → " }),
|
|
485
|
+
jsx(Text, { wrap: "truncate", children: entry.replacement })
|
|
486
|
+
] });
|
|
487
|
+
};
|
|
488
|
+
const OptimizeListPanel = ({
|
|
489
|
+
checkedEntries,
|
|
490
|
+
entries,
|
|
491
|
+
filterActive,
|
|
492
|
+
filterText,
|
|
493
|
+
filterType,
|
|
494
|
+
focused,
|
|
495
|
+
isDryRun,
|
|
496
|
+
scrollOffset,
|
|
497
|
+
selectedIndex,
|
|
498
|
+
totalEntries,
|
|
499
|
+
viewportHeight
|
|
500
|
+
}) => {
|
|
501
|
+
const borderColor = focused ? "white" : "gray";
|
|
502
|
+
let nativeCount = 0;
|
|
503
|
+
let preferredCount = 0;
|
|
504
|
+
let microCount = 0;
|
|
505
|
+
let socketCount = 0;
|
|
506
|
+
for (const e of entries) {
|
|
507
|
+
switch (e.category) {
|
|
508
|
+
case "micro-utility": {
|
|
509
|
+
microCount++;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
case "native": {
|
|
513
|
+
nativeCount++;
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
case "preferred": {
|
|
517
|
+
preferredCount++;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
case "socket": {
|
|
521
|
+
{
|
|
522
|
+
socketCount++;
|
|
523
|
+
}
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
const summaryParts = [];
|
|
529
|
+
if (nativeCount > 0) {
|
|
530
|
+
summaryParts.push(`${nativeCount} native`);
|
|
531
|
+
}
|
|
532
|
+
if (preferredCount > 0) {
|
|
533
|
+
summaryParts.push(`${preferredCount} preferred`);
|
|
534
|
+
}
|
|
535
|
+
if (microCount > 0) {
|
|
536
|
+
summaryParts.push(`${microCount} micro`);
|
|
537
|
+
}
|
|
538
|
+
if (socketCount > 0) {
|
|
539
|
+
summaryParts.push(`${socketCount} socket`);
|
|
540
|
+
}
|
|
541
|
+
const summaryText = summaryParts.length > 0 ? ` (${summaryParts.join(", ")})` : "";
|
|
542
|
+
const checkedCount = checkedEntries.size;
|
|
543
|
+
const rows = [];
|
|
544
|
+
for (const [index, entry] of entries.entries()) {
|
|
545
|
+
rows.push(jsx(EntryRow, { checked: checkedEntries.has(entry.packageName), entry, isSelected: index === selectedIndex }, entry.packageName));
|
|
546
|
+
}
|
|
547
|
+
const contentHeight = entries.length;
|
|
548
|
+
const showScrollbar = contentHeight > viewportHeight && viewportHeight > 0;
|
|
549
|
+
return jsxs(Box, { borderColor, borderStyle: "single", flexDirection: "column", flexGrow: 1, children: [
|
|
550
|
+
jsxs(Box, { flexShrink: 0, gap: 1, paddingX: 1, children: [
|
|
551
|
+
jsx(Text, { bold: true, inverse: true, children: " VIS OPTIMIZE " }),
|
|
552
|
+
jsxs(Text, { wrap: "truncate", children: [
|
|
553
|
+
totalEntries,
|
|
554
|
+
" optimizations",
|
|
555
|
+
summaryText
|
|
556
|
+
] }),
|
|
557
|
+
!isDryRun && checkedCount > 0 && jsxs(Text, { dimColor: true, children: [
|
|
558
|
+
" —",
|
|
559
|
+
checkedCount,
|
|
560
|
+
" selected"
|
|
561
|
+
] })
|
|
562
|
+
] }),
|
|
563
|
+
jsx(Box, { flexShrink: 0, gap: 1, paddingX: 1, paddingY: 1, children: FILTER_LABELS.map((f) => {
|
|
564
|
+
const isActive = filterType === f.key;
|
|
565
|
+
return jsxs(Box, { children: [
|
|
566
|
+
jsx(Text, { dimColor: !isActive, children: "[" }),
|
|
567
|
+
jsx(Text, { bold: isActive, color: isActive ? "cyan" : "gray", children: f.shortcut }),
|
|
568
|
+
jsx(Text, { dimColor: !isActive, children: "]" }),
|
|
569
|
+
jsxs(Text, { color: isActive ? "white" : "gray", children: [
|
|
570
|
+
" ",
|
|
571
|
+
f.label
|
|
572
|
+
] })
|
|
573
|
+
] }, f.key);
|
|
574
|
+
}) }),
|
|
575
|
+
filterActive && jsxs(Box, { flexShrink: 0, paddingX: 1, children: [
|
|
576
|
+
jsx(Text, { bold: true, color: "white", children: "/ " }),
|
|
577
|
+
jsx(Text, { children: filterText }),
|
|
578
|
+
jsx(Text, { inverse: true, children: " " })
|
|
579
|
+
] }),
|
|
580
|
+
jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [
|
|
581
|
+
jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", paddingLeft: 1, children: jsx(Box, { flexDirection: "column", marginTop: -scrollOffset, children: rows }) }),
|
|
582
|
+
showScrollbar && jsx(Box, { flexShrink: 0, marginLeft: 1, marginRight: 1, children: jsx(ScrollBar, { contentHeight, placement: "inset", scrollOffset, style: "block", viewportHeight }) })
|
|
583
|
+
] })
|
|
584
|
+
] });
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
const MIN_HORIZONTAL_WIDTH = 100;
|
|
588
|
+
const MIN_VIEWPORT_HEIGHT = 10;
|
|
589
|
+
const FILTER_KEYS = {
|
|
590
|
+
1: "all",
|
|
591
|
+
2: "native",
|
|
592
|
+
3: "preferred",
|
|
593
|
+
4: "micro-utility",
|
|
594
|
+
5: "socket"
|
|
595
|
+
};
|
|
596
|
+
const VisOptimizeApp = ({ isDryRun, store }) => {
|
|
597
|
+
const { exit } = useApp();
|
|
598
|
+
const { columns, rows } = useWindowSize();
|
|
599
|
+
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
600
|
+
const detailScrollRef = useRef(null);
|
|
601
|
+
const [listScrollOffset, setListScrollOffset] = useState(0);
|
|
602
|
+
const [quitDialogVisible, setQuitDialogVisible] = useState(false);
|
|
603
|
+
const filteredEntries = store.getFilteredEntries();
|
|
604
|
+
const selectedEntry = filteredEntries[state.selectedIndex] ?? null;
|
|
605
|
+
const isHorizontal = columns >= MIN_HORIZONTAL_WIDTH;
|
|
606
|
+
const headerHeight = 5;
|
|
607
|
+
const viewportHeight = Math.max(0, rows - headerHeight);
|
|
608
|
+
const handleExit = useCallback(
|
|
609
|
+
(result) => {
|
|
610
|
+
exit(result);
|
|
611
|
+
},
|
|
612
|
+
[exit]
|
|
613
|
+
);
|
|
614
|
+
useInput(
|
|
615
|
+
(input, key) => {
|
|
616
|
+
if (quitDialogVisible) {
|
|
617
|
+
if (input === "y" || input === "Y") {
|
|
618
|
+
handleExit();
|
|
619
|
+
} else {
|
|
620
|
+
setQuitDialogVisible(false);
|
|
621
|
+
}
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (state.filterActive) {
|
|
625
|
+
if (key.escape) {
|
|
626
|
+
store.setFilterActive(false);
|
|
627
|
+
store.setFilterText("");
|
|
628
|
+
} else if (key.return) {
|
|
629
|
+
store.setFilterActive(false);
|
|
630
|
+
} else if (key.backspace || key.delete) {
|
|
631
|
+
store.setFilterText(state.filterText.slice(0, -1));
|
|
632
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
633
|
+
store.setFilterText(state.filterText + input);
|
|
634
|
+
}
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (input === "q") {
|
|
638
|
+
if (!isDryRun && state.checkedEntries.size > 0) {
|
|
639
|
+
setQuitDialogVisible(true);
|
|
640
|
+
} else {
|
|
641
|
+
handleExit();
|
|
642
|
+
}
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (input === "/") {
|
|
646
|
+
store.setFilterActive(true);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
if (FILTER_KEYS[input]) {
|
|
650
|
+
store.setFilter(FILTER_KEYS[input]);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (key.tab) {
|
|
654
|
+
store.setFocusedPanel(state.focusedPanel === "list" ? "detail" : "list");
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
if (state.focusedPanel === "list") {
|
|
658
|
+
if (key.upArrow || input === "k") {
|
|
659
|
+
const newIndex = Math.max(0, state.selectedIndex - 1);
|
|
660
|
+
store.select(newIndex);
|
|
661
|
+
if (newIndex < listScrollOffset) {
|
|
662
|
+
setListScrollOffset(newIndex);
|
|
663
|
+
}
|
|
664
|
+
} else if (key.downArrow || input === "j") {
|
|
665
|
+
const newIndex = Math.min(filteredEntries.length - 1, state.selectedIndex + 1);
|
|
666
|
+
store.select(newIndex);
|
|
667
|
+
if (newIndex >= listScrollOffset + viewportHeight) {
|
|
668
|
+
setListScrollOffset(newIndex - viewportHeight + 1);
|
|
669
|
+
}
|
|
670
|
+
} else if (input === " ") {
|
|
671
|
+
if (selectedEntry) {
|
|
672
|
+
store.toggleCheck(selectedEntry.packageName);
|
|
673
|
+
}
|
|
674
|
+
} else if (input === "a") {
|
|
675
|
+
store.toggleAll();
|
|
676
|
+
} else if (key.return && !isDryRun && state.checkedEntries.size > 0) {
|
|
677
|
+
handleExit(store.getCheckedEntries());
|
|
678
|
+
}
|
|
679
|
+
} else if (state.focusedPanel === "detail") {
|
|
680
|
+
if (key.upArrow || input === "k") {
|
|
681
|
+
detailScrollRef.current?.scrollBy(-1);
|
|
682
|
+
} else if (key.downArrow || input === "j") {
|
|
683
|
+
detailScrollRef.current?.scrollBy(1);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
{ isActive: state.phase === "browsing" }
|
|
688
|
+
);
|
|
689
|
+
if (rows < MIN_VIEWPORT_HEIGHT) {
|
|
690
|
+
return jsx(Box, { alignItems: "center", justifyContent: "center", children: jsxs(Text, { color: "yellow", children: [
|
|
691
|
+
"Terminal too small. Resize to at least",
|
|
692
|
+
MIN_VIEWPORT_HEIGHT,
|
|
693
|
+
" rows."
|
|
694
|
+
] }) });
|
|
695
|
+
}
|
|
696
|
+
return jsxs(Box, { flexDirection: "column", height: rows, width: columns, children: [
|
|
697
|
+
jsxs(Box, { flexDirection: isHorizontal ? "row" : "column", flexGrow: 1, children: [
|
|
698
|
+
jsx(Box, { flexBasis: isHorizontal ? "50%" : void 0, flexGrow: 1, children: jsx(
|
|
699
|
+
OptimizeListPanel,
|
|
700
|
+
{
|
|
701
|
+
checkedEntries: state.checkedEntries,
|
|
702
|
+
entries: filteredEntries,
|
|
703
|
+
filterActive: state.filterActive,
|
|
704
|
+
filterText: state.filterText,
|
|
705
|
+
filterType: state.filterType,
|
|
706
|
+
focused: state.focusedPanel === "list",
|
|
707
|
+
isDryRun,
|
|
708
|
+
scrollOffset: listScrollOffset,
|
|
709
|
+
selectedIndex: state.selectedIndex,
|
|
710
|
+
totalEntries: state.entries.length,
|
|
711
|
+
viewportHeight
|
|
712
|
+
}
|
|
713
|
+
) }),
|
|
714
|
+
jsx(Box, { flexBasis: isHorizontal ? "50%" : void 0, flexGrow: 1, children: jsx(OptimizeDetailPanel, { entry: selectedEntry, focused: state.focusedPanel === "detail", scrollRef: detailScrollRef }) })
|
|
715
|
+
] }),
|
|
716
|
+
jsx(Box, { flexShrink: 0, paddingX: 1, children: jsxs(Text, { dimColor: true, children: [
|
|
717
|
+
isDryRun ? "Preview mode" : "space:toggle a:all enter:apply",
|
|
718
|
+
" | tab:switch panel /: filter q:quit |",
|
|
719
|
+
"⚙",
|
|
720
|
+
"=codemod available"
|
|
721
|
+
] }) }),
|
|
722
|
+
jsx(
|
|
723
|
+
QuitDialog,
|
|
724
|
+
{
|
|
725
|
+
autoExitSeconds: 3,
|
|
726
|
+
onCancel: () => {
|
|
727
|
+
setQuitDialogVisible(false);
|
|
728
|
+
},
|
|
729
|
+
visible: quitDialogVisible
|
|
730
|
+
}
|
|
731
|
+
)
|
|
732
|
+
] });
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
const collectDepsFromPkgJson = (pkgJsonPath, productionOnly) => {
|
|
736
|
+
const deps = /* @__PURE__ */ new Set();
|
|
737
|
+
try {
|
|
738
|
+
const pkg = readJsonSync(pkgJsonPath);
|
|
739
|
+
const maps = productionOnly ? [pkg.dependencies, pkg.optionalDependencies] : [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies, pkg.optionalDependencies];
|
|
740
|
+
for (const depMap of maps) {
|
|
741
|
+
if (depMap) {
|
|
742
|
+
for (const name of Object.keys(depMap)) {
|
|
743
|
+
deps.add(name);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
} catch {
|
|
748
|
+
}
|
|
749
|
+
return deps;
|
|
750
|
+
};
|
|
751
|
+
const discoverWorkspacePackages = (workspaceRoot) => {
|
|
752
|
+
const pnpmPatterns = readPnpmWorkspacePatterns(workspaceRoot);
|
|
753
|
+
if (pnpmPatterns) {
|
|
754
|
+
return resolveWorkspacePatterns(workspaceRoot, pnpmPatterns);
|
|
755
|
+
}
|
|
756
|
+
const rootPkgPath = join(workspaceRoot, "package.json");
|
|
757
|
+
if (!isAccessibleSync(rootPkgPath)) {
|
|
758
|
+
return [];
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
const pkg = readJsonSync(rootPkgPath);
|
|
762
|
+
const patterns = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages;
|
|
763
|
+
return patterns ? resolveWorkspacePatterns(workspaceRoot, patterns) : [];
|
|
764
|
+
} catch {
|
|
765
|
+
return [];
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
const E18E_DOC_BASE_URL = "https://github.com/es-tooling/module-replacements/blob/main/docs/modules";
|
|
769
|
+
const buildE18eDocUrl = (docPath) => `${E18E_DOC_BASE_URL}/${docPath}.md`;
|
|
770
|
+
const e18eReplacementHint = (entry) => {
|
|
771
|
+
if (entry.type === "simple" && entry.replacement) {
|
|
772
|
+
return entry.replacement;
|
|
773
|
+
}
|
|
774
|
+
if (entry.type === "native") {
|
|
775
|
+
const minNode = entry.nodeVersion ? ` (Node ${entry.nodeVersion}+)` : "";
|
|
776
|
+
return entry.replacement ? `${entry.replacement}${minNode}` : `Native API${minNode}`;
|
|
777
|
+
}
|
|
778
|
+
if (entry.type === "documented" && entry.docPath) {
|
|
779
|
+
return "see migration guide";
|
|
780
|
+
}
|
|
781
|
+
return "";
|
|
782
|
+
};
|
|
783
|
+
const buildE18eEntries = (allDeps) => {
|
|
784
|
+
const entries = [];
|
|
785
|
+
const scanManifest = (manifest, category) => {
|
|
786
|
+
const list = manifest.moduleReplacements;
|
|
787
|
+
if (!Array.isArray(list)) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
for (const entry of list) {
|
|
791
|
+
if (!allDeps.has(entry.moduleName)) {
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
entries.push({
|
|
795
|
+
category,
|
|
796
|
+
docUrl: entry.type === "documented" && entry.docPath ? buildE18eDocUrl(entry.docPath) : void 0,
|
|
797
|
+
hasCodemod: false,
|
|
798
|
+
// filled in below
|
|
799
|
+
overrideSpec: void 0,
|
|
800
|
+
packageName: entry.moduleName,
|
|
801
|
+
replacement: e18eReplacementHint(entry)
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
scanManifest(nativeManifest, "native");
|
|
806
|
+
scanManifest(preferredManifest, "preferred");
|
|
807
|
+
scanManifest(microUtilitiesManifest, "micro-utility");
|
|
808
|
+
return entries;
|
|
809
|
+
};
|
|
810
|
+
const buildSocketEntries = (allDeps, lockText, pm, pin) => {
|
|
811
|
+
const manifest = getManifestData("npm") ?? [];
|
|
812
|
+
const entries = [];
|
|
813
|
+
for (const [, data] of manifest) {
|
|
814
|
+
if (data.deprecated) {
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
const inDeps = allDeps.has(data.package);
|
|
818
|
+
const inLockfile = lockText ? lockfileContainsPackage(lockText, data.package, pm.name) : false;
|
|
819
|
+
if (!inDeps && !inLockfile) {
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
const major = coerce(data.version)?.major;
|
|
823
|
+
if (major === void 0) {
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
const spec = pin ? `npm:${data.name}@${data.version}` : `npm:${data.name}@^${String(major)}`;
|
|
827
|
+
entries.push({
|
|
828
|
+
category: "socket",
|
|
829
|
+
hasCodemod: false,
|
|
830
|
+
overrideSpec: spec,
|
|
831
|
+
packageName: data.package,
|
|
832
|
+
replacement: data.name
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
return entries;
|
|
836
|
+
};
|
|
837
|
+
let cachedCodemods;
|
|
838
|
+
const loadCodemods = async () => {
|
|
839
|
+
if (cachedCodemods) {
|
|
840
|
+
return cachedCodemods;
|
|
841
|
+
}
|
|
842
|
+
try {
|
|
843
|
+
const module_ = await import('module-replacements-codemods');
|
|
844
|
+
cachedCodemods = module_.codemods;
|
|
845
|
+
return cachedCodemods;
|
|
846
|
+
} catch {
|
|
847
|
+
return {};
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
const markCodemodAvailability = async (entries) => {
|
|
851
|
+
try {
|
|
852
|
+
const codemods = await loadCodemods();
|
|
853
|
+
for (const entry of entries) {
|
|
854
|
+
if (entry.category !== "socket" && codemods[entry.packageName]) {
|
|
855
|
+
entry.hasCodemod = true;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
} catch {
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
const runCodemod = async (workspaceRoot, packageName) => {
|
|
862
|
+
let filesChanged = 0;
|
|
863
|
+
try {
|
|
864
|
+
const codemods = await loadCodemods();
|
|
865
|
+
const factory = codemods[packageName];
|
|
866
|
+
if (!factory) {
|
|
867
|
+
return { filesChanged: 0, packageName };
|
|
868
|
+
}
|
|
869
|
+
const codemod = factory({});
|
|
870
|
+
const sourceFiles = await collectSourceFiles(workspaceRoot);
|
|
871
|
+
for (const filePath of sourceFiles) {
|
|
872
|
+
const source = readFileSync(filePath);
|
|
873
|
+
if (!source.includes(packageName)) {
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
const result = await codemod.transform({ file: { filename: filePath, source } });
|
|
878
|
+
if (result !== source) {
|
|
879
|
+
writeFileSync$1(filePath, result, "utf8");
|
|
880
|
+
filesChanged++;
|
|
881
|
+
}
|
|
882
|
+
} catch (error) {
|
|
883
|
+
process.stderr.write(`warn: codemod transform failed for ${filePath}: ${error instanceof Error ? error.message : String(error)}
|
|
884
|
+
`);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
} catch {
|
|
888
|
+
}
|
|
889
|
+
return { filesChanged, packageName };
|
|
890
|
+
};
|
|
891
|
+
const collectSourceFiles = async (dir) => glob("**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}", {
|
|
892
|
+
absolute: true,
|
|
893
|
+
cwd: dir,
|
|
894
|
+
// Matches the hand-rolled walker's SKIP set + "skip dotted
|
|
895
|
+
// entries" policy. `tinyglobby` (the engine) applies these as
|
|
896
|
+
// negative patterns during the walk so skipped subtrees are
|
|
897
|
+
// never descended into.
|
|
898
|
+
ignore: ["**/.*/**", "**/.*", "**/node_modules/**", "**/dist/**", "**/coverage/**", "**/.git/**", "**/.next/**", "**/.nuxt/**"]
|
|
899
|
+
});
|
|
900
|
+
const execute = async ({ logger, options, workspaceRoot: wsRoot }) => {
|
|
901
|
+
if (!wsRoot) {
|
|
902
|
+
throw new Error("Could not determine workspace root. Run this command inside a monorepo.");
|
|
903
|
+
}
|
|
904
|
+
const pm = detectPm(wsRoot);
|
|
905
|
+
const isDryRun = Boolean(options.dryRun);
|
|
906
|
+
const isProduction = Boolean(options.prod);
|
|
907
|
+
const isPin = Boolean(options.pin);
|
|
908
|
+
pail.info(`Detected ${pm.name} v${pm.version}.`);
|
|
909
|
+
const rootDeps = collectDepsFromPkgJson(join(wsRoot, "package.json"), isProduction);
|
|
910
|
+
const workspaceDirectories = discoverWorkspacePackages(wsRoot);
|
|
911
|
+
const allDeps = new Set(rootDeps);
|
|
912
|
+
for (const wsDir of workspaceDirectories) {
|
|
913
|
+
const wsDeps = collectDepsFromPkgJson(join(resolve(wsRoot, wsDir), "package.json"), isProduction);
|
|
914
|
+
for (const dep of wsDeps) {
|
|
915
|
+
allDeps.add(dep);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (workspaceDirectories.length > 0) {
|
|
919
|
+
pail.info(`Scanned ${String(workspaceDirectories.length)} workspace package${workspaceDirectories.length === 1 ? "" : "s"}.`);
|
|
920
|
+
}
|
|
921
|
+
pail.info("Scanning dependencies...\n");
|
|
922
|
+
const lockText = readLockfileText(wsRoot, pm.name);
|
|
923
|
+
const e18eEntries = buildE18eEntries(allDeps);
|
|
924
|
+
const socketEntries = buildSocketEntries(allDeps, lockText, pm, isPin);
|
|
925
|
+
const e18ePackages = new Set(e18eEntries.map((e) => e.packageName));
|
|
926
|
+
const dedupedSocketEntries = socketEntries.filter((e) => !e18ePackages.has(e.packageName));
|
|
927
|
+
const allEntries = [...e18eEntries, ...dedupedSocketEntries];
|
|
928
|
+
await markCodemodAvailability(allEntries);
|
|
929
|
+
if (allEntries.length === 0) {
|
|
930
|
+
pail.info("No optimizations found for your dependencies.");
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
const isTTY = Boolean(process.stdout.isTTY) && !isInCi;
|
|
934
|
+
const isJson = options.format === "json" || Boolean(options.json);
|
|
935
|
+
if (isTTY && !isDryRun && !isJson) {
|
|
936
|
+
const store = new OptimizeStore(allEntries);
|
|
937
|
+
const instance = render(React.createElement(VisOptimizeApp, { isDryRun: false, store }), {
|
|
938
|
+
alternateScreen: true,
|
|
939
|
+
exitOnCtrlC: false,
|
|
940
|
+
interactive: true,
|
|
941
|
+
patchConsole: true
|
|
942
|
+
});
|
|
943
|
+
const exitResult = await instance.waitUntilExit();
|
|
944
|
+
const selected = Array.isArray(exitResult) ? exitResult : [];
|
|
945
|
+
if (selected.length === 0) {
|
|
946
|
+
pail.info("No optimizations selected.");
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const selectedE18eWithCodemod = selected.filter((e) => e.category !== "socket" && e.hasCodemod);
|
|
950
|
+
const selectedE18eManual = selected.filter((e) => e.category !== "socket" && !e.hasCodemod);
|
|
951
|
+
const selectedSocket = selected.filter((e) => e.category === "socket");
|
|
952
|
+
if (selectedE18eWithCodemod.length > 0) {
|
|
953
|
+
pail.info(`
|
|
954
|
+
Running ${String(selectedE18eWithCodemod.length)} codemod${selectedE18eWithCodemod.length === 1 ? "" : "s"}...
|
|
955
|
+
`);
|
|
956
|
+
for (const entry of selectedE18eWithCodemod) {
|
|
957
|
+
const result = await runCodemod(wsRoot, entry.packageName);
|
|
958
|
+
if (result.filesChanged > 0) {
|
|
959
|
+
pail.success(` ${entry.packageName}: ${String(result.filesChanged)} file${result.filesChanged === 1 ? "" : "s"} updated`);
|
|
960
|
+
} else {
|
|
961
|
+
pail.info(` ${entry.packageName}: no files changed`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (selectedE18eManual.length > 0) {
|
|
966
|
+
pail.warn(
|
|
967
|
+
`
|
|
968
|
+
${String(selectedE18eManual.length)} selected replacement${selectedE18eManual.length === 1 ? "" : "s"} require manual migration (no codemod available):`
|
|
969
|
+
);
|
|
970
|
+
for (const entry of selectedE18eManual) {
|
|
971
|
+
pail.info(` ${entry.packageName} → ${entry.replacement}`);
|
|
972
|
+
}
|
|
973
|
+
pail.notice(" Replace usage in your source code, then remove from dependencies.");
|
|
974
|
+
}
|
|
975
|
+
if (selectedSocket.length > 0) {
|
|
976
|
+
const overrideEntries = selectedSocket.filter((e) => e.overrideSpec).map((e) => {
|
|
977
|
+
return { original: e.packageName, spec: e.overrideSpec };
|
|
978
|
+
});
|
|
979
|
+
const result = applyOverrides(wsRoot, join(wsRoot, "package.json"), overrideEntries, pm);
|
|
980
|
+
if (result.added.length > 0) {
|
|
981
|
+
pail.success(`
|
|
982
|
+
Added ${String(result.added.length)} override${result.added.length === 1 ? "" : "s"}.`);
|
|
983
|
+
}
|
|
984
|
+
if (result.updated.length > 0) {
|
|
985
|
+
pail.success(`Updated ${String(result.updated.length)} override${result.updated.length === 1 ? "" : "s"}.`);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
if (selectedSocket.length > 0 && !options.noInstall) {
|
|
989
|
+
pail.info(`
|
|
990
|
+
Running ${pm.name} install to update lockfile...`);
|
|
991
|
+
const installOptions = {
|
|
992
|
+
dev: false,
|
|
993
|
+
filter: [],
|
|
994
|
+
force: false,
|
|
995
|
+
frozenLockfile: false,
|
|
996
|
+
ignoreScripts: false,
|
|
997
|
+
lockfileOnly: false,
|
|
998
|
+
noOptional: false,
|
|
999
|
+
offline: false,
|
|
1000
|
+
prod: false,
|
|
1001
|
+
recursive: false,
|
|
1002
|
+
silent: false,
|
|
1003
|
+
workspaceRoot: false
|
|
1004
|
+
};
|
|
1005
|
+
const code = runInstall(pm, installOptions, wsRoot, logger);
|
|
1006
|
+
if (code !== 0) {
|
|
1007
|
+
pail.warn(`${pm.name} install exited with code ${String(code)}. Run it manually.`);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
pail.info("");
|
|
1011
|
+
pail.success("Optimization complete.");
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
if (isJson) {
|
|
1015
|
+
process.stdout.write(
|
|
1016
|
+
`${JSON.stringify(
|
|
1017
|
+
{
|
|
1018
|
+
e18e: e18eEntries.map((e) => {
|
|
1019
|
+
return {
|
|
1020
|
+
category: e.category,
|
|
1021
|
+
hasCodemod: e.hasCodemod,
|
|
1022
|
+
packageName: e.packageName,
|
|
1023
|
+
replacement: e.replacement
|
|
1024
|
+
};
|
|
1025
|
+
}),
|
|
1026
|
+
packageManager: pm.name,
|
|
1027
|
+
socket: dedupedSocketEntries.map((e) => {
|
|
1028
|
+
return { overrideSpec: e.overrideSpec, packageName: e.packageName, replacement: e.replacement };
|
|
1029
|
+
}),
|
|
1030
|
+
total: allEntries.length,
|
|
1031
|
+
workspaces: workspaceDirectories.length
|
|
1032
|
+
},
|
|
1033
|
+
void 0,
|
|
1034
|
+
2
|
|
1035
|
+
)}
|
|
1036
|
+
`
|
|
1037
|
+
);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const natives = e18eEntries.filter((e) => e.category === "native");
|
|
1041
|
+
const preferred = e18eEntries.filter((e) => e.category === "preferred");
|
|
1042
|
+
const micros = e18eEntries.filter((e) => e.category === "micro-utility");
|
|
1043
|
+
if (natives.length > 0) {
|
|
1044
|
+
pail.info(`Native replacements (${String(natives.length)}):`);
|
|
1045
|
+
for (const s of natives) {
|
|
1046
|
+
pail.info(` ${s.hasCodemod ? "⚙" : " "} ${s.packageName} → ${s.replacement}`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (preferred.length > 0) {
|
|
1050
|
+
pail.info(`
|
|
1051
|
+
Preferred alternatives (${String(preferred.length)}):`);
|
|
1052
|
+
for (const s of preferred) {
|
|
1053
|
+
pail.info(` ${s.hasCodemod ? "⚙" : " "} ${s.packageName} → ${s.replacement}`);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
if (micros.length > 0) {
|
|
1057
|
+
pail.info(`
|
|
1058
|
+
Micro-utilities (${String(micros.length)}):`);
|
|
1059
|
+
for (const s of micros) {
|
|
1060
|
+
pail.info(` ${s.hasCodemod ? "⚙" : " "} ${s.packageName} → ${s.replacement}`);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (dedupedSocketEntries.length > 0) {
|
|
1064
|
+
pail.info(`
|
|
1065
|
+
Socket.dev overrides (${String(dedupedSocketEntries.length)}):`);
|
|
1066
|
+
for (const s of dedupedSocketEntries) {
|
|
1067
|
+
pail.info(` ${s.packageName} → ${s.overrideSpec}`);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
pail.info(`
|
|
1071
|
+
Total: ${String(allEntries.length)} optimizations available (⚙ = codemod available).`);
|
|
1072
|
+
if (isDryRun) {
|
|
1073
|
+
pail.notice("Run without --dry-run for interactive selection.");
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
const handler = /*#__PURE__*/Object.defineProperty({
|
|
1078
|
+
__proto__: null,
|
|
1079
|
+
buildE18eEntries,
|
|
1080
|
+
buildSocketEntries,
|
|
1081
|
+
collectDepsFromPkgJson,
|
|
1082
|
+
default: execute,
|
|
1083
|
+
discoverWorkspacePackages,
|
|
1084
|
+
markCodemodAvailability,
|
|
1085
|
+
runCodemod
|
|
1086
|
+
}, Symbol.toStringTag, { value: 'Module' });
|
|
1087
|
+
|
|
1088
|
+
export { buildSocketEntries as a, buildE18eEntries as b, collectDepsFromPkgJson as c, discoverWorkspacePackages as d, applyOverrides as e, runCodemod as f, handler as h, markCodemodAvailability as m, readLockfileText as r };
|