Files
Ken Yasue 571b8ae0c4 feat(seed): ~5x richer demo data via deterministic generators
Rewrite scripts/seed-demo.ts as a thin orchestrator over a new scripts/seed/ module (rng, pools, helpers, content, schedule, logs, generators). Scales demo data from 6 users/3 projects to ~30 users/15 projects with ~5-8x per-table content (~6.8x total rows) via a seeded mulberry32 PRNG for full reproducibility (incl. bcrypt salts and file/URL identifiers). FK-safe ordering, real captured IDs for activity logs, enum pools typed against lib/types. Preserves canonical login credentials and projects.
2026-06-25 14:35:56 +02:00

51 lines
1.4 KiB
TypeScript

/**
* シードデータ生成用の決定論的乱数ユーティリティ。
* mulberry32 を用い、固定シードで再現可能なデータを生成する。
*/
export type Rng = () => number;
export function createRng(seed: number): Rng {
let a = seed >>> 0;
return () => {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
export function pick<T>(rng: Rng, arr: readonly T[]): T {
return arr[Math.floor(rng() * arr.length)]!;
}
export function pickN<T>(rng: Rng, arr: readonly T[], n: number): T[] {
return shuffle(rng, arr).slice(0, Math.min(n, arr.length));
}
export function randInt(rng: Rng, min: number, max: number): number {
return Math.floor(rng() * (max - min + 1)) + min;
}
export function shuffle<T>(rng: Rng, arr: readonly T[]): T[] {
const out = [...arr];
for (let i = out.length - 1; i > 0; i--) {
const j = Math.floor(rng() * (i + 1));
[out[i], out[j]] = [out[j]!, out[i]!];
}
return out;
}
export function chance(rng: Rng, p: number): boolean {
return rng() < p;
}
export function seededUuid(rng: Rng): string {
const hex = () =>
Math.floor(rng() * 0x10000)
.toString(16)
.padStart(4, '0');
return `${hex()}${hex()}-${hex()}-${hex()}-${hex()}-${hex()}${hex()}${hex()}`;
}