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.
51 lines
1.4 KiB
TypeScript
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()}`;
|
|
}
|