Skip to content
Source
Sign inSign up

check-dist-types.mjs

73 lines3.2 KB

1// Type-checks the built `effect` declarations the way a consumer with
2// `skipLibCheck: false` does. Run after `pnpm build` with `stripInternal`
3// enabled to catch public declarations that reference `@internal` symbols
4// (see Effect-TS/effect#6431, #7187, #8161).
5import { execFileSync } from "node:child_process"
6import * as Fs from "node:fs"
7import * as Os from "node:os"
8import * as Path from "node:path"
9import { fileURLToPath } from "node:url"
10​
11const root = Path.resolve(Path.dirname(fileURLToPath(import.meta.url)), "..")
12const pkgDir = Path.join(root, "packages", "effect")
13const dist = Path.join(pkgDir, "dist")
14​
15if (!Fs.existsSync(Path.join(dist, "index.d.ts"))) {
16 console.error("packages/effect/dist is missing; run `pnpm build` first")
17 process.exit(1)
19​
20const pkg = JSON.parse(Fs.readFileSync(Path.join(pkgDir, "package.json"), "utf8"))
21const entrypoints = Object.entries(pkg.publishConfig.exports)
22 .filter(([key, target]) => target !== null && key !== "./package.json" && !key.includes("*"))
23 .map(([key, target]) => [Path.posix.join(pkg.name, key), [Path.join(pkgDir, target.replace(/\.js$/, ".d.ts"))]])
24​
25const dir = Fs.mkdtempSync(Path.join(Os.tmpdir(), "effect-dist-types-"))
26try {
27 Fs.writeFileSync(
28 Path.join(dir, "index.ts"),
29 entrypoints.map(([entry], i) => `import * as _${i} from "${entry}"\nexport { _${i} }\n`).join("")
30 )
31 const config = {
32 compilerOptions: {
33 strict: true,
34 noEmit: true,
35 target: "ES2022",
36 module: "ESNext",
37 moduleResolution: "bundler",
38 skipLibCheck: false,
39 types: ["node"],
40 typeRoots: [Path.join(root, "node_modules", "@types")],
41 paths: {
42 ...Object.fromEntries(entrypoints),
43 [`${pkg.name}/*`]: [Path.join(dist, "*")]
44 }
45 },
46 files: ["index.ts"]
47 }
48 Fs.writeFileSync(Path.join(dir, "tsconfig.json"), JSON.stringify(config))
49 execFileSync("pnpm", ["exec", "tsc", "-p", Path.join(dir, "tsconfig.json")], { cwd: root, stdio: "inherit" })
50​
51 // Core, crypto and JOSE imports must work without DOM types (see Effect-TS/effect#10115).
52 Fs.writeFileSync(
53 Path.join(dir, "index.ts"),
54 ["effect", "effect/Effect", "effect/Schema", "effect/crypto/KeyFormat", "effect/jose"]
55 .map((entry, i) => `import * as _${i} from "${entry}"\nexport { _${i} }\n`).join("")
56 )
57 config.compilerOptions.lib = ["ES2024"]
58 config.compilerOptions.exactOptionalPropertyTypes = true
59 Fs.writeFileSync(Path.join(dir, "tsconfig.json"), JSON.stringify(config))
60 execFileSync("pnpm", ["exec", "tsc", "-p", Path.join(dir, "tsconfig.json")], { cwd: root, stdio: "inherit" })
61​
62 // Even a single subpath import must work without Node ambient types or
63 // an explicit ESNext.Disposable library (see Effect-TS/effect#9314).
64 Fs.writeFileSync(Path.join(dir, "index.ts"), 'export * from "effect/Option"\n')
65 config.compilerOptions.types = []
66 config.compilerOptions.lib = ["ES2022", "DOM", "DOM.Iterable"]
67 Fs.writeFileSync(Path.join(dir, "tsconfig.json"), JSON.stringify(config))
68 execFileSync("pnpm", ["exec", "tsc", "-p", Path.join(dir, "tsconfig.json")], { cwd: root, stdio: "inherit" })
69} catch (error) {
70 process.exitCode = typeof error.status === "number" ? error.status : 1
71} finally {
72 Fs.rmSync(dir, { recursive: true, force: true })