@@ -8,7 +8,8 @@ import { EffectFlock } from "./util/effect-flock"
88
99export namespace Npm {
1010 export class InstallFailedError extends Schema . TaggedErrorClass < InstallFailedError > ( ) ( "NpmInstallFailedError" , {
11- pkg : Schema . String ,
11+ add : Schema . Array ( Schema . String ) . pipe ( Schema . optional ) ,
12+ dir : Schema . String ,
1213 cause : Schema . optional ( Schema . Defect ) ,
1314 } ) { }
1415
@@ -19,7 +20,10 @@ export namespace Npm {
1920
2021 export interface Interface {
2122 readonly add : ( pkg : string ) => Effect . Effect < EntryPoint , InstallFailedError | EffectFlock . LockError >
22- readonly install : ( dir : string , input ?: { add : string [ ] } ) => Effect . Effect < void , EffectFlock . LockError >
23+ readonly install : (
24+ dir : string ,
25+ input ?: { add : string [ ] } ,
26+ ) => Effect . Effect < void , EffectFlock . LockError | InstallFailedError >
2327 readonly outdated : ( pkg : string , cachedVersion : string ) => Effect . Effect < boolean >
2428 readonly which : ( pkg : string ) => Effect . Effect < Option . Option < string > >
2529 }
@@ -55,6 +59,37 @@ export namespace Npm {
5559 interface ArboristTree {
5660 edgesOut : Map < string , { to ?: ArboristNode } >
5761 }
62+
63+ const reify = ( input : { dir : string ; add ?: string [ ] } ) =>
64+ Effect . gen ( function * ( ) {
65+ const { Arborist } = yield * Effect . promise ( ( ) => import ( "@npmcli/arborist" ) )
66+ const arborist = new Arborist ( {
67+ path : input . dir ,
68+ binLinks : true ,
69+ progress : false ,
70+ savePrefix : "" ,
71+ ignoreScripts : true ,
72+ } )
73+ return yield * Effect . tryPromise ( {
74+ try : ( ) =>
75+ arborist . reify ( {
76+ add : input ?. add || [ ] ,
77+ save : true ,
78+ saveType : "prod" ,
79+ } ) ,
80+ catch : ( cause ) =>
81+ new InstallFailedError ( {
82+ cause,
83+ add : input ?. add ,
84+ dir : input . dir ,
85+ } ) ,
86+ } ) as Effect . Effect < ArboristTree , InstallFailedError >
87+ } ) . pipe (
88+ Effect . withSpan ( "Npm.reify" , {
89+ attributes : input ,
90+ } ) ,
91+ )
92+
5893 export const layer = Layer . effect (
5994 Service ,
6095 Effect . gen ( function * ( ) {
@@ -91,45 +126,12 @@ export namespace Npm {
91126 } )
92127
93128 const add = Effect . fn ( "Npm.add" ) ( function * ( pkg : string ) {
94- const { Arborist } = yield * Effect . promise ( ( ) => import ( "@npmcli/arborist" ) )
95129 const dir = directory ( pkg )
96130 yield * flock . acquire ( `npm-install:${ dir } ` )
97131
98- const arborist = new Arborist ( {
99- path : dir ,
100- binLinks : true ,
101- progress : false ,
102- savePrefix : "" ,
103- ignoreScripts : true ,
104- } )
105-
106- const tree = yield * Effect . tryPromise ( {
107- try : ( ) => arborist . loadVirtual ( ) . catch ( ( ) => undefined ) ,
108- catch : ( ) => undefined ,
109- } ) . pipe ( Effect . orElseSucceed ( ( ) => undefined ) ) as Effect . Effect < ArboristTree | undefined >
110-
111- if ( tree ) {
112- const first = tree . edgesOut . values ( ) . next ( ) . value ?. to
113- if ( first ) {
114- return resolveEntryPoint ( first . name , first . path )
115- }
116- }
117-
118- const result = yield * Effect . tryPromise ( {
119- try : ( ) =>
120- arborist . reify ( {
121- add : [ pkg ] ,
122- save : true ,
123- saveType : "prod" ,
124- } ) ,
125- catch : ( cause ) => new InstallFailedError ( { pkg, cause } ) ,
126- } ) as Effect . Effect < ArboristTree , InstallFailedError >
127-
128- const first = result . edgesOut . values ( ) . next ( ) . value ?. to
129- if ( ! first ) {
130- return yield * new InstallFailedError ( { pkg } )
131- }
132-
132+ const tree = yield * reify ( { dir, add : [ pkg ] } )
133+ const first = tree . edgesOut . values ( ) . next ( ) . value ?. to
134+ if ( ! first ) return yield * new InstallFailedError ( { add : [ pkg ] , dir } )
133135 return resolveEntryPoint ( first . name , first . path )
134136 } , Effect . scoped )
135137
@@ -142,41 +144,20 @@ export namespace Npm {
142144
143145 yield * flock . acquire ( `npm-install:${ dir } ` )
144146
145- const reify = Effect . fn ( "Npm.reify" ) ( function * ( ) {
146- const { Arborist } = yield * Effect . promise ( ( ) => import ( "@npmcli/arborist" ) )
147- const arb = new Arborist ( {
148- path : dir ,
149- binLinks : true ,
150- progress : false ,
151- savePrefix : "" ,
152- ignoreScripts : true ,
153- } )
154- yield * Effect . tryPromise ( {
155- try : ( ) =>
156- arb
157- . reify ( {
158- add : input ?. add || [ ] ,
159- save : true ,
160- saveType : "prod" ,
161- } )
162- . catch ( ( ) => { } ) ,
163- catch : ( ) => { } ,
164- } ) . pipe ( Effect . orElseSucceed ( ( ) => { } ) )
165- } )
166-
167- const nodeModulesExists = yield * afs . existsSafe ( path . join ( dir , "node_modules" ) )
168- if ( ! nodeModulesExists ) {
169- yield * reify ( )
170- return
171- }
172-
173- const pkg = yield * afs . readJson ( path . join ( dir , "package.json" ) ) . pipe ( Effect . orElseSucceed ( ( ) => ( { } ) ) )
174- const lock = yield * afs . readJson ( path . join ( dir , "package-lock.json" ) ) . pipe ( Effect . orElseSucceed ( ( ) => ( { } ) ) )
175-
176- const pkgAny = pkg as any
177- const lockAny = lock as any
147+ yield * Effect . gen ( function * ( ) {
148+ const nodeModulesExists = yield * afs . existsSafe ( path . join ( dir , "node_modules" ) )
149+ if ( ! nodeModulesExists ) {
150+ yield * reify ( { add : input ?. add , dir } )
151+ return
152+ }
153+ } ) . pipe ( Effect . withSpan ( "Npm.checkNodeModules" ) )
178154
179155 yield * Effect . gen ( function * ( ) {
156+ const pkg = yield * afs . readJson ( path . join ( dir , "package.json" ) ) . pipe ( Effect . orElseSucceed ( ( ) => ( { } ) ) )
157+ const lock = yield * afs . readJson ( path . join ( dir , "package-lock.json" ) ) . pipe ( Effect . orElseSucceed ( ( ) => ( { } ) ) )
158+
159+ const pkgAny = pkg as any
160+ const lockAny = lock as any
180161 const declared = new Set ( [
181162 ...Object . keys ( pkgAny ?. dependencies || { } ) ,
182163 ...Object . keys ( pkgAny ?. devDependencies || { } ) ,
@@ -195,11 +176,12 @@ export namespace Npm {
195176
196177 for ( const name of declared ) {
197178 if ( ! locked . has ( name ) ) {
198- yield * reify ( )
179+ yield * reify ( { dir , add : input ?. add } )
199180 return
200181 }
201182 }
202183 } ) . pipe ( Effect . withSpan ( "Npm.checkDirty" ) )
184+
203185 return
204186 } , Effect . scoped )
205187
0 commit comments