Skip to content

Commit 9e23c9e

Browse files
committed
feat: add wip handlePackage
1 parent 695dc5b commit 9e23c9e

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { Bun, getPackageJson } from "@jsdocs-io/extractor";
2+
import { goTry } from "go-go-try";
3+
import { join } from "pathe";
4+
import { serverEnv } from "../../server-env";
5+
import { checkLicense } from "../../utils/check-license";
6+
import { packageId } from "../../utils/package-id";
7+
import { resolvePackage } from "../../utils/resolve-package";
8+
import { tempDir } from "../../utils/temp-dir";
9+
import { getLogger } from "../get-logger";
10+
import { redirect } from "../redirect";
11+
import { parsePackageSlug } from "./parse-package-slug";
12+
13+
const bun = new Bun(serverEnv.BUN_PATH);
14+
15+
export interface HandlePackageOutput {}
16+
17+
export async function handlePackage(slug: string) {
18+
const log = getLogger("handlePackage");
19+
log.info({ path: `/package/${slug}` });
20+
21+
// Start the performance timer.
22+
const start = performance.now();
23+
24+
// Parse the package page slug.
25+
const [slugErr, slugOut] = goTry(() => parsePackageSlug(slug));
26+
if (slugErr !== undefined) {
27+
log.error({ err: slugErr });
28+
return redirect("/404");
29+
}
30+
const { pkg, pkgName, subpath } = slugOut;
31+
32+
// Get a temporary work directory.
33+
await using dir = await tempDir();
34+
const cwd = dir.path;
35+
36+
// Install the package to let bun resolve the correct version.
37+
// Assume that installation errors are only caused by non existing packages.
38+
const [bunErr, packages] = await goTry(bun.add(pkg, cwd));
39+
if (bunErr !== undefined) {
40+
log.error({ err: bunErr });
41+
return redirect("/404");
42+
}
43+
44+
// Redirect to the canonical package page if necessary.
45+
const resolvedPkg = resolvePackage(pkgName, packages);
46+
const pkgId = packageId(resolvedPkg, subpath);
47+
if (pkg !== resolvedPkg) {
48+
log.info({ redirect: `${pkg} -> ${resolvedPkg}` });
49+
return redirect(`/package/${pkgId}`);
50+
}
51+
52+
// Read the package's own `package.json`.
53+
const pkgDir = join(cwd, "node_modules", pkgName);
54+
const [pkgJsonErr, pkgJson] = await goTry(getPackageJson(pkgDir));
55+
if (pkgJsonErr !== undefined) {
56+
log.error({ err: pkgJsonErr });
57+
return redirect("/500");
58+
}
59+
60+
// Check if the package has an SPDX license.
61+
const [licenseErr] = goTry(() => checkLicense(pkgJson.license));
62+
if (licenseErr !== undefined) {
63+
log.warn({ warn: licenseErr });
64+
return {
65+
status: "invalid-license" as const,
66+
pkgId,
67+
subpath,
68+
pkgJson,
69+
generatedAt: generatedAt(),
70+
generatedIn: generatedIn(start),
71+
};
72+
}
73+
74+
// TODO:
75+
// // Check if the package provides type definitions and if not
76+
// // check if there is an associated DefinitelyTyped (DT) package.
77+
// const typesRes = yield * Effect.either(packageTypes(pkgJson, subpath));
78+
// if (Either.isLeft(typesRes)) {
79+
// const dtPkgName = yield * findDefinitelyTypedPackage({ pkgName, cwd });
80+
// if (!dtPkgName) {
81+
// yield * Effect.logWarning(`no types: ${pkgId}`);
82+
// return {
83+
// status: "no-types" as const,
84+
// pkgId,
85+
// subpath,
86+
// pkgJson,
87+
// generatedAt: generatedAt(),
88+
// generatedIn: generatedIn(start),
89+
// };
90+
// }
91+
// return {
92+
// status: "definitely-typed" as const,
93+
// pkgId,
94+
// subpath,
95+
// pkgJson,
96+
// dtPkgName,
97+
// generatedAt: generatedAt(),
98+
// generatedIn: generatedIn(start),
99+
// };
100+
// }
101+
102+
// // Check if the DB already has the package API.
103+
// const db = yield * Db;
104+
// yield * Effect.logInfo(`using db: ${db.name}`);
105+
// const getPkgApiRes = yield * Effect.either(db.getPackageApi({ pkg, subpath }));
106+
// if (Either.isLeft(getPkgApiRes)) {
107+
// yield * Effect.logWarning(getPkgApiRes.left);
108+
// } else {
109+
// yield * Effect.logInfo(`db has package api for: ${pkgId}`);
110+
// const pkgApi = getPkgApiRes.right;
111+
// return {
112+
// status: "with-api" as const,
113+
// pkgId,
114+
// subpath,
115+
// pkgJson,
116+
// pkgApi,
117+
// generatedAt: generatedAt(),
118+
// generatedIn: generatedIn(start),
119+
// };
120+
// }
121+
122+
// // Extract the package API.
123+
// const pkgApiRes = yield * Effect.either(extractPackageApi({ pkg, subpath }));
124+
// if (Either.isLeft(pkgApiRes)) {
125+
// yield * Effect.logError(pkgApiRes.left);
126+
// return {
127+
// status: "no-api" as const,
128+
// pkgId,
129+
// subpath,
130+
// pkgJson,
131+
// generatedAt: generatedAt(),
132+
// generatedIn: generatedIn(start),
133+
// };
134+
// }
135+
// const pkgApi = pkgApiRes.right;
136+
137+
// // Store the package API in the DB.
138+
// const setPkgApiRes = yield * Effect.either(db.setPackageApi({ pkg, subpath, pkgApi }));
139+
// if (Either.isLeft(setPkgApiRes)) {
140+
// yield * Effect.logError(setPkgApiRes.left);
141+
// } else {
142+
// yield * Effect.logInfo(`db set package api for: ${pkgId}`);
143+
// }
144+
145+
// // Return data for rendering.
146+
// return {
147+
// status: "with-api" as const,
148+
// pkgId,
149+
// subpath,
150+
// pkgJson,
151+
// pkgApi,
152+
// generatedAt: generatedAt(),
153+
// generatedIn: generatedIn(start),
154+
// };
155+
}
156+
157+
function generatedAt(): string {
158+
return new Date().toISOString();
159+
}
160+
161+
function generatedIn(start: number): number {
162+
return Math.round(performance.now() - start);
163+
}

0 commit comments

Comments
 (0)