{"version":3,"file":"iso-8601.mjs","sources":["../../../../src/predefined/brand/string/iso-8601.mts"],"sourcesContent":["import {\n  type Brand,\n  type NonEmptyString,\n  type StrictOmit,\n} from 'ts-type-forge';\nimport { brand } from '../../../brand/index.mjs';\nimport { boolean, string } from '../../../primitives/index.mjs';\nimport { record } from '../../../record/index.mjs';\nimport { type Type, type TypeOf } from '../../../type.mjs';\n\n// A valid ISO 8601 string always begins with a 4-digit year, so `Iso8601` is\n// branded on top of `NonEmptyString` and is assignable to it.\nexport type Iso8601 = Brand<NonEmptyString, 'Iso8601'>;\n\n/**\n * @link https://github.com/validatorjs/validator.js/tree/v13.1.17?tab=readme-ov-file#validators\n * @link https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString\n * @link https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format\n */\nexport const iso8601 = (options?: ISO8601ValidatorOption): Type<Iso8601> => {\n  const filledOptions = ISO8601ValidatorOption.fill(options);\n\n  const is = isISO8601(filledOptions);\n\n  return brand<NonEmptyString, readonly ['Iso8601']>({\n    baseType: string(filledOptions.defaultValue, { nonempty: true }),\n    is,\n    brandKeys: ['Iso8601'],\n    typeName: 'Iso8601',\n  });\n};\n\nconst ISO8601ValidatorOption = record({\n  /**\n   *  If strict is true, date strings with invalid dates like 2009-02-29 will be invalid.\n   */\n  strict: boolean(false),\n\n  /**\n   * If strictSeparator is true, date strings with date and time separated by anything other than a T will be invalid.\n   */\n  strictSeparator: boolean(false),\n\n  /**\n   * @default new Date().toISOString()\n   */\n  // eslint-disable-next-line unicorn/no-unreadable-new-expression\n  defaultValue: string(new Date().toISOString()),\n});\n\ntype ISO8601ValidatorOption = TypeOf<typeof ISO8601ValidatorOption>;\n\nconst isISO8601 =\n  (options?: Partial<StrictOmit<ISO8601ValidatorOption, 'defaultValue'>>) =>\n  (str: string): str is Iso8601 => {\n    const filledOptions = ISO8601ValidatorOption.fill(options);\n\n    const check = filledOptions.strictSeparator\n      ? regexpIso8601StrictSeparator.test(str)\n      : regexpIso8601.test(str);\n\n    if (check && filledOptions.strict) return isValidDate(str);\n\n    return check;\n  };\n\n// from http://goo.gl/0ejHHW\nconst regexpIso8601 =\n  // eslint-disable-next-line security/detect-unsafe-regex\n  /^([+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([\\sT]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24:?00)([,.]\\d+(?!:))?)?(\\17[0-5]\\d([,.]\\d+)?)?([Zz]|([+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$/u;\n\n// same as above, except with a strict 'T' separator between date and time\nconst regexpIso8601StrictSeparator =\n  // eslint-disable-next-line security/detect-unsafe-regex\n  /^([+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))(T((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24:?00)([,.]\\d+(?!:))?)?(\\17[0-5]\\d([,.]\\d+)?)?([Zz]|([+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$/u;\n\nconst isValidDate = (str: string): boolean => {\n  // str must have passed the ISO8601 check\n  // this check is meant to catch invalid dates\n  // like 2009-02-31\n  // first check for ordinal dates\n  const ordinalMatch = /^(\\d{4})-?(\\d{3})([ T]\\.*|$)/u.exec(str);\n\n  if (ordinalMatch !== null) {\n    const oYear = Number(ordinalMatch[1]);\n\n    const oDay = Number(ordinalMatch[2]);\n\n    // if is leap year\n    if ((oYear % 4 === 0 && oYear % 100 !== 0) || oYear % 400 === 0)\n      return oDay <= 366;\n\n    return oDay <= 365;\n  }\n\n  const match = /(\\d{4})-?(\\d{0,2})-?(\\d*)/u.exec(str)?.map(Number);\n\n  const year = match?.[1];\n\n  const month: number | undefined = match?.[2];\n\n  const date: number | undefined = match?.[3];\n\n  // create a date object and compare\n  const d = new Date(\n    `${year}-${`0${month ?? 1}`.slice(-2)}-${`0${date ?? 1}`.slice(-2)}`,\n  );\n\n  if (month !== undefined && date !== undefined) {\n    return (\n      d.getUTCFullYear() === year &&\n      d.getUTCMonth() + 1 === month &&\n      d.getUTCDate() === date\n    );\n  }\n\n  return true;\n};\n"],"names":[],"mappings":";;;;;;;;AAmBO,MAAM,OAAA,GAAU,CAAC,OAAA,KAAoD;AAC1E,EAAA,MAAM,aAAA,GAAgB,sBAAA,CAAuB,IAAA,CAAK,OAAO,CAAA;AAEzD,EAAA,MAAM,EAAA,GAAK,UAAU,aAAa,CAAA;AAElC,EAAA,OAAO,KAAA,CAA4C;AAAA,IACjD,UAAU,MAAA,CAAO,aAAA,CAAc,cAAc,EAAE,QAAA,EAAU,MAAM,CAAA;AAAA,IAC/D,EAAA;AAAA,IACA,SAAA,EAAW,CAAC,SAAS,CAAA;AAAA,IACrB,QAAA,EAAU;AAAA,GACX,CAAA;AACH;AAEA,MAAM,yBAAyB,MAAA,CAAO;AAAA;AAAA;AAAA;AAAA,EAIpC,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAAA;AAAA;AAAA;AAAA,EAKrB,eAAA,EAAiB,QAAQ,KAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9B,cAAc,MAAA,CAAA,iBAAO,IAAI,IAAA,EAAK,EAAE,aAAa;AAC/C,CAAC,CAAA;AAID,MAAM,SAAA,GACJ,CAAC,OAAA,KACD,CAAC,GAAA,KAAgC;AAC/B,EAAA,MAAM,aAAA,GAAgB,sBAAA,CAAuB,IAAA,CAAK,OAAO,CAAA;AAEzD,EAAA,MAAM,KAAA,GAAQ,cAAc,eAAA,GACxB,4BAAA,CAA6B,KAAK,GAAG,CAAA,GACrC,aAAA,CAAc,IAAA,CAAK,GAAG,CAAA;AAE1B,EAAA,IAAI,KAAA,IAAS,aAAA,CAAc,MAAA,EAAQ,OAAO,YAAY,GAAG,CAAA;AAEzD,EAAA,OAAO,KAAA;AACT,CAAA;AAGF,MAAM,aAAA;AAAA;AAAA,EAEJ;AAAA,CAAA;AAGF,MAAM,4BAAA;AAAA;AAAA,EAEJ;AAAA,CAAA;AAEF,MAAM,WAAA,GAAc,CAAC,GAAA,KAAyB;AAK5C,EAAA,MAAM,YAAA,GAAe,+BAAA,CAAgC,IAAA,CAAK,GAAG,CAAA;AAE7D,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,YAAA,CAAa,CAAC,CAAC,CAAA;AAEpC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,YAAA,CAAa,CAAC,CAAC,CAAA;AAGnC,IAAA,IAAK,QAAQ,CAAA,KAAM,CAAA,IAAK,QAAQ,GAAA,KAAQ,CAAA,IAAM,QAAQ,GAAA,KAAQ,CAAA;AAC5D,MAAA,OAAO,IAAA,IAAQ,GAAA;AAEjB,IAAA,OAAO,IAAA,IAAQ,GAAA;AAAA,EACjB;AAEA,EAAA,MAAM,QAAQ,4BAAA,CAA6B,IAAA,CAAK,GAAG,CAAA,EAAG,IAAI,MAAM,CAAA;AAEhE,EAAA,MAAM,IAAA,GAAO,QAAQ,CAAC,CAAA;AAEtB,EAAA,MAAM,KAAA,GAA4B,QAAQ,CAAC,CAAA;AAE3C,EAAA,MAAM,IAAA,GAA2B,QAAQ,CAAC,CAAA;AAG1C,EAAA,MAAM,oBAAI,IAAI,IAAA;AAAA,IACZ,GAAG,IAAI,CAAA,CAAA,EAAI,CAAA,CAAA,EAAI,KAAA,IAAS,CAAC,CAAA,CAAA,CAAG,KAAA,CAAM,EAAE,CAAC,IAAI,CAAA,CAAA,EAAI,IAAA,IAAQ,CAAC,CAAA,CAAA,CAAG,KAAA,CAAM,EAAE,CAAC,CAAA;AAAA,GACpE;AAEA,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,IAAA,KAAS,MAAA,EAAW;AAC7C,IAAA,OACE,CAAA,CAAE,cAAA,EAAe,KAAM,IAAA,IACvB,CAAA,CAAE,WAAA,EAAY,GAAI,CAAA,KAAM,KAAA,IACxB,CAAA,CAAE,UAAA,EAAW,KAAM,IAAA;AAAA,EAEvB;AAEA,EAAA,OAAO,IAAA;AACT,CAAA;;;;"}