UNPKG

counterfact

Version:

Generate a TypeScript-based mock server from an OpenAPI spec in seconds — with stateful routes, hot reload, and REPL support.

83 lines (82 loc) 3.46 kB
import { format } from "prettier"; /** * Builds the `VersionsGTE` map: for each version V at index i, * maps V to all versions at indices >= i (i.e. V and all later-declared * versions, where "later" means "newer"). */ function buildVersionsGTE(versions) { const result = new Map(); versions.forEach((version, index) => { result.set(version, versions.slice(index)); }); return result; } /** * Generates the TypeScript source text for `types/versions.ts`. * * Returns an empty string when `versions` is empty. * The returned string is formatted with Prettier. * * @param versions - Ordered list of unique, non-empty version strings. * The first entry is the oldest version. */ export async function generateVersionsTsContent(versions) { if (versions.length === 0) { return ""; } const versionsUnion = versions.map((v) => `"${v}"`).join(" | "); const versionsGTE = buildVersionsGTE(versions); const versionsGTEBody = Array.from(versionsGTE, ([v, gte]) => ` "${v}": ${gte.map((g) => `"${g}"`).join(" | ")};`).join("\n"); const source = [ "// This file is auto-generated by Counterfact. Do not edit.", "", '/** Union of all version strings declared for this API group (e.g. `"v1" | "v2" | "v3"`). */', `export type Versions = ${versionsUnion};`, "", "/**", " * Maps each version to the set of versions that are greater than or equal to it.", " * Used by `Versioned.minVersion()` to narrow which versions a handler must support.", " */", "export type VersionsGTE = {", versionsGTEBody, "};", "", "type VersionMap = Partial<Record<Versions, object>>;", "", "/**", " * The type of the `$` argument in a versioned route handler.", " *", " * @typeParam T - A map from version string to the `$`-arg type for that version", " * (e.g. `{ v1: $v1Type; v2: $v2Type }`). Generated by Counterfact from the spec.", " * @typeParam V - The union of currently active version keys; defaults to all keys of `T`.", " *", " * An instance of `Versioned<T, V>` exposes:", " * - All properties of the intersection `T[V]` (request data, response builders, etc.)", ' * - `version` — the version string for the current request (e.g. `"v2"`).', " * - `minVersion(min)` — type predicate that returns `true` when the current version", " * is at or after `min` in the declared version order and narrows `$` accordingly.", " *", " * @example", " * ```ts", " * export const GET: HTTP_GET = ($) => {", ' * if ($.minVersion("v2")) {', " * // $ is now typed as the v2+ arg — v2-only fields are available", " * return $.response[200].json({ id: $.path.id, extra: $.body.extra });", " * }", " * return $.response[200].json({ id: $.path.id });", " * };", " * ```", " */", "export type Versioned<", " T extends VersionMap,", " V extends keyof T & Versions = keyof T & Versions,", "> = T[V] & {", " version: V;", " minVersion<M extends keyof T & Versions>(", " min: M,", " ): this is Versioned<T, Extract<V, VersionsGTE[M]>>;", "};", "", ].join("\n"); return format(source, { parser: "typescript" }); }