social-kit / scripts / gen-text-dts.mjs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Generates types/text.d.ts — the SocialTextKey string-literal union — from
// the EN table in src/ardegazu/social/text.cljs, so the i18n contract app
// catalogs mirror as Record<SocialTextKey, …> can never drift from the
// implementation. `--check` (used by `npm run check`) diffs the generated
// content against the committed file and fails on any difference.
import { readFileSync, writeFileSync } from "node:fs";

const SRC = new URL("../src/ardegazu/social/text.cljs", import.meta.url).pathname;
const OUT = new URL("../types/text.d.ts", import.meta.url).pathname;

const src = readFileSync(SRC, "utf8");
const keys = [...src.matchAll(/"(social\.[^"]+)"/g)].map((m) => m[1]).sort();
if (keys.length === 0) throw new Error("no social.* keys found in text.cljs");
const dupes = keys.filter((k, i) => keys.indexOf(k) !== i);
if (dupes.length > 0) throw new Error(`duplicate keys in text.cljs: ${dupes.join(", ")}`);

const content = `/**
 * GENERATED by scripts/gen-text-dts.mjs from src/ardegazu/social/text.cljs —
 * do not edit by hand. \`npm run check\` fails when this file drifts from the
 * implementation's EN table.
 */

/** Every chip/toast string the kit renders — the i18n contract app catalogs
 *  mirror as \`Record<SocialTextKey, …>\` so tsc catches drift after a bump. */
export type SocialTextKey =
${keys.map((k) => `  | ${JSON.stringify(k)}`).join("\n")};

export type SocialVars = Record<string, string | number>;

/** An app-supplied translator. Returning the key itself (or nothing) means
 *  "not translated" and falls back to the built-in EN table. */
export type SocialT = (key: string, vars?: SocialVars) => string | undefined;

/** The built-in EN text — also what senders put on the wire as the legacy
 *  invite label, which must stay English-stable for old receivers. */
export declare function enText(key: SocialTextKey, vars?: SocialVars): string;

/** Wrap an optional app translator with the EN fallback. */
export declare function mkT(userT?: SocialT): (key: SocialTextKey, vars?: SocialVars) => string;
`;

if (process.argv.includes("--check")) {
  let committed = null;
  try {
    committed = readFileSync(OUT, "utf8");
  } catch {
    /* missing counts as drift */
  }
  if (committed !== content) {
    console.error("gen-text-dts: types/text.d.ts is out of date — run `node scripts/gen-text-dts.mjs`");
    process.exit(1);
  }
  console.log(`gen-text-dts: OK (${keys.length} keys, types/text.d.ts in sync)`);
} else {
  writeFileSync(OUT, content);
  console.log(`gen-text-dts: wrote types/text.d.ts (${keys.length} keys)`);
}

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/social-kit.git