{"version":3,"file":"record-validator.mjs","names":[],"sources":["../../../../../../../@warlock.js/seal/src/validators/record-validator.ts"],"sourcesContent":["import { isPlainObject } from \"@mongez/supportive-is\";\r\nimport { setKeyPath } from \"../helpers\";\r\nimport { objectRule, plainObjectRule } from \"../rules\";\r\nimport type { SchemaContext, ValidationResult } from \"../types\";\r\nimport { BaseValidator } from \"./base-validator\";\r\nimport { applyNullable } from \"../standard-schema/json-schema\";\r\nimport type { JsonSchemaResult, JsonSchemaTarget } from \"../standard-schema/json-schema\";\r\n\r\n/**\r\n * Record validator class - validates objects with dynamic keys and consistent value types\r\n *\r\n * @example\r\n * ```ts\r\n * // Translations object\r\n * v.record(v.string())\r\n * // Valid: { en: \"Hello\", ar: \"مرحبا\", fr: \"Bonjour\" }\r\n *\r\n * // User preferences\r\n * v.record(v.union([v.string(), v.number(), v.boolean()]))\r\n * // Valid: { theme: \"dark\", fontSize: 16, notifications: true }\r\n * ```\r\n */\r\nexport class RecordValidator extends BaseValidator {\r\n  public constructor(\r\n    public valueValidator: BaseValidator,\r\n    errorMessage?: string,\r\n  ) {\r\n    super();\r\n    this.addMutableRule(objectRule, errorMessage);\r\n  }\r\n\r\n  /**\r\n   * Validate it as plain object\r\n   */\r\n  public plainObject(errorMessage?: string) {\r\n    return this.addRule(plainObjectRule, errorMessage);\r\n  }\r\n\r\n  /**\r\n   * Check if value is a plain object type\r\n   */\r\n  public matchesType(value: any): boolean {\r\n    return isPlainObject(value);\r\n  }\r\n\r\n  /**\r\n   * Clone the validator\r\n   */\r\n  public override clone(): this {\r\n    const cloned = super.clone();\r\n    cloned.valueValidator = this.valueValidator.clone();\r\n    return cloned;\r\n  }\r\n\r\n  /**\r\n   * Validate record - iterate all keys and validate each value\r\n   *\r\n   * Absent input (and absent without `.default()`) propagates as `data: undefined`\r\n   * so the parent ObjectValidator can omit the key. Without this, optional record\r\n   * fields would silently materialise as `{}` in the validated output.\r\n   */\r\n  public async validate(data: any, context: SchemaContext): Promise<ValidationResult> {\r\n    // Apply default when absent, then mutate. Mirrors BaseValidator's\r\n    // `valueForRules = data ?? this.getDefaultValue()` so `.default({...})`\r\n    // works on records too.\r\n    const valueForRules = data ?? this.getDefaultValue();\r\n    const mutatedData = await this.mutate(valueForRules, context);\r\n\r\n    const result = await super.validate(data, context);\r\n\r\n    if (result.isValid === false) return result;\r\n\r\n    // Nothing to iterate for absent (no default) or null (nullable) inputs —\r\n    // propagate so the parent ObjectValidator can omit the key.\r\n    if (mutatedData === undefined || mutatedData === null) return result;\r\n\r\n    // Defensive: type rule (objectRule) should have failed for non-objects.\r\n    if (!isPlainObject(mutatedData)) return result;\r\n\r\n    const errors: ValidationResult[\"errors\"] = [];\r\n    const keys = Object.keys(mutatedData);\r\n\r\n    // Validate all values in parallel\r\n    const validationPromises = keys.map(async (key) => {\r\n      const childContext: SchemaContext = {\r\n        ...context,\r\n        parent: mutatedData,\r\n        value: mutatedData[key],\r\n        key,\r\n        path: setKeyPath(context.path, key),\r\n      };\r\n\r\n      const childResult = await this.valueValidator.validate(mutatedData[key], childContext);\r\n\r\n      // Update mutated data with validated result\r\n      mutatedData[key] = childResult.data;\r\n\r\n      // Collect errors from this value\r\n      if (childResult.isValid === false) {\r\n        errors.push(...childResult.errors);\r\n      }\r\n    });\r\n\r\n    await Promise.all(validationPromises);\r\n\r\n    return {\r\n      isValid: errors.length === 0,\r\n      errors,\r\n      data: await this.startTransformationPipeline(mutatedData, context),\r\n    };\r\n  }\r\n\r\n  /**\r\n   * @inheritdoc\r\n   *\r\n   * Generates `{ type: \"object\", additionalProperties: <valueSchema> }` —\r\n   * the standard JSON Schema for a dictionary/map with homogeneous values.\r\n   *\r\n   * @example\r\n   * ```ts\r\n   * v.record(v.string()).toJsonSchema(\"draft-2020-12\")\r\n   * // → { type: \"object\", additionalProperties: { type: \"string\" } }\r\n   *\r\n   * v.record(v.union([v.string(), v.number()])).toJsonSchema(\"draft-2020-12\")\r\n   * // → { type: \"object\", additionalProperties: { oneOf: [{ type: \"string\" }, { type: \"number\" }] } }\r\n   * ```\r\n   */\r\n  public override toJsonSchema(target: JsonSchemaTarget = \"draft-2020-12\"): JsonSchemaResult {\r\n    const schema: JsonSchemaResult = {\r\n      type: \"object\",\r\n      additionalProperties: this.valueValidator.toJsonSchema(target),\r\n    };\r\n\r\n    if (this.isNullable) applyNullable(schema, target);\r\n\r\n    return schema;\r\n  }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,kBAAb,cAAqC,cAAc;CACjD,AAAO,YACL,AAAO,gBACP,cACA;EACA,MAAM;EAHC;EAIP,KAAK,eAAe,YAAY,YAAY;CAC9C;;;;CAKA,AAAO,YAAY,cAAuB;EACxC,OAAO,KAAK,QAAQ,iBAAiB,YAAY;CACnD;;;;CAKA,AAAO,YAAY,OAAqB;EACtC,OAAO,cAAc,KAAK;CAC5B;;;;CAKA,AAAgB,QAAc;EAC5B,MAAM,SAAS,MAAM,MAAM;EAC3B,OAAO,iBAAiB,KAAK,eAAe,MAAM;EAClD,OAAO;CACT;;;;;;;;CASA,MAAa,SAAS,MAAW,SAAmD;EAIlF,MAAM,gBAAgB,QAAQ,KAAK,gBAAgB;EACnD,MAAM,cAAc,MAAM,KAAK,OAAO,eAAe,OAAO;EAE5D,MAAM,SAAS,MAAM,MAAM,SAAS,MAAM,OAAO;EAEjD,IAAI,OAAO,YAAY,OAAO,OAAO;EAIrC,IAAI,gBAAgB,UAAa,gBAAgB,MAAM,OAAO;EAG9D,IAAI,CAAC,cAAc,WAAW,GAAG,OAAO;EAExC,MAAM,SAAqC,CAAC;EAI5C,MAAM,qBAHO,OAAO,KAAK,WAGK,CAAC,CAAC,IAAI,OAAO,QAAQ;GACjD,MAAM,eAA8B;IAClC,GAAG;IACH,QAAQ;IACR,OAAO,YAAY;IACnB;IACA,MAAM,WAAW,QAAQ,MAAM,GAAG;GACpC;GAEA,MAAM,cAAc,MAAM,KAAK,eAAe,SAAS,YAAY,MAAM,YAAY;GAGrF,YAAY,OAAO,YAAY;GAG/B,IAAI,YAAY,YAAY,OAC1B,OAAO,KAAK,GAAG,YAAY,MAAM;EAErC,CAAC;EAED,MAAM,QAAQ,IAAI,kBAAkB;EAEpC,OAAO;GACL,SAAS,OAAO,WAAW;GAC3B;GACA,MAAM,MAAM,KAAK,4BAA4B,aAAa,OAAO;EACnE;CACF;;;;;;;;;;;;;;;;CAiBA,AAAgB,aAAa,SAA2B,iBAAmC;EACzF,MAAM,SAA2B;GAC/B,MAAM;GACN,sBAAsB,KAAK,eAAe,aAAa,MAAM;EAC/D;EAEA,IAAI,KAAK,YAAY,cAAc,QAAQ,MAAM;EAEjD,OAAO;CACT;AACF"}