{"version":3,"file":"field-parse-BbNyotv5.mjs","names":[],"sources":["../src/runtime/field-parse.ts"],"sourcesContent":["import { formatDate } from \"./date\";\nimport { getTemporal } from \"./temporal\";\nimport type { FieldMetadata, TailorFieldType } from \"#/configure/types/field.types\";\nimport type { TailorPrincipal } from \"#/runtime/types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nconst regex = {\n  uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n  date: /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$/,\n  time: /^(?<hour>[01]\\d|2[0-3]):(?<minute>[0-5]\\d)$/,\n  datetime:\n    /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})[Tt](?<hour>[01]\\d|2[0-3]):(?<minute>[0-5]\\d):(?<second>[0-5]\\d|60)(\\.(?<fraction>\\d+))?(?<offset>[Zz]|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$/,\n  decimal: /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/,\n} as const;\n\n/**\n * Whether a value is an acceptable shape for a nested field. Runtime input may\n * not match the declared field type, so anything this rejects is reported\n * against the field rather than recursed into.\n * @param value - The value to check\n * @returns `true` when the value is a plain object the parser recurses into\n */\nexport function isNestedObject(value: unknown): value is Record<string, unknown> {\n  return (\n    typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof Date)\n  );\n}\n\nexport type FieldParseArgs = {\n  value: unknown;\n  data: unknown;\n  invoker: TailorPrincipal | null;\n};\n\nexport type FieldParseInternalArgs = {\n  value: unknown;\n  data: unknown;\n  invoker: TailorPrincipal | null;\n  pathArray: string[];\n};\n\nexport type FieldRuntime<T extends TailorFieldType = TailorFieldType> = {\n  readonly type: T;\n  readonly fields: Record<string, FieldRuntime>;\n  _metadata: FieldMetadata;\n};\n\ntype FieldParseRuntimeArgs<T extends TailorFieldType> = FieldParseInternalArgs & {\n  field: FieldRuntime<T>;\n};\n\ntype FieldValidationArgs<T extends TailorFieldType> = FieldParseRuntimeArgs<T> & {\n  issues: StandardSchemaV1.Issue[];\n};\n\nfunction validateBaseValue<T extends TailorFieldType>(args: FieldValidationArgs<T>): boolean {\n  const { field, value, pathArray, issues } = args;\n  const path = pathArray.length > 0 ? pathArray : undefined;\n  const initialIssueCount = issues.length;\n\n  switch (field.type) {\n    case \"string\":\n      if (typeof value !== \"string\") {\n        issues.push({\n          message: `Expected a string: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n\n    case \"integer\":\n      if (typeof value !== \"number\" || !Number.isInteger(value)) {\n        issues.push({\n          message: `Expected an integer: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n\n    case \"float\":\n      if (typeof value !== \"number\" || !Number.isFinite(value)) {\n        issues.push({\n          message: `Expected a number: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n\n    case \"boolean\":\n      if (typeof value !== \"boolean\") {\n        issues.push({\n          message: `Expected a boolean: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n\n    case \"uuid\":\n      if (typeof value !== \"string\" || !regex.uuid.test(value)) {\n        issues.push({\n          message: `Expected a valid UUID: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n    case \"date\":\n      if (typeof value !== \"string\" || !regex.date.test(value)) {\n        issues.push({\n          message: `Expected to match \"yyyy-MM-dd\" format: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n    case \"datetime\":\n      if (typeof value !== \"string\" || !regex.datetime.test(value)) {\n        issues.push({\n          message: `Expected to match ISO format: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n    case \"time\":\n      if (typeof value !== \"string\" || !regex.time.test(value)) {\n        issues.push({\n          message: `Expected to match \"HH:mm\" format: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n    case \"decimal\":\n      if (typeof value !== \"string\" || !regex.decimal.test(value)) {\n        issues.push({\n          message: `Expected a decimal string: received ${String(value)}`,\n          path,\n        });\n      }\n      break;\n\n    case \"enum\":\n      if (field._metadata.allowedValues) {\n        const allowedValues = field._metadata.allowedValues.map((v) => v.value);\n        if (typeof value !== \"string\" || !allowedValues.includes(value)) {\n          issues.push({\n            message: `Must be one of [${allowedValues.join(\", \")}]: received ${String(value)}`,\n            path,\n          });\n        }\n      }\n      break;\n\n    case \"nested\": {\n      if (!isNestedObject(value)) {\n        issues.push({\n          message: `Expected an object: received ${String(value)}`,\n          path,\n        });\n        return false;\n      }\n\n      let nestedBaseValid = true;\n      for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n        const fieldValue = value[fieldName];\n        if (\n          !validateBaseField({\n            ...args,\n            field: nestedField,\n            value: fieldValue,\n            pathArray: pathArray.concat(fieldName),\n          })\n        ) {\n          nestedBaseValid = false;\n        }\n      }\n      return nestedBaseValid;\n    }\n  }\n\n  return issues.length === initialIssueCount;\n}\n\nfunction validateCustomValue<T extends TailorFieldType>(\n  args: FieldValidationArgs<T>,\n  validateFns: NonNullable<FieldMetadata[\"validate\"]>,\n): void {\n  const { value, pathArray, issues } = args;\n  const path = pathArray.length > 0 ? pathArray : undefined;\n\n  for (const fn of validateFns) {\n    const result = fn({ value });\n    if (typeof result === \"string\") {\n      issues.push({\n        message: result,\n        path,\n      });\n    }\n  }\n}\n\nfunction validateBaseField<T extends TailorFieldType>(args: FieldValidationArgs<T>): boolean {\n  const { field, value, pathArray, issues } = args;\n  const path = pathArray.length > 0 ? pathArray : undefined;\n\n  const isNullOrUndefined = value === null || value === undefined;\n  if (field._metadata.required && isNullOrUndefined) {\n    issues.push({\n      message: \"Required field is missing\",\n      path,\n    });\n    return false;\n  }\n\n  if (!field._metadata.required && isNullOrUndefined) {\n    return true;\n  }\n\n  let baseValid = true;\n  if (field._metadata.array) {\n    if (!Array.isArray(value)) {\n      issues.push({\n        message: \"Expected an array\",\n        path,\n      });\n      return false;\n    }\n\n    for (let i = 0; i < value.length; i++) {\n      if (\n        !validateBaseValue({\n          ...args,\n          value: value[i],\n          pathArray: pathArray.concat(`[${i}]`),\n        })\n      ) {\n        baseValid = false;\n      }\n    }\n  } else {\n    baseValid = validateBaseValue(args);\n  }\n\n  return baseValid;\n}\n\nfunction validateCustomField<T extends TailorFieldType>(args: FieldValidationArgs<T>): void {\n  const { field, value, pathArray } = args;\n  if (value === null || value === undefined) {\n    return;\n  }\n\n  if (field.type === \"nested\") {\n    const records = field._metadata.array\n      ? (value as Record<string, unknown>[])\n      : [value as Record<string, unknown>];\n\n    for (let i = 0; i < records.length; i++) {\n      const record = records[i] as Record<string, unknown>;\n      const recordPath = field._metadata.array ? pathArray.concat(`[${i}]`) : pathArray;\n      for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n        validateCustomField({\n          ...args,\n          field: nestedField,\n          value: record[fieldName],\n          pathArray: recordPath.concat(fieldName),\n        });\n      }\n    }\n  }\n\n  const validateFns = field._metadata.validate;\n  if (validateFns?.length) {\n    validateCustomValue(args, validateFns);\n  }\n}\n\nexport function parseInternal<T extends TailorFieldType, Output>(\n  args: FieldParseRuntimeArgs<T>,\n): StandardSchemaV1.Result<Output> {\n  let { value } = args;\n  const issues: StandardSchemaV1.Issue[] = [];\n  const validationArgs = { ...args, issues };\n  const baseValid = validateBaseField(validationArgs);\n  if (baseValid) {\n    value = deserializeDates(validationArgs);\n    if (issues.length === 0) {\n      validateCustomField({ ...validationArgs, value });\n    }\n  }\n  if (issues.length > 0) {\n    return { issues };\n  }\n\n  return { value: (value ?? null) as Output };\n}\n\nfunction deserializeDates(args: FieldValidationArgs<TailorFieldType>): unknown {\n  const { field, value, issues, pathArray } = args;\n  if (value === null || value === undefined) return value;\n  const convert = (item: unknown, itemPath: string[]): unknown => {\n    const { type, _metadata: metadata } = field;\n    if (\n      (type === \"date\" || type === \"datetime\" || type === \"time\") &&\n      (metadata.as === \"date\" || metadata.as === \"temporal\")\n    ) {\n      try {\n        const text = String(item);\n        if (type === \"datetime\" && text.slice(17, 19) === \"60\") {\n          throw new RangeError(\"Leap seconds are not supported\");\n        }\n        if (metadata.as === \"temporal\") {\n          const Temporal = getTemporal();\n          if (type === \"date\") return Temporal.PlainDate.from(text);\n          if (type === \"datetime\") return Temporal.Instant.from(text);\n          return Temporal.PlainTime.from(text);\n        }\n        const date = new Date(\n          type === \"date\"\n            ? `${text}T00:00:00.000Z`\n            : type === \"time\"\n              ? `1970-01-01T${text}:00.000Z`\n              : text,\n        );\n        if (!Number.isFinite(date.getTime())) throw new RangeError(\"Invalid Date\");\n        if (type !== \"time\") {\n          const calendarDate = text.slice(0, 10);\n          if (formatDate(new Date(`${calendarDate}T00:00:00.000Z`)) !== calendarDate) {\n            throw new RangeError(\"Invalid calendar date\");\n          }\n        }\n        return date;\n      } catch (error) {\n        if (!(error instanceof RangeError)) throw error;\n        issues.push({\n          message: `Expected a valid ${type === \"date\" ? \"calendar date\" : type}: received ${item}`,\n          path: itemPath.length > 0 ? itemPath : undefined,\n        });\n        return item;\n      }\n    }\n    if (field.type !== \"nested\") return item;\n    const record = item as Record<string, unknown>;\n    let result = record;\n    for (const [key, child] of Object.entries(field.fields)) {\n      const converted = deserializeDates({\n        ...args,\n        field: child,\n        value: record[key],\n        pathArray: itemPath.concat(key),\n      });\n      if (converted !== record[key]) {\n        if (result === record) result = { ...record };\n        Object.defineProperty(result, key, {\n          value: converted,\n          enumerable: true,\n          configurable: true,\n          writable: true,\n        });\n      }\n    }\n    return result;\n  };\n  if (!field._metadata.array) return convert(value, pathArray);\n  const values = value as unknown[];\n  const converted = values.map((item, index) => convert(item, pathArray.concat(`[${index}]`)));\n  return converted.every((item, index) => item === values[index]) ? value : converted;\n}\n\ntype ParseInputFieldsArgs = FieldParseArgs & {\n  fields: Record<string, FieldRuntime>;\n};\n\n/**\n * Validate a value against a record of input fields, treating the record as a\n * single required object — the same code path deployed functions run via\n * `t.object(fields).parse(...)`, so local validation matches platform behavior.\n * @param args - Input field definitions plus the value, context data, and user\n * @returns Validation result\n */\nexport function parseInputFields(args: ParseInputFieldsArgs): StandardSchemaV1.Result<unknown> {\n  const { fields, ...parseArgs } = args;\n  return parseInternal({\n    ...parseArgs,\n    field: { type: \"nested\", fields, _metadata: { required: true } },\n    pathArray: [],\n  });\n}\n"],"mappings":"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"}