+
+/**
+ * Maps each digit to its numerical value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-digitVal>.
+ *
+ * ☡ This function throws if the provided value is not a digit string.
+ *
+ * ※ This function is not exposed.
+ */
+const digitValue = (d) => +ensureMatches(lexicalDigit, d);
+
+/**
+ * Maps a sequence of digits to the position‐weighted sum of the terms
+ * numerical values.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-digitSeqVal>.
+ *
+ * ☡ This function throws if the provided value is not an iterable of
+ * digit strings.
+ *
+ * ※ Although elsewhere the X·S·D specification claims that sequences
+ * count from zero, this sequence clearly must count from one.
+ *
+ * ※ This function is not exposed.
+ */
+const digitSequenceValue = (S) => {
+ let sum = 0;
+ for (const S_i of S) {
+ sum = sum * 10 + digitValue(S_i);
+ }
+ return sum;
+};
+
+/**
+ * Maps a sequence of digits to the position‐weighted sum of the terms
+ * numerical values, weighted appropriately for fractional digits.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-fracDigitSeqVal>.
+ *
+ * ☡ This function throws if the provided value is not an iterable of
+ * digit strings.
+ *
+ * ※ The X·S·D specification erroneously specifies ·digitValue·(Si) −
+ * 10^(−i), but ·digitValue·(Si) × 10^(−i) is correct.
+ *
+ * ※ Although elsewhere the X·S·D specification claims that sequences
+ * count from zero, this sequence clearly must count from one.
+ *
+ * ※ This function is not exposed.
+ */
+const fractionDigitSequenceValue = (S) => {
+ let sum = 0;
+ let i = 0;
+ for (const S_i of S) {
+ sum += digitValue(S_i) * 10 ** --i;
+ }
+ return sum;
+};
+
+/**
+ * Maps a fracFrag to the appropriate fractional decimal number.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-fracFragVal>.
+ *
+ * ☡ This function throws if the provided value is not a fracFrag
+ * string.
+ *
+ * ※ This function is not exposed.
+ */
+//deno-lint-ignore no-unused-vars
+const fractionFragValue = (N) =>
+ fractionDigitSequenceValue(
+ literalSequence(ensureMatches(fracFrag, N)),
+ );
+
+/**
+ * Maps an unsignedNoDecimalPtNumeral to its numerical value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-unsNoDecVal>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * unsignedNoDecimalPtNumeral string.
+ */
+export const unsignedNoDecimalMap = (N) =>
+ digitSequenceValue(
+ literalSequence(ensureMatches(unsignedNoDecimalPtNumeral, N)),
+ );
+
+/**
+ * Maps an noDecimalPtNumeral to its numerical value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-noDecVal>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * noDecimalPtNumeral string.
+ */
+export const noDecimalMap = (N) => {
+ switch (ensureMatches(noDecimalPtNumeral, N)[0]) {
+ case "-":
+ return -unsignedNoDecimalMap(substring(N, 1)) || 0;
+ case "+":
+ return unsignedNoDecimalMap(substring(N, 1));
+ default:
+ return unsignedNoDecimalMap(N);
+ }
+};
+
+/**
+ * Maps an unsignedDecimalPtNumeral to its numerical value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-unsDecVal>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * unsignedDecimalPtNumeral string.
+ *
+ * ※ This function makes use of the built·in Ecmascript float parsing
+ * to avoid rounding errors.
+ */
+export const unsignedDecimalPtMap = (D) => {
+ // const N = substring(
+ // ensureMatches(unsignedDecimalPtNumeral, D),
+ // 0,
+ // getFirstSubstringIndex(D, "."),
+ // );
+ // const F = substring(D, N.length + 1);
+ // if (F === "") {
+ // return unsignedNoDecimalMap(N);
+ // } else if (N === "") {
+ // return fractionFragValue(F);
+ // } else {
+ // return unsignedNoDecimalMap(N) + fractionFragValue(F);
+ // }
+ return stringToFloat(ensureMatches(unsignedDecimalPtNumeral, D));
+};
+
+/**
+ * Maps an decimalPtNumeral to its numerical value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-decVal>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * decimalPtNumeral string.
+ */
+export const decimalPtMap = (N) => {
+ switch (ensureMatches(decimalPtNumeral, N)[0]) {
+ case "-":
+ return -unsignedDecimalPtMap(substring(N, 1)) || 0;
+ case "+":
+ return unsignedDecimalPtMap(substring(N, 1));
+ default:
+ return unsignedDecimalPtMap(N);
+ }
+};
+
+/**
+ * Maps a scientificNotationNumeral to its numerical value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-sciVal>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * scientificNotationNumeral string.
+ *
+ * ※ The X·S·D specification erroneously specifies
+ * ·unsignedDecimalPtMap·(E), but ·noDecimalMap·(E) is correct.
+ *
+ * ※ This function makes use of the built·in Ecmascript float parsing
+ * to avoid rounding errors.
+ */
+export const scientificMap = (N) => {
+ // const C = substring(
+ // ensureMatches(scientificNotationNumeral, N),
+ // 0,
+ // (() => {
+ // let index = 0;
+ // for (const char of literalSequence(N)) {
+ // if (char === "e" || char === "E") {
+ // return index;
+ // } else {
+ // ++index;
+ // continue;
+ // }
+ // }
+ // })(),
+ // );
+ // const E = substring(N, C.length + 1);
+ // return getFirstSubstringIndex(N, ".") !== -1
+ // ? decimalPtMap(C) * 10 ** noDecimalMap(E)
+ // : noDecimalMap(C) * 10 ** noDecimalMap(E);
+ return stringToFloat(ensureMatches(scientificNotationNumeral, N)) ||
+ 0;
+};
+
+/**
+ * Maps each integer between 0 and 9 to the corresponding digit.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-digit>.
+ *
+ * ☡ This function throws if the provided value is not an integral
+ * number between 0 and 9 inclusive.
+ *
+ * ※ This function is not exposed.
+ */
+const digit = (i) => {
+ if (!(isIntegralNumber(i) && i >= 0 && i <= 9)) {
+ throw new TypeError(
+ `सूत्र: Expected an integral number between 0 and 9 inclusive, but got: ${i}.`,
+ );
+ } else {
+ return `${i}`;
+ }
+};
+
+/**
+ * Maps each nonnegative integer to a sequence of integers used by
+ * ·digitSeq· to ultimately create an unsignedNoDecimalPtNumeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-digitRemSeq>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ *
+ * ※ The sequence produced by this function is infinite.
+ *
+ * ※ This function is not exposed.
+ */
+const digitRemainderSeq = (i) => {
+ nonnegativeInteger(i);
+ return generatorSequence(function* () {
+ let s_j = i;
+ while (true) {
+ yield s_j;
+ s_j = div(s_j, 10);
+ }
+ });
+};
+
+/**
+ * Maps each nonnegative integer to a sequence of integers used by
+ * ·unsignedNoDecimalPtCanonicalMap· to create an
+ * unsignedNoDecimalPtNumeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-digitSeq>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ *
+ * ※ The sequence produced by this function is infinite.
+ *
+ * ※ This function is not exposed.
+ */
+const digitSeq = (i) => {
+ nonnegativeInteger(i);
+ return generatorSequence(function* () {
+ for (const i_j of digitRemainderSeq(i)) {
+ yield mod(i_j, 10);
+ }
+ });
+};
+
+/**
+ * Maps a sequence of nonnegative integers to the index before the
+ * first zero term.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-lastSigDigit>.
+ *
+ * ☡ This function throws if the values of the provided sequence are
+ * not nonnegative integers.
+ *
+ * ※ The X·S·D specification erroneously describes this function as
+ * giving the index *of* the first zero term, but it is actually the
+ * index of the last nonzero term.
+ *
+ * ※ The X·S·D specification erroneously describes this function as
+ * taking a sequence of nonnegative integers, but it is called with
+ * ·FractionDigitRemainderSeq·, which is a list of nonnegative decimal
+ * numbers.
+ *
+ * ※ This function is not exposed.
+ */
+const lastSignificantDigit = (s) => {
+ let j = 0;
+ for (const s_j of s) {
+ if (nonnegativeDecimalNumber(s_j) === 0) {
+ return j === 0 ? 0 : j - 1;
+ } else {
+ ++j;
+ continue;
+ }
+ }
+};
+
+/**
+ * Maps each nonnegative decimal number less than 1 to a sequence of
+ * decimal numbers used by ·fractionDigitSeq· to ultimately create an
+ * unsignedNoDecimalPtNumeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-fracDigitRemSeq>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number less than 1.
+ *
+ * ※ The X·S·D specification erroneously specifies s_0 = f − 10 and
+ * s_(j+1) = (s_j ·mod· 1) − 10, but s_0 = f × 10 and s_(j+1) = (s_j
+ * ·mod· 1) × 10 is correct.
+ *
+ * ※ The implementation of this function uses string operations
+ * because Ecmascript does not (currently) have a lossless decimal
+ * type.
+ *
+ * ※ The sequence produced by this function is infinite.
+ *
+ * ※ This function is not exposed.
+ */
+const FractionDigitRemainderSeq = (f) => {
+ if (!(isFiniteNumber(f) && f >= 0 && f < 1)) {
+ throw new TypeError(
+ `सूत्र: Expected a nonnegative finite number less than 1, but got: ${f}.`,
+ );
+ } else {
+ return generatorSequence(function* () {
+ let s_j = f * 10;
+ while (true) {
+ yield s_j;
+ s_j = mod(s_j, 1) * 10;
+ }
+ });
+ }
+};
+
+/**
+ * Maps each nonnegative decimal number less than 1 to a sequence of
+ * integers used by ·fractionDigitsCanonicalFragmentMap· to ultimately
+ * create an unsignedNoDecimalPtNumeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-fracDigitSeq>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number less than 1.
+ *
+ * ※ The sequence produced by this function is infinite.
+ *
+ * ※ This function is not exposed.
+ */
+const fractionDigitSeq = (f) => {
+ if (!(isFiniteNumber(f) && f >= 0 && f < 1)) {
+ throw new TypeError(
+ `सूत्र: Expected a nonnegative finite number less than 1, but got: ${f}.`,
+ );
+ } else {
+ return generatorSequence(function* () {
+ for (const s_j of FractionDigitRemainderSeq(f)) {
+ yield div(s_j, 1);
+ }
+ });
+ }
+};
+
+/**
+ * Maps each nonnegative decimal number less than 1 to a ·literal· used
+ * by ·unsignedDecimalPtCanonicalMap· to create an
+ * unsignedDecimalPtNumeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-fracDigitsMap>.
+ *
+ * ☡ This function throws if the provided value is not nonnegative and
+ * less than 1.
+ *
+ * ※ This function is not exposed.
+ */
+//deno-lint-ignore no-unused-vars
+const fractionDigitsCanonicalFragmentMap = (f) =>
+ stringCatenate(...generatorSequence(function* () {
+ const l = lastSignificantDigit(FractionDigitRemainderSeq(f));
+ let j = 0;
+ for (const f_j of fractionDigitSeq(f)) {
+ yield digit(f_j);
+ if (j === l) {
+ break;
+ } else {
+ ++j;
+ continue;
+ }
+ }
+ }));
+
+/**
+ * Maps a nonnegative integer to a unsignedNoDecimalPtNumeral, its
+ * ·canonical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-unsNoDecCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ */
+export const unsignedNoDecimalPtCanonicalMap = (i) => {
+ nonnegativeInteger(i);
+ return stringCatenate(...generatorSequence(function* () {
+ const l = lastSignificantDigit(digitRemainderSeq(i));
+ const digits = new Array(l + 1);
+ let j = 0;
+ for (const i_j of digitSeq(i)) {
+ digits[l - j] = digit(i_j);
+ if (j === l) {
+ break;
+ } else {
+ ++j;
+ continue;
+ }
+ }
+ for (j = 0; j <= l; ++j) {
+ yield digits[j];
+ }
+ }));
+};
+
+/**
+ * Maps an integer to a noDecimalPtNumeral, its ·canonical
+ * representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-noDecCanMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer.
+ */
+export const noDecimalPtCanonicalMap = (i) =>
+ integer(i) < 0
+ ? stringCatenate("-", unsignedNoDecimalPtCanonicalMap(-i))
+ : unsignedNoDecimalPtCanonicalMap(i);
+
+/**
+ * Maps a nonnegative decimal number to a unsignedDecimalPtNumeral, its
+ * ·canonical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-unsDecCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number.
+ *
+ * ※ This function makes use of the built·in Ecmascript float
+ * serialization to avoid rounding errors.
+ */
+export const unsignedDecimalPtCanonicalMap = (n) => {
+ // nonnegativeDecimalNumber(n);
+ // return stringCatenate(
+ // unsignedNoDecimalPtCanonicalMap(div(n, 1)),
+ // ".",
+ // fractionDigitsCanonicalFragmentMap(mod(n, 1)),
+ // );
+ const exp = toExponentialNotation(nonnegativeDecimalNumber(n));
+ const eIndex = getFirstSubstringIndex(exp, "e");
+ const exponent = +substring(exp, eIndex + 1);
+ const zeroPaddedMantissa = stringPadEnd(
+ stringPadStart(
+ exp[0],
+ -exponent + 1,
+ "0",
+ ) + (eIndex > 1 ? substring(exp, 2, eIndex) : ""),
+ exponent + 2,
+ "0",
+ );
+ const decimalPoint = exponent < 0 ? 1 : exponent + 1;
+ return stringCatenate(
+ substring(zeroPaddedMantissa, 0, decimalPoint),
+ ".",
+ substring(zeroPaddedMantissa, decimalPoint),
+ );
+};
+
+/**
+ * Maps a decimal number to a decimalPtNumeral, its ·canonical
+ * representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-decCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a finite number.
+ */
+export const decimalPtCanonicalMap = (n) =>
+ decimalNumber(n) < 0
+ ? stringCatenate("-", unsignedDecimalPtCanonicalMap(-n))
+ : unsignedDecimalPtCanonicalMap(n);
+
+/**
+ * Maps a nonnegative decimal number to a
+ * unsignedScientificNotationNumeral, its ·canonical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-unsSciCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number.
+ *
+ * ※ This function makes use of the built·in Ecmascript float
+ * serialization to avoid rounding errors.
+ */
+export const unsignedScientificCanonicalMap = (n) => {
+ // nonnegativeDecimalNumber(n);
+ // return stringCatenate(
+ // unsignedDecimalPtCanonicalMap(n / 10 ** div(log10(n), 1)),
+ // "E",
+ // noDecimalPtCanonicalMap(div(log10(n), 1)),
+ // );
+ const exp = toExponentialNotation(nonnegativeDecimalNumber(n));
+ const [mantissa, exponent] = stringSplit(exp, "e");
+ return stringCatenate(
+ mantissa,
+ stringIncludes(mantissa, ".") ? "E" : ".0E",
+ exponent[0] === "+" ? substring(exponent, 1) : exponent,
+ );
+};
+
+/**
+ * Maps a decimal number to a scientificNotationNumeral, its ·canonical
+ * representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-sciCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a finite number.
+ */
+export const scientificCanonicalMap = (n) =>
+ decimalNumber(n) < 0
+ ? stringCatenate("-", unsignedScientificCanonicalMap(-n))
+ : unsignedScientificCanonicalMap(n);
+
+/**
+ * Maps the ·lexical representations· of ·special values· used with
+ * some numerical datatypes to those ·special values·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-specRepVal>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * numericalSpecialRep string.
+ */
+export const specialRepValue = (c) => {
+ switch (ensureMatches(numericalSpecialRep, c)) {
+ case "INF":
+ case "+INF":
+ return positiveInfinity;
+ case "-INF":
+ return negativeInfinity;
+ case "NaN":
+ return notANumber;
+ }
+};
+
+/**
+ * Maps the ·special values· used with some numerical datatypes to
+ * their ·canonical representations·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-specValCanMap>.
+ *
+ * ☡ This function throws if the provided value is not nan or positive
+ * or negative infinity.
+ */
+export const specialRepCanonicalMap = (c) => {
+ if (sameValue(c, positiveInfinity)) {
+ return "INF";
+ } else if (sameValue(c, negativeInfinity)) {
+ return "-INF";
+ } else if (sameValue(c, notANumber)) {
+ return "NaN";
+ } else {
+ throw new TypeError(
+ `सूत्र: Expected a special value, but got: ${c}.`,
+ );
+ }
+};
+
+/**
+ * Maps a decimalLexicalRep onto a decimal value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-decimalLexmap>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * decimalLexicalRep string.
+ */
+export const decimalLexicalMap = (LEX) => {
+ ensureMatches(decimalLexicalRep, LEX);
+ if (noDecimalPtNumeral(LEX)) {
+ return noDecimalMap(LEX);
+ } else if (decimalPtNumeral(LEX)) {
+ return decimalPtMap(LEX);
+ }
+};
+
+/**
+ * Maps a decimal to its ·canonical representation·, a
+ * decimalLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-decimalCanmap>.
+ *
+ * ☡ This function throws if the provided value is not a finite number.
+ */
+export const decimalCanonicalMap = (d) =>
+ isIntegralNumber(decimalNumber(d))
+ ? noDecimalPtCanonicalMap(d)
+ : decimalPtCanonicalMap(d);
+
+/**
+ * Rounds a non-zero decimal number to the nearest floating-point
+ * value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-floatPtRound>.
+ *
+ * ☡ This function throws if the provided value is zero or is not a
+ * finite number.
+ *
+ * ※ This function uses native Ecmascript float rounding methods and
+ * only supports a cWidth of 24 or 53.
+ *
+ * ※ This function is not exposed.
+ */
+const floatingPointRound = (nV, cWidth, eMin, eMax) => {
+ if (!isFiniteNumber(nV) || nV == 0) {
+ throw new TypeError(
+ `सूत्र: Expected a finite nonzero number, but got: ${nV}.`,
+ );
+ } else if (cWidth !== 24 && cWidth !== 53) {
+ throw new TypeError(
+ `सूत्र: Unsupported cWidth: ${cWidth}.`,
+ );
+ } else if (
+ cWidth === 24 && (eMin !== -149 || eMax !== 104) ||
+ cWidth === 53 && (eMin !== -1074 || eMax !== 971)
+ ) {
+ throw new TypeError(
+ `सूत्र: Unsupported eMin and eMax for cWidth: ${cWidth}.`,
+ );
+ } else {
+ return cWidth <= 24 ? toFloat32(nV) : +nV;
+ }
+};
+
+/**
+ * Maps a decimal number to that value rounded by some power of 10.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-round>.
+ *
+ * ☡ This function throws if the provided value is not a finite number.
+ *
+ * ☡ This function throws if the provided power of 10 is not a
+ * nonnegative integer.
+ *
+ * ※ This function is not exposed.
+ */
+const round = (n, k) => {
+ decimalNumber(n);
+ nonnegativeInteger(k);
+ return div(n / 10 ** k + 0.5, 1) * 10 ** k;
+};
+
+/**
+ * Maps a decimal number (c × 10e) to successive approximations.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-round>.
+ *
+ * ☡ This function throws if the provided values are not a nonnegative
+ * integer, an integer, an a nonnegative integer.
+ *
+ * ※ This function is not exposed.
+ */
+//deno-lint-ignore no-unused-vars
+const floatApprox = (c, e, j) => {
+ nonnegativeInteger(c);
+ integer(e);
+ nonnegativeInteger(j);
+ return round(c, j) * 10 ** e;
+};
+
+/**
+ * Maps a floatRep onto a float value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-floatLexmap>.
+ *
+ * ☡ This function throws if the provided value is not a floatRep
+ * string.
+ */
+export const floatLexicalMap = (LEX) => {
+ ensureMatches(floatRep, LEX);
+ if (numericalSpecialRep(LEX)) {
+ return specialRepValue(LEX);
+ } else {
+ const nV = noDecimalPtNumeral(LEX)
+ ? noDecimalMap(LEX)
+ : decimalPtNumeral(LEX)
+ ? decimalPtMap(LEX)
+ : scientificMap(LEX);
+ const v = nV == 0 ? 0 : floatingPointRound(nV, 24, -149, 104);
+ return v == 0 ? LEX[0] === "-" ? negativeZero : positiveZero : v;
+ }
+};
+
+/**
+ * Maps a doubleRep onto a double value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-doubleLexmap>.
+ *
+ * ☡ This function throws if the provided value is not a doubleRep
+ * string.
+ */
+export const doubleLexicalMap = (LEX) => {
+ ensureMatches(doubleRep, LEX);
+ if (numericalSpecialRep(LEX)) {
+ return specialRepValue(LEX);
+ } else {
+ const nV = noDecimalPtNumeral(LEX)
+ ? noDecimalMap(LEX)
+ : decimalPtNumeral(LEX)
+ ? decimalPtMap(LEX)
+ : scientificMap(LEX);
+ const v = nV == 0 ? 0 : floatingPointRound(nV, 53, -1074, 971);
+ return v == 0 ? LEX[0] === "-" ? negativeZero : positiveZero : v;
+ }
+};
+
+/**
+ * Maps a float to its ·canonical representation·, a floatRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-floatCanmap>.
+ *
+ * ☡ This function throws if the provided value is not a 32‐bit float.
+ */
+export const floatCanonicalMap = (f) => {
+ float(f);
+ return f === positiveInfinity || f === negativeInfinity ||
+ sameValue(f, notANumber)
+ ? specialRepCanonicalMap(f)
+ : sameValue(f, 0)
+ ? "0.0E0"
+ : sameValue(f, -0)
+ ? "-0.0E0"
+ : scientificCanonicalMap(f);
+};
+
+/**
+ * Maps a double to its ·canonical representation·, a doubleRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-doubleCanmap>.
+ *
+ * ☡ This function throws if the provided value is not a number.
+ */
+export const doubleCanonicalMap = (f) => {
+ double(f);
+ return f === positiveInfinity || f === negativeInfinity ||
+ sameValue(f, notANumber)
+ ? specialRepCanonicalMap(f)
+ : sameValue(f, 0)
+ ? "0.0E0"
+ : sameValue(f, -0)
+ ? "-0.0E0"
+ : scientificCanonicalMap(f);
+};
+
+/**
+ * Maps a duYearFrag to an integer, intended as part of the value of
+ * the ·months· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duYrMap>.
+ *
+ * ☡ This function throws if the provided value is not a duYearFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously specifies the numeral as
+ * following the letter, but it precedes it.
+ *
+ * ※ This function is not exposed.
+ */
+const duYearFragmentMap = (Y) =>
+ noDecimalMap(stringSlice(ensureMatches(duYearFrag, Y), 0, -1));
+
+/**
+ * Maps a duMonthFrag to an integer, intended as part of the value of
+ * the ·months· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duMoMap>.
+ *
+ * ☡ This function throws if the provided value is not a duMonthFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously specifies the numeral as
+ * following the letter, but it precedes it.
+ *
+ * ※ This function is not exposed.
+ */
+const duMonthFragmentMap = (M) =>
+ noDecimalMap(stringSlice(ensureMatches(duMonthFrag, M), 0, -1));
+
+/**
+ * Maps a duDayFrag to an integer, intended as part of the value of the
+ * ·seconds· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duDaMap>.
+ *
+ * ☡ This function throws if the provided value is not a duDayFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously specifies the numeral as
+ * following the letter, but it precedes it.
+ *
+ * ※ This function is not exposed.
+ */
+const duDayFragmentMap = (D) =>
+ noDecimalMap(stringSlice(ensureMatches(duDayFrag, D), 0, -1));
+
+/**
+ * Maps a duHourFrag to an integer, intended as part of the value of
+ * the ·seconds· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duHrMap>.
+ *
+ * ☡ This function throws if the provided value is not a duHourFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously specifies the numeral as
+ * following the letter, but it precedes it.
+ *
+ * ※ The X·S·D specification has a copypasta typo in the definition of
+ * this function; it takes an argument H which necessarily is followed
+ * by an "H". There is no D which necessarily begins with "D".
+ *
+ * ※ This function is not exposed.
+ */
+const duHourFragmentMap = (H) =>
+ noDecimalMap(stringSlice(ensureMatches(duHourFrag, H), 0, -1));
+
+/**
+ * Maps a duMinuteFrag to an integer, intended as part of the value of
+ * the ·seconds· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duMiMap>.
+ *
+ * ☡ This function throws if the provided value is not a duMinuteFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously specifies the numeral as
+ * following the letter, but it precedes it.
+ *
+ * ※ This function is not exposed.
+ */
+const duMinuteFragmentMap = (M) =>
+ noDecimalMap(stringSlice(ensureMatches(duMinuteFrag, M), 0, -1));
+
+/**
+ * Maps a duSecondFrag to an integer, intended as part of the value of
+ * the ·seconds· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duSeMap>.
+ *
+ * ☡ This function throws if the provided value is not a duMinuteFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously specifies the numeral as
+ * following the letter, but it precedes it.
+ *
+ * ※ This function is not exposed.
+ */
+const duSecondFragmentMap = (S) =>
+ getFirstSubstringIndex(ensureMatches(duSecondFrag, S), ".") !== -1
+ ? decimalPtMap(stringSlice(S, 0, -1))
+ : noDecimalMap(stringSlice(S, 0, -1));
+
+/**
+ * Maps a duYearMonthFrag into an integer, intended as part of the
+ * ·months· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duYMMap>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * duYearMonthFrag string.
+ *
+ * ※ This function is not exposed.
+ */
+const duYearMonthFragmentMap = (YM) => {
+ let Y, M;
+ new Matcher(
+ rawString`(?<Y>\d+Y)?(?<M>\d+M)?`,
+ undefined,
+ (_, { groups }) => {
+ Y = groups.Y;
+ M = groups.M;
+ return true;
+ },
+ )(ensureMatches(duYearMonthFrag, YM));
+ const y = Y ? duYearFragmentMap(Y) : 0;
+ const m = M ? duMonthFragmentMap(M) : 0;
+ return 12 * y + m;
+};
+
+/**
+ * Maps a duTimeFrag into an integer, intended as part of the ·seconds·
+ * property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duTMap>.
+ *
+ * ☡ This function throws if the provided value is not a duTimeFrag
+ * string.
+ *
+ * ※ The X·S·D specification erroneously applies ·duDayFragmentMap· to
+ * H; ·duHourFragmentMap· is correct.
+ *
+ * ※ This function is not exposed.
+ */
+const duTimeFragmentMap = (T) => {
+ let H, M, S;
+ new Matcher(
+ rawString`T(?<H>\d+H)?(?<M>\d+M)?(?<S>[\d.]+S)?`,
+ undefined,
+ (_, { groups }) => {
+ H = groups.H;
+ M = groups.M;
+ S = groups.S;
+ return true;
+ },
+ )(ensureMatches(duTimeFrag, T));
+ const h = H ? duHourFragmentMap(H) : 0;
+ const m = M ? duMinuteFragmentMap(M) : 0;
+ const s = S ? duSecondFragmentMap(S) : 0;
+ return 3600 * h + 60 * m + s;
+};
+
+/**
+ * Maps a duDayTimeFrag into a decimal number, which is the potential
+ * value of the ·seconds· property of a duration value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duDTMap>.
+ *
+ * ☡ This function throws if the provided value is not a duDayTimeFrag
+ * string.
+ *
+ * ※ This function is not exposed.
+ */
+const duDayTimeFragmentMap = (DT) => {
+ let D, T;
+ new Matcher(
+ rawString`(?<D>\d+D)?(?<T>T.+)?`,
+ undefined,
+ (_, { groups }) => {
+ D = groups.D;
+ T = groups.T;
+ return true;
+ },
+ )(ensureMatches(duDayTimeFrag, DT));
+ const d = D ? duDayFragmentMap(D) : 0;
+ const t = T ? duTimeFragmentMap(T) : 0;
+ return 86400 * d + t;
+};
+
+/**
+ * Separates the durationLexicalRep into the month part and the seconds
+ * part, then maps them into the ·months· and ·seconds· of the duration
+ * value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-durationMap>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * durationLexicalRep string.
+ */
+export const durationMap = (DUR) => {
+ let Y, D;
+ new Matcher(
+ rawString`-?P(?<Y>(?:\d+Y)?(?:\d+M)?)(?<D>(?:\d+D)?(?:T.+)?)`,
+ undefined,
+ (_, { groups }) => {
+ Y = groups.Y;
+ D = groups.D;
+ return true;
+ },
+ )(ensureMatches(durationLexicalRep, DUR));
+ const s = DUR[0] === "-" ? -1 : 1;
+ return {
+ months: Y ? s * duYearMonthFragmentMap(Y) + 0 : 0, // cast −0 to 0
+ seconds: D ? s * duDayTimeFragmentMap(D) + 0 : 0, // cast −0 to 0
+ };
+};
+
+/**
+ * Maps the lexical representation into the ·months· of a
+ * yearMonthDuration value. (A yearMonthDuration's ·seconds· is always
+ * zero.) ·yearMonthDurationMap· is a restriction of ·durationMap·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-yearMonthDurationMap>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * yearMonthDurationLexicalRep string.
+ */
+export const yearMonthDurationMap = (YM) => {
+ const s = YM[0] === "-" ? -1 : 1;
+ const Y = substring(
+ ensureMatches(yearMonthDurationLexicalRep, YM),
+ s === -1 ? 2 : 1,
+ );
+ return {
+ months: s * duYearMonthFragmentMap(Y) + 0, // cast −0 to 0
+ seconds: 0,
+ };
+};
+
+/**
+ * Maps the lexical representation into the ·seconds· of a
+ * dayTimeDuration value. (A dayTimeDuration's ·months· is always
+ * zero.) ·dayTimeDurationMap· is a restriction of ·durationMap·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-yearMonthDurationMap>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * dayTimeDurationLexicalRep string.
+ *
+ * ※ The X·S·D specification erroneously describes the argument as a
+ * dayTimeDuration value rather than a dayTimeDurationLexicalRep.
+ */
+export const dayTimeDurationMap = (DT) => {
+ const s = DT[0] === "-" ? -1 : 1;
+ const D = substring(
+ ensureMatches(dayTimeDurationLexicalRep, DT),
+ s === -1 ? 2 : 1,
+ );
+ return {
+ months: 0,
+ seconds: s * duDayTimeFragmentMap(D) + 0, // cast −0 to 0
+ };
+};
+
+/**
+ * Maps a nonnegative integer, presumably the absolute value of the
+ * ·months· of a duration value, to a duYearMonthFrag, a fragment of a
+ * duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duYMCan>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ *
+ * ※ This function is not exposed.
+ */
+const duYearMonthCanonicalFragmentMap = (ym) => {
+ nonnegativeInteger(ym);
+ const y = div(ym, 12);
+ const m = mod(ym, 12);
+ return y !== 0 && m !== 0
+ ? stringCatenate(
+ unsignedNoDecimalPtCanonicalMap(y),
+ "Y",
+ unsignedNoDecimalPtCanonicalMap(m),
+ "M",
+ )
+ : y !== 0
+ ? stringCatenate(
+ unsignedNoDecimalPtCanonicalMap(y),
+ "Y",
+ )
+ : stringCatenate(
+ unsignedNoDecimalPtCanonicalMap(m),
+ "M",
+ );
+};
+
+/**
+ * Maps a nonnegative integer, presumably the day normalized value from
+ * the ·seconds· of a duration value, to a duDayFrag, a fragment of a
+ * duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duDCan>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ *
+ * ※ Despite the description, this function does not necessarily
+ * return a duDayFrag (it can return an empty string).
+ *
+ * ※ This function is not exposed.
+ */
+const duDayCanonicalFragmentMap = (d) =>
+ d !== 0
+ ? stringCatenate(
+ unsignedNoDecimalPtCanonicalMap(d),
+ "D",
+ )
+ : "";
+
+/**
+ * Maps a nonnegative integer, presumably the hour normalized value
+ * from the ·seconds· of a duration value, to a duHourFrag, a fragment
+ * of a duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duHCan>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ *
+ * ※ Despite the description, this function does not necessarily
+ * return a duHourFrag (it can return an empty string).
+ *
+ * ※ This function is not exposed.
+ */
+const duHourCanonicalFragmentMap = (h) =>
+ h !== 0
+ ? stringCatenate(
+ unsignedNoDecimalPtCanonicalMap(h),
+ "H",
+ )
+ : "";
+
+/**
+ * Maps a nonnegative integer, presumably the minute normalized value
+ * from the ·seconds· of a duration value, to a duMinuteFrag, a
+ * fragment of a duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duMCan>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer.
+ *
+ * ※ Despite the description, this function does not necessarily
+ * return a duMinuteFrag (it can return an empty string).
+ *
+ * ※ This function is not exposed.
+ */
+const duMinuteCanonicalFragmentMap = (m) =>
+ m !== 0
+ ? stringCatenate(
+ unsignedNoDecimalPtCanonicalMap(m),
+ "M",
+ )
+ : "";
+
+/**
+ * Maps a nonnegative decimal number, presumably the second normalized
+ * value from the ·seconds· of a duration value, to a duSecondFrag, a
+ * fragment of a duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duSCan>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number.
+ *
+ * ※ Despite the description, this function does not necessarily
+ * return a duSecondFrag (it can return an empty string).
+ *
+ * ※ This function is not exposed.
+ */
+const duSecondCanonicalFragmentMap = (s) =>
+ s !== 0
+ ? stringCatenate(
+ isIntegralNumber(s)
+ ? unsignedNoDecimalPtCanonicalMap(s)
+ : unsignedDecimalPtCanonicalMap(s),
+ "S",
+ )
+ : "";
+
+/**
+ * Maps three nonnegative numbers, presumably the hour, minute, and
+ * second normalized values from a duration's ·seconds·, to a
+ * duTimeFrag, a fragment of a duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duTCan>.
+ *
+ * ☡ This function throws if either of the first two provided values
+ * are not nonnegative integers, or if the final provided value is not
+ * a nonnegative finite number.
+ *
+ * ※ Despite the description, this function does not necessarily
+ * return a duTimeFrag (it can return an empty string).
+ *
+ * ※ This function is not exposed.
+ */
+const duTimeCanonicalFragmentMap = (h, m, s) =>
+ h !== 0 || m !== 0 || s !== 0
+ ? stringCatenate(
+ "T",
+ duHourCanonicalFragmentMap(h),
+ duMinuteCanonicalFragmentMap(m),
+ duSecondCanonicalFragmentMap(s),
+ )
+ : "";
+
+/**
+ * Maps a nonnegative decimal number, presumably the absolute value of
+ * the ·seconds· of a duration value, to a duDayTimeFrag, a fragment of
+ * a duration ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-duDTCan>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number.
+ *
+ * ※ This function is not exposed.
+ */
+const duDayTimeCanonicalFragmentMap = (ss) => {
+ nonnegativeDecimalNumber(ss);
+ const d = div(ss, 86400);
+ const h = div(mod(ss, 86400), 3600);
+ const m = div(mod(ss, 3600), 60);
+ const s = mod(ss, 60);
+ return ss !== 0
+ ? stringCatenate(
+ duDayCanonicalFragmentMap(d),
+ duTimeCanonicalFragmentMap(h, m, s),
+ )
+ : "T0S";
+};
+
+/**
+ * Maps a duration's property values to durationLexicalRep fragments
+ * and combines the fragments into a complete durationLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-durationCanMap>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * duration value.
+ */
+export const durationCanonicalMap = (v) => {
+ const { months: m, seconds: s } = duration(v);
+ const sgn = m < 0 || s < 0 ? "-" : "";
+ return m !== 0 && s !== 0
+ ? stringCatenate(
+ sgn,
+ "P",
+ duYearMonthCanonicalFragmentMap(abs(m)),
+ duDayTimeCanonicalFragmentMap(abs(s)),
+ )
+ : m !== 0
+ ? stringCatenate(
+ sgn,
+ "P",
+ duYearMonthCanonicalFragmentMap(abs(m)),
+ )
+ : stringCatenate(
+ sgn,
+ "P",
+ duDayTimeCanonicalFragmentMap(abs(s)),
+ );
+};
+
+/**
+ * Maps a yearMonthDuration's ·months· value to a
+ * yearMonthDurationLexicalRep. (The ·seconds· value is necessarily
+ * zero and is ignored.) ·yearMonthDurationCanonicalMap· is a
+ * restriction of ·durationCanonicalMap·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-yearMonthDurationCanMap>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * yearMonthDuration value.
+ */
+export const yearMonthDurationCanonicalMap = (ym) => {
+ const { months: m, seconds: s } = duration(ym);
+ if (s !== 0) {
+ throw new TypeError(
+ `सूत्र: Expected the provided yearMonthDuration to have a value of zero for seconds, but got: ${s}.`,
+ );
+ } else {
+ const sgn = m < 0 ? "-" : "";
+ return stringCatenate(
+ sgn,
+ "P",
+ duYearMonthCanonicalFragmentMap(abs(m)),
+ );
+ }
+};
+
+/**
+ * Maps a dayTimeDuration's ·seconds· value to a
+ * dayTimeDurationLexicalRep. (The ·months· value is necessarily zero
+ * and is ignored.) ·dayTimeDurationCanonicalMap· is a restriction of
+ * ·durationCanonicalMap·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dayTimeDurationCanMap>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * dayTimeDuration value.
+ */
+export const dayTimeDurationCanonicalMap = (dt) => {
+ const { months: m, seconds: s } = duration(dt);
+ if (m !== 0) {
+ throw new TypeError(
+ `सूत्र: Expected the provided dayTimeDuration to have a value of zero for months, but got: ${m}.`,
+ );
+ } else {
+ const sgn = s < 0 ? "-" : "";
+ return stringCatenate(
+ sgn,
+ "P",
+ duDayTimeCanonicalFragmentMap(abs(s)),
+ );
+ }
+};
+
+/**
+ * If month (mo) is out of range, adjust month and year (yr)
+ * accordingly; otherwise, make no change.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-normMo>.
+ *
+ * ☡ This function throws if the provided values are not integers.
+ *
+ * ※ This function is not exposed.
+ */
+const normalizeMonth = (yr, mo) => {
+ integer(yr);
+ integer(mo);
+ return [yr + div(mo - 1, 12), mod(mo - 1, 12) + 1];
+};
+
+/**
+ * If month (mo) is out of range, or day (da) is out of range for the
+ * appropriate month, then adjust values accordingly, otherwise make no
+ * change.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-normDa>.
+ *
+ * ☡ This function throws if the provided values are not integers.
+ *
+ * ※ This function is not exposed.
+ */
+const normalizeDay = (yr, mo, da) => {
+ integer(yr);
+ integer(mo);
+ integer(da);
+ [yr, mo] = normalizeMonth(yr, mo);
+ let limit = daysInMonth(yr, mo);
+ while (da > limit || da <= 0) {
+ if (da > limit) {
+ da -= limit;
+ mo += 1;
+ [yr, mo] = normalizeMonth(yr, mo);
+ limit = daysInMonth(yr, mo);
+ }
+ if (da <= 0) {
+ mo -= 1;
+ [yr, mo] = normalizeMonth(yr, mo);
+ limit = daysInMonth(yr, mo);
+ da += limit;
+ }
+ }
+ return [yr, mo, da];
+};
+
+/**
+ * Normalizes minute, hour, month, and year values to values that obey
+ * the appropriate constraints.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-normMi>.
+ *
+ * ☡ This function throws if the provided values are not integers.
+ *
+ * ※ This function is not exposed.
+ */
+const normalizeMinute = (yr, mo, da, hr, mi) => {
+ integer(yr);
+ integer(mo);
+ integer(da);
+ integer(hr);
+ integer(mi);
+ hr += div(mi, 60);
+ mi = mod(mi, 60);
+ da += div(hr, 24);
+ hr = mod(hr, 24);
+ [yr, mo, da] = normalizeDay(yr, mo, da);
+ return [yr, mo, da, hr, mi];
+};
+
+/**
+ * Normalizes minute, hour, month, and year values to values that obey
+ * the appropriate constraints. (This algorithm ignores leap seconds.)
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-normSe>.
+ *
+ * ☡ This function throws if the first five provided values are not
+ * integers or the sixth is not a finite number.
+ *
+ * ※ This function is not exposed.
+ */
+const normalizeSecond = (yr, mo, da, hr, mi, se) => {
+ integer(yr);
+ integer(mo);
+ integer(da);
+ integer(hr);
+ integer(mi);
+ decimalNumber(se);
+ mi += div(se, 60);
+ se = mod(se, 60);
+ [yr, mo, da, hr, mi] = normalizeMinute(yr, mo, da, hr, mi);
+ return [yr, mo, da, hr, mi, se];
+};
+
+/**
+ * Normalizes minute, hour, month, and year values to values that obey
+ * the appropriate constraints. (This algorithm ignores leap seconds.)
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-daysInMonth>.
+ *
+ * ☡ This function throws if the first value is not absent or an
+ * integer or if the second value is not an integer between 1 and 12
+ * inclusive.
+ */
+export const daysInMonth = (y, m) => {
+ if (y !== absent && !isIntegralNumber(y)) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer, but got: ${y}.`,
+ );
+ } else if (!(isIntegralNumber(m) && m >= 1 && m <= 12)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer between 1 and 12 inclusive, but got: ${m}.`,
+ );
+ } else {
+ return m === 2
+ ? y === absent || y % 4 || !(y % 100) && y % 400 ? 28 : 29
+ : m === 4 || m === 6 || m === 9 || m === 11
+ ? 30
+ : 31;
+ }
+};
+
+/**
+ * Returns an instance of the date/timeSevenPropertyModel with property
+ * values as specified in the arguments. If an argument is omitted, the
+ * corresponding property is set to absent.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#p-setDTFromRaw>.
+ *
+ * ※ The X·S·D specification erroneously fails to account for the
+ * value `"--02-29"`, which `·newDateTime·` treats as 01 March because
+ * it assumes February has 28 days when the year is absent. This is a
+ * correct assumption generally, but February should be treated as
+ * having 29 days when a value of `"--02-29"` is explicity given.
+ *
+ * ☡ This function throws if the provided values do not match the
+ * ranges expected by the Date∕time Seven‐Property Model.
+ */
+export const newDateTime = (Yr, Mo, Da, Hr, Mi, Se, Tz) => {
+ if (Yr !== absent && !isIntegralNumber(Yr)) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer, but got: ${Yr}.`,
+ );
+ } else if (
+ Mo !== absent && !(isIntegralNumber(Mo) && Mo >= 1 && Mo <= 12)
+ ) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer between 1 and 12 inclusive, but got: ${Mo}.`,
+ );
+ } else if (
+ Da !== absent && !(isIntegralNumber(Da) && Da >= 1 && Da <= 31)
+ ) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer between 1 and 31 inclusive, but got: ${Da}.`,
+ );
+ } else if (
+ Hr !== absent && !(isIntegralNumber(Hr) && Hr >= 0 && Hr <= 24)
+ ) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer between 0 and 24 inclusive, but got: ${Hr}.`,
+ );
+ } else if (
+ Mi !== absent && !(isIntegralNumber(Mi) && Mi >= 0 && Mi <= 59)
+ ) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer between 0 and 59 inclusive, but got: ${Mi}.`,
+ );
+ } else if (
+ Se !== absent && !(isFiniteNumber(Se) && Se >= 0 && Se < 60)
+ ) {
+ throw new TypeError(
+ `सूत्र: Expected an optional finite number greater than or equal to 0 and less than 60, but got: ${Se}.`,
+ );
+ } else if (
+ Tz !== absent && !(isIntegralNumber(Tz) && Tz >= -840 && Tz <= 840)
+ ) {
+ throw new TypeError(
+ `सूत्र: Expected an optional integer between -840 and 840 inclusive, but got: ${Tz}.`,
+ );
+ } else {
+ let yr = Yr !== absent ? Yr : Mo === 2 && Da === 29 ? 0 : 1;
+ let mo = Mo !== absent ? Mo : 1;
+ let da = Da !== absent ? Da : 1;
+ let hr = Hr !== absent ? Hr : 0;
+ let mi = Mi !== absent ? Mi : 0;
+ let se = Se !== absent ? Se : 0;
+ [yr, mo, da, hr, mi, se] = normalizeSecond(yr, mo, da, hr, mi, se);
+ return {
+ year: Yr === absent ? absent : yr,
+ month: Mo === absent ? absent : mo,
+ day: Da === absent ? absent : da,
+ hour: Hr === absent ? absent : hr,
+ minute: Mi === absent ? absent : mi,
+ second: Se === absent ? absent : se,
+ timezoneOffset: Tz,
+ };
+ }
+};
+
+/**
+ * Adds a duration to a dateTime value, producing another dateTime
+ * value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-dt-dateTimePlusDuration>.
+ *
+ * ※ The X·S·D specification erroneously fails to account for the
+ * value `"--02-29"`, which `·dateTimePlusDuration·` treats as 01 March
+ * because it assumes February has 28 days when the year is absent.
+ * This is a correct assumption generally, but February should be
+ * treated as having 29 days when a value of `"--02-29"` is explicity
+ * given.
+ *
+ * ☡ This function throws if the provided duration or
+ * date/timeSevenPropertyModel values are not valid.
+ *
+ * ※ Despite the name and description, this function can add a
+ * duration to any date/timeSevenPropertyModel value.
+ */
+export const dateTimePlusDuration = (du, dt) => {
+ const { months, seconds } = duration(du);
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(dt);
+ let yr = year !== absent ? year : month === 2 && day === 29 ? 0 : 1;
+ let mo = month !== absent ? month : 1;
+ let da = day !== absent ? day : 1;
+ let hr = hour !== absent ? hour : 0;
+ let mi = minute !== absent ? minute : 0;
+ let se = second !== absent ? second : 0;
+ mo += months;
+ [yr, mo] = normalizeMonth(yr, mo);
+ da = min(da, daysInMonth(yr, mo));
+ se += seconds;
+ [yr, mo, da, hr, mi, se] = normalizeSecond(yr, mo, da, hr, mi, se);
+ return newDateTime(
+ year === absent ? absent : yr,
+ month === absent ? absent : mo,
+ day === absent ? absent : da,
+ hour === absent ? absent : hr,
+ minute === absent ? absent : mi,
+ second === absent ? absent : se,
+ timezoneOffset,
+ );
+};
+
+/**
+ * Maps a date/timeSevenPropertyModel value to the decimal number
+ * representing its position on the "time line".
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-dt-timeOnTimeline>.
+ *
+ * ☡ This function throws if the provided date/timeSevenPropertyModel
+ * value is not valid.
+ */
+export const timeOnTimeline = (dt) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(dt);
+ const yr = year === absent ? 1971 : year - 1;
+ const mo = month === absent ? 12 : month;
+ const da = day === absent ? daysInMonth(yr + 1, mo) - 1 : day - 1;
+ const hr = hour === absent ? 0 : hour;
+ const mi = (minute === absent ? 0 : minute) -
+ (timezoneOffset === absent ? 0 : timezoneOffset);
+ const se = second === absent ? 0 : second;
+ let ToTI = 31536000 * yr;
+ ToTI += 86400 * (div(yr, 400) - div(yr, 100) + div(yr, 4));
+ for (let m = 1; m < mo; ++m) {
+ ToTI += 86400 * daysInMonth(yr + 1, m);
+ }
+ ToTI += 86400 * da;
+ ToTI += 3600 * hr + 60 * mi + se;
+ return ToTI;
+};
+
+/**
+ * Maps a yearFrag, part of a date/timeSevenPropertyModel's ·lexical
+ * representation·, onto an integer, presumably the ·year· property of
+ * a date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-yrMap>.
+ *
+ * ☡ This function throws if the provided value is not a yearFrag
+ * string.
+ */
+export const yearFragValue = (YR) =>
+ noDecimalMap(ensureMatches(yearFrag, YR));
+
+/**
+ * Maps a monthFrag, part of a date/timeSevenPropertyModel's ·lexical
+ * representation·, onto an integer, presumably the ·month· property of
+ * a date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-moMap>.
+ *
+ * ☡ This function throws if the provided value is not a monthFrag
+ * string.
+ */
+export const monthFragValue = (MO) =>
+ unsignedNoDecimalMap(ensureMatches(monthFrag, MO));
+
+/**
+ * Maps a dayFrag, part of a date/timeSevenPropertyModel's ·lexical
+ * representation·, onto an integer, presumably the ·day· property of a
+ * date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-daMap>.
+ *
+ * ☡ This function throws if the provided value is not a dayFrag
+ * string.
+ */
+export const dayFragValue = (DA) =>
+ unsignedNoDecimalMap(ensureMatches(dayFrag, DA));
+
+/**
+ * Maps a hourFrag, part of a date/timeSevenPropertyModel's ·lexical
+ * representation·, onto an integer, presumably the ·hour· property of
+ * a date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-hrMap>.
+ *
+ * ☡ This function throws if the provided value is not a hourFrag
+ * string.
+ */
+export const hourFragValue = (HR) =>
+ unsignedNoDecimalMap(ensureMatches(hourFrag, HR));
+
+/**
+ * Maps a minuteFrag, part of a date/timeSevenPropertyModel's ·lexical
+ * representation·, onto an integer, presumably the ·minute· property
+ * of a date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-miMap>.
+ *
+ * ☡ This function throws if the provided value is not a minuteFrag
+ * string.
+ */
+export const minuteFragValue = (MI) =>
+ unsignedNoDecimalMap(ensureMatches(minuteFrag, MI));
+
+/**
+ * Maps a secondFrag, part of a date/timeSevenPropertyModel's ·lexical
+ * representation·, onto a decimal number, presumably the ·second·
+ * property of a date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-seMap>.
+ *
+ * ☡ This function throws if the provided value is not a secondFrag
+ * string.
+ */
+export const secondFragValue = (SE) =>
+ getFirstSubstringIndex(ensureMatches(secondFrag, SE), ".") === -1
+ ? unsignedNoDecimalMap(SE)
+ : unsignedDecimalPtMap(SE);
+
+/**
+ * Maps a timezoneFrag, part of a date/timeSevenPropertyModel's
+ * ·lexical representation·, onto an integer, presumably the
+ * ·timezoneOffset· property of a date/timeSevenPropertyModel value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-dt-tzMap>.
+ *
+ * ※ The X·S·D specification erroneously specifies
+ * ·unsignedDecimalPtMap·(H) and ·unsignedDecimalPtMap·(M), but
+ * ·unsignedNoDecimalMap·(H) and ·unsignedDecimalPtMap·(M) is correct.
+ *
+ * ☡ This function throws if the provided value is not a timezoneFrag
+ * string.
+ */
+export const timezoneFragValue = (TZ) => {
+ const s = ensureMatches(timezoneFrag, TZ)[0];
+ if (s === "Z") {
+ return 0;
+ } else {
+ let H, M;
+ new Matcher(
+ rawString`[+-](?<H>\d{2}):(?<M>\d{2})`,
+ undefined,
+ (_, { groups }) => {
+ H = groups.H;
+ M = groups.M;
+ return true;
+ },
+ )(TZ);
+ return s === "-"
+ ? -(unsignedNoDecimalMap(H) * 60 + unsignedNoDecimalMap(M)) + 0
+ : unsignedNoDecimalMap(H) * 60 + unsignedNoDecimalMap(M);
+ }
+};
+
+/**
+ * Maps a dateTimeLexicalRep to a dateTime value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-dateTimeLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * dateTimeLexicalRep string.
+ */
+export const dateTimeLexicalMap = (LEX) => {
+ let Y, MO, D, H, MI, S, T;
+ new Matcher(
+ rawString`(?<Y>-?\d+)-(?<MO>\d+)-(?<D>\d+)T(?:24:00:00(?:\.0+)?|(?<H>\d+):(?<MI>\d+):(?<S>[\d.]+))(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ Y = groups.Y;
+ MO = groups.MO;
+ D = groups.D;
+ H = groups.H ?? absent;
+ MI = groups.MI ?? absent;
+ S = groups.S ?? absent;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(dateTimeLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return H === absent
+ ? newDateTime(
+ yearFragValue(Y),
+ monthFragValue(MO),
+ dayFragValue(D),
+ 24,
+ 0,
+ 0,
+ tz,
+ )
+ : newDateTime(
+ yearFragValue(Y),
+ monthFragValue(MO),
+ dayFragValue(D),
+ hourFragValue(H),
+ minuteFragValue(MI),
+ secondFragValue(S),
+ tz,
+ );
+};
+
+/**
+ * Maps a timeLexicalMap to a time value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-timeLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a timeLexicalMap
+ * string.
+ */
+export const timeLexicalMap = (LEX) => {
+ let H, MI, S, T;
+ new Matcher(
+ rawString`(?:24:00:00(?:\.0+)?|(?<H>\d+):(?<MI>\d+):(?<S>[\d.]+))(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ H = groups.H ?? absent;
+ MI = groups.MI ?? absent;
+ S = groups.S ?? absent;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(timeLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return H === absent
+ ? newDateTime(
+ absent,
+ absent,
+ absent,
+ 0,
+ 0,
+ 0,
+ tz,
+ )
+ : newDateTime(
+ absent,
+ absent,
+ absent,
+ hourFragValue(H),
+ minuteFragValue(MI),
+ secondFragValue(S),
+ tz,
+ );
+};
+
+/**
+ * Maps a dateLexicalRep to a date value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-dateLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a dateLexicalRep
+ * string.
+ */
+export const dateLexicalMap = (LEX) => {
+ let Y, M, D, T;
+ new Matcher(
+ rawString`(?<Y>-?\d+)-(?<M>\d+)-(?<D>\d+)(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ Y = groups.Y;
+ M = groups.M;
+ D = groups.D;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(dateLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return newDateTime(
+ yearFragValue(Y),
+ monthFragValue(M),
+ dayFragValue(D),
+ absent,
+ absent,
+ absent,
+ tz,
+ );
+};
+
+/**
+ * Maps a gYearMonthLexicalRep to a date value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gYearMonthLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * gYearMonthLexicalRep string.
+ */
+export const gYearMonthLexicalMap = (LEX) => {
+ let Y, M, T;
+ new Matcher(
+ rawString`(?<Y>-?\d+)-(?<M>\d+)(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ Y = groups.Y;
+ M = groups.M;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(gYearMonthLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return newDateTime(
+ yearFragValue(Y),
+ monthFragValue(M),
+ absent,
+ absent,
+ absent,
+ absent,
+ tz,
+ );
+};
+
+/**
+ * Maps a gYearLexicalRep to a date value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gYearLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * gYearLexicalRep string.
+ */
+export const gYearLexicalMap = (LEX) => {
+ let Y, T;
+ new Matcher(
+ rawString`(?<Y>-?\d+)(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ Y = groups.Y;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(gYearLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return newDateTime(
+ yearFragValue(Y),
+ absent,
+ absent,
+ absent,
+ absent,
+ absent,
+ tz,
+ );
+};
+
+/**
+ * Maps a gMonthDayLexicalRep to a date value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gMonthDayLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * gMonthDayLexicalRep string.
+ */
+export const gMonthDayLexicalMap = (LEX) => {
+ let M, D, T;
+ new Matcher(
+ rawString`--(?<M>\d+)-(?<D>\d+)(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ M = groups.M;
+ D = groups.D;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(gMonthDayLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return newDateTime(
+ absent,
+ monthFragValue(M),
+ dayFragValue(D),
+ absent,
+ absent,
+ absent,
+ tz,
+ );
+};
+
+/**
+ * Maps a gDayLexicalRep to a date value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gDayLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a gDayLexicalRep
+ * string.
+ */
+export const gDayLexicalMap = (LEX) => {
+ let D, T;
+ new Matcher(
+ rawString`---(?<D>\d+)(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ D = groups.D;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(gDayLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return newDateTime(
+ absent,
+ absent,
+ dayFragValue(D),
+ absent,
+ absent,
+ absent,
+ tz,
+ );
+};
+
+/**
+ * Maps a gMonthLexicalRep to a date value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gMonthLexRep>.
+ *
+ * ☡ This function throws if the provided value is not a
+ * gMonthLexicalRep string.
+ */
+export const gMonthLexicalMap = (LEX) => {
+ let M, T;
+ new Matcher(
+ rawString`--(?<M>\d+)(?<T>.+)?`,
+ undefined,
+ (_, { groups }) => {
+ M = groups.M;
+ T = groups.T ?? absent;
+ return true;
+ },
+ )(ensureMatches(gMonthLexicalRep, LEX));
+ const tz = T === absent ? absent : timezoneFragValue(T);
+ return newDateTime(
+ absent,
+ monthFragValue(M),
+ absent,
+ absent,
+ absent,
+ absent,
+ tz,
+ );
+};
+
+/**
+ * Maps a nonnegative integer less than 100 onto an unsigned
+ * always-two-digit numeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-unsTwoDigCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * integer less than 100.
+ *
+ * ※ This function is not exposed.
+ */
+const unsTwoDigitCanonicalFragmentMap = (i) => {
+ if (!(isIntegralNumber(i) && i >= 0 && i < 100)) {
+ throw new TypeError(
+ `सूत्र: Expected a nonnegative integer less than 100, but got: ${i}.`,
+ );
+ } else {
+ return stringCatenate(digit(div(i, 10)), digit(mod(i, 10)));
+ }
+};
+
+/**
+ * Maps an integer between -10000 and 10000 onto an always-four-digit numeral.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-fourDigCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer whose
+ * absolute value is less than 10000.
+ *
+ * ※ This function is not exposed.
+ */
+const fourDigitCanonicalFragmentMap = (i) => {
+ if (!(isIntegralNumber(i) && abs(i) < 10000)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer whose absolute value is less than 10000, but got: ${i}.`,
+ );
+ } else {
+ return i < 0
+ ? stringCatenate(
+ "-",
+ unsTwoDigitCanonicalFragmentMap(div(-i, 100)),
+ unsTwoDigitCanonicalFragmentMap(mod(-i, 100)),
+ )
+ : stringCatenate(
+ unsTwoDigitCanonicalFragmentMap(div(i, 100)),
+ unsTwoDigitCanonicalFragmentMap(mod(i, 100)),
+ );
+ }
+};
+
+/**
+ * Maps an integer, presumably the ·year· property of a
+ * date/timeSevenPropertyModel value, onto a yearFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-yrCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer.
+ */
+export const yearCanonicalFragmentMap = (y) =>
+ abs(integer(y)) > 9999
+ ? noDecimalPtCanonicalMap(y)
+ : fourDigitCanonicalFragmentMap(y);
+
+/**
+ * Maps an integer, presumably the ·month· property of a
+ * date/timeSevenPropertyModel value, onto a monthFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-moCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer
+ * between 1 and 12 inclusive.
+ */
+export const monthCanonicalFragmentMap = (m) => {
+ if (!(isIntegralNumber(m) && m >= 1 && m <= 12)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer between 1 and 12 inclusive, but got: ${m}.`,
+ );
+ } else {
+ return unsTwoDigitCanonicalFragmentMap(m);
+ }
+};
+
+/**
+ * Maps an integer, presumably the ·day· property of a
+ * date/timeSevenPropertyModel value, onto a dayFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-daCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer
+ * between 1 and 31 inclusive.
+ */
+export const dayCanonicalFragmentMap = (d) => {
+ if (!(isIntegralNumber(d) && d >= 1 && d <= 31)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer between 1 and 31 inclusive, but got: ${d}.`,
+ );
+ } else {
+ return unsTwoDigitCanonicalFragmentMap(d);
+ }
+};
+
+/**
+ * Maps an integer, presumably the ·hour· property of a
+ * date/timeSevenPropertyModel value, onto an hourFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hrCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer
+ * between 0 and 23 inclusive.
+ */
+export const hourCanonicalFragmentMap = (h) => {
+ if (!(isIntegralNumber(h) && h >= 0 && h <= 23)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer between 0 and 23 inclusive, but got: ${h}.`,
+ );
+ } else {
+ return unsTwoDigitCanonicalFragmentMap(h);
+ }
+};
+
+/**
+ * Maps an integer, presumably the ·minute· property of a
+ * date/timeSevenPropertyModel value, onto a minuteFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-miCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer
+ * between 0 and 59 inclusive.
+ */
+export const minuteCanonicalFragmentMap = (m) => {
+ if (!(isIntegralNumber(m) && m >= 0 && m <= 59)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer between 0 and 59 inclusive, but got: ${m}.`,
+ );
+ } else {
+ return unsTwoDigitCanonicalFragmentMap(m);
+ }
+};
+
+/**
+ * Maps a decimal number, presumably the ·second· property of a
+ * date/timeSevenPropertyModel value, onto a secondFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-seCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not a nonnegative
+ * finite number less than 60.
+ *
+ * ※ The X·S·D specification identifies the argument to this function
+ * as “a nonnegative decimal number less than 70”, but second values 60
+ * or larger are not supported by X·S·D.
+ *
+ * ※ This function makes use of the built·in Ecmascript float
+ * serialization to avoid rounding errors.
+ */
+export const secondCanonicalFragmentMap = (s) => {
+ if (!(isFiniteNumber(s) && s < 60)) {
+ throw new TypeError(
+ `सूत्र: Expected a nonnegative finite number less than 60, but got: ${s}.`,
+ );
+ } else {
+ // return isIntegralNumber(s)
+ // ? unsTwoDigitCanonicalFragmentMap(s)
+ // : stringCatenate(
+ // unsTwoDigitCanonicalFragmentMap(div(s, 1)),
+ // ".",
+ // fractionDigitsCanonicalFragmentMap(mod(s, 1)),
+ // );
+ return isIntegralNumber(s)
+ ? unsTwoDigitCanonicalFragmentMap(s)
+ : s < 10
+ ? stringCatenate("0", decimalPtCanonicalMap(s))
+ : decimalPtCanonicalMap(s);
+ }
+};
+
+/**
+ * Maps an integer, presumably the ·timezoneOffset· property of a
+ * date/timeSevenPropertyModel value, onto a timezoneFrag, part of a
+ * date/timeSevenPropertyModel's ·lexical representation·.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-tzCanFragMap>.
+ *
+ * ☡ This function throws if the provided value is not an integer
+ * between −840 and 840 inclusive.
+ */
+export const timezoneCanonicalFragmentMap = (t) => {
+ if (!(isIntegralNumber(t) && t >= -840 && t <= 840)) {
+ throw new TypeError(
+ `सूत्र: Expected an integer between −840 and 840 inclusive, but got: ${t}.`,
+ );
+ } else {
+ return t === 0 ? "Z" : t < 0
+ ? stringCatenate(
+ "-",
+ unsTwoDigitCanonicalFragmentMap(div(-t, 60)),
+ ":",
+ unsTwoDigitCanonicalFragmentMap(mod(-t, 60)),
+ )
+ : stringCatenate(
+ "+",
+ unsTwoDigitCanonicalFragmentMap(div(t, 60)),
+ ":",
+ unsTwoDigitCanonicalFragmentMap(mod(t, 60)),
+ );
+ }
+};
+
+/**
+ * Maps a dateTime value to a dateTimeLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-dateTimeCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * dateTime.
+ */
+export const dateTimeCanonicalMap = (dt) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(dt);
+ ensurePresence("year", year, true);
+ ensurePresence("month", month, true);
+ ensurePresence("day", day, true);
+ ensurePresence("hour", hour, true);
+ ensurePresence("minute", minute, true);
+ ensurePresence("second", second, true);
+ const DT = stringCatenate(
+ yearCanonicalFragmentMap(year),
+ "-",
+ monthCanonicalFragmentMap(month),
+ "-",
+ dayCanonicalFragmentMap(day),
+ "T",
+ hourCanonicalFragmentMap(hour),
+ ":",
+ minuteCanonicalFragmentMap(minute),
+ ":",
+ secondCanonicalFragmentMap(second),
+ );
+ return timezoneOffset === absent
+ ? DT
+ : stringCatenate(DT, timezoneCanonicalFragmentMap(timezoneOffset));
+};
+
+/**
+ * Maps a time value to a timeLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-timeCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete time.
+ */
+export const timeCanonicalMap = (ti) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(ti);
+ ensurePresence("year", year, false);
+ ensurePresence("month", month, false);
+ ensurePresence("day", day, false);
+ ensurePresence("hour", hour, true);
+ ensurePresence("minute", minute, true);
+ ensurePresence("second", second, true);
+ const T = stringCatenate(
+ hourCanonicalFragmentMap(hour),
+ ":",
+ minuteCanonicalFragmentMap(minute),
+ ":",
+ secondCanonicalFragmentMap(second),
+ );
+ return timezoneOffset === absent
+ ? T
+ : stringCatenate(T, timezoneCanonicalFragmentMap(timezoneOffset));
+};
+
+/**
+ * Maps a date value to a dateLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-dateCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete date.
+ */
+export const dateCanonicalMap = (da) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(da);
+ ensurePresence("year", year, true);
+ ensurePresence("month", month, true);
+ ensurePresence("day", day, true);
+ ensurePresence("hour", hour, false);
+ ensurePresence("minute", minute, false);
+ ensurePresence("second", second, false);
+ const D = stringCatenate(
+ yearCanonicalFragmentMap(year),
+ "-",
+ monthCanonicalFragmentMap(month),
+ "-",
+ dayCanonicalFragmentMap(day),
+ );
+ return timezoneOffset === absent
+ ? D
+ : stringCatenate(D, timezoneCanonicalFragmentMap(timezoneOffset));
+};
+
+/**
+ * Maps a gYearMonth value to a gYearMonthLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gYearMonthCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * gYearMonth.
+ */
+export const gYearMonthCanonicalMap = (ym) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(ym);
+ ensurePresence("year", year, true);
+ ensurePresence("month", month, true);
+ ensurePresence("day", day, false);
+ ensurePresence("hour", hour, false);
+ ensurePresence("minute", minute, false);
+ ensurePresence("second", second, false);
+ const YM = stringCatenate(
+ yearCanonicalFragmentMap(year),
+ "-",
+ monthCanonicalFragmentMap(month),
+ );
+ return timezoneOffset === absent
+ ? YM
+ : stringCatenate(YM, timezoneCanonicalFragmentMap(timezoneOffset));
+};
+
+/**
+ * Maps a gYear value to a gYearLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gYearCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * gYear.
+ */
+export const gYearCanonicalMap = (gY) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(gY);
+ ensurePresence("year", year, true);
+ ensurePresence("month", month, false);
+ ensurePresence("day", day, false);
+ ensurePresence("hour", hour, false);
+ ensurePresence("minute", minute, false);
+ ensurePresence("second", second, false);
+ return timezoneOffset === absent
+ ? yearCanonicalFragmentMap(year)
+ : stringCatenate(
+ yearCanonicalFragmentMap(year),
+ timezoneCanonicalFragmentMap(timezoneOffset),
+ );
+};
+
+/**
+ * Maps a gMonthDay value to a gMonthDayLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gMonthDayCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * gMonthDay.
+ */
+export const gMonthDayCanonicalMap = (md) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(md);
+ ensurePresence("year", year, false);
+ ensurePresence("month", month, true);
+ ensurePresence("day", day, true);
+ ensurePresence("hour", hour, false);
+ ensurePresence("minute", minute, false);
+ ensurePresence("second", second, false);
+ const MD = stringCatenate(
+ "--",
+ monthCanonicalFragmentMap(month),
+ "-",
+ dayCanonicalFragmentMap(day),
+ );
+ return timezoneOffset === absent
+ ? MD
+ : stringCatenate(MD, timezoneCanonicalFragmentMap(timezoneOffset));
+};
+
+/**
+ * Maps a gDay value to a gDayLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gDayCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete gDay.
+ */
+export const gDayCanonicalMap = (gD) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(gD);
+ ensurePresence("year", year, false);
+ ensurePresence("month", month, false);
+ ensurePresence("day", day, true);
+ ensurePresence("hour", hour, false);
+ ensurePresence("minute", minute, false);
+ ensurePresence("second", second, false);
+ return timezoneOffset === absent
+ ? stringCatenate("---", dayCanonicalFragmentMap(day))
+ : stringCatenate(
+ "---",
+ dayCanonicalFragmentMap(day),
+ timezoneCanonicalFragmentMap(timezoneOffset),
+ );
+};
+
+/**
+ * Maps a gMonth value to a gMonthLexicalRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#vp-gMonthCanRep>.
+ *
+ * ☡ This function throws if the provided value is not a complete
+ * gMonth.
+ */
+export const gMonthCanonicalMap = (gM) => {
+ const {
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ timezoneOffset,
+ } = date·timeSevenPropertyModel(gM);
+ ensurePresence("year", year, false);
+ ensurePresence("month", month, true);
+ ensurePresence("day", day, false);
+ ensurePresence("hour", hour, false);
+ ensurePresence("minute", minute, false);
+ ensurePresence("second", second, false);
+ return timezoneOffset === absent
+ ? stringCatenate("--", dayCanonicalFragmentMap(month))
+ : stringCatenate(
+ "--",
+ dayCanonicalFragmentMap(month),
+ timezoneCanonicalFragmentMap(timezoneOffset),
+ );
+};
+
+/**
+ * Maps a ·literal· matching the stringRep production to a string
+ * value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-stringLexmap>.
+ *
+ * ☡ This function throws if the provided value is not a stringRep
+ * string.
+ */
+export const stringLexicalMap = (LEX) => ensureMatches(stringRep, LEX);
+
+/**
+ * Maps a ·literal· matching the booleanRep production to a boolean
+ * value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-booleanLexmap>.
+ *
+ * ☡ This function throws if the provided value is not a booleanRep
+ * string.
+ */
+export const booleanLexicalMap = (LEX) => {
+ ensureMatches(booleanRep, LEX);
+ return LEX === "true" || LEX === "1";
+};
+
+/**
+ * Maps a string value to a stringRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-stringCanmap>.
+ *
+ * ☡ This function throws if the provided value is not a valid string.
+ */
+export const stringCanonicalMap = (s) => ensureMatches(stringRep, s);
+
+/**
+ * Maps a boolean value to a booleanRep.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-booleanCanmap>.
+ *
+ * ☡ This function throws if the provided value is not a boolean.
+ */
+export const booleanCanonicalMap = (b) => {
+ if (typeof b !== "boolean") {
+ throw new TypeError(`सूत्र: Expected a boolean, but got: ${b}.`);
+ } else {
+ return b ? "true" : "false";
+ }
+};
+
+/**
+ * Maps a ·literal· matching the hexBinary production to a sequence of
+ * octets in the form of a hexBinary value.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hexBinaryMap>.
+ *
+ * ☡ This function throws if the provided value is not a hexBinary
+ * string.
+ *
+ * ※ This function returns an `ArrayBuffer`.
+ */
+export const hexBinaryMap = (LEX) => {
+ ensureMatches(hexBinary, LEX);
+ const bufferLength = LEX.length / 2;
+ const o = new ArrayBuffer(bufferLength);
+ for (let bufferIndex = 0, index = 0; bufferIndex < bufferLength;) {
+ set8BitIntegralItem(
+ o,
+ bufferIndex,
+ hexOctetMap(substring(LEX, index, index = ++bufferIndex * 2)),
+ );
+ }
+ return o;
+};
+
+/**
+ * Maps a ·literal· matching the hexOctet production to a single octet.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hexOctetMap>.
+ *
+ * ☡ This function throws if the provided value is not a hexOctet
+ * string.
+ *
+ * ※ This function is not exposed.
+ */
+const hexOctetMap = (LEX) => {
+ const [d0, d1] = ensureMatches(hexOctet, LEX);
+ let octet = 0;
+ let bit = 8;
+ for (const digit of hexDigitMap(d0)) {
+ octet |= digit << --bit;
+ }
+ for (const digit of hexDigitMap(d1)) {
+ octet |= digit << --bit;
+ }
+ return octet;
+};
+
+/**
+ * Maps a hexadecimal digit (a character matching the hexDigit
+ * production) to a sequence of four binary digits.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hexDigitMap>.
+ *
+ * ☡ This function throws if the provided value is not a hexDigit
+ * string.
+ *
+ * ※ It would be way simpler and more efficient to just return a
+ * single value here rather than a sequence of digits.
+ *
+ * ※ This function is not exposed.
+ */
+const hexDigitMap = (d) => {
+ switch (ensureMatches(hexDigit, d)) {
+ case "0":
+ return binaryDigitSequence("0000");
+ case "1":
+ return binaryDigitSequence("0001");
+ case "2":
+ return binaryDigitSequence("0010");
+ case "3":
+ return binaryDigitSequence("0011");
+ case "4":
+ return binaryDigitSequence("0100");
+ case "5":
+ return binaryDigitSequence("0101");
+ case "6":
+ return binaryDigitSequence("0110");
+ case "7":
+ return binaryDigitSequence("0111");
+ case "8":
+ return binaryDigitSequence("1000");
+ case "9":
+ return binaryDigitSequence("1001");
+ case "A":
+ case "a":
+ return binaryDigitSequence("1010");
+ case "B":
+ case "b":
+ return binaryDigitSequence("1011");
+ case "C":
+ case "c":
+ return binaryDigitSequence("1100");
+ case "D":
+ case "d":
+ return binaryDigitSequence("1101");
+ case "E":
+ case "e":
+ return binaryDigitSequence("1110");
+ case "F":
+ case "f":
+ return binaryDigitSequence("1111");
+ }
+};
+
+/**
+ * Maps a hexBinary value to a literal matching the hexBinary
+ * production.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hexBinaryCanonical>.
+ *
+ * ☡ This function throws if the provided value is not an
+ * `ArrayBuffer`.
+ */
+export const hexBinaryCanonical = (o) => {
+ hexBinaryValue(o);
+ const length = getByteLength(o);
+ return stringCatenate(
+ "",
+ ...generatorSequence(function* () {
+ for (let index = 0; index < length; ++index) {
+ yield hexOctetCanonical(
+ toNumber(get8BitUnsignedIntegralItem(o, index)),
+ );
+ }
+ }),
+ );
+};
+
+/**
+ * Maps a binary octet to a literal matching the hexOctet production.
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hexOctetCanonical>.
+ *
+ * ☡ This function throws if the provided value is not a hexOctet
+ * string.
+ *
+ * ※ This function is not exposed.
+ */
+const hexOctetCanonical = (o) => {
+ if (!(isIntegralNumber(o) && o >= 0 && o <= 0xFF)) {
+ throw new TypeError(
+ `सूत्र: Expected a binary octet but got: ${o}.`,
+ );
+ } else {
+ const lo = generatorSequence(function* () {
+ for (let i = 1; i <= 4; ++i) {
+ const offset = 4 - i;
+ yield (o & 1 << offset) >> offset;
+ }
+ });
+ const hi = generatorSequence(function* () {
+ for (let i = 1; i <= 4; ++i) {
+ const offset = 8 - i;
+ yield (o & 1 << offset) >> offset;
+ }
+ });
+ return hexDigitCanonical(hi) + hexDigitCanonical(lo);
+ }
+};
+
+/**
+ * Maps a four-bit sequence to a hexadecimal digit (a literal matching
+ * the hexDigit production).
+ *
+ * See <https://www.w3.org/TR/xmlschema11-2/#f-hexDigitCanonical>.
+ *
+ * ☡ This function throws if the provided value is not an iterable of
+ * binary digits.
+ *
+ * ※ It would be way simpler and more efficient to just call this with
+ * a single value rather than a sequence of digits.
+ *
+ * ※ This function is not exposed.
+ */
+const hexDigitCanonical = (d) => {
+ let sum = 0;
+ for (const digit of d) {
+ if (digit != 0 && digit != 1) {
+ throw new TypeError(
+ `सूत्र: Expected a binary digit but got: ${digit}.`,
+ );
+ } else {
+ sum = (sum << 1) | digit;
+ }
+ }
+ switch (sum) {
+ case 0b0000:
+ return "0";
+ case 0b0001:
+ return "1";
+ case 0b0010:
+ return "2";
+ case 0b0011:
+ return "3";
+ case 0b0100:
+ return "4";
+ case 0b0101:
+ return "5";
+ case 0b0110:
+ return "6";
+ case 0b0111:
+ return "7";
+ case 0b1000:
+ return "8";
+ case 0b1001:
+ return "9";
+ case 0b1010:
+ return "A";
+ case 0b1011:
+ return "B";
+ case 0b1100:
+ return "C";
+ case 0b1101:
+ return "D";
+ case 0b1110:
+ return "E";
+ case 0b1111:
+ return "F";
+ }
+};