summaryrefslogtreecommitdiffhomepage
path: root/packages/shared/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/shared/src')
-rw-r--r--packages/shared/src/npm.ts126
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)