{"version":3,"file":"isValidDomain-DloI5laq.cjs","names":["isString","isBoolean","joinLines","getPreciseType","safeStableStringify","EOL","punycodeUtilsJS","ccTldMap","sldMap","createMessage"],"sources":["../src/predicates/is/isURL.ts","../src/predicates/is/_private/data/domain/sldMap.json","../src/predicates/is/_private/data/domain/ccTldMap.json","../src/predicates/is/isValidDomain.ts"],"sourcesContent":["/** ---------------------------------------------------------\n * * ***Type guard: `isURL`.***\n * ----------------------------------------------------------\n * **Checks if a value is an instance of the\n * **[`URL`](https://developer.mozilla.org/docs/Web/API/URL)** class.**\n *\n * ---\n * - **Behavior:**\n *     - Narrows type to `URL` when true.\n *     - Excludes `strings`, `plain-objects`, and `other non-URL values`.\n *\n * ---\n * @param {*} value - The value to check.\n *\n * ---\n * @returns {boolean} Returns `true` if the value is an instance of `URL`, otherwise `false`.\n *\n * ---\n * @example\n * isURL(new URL(\"https://example.com\"));\n * // ➔ true\n * isURL(\"https://example.com\");\n * // ➔ false\n */\nexport const isURL = (value: unknown): value is URL => {\n  return value instanceof URL;\n};\n","","","import { joinLines, EOL } from \"@rzl-zone/build-tools/utils\";\n\nimport { createMessage } from \"@/_private/logger\";\n\nimport { punycodeUtilsJS } from \"@/urls/utils/punyCode\";\nimport { assertIsPlainObject } from \"@/assertions/objects/assertIsPlainObject\";\nimport { safeStableStringify } from \"@/conversions/stringify/safeStableStringify\";\n\nimport sldMap from \"./_private/data/domain/sldMap.json\";\nimport ccTldMap from \"./_private/data/domain/ccTldMap.json\";\n\nimport { isString } from \"./isString\";\nimport { isBoolean } from \"./isBoolean\";\n\nimport { getPreciseType } from \"../type/getPreciseType\";\n\n/** ---------------------------------------------------------\n * * ***Options for `isValidDomain` predicate.***\n * ----------------------------------------------------------\n * **Customize the behavior of domain validation.**\n */\ntype IsValidDomainOptions = {\n  /** ---------------------------------------------------------\n   * * ***Enable conversion of Unicode domains (IDN) to ASCII (punycode).***\n   * ----------------------------------------------------------\n   *\n   * - Example:\n   *     - `\"пример.рф\"` ➔ `\"xn--e1afmkfd.xn--p1ai\"`.\n   * - Allows validating Unicode domains correctly.\n   * - Default: `false`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * false\n   * ```\n   */\n  allowUnicode?: boolean;\n\n  /** ---------------------------------------------------------\n   * * ***If `true`, validates **only top-level domains (TLDs)** that are not part of any SLD/second-level domain.***\n   * ----------------------------------------------------------\n   *\n   * - Behavior:\n   *     - Accepts country-code TLDs like `\"ai\"` or `\"ai.\"` ✅.\n   *     - Rejects common TLDs that are part of SLDs like `\"com\"` ❌.\n   *     - Only the final label is checked; subdomains are ignored.\n   *     - Default: `false`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * false\n   * ```\n   */\n  topLevel?: boolean;\n\n  /** ---------------------------------------------------------\n   * * ***Allow or disallow subdomains.***\n   * ----------------------------------------------------------\n   *\n   * - Example:\n   *     - `\"sub.example.com\"` ✅ if `subdomain` is `true`, ❌ if `false`.\n   * - Wildcards and SLDs are considered when evaluating subdomains.\n   * - Default: `true`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * true\n   * ```\n   */\n  subdomain?: boolean;\n\n  /** ---------------------------------------------------------\n   * * ***Allow a wildcard `*` in the left-most label.***\n   * ----------------------------------------------------------\n   *\n   * - Example:\n   *     - `\"*.example.com\"` ✅ if `wildcard` is `true`, ❌ if `false`.\n   * - Wildcards are only valid in the first label and require at least one additional label.\n   * - Default: `false`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * false\n   * ```\n   */\n  wildcard?: boolean;\n\n  /** ---------------------------------------------------------\n   * * ***Allow a port after the domain.***\n   * ----------------------------------------------------------\n   *\n   * - Example:\n   *     - `\"localhost:3000\"` or `\"example.com:8080\"` ✅ if `allowPort` is `true`.\n   * - Validates that the port is a number between `1` and `65535`.\n   * - Does not affect domain validation rules otherwise.\n   * - Default: `false`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * false\n   * ```\n   */\n  allowPort?: boolean;\n\n  /** ---------------------------------------------------------\n   * * ***Allow special domains like `localhost`.***\n   * ----------------------------------------------------------\n   *\n   * - Example:\n   *     - `\"localhost\"` ✅ if `allowLocalhost` is `true`.\n   * - Works with or without a port if `allowPort` is enabled.\n   * - Default: `false`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * false\n   * ```\n   */\n  allowLocalhost?: boolean;\n\n  /** ---------------------------------------------------------\n   * * ***Allow URLs with protocol (`http`/`https`) and automatically extract the hostname.***\n   * ----------------------------------------------------------\n   *\n   * - Example:\n   *     - `\"https://example.com/foo/bar\"` ➔ `\"example.com\"`.\n   * - The function will validate only the hostname part and ***ignore*** the `path`, `query`, and `fragment`.\n   * - Default: `false`.\n   *\n   * ---\n   * @default\n   * ```ts\n   * false\n   * ```\n   */\n  allowProtocol?: boolean;\n};\n\n/** ---------------------------------------------------------\n * * ***Predicate: `isValidDomain`.***\n * ----------------------------------------------------------\n * **Validates whether a given string is a properly formatted domain name.**\n *\n * ---\n * - #### *Behavior:*\n *     - Supports options for:\n *         - `allowUnicode` ➔ allows internationalized domain names (IDN) with Unicode characters.\n *         - `topLevel` ➔ validates **only top-level domains (TLDs)**; ignores subdomains and SLDs.\n *         - `subdomain` ➔ allows or disallows subdomains.\n *         - `wildcard` ➔ allows wildcard (`*`) in the left-most label.\n *         - `allowPort` ➔ allows a port number after the domain (e.g., `example.com:8080`).\n *         - `allowLocalhost` ➔ allows the special domain `\"localhost\"`.\n *         - `allowProtocol` ➔ allows a URL with protocol (`http`/`https`) and extracts the hostname.\n *     - Converts Unicode to ASCII (punycode) if `allowUnicode` is `true`.\n *     - Checks label lengths (`≤63` chars), valid characters, and punycode consistency.\n *     - Validates port if `allowPort` is `true` (must be 1–65535).\n *     - Accepts `\"localhost\"` if `allowLocalhost` is `true`.\n *     - Extracts hostname from URLs if `allowProtocol` is `true`.\n *     - Rejects invalid domains, labels starting/ending with `-`, double dots, malformed TLDs, or invalid port numbers.\n *     - Handles both standard domains (`example.com`), URLs with protocols (`https://example.com/foo`), and IDNs (`пример.рф`).\n *\n * ---\n * @param {*} value - The value to validate; only strings are valid domains.\n * @param {IsValidDomainOptions} [options] - Optional configuration for domain validation.\n * @param {boolean} [options.allowUnicode=false] - Enable punycode conversion for Unicode domains.\n * @param {boolean} [options.topLevel=false] - Validate only TLDs (e.g., `ai`, `uk.`); ignores SLDs like `com`.\n * @param {boolean} [options.subdomain=true] - Allow subdomains; set `false` to reject any subdomain.\n * @param {boolean} [options.wildcard=false] - Allow wildcard `*` in the left-most label (e.g., `*.example.com`).\n * @param {boolean} [options.allowPort=false] - Allow port number after domain (e.g., `:3000`); must be 1–65535.\n * @param {boolean} [options.allowLocalhost=false] - Allow special domain `\"localhost\"`.\n * @param {boolean} [options.allowProtocol=false] - Allow URLs with protocol (`http`/`https`) and extract hostname only.\n *\n * ---\n * @returns {boolean} Returns `true` if the value is a valid domain according to the rules and options; otherwise `false`.\n *\n * ---\n * @example\n * isValidDomain(\"google.com\");\n * // ➔ true\n * isValidDomain(\"пример.рф\", { allowUnicode: true });\n * // ➔ true\n * isValidDomain(\"sub.example.com\", { subdomain: false });\n * // ➔ false\n * isValidDomain(\"*.example.com\", { wildcard: true });\n * // ➔ true\n * isValidDomain(\"com\", { topLevel: true });\n * // ➔ false (common TLD rejected because it's part of SLD)\n * isValidDomain(\"ai.\", { topLevel: true });\n * // ➔ true (country-code TLD accepted)\n * isValidDomain(\"localhost\", { allowLocalhost: true });\n * // ➔ true\n * isValidDomain(\"localhost:3000\", { allowLocalhost: true, allowPort: true });\n * // ➔ true\n * isValidDomain(\"example.com:8080\", { allowPort: true });\n * // ➔ true\n * isValidDomain(\"https://example.com/foo/bar\", { allowProtocol: true });\n * // ➔ true (protocol stripped and hostname validated)\n * isValidDomain(\"invalid_domain.com\");\n * // ➔ false\n */\nexport const isValidDomain = (\n  value: unknown,\n  options: IsValidDomainOptions = {}\n): boolean => {\n  if (!isString(value)) return false;\n\n  assertIsPlainObject(options, {\n    message: ({ currentType, validType }) =>\n      errorMsg(\n        `Second parameter (\\`options\\`) must be of type \\`${validType}\\`, but received: \\`${currentType}\\`.`\n      )\n  });\n\n  const {\n    subdomain = true,\n    topLevel = false,\n    wildcard = false,\n    allowUnicode = false,\n    allowPort = false,\n    allowLocalhost = false,\n    allowProtocol = false\n  } = options;\n\n  // Validate Options:\n  const invalid = Object.entries({\n    subdomain,\n    topLevel,\n    wildcard,\n    allowUnicode,\n    allowProtocol,\n    allowPort,\n    allowLocalhost\n  }).filter(([, value]) => !isBoolean(value));\n\n  if (invalid.length) {\n    const msg = invalid\n      .map(([key, value], i) => {\n        return joinLines(\n          `   ${i + 1}. option: \"${key}\"`,\n          \"      expected: boolean\",\n          `      received: ${getPreciseType(value)} (${safeStableStringify(\n            value,\n            {\n              keepUndefined: true\n            }\n          )})`\n        );\n      })\n      .join(EOL);\n\n    throw new TypeError(\n      errorMsg(\n        joinLines(\"\", \"> Invalid options detected in second parameter:\", msg)\n      )\n    );\n  }\n\n  // -----------------\n\n  let _value = value.toLowerCase();\n\n  if (allowProtocol) {\n    try {\n      const url = new URL(value); // use original input\n      if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return false; // reject non-http(s)\n      if (!allowPort && url.port) return false; // reject port if allowPort=false\n      _value = url.hostname.toLowerCase(); // extract only hostname\n\n      // wildcard check\n      const labels = _value.split(\".\");\n      if (labels[0] === \"*\" && !wildcard) return false;\n    } catch {\n      // if parsing fails, leave _value unchanged\n    }\n  }\n\n  if (value.endsWith(\".\")) {\n    _value = _value.slice(0, _value.length - 1);\n  }\n\n  // Handle port\n  let port: string;\n  if (allowPort) {\n    const portMatch = _value.match(/:(\\d{1,5})$/);\n    if (portMatch) {\n      port = portMatch[0];\n      _value = _value.slice(0, -port.length);\n      const portNum = Number(portMatch[1]);\n      if (portNum < 1 || portNum > 65535) return false;\n    }\n  }\n\n  // Allow localhost\n  if (allowLocalhost && _value === \"localhost\") return true;\n\n  if (allowUnicode) {\n    try {\n      _value = punycodeUtilsJS.toASCII(_value);\n    } catch {\n      return false;\n    }\n  }\n\n  if (_value.length > 253) return false;\n\n  const validChars = /^([\\u0E00-\\u0E7Fa-z0-9-._*]+)$/g;\n  if (!validChars.test(_value)) return false;\n\n  if (topLevel) {\n    if (ccTldMap[_value.replace(/\\.$/, \"\") as keyof typeof ccTldMap]) {\n      return true;\n    }\n  }\n\n  const sldRegex = /(.*)\\.(([\\u0E00-\\u0E7Fa-z0-9]+)(\\.[a-z0-9]+))/;\n  const matches = _value.match(sldRegex);\n  // eslint-disable-next-line no-useless-assignment\n  let tld: string | null = null;\n  let labels: string[] | null = null;\n\n  if (matches && matches.length > 2) {\n    if (sldMap[matches[2] as keyof typeof sldMap]) {\n      // eslint-disable-next-line no-useless-assignment\n      tld = matches[2] || null;\n      labels = matches[1]?.split(\".\") || null;\n    }\n  }\n\n  if (!labels) {\n    labels = _value.split(\".\");\n    if (labels.length <= 1) return false;\n\n    tld = labels.pop()!;\n    const tldRegex = /^(?:xn--)?(?!^\\d+$)[\\u0E00-\\u0E7Fa-z0-9]+$/gi;\n    if (!tldRegex.test(tld)) return false;\n  }\n\n  if (subdomain === false && labels.length > 1) return false;\n\n  return labels.every((label, index) => {\n    if (wildcard && index === 0 && label === \"*\" && labels.length > 1) {\n      return true;\n    }\n\n    let validLabelChars = /^([\\u0E00-\\u0E7Fa-zA-Z0-9-_]+)$/g;\n    if (index === labels.length - 1) {\n      validLabelChars = /^([\\u0E00-\\u0E7Fa-zA-Z0-9-]+)$/g;\n    }\n\n    const doubleDashCount = (label.match(/--(--)?/g) || []).length;\n    const xnDashCount = (label.match(/xn--/g) || []).length;\n    if (index === labels.length - 1 && doubleDashCount !== xnDashCount) {\n      return false;\n    }\n\n    return (\n      validLabelChars.test(label) &&\n      label.length < 64 &&\n      !label.startsWith(\"-\") &&\n      !label.endsWith(\"-\")\n    );\n  });\n};\n\n/**\n * @internal ***`Not part of the public API.`***\n */\nconst errorMsg = (msg: string) => createMessage(\"isValidDomain\", msg);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,SAAS,UAAiC;CACrD,OAAO,iBAAiB;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
