{"version":3,"file":"id-formats.mjs","names":[],"sources":["../../../../../../../../@warlock.js/seal/src/rules/string/id-formats.ts"],"sourcesContent":["import { invalidRule, VALID_RULE } from \"../../helpers\";\nimport type { SchemaRule } from \"../../types\";\n\n/**\n * Modern ID format validators — UUID, CUID, ULID, nanoid.\n *\n * Each rule asserts the value is a string in the canonical format for its\n * identifier scheme. Rules are intentionally strict (variant nibbles checked\n * for UUID, character classes enforced for ULID's Crockford base32, etc.)\n * so \"looks-like-but-not-valid\" inputs are rejected.\n */\n\nconst UUID_ANY = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst UUID_BY_VERSION: Record<1 | 3 | 4 | 5 | 6 | 7, RegExp> = {\n  1: /^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n  3: /^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n  4: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n  5: /^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n  6: /^[0-9a-f]{8}-[0-9a-f]{4}-6[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n  7: /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n};\n\nexport type UUIDVersion = 1 | 3 | 4 | 5 | 6 | 7;\n\n/**\n * UUID rule — value must be a valid UUID. Optionally restrict to a specific version.\n *\n * @example\n * v.string().uuid()       // any RFC 4122 UUID\n * v.string().uuid(4)      // only v4 (random)\n * v.string().uuid(7)      // only v7 (timestamp-ordered)\n */\nexport const uuidRule: SchemaRule<{ version?: UUIDVersion }> = {\n  name: \"uuid\",\n  defaultErrorMessage: \"The :input must be a valid UUID\",\n  async validate(value, context) {\n    if (typeof value !== \"string\") return invalidRule(this, context);\n\n    const version = this.context.options.version;\n\n    const pattern = version ? UUID_BY_VERSION[version] : UUID_ANY;\n    if (pattern.test(value)) return VALID_RULE;\n\n    if (version !== undefined) {\n      this.context.translationParams.version = version;\n    }\n\n    return invalidRule(this, context);\n  },\n};\n\n/**\n * CUID rule — value must be a valid CUID.\n *\n * Defaults to CUID2 (24 chars, lowercase, starts with letter — see\n * https://github.com/paralleldrive/cuid2). Pass `{ version: 1 }` for legacy\n * CUID1 format (starts with \"c\", ≥25 chars).\n *\n * @example\n * v.string().cuid()                  // CUID2\n * v.string().cuid({ version: 1 })    // legacy CUID1\n */\nexport const cuidRule: SchemaRule<{ version?: 1 | 2 }> = {\n  name: \"cuid\",\n  defaultErrorMessage: \"The :input must be a valid CUID\",\n  async validate(value, context) {\n    if (typeof value !== \"string\") return invalidRule(this, context);\n    const version = this.context.options.version ?? 2;\n    const pattern = version === 1 ? /^c[a-z0-9]{24,}$/ : /^[a-z][a-z0-9]{23}$/;\n    if (pattern.test(value)) return VALID_RULE;\n    this.context.translationParams.version = version;\n    return invalidRule(this, context);\n  },\n};\n\n/**\n * ULID rule — value must be a valid ULID (26 chars, Crockford base32).\n *\n * Crockford base32 excludes the letters I, L, O, U to avoid ambiguity.\n *\n * @example\n * v.string().ulid()\n */\nexport const ulidRule: SchemaRule = {\n  name: \"ulid\",\n  defaultErrorMessage: \"The :input must be a valid ULID\",\n  async validate(value, context) {\n    if (typeof value !== \"string\") return invalidRule(this, context);\n    if (/^[0-9A-HJKMNP-TV-Z]{26}$/.test(value)) return VALID_RULE;\n    return invalidRule(this, context);\n  },\n};\n\n/**\n * nanoid rule — value must be a valid nanoid string.\n *\n * Default length is 21 (standard nanoid). URL-safe alphabet:\n * A–Z, a–z, 0–9, `_`, `-`.\n *\n * @example\n * v.string().nanoid()         // 21 chars (default)\n * v.string().nanoid(10)       // 10 chars\n */\nexport const nanoidRule: SchemaRule<{ length?: number }> = {\n  name: \"nanoid\",\n  defaultErrorMessage: \"The :input must be a valid nanoid\",\n  async validate(value, context) {\n    if (typeof value !== \"string\") return invalidRule(this, context);\n    const length = this.context.options.length ?? 21;\n    const pattern = new RegExp(`^[A-Za-z0-9_-]{${length}}$`);\n    if (pattern.test(value)) return VALID_RULE;\n    this.context.translationParams.length = length;\n    return invalidRule(this, context);\n  },\n};\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,WAAW;AAEjB,MAAM,kBAAyD;CAC7D,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL;;;;;;;;;AAYA,MAAa,WAAkD;CAC7D,MAAM;CACN,qBAAqB;CACrB,MAAM,SAAS,OAAO,SAAS;EAC7B,IAAI,OAAO,UAAU,UAAU,OAAO,YAAY,MAAM,OAAO;EAE/D,MAAM,UAAU,KAAK,QAAQ,QAAQ;EAGrC,KADgB,UAAU,gBAAgB,WAAW,SAC1C,CAAC,KAAK,KAAK,GAAG,OAAO;EAEhC,IAAI,YAAY,QACd,KAAK,QAAQ,kBAAkB,UAAU;EAG3C,OAAO,YAAY,MAAM,OAAO;CAClC;AACF;;;;;;;;;;;;AAaA,MAAa,WAA4C;CACvD,MAAM;CACN,qBAAqB;CACrB,MAAM,SAAS,OAAO,SAAS;EAC7B,IAAI,OAAO,UAAU,UAAU,OAAO,YAAY,MAAM,OAAO;EAC/D,MAAM,UAAU,KAAK,QAAQ,QAAQ,WAAW;EAEhD,KADgB,YAAY,IAAI,qBAAqB,sBAC1C,CAAC,KAAK,KAAK,GAAG,OAAO;EAChC,KAAK,QAAQ,kBAAkB,UAAU;EACzC,OAAO,YAAY,MAAM,OAAO;CAClC;AACF;;;;;;;;;AAUA,MAAa,WAAuB;CAClC,MAAM;CACN,qBAAqB;CACrB,MAAM,SAAS,OAAO,SAAS;EAC7B,IAAI,OAAO,UAAU,UAAU,OAAO,YAAY,MAAM,OAAO;EAC/D,IAAI,2BAA2B,KAAK,KAAK,GAAG,OAAO;EACnD,OAAO,YAAY,MAAM,OAAO;CAClC;AACF;;;;;;;;;;;AAYA,MAAa,aAA8C;CACzD,MAAM;CACN,qBAAqB;CACrB,MAAM,SAAS,OAAO,SAAS;EAC7B,IAAI,OAAO,UAAU,UAAU,OAAO,YAAY,MAAM,OAAO;EAC/D,MAAM,SAAS,KAAK,QAAQ,QAAQ,UAAU;EAE9C,IAAI,IADgB,OAAO,kBAAkB,OAAO,GAC1C,CAAC,CAAC,KAAK,KAAK,GAAG,OAAO;EAChC,KAAK,QAAQ,kBAAkB,SAAS;EACxC,OAAO,YAAY,MAAM,OAAO;CAClC;AACF"}