Skip to content

Commit

Permalink
feat: add PackageManager and update extractPackageApiEffect
Browse files Browse the repository at this point in the history
  • Loading branch information
velut committed Mar 14, 2024
1 parent 2988f04 commit ba52e1e
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 75 deletions.
32 changes: 32 additions & 0 deletions src/bun-package-manager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Effect } from "effect";
import { temporaryDirectoryTask } from "tempy";
import { expect, test } from "vitest";
import { bunPackageManager } from "./bun-package-manager";
import type { InstallPackageOptions } from "./package-manager";

const bun = bunPackageManager();

const _installPackage = (options: InstallPackageOptions) =>
Effect.runPromise(bun.installPackage(options));

test("invalid package", async () => {
await temporaryDirectoryTask(async (cwd) => {
await expect(_installPackage({ pkg: "", cwd })).rejects.toThrow();
});
});

test("package with no production dependencies", async () => {
await temporaryDirectoryTask(async (cwd) => {
await expect(_installPackage({ pkg: "[email protected]", cwd })).resolves.toStrictEqual([
"[email protected]",
]);
});
});

test("package with some production dependencies", async () => {
await temporaryDirectoryTask(async (cwd) => {
await expect(_installPackage({ pkg: "[email protected]", cwd })).resolves.toContain(
"[email protected]",
);
});
});
29 changes: 29 additions & 0 deletions src/bun-package-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Effect } from "effect";
import { execa } from "execa";
import { InstallPackageError, PackageManager } from "./package-manager";

/** @internal */
export const bunPackageManager = (bunPath = "bun") =>
PackageManager.of({
installPackage: ({ pkg, cwd }) =>
Effect.gen(function* (_) {
// Run `bun add <pkg> --verbose`.
// See https://bun.sh/docs/cli/add.
const { stdout } = yield* _(
Effect.tryPromise({
try: () => execa(bunPath, ["add", pkg, "--verbose"], { cwd }),
catch: (e) => new InstallPackageError({ cause: e }),
}),
);

// With verbose output on, bun prints one line per installed package
// (e.g., "[email protected]"), including all installed dependencies.
// These lines are between the two delimiting lines found here:
// https://github.com/oven-sh/bun/blob/972a7b7080bd3066b54dcb43e9c91c5dfa26a69c/src/install/lockfile.zig#L5369-L5370.
const lines = stdout.split("\n");
const beginHash = lines.findIndex((line) => line.startsWith("-- BEGIN SHA512/256"));
const endHash = lines.findIndex((line) => line.startsWith("-- END HASH"));
const installedPackages = lines.slice(beginHash + 1, endHash);
return installedPackages;
}),
});
11 changes: 6 additions & 5 deletions src/extract-package-api-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { performance } from "node:perf_hooks";
import { join } from "pathe";
import { createProject } from "./create-project";
import type { ExtractPackageApiOptions, PackageApi } from "./extract-package-api";
import { installPackage } from "./install-package";
import { packageDeclarations } from "./package-declarations";
import { packageJson } from "./package-json";
import { PackageManager } from "./package-manager";
import { packageName } from "./package-name";
import { packageOverview } from "./package-overview";
import { packageTypes } from "./package-types";
Expand All @@ -16,21 +16,21 @@ export const extractPackageApiEffect = ({
pkg,
subpath = ".",
maxDepth = 5,
bunPath = "bun",
}: ExtractPackageApiOptions) =>
Effect.gen(function* (_) {
const startTime = performance.now();
const pkgName = yield* _(packageName(pkg));
const { path: cwd } = yield* _(workDir);
const packages = yield* _(installPackage({ pkg, cwd, bunPath }));
const pm = yield* _(PackageManager);
const packages = yield* _(pm.installPackage({ pkg, cwd }));
const pkgDir = join(cwd, "node_modules", pkgName);
const pkgJson = yield* _(packageJson(pkgDir));
const types = yield* _(packageTypes(pkgJson, subpath));
const indexFilePath = join(pkgDir, types);
const { project, indexFile } = yield* _(createProject({ indexFilePath, cwd }));
const overview = packageOverview(indexFile);
const declarations = yield* _(packageDeclarations({ pkgName, project, indexFile, maxDepth }));
return {
const pkgApi: PackageApi = {
name: pkgJson.name,
version: pkgJson.version,
subpath,
Expand All @@ -40,5 +40,6 @@ export const extractPackageApiEffect = ({
packages,
analyzedAt: new Date().toISOString(),
analyzedIn: Math.round(performance.now() - startTime),
} satisfies PackageApi;
};
return pkgApi;
});
8 changes: 7 additions & 1 deletion src/extract-package-api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Effect } from "effect";
import { bunPackageManager } from "./bun-package-manager";
import type { ExtractedDeclaration } from "./extract-declarations";
import { extractPackageApiEffect } from "./extract-package-api-effect";
import { PackageManager } from "./package-manager";

/**
`ExtractPackageApiOptions` contains all the options
Expand Down Expand Up @@ -129,4 +131,8 @@ export const extractPackageApi = ({
maxDepth = 5,
bunPath = "bun",
}: ExtractPackageApiOptions): Promise<PackageApi> =>
Effect.runPromise(Effect.scoped(extractPackageApiEffect({ pkg, subpath, maxDepth, bunPath })));
extractPackageApiEffect({ pkg, subpath, maxDepth }).pipe(
Effect.scoped,
Effect.provideService(PackageManager, bunPackageManager(bunPath)),
Effect.runPromise,
);
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type {
AllExtractedDeclaration,
AllExtractedDeclarationKind,
} from "./all-extracted-declaration";
export { bunPackageManager } from "./bun-package-manager";
export { ProjectError } from "./create-project";
export type {
ExtractedClass,
Expand Down Expand Up @@ -36,9 +37,9 @@ export {
export { extractPackageApiEffect } from "./extract-package-api-effect";
export type { ExtractedTypeAlias } from "./extract-type-alias";
export type { ExtractedVariable } from "./extract-variable";
export { InstallPackageError, installPackage, type InstallPackageOptions } from "./install-package";
export { PackageDeclarationsError } from "./package-declarations";
export { PackageJsonError, packageJson } from "./package-json";
export { InstallPackageError, PackageManager, type InstallPackageOptions } from "./package-manager";
export { PackageNameError, packageName } from "./package-name";
export { PackageTypesError, packageTypes } from "./package-types";
export { parseDocComment } from "./parse-doc-comment";
Expand Down
29 changes: 0 additions & 29 deletions src/install-package.test.ts

This file was deleted.

39 changes: 0 additions & 39 deletions src/install-package.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/package-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Context, Data, Effect } from "effect";

/** @internal */
export type InstallPackageOptions = {
pkg: string;
cwd: string;
};

/** @internal */
export class InstallPackageError extends Data.TaggedError("InstallPackageError")<{
cause?: unknown;
}> {}

/** @internal */
export class PackageManager extends Context.Tag("PackageManager")<
PackageManager,
{
readonly installPackage: ({
pkg,
cwd,
}: InstallPackageOptions) => Effect.Effect<string[], InstallPackageError>;
}
>() {}

0 comments on commit ba52e1e

Please sign in to comment.