{"version":3,"file":"parse-domain.js","sourceRoot":"","sources":["../src/parse-domain.ts"],"names":[],"mappings":"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","sourcesContent":["import { icannTrie, privateTrie } from \"./serialized-tries.js\";\nimport { lookUpTldsInTrie } from \"./trie/look-up.js\";\nimport {\n  ValidationError,\n  sanitize,\n  SanitizationResultType,\n  SanitizationResultValidIp,\n  Validation,\n} from \"./sanitize.js\";\nimport { TrieRootNode } from \"./trie/nodes.js\";\nimport { parseTrie } from \"./trie/parse-trie.js\";\nimport { NO_HOSTNAME } from \"./from-url.js\";\n\nexport const RESERVED_TOP_LEVEL_DOMAINS = [\n  \"localhost\",\n  \"local\",\n  \"example\",\n  \"invalid\",\n  \"test\",\n];\n\nexport type Label = string;\n\nexport enum ParseResultType {\n  /**\n   * This parse result is returned in case the given hostname does not adhere to [RFC 1034](https://tools.ietf.org/html/rfc1034).\n   */\n  Invalid = \"INVALID\",\n  /**\n   * This parse result is returned if the given hostname was an IPv4 or IPv6.\n   */\n  Ip = \"IP\",\n  /**\n   * This parse result is returned when the given hostname\n   * - is the root domain (the empty string `\"\"`)\n   * - belongs to the top-level domain `localhost`, `local`, `example`, `invalid` or `test`\n   */\n  Reserved = \"RESERVED\",\n  /**\n   * This parse result is returned when the given hostname is valid and does not belong to a reserved top-level domain, but is not listed in the public suffix list.\n   */\n  NotListed = \"NOT_LISTED\",\n  /**\n   * This parse result is returned when the given hostname belongs to a top-level domain that is listed in the public suffix list.\n   */\n  Listed = \"LISTED\",\n}\n\n// The following parse result types are organized in this complicated way\n// way because every property should only be described by a single JSDoc comment.\n// If we copy the types (hence duplicating the shared properties),\n// JSDoc comments would show up duplicated in the final return type as well.\ntype ParseResultCommon<Type extends ParseResultType> = {\n  /**\n   * The type of the parse result. Use switch or if to distinguish between different results.\n   */\n  type: Type;\n  /**\n   * The original hostname that was passed to parseDomain().\n   */\n  hostname: Type extends ParseResultType.Invalid\n    ? string | typeof NO_HOSTNAME\n    : string;\n};\n\nexport type ParseResultInvalid = ParseResultCommon<ParseResultType.Invalid> & {\n  /**\n   * An array of validation errors.\n   */\n  errors: Array<ValidationError>;\n};\n\ntype ParseResultCommonValidDomain = {\n  /**\n   * An array of labels that were separated by a dot character in the given hostname.\n   */\n  labels: Array<Label>;\n};\n\nexport type ParseResultIp = ParseResultCommon<ParseResultType.Ip> &\n  Pick<SanitizationResultValidIp, \"ipVersion\">;\n\nexport type ParseResultReserved = ParseResultCommon<ParseResultType.Reserved> &\n  ParseResultCommonValidDomain;\n\nexport type ParseResultNotListed =\n  ParseResultCommon<ParseResultType.NotListed> & ParseResultCommonValidDomain;\n\ntype ParseResultListedDomains = {\n  /**\n   * An array of labels that belong to the subdomain. Can be empty if there was no subdomain in the given hostname.\n   */\n  subDomains: Array<Label>;\n  /**\n   * The first label that belongs to the user-controlled section of the hostname. Can be undefined if just a top-level domain was passed to parseDomain().\n   */\n  domain: Label | undefined;\n  /**\n   * An array of labels that are controlled by the domain registrar.\n   */\n  topLevelDomains: Array<Label>;\n};\n\nexport type ParseResultListed = ParseResultCommon<ParseResultType.Listed> &\n  ParseResultCommonValidDomain &\n  ParseResultListedDomains & {\n    /**\n     * The parse result according to ICANN only without private top-level domains.\n     */\n    icann: ParseResultListedDomains;\n  };\n\nexport type ParseResult =\n  | ParseResultInvalid\n  | ParseResultIp\n  | ParseResultReserved\n  | ParseResultNotListed\n  | ParseResultListed;\n\nconst getAtIndex = <Item>(\n  array: Array<Item>,\n  index: number,\n): Item | undefined => {\n  return index >= 0 && index < array.length ? array[index] : undefined;\n};\n\nconst splitLabelsIntoDomains = (\n  labels: Array<Label>,\n  index: number,\n): ParseResultListedDomains => {\n  return {\n    subDomains: labels.slice(0, Math.max(0, index)),\n    domain: getAtIndex(labels, index),\n    topLevelDomains: labels.slice(index + 1),\n  };\n};\n\nlet parsedIcannTrie: TrieRootNode | undefined;\nlet parsedPrivateTrie: TrieRootNode | undefined;\n\nexport type ParseDomainOptions = {\n  /**\n   * If no validation is specified, Validation.Strict will be used.\n   **/\n  validation?: Validation;\n};\n\n/**\n * Splits the given hostname in topLevelDomains, a domain and subDomains.\n */\nexport const parseDomain = (\n  hostname: string | typeof NO_HOSTNAME,\n  options?: ParseDomainOptions,\n): ParseResult => {\n  const sanitizationResult = sanitize(hostname, options);\n\n  if (sanitizationResult.type === SanitizationResultType.Error) {\n    return {\n      type: ParseResultType.Invalid,\n      hostname,\n      errors: sanitizationResult.errors,\n    };\n  }\n\n  if (sanitizationResult.type === SanitizationResultType.ValidIp) {\n    return {\n      type: ParseResultType.Ip,\n      hostname: sanitizationResult.ip,\n      ipVersion: sanitizationResult.ipVersion,\n    };\n  }\n\n  const { labels, domain } = sanitizationResult;\n\n  if (\n    hostname === \"\" ||\n    RESERVED_TOP_LEVEL_DOMAINS.includes(labels[labels.length - 1])\n  ) {\n    return {\n      type: ParseResultType.Reserved,\n      hostname: domain,\n      labels,\n    };\n  }\n\n  // Parse the serialized trie lazily\n  parsedIcannTrie = parsedIcannTrie ?? parseTrie(icannTrie);\n  parsedPrivateTrie = parsedPrivateTrie ?? parseTrie(privateTrie);\n\n  const icannTlds = lookUpTldsInTrie(labels, parsedIcannTrie);\n  const privateTlds = lookUpTldsInTrie(labels, parsedPrivateTrie);\n\n  if (icannTlds.length === 0 && privateTlds.length === 0) {\n    return {\n      type: ParseResultType.NotListed,\n      hostname: domain,\n      labels,\n    };\n  }\n\n  const indexOfPublicSuffixDomain =\n    labels.length - Math.max(privateTlds.length, icannTlds.length) - 1;\n\n  const indexOfIcannDomain = labels.length - icannTlds.length - 1;\n\n  return {\n    type: ParseResultType.Listed,\n    hostname: domain,\n    labels,\n    icann: splitLabelsIntoDomains(labels, indexOfIcannDomain),\n    ...splitLabelsIntoDomains(labels, indexOfPublicSuffixDomain),\n  };\n};\n"]}