mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 19:07:17 +01:00
The two shared packages are the first repos on the preset (link:../ts_config inside the monorepo; consumers outside use the git tag). Each eslint.config.js is now the defineConfig() call plus one override with its reason: a public API name (`nextChance`, `fuzzyMatch`) the boolean-prefix rule would rename, which is a breaking change for the three repos importing it. Everything else the preset flagged is fixed in code, not disabled: key order (perfectionist), hex casing, sort compare functions in tests, Iterator#map().toArray(), explicit returns on multiline arrows. web_ui: react-refresh/only-export-components was a real finding -- range-slider.tsx exported `steppedValue` next to the component, which breaks Vite HMR for the module. The keyboard contract moves to stepped-value.ts as `steppedValue` + a new pure `keyTarget(key, values, current)`, which also resolves unicorn/no-late-event-control: the handler now decides the target first and calls preventDefault() only when it owns the key. Its tests move with it (the 250-line gate caught the combined file). Minor bump for the new export. dist/ rebuilt in both packages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnAYyNH1Sm4iJNidfYbrZJ
74 lines
3.2 KiB
TypeScript
74 lines
3.2 KiB
TypeScript
/**
|
|
* Seeded, deterministic PRNG (mulberry32).
|
|
*
|
|
* A given seed must always reproduce the exact same world, so consumers ban
|
|
* `Math.random` by lint outside this file.
|
|
*
|
|
* ## Why there are two interfaces
|
|
*
|
|
* The four repos that had grown their own copy did not agree on shape:
|
|
* konbini-67 used mutable state plus free functions (`nextFloat(rng)`),
|
|
* while sims3-clone and europe-county-map returned an object of closures
|
|
* (`rng.next()` / `rng.float()`). Both are exported here rather than
|
|
* reconciled into one, because the *sequence* is the contract: these repos
|
|
* have seeded tests and "same seed -> identical world" guarantees, and
|
|
* changing how many times a helper advances the generator silently changes
|
|
* every generated world. A shared package that quietly re-rolled saved
|
|
* worlds would be worse than the duplication it replaced.
|
|
*
|
|
* The generator core is identical in both, so a given seed produces the same
|
|
* float sequence whichever interface you use -- verified in the tests.
|
|
*
|
|
* Note `int` is inclusive of both bounds, matching sims3-clone and
|
|
* europe-county-map. konbini-67's local helper took a single *exclusive*
|
|
* max; it maps to `int(rng, 0, max - 1)`.
|
|
*/
|
|
/** Mutable state for a mulberry32 generator. */
|
|
export interface Rng {
|
|
/** Internal 32-bit state. Advanced by every draw. */
|
|
s: number;
|
|
}
|
|
/** Creates mutable generator state from a seed. */
|
|
export declare const createRng: (seed: number) => Rng;
|
|
/**
|
|
* Deterministic float in [0, 1). Advances the generator.
|
|
*
|
|
* This is the mulberry32 core; every other helper here is defined in terms
|
|
* of it, so they all consume exactly one step per call.
|
|
*/
|
|
export declare const nextFloat: (rng: Rng) => number;
|
|
/** Deterministic integer in [minInclusive, maxInclusive]. One step. */
|
|
export declare const nextInt: (rng: Rng, minInclusive: number, maxInclusive: number) => number;
|
|
/** True with the given probability in [0, 1]. One step. */
|
|
export declare const nextChance: (rng: Rng, probability: number) => boolean;
|
|
/**
|
|
* Deterministic pick from a non-empty tuple. One step.
|
|
*
|
|
* Iterates rather than indexing: under `noUncheckedIndexedAccess` an index
|
|
* read is `T | undefined`, and the undefined arm is unreachable here, so it
|
|
* could never be covered by a test.
|
|
*/
|
|
export declare const pick: <T>(rng: Rng, items: readonly [T, ...T[]]) => T;
|
|
/**
|
|
* The closure-style interface, for consumers that pass an `Rng` object
|
|
* around rather than threading mutable state through free functions.
|
|
*/
|
|
export interface SeededRng {
|
|
/** True with the given probability in [0, 1]. */
|
|
chance: (probability: number) => boolean;
|
|
/** Uniform float in [0, 1). */
|
|
float: () => number;
|
|
/** Uniform integer in [minInclusive, maxInclusive]. */
|
|
int: (minInclusive: number, maxInclusive: number) => number;
|
|
/** Uniform element of a non-empty array. */
|
|
pick: <T>(items: readonly T[]) => T;
|
|
}
|
|
/**
|
|
* Creates a {@link SeededRng} over the same mulberry32 core.
|
|
*
|
|
* `pick` throws on an empty array rather than returning `undefined`: the
|
|
* callers all treat their input as non-empty, and a silent `undefined`
|
|
* propagates into generated data where it is far harder to trace.
|
|
*/
|
|
export declare const createSeededRng: (seed: number) => SeededRng;
|
|
//# sourceMappingURL=rng.d.ts.map
|