Skip to content

Commit 21548c0

Browse files
committed
feat: add PackageTypesResolver
1 parent 94a3f76 commit 21548c0

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

src/package-types-resolver.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type { NormalizedPackageJson } from "read-pkg";
2+
import { exports } from "resolve.exports";
3+
4+
export class PackageTypesResolver {
5+
#pkgJson: Partial<NormalizedPackageJson>;
6+
#subpath: string;
7+
8+
constructor(pkgJson: Partial<NormalizedPackageJson>, subpath: string) {
9+
this.#pkgJson = pkgJson;
10+
this.#subpath = subpath.trim();
11+
}
12+
13+
resolveTypes(): string | undefined {
14+
return this.resolveExportsMapTypes() ?? this.resolveTypesOrTypings();
15+
}
16+
17+
resolveExportsMapTypes(): string | undefined {
18+
try {
19+
const entries =
20+
exports(this.#pkgJson, this.#subpath, {
21+
conditions: ["types", "import", "node"],
22+
unsafe: true,
23+
}) ?? [];
24+
const entry = entries.at(0);
25+
if (!entry || !this.isTypesFile(entry)) return undefined;
26+
return entry;
27+
} catch {
28+
// The package may not have an `exports` map.
29+
return undefined;
30+
}
31+
}
32+
33+
resolveTypesOrTypings(): string | undefined {
34+
// Try to find the `package.json#/types` (or `typings`) file
35+
// but accept it only to describe the types for the root subpath.
36+
if (!this.isRootSubpath()) return undefined;
37+
const entry = this.#pkgJson.types || this.#pkgJson.typings;
38+
if (!entry || !this.isTypesFile(entry)) return undefined;
39+
return entry;
40+
}
41+
42+
isRootSubpath(): boolean {
43+
return [".", this.#pkgJson.name].includes(this.#subpath);
44+
}
45+
46+
isTypesFile(filename: string): boolean {
47+
return [".d.ts", ".d.mts", ".d.cts"].some((ext) => filename.endsWith(ext));
48+
}
49+
}

0 commit comments

Comments
 (0)