UNPKG

zpt

Version:

Zenon Page Templates - JS (ZPT-JS)

1,635 lines (1,633 loc) 179 kB
var __getOwnPropNames = Object.getOwnPropertyNames; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; // node_modules/@messageformat/core/messageformat.js var require_messageformat = __commonJS({ "node_modules/@messageformat/core/messageformat.js"(exports, module) { (function(global2, factory) { typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, global2.MessageFormat = factory()); })(exports, (function() { "use strict"; var __assign = function() { __assign = Object.assign || function __assign2(t2) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t2[p] = s[p]; } return t2; }; return __assign.apply(this, arguments); }; function __values(o2) { var s = typeof Symbol === "function" && Symbol.iterator, m2 = s && o2[s], i = 0; if (m2) return m2.call(o2); if (o2 && typeof o2.length === "number") return { next: function() { if (o2 && i >= o2.length) o2 = void 0; return { value: o2 && o2[i++], done: !o2 }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o2, n) { var m2 = typeof Symbol === "function" && o2[Symbol.iterator]; if (!m2) return o2; var i = m2.call(o2), r, ar2 = [], e2; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar2.push(r.value); } catch (error) { e2 = { error }; } finally { try { if (r && !r.done && (m2 = i["return"])) m2.call(i); } finally { if (e2) throw e2.error; } } return ar2; } function __spreadArray(to2, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar2; i < l; i++) { if (ar2 || !(i in from)) { if (!ar2) ar2 = Array.prototype.slice.call(from, 0, i); ar2[i] = from[i]; } } return to2.concat(ar2 || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { var e2 = new Error(message); return e2.name = "SuppressedError", e2.error = error, e2.suppressed = suppressed, e2; }; class DateFormatError extends Error { /** @internal */ constructor(msg, token, type) { super(msg); this.token = token; this.type = type || "error"; } } const alpha = (width) => width < 4 ? "short" : width === 4 ? "long" : "narrow"; const numeric = (width) => width % 2 === 0 ? "2-digit" : "numeric"; function yearOptions(token, onError) { switch (token.char) { case "y": return { year: numeric(token.width) }; case "r": return { calendar: "gregory", year: "numeric" }; case "u": case "U": case "Y": default: onError(`${token.desc} is not supported; falling back to year:numeric`, DateFormatError.WARNING); return { year: "numeric" }; } } function monthStyle(token, onError) { switch (token.width) { case 1: return "numeric"; case 2: return "2-digit"; case 3: return "short"; case 4: return "long"; case 5: return "narrow"; default: onError(`${token.desc} is not supported with width ${token.width}`); return void 0; } } function dayStyle(token, onError) { const { char, desc, width } = token; if (char === "d") { return numeric(width); } else { onError(`${desc} is not supported`); return void 0; } } function weekdayStyle(token, onError) { const { char, desc, width } = token; if ((char === "c" || char === "e") && width < 3) { const msg = `Numeric value is not supported for ${desc}; falling back to weekday:short`; onError(msg, DateFormatError.WARNING); } return alpha(width); } function hourOptions(token) { const hour = numeric(token.width); let hourCycle; switch (token.char) { case "h": hourCycle = "h12"; break; case "H": hourCycle = "h23"; break; case "k": hourCycle = "h24"; break; case "K": hourCycle = "h11"; break; } return hourCycle ? { hour, hourCycle } : { hour }; } function timeZoneNameStyle(token, onError) { const { char, desc, width } = token; switch (char) { case "v": case "z": return width === 4 ? "long" : "short"; case "V": if (width === 4) return "long"; onError(`${desc} is not supported with width ${width}`); return void 0; case "X": onError(`${desc} is not supported`); return void 0; } return "short"; } function compileOptions(token, onError) { switch (token.field) { case "era": return { era: alpha(token.width) }; case "year": return yearOptions(token, onError); case "month": return { month: monthStyle(token, onError) }; case "day": return { day: dayStyle(token, onError) }; case "weekday": return { weekday: weekdayStyle(token, onError) }; case "period": return void 0; case "hour": return hourOptions(token); case "min": return { minute: numeric(token.width) }; case "sec": return { second: numeric(token.width) }; case "tz": return { timeZoneName: timeZoneNameStyle(token, onError) }; case "quarter": case "week": case "sec-frac": case "ms": onError(`${token.desc} is not supported`); } return void 0; } function getDateFormatOptions(tokens, timeZone) { let onError = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : (error) => { throw error; }; const options = { timeZone }; const fields2 = []; for (const token of tokens) { const { error, field, str } = token; if (error) { const dte = new DateFormatError(error.message, token); dte.stack = error.stack; onError(dte); } if (str) { const msg = `Ignoring string part: ${str}`; onError(new DateFormatError(msg, token, DateFormatError.WARNING)); } if (field) { if (fields2.indexOf(field) === -1) fields2.push(field); else onError(new DateFormatError(`Duplicate ${field} token`, token)); } const opt = compileOptions(token, (msg, isWarning) => onError(new DateFormatError(msg, token, isWarning))); if (opt) Object.assign(options, opt); } return options; } const fields = { G: { field: "era", desc: "Era" }, y: { field: "year", desc: "Year" }, Y: { field: "year", desc: 'Year of "Week of Year"' }, u: { field: "year", desc: "Extended year" }, U: { field: "year", desc: "Cyclic year name" }, r: { field: "year", desc: "Related Gregorian year" }, Q: { field: "quarter", desc: "Quarter" }, q: { field: "quarter", desc: "Stand-alone quarter" }, M: { field: "month", desc: "Month in year" }, L: { field: "month", desc: "Stand-alone month in year" }, w: { field: "week", desc: "Week of year" }, W: { field: "week", desc: "Week of month" }, d: { field: "day", desc: "Day in month" }, D: { field: "day", desc: "Day of year" }, F: { field: "day", desc: "Day of week in month" }, g: { field: "day", desc: "Modified julian day" }, E: { field: "weekday", desc: "Day of week" }, e: { field: "weekday", desc: "Local day of week" }, c: { field: "weekday", desc: "Stand-alone local day of week" }, a: { field: "period", desc: "AM/PM marker" }, b: { field: "period", desc: "AM/PM/noon/midnight marker" }, B: { field: "period", desc: "Flexible day period" }, h: { field: "hour", desc: "Hour in AM/PM (1~12)" }, H: { field: "hour", desc: "Hour in day (0~23)" }, k: { field: "hour", desc: "Hour in day (1~24)" }, K: { field: "hour", desc: "Hour in AM/PM (0~11)" }, j: { field: "hour", desc: "Hour in preferred cycle" }, J: { field: "hour", desc: "Hour in preferred cycle without marker" }, C: { field: "hour", desc: "Hour in preferred cycle with flexible marker" }, m: { field: "min", desc: "Minute in hour" }, s: { field: "sec", desc: "Second in minute" }, S: { field: "sec-frac", desc: "Fractional second" }, A: { field: "ms", desc: "Milliseconds in day" }, z: { field: "tz", desc: "Time Zone: specific non-location" }, Z: { field: "tz", desc: "Time Zone" }, O: { field: "tz", desc: "Time Zone: localized" }, v: { field: "tz", desc: "Time Zone: generic non-location" }, V: { field: "tz", desc: "Time Zone: ID" }, X: { field: "tz", desc: "Time Zone: ISO8601 with Z" }, x: { field: "tz", desc: "Time Zone: ISO8601" } }; const isLetter = (char) => char >= "A" && char <= "Z" || char >= "a" && char <= "z"; function readFieldToken(src, pos) { const char = src[pos]; let width = 1; while (src[++pos] === char) ++width; const field = fields[char]; if (!field) { const msg = `The letter ${char} is not a valid field identifier`; return { char, error: new Error(msg), width }; } return { char, field: field.field, desc: field.desc, width }; } function readQuotedToken(src, pos) { let str = src[++pos]; let width = 2; if (str === "'") return { char: "'", str, width }; while (true) { const next = src[++pos]; ++width; if (next === void 0) { const msg = `Unterminated quoted literal in pattern: ${str || src}`; return { char: "'", error: new Error(msg), str, width }; } else if (next === "'") { if (src[++pos] !== "'") return { char: "'", str, width }; else ++width; } str += next; } } function readToken(src, pos) { const char = src[pos]; if (!char) return null; if (isLetter(char)) return readFieldToken(src, pos); if (char === "'") return readQuotedToken(src, pos); let str = char; let width = 1; while (true) { const next = src[++pos]; if (!next || isLetter(next) || next === "'") return { char, str, width }; str += next; width += 1; } } function parseDateTokens(src) { const tokens = []; let pos = 0; while (true) { const token = readToken(src, pos); if (!token) return tokens; tokens.push(token); pos += token.width; } } function getDateFormatter(locales, tokens, timeZone, onError) { if (typeof tokens === "string") tokens = parseDateTokens(tokens); if (typeof timeZone === "function") { onError = timeZone; timeZone = void 0; } const opt = getDateFormatOptions(tokens, timeZone, onError); const dtf = new Intl.DateTimeFormat(locales, opt); return (date2) => dtf.format(date2); } function getDateFormatterSource(locales, tokens, timeZone, onError) { if (typeof tokens === "string") tokens = parseDateTokens(tokens); if (typeof timeZone === "function") { onError = timeZone; timeZone = void 0; } const opt = getDateFormatOptions(tokens, timeZone, onError); const lines = [`(function() {`, `var opt = ${JSON.stringify(opt)};`, `var dtf = new Intl.DateTimeFormat(${JSON.stringify(locales)}, opt);`, `return function(value) { return dtf.format(value); }`]; return lines.join("\n ") + "\n})()"; } class NumberFormatError extends Error { /** @internal */ constructor(code, msg) { super(msg); this.code = code; } } class BadOptionError extends NumberFormatError { constructor(stem, opt) { super("BAD_OPTION", `Unknown ${stem} option: ${opt}`); this.stem = stem; this.option = opt; } } class BadStemError extends NumberFormatError { constructor(stem) { super("BAD_STEM", `Unknown stem: ${stem}`); this.stem = stem; } } class MaskedValueError extends NumberFormatError { constructor(type, prev) { super("MASKED_VALUE", `Value for ${type} is set multiple times`); this.type = type; this.prev = prev; } } class MissingOptionError extends NumberFormatError { constructor(stem) { super("MISSING_OPTION", `Required option missing for ${stem}`); this.stem = stem; } } class PatternError extends NumberFormatError { constructor(char, msg) { super("BAD_PATTERN", msg); this.char = char; } } class TooManyOptionsError extends NumberFormatError { constructor(stem, options, maxOpt) { const maxOptStr = maxOpt > 1 ? `${maxOpt} options` : "one option"; super("TOO_MANY_OPTIONS", `Token ${stem} only supports ${maxOptStr} (got ${options.length})`); this.stem = stem; this.options = options; } } class UnsupportedError extends NumberFormatError { constructor(stem, source) { super("UNSUPPORTED", `The stem ${stem} is not supported`); this.stem = stem; if (source) { this.message += ` with value ${source}`; this.source = source; } } } function getNumberFormatLocales(locales, _ref) { let { numberingSystem } = _ref; if (!Array.isArray(locales)) locales = [locales]; return numberingSystem ? locales.map((lc) => { const ext = lc.indexOf("-u-") === -1 ? "u-nu" : "nu"; return `${lc}-${ext}-${numberingSystem}`; }).concat(locales) : locales; } function round(x2, precision) { const y = +x2 + precision / 2; return y - y % +precision; } function getNumberFormatMultiplier(_ref) { let { scale, unit } = _ref; let mult = typeof scale === "number" && scale >= 0 ? scale : 1; if (unit && unit.style === "percent") mult *= 0.01; return mult; } function getNumberFormatModifier(skeleton) { const mult = getNumberFormatMultiplier(skeleton); const { precision } = skeleton; if (precision && precision.style === "precision-increment") { return (n) => round(n, precision.increment) * mult; } else { return (n) => n * mult; } } function getNumberFormatModifierSource(skeleton) { const mult = getNumberFormatMultiplier(skeleton); const { precision } = skeleton; if (precision && precision.style === "precision-increment") { const setX = `+n + ${precision.increment / 2}`; let res = `x - (x % +${precision.increment})`; if (mult !== 1) res = `(${res}) * ${mult}`; return `function(n) { var x = ${setX}; return ${res}; }`; } return mult !== 1 ? `function(n) { return n * ${mult}; }` : null; } function getNumberFormatOptions(skeleton, onUnsupported) { const { decimal, group, integerWidth, notation, precision, roundingMode, sign, unit, unitPer, unitWidth } = skeleton; const fail = (stem, source) => { if (onUnsupported) onUnsupported(new UnsupportedError(stem, source)); }; const opt = {}; if (unit) { switch (unit.style) { case "base-unit": opt.style = "decimal"; break; case "currency": opt.style = "currency"; opt.currency = unit.currency; break; case "measure-unit": opt.style = "unit"; opt.unit = unit.unit.replace(/.*-/, ""); if (unitPer) opt.unit += "-per-" + unitPer.replace(/.*-/, ""); break; case "percent": opt.style = "percent"; break; case "permille": fail("permille"); break; } } switch (unitWidth) { case "unit-width-full-name": opt.currencyDisplay = "name"; opt.unitDisplay = "long"; break; case "unit-width-hidden": fail(unitWidth); break; case "unit-width-iso-code": opt.currencyDisplay = "code"; break; case "unit-width-narrow": opt.currencyDisplay = "narrowSymbol"; opt.unitDisplay = "narrow"; break; case "unit-width-short": opt.currencyDisplay = "symbol"; opt.unitDisplay = "short"; break; } switch (group) { case "group-off": opt.useGrouping = false; break; case "group-auto": opt.useGrouping = true; break; case "group-min2": case "group-on-aligned": case "group-thousands": fail(group); opt.useGrouping = true; break; } if (precision) { switch (precision.style) { case "precision-fraction": { const { minFraction: minF, maxFraction: maxF, minSignificant: minS, maxSignificant: maxS, source } = precision; if (typeof minF === "number") { opt.minimumFractionDigits = minF; if (typeof minS === "number") fail("precision-fraction", source); } if (typeof maxF === "number") opt.maximumFractionDigits = maxF; if (typeof minS === "number") opt.minimumSignificantDigits = minS; if (typeof maxS === "number") opt.maximumSignificantDigits = maxS; break; } case "precision-integer": opt.maximumFractionDigits = 0; break; case "precision-unlimited": opt.maximumFractionDigits = 20; break; case "precision-increment": break; case "precision-currency-standard": opt.trailingZeroDisplay = precision.trailingZero; break; case "precision-currency-cash": fail(precision.style); break; } } if (notation) { switch (notation.style) { case "compact-short": opt.notation = "compact"; opt.compactDisplay = "short"; break; case "compact-long": opt.notation = "compact"; opt.compactDisplay = "long"; break; case "notation-simple": opt.notation = "standard"; break; case "scientific": case "engineering": { const { expDigits, expSign, source, style } = notation; opt.notation = style; if (expDigits && expDigits > 1 || expSign && expSign !== "sign-auto") { fail(style, source); } break; } } } if (integerWidth) { const { min, max, source } = integerWidth; if (min > 0) opt.minimumIntegerDigits = min; if (Number(max) > 0) { const hasExp = opt.notation === "engineering" || opt.notation === "scientific"; if (max === 3 && hasExp) opt.notation = "engineering"; else fail("integer-width", source); } } switch (sign) { case "sign-auto": opt.signDisplay = "auto"; break; case "sign-always": opt.signDisplay = "always"; break; case "sign-except-zero": opt.signDisplay = "exceptZero"; break; case "sign-never": opt.signDisplay = "never"; break; case "sign-accounting": opt.currencySign = "accounting"; break; case "sign-accounting-always": opt.currencySign = "accounting"; opt.signDisplay = "always"; break; case "sign-accounting-except-zero": opt.currencySign = "accounting"; opt.signDisplay = "exceptZero"; break; } if (decimal === "decimal-always") fail(decimal); if (roundingMode) fail(roundingMode); return opt; } function parseAffixToken(src, pos, onError) { const char = src[pos]; switch (char) { case "%": return { char: "%", style: "percent", width: 1 }; case "\u2030": return { char: "%", style: "permille", width: 1 }; case "\xA4": { let width = 1; while (src[++pos] === "\xA4") ++width; switch (width) { case 1: return { char, currency: "default", width }; case 2: return { char, currency: "iso-code", width }; case 3: return { char, currency: "full-name", width }; case 5: return { char, currency: "narrow", width }; default: { const msg = `Invalid number (${width}) of \xA4 chars in pattern`; onError(new PatternError("\xA4", msg)); return null; } } } case "*": { const pad = src[pos + 1]; if (pad) return { char, pad, width: 2 }; break; } case "+": case "-": return { char, width: 1 }; case "'": { let str = src[++pos]; let width = 2; if (str === "'") return { char, str, width }; while (true) { const next = src[++pos]; ++width; if (next === void 0) { const msg = `Unterminated quoted literal in pattern: ${str}`; onError(new PatternError("'", msg)); return { char, str, width }; } else if (next === "'") { if (src[++pos] !== "'") return { char, str, width }; else ++width; } str += next; } } } return null; } const isDigit = (char) => char >= "0" && char <= "9"; function parseNumberToken(src, pos) { const char = src[pos]; if (isDigit(char)) { let digits = char; while (true) { const next = src[++pos]; if (isDigit(next)) digits += next; else return { char: "0", digits, width: digits.length }; } } switch (char) { case "#": { let width = 1; while (src[++pos] === "#") ++width; return { char, width }; } case "@": { let min = 1; while (src[++pos] === "@") ++min; let width = min; pos -= 1; while (src[++pos] === "#") ++width; return { char, min, width }; } case "E": { const plus = src[pos + 1] === "+"; if (plus) ++pos; let expDigits = 0; while (src[++pos] === "0") ++expDigits; const width = (plus ? 2 : 1) + expDigits; if (expDigits) return { char, expDigits, plus, width }; else break; } case ".": case ",": return { char, width: 1 }; } return null; } function parseSubpattern(src, pos, onError) { let State; (function(State2) { State2[State2["Prefix"] = 0] = "Prefix"; State2[State2["Number"] = 1] = "Number"; State2[State2["Suffix"] = 2] = "Suffix"; })(State || (State = {})); const prefix = []; const number2 = []; const suffix = []; let state = State.Prefix; let str = ""; while (pos < src.length) { const char = src[pos]; if (char === ";") { pos += 1; break; } switch (state) { case State.Prefix: { const token = parseAffixToken(src, pos, onError); if (token) { if (str) { prefix.push({ char: "'", str, width: str.length }); str = ""; } prefix.push(token); pos += token.width; } else { const token2 = parseNumberToken(src, pos); if (token2) { if (str) { prefix.push({ char: "'", str, width: str.length }); str = ""; } state = State.Number; number2.push(token2); pos += token2.width; } else { str += char; pos += 1; } } break; } case State.Number: { const token = parseNumberToken(src, pos); if (token) { number2.push(token); pos += token.width; } else { state = State.Suffix; } break; } case State.Suffix: { const token = parseAffixToken(src, pos, onError); if (token) { if (str) { suffix.push({ char: "'", str, width: str.length }); str = ""; } suffix.push(token); pos += token.width; } else { str += char; pos += 1; } break; } } } if (str) suffix.push({ char: "'", str, width: str.length }); return { pattern: { prefix, number: number2, suffix }, pos }; } function parseTokens(src, onError) { const { pattern, pos } = parseSubpattern(src, 0, onError); if (pos < src.length) { const { pattern: negative } = parseSubpattern(src, pos, onError); return { tokens: pattern, negative }; } return { tokens: pattern }; } function parseNumberAsSkeleton(tokens, onError) { const res = {}; let hasGroups = false; let hasExponent = false; let intOptional = 0; let intDigits = ""; let decimalPos = -1; let fracDigits = ""; let fracOptional = 0; for (let pos = 0; pos < tokens.length; ++pos) { const token = tokens[pos]; switch (token.char) { case "#": { if (decimalPos === -1) { if (intDigits) { const msg = "Pattern has # after integer digits"; onError(new PatternError("#", msg)); } intOptional += token.width; } else { fracOptional += token.width; } break; } case "0": { if (decimalPos === -1) { intDigits += token.digits; } else { if (fracOptional) { const msg = "Pattern has digits after # in fraction"; onError(new PatternError("0", msg)); } fracDigits += token.digits; } break; } case "@": { if (res.precision) { onError(new MaskedValueError("precision", res.precision)); } res.precision = { style: "precision-fraction", minSignificant: token.min, maxSignificant: token.width }; break; } case ",": hasGroups = true; break; case ".": if (decimalPos === 1) { const msg = "Pattern has more than one decimal separator"; onError(new PatternError(".", msg)); } decimalPos = pos; break; case "E": { if (hasExponent) { onError(new MaskedValueError("exponent", res.notation)); } if (hasGroups) { const msg = "Exponential patterns may not contain grouping separators"; onError(new PatternError("E", msg)); } res.notation = { style: "scientific" }; if (token.expDigits > 1) res.notation.expDigits = token.expDigits; if (token.plus) res.notation.expSign = "sign-always"; hasExponent = true; } } } if (hasGroups) res.group = "group-auto"; else if (intOptional + intDigits.length > 3) res.group = "group-off"; const increment = Number(`${intDigits || "0"}.${fracDigits}`); if (increment) res.precision = { style: "precision-increment", increment }; if (!hasExponent) { if (intDigits.length > 1) res.integerWidth = { min: intDigits.length }; if (!res.precision && (fracDigits.length || fracOptional)) { res.precision = { style: "precision-fraction", minFraction: fracDigits.length, maxFraction: fracDigits.length + fracOptional }; } } else { if (!res.precision || increment) { res.integerWidth = intOptional ? { min: 1, max: intOptional + intDigits.length } : { min: Math.max(1, intDigits.length) }; } if (res.precision) { if (!increment) res.integerWidth = { min: 1, max: 1 }; } else { const dc = intDigits.length + fracDigits.length; if (decimalPos === -1) { if (dc > 0) { res.precision = { style: "precision-fraction", maxSignificant: dc }; } } else { res.precision = { style: "precision-fraction", maxSignificant: Math.max(1, dc) + fracOptional }; if (dc > 1) res.precision.minSignificant = dc; } } } return res; } function handleAffix(affixTokens, res, currency, onError, isPrefix) { let inFmt = false; let str = ""; for (const token of affixTokens) { switch (token.char) { case "%": res.unit = { style: token.style }; if (isPrefix) inFmt = true; else str = ""; break; case "\xA4": if (!currency) { const msg = `The \xA4 pattern requires a currency`; onError(new PatternError("\xA4", msg)); break; } res.unit = { style: "currency", currency }; switch (token.currency) { case "iso-code": res.unitWidth = "unit-width-iso-code"; break; case "full-name": res.unitWidth = "unit-width-full-name"; break; case "narrow": res.unitWidth = "unit-width-narrow"; break; } if (isPrefix) inFmt = true; else str = ""; break; case "*": break; case "+": if (!inFmt) str += "+"; break; case "'": if (!inFmt) str += token.str; break; } } return str; } function getNegativeAffix(affixTokens, isPrefix) { let inFmt = false; let str = ""; for (const token of affixTokens) { switch (token.char) { case "%": case "\xA4": if (isPrefix) inFmt = true; else str = ""; break; case "-": if (!inFmt) str += "-"; break; case "'": if (!inFmt) str += token.str; break; } } return str; } function parseNumberPattern(src, currency) { let onError = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : (error) => { throw error; }; const { tokens, negative } = parseTokens(src, onError); const res = parseNumberAsSkeleton(tokens.number, onError); const prefix = handleAffix(tokens.prefix, res, currency, onError, true); const suffix = handleAffix(tokens.suffix, res, currency, onError, false); if (negative) { const negPrefix = getNegativeAffix(negative.prefix, true); const negSuffix = getNegativeAffix(negative.suffix, false); res.affix = { pos: [prefix, suffix], neg: [negPrefix, negSuffix] }; res.sign = "sign-never"; } else if (prefix || suffix) { res.affix = { pos: [prefix, suffix] }; } return res; } function isNumberingSystem(ns) { const systems = ["arab", "arabext", "bali", "beng", "deva", "fullwide", "gujr", "guru", "hanidec", "khmr", "knda", "laoo", "latn", "limb", "mlym", "mong", "mymr", "orya", "tamldec", "telu", "thai", "tibt"]; return systems.indexOf(ns) !== -1; } function isUnit(unit) { const types = ["acceleration", "angle", "area", "concentr", "consumption", "digital", "duration", "electric", "energy", "force", "frequency", "graphics", "length", "light", "mass", "power", "pressure", "speed", "temperature", "torque", "volume"]; const [type] = unit.split("-", 1); return types.indexOf(type) !== -1; } const maxOptions = { "compact-short": 0, "compact-long": 0, "notation-simple": 0, scientific: 2, engineering: 2, percent: 0, permille: 0, "base-unit": 0, currency: 1, "measure-unit": 1, "per-measure-unit": 1, "unit-width-narrow": 0, "unit-width-short": 0, "unit-width-full-name": 0, "unit-width-iso-code": 0, "unit-width-hidden": 0, "precision-integer": 0, "precision-unlimited": 0, "precision-currency-standard": 1, "precision-currency-cash": 0, "precision-increment": 1, "rounding-mode-ceiling": 0, "rounding-mode-floor": 0, "rounding-mode-down": 0, "rounding-mode-up": 0, "rounding-mode-half-even": 0, "rounding-mode-half-down": 0, "rounding-mode-half-up": 0, "rounding-mode-unnecessary": 0, "integer-width": 1, scale: 1, "group-off": 0, "group-min2": 0, "group-auto": 0, "group-on-aligned": 0, "group-thousands": 0, latin: 0, "numbering-system": 1, "sign-auto": 0, "sign-always": 0, "sign-never": 0, "sign-accounting": 0, "sign-accounting-always": 0, "sign-except-zero": 0, "sign-accounting-except-zero": 0, "decimal-auto": 0, "decimal-always": 0 }; const minOptions = { currency: 1, "integer-width": 1, "measure-unit": 1, "numbering-system": 1, "per-measure-unit": 1, "precision-increment": 1, scale: 1 }; function hasMaxOption(stem) { return stem in maxOptions; } function hasMinOption(stem) { return stem in minOptions; } function validOptions(stem, options, onError) { if (hasMaxOption(stem)) { const maxOpt = maxOptions[stem]; if (options.length > maxOpt) { if (maxOpt === 0) { for (const opt of options) onError(new BadOptionError(stem, opt)); } else { onError(new TooManyOptionsError(stem, options, maxOpt)); } return false; } else if (hasMinOption(stem) && options.length < minOptions[stem]) { onError(new MissingOptionError(stem)); return false; } } return true; } function parseBlueprintDigits(src, style) { const re = style === "fraction" ? /^\.(0*)(\+|#*)$/ : /^(@+)(\+|#*)$/; const match = src && src.match(re); if (match) { const min = match[1].length; switch (match[2].charAt(0)) { case "": return { min, max: min }; case "+": return { min, max: null }; case "#": { return { min, max: min + match[2].length }; } } } return null; } function parsePrecisionBlueprint(stem, options, onError) { const fd = parseBlueprintDigits(stem, "fraction"); if (fd) { if (options.length > 1) onError(new TooManyOptionsError(stem, options, 1)); const res = { style: "precision-fraction", source: stem, minFraction: fd.min }; if (fd.max != null) res.maxFraction = fd.max; const option = options[0]; const sd3 = parseBlueprintDigits(option, "significant"); if (sd3) { res.source = `${stem}/${option}`; res.minSignificant = sd3.min; if (sd3.max != null) res.maxSignificant = sd3.max; } else if (option) { onError(new BadOptionError(stem, option)); } return res; } const sd2 = parseBlueprintDigits(stem, "significant"); if (sd2) { for (const opt of options) onError(new BadOptionError(stem, opt)); const res = { style: "precision-fraction", source: stem, minSignificant: sd2.min }; if (sd2.max != null) res.maxSignificant = sd2.max; return res; } return null; } class TokenParser { constructor(onError) { this.skeleton = {}; this.onError = onError; } badOption(stem, opt) { this.onError(new BadOptionError(stem, opt)); } assertEmpty(key) { const prev = this.skeleton[key]; if (prev) this.onError(new MaskedValueError(key, prev)); } parseToken(stem, options) { if (!validOptions(stem, options, this.onError)) return; const option = options[0]; const res = this.skeleton; switch (stem) { // notation case "compact-short": case "compact-long": case "notation-simple": this.assertEmpty("notation"); res.notation = { style: stem }; break; case "scientific": case "engineering": { let expDigits = null; let expSign = void 0; for (const opt of options) { switch (opt) { case "sign-auto": case "sign-always": case "sign-never": case "sign-accounting": case "sign-accounting-always": case "sign-except-zero": case "sign-accounting-except-zero": expSign = opt; break; default: if (/^\+e+$/.test(opt)) { expDigits = opt.length - 1; } else { this.badOption(stem, opt); } } } this.assertEmpty("notation"); const source = options.join("/"); res.notation = expDigits && expSign ? { style: stem, source, expDigits, expSign } : expDigits ? { style: stem, source, expDigits } : expSign ? { style: stem, source, expSign } : { style: stem, source }; break; } // unit case "percent": case "permille": case "base-unit": this.assertEmpty("unit"); res.unit = { style: stem }; break; case "currency": if (/^[A-Z]{3}$/.test(option)) { this.assertEmpty("unit"); res.unit = { style: stem, currency: option }; } else { this.badOption(stem, option); } break; case "measure-unit": { if (isUnit(option)) { this.assertEmpty("unit"); res.unit = { style: stem, unit: option }; } else { this.badOption(stem, option); } break; } // unitPer case "per-measure-unit": { if (isUnit(option)) { this.assertEmpty("unitPer"); res.unitPer = option; } else { this.badOption(stem, option); } break; } // unitWidth case "unit-width-narrow": case "unit-width-short": case "unit-width-full-name": case "unit-width-iso-code": case "unit-width-hidden": this.assertEmpty("unitWidth"); res.unitWidth = stem; break; // precision case "precision-integer": case "precision-unlimited": case "precision-currency-cash": this.assertEmpty("precision"); res.precision = { style: stem }; break; case "precision-currency-standard": this.assertEmpty("precision"); if (option === "w") { res.precision = { style: stem, trailingZero: "stripIfInteger" }; } else { res.precision = { style: stem }; } break; case "precision-increment": { const increment = Number(option); if (increment > 0) { this.assertEmpty("precision"); res.precision = { style: stem, increment }; } else { this.badOption(stem, option); } break; } // roundingMode case "rounding-mode-ceiling": case "rounding-mode-floor": case "rounding-mode-down": case "rounding-mode-up": case "rounding-mode-half-even": case "rounding-mode-half-odd": case "rounding-mode-half-ceiling": case "rounding-mode-half-floor": case "rounding-mode-half-down": case "rounding-mode-half-up": case "rounding-mode-unnecessary": this.assertEmpty("roundingMode"); res.roundingMode = stem; break; // integerWidth case "integer-width": { if (/^\+0*$/.test(option)) { this.assertEmpty("integerWidth"); res.integerWidth = { source: option, min: option.length - 1 }; } else { const m2 = option.match(/^#*(0*)$/); if (m2) { this.assertEmpty("integerWidth"); res.integerWidth = { source: option, min: m2[1].length,