# UuidPlugin ## Purpose Generates UUID v4 and URL-safe nano-ID strings inline within templates. Because ID generation depends on `crypto.randomUUID` or `Math.random`, the plugin accepts an injectable `Rng` from `@suaveplan/types` so tests can produce deterministic output. Each template token renders a freshly generated ID, making the plugin appropriate for generating row identifiers, correlation IDs, or unique slugs during batch template rendering. ## Features - `{_uuid}` — UUID v4 string (`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`). - `{_uuid:v4}` — explicit UUID v4 (same as above). - `{_nanoid}` — 21-character URL-safe nano-ID using the default base-64 alphabet. - `{_nanoid:10}` — nano-ID with custom length. - Injectable `Rng` for fully deterministic output in tests. - Prefers `globalThis.crypto.randomUUID()` when available and no `rng` is injected. ## Usage: Basic Example ```ts import { TemplateEngine, createUuidPlugin } from "@suaveplan/templates"; const engine = new TemplateEngine().use(createUuidPlugin()); engine.parse("ID: {_uuid}", {}); // → "ID: f47ac10b-58cc-4372-a567-0e02b2c3d479" (random) engine.parse("Slug: {_nanoid:8}", {}); // → "Slug: V1StGXR8" (random 8-char) ``` ## Usage: Advanced Example ```ts import { TemplateEngine, createUuidPlugin } from "@suaveplan/templates"; import type { Rng } from "@suaveplan/types"; // Deterministic RNG for tests const deterministicRng: Rng = { nextUint32: () => 0xdeadbeef, nextFloat: () => 0.42, }; const engine = new TemplateEngine().use(createUuidPlugin({ rng: deterministicRng })); const id1 = engine.parse("{_uuid}", {}); const id2 = engine.parse("{_uuid}", {}); // id1 === id2 — same RNG seed produces same output console.assert(id1 === id2); // Nano-ID with explicit length engine.parse("{_nanoid:12}", {}); // → same 12-char string every call with deterministic rng ``` ## API Reference ### `UuidPluginOptions` | Property | Type | Description | |----------|------|-------------| | `rng` | `Rng` (optional) | Injectable RNG; if omitted, uses `crypto.randomUUID` or `Math.random` | ### `createUuidPlugin(opts?): Plugin` Returns a `Plugin` with: - `name: "uuid"` - `priority: PluginPriority.HIGH` (80) - `pattern: /\{_(uuid|nanoid)(?::([^}]+))?\}/g` The pattern captures two groups: 1. Type keyword: `uuid` or `nanoid` 2. Optional parameter (`v4` for UUID variant, numeric length for nano-ID) **transform(match)**: Dispatches on the type keyword. For `uuid`, calls `generateUuid(opts.rng)`. For `nanoid`, parses the parameter as an integer length (defaults to 21) and calls `generateNanoid(length, undefined, opts.rng)`. Returns the original match text for unrecognised type keywords (defensive — cannot occur given the pattern). ## Implementation Notes - `generateUuid` prefers `globalThis.crypto.randomUUID()` when it is available and no `rng` is injected. This avoids manual bit-manipulation and takes advantage of the cryptographically secure native implementation. - When `crypto.randomUUID` is unavailable (older runtimes), the fallback constructs a UUID using the standard `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` template with bitwise operations to enforce RFC 4122 version and variant bits. - `generateNanoid` uses modular selection from the alphabet rather than the rejection-sampling algorithm used by the `nanoid` npm package. This is sufficient for the lengths and alphabets used in template generation and avoids the complexity of rejection sampling. - Runs at `HIGH` priority so IDs are generated before MEDIUM-priority transforms, allowing `{_uuid:upper}` style compositions in future plugin extensions.