writeLibrary
uses node:fs
A library written the way real ones are: bundler-style imports and the TypeScript features Node can't strip.
import fs from "node:fs"; import path from "node:path"; export function writeLibrary(lib: string) { const write = (file: string, text: string) => { fs.mkdirSync(path.dirname(path.join(lib, file)), { recursive: true }); fs.writeFileSync(path.join(lib, file), text); }; write( "tsconfig.json", JSON.stringify({ compilerOptions: { strict: true, module: "ESNext", moduleResolution: "node", declaration: true, isolatedDeclarations: true, noEmit: true, lib: ["ESNext"], target: "ES2022", }, }), ); write( "src/symbols.ts", `export const tag = Symbol("tag"); // two ambient brands with identical text are still two distinct symbols export declare const BrandA: unique symbol; export declare const BrandB: unique symbol; export type A = string & { [BrandA]: true }; export type B = string & { [BrandB]: true }; export type infer<T> = T extends { value: infer V } ? V : never; `, ); write( "src/shapes.ts", `import * as symbols from "./symbols"; export enum Kind { Circle = "circle", Square = "square" } export namespace Geometry { export const tau = 2 * Math.PI; } export class Shape { constructor(public readonly kind: Kind, private size: number) {} area(): number { return this.kind === Kind.Circle ? (Geometry.tau / 2) * this.size ** 2 : this.size ** 2; } get [symbols.tag](): string { return this.kind; } } // a type named like a type keyword, through a namespace import, in a type position export function unwrap<T extends { value: unknown }>(x: T): symbols.infer<T> { return x.value as symbols.infer<T>; } `, ); write( "src/config.ts", `// module state: a lazily created cell, written by one function and read by another let config: { verbose: boolean } | undefined; let calls = 0; export function setConfig(c: { verbose: boolean }): void { config = c; calls++; } export function getConfig(): { verbose: boolean } { return config ?? { verbose: false }; } export const callCount = (): number => calls; // @ts-expect-error the implementation is deliberately looser than this overload // (the explanation continues on a second line) export function pick(x: number): string; export function pick(x: string): string; export function pick(x: string | boolean): string { return String(x); } `, ); write( "src/tables.ts", `// constants set up by the statements after them: a table a loop fills, a constructor's prototype, a frozen object const alphabet = "abc"; const codes = new Uint8Array(128).fill(255); for (let i = 0; i < alphabet.length; i++) codes[alphabet.charCodeAt(i)] = i; const Proto = { describe(this: { n: number }): string { return "n=" + this.n; }, }; const Impl = function (this: { n: number }, n: number) { this.n = n; } as unknown as { new (n: number): { n: number; describe(): string }; prototype: unknown }; Impl.prototype = Proto; export const limits = { max: 3 }; Object.freeze(limits); export const code = (c: string): number => codes[c.charCodeAt(0)]!; // another name for the same function export const codeOf: (c: string) => number = code; export const make = (n: number) => new Impl(n); // an interface with a namespace of types beside it, as Effect writes them export interface Box<A> { readonly value: A; } export declare namespace Box { type Value<B> = B extends Box<infer A> ? A : never; } export const box = <A>(value: A): Box<A> => ({ value }); // a function, an interface and a namespace of types sharing a name, in one cycle, as Effect's Struct export declare namespace Pair { type Of<A> = readonly [A, A]; } export function Pair<A>(a: A, b: A): Pair<A> { return { items: [a, b], make: Pair }; } export interface Pair<A> { readonly items: Pair.Of<A>; readonly make: typeof Pair; } export const firstOf = <A>(p: Pair<A>): Pair.Of<A>[0] => p.items[0]; export const unbox = <B extends Box<unknown>>(b: B): Box.Value<B> => b.value as Box.Value<B>; `, ); // what the host provides, declared rather than imported, as code that runs on several hosts does write( "src/host.ts", `declare const process: { readonly platform: string };\nexport const platform = (): string => process.platform;\n`, ); // a name both imported (as a type) and declared here (as a value), as Effect's internal Stream is write( "src/merged.ts", `import type { Box } from "./tables"; const Box = function (this: { value: number }, value: number) { this.value = value; } as unknown as new (value: number) => Box<number>; export const boxed = (n: number): Box<number> => new Box(n); `, ); write("src/index.ts", `export * from "./shapes";\nexport * from "./config";\n`); // test helpers that need a dev dependency nobody installed: excluded write( "src/testing/helpers.ts", `import { expect } from "vitest";\nexport const ok = () => expect(1).toBe(1);\n`, ); }