Skip to content

Commit 54ab951

Browse files
committed
feat: migrate from neverthrow to effect
1 parent 647d762 commit 54ab951

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+605
-749
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@
5858
},
5959
"dependencies": {
6060
"@microsoft/tsdoc": "^0.14.2",
61+
"effect": "^2.4.1",
6162
"execa": "^8.0.1",
6263
"memoize": "^10.0.0",
6364
"natural-orderby": "^3.0.2",
64-
"neverthrow": "^6.1.0",
6565
"pathe": "^1.1.2",
6666
"prettier": "^3.2.5",
6767
"read-pkg": "^9.0.1",

pnpm-lock.yaml

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/create-project.test.ts

+27-29
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,55 @@
1+
import { Effect } from "effect";
12
import fs from "node:fs/promises";
23
import { join } from "pathe";
34
import { temporaryDirectoryTask } from "tempy";
45
import { expect, test } from "vitest";
5-
import { createProject } from "./create-project";
6-
import { ProjectError } from "./errors";
6+
import { createProject, type CreateProjectOptions } from "./create-project";
7+
8+
const _createProject = (options: CreateProjectOptions) =>
9+
Effect.runPromise(createProject(options));
710

811
test("no cwd", async () => {
912
await temporaryDirectoryTask(async (dir) => {
10-
const project = createProject({
11-
indexFilePath: "./no-such-file.ts",
12-
cwd: join(dir, "this-dir-does-not-exist"),
13-
});
14-
expect(project.isErr()).toBe(true);
15-
expect(project._unsafeUnwrapErr() instanceof ProjectError).toBe(true);
13+
await expect(
14+
_createProject({
15+
indexFilePath: "./this-file-does-not-exist.ts",
16+
cwd: join(dir, "this-dir-does-not-exist"),
17+
}),
18+
).rejects.toThrow();
1619
});
1720
});
1821

1922
test("no index file", async () => {
2023
await temporaryDirectoryTask(async (dir) => {
21-
const project = createProject({
22-
indexFilePath: "./no-such-file.ts",
23-
cwd: dir,
24-
});
25-
expect(project.isErr()).toBe(true);
26-
expect(project._unsafeUnwrapErr() instanceof ProjectError).toBe(true);
24+
await expect(
25+
_createProject({
26+
indexFilePath: "./this-file-does-not-exist.ts",
27+
cwd: dir,
28+
}),
29+
).rejects.toThrow();
2730
});
2831
});
2932

3033
test("with index file", async () => {
3134
await temporaryDirectoryTask(async (dir) => {
32-
await fs.writeFile(join(dir, "./index.ts"), "export {};");
33-
const project = createProject({ indexFilePath: "./index.ts", cwd: dir });
34-
expect(project.isOk()).toBe(true);
35+
const indexFilePath = join(dir, "./index.ts");
36+
await fs.writeFile(indexFilePath, "export {};");
37+
const { project } = await _createProject({ indexFilePath, cwd: dir });
3538
expect(
36-
project
37-
._unsafeUnwrap()
38-
.project.getSourceFiles()
39-
.map((sf) => sf.getBaseName()),
39+
project.getSourceFiles().map((sf) => sf.getBaseName()),
4040
).toStrictEqual(["index.ts"]);
4141
});
4242
});
4343

4444
test("with index file and other file", async () => {
4545
await temporaryDirectoryTask(async (dir) => {
46-
await fs.writeFile(join(dir, "./index.ts"), "export * from './other';");
47-
await fs.writeFile(join(dir, "./other.ts"), "export const a = 1;");
48-
const project = createProject({ indexFilePath: "./index.ts", cwd: dir });
49-
expect(project.isOk()).toBe(true);
46+
const indexFilePath = join(dir, "./index.ts");
47+
const otherFilePath = join(dir, "./other.ts");
48+
await fs.writeFile(indexFilePath, "export * from './other';");
49+
await fs.writeFile(otherFilePath, "export const a = 1;");
50+
const { project } = await _createProject({ indexFilePath, cwd: dir });
5051
expect(
51-
project
52-
._unsafeUnwrap()
53-
.project.getSourceFiles()
54-
.map((sf) => sf.getBaseName()),
52+
project.getSourceFiles().map((sf) => sf.getBaseName()),
5553
).toStrictEqual(["index.ts", "other.ts"]);
5654
});
5755
});

src/create-project.ts

+31-50
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,44 @@
1-
import { Result, err, ok } from "neverthrow";
2-
import process from "node:process";
1+
import { Effect } from "effect";
32
import {
43
ModuleKind,
54
ModuleResolutionKind,
65
Project,
76
ScriptTarget,
8-
SourceFile,
97
} from "ts-morph";
10-
import { ProjectError } from "./errors";
118

129
export type CreateProjectOptions = {
1310
indexFilePath: string;
1411
cwd: string;
1512
};
1613

17-
export type ProjectContainer = {
18-
project: Project;
19-
indexFile: SourceFile;
20-
};
21-
22-
export const createProject = ({
23-
indexFilePath,
24-
cwd,
25-
}: CreateProjectOptions): Result<ProjectContainer, ProjectError> => {
26-
try {
27-
// By default, ts-morph creates the project in the current working directory.
28-
// We must change it to the temporary directory where the packages are installed,
29-
// otherwise TypeScript will pick up type definitions from our local `node_modules`.
30-
const startDir = process.cwd();
31-
process.chdir(cwd);
32-
const res = _createProject(indexFilePath);
33-
process.chdir(startDir);
34-
return res;
35-
} catch (e) {
36-
return err(new ProjectError("failed to change directories", { cause: e }));
37-
}
38-
};
14+
/** @internal */
15+
export class ProjectError {
16+
readonly _tag = "ProjectError";
17+
constructor(readonly cause?: unknown) {}
18+
}
3919

40-
const _createProject = (
41-
indexFilePath: string,
42-
): Result<ProjectContainer, ProjectError> => {
43-
try {
44-
const project = new Project({
45-
compilerOptions: {
46-
// See https://github.com/dsherret/ts-morph/issues/938
47-
// and https://github.com/microsoft/TypeScript/blob/master/lib/lib.esnext.full.d.ts
48-
lib: ["lib.esnext.full.d.ts"],
49-
target: ScriptTarget.ESNext,
50-
module: ModuleKind.ESNext,
51-
moduleResolution: ModuleResolutionKind.Bundler,
52-
},
53-
});
54-
const indexFile = project.addSourceFileAtPath(indexFilePath);
55-
project.resolveSourceFileDependencies();
56-
return ok({
57-
project,
58-
indexFile,
59-
});
60-
} catch (e) {
61-
return err(new ProjectError("failed to create project", { cause: e }));
62-
}
63-
};
20+
export const createProject = ({ indexFilePath, cwd }: CreateProjectOptions) =>
21+
Effect.try({
22+
try: () => {
23+
const project = new Project({
24+
compilerOptions: {
25+
// See https://github.com/dsherret/ts-morph/issues/938
26+
// and https://github.com/microsoft/TypeScript/blob/master/lib/lib.esnext.full.d.ts
27+
lib: ["lib.esnext.full.d.ts"],
28+
target: ScriptTarget.ESNext,
29+
module: ModuleKind.ESNext,
30+
moduleResolution: ModuleResolutionKind.Bundler,
31+
// By default, ts-morph creates a project rooted in the current working directory.
32+
// We must change the `typeRoots` directory to the temporary directory
33+
// where the packages are installed, otherwise TypeScript will discover
34+
// `@types` packages from our local `node_modules` directory.
35+
// See https://www.typescriptlang.org/tsconfig#typeRoots.
36+
typeRoots: [cwd],
37+
},
38+
});
39+
const indexFile = project.addSourceFileAtPath(indexFilePath);
40+
project.resolveSourceFileDependencies();
41+
return { project, indexFile };
42+
},
43+
catch: (e) => new ProjectError(e),
44+
});

src/errors.test.ts

-52
This file was deleted.

src/errors.ts

-87
This file was deleted.

0 commit comments

Comments
 (0)