salve-annos
Version:
A fork with support for documentation of Salve, a Javascript library which implements a validator able to validate an XML document on the basis of a subset of RelaxNG.
1,321 lines • 56.7 kB
JavaScript
"use strict";
/**
* Implementation of the XMLSchema datatypes.
* @author Louis-Dominique Dubeau
* @license MPL 2.0
* @copyright Mangalam Research Center for Buddhist Languages
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.xmlschema = void 0;
const errors_1 = require("./errors");
const regexp = __importStar(require("./regexp"));
const xmlcharacters_1 = require("./xmlcharacters");
// tslint:disable: no-reserved-keywords
/**
* Convert a number to an internal representation. This takes care of the
* differences between JavaScript and XML Schema (e.g. "Infinity" vs "INF").
*
* @param value The value as expressed in an XML file or schema.
*
* @returns The number, in its internal representation.
*/
function convertToInternalNumber(value) {
if (value === "INF") {
return Infinity;
}
if (value === "-INF") {
return -Infinity;
}
return Number(value);
}
/**
* Convert an internal representation of a number to a string. This takes care
* of the differences between JavaScript and XML Schema. For instance, a value
* of ``Infinity`` will be represented as the string ``"INF"``.
*
* @param number The internal representation.
*
* @returns The string representation.
*/
function convertInternalNumberToString(value) {
if (value === Infinity) {
return "INF";
}
if (value === -Infinity) {
return "-INF";
}
return value.toString();
}
class NumericParameter {
convert(value) {
return convertToInternalNumber(value);
}
}
class NonNegativeIntegerParameter extends NumericParameter {
isInvalidParam(value, name) {
const asNum = Number(value);
if (Number.isInteger(asNum) && asNum >= 0) {
return false;
}
return new errors_1.ParamError(`${name} must have a non-negative integer value`);
}
}
class LengthP extends NonNegativeIntegerParameter {
constructor() {
super(...arguments);
this.name = "length";
this.repeatable = false;
}
isInvalidValue(value, param, type) {
if (type.valueLength(value) === param) {
return false;
}
return new errors_1.ValueError(`length of value should be ${param}`);
}
}
const lengthP = new LengthP();
class MinLengthP extends NonNegativeIntegerParameter {
constructor() {
super(...arguments);
this.name = "minLength";
this.repeatable = false;
}
isInvalidValue(value, param, type) {
if (type.valueLength(value) >= param) {
return false;
}
return new errors_1.ValueError("length of value should be greater than " +
`or equal to ${param}`);
}
}
const minLengthP = new MinLengthP();
class MaxLengthP extends NonNegativeIntegerParameter {
constructor() {
super(...arguments);
this.name = "maxLength";
this.repeatable = false;
}
isInvalidValue(value, param, type) {
if (type.valueLength(value) <= param) {
return false;
}
return new errors_1.ValueError("length of value should be less than " +
`or equal to ${param}`);
}
}
const maxLengthP = new MaxLengthP();
//
// pattern is special. It converts the param value found in the RNG file into an
// object with two fields: ``rng`` and ``internal``. RNG is the string value
// from the RNG file, and ``internal`` is a representation internal to salve. We
// use ``internal`` for performing the validation but present ``rng`` to the
// user. Note that if pattern appears multiple times as a parameter, the two
// values are the result of the concatenation of all the instance of the pattern
// parameter. (Why this? Because it would be confusing to show the internal
// value in error messages to the user.)
//
/**
* A mapping of raw schema values to the corresponding ``RegExp`` object.
*/
const reCache = Object.create(null);
class PatternP {
constructor() {
this.name = "pattern";
this.repeatable = true;
}
convert(value) {
let internal = reCache[value];
if (internal === undefined) {
internal = reCache[value] = regexp.parse(value);
}
return {
rng: value,
internal,
};
}
isInvalidParam(value) {
try {
this.convert(value);
}
catch (ex) {
// Convert the error into something that makes sense for salve.
if (ex instanceof regexp.SalveParsingError) {
return new errors_1.ParamError(ex.message);
}
// Rethrow
throw ex;
}
return false;
}
isInvalidValue(value, param) {
if (param instanceof Array) {
let failedOn;
for (const p of param) {
if (!p.internal.test(value)) {
failedOn = p;
break;
}
}
if (failedOn === undefined) {
return false;
}
return new errors_1.ValueError(`value does not match the pattern ${failedOn.rng}`);
}
if (param.internal.test(value)) {
return false;
}
return new errors_1.ValueError(`value does not match the pattern ${param.rng}`);
}
}
const patternP = new PatternP();
class TotalDigitsP extends NumericParameter {
constructor() {
super(...arguments);
this.name = "totalDigits";
this.repeatable = false;
}
isInvalidParam(value, name) {
const asNum = Number(value);
if (Number.isInteger(asNum) && asNum > 0) {
return false;
}
return new errors_1.ParamError(`${name} must have a positive value`);
}
isInvalidValue(value, param) {
const str = String(Number(value)).replace(/[-+.]/g, "");
if (str.length > param) {
return new errors_1.ValueError(`value must have at most ${param} digits`);
}
return false;
}
}
const totalDigitsP = new TotalDigitsP();
class FractionDigitsP extends NonNegativeIntegerParameter {
constructor() {
super(...arguments);
this.name = "fractionDigits";
this.repeatable = false;
}
isInvalidValue(value, param) {
const str = String(Number(value)).replace(/^.*\./, "");
if (str.length > param) {
return new errors_1.ValueError(`value must have at most ${param} fraction digits`);
}
return false;
}
}
class NumericTypeDependentParameter extends NumericParameter {
isInvalidParam(value, name, type) {
const errors = type.disallows(value, type.defaultParams);
if (!errors) {
return false;
}
// Support for multiple value errors is mainly so that we can report if a
// value violates multiple param specifications. When we check a param in
// isolation, it is unlikely that we'd get multiple errors. If we do, we
// narrow it to the first error and convert the ValueError to a ParamError.
return new errors_1.ParamError(errors[0].message);
}
}
const fractionDigitsP = new FractionDigitsP();
class MaxInclusiveP extends NumericTypeDependentParameter {
constructor() {
super(...arguments);
this.name = "maxInclusive";
this.repeatable = false;
}
isInvalidValue(value, param) {
if ((isNaN(value) !== isNaN(param)) || value > param) {
const repr = convertInternalNumberToString(param);
return new errors_1.ValueError(`value must be less than or equal to ${repr}`);
}
return false;
}
}
const maxInclusiveP = new MaxInclusiveP();
class MaxExclusiveP extends NumericTypeDependentParameter {
constructor() {
super(...arguments);
this.name = "maxExclusive";
this.repeatable = false;
}
isInvalidValue(value, param) {
// The negation of a less-than test allows handling a parameter value of NaN
// automatically.
if (!(value < param)) {
const repr = convertInternalNumberToString(param);
return new errors_1.ValueError(`value must be less than ${repr}`);
}
return false;
}
}
const maxExclusiveP = new MaxExclusiveP();
class MinInclusiveP extends NumericTypeDependentParameter {
constructor() {
super(...arguments);
this.name = "minInclusive";
this.repeatable = false;
}
isInvalidValue(value, param) {
if ((isNaN(value) !== isNaN(param)) || value < param) {
const repr = convertInternalNumberToString(param);
return new errors_1.ValueError(`value must be greater than or equal to ${repr}`);
}
return false;
}
}
const minInclusiveP = new MinInclusiveP();
class MinExclusiveP extends NumericTypeDependentParameter {
constructor() {
super(...arguments);
this.name = "minExclusive";
this.repeatable = false;
}
isInvalidValue(value, param) {
// The negation of a greater-than test allows handling a parameter value of
// NaN automatically.
if (!(value > param)) {
const repr = convertInternalNumberToString(param);
return new errors_1.ValueError(`value must be greater than ${repr}`);
}
return false;
}
}
const minExclusiveP = new MinExclusiveP();
/**
* A mapping of parameter names to parameter objects.
*/
const PARAM_NAME_TO_OBJ = Object.create(null);
for (const param of [lengthP, minLengthP, maxLengthP, patternP, totalDigitsP,
fractionDigitsP, minExclusiveP, minInclusiveP,
maxExclusiveP, maxInclusiveP]) {
PARAM_NAME_TO_OBJ[param.name] = param;
}
const EMPTY_PARAMS = Object.create(null);
/**
* The structure that all datatype implementations in this module share.
*
* @private
*
*/
class Base {
/**
* The default parameters if none are specified.
*/
get defaultParams() {
return EMPTY_PARAMS;
}
/**
* Computes the value's length. This may differ from the value's length, as it
* appears in the XML document it comes from.
*
* @param value The value from the XML document.
*
* @returns The length.
*/
valueLength(value) {
return value.length;
}
parseValue(location, value, context) {
const errors = this.disallows(value, this.defaultParams, context);
if (errors) {
throw new errors_1.ValueValidationError(location, errors);
}
const result = this.convertValue(value, context);
if (result instanceof Array) {
throw new errors_1.ValueValidationError(location, result);
}
return { value: result };
}
// tslint:disable-next-line: max-func-body-length
parseParams(location, params) {
const ret = Object.create(null);
if (params === undefined) {
return ret;
}
const errors = [];
for (const x of params) {
const { name, value } = x;
const prop = PARAM_NAME_TO_OBJ[name];
// Do we know this parameter?
if (prop === undefined || !this.validParams.includes(prop)) {
errors.push(new errors_1.ParamError(`unexpected parameter: ${name}`));
continue;
}
// Is the value valid at all?
const invalid = prop.isInvalidParam(value, name, this);
if (invalid) {
errors.push(invalid);
}
else {
const converted = prop.convert(value);
const values = ret[name];
// We gather all the values in a map of name to value.
if (values === undefined) {
ret[name] = converted;
}
else {
if (!prop.repeatable) {
errors.push(new errors_1.ParamError(`cannot repeat parameter ${name}`));
}
if (Array.isArray(values)) {
values.push(converted);
}
else {
ret[name] = [values, converted];
}
}
}
}
if (errors.length !== 0) {
throw new errors_1.ParameterParsingError(location, errors);
}
// Inter-parameter checks. There's no point in trying to generalize
// this.
const { minLength, maxLength, maxInclusive, maxExclusive, minInclusive, minExclusive } = ret;
if (minLength > maxLength) {
errors.push(new errors_1.ParamError("minLength must be less than or equal to maxLength"));
}
if (ret.length !== undefined) {
if (minLength !== undefined) {
errors.push(new errors_1.ParamError("length and minLength cannot appear together"));
}
if (maxLength !== undefined) {
errors.push(new errors_1.ParamError("length and maxLength cannot appear together"));
}
}
if (maxInclusive !== undefined) {
if (maxExclusive !== undefined) {
errors.push(new errors_1.ParamError("maxInclusive and maxExclusive cannot appear together"));
}
// maxInclusive, minExclusive
if (minExclusive >= maxInclusive) {
errors.push(new errors_1.ParamError("minExclusive must be less than maxInclusive"));
}
}
if (minInclusive !== undefined) {
if (minExclusive !== undefined) {
errors.push(new errors_1.ParamError("minInclusive and minExclusive cannot appear together"));
}
// maxInclusive, minInclusive
if (minInclusive > maxInclusive) {
errors.push(new errors_1.ParamError("minInclusive must be less than or equal to maxInclusive"));
}
// maxExclusive, minInclusive
if (minInclusive >= maxExclusive) {
errors.push(new errors_1.ParamError("minInclusive must be less than maxExclusive"));
}
}
// maxExclusive, minExclusive
if (minExclusive > maxExclusive) {
errors.push(new errors_1.ParamError("minExclusive must be less than or equal to maxExclusive"));
}
if (errors.length !== 0) {
throw new errors_1.ParameterParsingError(location, errors);
}
return ret;
}
equal(value, schemaValue, context) {
const converted = this.convertValue(value, context);
return converted instanceof Array ? false :
converted === schemaValue.value;
}
disallows(value, params, context) {
if (!this.regexp.test(value)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
const paramNames = Object.keys(params);
if (paramNames.length === 0) {
return false;
}
const converted = this.convertValue(value, context);
if (converted instanceof Array) {
return converted;
}
const errors = [];
for (const name of paramNames) {
const param = PARAM_NAME_TO_OBJ[name];
const err = param.isInvalidValue(converted, params[name], this);
if (err) {
errors.push(err);
}
}
return (errors.length !== 0) ? errors : false;
}
}
//
// String family
//
class CommonStringBased extends Base {
convertValue(value) {
return value.trim().replace(/\s+/g, " ");
}
}
/* tslint:disable:class-name */
class string_ extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "string";
this.typeErrorMsg = "value is not a string";
this.validParams = [lengthP, minLengthP, maxLengthP,
patternP];
this.needsContext = false;
// [^] means "any character". The dot would exclude line terminators (\r\n,
// etc.).
this.regexp = /^[^]*$/;
}
convertValue(value) {
return value;
}
// This is a specialized version of disallows that avoids bothering with tests
// that don't affect the results. string and some of its immediate derivates
// are not affected by their regexp, nor do they have default parameters that
// affect what values are allowed.
disallows(value, params) {
if (Object.keys(params).length === 0) {
// The default params don't disallow anything.
return false;
}
const converted = this.convertValue(value);
const errors = [];
// We use Object.keys because we don't know the precise type of params.
for (const name of Object.keys(params)) {
const param = PARAM_NAME_TO_OBJ[name];
const err = param.isInvalidValue(converted, params[name], this);
if (err) {
errors.push(err);
}
}
return (errors.length !== 0) ? errors : false;
}
}
class normalizedString extends string_ {
constructor() {
super(...arguments);
this.name = "normalizedString";
this.typeErrorMsg = "string contains a tab, carriage return or newline";
}
convertValue(value) {
return value.replace(/\s+/g, " ");
}
}
class token extends normalizedString {
constructor() {
super(...arguments);
this.name = "token";
this.typeErrorMsg = "not a valid token";
}
convertValue(value) {
return value.trim().replace(/\s+/g, " ");
}
}
class tokenInternal extends token {
disallows(value, params) {
if (!this.regexp.test(value)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return super.disallows(value, params);
}
}
class language extends tokenInternal {
constructor() {
super(...arguments);
this.name = "language";
this.typeErrorMsg = "not a valid language identifier";
this.regexp = /^\s*[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*\s*$/;
}
}
class Name extends tokenInternal {
constructor() {
super(...arguments);
this.name = "Name";
this.typeErrorMsg = "not a valid Name";
this.regexp = xmlcharacters_1.xmlNameRe;
}
}
class NCName extends Name {
constructor() {
super(...arguments);
this.name = "NCName";
this.typeErrorMsg = "not a valid NCName";
this.regexp = xmlcharacters_1.xmlNcnameRe;
}
}
class NMTOKEN extends tokenInternal {
constructor() {
super(...arguments);
this.name = "NMTOKEN";
this.typeErrorMsg = "not a valid NMTOKEN";
this.regexp = new RegExp(`^\\s*[${xmlcharacters_1.xmlNameChar}]+\\s*$`);
}
}
class NMTOKENS extends NMTOKEN {
constructor() {
super(...arguments);
this.name = "NMTOKENS";
this.typeErrorMsg = "not a valid NMTOKENS";
this.regexp = new RegExp(`^\\s*[${xmlcharacters_1.xmlNameChar}]+(?:\\s+[${xmlcharacters_1.xmlNameChar}]+)*\\s*$`);
}
}
class ID extends NCName {
constructor() {
super(...arguments);
this.name = "ID";
this.typeErrorMsg = "not a valid ID";
}
}
class IDREF extends NCName {
constructor() {
super(...arguments);
this.name = "IDREF";
this.typeErrorMsg = "not a valid IDREF";
}
}
class IDREFS extends IDREF {
constructor() {
super(...arguments);
this.name = "IDREFS";
this.typeErrorMsg = "not a valid IDREFS";
this.regexp = new RegExp(`^\\s*${xmlcharacters_1.xmlNcname}(?:\\s+${xmlcharacters_1.xmlNcname})*\\s*$`);
}
}
class ENTITY extends NCName {
constructor() {
super(...arguments);
this.name = "ENTITY";
this.typeErrorMsg = "not a valid ENTITY";
}
}
class ENTITIES extends ENTITY {
constructor() {
super(...arguments);
this.name = "ENTITIES";
this.typeErrorMsg = "not a valid ENTITIES";
this.regexp = new RegExp(`^\\s*${xmlcharacters_1.xmlNcname}(?:\\s+${xmlcharacters_1.xmlNcname})*\\s*$`);
}
}
//
// Decimal family
//
const decimalPattern = "[-+]?(?!$)\\d*(\\.\\d*)?";
class decimal extends Base {
constructor() {
super(...arguments);
this.name = "decimal";
this.typeErrorMsg = "value not a decimal number";
this.regexp = new RegExp(`^\\s*${decimalPattern}\\s*$`);
this.needsContext = false;
this.validParams = [
totalDigitsP, fractionDigitsP, patternP, minExclusiveP, minInclusiveP,
maxExclusiveP, maxInclusiveP,
];
}
convertValue(value) {
// We don't need to do white-space processing on the value.
return Number(value);
}
}
const integerPattern = "[-+]?\\d+";
class integer extends decimal {
constructor() {
super(...arguments);
this.name = "integer";
this.typeErrorMsg = "value is not an integer";
this.regexp = new RegExp(`^\\s*${integerPattern}\\s*$`);
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
get defaultParams() {
if (this._defaultParams === undefined) {
const params = this._defaultParams = Object.create(null);
const { highestVal, lowestVal } = this;
if (highestVal !== undefined) {
params.maxInclusive = highestVal;
}
if (lowestVal !== undefined) {
params.minInclusive = lowestVal;
}
return params;
}
return this._defaultParams;
}
parseParams(location, params) {
const ret = super.parseParams(location, params);
function fail(message) {
throw new errors_1.ParameterParsingError(location, [new errors_1.ParamError(message)]);
}
const { highestVal, lowestVal } = this;
if (highestVal !== undefined) {
const me = ret.maxExclusive;
if (me !== undefined) {
if (me > highestVal) {
fail(`maxExclusive cannot be greater than ${highestVal}`);
}
}
else {
const mi = ret.maxInclusive;
if (mi !== undefined) {
if (mi > highestVal) {
fail(`maxInclusive cannot be greater than ${highestVal}`);
}
}
else {
ret.maxInclusive = highestVal;
}
}
}
if (lowestVal !== undefined) {
const me = ret.minExclusive;
if (me !== undefined) {
if (me < lowestVal) {
fail(`minExclusive cannot be lower than ${this.lowestVal}`);
}
}
else {
const mi = ret.minInclusive;
if (mi !== undefined) {
if (mi < lowestVal) {
fail(`minInclusive cannot be lower than ${this.lowestVal}`);
}
}
else {
ret.minInclusive = lowestVal;
}
}
}
return ret;
}
}
class nonPositiveInteger extends integer {
constructor() {
super(...arguments);
this.name = "nonPositiveInteger";
this.typeErrorMsg = "value is not a nonPositiveInteger";
this.regexp = /^\s*\+?0+|-\d+\s*$/;
this.highestVal = 0;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class negativeInteger extends nonPositiveInteger {
constructor() {
super(...arguments);
this.name = "negativeInteger";
this.typeErrorMsg = "value is not a negativeInteger";
this.regexp = /^\s*-\d+\s*$/;
this.highestVal = -1;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class nonNegativeInteger extends integer {
constructor() {
super(...arguments);
this.name = "nonNegativeInteger";
this.typeErrorMsg = "value is not a nonNegativeInteger";
this.regexp = /^\s*(\+?\d+|-0)\s*$/;
this.lowestVal = 0;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class positiveInteger extends nonNegativeInteger {
constructor() {
super(...arguments);
this.name = "positiveInteger";
this.typeErrorMsg = "value is not a positiveInteger";
this.regexp = /^\s*\+?\d+\s*$/;
this.lowestVal = 1;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class long_ extends integer {
constructor() {
super(...arguments);
this.name = "long";
this.typeErrorMsg = "value is not a long";
this.highestVal = 9223372036854775807;
this.lowestVal = -9223372036854775808;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class int_ extends long_ {
constructor() {
super(...arguments);
this.name = "int";
this.typeErrorMsg = "value is not an int";
this.highestVal = 2147483647;
this.lowestVal = -2147483648;
}
}
class short_ extends int_ {
constructor() {
super(...arguments);
this.name = "short";
this.typeErrorMsg = "value is not a short";
this.highestVal = 32767;
this.lowestVal = -32768;
}
}
class byte_ extends short_ {
constructor() {
super(...arguments);
this.name = "byte";
this.typeErrorMsg = "value is not a byte";
this.highestVal = 127;
this.lowestVal = -128;
}
}
class unsignedLong extends nonNegativeInteger {
constructor() {
super(...arguments);
this.name = "unsignedLong";
this.typeErrorMsg = "value is not an unsignedLong";
this.highestVal = 18446744073709551615;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class unsignedInt extends unsignedLong {
constructor() {
super(...arguments);
this.name = "unsignedInt";
this.typeErrorMsg = "value is not an unsignedInt";
this.highestVal = 4294967295;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class unsignedShort extends unsignedInt {
constructor() {
super(...arguments);
this.name = "unsignedShort";
this.typeErrorMsg = "value is not an unsignedShort";
this.highestVal = 65535;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class unsignedByte extends unsignedShort {
constructor() {
super(...arguments);
this.name = "unsignedByte";
this.typeErrorMsg = "value is not an unsignedByte";
this.highestVal = 255;
this.validParams = [
totalDigitsP, patternP, minExclusiveP, minInclusiveP, maxExclusiveP,
maxInclusiveP,
];
}
}
class boolean_ extends Base {
constructor() {
super(...arguments);
this.name = "boolean";
this.typeErrorMsg = "not a valid boolean";
this.regexp = /^\s*(1|0|true|false)\s*$/;
this.validParams = [patternP];
this.needsContext = false;
}
convertValue(value) {
return (value === "1" || value === "true");
}
}
const B04 = "[AQgw]";
const B16 = "[AEIMQUYcgkosw048]";
const B64 = "[A-Za-z0-9+/]";
const B64S = `(?:${B64}\\s*)`;
const B16S = `(?:${B16}\\s*)`;
const B04S = `(?:${B04}\\s*)`;
const base64BinaryRe = new RegExp(`^\\s*(?:(?:${B64S}{4})*(?:(?:${B64S}{3}${B64})|(?:${B64S}{2}${B16S}=)|(?:` +
`${B64S}${B04S}= ?=)))?\\s*$`);
class base64Binary extends Base {
constructor() {
super(...arguments);
this.name = "base64Binary";
this.typeErrorMsg = "not a valid base64Binary";
this.regexp = base64BinaryRe;
this.needsContext = false;
this.validParams = [lengthP, minLengthP, maxLengthP, patternP];
}
convertValue(value) {
// We don't need to actually decode it.
return value.replace(/\s/g, "");
}
valueLength(value) {
// Length of the decoded value.
return Math.floor((value.replace(/[\s=]/g, "").length * 3) / 4);
}
}
class hexBinary extends Base {
constructor() {
super(...arguments);
this.name = "hexBinary";
this.typeErrorMsg = "not a valid hexBinary";
this.regexp = /^\s*(?:[0-9a-fA-F]{2})*\s*$/;
this.needsContext = false;
this.validParams = [lengthP, minLengthP, maxLengthP, patternP];
}
convertValue(value) {
return value;
}
valueLength(value) {
// Length of the byte list.
return value.length / 2;
}
}
const doubleRe = new RegExp(`^\\s*(?:(?:[-+]?INF)|(?:NaN)|(?:${decimalPattern}\
(?:[Ee]${integerPattern})?))\\s*$`);
class float_ extends Base {
constructor() {
super(...arguments);
this.name = "float";
this.typeErrorMsg = "not a valid float";
this.regexp = doubleRe;
this.needsContext = false;
this.validParams = [
patternP, minInclusiveP, minExclusiveP, maxInclusiveP, maxExclusiveP,
];
}
convertValue(value) {
return convertToInternalNumber(value);
}
equal(value, schemaValue) {
const converted = this.convertValue(value);
// In the IEEE 754-1985 standard, which is what XMLSChema 1.0 follows, NaN
// is equal to NaN. In JavaScript NaN is equal to nothing, not even itself.
// So we need to handle this difference.
if (isNaN(converted)) {
return isNaN(schemaValue.value);
}
return converted === schemaValue.value;
}
}
class double_ extends float_ {
constructor() {
super(...arguments);
this.name = "double";
this.typeErrorMsg = "not a valid double";
}
}
class QName extends Base {
constructor() {
super(...arguments);
this.name = "QName";
this.typeErrorMsg = "not a valid QName";
this.regexp = new RegExp(`^\\s*(?:${xmlcharacters_1.xmlNcname}:)?${xmlcharacters_1.xmlNcname}\\s*$`);
this.needsContext = true;
this.validParams = [patternP, lengthP, minLengthP, maxLengthP];
}
disallows(value, params, context) {
if (!this.regexp.test(value)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
const converted = this.convertValue(value, context);
if (converted instanceof Array) {
return converted;
}
const paramNames = Object.keys(params);
if (paramNames.length === 0) {
return false;
}
const errors = [];
for (const name of paramNames) {
const param = PARAM_NAME_TO_OBJ[name];
const err = param.isInvalidValue(converted, params[name], this);
if (err) {
errors.push(err);
}
}
return (errors.length !== 0) ? errors : false;
}
convertValue(value, context) {
const ret = context.resolver.resolveName(value.trim());
if (ret === undefined) {
return [new errors_1.ValueError(`cannot resolve the name ${value}`)];
}
return `{${ret.ns}}${ret.name}`;
}
}
class NOTATION extends Base {
constructor() {
super(...arguments);
this.name = "NOTATION";
this.typeErrorMsg = "not a valid NOTATION";
this.regexp = new RegExp(`^\\s*(?:${xmlcharacters_1.xmlNcname}:)?${xmlcharacters_1.xmlNcname}\\s*$`);
this.needsContext = true;
this.validParams = [patternP, lengthP, minLengthP, maxLengthP];
}
disallows(value, params, context) {
if (!this.regexp.test(value)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
const converted = this.convertValue(value, context);
if (converted instanceof Array) {
return converted;
}
const paramNames = Object.keys(params);
if (paramNames.length === 0) {
return false;
}
const errors = [];
for (const name of paramNames) {
const param = PARAM_NAME_TO_OBJ[name];
const err = param.isInvalidValue(converted, params[name], this);
if (err) {
errors.push(err);
}
}
return (errors.length !== 0) ? errors : false;
}
convertValue(value, context) {
const ret = context.resolver.resolveName(value.trim());
if (ret === undefined) {
return [new errors_1.ValueError(`cannot resolve the name ${value}`)];
}
return `{${ret.ns}}${ret.name}`;
}
}
class duration extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "duration";
this.typeErrorMsg = "not a valid duration";
this.regexp =
// tslint:disable-next-line:max-line-length
/^\s*-?P(?!$)(?:\d+Y)?(?:\d+M)?(?:\d+D)?(?:T(?!$)(?:\d+H)?(?:\d+M)?(?:\d+(\.\d+)?S)?)?\s*$/;
this.validParams = [patternP];
this.needsContext = false;
}
}
const yearPattern = "-?(?:[1-9]\\d*)?\\d{4}";
const monthPattern = "[01]\\d";
const domPattern = "[0-3]\\d";
const timePattern = "[012]\\d:[0-5]\\d:[0-5]\\d(?:\\.\\d+)?";
const tzPattern = "(?:[+-][01]\\d:[0-5]\\d|Z)";
const tzRe = new RegExp(`${tzPattern}$`);
function isLeapYear(year) {
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
}
const dateGroupingRe = new RegExp(`^\\s*(${yearPattern})-(${monthPattern})-(${domPattern})T(${timePattern})` +
`(${tzPattern}?)\\s*$`);
const maxDoms = [undefined, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function checkDate(value) {
// The Date.parse method of JavaScript is not reliable.
const match = value.match(dateGroupingRe);
if (match === null) {
return false;
}
const year = match[1];
const leap = isLeapYear(Number(year));
const month = Number(match[2]);
if (month === 0 || month > 12) {
return false;
}
const dom = Number(match[3]);
// We cannot have an undefined value here... so...
// tslint:disable-next-line:no-non-null-assertion
let maxDom = maxDoms[month];
if (month === 2 && !leap) {
maxDom = 28;
}
if (dom === 0 || dom > maxDom) {
return false;
}
const timeParts = match[4].split(":");
const minutes = Number(timeParts[1]);
if (minutes > 59) {
return false;
}
const seconds = Number(timeParts[2]);
if (seconds > 59) {
return false;
}
// 24 is valid if minutes and seconds are at 0, otherwise 23 is the
// limit.
const hoursLimit = (minutes === 0 && seconds === 0) ? 24 : 23;
if (Number(timeParts[0]) > hoursLimit) {
return false;
}
if (match[5] !== undefined && match[5] !== "" && match[5] !== "Z") {
// We have a TZ
const tzParts = match[5].split(":");
// Slice: skip the sign.
const tzHours = Number(tzParts[0].slice(1));
if (tzHours > 14) {
return false;
}
const tzSeconds = Number(tzParts[1]);
if (tzSeconds > 59) {
return false;
}
if (tzHours === 14 && tzSeconds !== 0) {
return false;
}
}
return true;
}
class dateTime extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "dateTime";
this.typeErrorMsg = "not a valid dateTime";
this.regexp = new RegExp(`^\\s*${yearPattern}-${monthPattern}-${domPattern}` +
`T${timePattern}${tzPattern}?\\s*$`);
this.needsContext = false;
this.validParams = [patternP];
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret instanceof Array) {
return ret;
}
if (!checkDate(value)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class time extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "time";
this.typeErrorMsg = "not a valid time";
this.regexp = new RegExp(`^\\s*${timePattern}${tzPattern}?\\s*$`);
this.validParams = [patternP];
this.needsContext = false;
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// Date does not validate times, so set the date to something fake.
if (!checkDate(`1901-01-01T${value}`)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class date extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "date";
this.typeErrorMsg = "not a valid date";
this.regexp = new RegExp(`^\\s*${yearPattern}-${monthPattern}-${domPattern}${tzPattern}?\\s*$`);
this.needsContext = false;
this.validParams = [patternP];
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// We have to add time for Date() to parse it.
const match = value.match(tzRe);
const withTime = match !== null ?
`${value.slice(0, match.index)}T00:00:00${match[0]}` :
`${value}T00:00:00`;
if (!checkDate(withTime)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class gYearMonth extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "gYearMonth";
this.typeErrorMsg = "not a valid gYearMonth";
this.regexp = new RegExp(`^\\s*${yearPattern}-${monthPattern}${tzPattern}?\\s*$`);
this.validParams = [patternP];
this.needsContext = false;
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// We have to add a day and time for Date() to parse it.
const match = value.match(tzRe);
const withTime = match !== null ?
`${value.slice(0, match.index)}-01T00:00:00${match[0]}` :
`${value}-01T00:00:00`;
if (!checkDate(withTime)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class gYear extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "gYear";
this.typeErrorMsg = "not a valid gYear";
this.regexp = new RegExp(`^\\s*${yearPattern}${tzPattern}?\\s*$`);
this.needsContext = false;
this.validParams = [patternP];
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// We have to add a month, a day and a time for Date() to parse it.
const match = value.match(tzRe);
const withTime = match !== null ?
`${value.slice(0, match.index)}-01-01T00:00:00${match[0]}` :
`${value}-01-01T00:00:00`;
if (!checkDate(withTime)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class gMonthDay extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "gMonthDay";
this.typeErrorMsg = "not a valid gMonthDay";
this.regexp = new RegExp(`^\\s*${monthPattern}-${domPattern}${tzPattern}?\\s*$`);
this.needsContext = false;
this.validParams = [patternP];
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// We have to add a year and a time for Date() to parse it.
const match = value.match(tzRe);
const withTime = match !== null ?
`${value.slice(0, match.index)}T00:00:00${match[0]}` :
`${value}T00:00:00`;
// We always add 2000, which is a leap year, so 01-29 won't raise an
// error.
if (!checkDate(`2000-${withTime}`)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class gDay extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "gDay";
this.typeErrorMsg = "not a valid gDay";
this.regexp = new RegExp(`^\\s*${domPattern}${tzPattern}?\\s*$`);
this.needsContext = false;
this.validParams = [patternP];
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// We have to add a year and a time for Date() to parse it.
const match = value.match(tzRe);
const withTime = match !== null ?
`${value.slice(0, match.index)}T00:00:00${match[0]}` :
`${value}T00:00:00`;
// We always add 2000, which is a leap year, so 01-29 won't raise an
// error.
if (!checkDate(`2000-01-${withTime}`)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
class gMonth extends CommonStringBased {
constructor() {
super(...arguments);
this.name = "gMonth";
this.typeErrorMsg = "not a valid gMonth";
this.regexp = new RegExp(`^\\s*${monthPattern}${tzPattern}?\\s*$`);
this.needsContext = false;
this.validParams = [patternP];
}
disallows(value, params) {
const ret = super.disallows(value, params);
if (ret) {
return ret;
}
// We have to add a year and a time for Date() to parse it.
const match = value.match(tzRe);
const withTime = match !== null ?
`${value.slice(0, match.index)}-01T00:00:00${match[0]}` :
`${value}-01T00:00:00`;
// We always add 2000, which is a leap year, so 01-29 won't raise an
// error.
if (!checkDate(`2000-${withTime}`)) {
return [new errors_1.ValueError(this.typeErrorMsg)];
}
return false;
}
}
//
// See
// https://www.w3.org/TR/2012/REC-xmlschema11-2-20120405/datatypes.html#anyURI
//
// Though the specification referred above above does not require any syntactic
// checks, in practice Jing reports errors on malformed URIs. We follow Jing's
// lead.
//
// tslint:disable-next-line:max-line-length
// Derived from https://stackoverflow.com/questions/161738/what-is-the-best-regular-expression-to-check-if-a-string-is-a-valid-url/190405#190405
// tslint:disable-next-line:max-line-length
// @ts-expect-error
const reJsRfc3987UriReference = /^\s*(?:[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD}!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\uE000-\uF8FF\uF0000-\uFFFFD\u100000-\u10FFFD\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\/\?])*)?|(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\uA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uD