diff options
Diffstat (limited to 'packages/shared/src')
| -rw-r--r-- | packages/shared/src/npm.ts | 126 |
1 files changed, 54 insertions, 72 deletions
diff --git a/packages/shared/src/npm.ts b/packages/shared/src/npm.ts index e4f42227d..865e827b3 100644 --- a/packages/shared/src/npm.ts +++ b/packages/shared/src/npm.ts @@ -8,7 +8,8 @@ import { EffectFlock } from "./util/effect-flock" export namespace Npm { export class InstallFailedError extends Schema.TaggedErrorClass<InstallFailedError>()("NpmInstallFailedError", { - pkg: Schema.String, + add: Schema.Array(Schema.String).pipe(Schema.optional), + dir: Schema.String, cause: Schema.optional(Schema.Defect), }) {} @@ -19,7 +20,10 @@ export namespace Npm { export interface Interface { readonly add: (pkg: string) => Effect.Effect<EntryPoint, InstallFailedError | EffectFlock.LockError> - readonly install: (dir: string, input?: { add: string[] }) => Effect.Effect<void, EffectFlock.LockError> + readonly install: ( + dir: string, + input?: { add: string[] }, + ) => Effect.Effect<void, EffectFlock.LockError | InstallFailedError> readonly outdated: (pkg: string, cachedVersion: string) => Effect.Effect<boolean> readonly which: (pkg: string) => Effect.Effect<Option.Option<string>> } @@ -55,6 +59,37 @@ export namespace Npm { interface ArboristTree { edgesOut: Map<string, { to?: ArboristNode }> } + + const reify = (input: { dir: string; add?: string[] }) => + Effect.gen(function* () { + const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist")) + const arborist = new Arborist({ + path: input.dir, + binLinks: true, + progress: false, + savePrefix: "", + ignoreScripts: true, + }) + return yield* Effect.tryPromise({ + try: () => + arborist.reify({ + add: input?.add || [], + save: true, + saveType: "prod", + }), + catch: (cause) => + new InstallFailedError({ + cause, + add: input?.add, + dir: input.dir, + }), + }) as Effect.Effect<ArboristTree, InstallFailedError> + }).pipe( + Effect.withSpan("Npm.reify", { + attributes: input, + }), + ) + export const layer = Layer.effect( Service, Effect.gen(function* () { @@ -91,45 +126,12 @@ export namespace Npm { }) const add = Effect.fn("Npm.add")(function* (pkg: string) { - const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist")) const dir = directory(pkg) yield* flock.acquire(`npm-install:${dir}`) - const arborist = new Arborist({ - path: dir, - binLinks: true, - progress: false, - savePrefix: "", - ignoreScripts: true, - }) - - const tree = yield* Effect.tryPromise({ - try: () => arborist.loadVirtual().catch(() => undefined), - catch: () => undefined, - }).pipe(Effect.orElseSucceed(() => undefined)) as Effect.Effect<ArboristTree | undefined> - - if (tree) { - const first = tree.edgesOut.values().next().value?.to - if (first) { - return resolveEntryPoint(first.name, first.path) - } - } - - const result = yield* Effect.tryPromise({ - try: () => - arborist.reify({ - add: [pkg], - save: true, - saveType: "prod", - }), - catch: (cause) => new InstallFailedError({ pkg, cause }), - }) as Effect.Effect<ArboristTree, InstallFailedError> - - const first = result.edgesOut.values().next().value?.to - if (!first) { - return yield* new InstallFailedError({ pkg }) - } - + const tree = yield* reify({ dir, add: [pkg] }) + const first = tree.edgesOut.values().next().value?.to + if (!first) return yield* new InstallFailedError({ add: [pkg], dir }) return resolveEntryPoint(first.name, first.path) }, Effect.scoped) @@ -142,41 +144,20 @@ export namespace Npm { yield* flock.acquire(`npm-install:${dir}`) - const reify = Effect.fn("Npm.reify")(function* () { - const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist")) - const arb = new Arborist({ - path: dir, - binLinks: true, - progress: false, - savePrefix: "", - ignoreScripts: true, - }) - yield* Effect.tryPromise({ - try: () => - arb - .reify({ - add: input?.add || [], - save: true, - saveType: "prod", - }) - .catch(() => {}), - catch: () => {}, - }).pipe(Effect.orElseSucceed(() => {})) - }) - - const nodeModulesExists = yield* afs.existsSafe(path.join(dir, "node_modules")) - if (!nodeModulesExists) { - yield* reify() - return - } - - const pkg = yield* afs.readJson(path.join(dir, "package.json")).pipe(Effect.orElseSucceed(() => ({}))) - const lock = yield* afs.readJson(path.join(dir, "package-lock.json")).pipe(Effect.orElseSucceed(() => ({}))) - - const pkgAny = pkg as any - const lockAny = lock as any + yield* Effect.gen(function* () { + const nodeModulesExists = yield* afs.existsSafe(path.join(dir, "node_modules")) + if (!nodeModulesExists) { + yield* reify({ add: input?.add, dir }) + return + } + }).pipe(Effect.withSpan("Npm.checkNodeModules")) yield* Effect.gen(function* () { + const pkg = yield* afs.readJson(path.join(dir, "package.json")).pipe(Effect.orElseSucceed(() => ({}))) + const lock = yield* afs.readJson(path.join(dir, "package-lock.json")).pipe(Effect.orElseSucceed(() => ({}))) + + const pkgAny = pkg as any + const lockAny = lock as any const declared = new Set([ ...Object.keys(pkgAny?.dependencies || {}), ...Object.keys(pkgAny?.devDependencies || {}), @@ -195,11 +176,12 @@ export namespace Npm { for (const name of declared) { if (!locked.has(name)) { - yield* reify() + yield* reify({ dir, add: input?.add }) return } } }).pipe(Effect.withSpan("Npm.checkDirty")) + return }, Effect.scoped) |
