{"version":3,"sources":["../../src/query/parsers.ts"],"sourcesContent":["/**\n * Farm.js Query State Parsers\n *\n * Shared parsers that can be used in both client and server contexts\n */\n\nexport interface Parser<T> {\n  parse: (value: string) => T | null;\n  serialize: (value: T) => string;\n  withDefault?: (defaultValue: T) => Parser<T>;\n}\n\nconst INTEGER_PATTERN = /^[+-]?\\d+$/;\nconst FLOAT_PATTERN = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/;\nconst ISO_DATE_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst ISO_DATE_TIME_PATTERN =\n  /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$/;\n\nfunction parseInteger(value: string): number | null {\n  if (!INTEGER_PATTERN.test(value)) return null;\n  const parsed = Number(value);\n  return Number.isSafeInteger(parsed) ? parsed : null;\n}\n\nfunction parseFloatValue(value: string): number | null {\n  if (!FLOAT_PATTERN.test(value)) return null;\n  const parsed = Number(value);\n  return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction isValidCalendarDate(year: number, month: number, day: number): boolean {\n  if (month < 1 || month > 12 || day < 1) return false;\n  const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n  const daysInMonth = [31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n  return day <= daysInMonth[month - 1];\n}\n\nfunction parseIsoDate(value: string): Date | null {\n  const match = value.match(ISO_DATE_PATTERN);\n  if (!match) return null;\n\n  const year = Number(match[1]);\n  const month = Number(match[2]);\n  const day = Number(match[3]);\n  if (!isValidCalendarDate(year, month, day)) return null;\n\n  const date = new Date(0);\n  date.setUTCHours(0, 0, 0, 0);\n  date.setUTCFullYear(year, month - 1, day);\n  return date;\n}\n\nfunction parseIsoDateTime(value: string): Date | null {\n  const match = value.match(ISO_DATE_TIME_PATTERN);\n  if (!match) return null;\n\n  const year = Number(match[1]);\n  const month = Number(match[2]);\n  const day = Number(match[3]);\n  const hour = Number(match[4]);\n  const minute = Number(match[5]);\n  const second = Number(match[6]);\n  const timezone = match[7];\n  if (!isValidCalendarDate(year, month, day) || hour > 23 || minute > 59 || second > 59) {\n    return null;\n  }\n\n  if (timezone !== \"Z\") {\n    const [offsetHour, offsetMinute] = timezone.slice(1).split(\":\").map(Number);\n    if (offsetHour > 23 || offsetMinute > 59) return null;\n  }\n\n  const date = new Date(value);\n  return Number.isFinite(date.getTime()) ? date : null;\n}\n\n// String parser\nexport const asString: Parser<string> = {\n  parse: (value: string) => (value && value.trim()) || null,\n  serialize: (value: string) => value,\n  withDefault: (defaultValue: string) => ({\n    parse: (value: string) => (value && value.trim()) || defaultValue,\n    serialize: (value: string) => value || defaultValue,\n  }),\n};\n\n// Integer parser\nexport const asInteger: Parser<number> = {\n  parse: parseInteger,\n  serialize: (value: number) => value.toString(),\n  withDefault: (defaultValue: number) => ({\n    parse: (value: string) => parseInteger(value) ?? defaultValue,\n    serialize: (value: number) => value.toString(),\n  }),\n};\n\n// Float parser\nexport const asFloat: Parser<number> = {\n  parse: parseFloatValue,\n  serialize: (value: number) => value.toString(),\n  withDefault: (defaultValue: number) => ({\n    parse: (value: string) => parseFloatValue(value) ?? defaultValue,\n    serialize: (value: number) => value.toString(),\n  }),\n};\n\n// Boolean parser\nexport const asBoolean: Parser<boolean> = {\n  parse: (value: string) => {\n    if (value === \"true\") return true;\n    if (value === \"false\") return false;\n    return null;\n  },\n  serialize: (value: boolean) => value.toString(),\n  withDefault: (defaultValue: boolean) => ({\n    parse: (value: string) => {\n      if (value === \"true\") return true;\n      if (value === \"false\") return false;\n      return defaultValue;\n    },\n    serialize: (value: boolean) => value.toString(),\n  }),\n};\n\n// Array parser\nconst STRUCTURED_ARRAY_PREFIX = \"~farm-array:v1:\";\nexport interface ArrayParserOptions {\n  /** Preserve comma URLs by default; opt in when item delimiters must round-trip. */\n  format?: \"comma\" | \"structured\";\n}\n\nfunction parseArrayItems(value: string, structured: boolean): string[] {\n  if (structured && value.startsWith(STRUCTURED_ARRAY_PREFIX)) {\n    try {\n      const parsed = JSON.parse(value.slice(STRUCTURED_ARRAY_PREFIX.length));\n      if (Array.isArray(parsed) && parsed.every((item) => typeof item === \"string\")) {\n        return parsed;\n      }\n    } catch {\n      // Keep accepting legacy values that happen to begin with the prefix.\n    }\n  }\n\n  return value\n    .split(\",\")\n    .filter(Boolean)\n    .map((item) => item.trim());\n}\n\nfunction serializeArrayItems(values: string[], structured: boolean): string {\n  if (!structured) return values.join(\",\");\n\n  const needsStructuredEncoding = values.some(\n    (value, index) =>\n      value === \"\" ||\n      value.trim() !== value ||\n      value.includes(\",\") ||\n      (index === 0 && value.startsWith(STRUCTURED_ARRAY_PREFIX)),\n  );\n  return needsStructuredEncoding\n    ? `${STRUCTURED_ARRAY_PREFIX}${JSON.stringify(values)}`\n    : values.join(\",\");\n}\n\nexport function asArrayOf<T>(itemParser: Parser<T>, options: ArrayParserOptions = {}): Parser<T[]> {\n  const structured = options.format === \"structured\";\n  const parse = (value: string): T[] | null => {\n    if (!value) return null;\n    return parseArrayItems(value, structured)\n      .map((item) => itemParser.parse(item))\n      .filter((item) => item !== null) as T[];\n  };\n  const serialize = (value: T[]) =>\n    serializeArrayItems(\n      value.map((item) => itemParser.serialize(item)),\n      structured,\n    );\n\n  return {\n    parse,\n    serialize,\n    withDefault: (defaultValue: T[]) => ({\n      parse: (value: string) => parse(value) ?? defaultValue,\n      serialize,\n    }),\n  };\n}\n\n// JSON parser\nexport function asJson<T>(): Parser<T> {\n  return {\n    parse: (value: string) => {\n      try {\n        return JSON.parse(value);\n      } catch {\n        return null;\n      }\n    },\n    serialize: (value: T) => JSON.stringify(value),\n    withDefault: (defaultValue: T) => ({\n      parse: (value: string) => {\n        try {\n          return JSON.parse(value);\n        } catch {\n          return defaultValue;\n        }\n      },\n      serialize: (value: T) => JSON.stringify(value),\n    }),\n  };\n}\n\n// ISO Date parser\nexport const asIsoDate: Parser<Date> = {\n  parse: parseIsoDate,\n  serialize: (value: Date) => value.toISOString().slice(0, 10),\n  withDefault: (defaultValue: Date) => ({\n    parse: (value: string) => parseIsoDate(value) ?? defaultValue,\n    serialize: (value: Date) => value.toISOString().slice(0, 10),\n  }),\n};\n\n// ISO DateTime parser\nexport const asIsoDateTime: Parser<Date> = {\n  parse: parseIsoDateTime,\n  serialize: (value: Date) => value.toISOString(),\n  withDefault: (defaultValue: Date) => ({\n    parse: (value: string) => parseIsoDateTime(value) ?? defaultValue,\n    serialize: (value: Date) => value.toISOString(),\n  }),\n};\n\n// Custom parser creator\nexport function createParser<T>(config: {\n  parse: (value: string) => T | null;\n  serialize: (value: T) => string;\n}): Parser<T> {\n  return {\n    parse: config.parse,\n    serialize: config.serialize,\n    withDefault: (defaultValue: T) => ({\n      parse: (value: string) => config.parse(value) ?? defaultValue,\n      serialize: config.serialize,\n    }),\n  };\n}\n\n// Type inference helper\nexport type inferParserType<T> = T extends Parser<infer U> ? U : never;\n"],"mappings":"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","names":[]}