{"version":3,"file":"common-validation-rule.min.cjs","sources":["../src/rules/alpha-number.js","../src/rules/bool.js","../src/rules/impl/china-identity-card-validator.js","../src/rules/china-identity-card.js","../src/rules/china-mobile.js","../src/rules/china-officer-card.js","../src/rules/china-passport.js","../src/rules/china-phone.js","../src/rules/email.js","../node_modules/email-validator/index.js","../src/rules/integer.js","../src/rules/local-date.js","../src/rules/local-date-time.js","../src/rules/local-time.js","../src/rules/lowercase-hyphen.js","../src/rules/lowercase-underscore.js","../src/rules/number.js","../src/rules/numeric.js","../src/rules/other-credential.js","../src/rules/password.js","../src/rules/person-name.js","../src/rules/timestamp.js","../src/rules/uppercase-alpha-number.js","../src/rules/uppercase-underscore.js","../node_modules/node-uri/src/helpers/object.js","../node_modules/node-uri/src/helpers/cast.js","../node_modules/node-uri/src/helpers/index.js","../node_modules/node-uri/src/ip/index.js","../node_modules/node-uri/src/punycode/index.js","../node_modules/node-uri/src/config/index.js","../node_modules/node-uri/src/parser/index.js","../node_modules/node-uri/src/checkers/chars.js","../node_modules/node-uri/src/domain/index.js","../node_modules/node-uri/src/sitemap/index.js","../node_modules/node-uri/src/checkers/index.js","../node_modules/node-uri/src/index.js","../node_modules/node-uri/src/encoders/index.js","../node_modules/node-uri/src/decoders/index.js","../src/rules/url.js","../src/rules/username.js","../src/validation-result.js","../src/rules/verify-code.js"],"sourcesContent":["////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是数字和字母组合成字符串的正则表达式。\n *\n * 这类字符串通常可以用来表示证件编号、发票号等数据。\n *\n * @author 胡海星\n * @private\n */\nconst ALPHA_NUMBER_REGEXP = /^\\s*[0-9a-zA-Z]+\\s*$/;\n\n/**\n * 数字和字母组合字符串的验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst AlphaNumberRule = {\n\n  /**\n   * 测试一个值是否是数字和字母组合成字符串。\n   *\n   * 这类字符串通常可以用来表示证件编号、发票号等数据。\n   *\n   * @param {any} value\n   *    待测试的值，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是数字和字母组合成字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isString(value)) {\n      return ALPHA_NUMBER_REGEXP.test(value);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default AlphaNumberRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2024.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isBoolean, isString } from '@qubit-ltd/type-detect';\n\n/**\n * 布尔值验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst BoolRule = {\n  /**\n   * 测试一个值是否是一个布尔值或表示合法布尔值的字符串。\n   *\n   * 测试时忽略大小写。\n   *\n   * @param {any} value\n   *    待测试的值，前后允许有空白字符。\n   * @return {boolean}\n   *    若该值是一个布尔值或表示合法布尔值的字符串，则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isBoolean(value)) {\n      return true;\n    } else if (isString(value)) {\n      const val = value.trim().toLowerCase();\n      return (val === 'true' || val === 'false');\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default BoolRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\nimport AREA_CODES from './china-area-codes';\n\nconst NUMBER_LENGTH = 18;\nconst YEAR_INDEX = 6;\nconst YEAR_LENGTH = 4;\nconst MONTH_INDEX = 10;\nconst MONTH_LENGTH = 2;\nconst DAY_INDEX = 12;\nconst DAY_LENGTH = 2;\nconst AREA_INDEX = 0;\nconst AREA_LENGTH = 6;\nconst GENDER_INDEX = 16;\nconst DECIMAL_BASE = 10;\nconst ASCII_0_CHAR_CODE = 48;\nconst ASCII_9_CHAR_CODE = 57;\nconst RATIO = [\n  7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2,\n];\nconst LAST_CHAR = [\n  '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2',\n];\n\n/**\n * 将给定的身份证号码给定的片段解析为整数。\n *\n * @param {string} number\n *     给定的身份证号码。\n * @param {Number} start\n *     起始位置。\n * @param {Number} end\n *     结束位置（不包含在内）。\n * @return\n *     若给定的号码的起始位置到结束位置（不包含）的片段可以解析为一个整数，则返\n *     回解析后的整数；否则返回null。\n * @author 胡海星\n * @private\n */\nfunction parseNumber(number, start, end) {\n  let result = 0;\n  for (let i = start; i < end; ++i) {\n    const ch = number.charCodeAt(i);\n    if (ch < ASCII_0_CHAR_CODE || ch > ASCII_9_CHAR_CODE) {\n      return null;\n    }\n    result *= DECIMAL_BASE;\n    result += (ch - ASCII_0_CHAR_CODE);\n  }\n  return result;\n}\n\n/**\n * 判定给定的身份证号码的生日字段是否合法。\n *\n * 身份证号码第7~12为日期码，表示该居民的出生年月日。格式为YYYYMMDD，如19491001。\n * 出生日期码是按GB/T 7408的规定执行的。\n *\n * 注意：对于身份证号码中编码的出生日期，此函数不仅验证该日期是否存在，也会验证\n * 出生日期是否是个合法的日期，同时也会验证该日期是否超过今天的日期（不应该超过\n * 今天的日期）。\n *\n * @param {string} number\n *     给定的身份证号码。\n * @return {Boolean}\n *     若给定的身份证号码的生日字段合法，则返回true；否则返回false。\n * @author 胡海星\n * @private\n */\nexport function isIdCardBirthdayValid(number) {\n  if (isString(number)) {\n    number = number.trim();\n    if (number.length !== NUMBER_LENGTH) {\n      return false;\n    }\n    const year = parseNumber(number, YEAR_INDEX, YEAR_INDEX + YEAR_LENGTH);\n    const month = parseNumber(number, MONTH_INDEX, MONTH_INDEX + MONTH_LENGTH);\n    const day = parseNumber(number, DAY_INDEX, DAY_INDEX + DAY_LENGTH);\n    if (year == null || month == null || day == null) {\n      return false;\n    }\n    const birthday = new Date(year, month - 1, day);  // 注意月份从0开始计算\n    // 判定解析出来的年、月、日是否是合法的年、月、日\n    if (birthday.getFullYear() !== year\n      || birthday.getMonth() !== month - 1\n      || birthday.getDate() !== day) {\n      return false;\n    }\n    // 判定解析出来的日期是否超过今天，合法的身份证的日期不应该超过今天\n    const now = new Date();\n    if (birthday.getTime() > now.getTime()) {\n      return false;\n    }\n    return true;\n  }\n  return false;\n}\n\n/**\n * 判定给定的身份证号码的地址区县字段是否合法。\n *\n * 身份证号码第1~6位为地址码，表示登记户口时所在地的行政区划代码（省、市、县）。\n * 其中1-2位省、自治区、直辖市代码；3-4位地级市、盟、自治州代码；5-6位县、县级市、\n * 区代码。如果行政区划进行了重新划分，同一个地方进行户口登记的可能存在地址码不\n * 一致的情况。行政区划代码按GB/T2260的规定执行。\n *\n * @param {string} number\n *     给定的身份证号码。\n * @return {Boolean}\n *     若给定的身份证号码的地址区县字段合法，则返回true；否则返回false。\n * @author 胡海星\n * @private\n */\nexport function isIdCardAreaValid(number) {\n  if (isString(number)) {\n    number = number.trim();\n    if (number.length !== NUMBER_LENGTH) {\n      return false;\n    }\n    const code = number.substring(AREA_INDEX, AREA_INDEX + AREA_LENGTH);\n    return AREA_CODES.has(code);\n  } else {\n    return false;\n  }\n}\n\n/**\n * 判定给定的身份证号码是否合法。\n *\n * 身份证号码第1~6位为地址码，表示登记户口时所在地的行政区划代码（省、市、县）。\n * 其中1-2位省、自治区、直辖市代码；3-4位地级市、盟、自治州代码；5-6位县、县级市、\n * 区代码。如果行政区划进行了重新划分，同一个地方进行户口登记的可能存在地址码不\n * 一致的情况。行政区划代码按GB/T2260的规定执行。\n *\n * 身份证号码第7~12为日期码，表示该居民的出生年月日。格式为YYYYMMDD，如19491001。\n * 出生日期码是按GB/T 7408的规定执行的。\n *\n * 身份证号码第15~17为顺序码，表示同一地址码区域内，同年、同月、同日生的人所编订\n * 的顺序号，根据自己身份证的顺序码就可以知道：与我们同年同月同日生的同性至少有\n * 多少个，且在我们之前登记户籍的有多少人。身份证顺序码的奇数分配给男性，偶数分\n * 配给女性。因此身份证号码倒数第2位是奇数则为男性，偶数则为女性。\n *\n * 身份证中第十八位数字的计算方法如下：\n * - 将前面的身份证号码17位数分别乘以不同的系数，从第一位到第十七位的系数分别\n *   为：7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2；\n * - 将这17位数字和系数相乘的结果相加；\n * - 用加出来和除以11，看余数是多少；\n * - 余数只可能有0 、1、 2、 3、 4、 5、 6、 7、 8、 9、 10这11个数字；\n * - 其分别对应的最后一位身份证的号码为1、0、X、9、8、7、6、5、4、3、2；\n *\n * 通过上面得知如果余数是2，就会在身份证的第18位数字上出现罗马数字的Ⅹ。\n * 如果余数是10，身份证的最后一位号码就是2。\n *\n * @param {string} number\n *     给定的身份证号码，前后允许有空白字符。\n * @return {Boolean}\n *     若给定的身份证号码合法，则返回true；否则返回false。\n * @author 胡海星\n * @private\n */\nexport function isIdCardNumberValid(number) {\n  if (isString(number)) {\n    number = number.trim();\n    if (number.length !== NUMBER_LENGTH) {\n      return false;\n    }\n    // 验证奇偶校验码是否合法\n    let sum = 0;\n    for (let i = 0; i < NUMBER_LENGTH - 1; ++i) {\n      const ch = number.charCodeAt(i);\n      if (ch < ASCII_0_CHAR_CODE || ch > ASCII_9_CHAR_CODE) {\n        return false;\n      }\n      sum += (ch - ASCII_0_CHAR_CODE) * RATIO[i];\n    }\n    const lastChar = LAST_CHAR[sum % LAST_CHAR.length];\n    if (number.charAt(NUMBER_LENGTH - 1).toUpperCase() !== lastChar) {\n      return false;\n    }\n    // 验证出生日期是否合法\n    if (!isIdCardBirthdayValid(number)) {\n      return false;\n    }\n    // 验证地址区县是否合法\n    // 暂时屏蔽区号验证\n    // if (!isIdCardAreaValid(number)) {\n    //   return false;\n    // }\n    return true;\n  } else {\n    return false;\n  }\n}\n\n/**\n * 从给定的身份证号码中提取出生日期。\n *\n * 身份证号码第7~12为日期码，表示该居民的出生年月日。格式为YYYYMMDD，如19491001。\n * 出生日期码是按GB/T 7408的规定执行的。\n *\n * 注意此函数不验证给定的身份证号码是否合法，也不验证提取出的出生日期是否合法。\n *\n * @param {string} number\n *     给定的身份证号码。\n * @return {string|null}\n *     从给定的身份证号码中提取出的出生日期，表示为'YYYY-MM-DD'格式的字符串。如\n *     果无法提取，则返回`null`。\n * @author 胡海星\n * @private\n */\nexport function getIdCardBirthday(number) {\n  if (isString(number)) {\n    number = number.trim();\n    if (number.length !== NUMBER_LENGTH) {\n      return null;\n    }\n    const year = number.substring(YEAR_INDEX, YEAR_INDEX + YEAR_LENGTH);\n    const month = number.substring(MONTH_INDEX, MONTH_INDEX + MONTH_LENGTH);\n    const day = number.substring(DAY_INDEX, DAY_INDEX + DAY_LENGTH);\n    return `${year}-${month}-${day}`;\n  } else {\n    return null;\n  }\n}\n\n/**\n * 从给定的身份证号码中提取性别。\n *\n * 注意此函数不验证给定的身份证号码是否合法。\n *\n * @param {string} number\n *     给定的身份证号码。\n * @return {string|null}\n *     从给定的身份证号码中提取出的性别，表示为字符串`'MALE'`或`'FEMALE'`。如果无法提取，则\n *     返回`null`。\n * @author 胡海星\n * @private\n */\nexport function getIdCardGender(number) {\n  if (isString(number)) {\n    number = number.trim();\n    if (number.length !== NUMBER_LENGTH) {\n      return null;\n    }\n    const digit = number.charCodeAt(GENDER_INDEX) - ASCII_0_CHAR_CODE;\n    return (digit % 2 === 1 ? 'MALE' : 'FEMALE');\n  } else {\n    return null;\n  }\n}\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport {\n  isIdCardNumberValid, getIdCardBirthday, getIdCardGender,\n} from './impl/china-identity-card-validator';\n\n/**\n * 中华人民共和国大陆身份证号码验证规则。\n *\n * 身份证号码第1~6位为地址码，表示登记户口时所在地的行政区划代码（省、市、县）。\n * 其中1-2位省、自治区、直辖市代码；3-4位地级市、盟、自治州代码；5-6位县、县级市、\n * 区代码。如果行政区划进行了重新划分，同一个地方进行户口登记的可能存在地址码不\n * 一致的情况。行政区划代码按GB/T2260的规定执行。\n *\n * 身份证号码第7~12为日期码，表示该居民的出生年月日。格式为YYYYMMDD，如19491001。\n * 出生日期码是按GB/T 7408的规定执行的。\n *\n * 身份证号码第15~17为顺序码，表示同一地址码区域内，同年、同月、同日生的人所编订\n * 的顺序号，根据自己身份证的顺序码就可以知道：与我们同年同月同日生的同 性至少有\n * 多少个，且在我们之前登记户籍的有多少人。身份证顺序码的奇数分配给男性，偶数分\n * 配给女性。因此身份证号码倒数第2位是奇数则为男性，偶数则为女性。\n *\n * 身份证中第十八位数字的计算方法如下：\n * - 将前面的身份证号码17位数分别乘以不同的系数，从第一位到第十七位的系数分别\n *   为：7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2；\n * - 将这17位数字和系数相乘的结果相加；\n * - 用加出来和除以11，看余数是多少；\n * - 余数只可能有0 、1、 2、 3、 4、 5、 6、 7、 8、 9、 10这11个数字；\n * - 其分别对应的最后一位身份证的号码为1、0、X、9、8、7、6、5、4、3、2；\n *\n * 通过上面得知如果余数是2，就会在身份证的第18位数字上出现罗马数字的Ⅹ。\n * 如果余数是10，身份证的最后一位号码就是2。\n *\n * 注意：对于身份证号码中编码的出生日期，此验证规则只验证该日期是否存在，没有验\n * 证出生日期的范围是否合法。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst ChinaIdentityCardRule = {\n  /**\n   * 表示身份证的证件类型的字符串。\n   *\n   * @author 胡海星\n   */\n  type: 'IDENTITY_CARD',\n\n  /**\n   * 身份证的证件名称。\n   *\n   * @author 胡海星\n   */\n  name: '身份证',\n\n  /**\n   * 检查身份证号码是否合法\n   *\n   * @param {any} number\n   *    身份证号码，前后允许有空白字符。\n   * @return {boolean}\n   *    若该身份证号码合法，返回true；否则返回false\n   * @author 胡海星\n   */\n  isValid(number) {\n    return isIdCardNumberValid(number);\n  },\n\n  /**\n   * 根据身份证号码计算性别。\n   *\n   * 注意此函数不验证给定的身份证号码是否合法。\n   *\n   * @param {any} number\n   *    身份证号码，前后允许有空白字符。\n   * @return {string|null}\n   *     从给定的身份证号码中提取出的性别，表示为字符串`'MALE'`或`'FEMALE'`。如果无法提取，\n   *     则返回`null`。\n   * @author 胡海星\n   */\n  getGender(number) {\n    return getIdCardGender(number);\n  },\n\n  /**\n   * 根据身份证号码计算出生日期。\n   *\n   * 注意此函数不验证给定的身份证号码是否合法，也不验证提取出的出生日期是否合法。\n   *\n   * @param {any} number\n   *    身份证号码，前后允许有空白字符。\n   * @return {string|null}\n   *    返回该身份证号码对应的出生日期，以字符串形式表示，格式为'YYYY-MM-DD'；\n   *    如身份证号码长度不对，则返回`null`。\n   * @author 胡海星\n   */\n  getBirthday(number) {\n    return getIdCardBirthday(number);\n  },\n};\n\nexport default ChinaIdentityCardRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证中国手机号码的正则表达式\n *\n * - 手机号码可以以 \"0\", \"86\", \"17951\" 开头\n * - 手机号码一共11位数字\n * - 各运营商手机号码开头3位数字为\n *     - 移动：134 135 136 137 138 139 147 148 150 151 152 157 158 159 165 172 178\n *            182 183 184 187 188 198\n *     - 联通：130 131 132 145 146 155 156 166 171 175 176 185 186\n *     - 电信：133 149 153 173 174 177 180 181 189 191 199\n *     - 虚拟运营商：170\n *\n * 参考资料：\n * 1. https://blog.csdn.net/fengshi_sh/article/details/12085307\n * 2. http://www.cnblogs.com/zengxiangzhan/p/phone.html\n *\n * TODO：增加手机号码归属地计算\n *\n * @author 胡海星\n * @private\n */\nconst MOBILE_REGEXP = /^\\s*(0|86|17951)?(13[0-9]|14[5-9]|15[0-35-9]|16[5-6]|17[0-8]|18[0-9]|19[1589])[0-9]{8}\\s*$/;\n\n/**\n * 中国手机号码验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst ChinaMobileRule = {\n  /**\n   * 测试中国手机号码是否合法\n   *\n   * @param {any} mobile\n   *    待测试的手机号码，前后允许有空白字符。\n   * @return {boolean}\n   *    若手机号码合法则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(mobile) {\n    return isString(mobile)\n        && (mobile.length !== 0)\n        && MOBILE_REGEXP.test(mobile);\n  },\n};\n\nexport default ChinaMobileRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证中华人民共和国军官证号码合法性的正则表达式。\n *\n * 合法的军官证号码由6~8位字母、数字或句点组成。\n *\n * @author 胡海星\n * @private\n */\nconst NUMBER_REGEXP = /^\\s*[a-zA-Z0-9.]{6,8}\\s*$/;\n\n/**\n * 中华人民共和国军官证号码验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst ChinaOfficerCardRule = {\n  /**\n   * 表示军官证的证件类型的字符串。\n   *\n   * @type string\n   * @author 胡海星\n   */\n  type: 'OFFICER_CARD',\n\n  /**\n   * 军官证的证件名称。\n   *\n   * @type string\n   * @author 胡海星\n   */\n  name: '中国人民解放军军官证',\n\n  /**\n   * 检查军官证号码是否合法\n   *\n   * @param {any} number\n   *    军官证号码，前后允许有空白字符。\n   * @return {boolean}\n   *    若该军官证号码合法，返回true；否则返回false\n   * @author 胡海星\n   */\n  isValid(number) {\n    if (isString(number)) {\n      return NUMBER_REGEXP.test(number);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default ChinaOfficerCardRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证中华人民共和国护照号码合法性的正则表达式。\n *\n * 中国于2012年5月起正式签发普通电子护照。\n *\n * 普通电子护照颁发给因定居、探亲、学习、就业、旅行、从事商务活动等非公务原因出\n * 国的中国公民，护照号码格式市：E+8 位数字编号 或 E+字母+7位数字编号。\n *\n * 公务护照又分为因公普通护照、公务护照和外交护照三个类别\n * 1. 因公普通护照：PE+7 位数字编码\n * 2. 公务护照：SE+7 位数字编码\n * 3. 外交护照：DE+7 位数字编码\n *\n * 发给有澳门特区永久性居民身份证的中国公民，护照号码格式是：MA+7 位编号。\n *\n * 发给有香港永久性居民身份证，并享有香港特别行政区居留权的中国公民，护照号格\n * 式是：K+8 位编号。\n *\n * 旧版护照号码格式如下：\n *\n * 1. 因私普通护照号码格式：14 + 7位数字， 15 + 7位数字， G + 8位数字；\n * 2. 因公普通护照号码格式：P + 7位数；\n * 3. 公务护照号码格式：S + 7位数 或  S + 8位数；\n * 4. 外交护照号码格式：D + 8为数字；\n *\n * @author 胡海星\n * @private\n */\nconst NUMBER_REGEXP = /^\\s*(E[A-Z0-9][0-9]{7}|[SDP]E[0-9]{7}|MA[0-9]{7}|K[0-9]{8}|1[45][0-9]{7}|G[0-9]{8}|P[0-9]{7}|S[0-9]{7,8}|D[0-9]{8})\\s*$/;\n\n/**\n * 中华人民共和国护照号码验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst ChinaPassportRule = {\n\n  /**\n   * 表示护照的证件类型的字符串。\n   *\n   * @author 胡海星\n   */\n  type: 'PASSPORT',\n\n  /**\n   * 护照的证件名称。\n   *\n   * @author 胡海星\n   */\n  name: '护照',\n\n  /**\n   * 检查护照号码是否合法\n   *\n   * @param {any} number\n   *    护照号码，前后允许有空白字符。\n   * @return {boolean}\n   *    若该护照号码合法，返回true；否则返回false\n   * @author 胡海星\n   */\n  isValid(number) {\n    if (isString(number)) {\n      return NUMBER_REGEXP.test(number);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default ChinaPassportRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证中国固定电话号码的正则表达式\n *\n * - 国内固定电话和传真的格式基本都是带有0的区号+连接符\"-\"＋电话号码；\n * - 另外还有可能有分机号\n * - 区号有3位、4位，电话号码有7位和8位的\n * - 其它格式的有前面不带0的，或者不带连接符的\n * - 或者分机号前面使用#号的，或者前面加\"+86\"的等等；\n *\n * 参考资料：\n * 1. https://blog.csdn.net/lyhjava/article/details/52316438\n *\n * FIXME：验证此规则正确性，并重构规则\n *\n * @author 胡海星\n * @private\n */\nconst PHONE_REGEXP = /^\\s*(\\+?\\d{2,4}[-_－—]?\\d{3,8}([-_－—]?\\d{1,8}){0,2}|0?1[35]\\d{9})\\s*$/;\n\n/**\n * 中国固定电话号码验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst ChinaPhoneRule = {\n  /**\n   * 测试中国固定电话号码是否合法\n   *\n   * @param {any} phone\n   *    待测试的固定电话号码，前后允许有空白字符。\n   * @return {boolean}\n   *    若固定电话号码合法则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(phone) {\n    return isString(phone)\n        && (phone.length !== 0)\n        && PHONE_REGEXP.test(phone);\n  },\n};\n\nexport default ChinaPhoneRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport EmailValidator from 'email-validator';\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 电子邮件地址验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst EmailRule = {\n  /**\n   * 测试电子邮件地址是否合法。\n   *\n   * @param {any} email\n   *    待测试的电子邮件地址，前后允许有空白字符。\n   * @return {boolean}\n   *    若电子邮件地址合法则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(email) {\n    return isString(email)\n        && EmailValidator.validate(email.trim());\n  },\n};\n\nexport default EmailRule;\n","\"use strict\";\r\n\r\nvar tester = /^[-!#$%&'*+\\/0-9=?A-Z^_a-z{|}~](\\.?[-!#$%&'*+\\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\\.?[a-zA-Z0-9])*\\.[a-zA-Z](-?[a-zA-Z0-9])+$/;\r\n// Thanks to:\r\n// http://fightingforalostcause.net/misc/2006/compare-email-regex.php\r\n// http://thedailywtf.com/Articles/Validating_Email_Addresses.aspx\r\n// http://stackoverflow.com/questions/201323/what-is-the-best-regular-expression-for-validating-email-addresses/201378#201378\r\nexports.validate = function(email)\r\n{\r\n\tif (!email)\r\n\t\treturn false;\r\n\t\t\r\n\tif(email.length>254)\r\n\t\treturn false;\r\n\r\n\tvar valid = tester.test(email);\r\n\tif(!valid)\r\n\t\treturn false;\r\n\r\n\t// Further checking of some things regex can't handle\r\n\tvar parts = email.split(\"@\");\r\n\tif(parts[0].length>64)\r\n\t\treturn false;\r\n\r\n\tvar domainParts = parts[1].split(\".\");\r\n\tif(domainParts.some(function(part) { return part.length>63; }))\r\n\t\treturn false;\r\n\r\n\treturn true;\r\n}","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isBigInt, isNumber, isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否表示合法的整数的正则表达式。\n *\n * 整数可以是正数或者负数，只考虑十进制。\n *\n * @author 胡海星\n * @private\n */\nconst INTEGER_REGEXP = /^\\s*[+-]?\\d+\\s*$/;\n\n/**\n * 整数验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst IntegerRule = {\n  /**\n   * 测试一个值是否表示一个合法的整数。\n   *\n   * 整数可以是正数或者负数，只考虑十进制。\n   *\n   * 注意此函数允许字符串首位出现空格。\n   *\n   * @param {any} value\n   *    待测试的值，前后允许有空白字符。\n   * @return {boolean}\n   *    若该值是一个表示整数的`number`，`Number`或`bigint`，或表示整数的字符串，则返回true；\n   *    否则返回false。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isBigInt(value)) {\n      return true;\n    } else if (isNumber(value)) {\n      return Number.isInteger(Number(value));\n    } else if (isString(value)) {\n      return INTEGER_REGEXP.test(value);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default IntegerRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isDate, isString } from '@qubit-ltd/type-detect';\n\n/**\n * 有效本地日期的正则表达式。\n *\n * @author 胡海星\n * @private\n */\nconst DATE_REGEXP = /^\\s*[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}\\s*$/;\n\n/**\n * 本地日期值的验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst LocalDateRule = {\n  /**\n   * 测试一个值是否表示有效的本地日期。\n   *\n   * 该值可以是表示有效本地日期的字符串，或者内置的`Date`对象。\n   *\n   * 如果该值是字符串，在测试前会被去除前后空格。\n   *\n   * 注意，此函数仅测试日期的格式，而不测试其逻辑值（例如，一个月是否超过31天）。\n   *\n   * @param {any} value\n   *    要测试的值。它可以是字符串原始值、内置的`String`对象或内置的`Date`对象。\n   *    字符串的前导或尾随空格将在测试前被去除。\n   * @return {boolean}\n   *    如果该值表示有效的本地日期，则返回`true`；否则返回`false`。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isDate(value)) {\n      return true;\n    } else if (isString(value)) {\n      return DATE_REGEXP.test(value.trim());\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default LocalDateRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否表示合法的本地日期时间的正则表达式。\n *\n * @author 胡海星\n * @private\n */\nconst DATETIME_REGEXP = /^\\s*[0-9]{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01]) (0?[0-9]|1[0-9]|2[0-3]):(0?[0-9]|[1-5][0-9])(:(0?[0-9]|[1-5][0-9]))?\\s*$/;\n\n/**\n * 本地日期时间验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst LocalDateTimeRule = {\n  /**\n   * 测试一个字符串是否表示一个合法的本地日期时间。\n   *\n   * 一个合法的本地日期时间字符串应该符合以下格式：\n   *\n   * ```\n   * yyyy-MM-dd' 'HH:mm:ss\n   * ```\n   *\n   * 注意此函数允许字符串首位出现空格。\n   *\n   * 注意，此函数只考虑日期时间格式是否正确，不考虑日期时间的逻辑合理性（比如某个月超过了31天）。\n   *\n   * @param {any} datetime\n   *    待测试的字符串，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串表示一个合法的日期时间则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(datetime) {\n    if (isString(datetime)) {\n      return DATETIME_REGEXP.test(datetime);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default LocalDateTimeRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 有效本地时间的正则表达式。\n *\n * @author 胡海星\n * @private\n */\nconst TIME_REGEXP = /^\\s*(0?[0-9]|1[0-9]|2[0-3]):(0?[0-9]|[0-5][0-9])(:(0?[0-9]|[0-5][0-9]))?\\s*$/;\n\n/**\n * 本地时间值的验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst LocalTimeRule = {\n  /**\n   * 测试一个值是否表示有效的本地时间。\n   *\n   * 如果该值是字符串，在测试前会被去除前后空格。\n   *\n   * 有效的本地时间字符串应该符合以下格式：\n   * ```\n   * [H]H:[m]m[:[s]s]\n   * ```\n   *\n   * 例如，`12:34`、`23:59:59`、`02:32:9`、`1:2:3`等。\n   *\n   * 注意，此函数仅测试时间的格式，以及其逻辑值（例如，一秒是否超过60）。\n   *\n   * @param {any} value\n   *    要测试的值。它可以是字符串原始值、内置的`String`对象或其他类型。\n   *    字符串的前导和尾随空格将在测试前被去除。\n   * @return {boolean}\n   *    如果该值表示有效的本地时间，则返回`true`；否则返回`false`。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isString(value)) {\n      return TIME_REGEXP.test(value);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default LocalTimeRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2025.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是小写字母和连字符组合成字符串的正则表达式。\n *\n * 这类字符串通常可以用来表示CSS类名、URL路径等数据。\n *\n * @author 胡海星\n * @private\n */\nconst LOWERCASE_HYPHEN_REGEXP = /^\\s*[a-z0-9-]+[a-z0-9-]*\\s*$/;\n\n/**\n * 小写字母和连字符组合字符串验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst LowercaseHyphenRule = {\n  /**\n   * 测试一个字符串是否是小写字母和连字符组合成字符串。\n   *\n   * 这类字符串通常可以用来表示CSS类名、URL路径等数据。\n   * 规则：\n   * - 只能包含小写字母、数字和连字符\n   * - 前后允许有空白字符\n   *\n   * @param {any} str\n   *    待测试的字符串，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是小写字母和连字符组合成字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(str) {\n    if (isString(str)) {\n      return LOWERCASE_HYPHEN_REGEXP.test(str);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default LowercaseHyphenRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2025.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是小写字母和下划线组合成字符串的正则表达式。\n *\n * 这类字符串通常可以用来表示变量名、函数名等数据。\n *\n * @author 胡海星\n * @private\n */\nconst LOWERCASE_UNDERSCORE_REGEXP = /^\\s*[a-z0-9_]+[a-z0-9_]*\\s*$/;\n\n/**\n * 小写字母和下划线组合字符串验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst LowercaseUnderscoreRule = {\n  /**\n   * 测试一个字符串是否是小写字母和下划线组合成字符串。\n   *\n   * 这类字符串通常可以用来表示变量名、函数名等数据。\n   * 规则：\n   * - 只能包含小写字母、数字和下划线\n   * - 前后允许有空白字符\n   *\n   * @param {any} str\n   *    待测试的字符串，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是小写字母和下划线组合成字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(str) {\n    if (isString(str)) {\n      return LOWERCASE_UNDERSCORE_REGEXP.test(str);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default LowercaseUnderscoreRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isNumber, isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否表示合法的数字的正则表达式。\n *\n * 数字可以是正数或者负数，可以是科学计数法，并且只考虑十进制。\n *\n * 注意，此正则表达式不考虑 `NaN` 和 `Infinity`.\n *\n * @author 胡海星\n * @private\n */\nconst NUMBER_REGEXP = /^\\s*[+-]?(?:\\d+\\.?|\\d*\\.\\d+)(?:[E|e][+|-]?\\d+)?\\s*$/;\n\n/**\n * 用于测试一个值是否表示合法的数字的规则对象。\n *\n * 数字包括整数和浮点数（`number`, `Number`对象），但**不包括**大整数（`bigint`）。\n *\n * 表示一个合法数字的字符串（`string`或`String`对象），也被看作是一个合法的数字。\n *\n * 数字可以是正数或者负数，可以是科学计数法，并且只考虑十进制。\n *\n * **注意：** 和 `NumericRule` 对象不同，`bigint` 值不被看作是一个合法的数字。\n *\n * @type {object}\n * @namespace\n * @see NumericRule\n * @author 胡海星\n */\nconst NumberRule = {\n\n  /**\n   * 默认的测试选项。\n   */\n  DEFAULT_OPTION: {\n    allowNaN: false,\n    allowInfinity: false,\n  },\n\n  /**\n   * 测试一个值是否表示一个合法的数字。\n   *\n   * 数字包括整数和浮点数（`number`, `Number`对象），但**不包括**大整数（`bigint`）。\n   *\n   * 表示一个合法数字的字符串（`string`或`String`对象），也被看作是一个合法的数字。\n   *\n   * 数字可以是正数或者负数，可以用科学计数法，并且只考虑十进制。\n   *\n   * 注意此函数允许字符串首位出现空格。\n   *\n   * **注意：** 和 `NumericRule.isValid()` 不同，`bigint` 值不被看作是一个合法的数字。\n   *\n   * @param {any} value\n   *    待测试的值，前后允许有空白字符。\n   * @param {object} option\n   *    测试选项，表示是否将 'NaN' 或 'Infinity' 也看做是合法的数字字符串表示。\n   *    此选项对象可以包含下列属性：\n   *    - allowNaN: 是否将字符串 'NaN' 也看做是一个表示浮点数的合法字符串；默认值为`false`。\n   *    - allowInfinity: 是否将字符串 'Infinity' （注意大小写）也看做是一个表示浮点数的合法字符串；默认值为`false`。\n   * @return {boolean}\n   *    若该值是一个合法数字，或时一个表示合法数字的字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(value, option = this.DEFAULT_OPTION) {\n    if (isNumber(value)) {\n      const val = Number(value);  // should convert value to primitive number\n      if (Number.isNaN(val)) {\n        return (option.allowNaN === true);\n      } else if (!Number.isFinite(val)) {\n        return (option.allowInfinity === true);\n      }\n      return true;\n    } else if (isString(value)) {\n      value = value.trim();\n      if (value.length === 0) {\n        return false;\n      }\n      if (NUMBER_REGEXP.test(value)) {\n        return true;\n      }\n      if (option.allowNaN && value.trim() === 'NaN') {\n        return true;\n      }\n      if (option.allowInfinity && value.trim() === 'Infinity') {\n        return true;\n      }\n    }\n    return false;\n  },\n};\n\nexport default NumberRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isBigInt } from '@qubit-ltd/type-detect';\nimport NumberRule from './number';\n\n/**\n * 用于测试一个值是否表示合法的数值的规则对象。\n *\n * 数值包括整数和浮点数（`number`, `Number`对象），和大整数（`bigint`）。\n *\n * 表示一个合法数字的字符串（`string`或`String`对象），也被看作是一个合法的数值。\n *\n * **注意：** 和 `NumberRule` 对象不同，`bigint` 值也被看作是一个合法的数值。\n *\n * @type {object}\n * @namespace\n * @see NumberRule\n * @author 胡海星\n */\nconst NumericRule = {\n  /**\n   * 测试一个值是否表示一个合法的数值。\n   *\n   * 数值包括整数和浮点数（`number`, `Number`对象），和大整数（`bigint`）。\n   *\n   * 表示一个合法数字的字符串（`string`或`String`对象），也被看作是一个合法的数值。\n   *\n   * 注意此函数允许字符串首位出现空格。\n   *\n   * **注意：** 和 `NumberRule.isValid()` 不同，`bigint` 值也被看作是一个合法的数值。\n   *\n   * @param {any} value\n   *    待测试的值，前后允许有空白字符。\n   * @param {object} option\n   *    测试选项，表示是否将 'NaN' 或 'Infinity' 也看做是合法的浮点数字符串表示。\n   *    此选项对象可以包含下列属性：\n   *    - allowNaN: 是否将字符串 'NaN' 也看做是一个表示浮点数的合法字符串；默认值为`false`。\n   *    - allowInfinity: 是否将字符串 'Infinity' （注意大小写）也看做是一个表示浮点数的合法字符串；默认值为`false`。\n   * @return {boolean}\n   *    若该值是一个合法浮点数，或时一个表示合法浮点数的字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(value, option = NumberRule.DEFAULT_OPTION) {\n    if (isBigInt(value)) {\n      return true;\n    }\n    return NumberRule.isValid(value, option);\n  },\n};\n\nexport default NumericRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证其他证件号码合法性的正则表达式。\n *\n * 合法的证件号码由2~60位字母、数字或句点组成。\n *\n * @author 胡海星\n * @private\n */\nconst NUMBER_REGEXP = /^\\s*[a-zA-Z0-9.]{2,60}\\s*$/;\n\n/**\n * 其他证件号码验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst OtherCredentialRule = {\n  /**\n   * 检查其他证件号码是否合法\n   *\n   * @param {any} number\n   *    证件号码，前后允许有空白字符。\n   * @return {boolean}\n   *    若该证件号码合法，返回true；否则返回false\n   * @author 胡海星\n   */\n  isValid(number) {\n    if (isString(number)) {\n      return NUMBER_REGEXP.test(number);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default OtherCredentialRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2024.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是合法的密码的正则表达式。\n *\n * 密码的规则如下：\n *\n * - 最少6个字符；\n * - 最多32个字符；\n * - 可以包含字母、数字；\n * - 可以包含下列特殊字符：`~!@#$%^&*()_=+{}[]|\\:;'\",./?<>`；\n *\n * @author 胡海星\n * @private\n */\nconst PASSWORD_REGEXP = /^[-a-zA-Z0-9`~!@#$%^&*()_=+{}[\\]|\\\\:;'\",./?<>]+$/;\n\n/**\n * 密码的验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst PasswordRule = {\n  /**\n   * 密码的最小长度。\n   */\n  minLength: 6,\n\n  /**\n   * 密码的最大长度。\n   */\n  maxLength: 32,\n\n  /**\n   * 测试一个值是否是合法的密码。\n   *\n   * 密码的规则如下：\n   *\n   * - 最少6个字符；\n   * - 最多32个字符；\n   * - 可以包含字母、数字；\n   * - 可以包含下列特殊字符：`~!@#$%^&*()_=+{}[]|\\:;'\",./?<>`；\n   *\n   * @param {any} value\n   *    待测试的值，前后不允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是一个表示合法密码的字符串则返回`true`；否则返回`false`。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isString(value)) {\n      return (value.length >= this.minLength)\n        && (value.length <= this.maxLength)\n        && PASSWORD_REGEXP.test(value);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default PasswordRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证中文姓名的正则表达式\n *\n * 中文名称允许出现下述 Unicode 字符集\n * - CJK Unified Ideographs (U+4E00..U+9FEF)\n * - CJK Unified Ideographs Extension A (U+3400..U+4DBF)\n * - CJK Unified Ideographs Extension B (U+20000..U+2A6D6)\n * - CJK Unified Ideographs Extension C (U+2A700..U+2B734)\n * - CJK Unified Ideographs Extension D (U+2B740..U+2B81D)\n * - CJK Unified Ideographs Extension E (U+2B820..U+2CEA1)\n * - CJK Unified Ideographs Extension F (U+2CEB0..U+2EBE0)\n * - CJK Compatibility Ideographs (U+F900..U+FAD9)\n * - CJK Compatibility Ideographs Supplement (U+2F800..U+2FA1F)\n *\n *\n * 同时允许出现少数民族名中的点，包含[.·]等。\n *\n * 最小长度为２个字符，最大为30个字符。名字中间不允许出现空格。\n *\n * 参考链接：\n * 1. https://en.wikipedia.org/wiki/CJK_Unified_Ideographs\n * 2. https://en.wikipedia.org/wiki/CJK_Compatibility_Ideographs\n * 3. https://en.wikipedia.org/wiki/CJK_Compatibility_Ideographs_Supplement\n *\n * @author 胡海星\n * @private\n */\nconst CHINESE_NAME_REGEXP = /^\\s*[\\u{4E00}-\\u{9FEF}\\u{3400}-\\u{4DBF}\\u{20000}-\\u{2A6D6}\\u{2A700}-\\u{2B734}\\u{2B740}-\\u{2B81D}\\u{2B820}-\\u{2CEA1}\\u{2CEB0}-\\u{2EBE0}\\u{F900}-\\u{FAD9}\\u{2F800}-\\u{2FA1F}][\\u{4E00}-\\u{9FEF}\\u{3400}-\\u{4DBF}\\u{20000}-\\u{2A6D6}\\u{2A700}-\\u{2B734}\\u{2B740}-\\u{2B81D}\\u{2B820}-\\u{2CEA1}\\u{2CEB0}-\\u{2EBE0}\\u{F900}-\\u{FAD9}\\u{2F800}-\\u{2FA1F}·.]{0,28}[\\u{4E00}-\\u{9FEF}\\u{3400}-\\u{4DBF}\\u{20000}-\\u{2A6D6}\\u{2A700}-\\u{2B734}\\u{2B740}-\\u{2B81D}\\u{2B820}-\\u{2CEA1}\\u{2CEB0}-\\u{2EBE0}\\u{F900}-\\u{FAD9}\\u{2F800}-\\u{2FA1F}]\\s*$/u;\n\n/**\n * 验证英文姓名或汉语拼音名字的正则表达式\n *\n * 英文姓名或汉语拼音姓名允许大小写英文字母，半角空格，半角句点。\n *\n * 最短需要有2个字符，最长不超过60个字符。\n *\n * @author 胡海星\n * @private\n */\nconst ENGLISH_NAME_REGEXP = /^\\s*[a-zA-Z][a-zA-Z .]{0,58}[a-zA-Z]\\s*$/;\n\n/**\n * 中英文姓名验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst PersonNameRule = {\n  /**\n   * 测试中英文姓名是否合法\n   *\n   * @param {any} name\n   *    待测试的姓名，前后允许有空白字符。\n   * @return {boolean}\n   *    若姓名合法则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(name) {\n    return isString(name)\n        && (name.length !== 0)\n        && (CHINESE_NAME_REGEXP.test(name) || ENGLISH_NAME_REGEXP.test(name));\n  },\n};\n\nexport default PersonNameRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否表示合法的时间戳的正则表达式。\n *\n * @author 胡海星\n * @private\n */\nconst TIMESTAMP_REGEXP = /^\\s*[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}([ ]?T?[0-2]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9](\\.[0-9]{1,3})?)?)?([ ]*[Zz])?\\s*$/;\n\n/**\n * 时间戳验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst TimestampRule = {\n  /**\n   * 测试一个字符串是否表示一个合法的时间戳。\n   *\n   * 一个合法的时间戳字符串应该符合以下格式：\n   *\n   * ```\n   * yyyy-MM-dd[ ][T][HH:mm[:ss[.S[S[S]]]]][ ][Z|z]\n   * ```\n   *\n   * 注意此函数允许字符串首位出现空格。\n   *\n   * 注意，此函数只考虑时间戳格式是否正确，不考虑时间戳的逻辑合理性（比如某个月超过了31天）。\n   *\n   * @param {any} timestamp\n   *    待测试的字符串，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串表示一个合法的时间戳则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(timestamp) {\n    if (isString(timestamp)) {\n      return TIMESTAMP_REGEXP.test(timestamp);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default TimestampRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是数字和大写字母组合成字符串。\n *\n * 这类字符串通常可以用来表示证件编号、发票号等数据。\n *\n * @author 胡海星\n * @private\n */\nconst UPPERCASE_ALPHA_NUMBER_REGEXP = /^\\s*[0-9A-Z]+\\s*$/;\n\n/**\n * 数字和大写字母组合字符串验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst UppercaseAlphaNumberRule = {\n  /**\n   * 测试一个字符串是否是数字和大写字母组合成字符串。\n   *\n   * 这类字符串通常可以用来表示证件编号、发票号等数据。\n   *\n   * @param {any} str\n   *    待测试的字符串，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是数字和大写字母组合成字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(str) {\n    if (isString(str)) {\n      return UPPERCASE_ALPHA_NUMBER_REGEXP.test(str);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default UppercaseAlphaNumberRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2025.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是大写字母和下划线组合成字符串的正则表达式。\n *\n * 这类字符串通常可以用来表示常量名、枚举值等数据。\n *\n * @author 胡海星\n * @private\n */\nconst UPPERCASE_UNDERSCORE_REGEXP = /^\\s*[A-Z_]+[A-Z0-9_]*\\s*$/;\n\n/**\n * 大写字母和下划线组合字符串验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst UppercaseUnderscoreRule = {\n  /**\n   * 测试一个字符串是否是大写字母和下划线组合成字符串。\n   *\n   * 这类字符串通常可以用来表示常量名、枚举值等数据。\n   * 规则：\n   * - 必须以大写字母或下划线开头\n   * - 只能包含大写字母、数字和下划线\n   * - 前后允许有空白字符\n   *\n   * @param {any} str\n   *    待测试的字符串，前后允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是大写字母和下划线组合成字符串则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(str) {\n    if (isString(str)) {\n      return UPPERCASE_UNDERSCORE_REGEXP.test(str);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default UppercaseUnderscoreRule;\n","/**\n * Object helper from consis (https://github.com/elysiumphase/consis).\n *\n *    - exists(thing) -> Boolean\n *    - is(Type, thing) -> Boolean\n */\n\n/**\n * @func exists\n *\n * whether the specified value is not null, undefined or NaN\n * @param  {Any} thing\n * @return {Boolean}\n */\nconst exists = function exists(thing) {\n  return !(thing === undefined || thing === null || Number.isNaN(thing));\n};\n\n/**\n * @func is\n *\n * whether the specified value is from the specified type regarding its whole prototype\n * @param  {Function} Type a type function\n * @param  {Any} thing\n * @return {Boolean}\n */\nconst is = function is(Type, thing) {\n  return exists(Type)\n  && exists(thing)\n  && (thing.constructor === Type\n  || thing instanceof Type);\n};\n\nmodule.exports = Object.freeze({\n  exists,\n  is,\n});\n","/**\n * Type casting helper from consis (https://github.com/elysiumphase/consis).\n *\n * Cast a value to a specific primitive type. If the value is\n * not of this type or can not be infer from this type, undefined is returned.\n *\n * undefined is an interesting value. When stringifying an object, an undefined property\n * disappears. Useful to respect data type schemas and where null values are not allowed.\n *\n *    - num(thing, { le, ge } = {}) -> Number or undefined\n *    - int(thing, { le, ge } = {}) -> Integer Number or undefined\n */\nconst { is, exists } = require('./object');\n\n/**\n * @func number\n *\n * cast to primitive number if possible or returns undefined\n * because Number(null) returns 0 and Number(undefined|NaN) returns NaN\n * beware to call Number.isFinite only on number values\n * NOTE: only finite values\n *\n * @param  {Any} thing a value to cast to primitive number\n * @return {Number|undefined}\n */\nconst number = function number(thing) {\n  let castNum;\n\n  if (exists(thing)) {\n    const value = thing.valueOf();\n\n    if (is(Number, value)) {\n      if (Number.isFinite(value)) {\n        castNum = value;\n      }\n    } else if (is(String, value) || is(Boolean, value)) {\n      const cast = Number(value);\n\n      if (Number.isFinite(cast)) {\n        castNum = cast;\n      }\n    }\n  }\n\n  return castNum;\n};\n\n/**\n * @func num\n *\n * cast to primitive number, with 'less or equal than'\n * or 'greater or equal than' options, or returns undefined\n * NOTE: based on \"number\" function\n *\n * @param  {Any} thing a value to cast to primitive number\n * @return {Number|undefined}\n */\nconst num = function num(thing, { ge, le } = {}) {\n  let castNum = number(thing);\n\n  if (castNum !== undefined) {\n    const lessThan = number(le);\n    const greaterThan = number(ge);\n\n    if (lessThan !== undefined && greaterThan !== undefined) {\n      if (castNum < greaterThan || castNum > lessThan) {\n        castNum = undefined;\n      }\n    } else if (lessThan !== undefined && castNum > lessThan) {\n      castNum = undefined;\n    } else if (greaterThan !== undefined && castNum < greaterThan) {\n      castNum = undefined;\n    }\n  }\n\n  return castNum;\n};\n\n/**\n * @func integer\n *\n * cast to primitive integer number if possible or returns undefined\n * NOTE: based on \"number\" function, in base 10 only\n *\n * @param  {Any} thing a value to cast to primitive integer number\n * @return {Integer Number|undefined}\n */\nconst integer = function integer(thing) {\n  // first cast to number to avoid some inconsistencies with hexa\n  const castNum = number(thing);\n  let castInt;\n\n  if (castNum !== undefined) {\n    const int = parseInt(castNum, 10);\n\n    if (!Number.isNaN(int)) {\n      castInt = int;\n    }\n  }\n\n  return castInt;\n};\n\n/**\n * @func int\n *\n * cast to primitive integer number, with 'less or equal than'\n * or 'greater or equal than' options, or returns undefined\n * NOTE: based on \"integer\" function, in base 10 only\n *\n * @param  {Any} thing a value to cast to primitive integer number\n * @return {Integer Number|undefined}\n */\nconst int = function int(thing, { le, ge } = {}) {\n  let castInt = integer(thing);\n\n  if (castInt !== undefined) {\n    const lessThan = integer(le);\n    const greaterThan = integer(ge);\n\n    if (lessThan !== undefined && greaterThan !== undefined) {\n      if (castInt < greaterThan || castInt > lessThan) {\n        castInt = undefined;\n      }\n    } else if (lessThan !== undefined && castInt > lessThan) {\n      castInt = undefined;\n    } else if (greaterThan !== undefined && castInt < greaterThan) {\n      castInt = undefined;\n    }\n  }\n\n  return castInt;\n};\n\n// exports\nmodule.exports = Object.freeze({\n  number,\n  num,\n  int,\n  integer,\n});\n","const cast = require('./cast');\nconst object = require('./object');\n\nmodule.exports = Object.freeze({\n  cast,\n  object,\n});\n","/**\n * IP validator\n *\n * - isIP(ip) -> Boolean\n * - isIPv4(ip) -> Boolean\n * - isIPv6(ip) -> Boolean\n */\nconst { object: { is } } = require('../helpers');\n\n// ip regexps, credits: https://github.com/sindresorhus/ip-regex/blob/master/index.js\nconst v4 = '(?:25[0-5]|2[0-4]\\\\d|1\\\\d\\\\d|[1-9]\\\\d|\\\\d)(?:\\\\.(?:25[0-5]|2[0-4]\\\\d|1\\\\d\\\\d|[1-9]\\\\d|\\\\d)){3}';\nconst v6seg = '[a-fA-F\\\\d]{1,4}';\nconst v6 = `\n(\n(?:${v6seg}:){7}(?:${v6seg}|:)|                                // 1:2:3:4:5:6:7::  1:2:3:4:5:6:7:8\n(?:${v6seg}:){6}(?:${v4}|:${v6seg}|:)|                         // 1:2:3:4:5:6::    1:2:3:4:5:6::8   1:2:3:4:5:6::8  1:2:3:4:5:6::1.2.3.4\n(?:${v6seg}:){5}(?::${v4}|(:${v6seg}){1,2}|:)|                 // 1:2:3:4:5::      1:2:3:4:5::7:8   1:2:3:4:5::8    1:2:3:4:5::7:1.2.3.4\n(?:${v6seg}:){4}(?:(:${v6seg}){0,1}:${v4}|(:${v6seg}){1,3}|:)| // 1:2:3:4::        1:2:3:4::6:7:8   1:2:3:4::8      1:2:3:4::6:7:1.2.3.4\n(?:${v6seg}:){3}(?:(:${v6seg}){0,2}:${v4}|(:${v6seg}){1,4}|:)| // 1:2:3::          1:2:3::5:6:7:8   1:2:3::8        1:2:3::5:6:7:1.2.3.4\n(?:${v6seg}:){2}(?:(:${v6seg}){0,3}:${v4}|(:${v6seg}){1,5}|:)| // 1:2::            1:2::4:5:6:7:8   1:2::8          1:2::4:5:6:7:1.2.3.4\n(?:${v6seg}:){1}(?:(:${v6seg}){0,4}:${v4}|(:${v6seg}){1,6}|:)| // 1::              1::3:4:5:6:7:8   1::8            1::3:4:5:6:7:1.2.3.4\n(?::((?::${v6seg}){0,5}:${v4}|(?::${v6seg}){1,7}|:))           // ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8  ::8             ::1.2.3.4\n)(%[0-9a-zA-Z]{1,})?                                           // %eth0            %1\n`.replace(/\\s*\\/\\/.*$/gm, '').replace(/\\n/g, '').trim();\n\n/**\n * @func isIP\n *\n * Test a string is a valid IP.\n *\n * @param  {String} ip\n * @return {Boolean}\n */\nconst isIP = function isIP(ip) {\n  if (!is(String, ip)) {\n    return false;\n  }\n\n  return new RegExp(`(?:^${v4}$)|(?:^${v6}$)`).test(ip);\n};\n\n/**\n * @func isIPv4\n *\n * Test a string is a valid IPv4.\n *\n * @param  {String} ip\n * @return {Boolean}\n */\nconst isIPv4 = function isIPv4(ip) {\n  if (!is(String, ip)) {\n    return false;\n  }\n\n  return new RegExp(`^${v4}$`).test(ip);\n};\n\n/**\n * @func isIPv6\n *\n * Test a string is a valid IPv6.\n *\n * @param  {String} ip\n * @return {Boolean}\n */\nconst isIPv6 = function isIPv6(ip) {\n  if (!is(String, ip)) {\n    return false;\n  }\n\n  return new RegExp(`^${v6}$`).test(ip);\n};\n\nmodule.exports = Object.freeze({\n  isIP,\n  isIPv4,\n  isIPv6,\n});\n","/**\n * punycode and punydecode\n *\n * - punycode(domain) -> String\n * - punydecode(domain) -> String\n */\nconst { domainToASCII, domainToUnicode } = require('url');\nconst { isIPv6 } = require('../ip');\nconst { object: { is } } = require('../helpers');\n\n/**\n * @func punycode\n *\n * Returns the Punycode ASCII serialization of the domain.\n * If domain is an invalid domain, the empty string is returned.\n *\n * Note:\n * - native function url.domainToASCII does not support IPv6 only IPv4;\n * - native function url.domainToASCII throws if no domain is provided or returns\n *   `null`, `undefined`, `nan` for `null`, `undefined` or `NaN` values which is\n *   not what to be expected.\n *\n * @param  {String} domain\n * @return {String}\n */\nconst punycode = function punycode(domain) {\n  if (isIPv6(domain)) {\n    return domain;\n  }\n\n  return is(String, domain) ? domainToASCII(domain) : '';\n};\n\n/**\n * @func punydecode\n *\n * Returns the Unicode serialization of the domain.\n * If domain is an invalid domain, the empty string is returned.\n *\n * Note:\n * - native function url.domainToUnicode does not support IPv6 only IPv4;\n * - native function url.domainToUnicode throws if no domain is provided or returns\n *   `null`, `undefined`, `nan` for `null`, `undefined` or `NaN` values which is\n *   not what to be expected.\n *\n * @param  {String} domain\n * @return {String}\n */\nconst punydecode = function punydecode(domain) {\n  if (isIPv6(domain)) {\n    return domain;\n  }\n\n  return is(String, domain) ? domainToUnicode(domain) : '';\n};\n\nmodule.exports = Object.freeze({\n  punycode,\n  punydecode,\n});\n","/**\n * config module\n */\n\nconst maxLengthURL = 2048;\nconst minPortInteger = 0;\nconst maxPortInteger = 65535;\n\nmodule.exports = Object.freeze({\n  maxLengthURL,\n  minPortInteger,\n  maxPortInteger,\n});\n","/**\n * parser\n *\n * - hostToURI(host) -> String\n * - recomposeURI({ scheme, userinfo, host port, path, query, fragment } = {}) -> String\n * - parseURI(uri) -> Object\n */\nconst { punycode, punydecode } = require('../punycode');\nconst { isIPv6 } = require('../ip');\nconst { cast: { int }, object: { exists, is } } = require('../helpers');\nconst { minPortInteger, maxPortInteger } = require('../config');\n\n// regexp parsing uri from RFC-3986 https://tools.ietf.org/html/rfc3986#appendix-B\n// adding ?: to disable capturing some groups\nconst uriRegexp = /^(?:([^:/?#]+):)?(?:\\/\\/([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?/;\n\n// detect IPv6 (regex based on RFC-3986 one): [ipv6]:port\nconst ipv6Regexp = /^(?:\\[([^\\]]+)\\]:?)([0-9]+)?$/;\n\n/**\n * @func hostToURI\n *\n * Format host with special [] for IPv6. The empty string is returned if host\n * is not a string.\n *\n * @param  {String} host\n * @return {String}\n */\nconst hostToURI = function hostToURI(host) {\n  if (!is(String, host)) {\n    return '';\n  }\n\n  return isIPv6(host) ? `[${host}]` : host;\n};\n\n/**\n * @func recomposeURI\n *\n * Recompose an URI from its components with basic URI checking.\n *\n * The empty string is returned if unable to recompose the URI.\n *\n * Rules:\n * 1. scheme is required and must be at least 1 character;\n * 2. path is required and can be empty;\n * 3. if host is present path must be empty or start with /;\n * 4. if host is not present path must not start with //;\n * 5. host, if any, must be at least 3 characters;\n * 6. userinfo will be ignored if empty;\n * 7. port will be ignored if empty or not an integer;\n * 8. query will be ignored if empty;\n * 9. fragment will be ignored if empty.\n *\n * Support:\n * - IPv4 and IPv6.\n *\n * Note:\n * / is added to any URI with a host and an empty path.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986.\n *\n * @param {Object} components:\n * @param {String} scheme\n * @param {String} userinfo\n * @param {String} host\n * @param {Integer} port\n * @param {String} path\n * @param {String} query\n * @param {String} fragment\n * @return {String}\n */\nconst recomposeURI = function recomposeURI(components) {\n  const cpts = components || {};\n  const defaultReturnValue = '';\n\n  if (!(is(String, cpts.scheme) && cpts.scheme.length > 0) || !is(String, cpts.path)) {\n    return defaultReturnValue;\n  }\n\n  let uri = cpts.scheme;\n\n  if (is(String, cpts.host)) {\n    if (!(cpts.path === '' || cpts.path.startsWith('/'))) {\n      return defaultReturnValue;\n    }\n\n    if (cpts.host.length <= 2) {\n      return defaultReturnValue;\n    }\n\n    uri += '://';\n\n    if (is(String, cpts.userinfo) && cpts.userinfo.length > 0) {\n      uri += `${cpts.userinfo}@`;\n    }\n\n    uri += hostToURI(cpts.host);\n\n    if (exists(cpts.port)\n      && int(cpts.port, { ge: minPortInteger, le: maxPortInteger }) !== undefined) {\n      uri += `:${cpts.port}`;\n    }\n  } else {\n    if (cpts.path.startsWith('//')) {\n      return defaultReturnValue;\n    }\n\n    uri += ':';\n  }\n\n  // add / if any host but path is empty and query/fragment is not\n  if (cpts.path === '' && is(String, cpts.host)) {\n    uri += '/';\n  } else {\n    uri += cpts.path;\n  }\n\n  if (is(String, cpts.query) && cpts.query.length > 0) {\n    uri += `?${cpts.query}`;\n  }\n\n  if (is(String, cpts.fragment) && cpts.fragment.length > 0) {\n    uri += `#${cpts.fragment}`;\n  }\n\n  return uri;\n};\n\n/**\n * @func parseURI\n *\n * Parse a string to get URI components.\n *\n * Support:\n * - IPv4 and IPv6 hosts;\n * - Internationalized Domain Name (IDN).\n *\n * Note:\n * - RegExp from RFC-3986 https://tools.ietf.org/html/rfc3986#appendix-B;\n * - scheme and host strings will always be put in lowercase once parsed,\n *   as specified in RFC-3986;\n * - authority and its components will be put at null values if authority\n *   parsed is missing or empty.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986.\n *\n * @param  {String} uri\n * @return {Object}\n */\nconst parseURI = function parseURI(uri) {\n  const parsed = {\n    scheme: null,\n    authority: null,\n    authorityPunydecoded: null,\n    userinfo: null,\n    host: null,\n    hostPunydecoded: null,\n    port: null,\n    path: null,\n    pathqf: null,\n    query: null,\n    fragment: null,\n    href: null,\n  };\n\n  // return an object with null attributes if uri is not a string or an empty string\n  if (!(is(String, uri) && uri.length > 0)) {\n    return parsed;\n  }\n\n  // extract uri components from RegExp\n  const [,\n    scheme,\n    authorityParsed,\n    path,\n    queryParsed,\n    fragmentParsed,\n  ] = uri.match(uriRegexp);\n\n  // scheme is required and must be a not empty string or this is not an uri\n  if (!(is(String, scheme) && scheme.length > 0)) {\n    return parsed;\n  }\n\n  let authority = null;\n  let authorityPunydecoded = null;\n  let userinfo = null;\n  let host = null;\n  let hostPunydecoded = null;\n  let port = null;\n\n  // parse authority components, if any\n  if (is(String, authorityParsed)) {\n    let hostAndPort = null;\n\n    [userinfo = null, hostAndPort = null] = authorityParsed.split('@');\n\n    // authority had no '@' and no userinfo can be extracted\n    if (!exists(hostAndPort) && exists(userinfo)) {\n      hostAndPort = userinfo;\n      userinfo = null;\n    }\n\n    // try to extract host and port only if any\n    if (is(String, hostAndPort)) {\n      // detect IPv6 here first\n      const ipv6Match = hostAndPort.match(ipv6Regexp);\n      let hostParsed;\n      let portToCast;\n\n      // if an array then it's constructed as an ipv6\n      if (is(Array, ipv6Match)) {\n        [, hostParsed = null, portToCast = null] = ipv6Match;\n      } else {\n        // not an ipv6\n        [hostParsed = null, portToCast = null] = hostAndPort.split(':');\n      }\n\n      // hostPunydecoded should be the host in Unicode, host its Punycode value\n      const hostLowerCase = is(String, hostParsed) ? hostParsed.toLowerCase() : null;\n      const toASCII = punycode(hostLowerCase);\n      const toUnicode = punydecode(hostLowerCase);\n\n      // host parsed was in Unicode\n      if (hostLowerCase !== toASCII) {\n        host = toASCII;\n        hostPunydecoded = hostLowerCase;\n      } else if (hostLowerCase !== toUnicode) {\n        // host parsed was punycoded\n        host = hostLowerCase;\n        hostPunydecoded = toUnicode;\n      } else {\n        host = hostLowerCase;\n        hostPunydecoded = hostLowerCase;\n      }\n\n      // we only keep original authority/host parsed so using parseURI allows to\n      // see issues with provided host\n      if (host === '' || hostPunydecoded === '') {\n        host = null;\n      }\n\n      // necessary to handle possible port errors when checking uri\n      // port is a valid integer or we keep its initial value to be aware of the error\n      // here we also don't check wrong range for the same reason\n      port = int(portToCast) || portToCast;\n\n      // recompose authority with punycode ASCII and Unicode serialization of the host\n      // userinfo@host:port\n      // we still want to know the original host and authority provided\n      // to check possible uri errors: a null host with a hostPunydecoded filled\n      // means uri parsed had an invalid host name\n      if (exists(hostPunydecoded)) {\n        authorityPunydecoded = '';\n\n        // recompose authorityPunydecoded, order matters\n        if (exists(userinfo)) {\n          authorityPunydecoded += `${userinfo}@`;\n        }\n\n        authorityPunydecoded += hostToURI(hostPunydecoded);\n\n        if (exists(port)) {\n          authorityPunydecoded += `:${port}`;\n        }\n      }\n\n      // as punycode returns '' for invalid host, we already know if the host is basically valid\n      // and there cannot be userinfo or a port with a null host parsed\n      if (exists(host)) {\n        authority = '';\n\n        // recompose authority, order matters\n        if (exists(userinfo)) {\n          authority += `${userinfo}@`;\n        }\n\n        authority += hostToURI(host);\n\n        if (exists(port)) {\n          authority += `:${port}`;\n        }\n      } else {\n        userinfo = null;\n        port = null;\n      }\n    }\n  }\n\n  // format query and fragment\n  const query = is(String, queryParsed) && queryParsed.length > 0 ? queryParsed : null;\n  const fragment = is(String, fragmentParsed) && fragmentParsed.length > 0 ? fragmentParsed : null;\n\n  // pathqf: recompose path + query + fragment if any\n  // using valueOf to avoid potential String objects mutation with parsed.path\n  parsed.pathqf = is(String, path) ? path.valueOf() : null;\n\n  if (is(String, parsed.pathqf)) {\n    if (is(String, query)) {\n      parsed.pathqf += `?${query}`;\n    }\n\n    if (is(String, fragment)) {\n      parsed.pathqf += `#${fragment}`;\n    }\n  }\n\n  // we checked scheme is a string\n  parsed.scheme = scheme.toLowerCase();\n  parsed.authority = authority;\n  parsed.authorityPunydecoded = authorityPunydecoded;\n  parsed.userinfo = userinfo;\n  parsed.host = host;\n  parsed.hostPunydecoded = hostPunydecoded;\n  parsed.port = port;\n  parsed.path = path;\n  parsed.query = query;\n  parsed.fragment = fragment;\n\n  const recomposedURI = recomposeURI({\n    scheme: parsed.scheme,\n    userinfo: parsed.userinfo,\n    host: parsed.host,\n    port: parsed.port,\n    path: parsed.path,\n    query: parsed.query,\n    fragment: parsed.fragment,\n  });\n\n  parsed.href = recomposedURI !== '' ? recomposedURI : null;\n\n  return parsed;\n};\n\nmodule.exports = Object.freeze({\n  hostToURI,\n  recomposeURI,\n  parseURI,\n});\n","/**\n * chars checkers\n *\n * - isSchemeChar(char, { start } = {}) -> Boolean\n * - isUserinfoChar(char, encode) -> Boolean\n * - isSitemapUserinfoChar(char, encode) -> Boolean\n * - isDomainChar(char, { start, end } = {}) -> Boolean\n * - isPathChar(char, encode) -> Boolean\n * - isSitemapPathChar(char, encode) -> Boolean\n * - isQueryOrFragmentChar(char, encode) -> Boolean\n * - isSitemapQueryOrFragmentChar(char, encode) -> Boolean\n * - isPercentEncodingChar(char) -> Boolean\n */\nconst { object: { is } } = require('../helpers');\n\n/**\n * @func isSchemeChar\n *\n * Check scheme legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.1.\n *\n * Scheme must start with a letter and be followed by any combination of\n * letters, digits, plus (\"+\"), period (\".\"), or hyphen (\"-\").\n *\n * Letters must be in lowercase.\n *\n * 43             +\n * 45             -\n * 46             .\n * 48 to 57       0-9\n * 97 to 122      a-z\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isSchemeChar = function isSchemeChar(char, { start } = {}) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  const code = char.charCodeAt();\n\n  if (start) {\n    return code >= 97 && code <= 122;\n  }\n\n  return (code >= 48 && code <= 57)\n    || (code >= 97 && code <= 122)\n    || code === 43\n    || code === 45\n    || code === 46;\n};\n\n/**\n * @func isUserinfoChar\n *\n * Check userinfo legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.2.1.\n *\n * 33             !\n * 36             $\n * 37             % (not allowed when encoding)\n * 38 to 46       &'()*+,-.\n * 48 to 57       0-9\n * 58             :\n * 59             ;\n * 61             =\n * 65 to 90       A-Z\n * 95             _\n * 97 to 122      a-z\n * 126            ~\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isUserinfoChar = function isUserinfoChar(char, encode) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  // false by default\n  const encoding = encode === true;\n  const code = char.charCodeAt();\n\n  // % is not allowed when encoding\n  if (code === 37) {\n    return !encoding;\n  }\n\n  return (code >= 38 && code <= 46)\n    || (code >= 48 && code <= 57)\n    || (code >= 65 && code <= 90)\n    || (code >= 97 && code <= 122)\n    || code === 33\n    || code === 36\n    || code === 58\n    || code === 59\n    || code === 61\n    || code === 95\n    || code === 126;\n};\n\n/**\n * @func isSitemapUserinfoChar\n *\n * Check sitemap userinfo legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.2.1;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * Removed AZ ' and *\n *\n * 33             !\n * 36             $\n * 37             % (not allowed when encoding)\n * 38             & (allowed but must be a proper escape code)\n * 40 to 41       ()\n * 43 to 46       +,-.\n * 48 to 57       0-9\n * 58             :\n * 59             ;\n * 61             =\n * 95             _\n * 97 to 122      a-z\n * 126            ~\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isSitemapUserinfoChar = function isSitemapUserinfoChar(char, encode) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  // false by default\n  const encoding = encode === true;\n  const code = char.charCodeAt();\n\n  // % is not allowed when encoding\n  if (code === 37) {\n    return !encoding;\n  }\n\n  return (code >= 40 && code <= 41)\n    || (code >= 43 && code <= 46)\n    || (code >= 48 && code <= 57)\n    || (code >= 97 && code <= 122)\n    || code === 33\n    || code === 36\n    || code === 38\n    || code === 58\n    || code === 59\n    || code === 61\n    || code === 95\n    || code === 126;\n};\n\n/**\n * @func isDomainChar\n *\n * Check domain legal codes according to\n * - RFC-1034 https://www.ietf.org/rfc/rfc1034.txt.\n *\n * 45             -\n * 48 to 57       0-9\n * 97 to 122      a-z\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isDomainChar = function isDomainChar(char, { start, end } = {}) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  const code = char.charCodeAt();\n\n  if ((start === true || end === true) && code === 45) {\n    return false;\n  }\n\n  return (code >= 48 && code <= 57)\n    || (code >= 97 && code <= 122)\n    || code === 45;\n};\n\n/**\n * @func isPathChar\n *\n * Check path legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.3.\n *\n * 33             !\n * 36 to 59       $%&'()*+,-./0-9:;\n * 61             =\n * 64 to 90       @A-Z\n * 95             _\n * 97 to 122      a-z\n * 126            ~\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isPathChar = function isPathChar(char, encode) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  // false by default\n  const encoding = encode === true;\n  const code = char.charCodeAt();\n\n  // % is not allowed when encoding\n  if (code === 37) {\n    return !encoding;\n  }\n\n  return (code >= 36 && code <= 59)\n    || (code >= 64 && code <= 90)\n    || (code >= 97 && code <= 122)\n    || code === 33\n    || code === 61\n    || code === 95\n    || code === 126;\n};\n\n/**\n * @func isSitemapPathChar\n *\n * Check path legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.3.\n *\n * Removed AZ ' and *\n *\n * 33             !\n * 36 to 38       $%& (& allowed but must be a proper escape code)\n * 40 to 41       ()\n * 43 to 59       +,-./0-9:;\n * 61             =\n * 64             @\n * 95             _\n * 97 to 122      a-z\n * 126            ~\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isSitemapPathChar = function isSitemapPathChar(char, encode) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  // false by default\n  const encoding = encode === true;\n  const code = char.charCodeAt();\n\n  // % is not allowed when encoding\n  if (code === 37) {\n    return !encoding;\n  }\n\n  return (code >= 36 && code <= 38)\n    || (code >= 40 && code <= 41)\n    || (code >= 43 && code <= 59)\n    || (code >= 97 && code <= 122)\n    || code === 33\n    || code === 61\n    || code === 64\n    || code === 95\n    || code === 126;\n};\n\n/**\n * @func isQueryOrFragmentChar\n *\n * Check query/fragment legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.4;\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.5.\n *\n * path char\n * 63             ?\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isQueryOrFragmentChar = function isQueryOrFragmentChar(char, encode) {\n  if (isPathChar(char, encode)) {\n    return true;\n  }\n\n  return is(String, char) && char.charCodeAt() === 63;\n};\n\n/**\n * @func isSitemapQueryOrFragmentChar\n *\n * Check query/fragment legal ascii codes according to\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.4;\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.5.\n *\n * sitemap path char\n * 63             ?\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isSitemapQueryOrFragmentChar = function isSitemapQueryOrFragmentChar(char, encode) {\n  if (isSitemapPathChar(char, encode)) {\n    return true;\n  }\n\n  return is(String, char) && char.charCodeAt() === 63;\n};\n\n/**\n * @func isPercentEncodingChar\n *\n * Check percent encoding legal ascii codes according to RFC-3986 https://tools.ietf.org/html/rfc3986#section-2.1.\n *\n * 48 to 57       0-9\n * 65 to 70       A-F\n *\n * @param  {String} char\n * @return {Boolean}\n */\nconst isPercentEncodingChar = function isPercentEncodingChar(char) {\n  if (!is(String, char)) {\n    return false;\n  }\n\n  const code = char.charCodeAt();\n\n  return (code >= 48 && code <= 57)\n    || (code >= 65 && code <= 70);\n};\n\nmodule.exports = Object.freeze({\n  isSchemeChar,\n  isUserinfoChar,\n  isSitemapUserinfoChar,\n  isDomainChar,\n  isPathChar,\n  isSitemapPathChar,\n  isQueryOrFragmentChar,\n  isSitemapQueryOrFragmentChar,\n  isPercentEncodingChar,\n});\n","/**\n * domain\n *\n * - isDomainLabel(label) -> Boolean\n * - isDomain(name) -> Boolean\n */\nconst { punycode } = require('../punycode');\nconst { isDomainChar } = require('../checkers/chars');\nconst { object: { is } } = require('../helpers');\n\n/**\n * @func isDomainLabel\n *\n * Test a label is a valid domain label according to RFC-1034.\n *\n * \"Note that while upper and lower case letters are allowed in domain names,\n * no significance is attached to the case.  That is, two names with the same\n * spelling but different case are to be treated as if identical.\"\n *\n * By convention uppercased domain label will be considered invalid.\n *\n * Rules:\n * 1. \"Labels must be 63 characters or less.\";\n * 2. can be minimum one character;\n * 3. must only use lowercase letters, digits or hyphens;\n * 4. must not start or end with a hyphen;\n * 5. must not have consecutive hyphens;\n * 6. can start or end with a digit.\n *\n * Based on:\n * - RFC-1034 https://www.ietf.org/rfc/rfc1034.txt.\n *\n * @param  {String} label\n * @return {Boolean}\n */\nconst isDomainLabel = function isDomainLabel(label) {\n  // 1) and 2) rules\n  if (!is(String, label)) {\n    return false;\n  }\n\n  const len = label.length;\n\n  if (len < 1 || len > 63) {\n    return false;\n  }\n\n  // check each character\n  for (let i = 0; i < len; i += 1) {\n    if (!isDomainChar(label[i], { start: (i === 0), end: (i === len - 1) })) {\n      return false;\n    }\n\n    // check consecutive hyphens\n    if (label[i] === '-' && (i + 1) < len && label[i + 1] === '-') {\n      return false;\n    }\n  }\n\n  return true;\n};\n\n/**\n * @func isDomain\n *\n * Test a name is a valid domain according to RFC-1034.\n *\n * Supports Fully-Qualified Domain Name (FQDN) and Internationalized Domain Name (IDN).\n *\n * Rules:\n * 1. labels rules apply;\n * 2. \"[...] the total number of octets that represent a domain name\n *   (i.e., the sum of all label octets and label lengths) is limited to 255.\";\n * 3. labels are separated by dots (\".\");\n * 4. must have at least one extension label;\n * 5. must have labels different from each other;\n * 6. last label can be empty (root label \".\");\n * 7. labels can start with `xn--` for IDNs if the ASCII serialization is a valid Punycode;\n * 8. check also Punycodes as ॐ gives xn--'-6xd where ' is not valid.\n *\n * Based on:\n * - RFC-1034 https://www.ietf.org/rfc/rfc1034.txt.\n *\n * @param  {String} name\n * @return {Boolean}\n */\nconst isDomain = function isDomain(name) {\n  if (!is(String, name)) {\n    return false;\n  }\n\n  // if a domain has an invalid label, its punycode value will be ''\n  // eg. 'a.xn--hf.com'\n  const domain = punycode(name);\n\n  if (domain === 'localhost') {\n    return true;\n  }\n\n  const len = domain.length;\n\n  // \"To simplify implementations, the total number of octets that represent a\n  // domain name (i.e., the sum of all label octets and label lengths) is\n  // limited to 255.\"\n  if (len <= 0 || len > 255) {\n    return false;\n  }\n\n  // \"[...] the labels are separated by dots (\".\"). Since a complete\n  // domain name ends with the root label, this leads to a printed form which\n  // ends in a dot.\"\n  // google.com./ is valid\n  const labels = domain.split('.');\n  const labelsLen = labels.length;\n\n  // no label extension\n  if (labelsLen <= 1) {\n    return false;\n  }\n\n  // labels:\n  // a) must be different from each other\n  // b) last label can be empty (root label '.')\n  // c) label can start with 'xn--' for IDNs if the Punycode is valid\n  const occurences = {};\n\n  for (let i = 0; i < labelsLen; i += 1) {\n    // ignore root label if ''\n    if (!(i === labelsLen - 1 && labels[i] === '')) {\n      const label = labels[i].startsWith('xn--') ? labels[i].slice(4) : labels[i];\n\n      // also check punycoded label as i.e. ॐ gives xn--'-6xd where ' is not valid\n      if (!isDomainLabel(label)) {\n        return false;\n      }\n\n      occurences[labels[i]] = (occurences[labels[i]] || 0) + 1;\n\n      if (occurences[labels[i]] > 1) {\n        return false;\n      }\n    }\n  }\n\n  return true;\n};\n\nmodule.exports = Object.freeze({\n  isDomainLabel,\n  isDomain,\n});\n","/**\n * sitemap\n *\n * Percent encodings, entities and escape codes.\n *\n * - specialChars\n * - specialCharsKeys\n * - pencodings\n * - pencodingsKeys\n * - entities\n * - entitiesKeys\n * - escapeCodes\n * - escapeCodesKeys\n * - escapeCodesKeysLen\n */\n\n// special chars and their percent encodings\nconst specialChars = {\n  '*': '%2A',\n};\n\n// special chars keys\nconst specialCharsKeys = Object.keys(specialChars);\n\n// inversed special chars (percent encodings)\nconst pencodings = {};\nspecialCharsKeys.forEach((char) => {\n  pencodings[specialChars[char]] = char;\n});\n\nconst pencodingsKeys = Object.keys(pencodings);\n\n// sitemap entities to be escaped in URLs\nconst entities = {\n  '&': '&amp;',\n  '\\'': '&apos;',\n};\n\n// entities keys\nconst entitiesKeys = Object.keys(entities);\n\n// inversed entities keys (escape codes)\nconst escapeCodes = {};\nentitiesKeys.forEach((entity) => {\n  escapeCodes[entities[entity]] = entity;\n});\n\n// escape codes keys and length\nconst escapeCodesKeys = Object.keys(escapeCodes);\nconst escapeCodesKeysLen = escapeCodesKeys.length;\n\nmodule.exports = Object.freeze({\n  specialChars,\n  specialCharsKeys,\n  pencodings,\n  pencodingsKeys,\n  entities,\n  entitiesKeys,\n  escapeCodes,\n  escapeCodesKeys,\n  escapeCodesKeysLen,\n});\n","/**\n * checkers\n *\n * - checkPercentEncoding(string, index, stringLen) -> Number throws URIError\n * - checkSitemapEncoding(string, index, stringLen) -> Number throws URIError\n * - checkComponent({ type, string, sitemap } = {}) -> Boolean throws URIError\n * - checkSchemeChars(scheme, len) -> Boolean throws URIError\n * - checkLowercase(uri) -> Boolean throws URIError\n * - checkURISyntax(uri) -> Object throws URIError\n * - checkURI(uri, { sitemap } = {}) -> Object throws URIError\n * - checkHttpURL(uri, { https, web, sitemap } = {}) -> Object throws URIError\n * - checkHttpsURL(uri) -> Object throws URIError\n * - checkHttpSitemapURL(uri) -> Object throws URIError\n * - checkHttpsSitemapURL(uri) -> Object throws URIError\n * - checkWebURL(uri) -> Object throws URIError\n * - checkSitemapURL(uri) -> Object throws URIError\n */\nconst { maxLengthURL, minPortInteger, maxPortInteger } = require('../config');\nconst { parseURI } = require('../parser');\nconst { isDomain } = require('../domain');\nconst { cast: { int }, object: { exists, is } } = require('../helpers');\nconst { isIP } = require('../ip');\nconst {\n  escapeCodesKeys,\n  escapeCodesKeysLen,\n} = require('../sitemap');\nconst {\n  isSchemeChar,\n  isUserinfoChar,\n  isPathChar,\n  isQueryOrFragmentChar,\n  isSitemapUserinfoChar,\n  isSitemapPathChar,\n  isSitemapQueryOrFragmentChar,\n  isPercentEncodingChar,\n} = require('./chars');\n\n/**\n * @func checkPercentEncoding\n *\n * Check a % char found from a string at a specific index has a valid\n * percent encoding following this char.\n *\n * @param  {String} string\n * @param  {Number} index\n * @param  {Number} stringLen\n * @return {Number} the offset where to check next\n * @throws {URIError}\n */\nconst checkPercentEncoding = function checkPercentEncoding(string, index, stringLen) {\n  if (!is(String, string)) {\n    const error = new URIError('a string is required when checking for percent encoding');\n    error.code = 'URI_INVALID_PERCENT_ENCODING';\n    throw error;\n  }\n\n  const len = is(Number, stringLen) && stringLen >= 0 ? stringLen : string.length;\n  const i = is(Number, index) && index < len ? index : 0;\n  let offset = 0;\n\n  if (len > 0 && string[i] === '%') {\n    // should be %[A-F0-9]{2}(%[A-F0-9]{2}){0,1}\n    // example: %20 or %C3%BC\n    if (i + 2 < len) {\n      if (!isPercentEncodingChar(string[i + 1])) {\n        const error = new URIError(`invalid percent encoding char '${string[i + 1]}'`);\n        error.code = 'URI_INVALID_PERCENT_ENCODING';\n        throw error;\n      } else if (!isPercentEncodingChar(string[i + 2])) {\n        const error = new URIError(`invalid percent encoding char '${string[i + 2]}'`);\n        error.code = 'URI_INVALID_PERCENT_ENCODING';\n        throw error;\n      } else {\n        offset = 2;\n      }\n    } else {\n      const error = new URIError('incomplete percent encoding found');\n      error.code = 'URI_INVALID_PERCENT_ENCODING';\n      throw error;\n    }\n  }\n\n  return offset;\n};\n\n/**\n * @func checkSitemapEncoding\n *\n * Check an entity in an URL at a specific index has a valid\n * sitemap escape encoding following this char.\n *\n * @param  {String} string\n * @param  {Number} index\n * @param  {Number} stringLen\n * @return {Number} the offset where to check next\n * @throws {URIError}\n */\nconst checkSitemapEncoding = function checkSitemapEncoding(string, index, stringLen) {\n  if (!is(String, string)) {\n    const error = new URIError('a string is required when checking for sitemap encoding');\n    error.code = 'URI_INVALID_SITEMAP_ENCODING';\n    throw error;\n  }\n\n  const len = is(Number, stringLen) && stringLen >= 0 ? stringLen : string.length;\n  const i = is(Number, index) && index < len ? index : 0;\n  let offset = 0;\n\n  // check each &... is an expected escape code\n  if (len > 0 && string[i] === '&') {\n    let escapeOffset;\n\n    for (let j = 0; j < escapeCodesKeysLen; j += 1) {\n      const code = escapeCodesKeys[j];\n      const codeLen = code.length;\n\n      if (i + codeLen <= len && code === string.substring(i, i + codeLen)) {\n        escapeOffset = codeLen - 1;\n        break;\n      }\n    }\n\n    if (!exists(escapeOffset)) {\n      const error = new URIError(`entity '${string[i]}' is not properly escaped`);\n      error.code = 'URI_INVALID_SITEMAP_ENCODING';\n      throw error;\n    } else {\n      offset = escapeOffset;\n    }\n  }\n\n  return offset;\n};\n\n/**\n * @func checkComponent\n *\n * Check a string has valid characters regarding userinfo, path, query,\n * or fragment URI component type.\n *\n * NOTE:\n * - check only if string is present as these components are not required;\n * - path is required but is at least empty,\n *   regexp assures that and checkURISyntax verifies that too.\n *\n * @param  {String} type\n * @param  {String} string\n * @param  {Boolean} sitemap\n * @return {Boolean}\n * @throws {URIError}\n */\nconst checkComponent = function checkComponent({ type, string, sitemap } = {}) {\n  if (!['userinfo', 'path', 'query', 'fragment'].includes(type)) {\n    const error = new URIError(`unable to check pathqf, got '${type}' component to check`);\n    error.code = 'URI_INVALID_CHECKING_COMPONENT';\n    throw error;\n  }\n\n  // path is always at least empty here, userinfo, query and fragment are not required\n  if ((type === 'path' && (!exists(string) || string === '')) || !exists(string)) {\n    return true;\n  }\n\n  const len = string.length;\n  const checkSitemap = sitemap === true;\n  let checkCharFunc;\n\n  switch (type) {\n    case 'userinfo':\n      checkCharFunc = checkSitemap ? isSitemapUserinfoChar : isUserinfoChar;\n      break;\n    case 'path':\n      checkCharFunc = checkSitemap ? isSitemapPathChar : isPathChar;\n      break;\n    case 'query':\n    case 'fragment':\n      checkCharFunc = checkSitemap ? isSitemapQueryOrFragmentChar : isQueryOrFragmentChar;\n      break;\n    default:\n  }\n\n  for (let i = 0; i < len; i += 1) {\n    // check character is valid\n    if (!checkCharFunc(string[i])) {\n      const error = new URIError(`invalid ${type} char '${string[i]}'`);\n      error.code = `URI_INVALID_${type.toUpperCase()}_CHAR`;\n      throw error;\n    }\n\n    // check percent encodings\n    // increase i if a percent encoding has been found (0 if not)\n    i += checkPercentEncoding(string, i, len);\n\n    // check sitemap encodings\n    if (checkSitemap) {\n      // increase i if a sitemap encoding has been found (0 if not)\n      i += checkSitemapEncoding(string, i, len);\n    }\n  }\n\n  return true;\n};\n\n/**\n * @func checkSchemeChars\n *\n * Check scheme characters are valid.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986#section-3.1.\n *\n * @param {String} scheme\n * @return {Boolean}\n */\nconst checkSchemeChars = function checkSchemeChars(scheme, len) {\n  if (!is(String, scheme)) {\n    const error = new URIError('scheme must be a string');\n    error.code = 'URI_INVALID_SCHEME';\n    throw error;\n  }\n\n  const schemeLen = is(Number, len) && len > 0 ? len : scheme.length;\n\n  if (schemeLen <= 0) {\n    const error = new URIError('scheme cannot be empty');\n    error.code = 'URI_INVALID_SCHEME';\n    throw error;\n  }\n\n  for (let i = 0; i < schemeLen; i += 1) {\n    if (!isSchemeChar(scheme[i], { start: (i === 0) })) {\n      const error = new URIError(`invalid scheme char '${scheme[i]}'`);\n      error.code = 'URI_INVALID_SCHEME_CHAR';\n      throw error;\n    }\n  }\n\n  return true;\n};\n\n/**\n * @func checkLowercase\n *\n * Check a string has not any uppercase characters.\n *\n * @param  {String} uri\n * @return {Boolean}\n * @throws {URIError}\n */\nconst checkLowercase = function checkLowercase(uri) {\n  if (!is(String, uri)) {\n    const error = new URIError('uri must be a string');\n    error.code = 'URI_INVALID_TYPE';\n    throw error;\n  }\n\n  if (uri.toLowerCase() !== uri) {\n    const error = new URIError('uri cannot contain any uppercase characters');\n    error.code = 'URI_INVALID_CHAR';\n    throw error;\n  }\n\n  return true;\n};\n\n/**\n * @func checkURISyntax\n *\n * Check an URI syntax is valid according to RFC-3986.\n *\n * Beware this function does not fully check if an URI is valid.\n * Rules:\n * 1. scheme is required and cannot be empty;\n * 2. path is required and can be empty;\n * 3. if authority is present path must be empty or start with /;\n * 4. if authority is not present path must not start with //;\n * 5. check for inconsistent authority (original vs parsed)\n *    which would mean host parsed was actually wrong.\n *\n * @param  {String} uri\n * @return {Object}\n * @throws {URIError}\n */\nconst checkURISyntax = function checkURISyntax(uri) {\n  if (!is(String, uri)) {\n    const error = new URIError('uri must be a string');\n    error.code = 'URI_INVALID_TYPE';\n    throw error;\n  }\n\n  // parse uri and check scheme, authority, pathname and slashes\n  // NOTE: parseURI automatically convert host to punycode\n  // example:\n  const {\n    scheme,\n    authority,\n    authorityPunydecoded,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    pathqf,\n    query,\n    fragment,\n    href,\n  } = parseURI(uri);\n  const schemeLen = is(String, scheme) ? scheme.length : 0;\n\n  // scheme (required)\n  if (!is(String, scheme)) {\n    const error = new URIError('uri scheme is required');\n    error.code = 'URI_MISSING_SCHEME';\n    throw error;\n  } else if (schemeLen <= 0) {\n    const error = new URIError('uri scheme must not be empty');\n    error.code = 'URI_EMPTY_SCHEME';\n    throw error;\n  }\n\n  // path (required), can be an empty string\n  if (!is(String, path)) {\n    const error = new URIError('uri path is required');\n    error.code = 'URI_MISSING_PATH';\n    throw error;\n  }\n\n  // path: if authority is present path must be empty or start with /\n  if (is(String, authority) && authority.length > 0) {\n    if (!(path === '' || path.startsWith('/'))) {\n      const error = new URIError('path must be empty or start with \\'/\\' when authority is present');\n      error.code = 'URI_INVALID_PATH';\n      throw error;\n    }\n  } else if (path.startsWith('//')) {\n    // if authority is not present path must not start with //\n    const error = new URIError('path must not start with \\'//\\' when authority is not present');\n    error.code = 'URI_INVALID_PATH';\n    throw error;\n  }\n\n  // check for inconsistent authority (original vs parsed) which means\n  // host parsed was actually wrong\n  if (!exists(authority) && exists(authorityPunydecoded)) {\n    const error = new URIError(`host must be a valid ip or domain name, got '${hostPunydecoded}'`);\n    error.code = 'URI_INVALID_HOST';\n    throw error;\n  }\n\n  return {\n    scheme,\n    authority,\n    authorityPunydecoded,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    pathqf,\n    query,\n    fragment,\n    href,\n    schemeLen,\n    valid: true,\n  };\n};\n\n/**\n * @func checkURI\n *\n * Check an URI is valid according to RFC-3986.\n *\n * Rules:\n * 1. scheme is required and cannot be empty;\n * 2. path is required and can be empty;\n * 3. if authority is present path must be empty or start with /;\n * 4. if authority is not present path must not start with //;\n * 5. scheme can only have specific characters:\n *    https://tools.ietf.org/html/rfc3986#section-3.1;\n * 6. if authority is present:\n *    1. host must be a valid IP or domain name;\n *    2. userinfo, if any, can only have specific characters:\n *       https://tools.ietf.org/html/rfc3986#section-3.2.1;\n *    3. port, if any, must be an integer in a specific range.\n * 7. path, query and fragment can only have specific characters:\n *    https://tools.ietf.org/html/rfc3986#section-3.3.\n *\n * @param  {String} uri\n * @param  {Boolean} sitemap\n * @return {Object}\n * @throws {URIError}\n */\nconst checkURI = function checkURI(uri, { sitemap } = {}) {\n  // check uri type and syntax\n  const {\n    scheme,\n    authority,\n    authorityPunydecoded,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    pathqf,\n    query,\n    fragment,\n    href,\n    schemeLen,\n  } = checkURISyntax(uri);\n\n  // check scheme characters\n  checkSchemeChars(scheme, schemeLen);\n\n  // authority (not required)\n  if (exists(authority)) {\n    // check userinfo\n    checkComponent({ sitemap, type: 'userinfo', string: userinfo });\n\n    // check host is a valid ip first (RFC-3986) or a domain name\n    if (!isIP(host) && !isDomain(host)) {\n      const error = new URIError(`host must be a valid ip or domain name, got '${host}'`);\n      error.code = 'URI_INVALID_HOST';\n      throw error;\n    }\n\n    // check port is a number if any\n    if (exists(port) && int(port, { ge: minPortInteger, le: maxPortInteger }) === undefined) {\n      const error = new URIError(`port must be an integer between ${minPortInteger}-${maxPortInteger}, got '${port}'`);\n      error.code = 'URI_INVALID_PORT';\n      throw error;\n    }\n  }\n\n  // check path, query and fragment\n  checkComponent({ sitemap, type: 'path', string: path });\n  checkComponent({ sitemap, type: 'query', string: query });\n  checkComponent({ sitemap, type: 'fragment', string: fragment });\n\n  return {\n    scheme,\n    authority,\n    authorityPunydecoded,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    pathqf,\n    query,\n    fragment,\n    href,\n    valid: true,\n  };\n};\n\n/**\n * @func checkHttpURL\n *\n * Check an URI is a valid HTTP URL (sitemap URLs supported to create aliases).\n *\n * This function uses checkURI to check URI provided is valid.\n *\n * Rules:\n * 1. scheme must be http or HTTP;\n * 2. authority is required;\n * 3. URL must be less than max length.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @param  {Boolean} https\n * @param  {Boolean} web whether to check both http and https\n * @param  {Boolean} sitemap\n * @return {Object}\n * @throws {URIError}\n */\nconst checkHttpURL = function checkHttpURL(uri, { https, web, sitemap } = {}) {\n  // precheck case for sitemap only\n  if (sitemap === true) {\n    checkLowercase(uri);\n  }\n\n  const schemesToCheck = [];\n\n  if (https === true) {\n    schemesToCheck.push('https');\n  } else if (web === true) {\n    schemesToCheck.push('http', 'https');\n  } else {\n    schemesToCheck.push('http');\n  }\n\n  const {\n    scheme,\n    authority,\n    authorityPunydecoded,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    pathqf,\n    query,\n    fragment,\n    href,\n  } = checkURI(uri, { sitemap });\n\n  // scheme\n  if (!schemesToCheck.includes(scheme)) {\n    const error = new URIError(`scheme must be ${schemesToCheck.join(' or ')}, got '${scheme}'`);\n    error.code = 'URI_INVALID_SCHEME';\n    throw error;\n  }\n\n  // authority\n  if (!is(String, authority)) {\n    const error = new URIError('authority is required');\n    error.code = 'URI_MISSING_AUTHORITY';\n    throw error;\n  }\n\n  // max length\n  if (is(String, href) && href.length > maxLengthURL) {\n    const error = new URIError(`max URL length of ${maxLengthURL} reached: ${href.length}`);\n    error.code = 'URI_MAX_LENGTH_URL';\n    throw error;\n  }\n\n  return {\n    scheme,\n    authority,\n    authorityPunydecoded,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    pathqf,\n    query,\n    fragment,\n    href,\n    valid: true,\n  };\n};\n\n/**\n * @func checkHttpsURL\n *\n * Check an URI is a valid HTTPS URL.\n *\n * Same behavior than checkHttpURL except scheme must be https or HTTPS.\n *\n * @param  {String} uri\n * @return {Object}\n * @throws {URIError}\n */\nconst checkHttpsURL = function checkHttpsURL(uri) {\n  return checkHttpURL(uri, { https: true });\n};\n\n/**\n * @func checkHttpSitemapURL\n *\n * Check an URI is a valid HTTP URL to be used in an XML sitemap file.\n *\n * This function uses checkHttpURL to check URI provided is a valid HTTP URL.\n *\n * Rules:\n * 1. scheme must be http;\n * 2. authority is required;\n * 3. specific characters must be escaped;\n * 4. can only contain lowercase characters;\n * 5. URL must be less than max length.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @return {Object}\n * @throws {URIError}\n */\nconst checkHttpSitemapURL = function checkHttpSitemapURL(uri) {\n  return checkHttpURL(uri, { sitemap: true });\n};\n\n/**\n * @func checkHttpsSitemapURL\n *\n * Check an URI is a valid HTTPS URL to be used in an XML sitemap file.\n * Same behavior than checkHttpSitemapURL except scheme must be https.\n *\n * @param  {String} uri\n * @return {Object}\n * @throws {URIError}\n */\nconst checkHttpsSitemapURL = function checkHttpsSitemapURL(uri) {\n  return checkHttpURL(uri, { https: true, sitemap: true });\n};\n\n/**\n * @func checkWebURL\n *\n * Check an URI is a valid HTTP or HTTPS URL.\n *\n * Same behavior than checkHttpURL except scheme can be http/HTTP or https/HTTPS.\n *\n * @param  {String} uri\n * @return {Object}\n * @throws {URIError}\n */\nconst checkWebURL = function checkWebURL(uri) {\n  return checkHttpURL(uri, { web: true });\n};\n\n/**\n * @func checkSitemapURL\n *\n * Check an URI is a valid HTTP or HTTPS URL to be used in an XML sitemap file.\n *\n * Same behavior than checkHttpSitemapURL except scheme can be http or https.\n *\n * @param  {String} uri\n * @return {Object}\n * @throws {URIError}\n */\nconst checkSitemapURL = function checkSitemapURL(uri) {\n  return checkHttpURL(uri, { web: true, sitemap: true });\n};\n\nmodule.exports = Object.freeze({\n  checkPercentEncoding,\n  checkSitemapEncoding,\n  checkComponent,\n  checkSchemeChars,\n  checkLowercase,\n  checkURISyntax,\n  checkURI,\n  checkHttpURL,\n  checkHttpsURL,\n  checkHttpSitemapURL,\n  checkHttpsSitemapURL,\n  checkWebURL,\n  checkSitemapURL,\n});\n","/**\n * node-uri\n */\nconst { punycode, punydecode } = require('./punycode');\nconst { parseURI, recomposeURI } = require('./parser');\nconst { isDomainLabel, isDomain } = require('./domain');\nconst { isIP, isIPv4, isIPv6 } = require('./ip');\nconst {\n  checkURI,\n  checkHttpURL,\n  checkHttpsURL,\n  checkHttpSitemapURL,\n  checkHttpsSitemapURL,\n  checkWebURL,\n  checkSitemapURL,\n} = require('./checkers');\nconst {\n  encodeURIComponentString,\n  encodeURIString,\n  encodeWebURL,\n  encodeSitemapURL,\n} = require('./encoders');\nconst {\n  decodeURIComponentString,\n  decodeURIString,\n  decodeWebURL,\n  decodeSitemapURL,\n} = require('./decoders');\n\nmodule.exports = Object.freeze({\n  punycode,\n  punydecode,\n  parseURI,\n  recomposeURI,\n  isDomainLabel,\n  isDomain,\n  isIP,\n  isIPv4,\n  isIPv6,\n  checkURI,\n  checkHttpURL,\n  checkHttpsURL,\n  checkHttpSitemapURL,\n  checkHttpsSitemapURL,\n  checkWebURL,\n  checkSitemapURL,\n  encodeURIComponentString,\n  encodeURIString,\n  encodeWebURL,\n  encodeSitemapURL,\n  decodeURIComponentString,\n  decodeURIString,\n  decodeWebURL,\n  decodeSitemapURL,\n});\n","/**\n * encoders\n *\n * - encodeURIComponentString(uri, { sitemap, lowercase } = {}) -> String\n * - encodeURIString(uri, { web, sitemap, lowercase } = {}) -> String throws URIError\n * - encodeWebURL(uri, { lowercase } = {}) -> String\n * - encodeSitemapURL(uri, { lowercase } = {}) -> String\n */\nconst { maxLengthURL, minPortInteger, maxPortInteger } = require('../config');\nconst { checkURISyntax, checkSchemeChars } = require('../checkers');\nconst {\n  isUserinfoChar,\n  isPathChar,\n  isQueryOrFragmentChar,\n  isSitemapUserinfoChar,\n  isSitemapPathChar,\n  isSitemapQueryOrFragmentChar,\n} = require('../checkers/chars');\nconst { recomposeURI } = require('../parser');\nconst { entities, specialChars } = require('../sitemap');\nconst { isDomain } = require('../domain');\nconst { isIP } = require('../ip');\nconst { cast: { int }, object: { exists, is } } = require('../helpers');\n\n/**\n * @func encodeURIComponentString\n *\n * Encode an URI component according to RFC-3986 with Sitemap entities support.\n *\n * Support:\n * - Sitemap's special characters;\n * - lower and upper case.\n *\n * Note:\n * - only userinfo, path, query and fragment components can be encoded;\n * - scheme and authority host+port can never have percent encoded characters;\n * - the empty string is returned if unable to encode;\n * - sitemap characters must be in lowercase and escaped for XML sitemap.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} component\n * @param  {String} type\n * @param  {Boolean} sitemap\n * @param  {Boolean} lowercase\n * @return {String}\n */\nconst encodeURIComponentString = function encodeURIComponentString(\n  component,\n  { type, sitemap, lowercase } = {},\n) {\n  if (!is(String, component)) {\n    return '';\n  }\n\n  const componentToEncode = lowercase === true || sitemap === true\n    ? component.toLowerCase()\n    : component;\n  const componentToEncodeLen = componentToEncode.length;\n  let uricomponent = '';\n\n  for (let i = 0; i < componentToEncodeLen; i += 1) {\n    let encoded = false;\n\n    // escape entity or special chars if any FIRST\n    if (sitemap === true) {\n      if (exists(entities[componentToEncode[i]])) {\n        uricomponent += entities[componentToEncode[i]];\n        encoded = true;\n      } else if (exists(specialChars[componentToEncode[i]])) {\n        uricomponent += specialChars[componentToEncode[i]];\n        encoded = true;\n      }\n    }\n\n    if (!encoded) {\n      let isChar;\n\n      switch (type) {\n        case 'userinfo':\n          isChar = (sitemap && isSitemapUserinfoChar(componentToEncode[i], true))\n            || isUserinfoChar(componentToEncode[i], true);\n          break;\n        case 'path':\n          isChar = (sitemap && isSitemapPathChar(componentToEncode[i], true))\n            || isPathChar(componentToEncode[i], true);\n          break;\n        case 'query':\n        case 'fragment':\n          isChar = (sitemap && isSitemapQueryOrFragmentChar(componentToEncode[i], true))\n            || isQueryOrFragmentChar(componentToEncode[i], true);\n          break;\n        default:\n          isChar = false;\n      }\n\n      uricomponent += !isChar\n        ? encodeURIComponent(componentToEncode[i])\n        : componentToEncode[i];\n    }\n  }\n\n  return uricomponent;\n};\n\n/**\n * @func encodeURIString\n *\n * Encode an URI string according to RFC-3986 with basic checking.\n *\n * Checked:\n * - scheme is required;\n * - path is required, can be empty;\n * - port, if any, must be an integer in a specific range;\n * - host must be a valid ip or domain name;\n * - maximum size once encoded for URLs.\n *\n * Support:\n * - IDNs: returns URI with its Punycode host, if any;\n * - lower and upper case.\n *\n * Note:\n * - only userinfo, path, query and fragment can be percent encoded;\n * - native function encodeURI encodes string according to RFC-2396 which is outdated;\n * - native function encodeURI also encodes scheme and host that cannot have\n *   percend-encoded characters;\n * - characters that should not be percent-encoded in RFC-3986 are [] to represent IPv6 host;\n * - to stay fully RFC-3986 compliant, scheme and host are put in lowercase.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @param  {Boolean} web\n * @param  {Boolean} sitemap\n * @param  {Boolean} lowercase\n * @return {String}\n * @throws {URIError}\n */\nconst encodeURIString = function encodeURIString(uri, { web, sitemap, lowercase } = {}) {\n  const uriToEncode = is(String, uri) && lowercase === true ? uri.toLowerCase() : uri;\n  const webURL = web === true || sitemap === true;\n\n  // check uri type and syntax\n  const {\n    scheme,\n    authority,\n    userinfo,\n    host,\n    port,\n    path,\n    query,\n    fragment,\n    schemeLen,\n  } = checkURISyntax(uriToEncode);\n\n  // scheme must be http or https for web/sitemap or with valid chars, always in lowercase\n  if (webURL) {\n    if (scheme !== 'http' && scheme !== 'https') {\n      const error = new URIError(`scheme must be http or https, got '${scheme}'`);\n      error.code = 'URI_INVALID_SCHEME';\n      throw error;\n    }\n  } else {\n    // check scheme characters, it is not intended to encode a scheme\n    checkSchemeChars(scheme, schemeLen);\n  }\n\n  // authority is required and must be a valid host for web/sitemap\n  if (webURL && !is(String, authority)) {\n    const error = new URIError('authority is required');\n    error.code = 'URI_MISSING_AUTHORITY';\n    throw error;\n  }\n\n  // check host is a valid ip first (RFC-3986) or a domain name\n  if (exists(host) && !isIP(host) && !isDomain(host)) {\n    const error = new URIError(`host must be a valid ip or domain name, got '${host}'`);\n    error.code = 'URI_INVALID_HOST';\n    throw error;\n  }\n\n  // check port is a number if any\n  if (exists(port) && int(port, { ge: minPortInteger, le: maxPortInteger }) === undefined) {\n    const error = new URIError(`port must be an integer between ${minPortInteger}-${maxPortInteger}, got '${port}'`);\n    error.code = 'URI_INVALID_PORT';\n    throw error;\n  }\n\n  // userinfo\n  // pass lowercase to false option since whole uri has been lowercased if true\n  const userinfoEncoded = encodeURIComponentString(userinfo, {\n    sitemap,\n    type: 'userinfo',\n    lowercase: false,\n  });\n\n  // path\n  const pathEncoded = encodeURIComponentString(path, {\n    sitemap,\n    type: 'path',\n    lowercase: false,\n  });\n\n  // query\n  const queryEncoded = encodeURIComponentString(query, {\n    sitemap,\n    type: 'query',\n    lowercase: false,\n  });\n\n  // fragment\n  const fragmentEncoded = encodeURIComponentString(fragment, {\n    sitemap,\n    type: 'fragment',\n    lowercase: false,\n  });\n\n  const uriencoded = recomposeURI({\n    scheme,\n    host,\n    port,\n    userinfo: userinfoEncoded,\n    path: pathEncoded,\n    query: queryEncoded,\n    fragment: fragmentEncoded,\n  });\n\n  if (webURL && uriencoded.length > maxLengthURL) {\n    const error = new URIError(`max URL length of ${maxLengthURL} reached: ${uriencoded.length}`);\n    error.code = 'URI_MAX_LENGTH_URL';\n    throw error;\n  }\n\n  return uriencoded;\n};\n\n/**\n * @func encodeWebURL\n *\n * Encode an URI string with basic checking based on RFC-3986 standard applied\n * to HTTP and HTTPS URLs.\n *\n * Uses a fixed encodeURI function to be RFC-3986 compliant.\n *\n * Checked:\n * - scheme must be http/HTTP or https/HTTPS;\n * - path is required, can be empty;\n * - authority is required;\n * - port, if any, must be an integer in a specific range;\n * - host must be a valid IP or domain name;\n * - maximum size once encoded.\n *\n * Support:\n * - IDNs: returns URL with its Punycode host, if any;\n * - lower and upper case.\n *\n * Note:\n * - only userinfo, path, query and fragment can be percent encoded;\n * - native function encodeURI encodes string according to RFC-2396 which is outdated;\n * - native function encodes also scheme and host that cannot have percend encoded characters;\n * - characters that should not be percent-encoded in RFC-3986 are [] to represent IPv6 host;\n * - to stay fully RFC-3986 compliant, scheme and host are put in lowercase.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986.\n *\n *\n * @param {String} uri\n * @param  {Boolean} lowercase\n * @return {String}\n * @throws {URIError}\n */\nconst encodeWebURL = function encodeWebURL(uri, { lowercase } = {}) {\n  return encodeURIString(uri, { lowercase, web: true });\n};\n\n/**\n * @func encodeSitemapURL\n *\n * Encode an URI string with basic checking based on RFC-3986 standard applied\n * to HTTP and HTTPS URLs and sitemap requirements regarding special entities to escape.\n *\n * Checked:\n * - scheme must be http/HTTP or https/HTTPS;\n * - path is required, can be empty;\n * - authority is required;\n * - port, if any, must be an integer in a specific range;\n * - host must be a valid IP or domain name;\n * - maximum size once encoded.\n *\n * Support:\n * - Sitemap's special characters;\n * - IDNs: returns URI with its Punycode host, if any;\n * - lower case only.\n *\n * Note:\n * - only userinfo, path, query and fragment can be percent encoded;\n * - native function encodeURI encodes string according to RFC-2396 which is outdated;\n * - native function encodes also scheme and host that cannot have percend encoded characters;\n * - characters that should not be percent-encoded in RFC-3986 are [] to represent IPv6 host;\n * - to stay fully RFC-3986 compliant, scheme and host are put in lowercase.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @return {String}\n * @throws {URIError}\n */\nconst encodeSitemapURL = function encodeSitemapURL(uri) {\n  return encodeURIString(uri, { lowercase: true, sitemap: true });\n};\n\nmodule.exports = Object.freeze({\n  encodeURIComponentString,\n  encodeURIString,\n  encodeWebURL,\n  encodeSitemapURL,\n});\n","/**\n * decoders\n *\n * - decodeURIComponentString(component, { sitemap, lowercase } = {}) -> String\n * - decodeURIString(uri, { sitemap, lowercase } = {}) -> String throws URIError\n * - decodeWebURL(uri, { lowercase } = {}) -> String\n * - decodeSitemapURL(uri, { lowercase } = {}) -> String\n */\nconst { maxLengthURL, minPortInteger, maxPortInteger } = require('../config');\nconst { checkURISyntax, checkSchemeChars } = require('../checkers');\nconst { cast: { int }, object: { exists, is } } = require('../helpers');\nconst { recomposeURI } = require('../parser');\nconst { isDomain } = require('../domain');\nconst { isIP } = require('../ip');\nconst {\n  escapeCodes,\n  escapeCodesKeys,\n  pencodings,\n  pencodingsKeys,\n} = require('../sitemap');\n\n/**\n * @func decodeURIComponentString\n *\n * Decode an URI component string with Sitemap's escape codes support.\n *\n * Native function decodeURIComponent could throw and to be consistent with\n * encodeURIComponentString the empty string is returned if unable to decode.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @param  {Boolean} sitemap\n * @param  {Boolean} lowercase\n * @return {String}\n */\nconst decodeURIComponentString = function decodeURIComponentString(\n  component,\n  { sitemap, lowercase } = {},\n) {\n  if (!is(String, component)) {\n    return '';\n  }\n\n  const componentToDecode = lowercase === true ? component.toLowerCase() : component;\n\n  if (sitemap === true) {\n    const regexp = new RegExp(escapeCodesKeys.concat(pencodingsKeys).join('|'), 'g');\n    const uriToDecode = componentToDecode.replace(\n      regexp,\n      (match) => escapeCodes[match] || pencodings[match],\n    );\n\n    try {\n      return decodeURIComponent(uriToDecode);\n    } catch (e) {\n      return '';\n    }\n  }\n\n  try {\n    return decodeURIComponent(componentToDecode);\n  } catch (e) {\n    return '';\n  }\n};\n\n/**\n * @func decodeURIString\n *\n * Decode an URI string according to RFC-3986 with basic checking.\n *\n * Checked:\n * - scheme is required;\n * - path is required, can be empty;\n * - port, if any, must be an integer in a specific range;\n * - host must be a valid ip or domain name;\n * - maximum size once encoded for URLs.\n *\n * Support:\n * - IDNs: returns URI with its Punydecoded host (Unicode serialization of the domain), if any;\n * - lower and upper case.\n *\n * Note:\n * - if one of userinfo, path, query or fragment component cannot be decoded, it will be ignored;\n * - native function decodeURI does not support IDNs and cannot properly work\n *   with encodeURI since the function is based on an outdated standard;\n * - to stay fully RFC-3986 compliant, scheme and host are put in lowercase;\n * - to only use with encodeURIString.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @param  {Boolean} sitemap\n * @param  {Boolean} lowercase\n * @return {String}\n * @throws {URIError}\n */\nconst decodeURIString = function decodeURIString(uri, { web, sitemap, lowercase } = {}) {\n  const uriToDecode = is(String, uri) && lowercase === true ? uri.toLowerCase() : uri;\n  const webURL = web === true || sitemap === true;\n\n  // check uri type and syntax\n  const {\n    scheme,\n    authority,\n    userinfo,\n    host,\n    hostPunydecoded,\n    port,\n    path,\n    query,\n    fragment,\n    schemeLen,\n  } = checkURISyntax(uriToDecode);\n\n  // scheme must be http or https for web/sitemap or with valid chars, always in lowercase\n  if (webURL) {\n    if (scheme !== 'http' && scheme !== 'https') {\n      const error = new URIError(`scheme must be http or https, got '${scheme}'`);\n      error.code = 'URI_INVALID_SCHEME';\n      throw error;\n    }\n  } else {\n    // check scheme characters, it is not intended to decode a scheme\n    checkSchemeChars(scheme, schemeLen);\n  }\n\n  // authority is required and must be a valid host for web/sitemap\n  if (webURL && !is(String, authority)) {\n    const error = new URIError('authority is required');\n    error.code = 'URI_MISSING_AUTHORITY';\n    throw error;\n  }\n\n  // check host is a valid ip first (RFC-3986) or a domain name\n  if (exists(host) && !isIP(host) && !isDomain(host)) {\n    const error = new URIError(`host must be a valid ip or domain name, got '${host}'`);\n    error.code = 'URI_INVALID_HOST';\n    throw error;\n  }\n\n  // check port is a number if any\n  if (exists(port) && int(port, { ge: minPortInteger, le: maxPortInteger }) === undefined) {\n    const error = new URIError(`port must be an integer between ${minPortInteger}-${maxPortInteger}, got '${port}'`);\n    error.code = 'URI_INVALID_PORT';\n    throw error;\n  }\n\n  // userinfo\n  // pass lowercase to false option since whole uri has been lowercased if true\n  const userinfoDecoded = decodeURIComponentString(\n    userinfo,\n    { sitemap, lowercase: false },\n  );\n\n  // path\n  const pathDecoded = decodeURIComponentString(\n    path,\n    { sitemap, lowercase: false },\n  );\n\n  // query\n  const queryDecoded = decodeURIComponentString(\n    query,\n    { sitemap, lowercase: false },\n  );\n\n  // fragment\n  const fragmentDecoded = decodeURIComponentString(\n    fragment,\n    { sitemap, lowercase: false },\n  );\n\n  const uridecoded = recomposeURI({\n    scheme,\n    port,\n    host: hostPunydecoded,\n    userinfo: userinfoDecoded,\n    path: pathDecoded,\n    query: queryDecoded,\n    fragment: fragmentDecoded,\n  });\n\n  if (webURL && uridecoded.length > maxLengthURL) {\n    const error = new URIError(`max URL length of ${maxLengthURL} reached: ${uridecoded.length}`);\n    error.code = 'URI_MAX_LENGTH_URL';\n    throw error;\n  }\n\n  return uridecoded;\n};\n\n/**\n * @func decodeWebURL\n *\n * Decode an URI string with basic checking based on RFC-3986 standard applied\n * to HTTP and HTTPS URLs.\n *\n * Uses a fixed decodeURI function to be RFC-3986 compliant.\n *\n * Checked:\n * - scheme must be http/HTTP or https/HTTPS;\n * - path is required, can be empty;\n * - authority is required;\n * - port, if any, must be an integer in a specific range;\n * - parseURI prechecked host, will be null if invalid and so does authority.\n *\n * Support:\n * - IDNs: returns URI with its Punydecoded host\n *   (Unicode serialization of the domain), if any;\n * - lower and upper case.\n *\n * Note:\n * - native function decodeURI does not support IDNs and cannot properly work\n *   with encodeURI since the function is based on an outdated standard;\n * - to stay fully RFC-3986 compliant, scheme and host are put in lowercase;\n * - to use only with encodeWebURL.\n *\n * @param  {String} uri\n * @param  {Boolean} lowercase\n * @return {String}\n * @throws {URIError}\n */\nconst decodeWebURL = function decodeWebURL(uri, { lowercase } = {}) {\n  return decodeURIString(uri, { lowercase, web: true });\n};\n\n/**\n * @func decodeSitemapURL\n *\n * Decode an URI string with basic checking based on RFC-3986 standard applied\n * to HTTP and HTTPS URLs and sitemap requirements regarding escape codes to decode.\n *\n * Checked:\n * - scheme must be http/HTTP or https/HTTPS;\n * - path is required, can be empty;\n * - authority is required;\n * - port, if any, must be an integer in a specific range;\n * - parseURI prechecked host, will be null if invalid and so does authority.\n *\n * Support:\n * - Sitemap's escape codes;\n * - IDNs: returns URI with its Punydecoded host\n *   (Unicode serialization of the domain), if any;\n * - lower and upper case.\n *\n * Note:\n * - native function decodeURI does not support IDNs and cannot properly work\n *   with encodeURI since the function is based on an outdated standard;\n * - to stay fully RFC-3986 compliant, scheme and host are put in lowercase;\n * - to use only with encodeSitemapURL.\n *\n * Based on:\n * - RFC-3986 https://tools.ietf.org/html/rfc3986;\n * - https://support.google.com/webmasters/answer/183668?hl=en&ref_topic=4581190.\n *\n * @param  {String} uri\n * @param  {Boolean} lowercase\n * @return {String}\n * @throws {URIError}\n */\nconst decodeSitemapURL = function decodeSitemapURL(uri, { lowercase } = {}) {\n  return decodeURIString(uri, { lowercase, sitemap: true });\n};\n\nmodule.exports = Object.freeze({\n  decodeURIComponentString,\n  decodeURIString,\n  decodeWebURL,\n  decodeSitemapURL,\n});\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport uri from 'node-uri';\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * URL地址验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst UrlRule = {\n  /**\n   * 测试URL是否是合法的网址。\n   *\n   * 合法的网址的schema必须是HTTP或HTTPS协议。\n   *\n   * @param {String} url\n   *    待测试的URL，前后允许有空白字符。\n   * @return {Boolean}\n   *    若URL合法则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(url) {\n    if (isString(url)) {\n      const u = url.trim();\n      if (u.length === 0) {\n        return false;\n      }\n      try {\n        uri.checkWebURL(u);\n        return true;\n      } catch {\n        return false;\n      }\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default UrlRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2024.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证字符串是否是合法的用户名的正则表达式。\n *\n * 用户名的规则如下：\n *\n * - 必须以字母或数字开头；\n * - 只能包含字母、数字、下划线、连字符、点号、@符号；\n * - 长度为4到32个字符。\n *\n * @author 胡海星\n * @private\n */\nconst USERNAME_REGEXP = /^[a-zA-Z0-9][a-zA-Z0-9@\\\\._-]*$/;\n\n/**\n * 用户名的验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst UsernameRule = {\n  /**\n   * 用户名的最小长度。\n   */\n  minLength: 4,\n\n  /**\n   * 用户名的最大长度。\n   */\n  maxLength: 32,\n\n  /**\n   * 测试一个值是否是合法的用户名。\n   *\n   * 用户名的规则如下：\n   *\n   * - 必须以字母或数字开头；\n   * - 只能包含字母、数字、下划线、连字符、点号、@符号；\n   * - 长度为4到32个字符。\n   *\n   * @param {any} value\n   *    待测试的值，前后不允许有空白字符。\n   * @return {boolean}\n   *    若该字符串是一个表示合法用户名的字符串则返回`true`；否则返回`false`。\n   * @author 胡海星\n   */\n  isValid(value) {\n    if (isString(value)) {\n      return (value.length >= this.minLength)\n        && (value.length <= this.maxLength)\n        && USERNAME_REGEXP.test(value);\n    } else {\n      return false;\n    }\n  },\n};\n\nexport default UsernameRule;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * 验证结果的类。\n *\n * @author 胡海星\n */\nclass ValidationResult {\n  /**\n   * 表示验证是否成功。\n   *\n   * @type {boolean}\n   */\n  success = true;\n\n  /**\n   * 验证结果的描述。\n   *\n   * @type {string}\n   */\n  description = '';\n\n  /**\n   * 下一个验证结果。\n   *\n   * 如果验证有多个失败结果，下一个失败结果将链接到此字段。\n   *\n   * @type {ValidationResult | null}\n   */\n  next = null;\n\n  /**\n   * 创建一个新的 {@link ValidationResult} 对象。\n   *\n   * @param {boolean} success\n   *     新对象的验证正确性标志。如果未提供，则使用默认值 `true`。\n   * @param {string} description\n   *     新对象的验证结果描述。如果未提供，默认值为空字符串。\n   */\n  constructor(success = true, description = '') {\n    this.success = success ?? true;\n    this.description = description ?? '';\n    this.next = null;\n  }\n\n  /**\n   * 合并多个 {@link ValidationResult} 对象。\n   *\n   * 如果要合并的所有 {@link ValidationResult} 对象都成功，\n   * 则合并结果为单个成功的 {@link ValidationResult} 对象；\n   * 否则，合并结果为所有失败的 {@link ValidationResult} 对象的链。\n   *\n   * @param  {Array} results\n   *     多个 {@link ValidationResult} 对象的数组。\n   * @return {ValidationResult}\n   *     返回将指定的 {@link ValidationResult} 对象数组中的所有对象\n   *     合并的结果作为一个新的 {@link ValidationResult} 对象。\n   */\n  static merge(results) {\n    if (Array.isArray(results) && (results.length > 0)) {\n      const first = new ValidationResult(true);\n      let last = first;\n      for (let i = 0; i < results.length; ++i) {\n        const result = results[i];\n        if (result && !result.success) {\n          last.next = result;\n          last = result;\n        }\n      }\n      last.next = null;\n      if (first.next) {\n        last = first.next;\n        first.next = null;\n        return last;\n      } else {\n        return first;\n      }\n    } else {\n      return new ValidationResult(true);\n    }\n  }\n}\n\nexport default ValidationResult;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { isString } from '@qubit-ltd/type-detect';\n\n/**\n * 验证码的默认长度。\n *\n * @type {number}\n * @private\n */\nconst DEFAULT_VERIFY_CODE_LENGTH = 6;\n\n/**\n * 验证码的验证规则。\n *\n * @type {object}\n * @namespace\n * @author 胡海星\n */\nconst VerifyCodeRule = {\n  /**\n   * 测试字符串是否是有效的验证码。\n   *\n   * 有效的验证码是仅包含数字且具有指定长度的字符串。\n   *\n   * @param {string} code\n   *     要测试的字符串。前后的空格会被忽略。\n   * @param {number} length\n   *     可选的验证码长度。默认值为6。\n   * @return\n   *     如果字符串是有效的验证码，则返回true；否则返回false。\n   * @author 胡海星\n   */\n  isValid(code, length = DEFAULT_VERIFY_CODE_LENGTH) {\n    if (isString(code)) {\n      code = code.trim();\n      const n = code.length;\n      if (n !== length) {\n        return false;\n      }\n      for (let i = 0; i < n; ++i) {\n        if ((code.charCodeAt(i) < 48)     // 48 是 '0' 的ASCII码\n          || (code.charCodeAt(i) > 57)) { // 57 是 '9' 的ASCII码\n          return false;\n        }\n      }\n      return true;\n    }\n    return false;\n  },\n};\n\nexport default VerifyCodeRule;\n"],"names":["typeDetect","require","require$$0","_classCallCheck","_createClass","_defineProperty","ALPHA_NUMBER_REGEXP","AlphaNumberRule","isValid","value","isString","test","BoolRule","isBoolean","val","trim","toLowerCase","NUMBER_LENGTH","RATIO","LAST_CHAR","parseNumber","number","start","end","result","i","ch","charCodeAt","isIdCardNumberValid","length","sum","lastChar","charAt","toUpperCase","isIdCardBirthdayValid","year","YEAR_INDEX","month","MONTH_INDEX","day","DAY_INDEX","birthday","Date","getFullYear","getMonth","getDate","now","getTime","ChinaIdentityCardRule","type","name","getGender","getIdCardGender","getBirthday","getIdCardBirthday","substring","concat","MOBILE_REGEXP","ChinaMobileRule","mobile","NUMBER_REGEXP","ChinaOfficerCardRule","ChinaPassportRule","PHONE_REGEXP","ChinaPhoneRule","phone","getDefaultExportFromCjs","x","EmailValidator","tester","emailValidator","validate","email","parts","split","some","part","EmailRule","INTEGER_REGEXP","IntegerRule","isBigInt","isNumber","Number","isInteger","DATE_REGEXP","LocalDateRule","isDate","DATETIME_REGEXP","LocalDateTimeRule","datetime","TIME_REGEXP","LocalTimeRule","LOWERCASE_HYPHEN_REGEXP","LowercaseHyphenRule","str","LOWERCASE_UNDERSCORE_REGEXP","LowercaseUnderscoreRule","NumberRule","DEFAULT_OPTION","allowNaN","allowInfinity","option","arguments","undefined","this","isNaN","isFinite","NumericRule","OtherCredentialRule","PASSWORD_REGEXP","PasswordRule","minLength","maxLength","CHINESE_NAME_REGEXP","ENGLISH_NAME_REGEXP","PersonNameRule","TIMESTAMP_REGEXP","TimestampRule","timestamp","UPPERCASE_ALPHA_NUMBER_REGEXP","UppercaseAlphaNumberRule","UPPERCASE_UNDERSCORE_REGEXP","UppercaseUnderscoreRule","exists","thing","object","Object","freeze","is","Type","constructor","castNum","valueOf","String","Boolean","cast","integer","castInt","int","parseInt","num","ge","le","lessThan","greaterThan","require$$1","helpers","v4","v6seg","v6","replace","ip","isIP","RegExp","isIPv4","isIPv6","domainToASCII","domainToUnicode","require$$2","punycode_1","punycode","domain","punydecode","config","maxLengthURL","minPortInteger","maxPortInteger","require$$3","uriRegexp","ipv6Regexp","hostToURI","host","recomposeURI","components","cpts","scheme","path","uri","startsWith","userinfo","port","query","fragment","parser","parseURI","parsed","authority","authorityPunydecoded","hostPunydecoded","pathqf","href","authorityParsed","queryParsed","fragmentParsed","match","hostAndPort","ipv6Match","hostParsed","portToCast","Array","hostLowerCase","toASCII","toUnicode","recomposedURI","isPathChar","char","encode","encoding","code","isSitemapPathChar","chars","isSchemeChar","isUserinfoChar","isSitemapUserinfoChar","isDomainChar","isQueryOrFragmentChar","isSitemapQueryOrFragmentChar","isPercentEncodingChar","isDomainLabel","label","len","isDomain","labels","labelsLen","occurences","slice","specialChars","specialCharsKeys","keys","pencodings","forEach","pencodingsKeys","entities","entitiesKeys","escapeCodes","entity","escapeCodesKeys","escapeCodesKeysLen","sitemap","require$$4","require$$5","require$$6","checkPercentEncoding","string","index","stringLen","error","URIError","offset","checkSitemapEncoding","escapeOffset","j","codeLen","checkComponent","includes","checkSitemap","checkCharFunc","checkSchemeChars","schemeLen","checkLowercase","checkURISyntax","valid","checkURI","checkHttpURL","https","web","schemesToCheck","push","join","checkers","checkHttpsURL","checkHttpSitemapURL","checkHttpsSitemapURL","checkWebURL","checkSitemapURL","encodeURIComponentString","encodeURIString","encodeWebURL","encodeSitemapURL","require$$7","component","lowercase","componentToEncode","componentToEncodeLen","uricomponent","encoded","isChar","encodeURIComponent","uriToEncode","webURL","userinfoEncoded","pathEncoded","queryEncoded","fragmentEncoded","uriencoded","encoders","decodeURIComponentString","decodeURIString","decodeWebURL","decodeSitemapURL","componentToDecode","regexp","uriToDecode","decodeURIComponent","e","userinfoDecoded","pathDecoded","queryDecoded","fragmentDecoded","uridecoded","decoders","src","srcExports","UrlRule","url","u","_unused","USERNAME_REGEXP","UsernameRule","ValidationResult","success","description","next","key","merge","results","isArray","first","last","VerifyCodeRule","n","exports"],"mappings":"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","x_google_ignoreList":[9,24,25,26,27,28,29,30,31,32,33,34,35,36,37]}