From d29a4253df543399387e46349d2a6ecc5f534e41 Mon Sep 17 00:00:00 2001 From: Niklas Kiefer Date: Mon, 25 Sep 2023 15:59:35 +0200 Subject: [PATCH] feat: update to form-js@1.3.0 --- src/main/resources/public/css/form-js.css | 57 +- .../resources/public/js/form-viewer.umd.js | 4899 +++++++++-------- 2 files changed, 2717 insertions(+), 2239 deletions(-) diff --git a/src/main/resources/public/css/form-js.css b/src/main/resources/public/css/form-js.css index ca3bdf2..baf2240 100644 --- a/src/main/resources/public/css/form-js.css +++ b/src/main/resources/public/css/form-js.css @@ -63,6 +63,7 @@ --cds-border-strong, var(--cds-border-strong-01, var(--color-grey-225-10-55)) ); + --color-borders-group: var(--cds-border-subtle, var(--color-grey-225-10-85)); --color-borders-disabled: var(--cds-border-disabled, var(--color-grey-225-10-75)); --color-borders-adornment: var( --cds-border-subtle, @@ -80,6 +81,7 @@ --color-datepicker-focused-day: var(--cds-button-primary, var(--color-grey-225-10-55)); --color-shadow: var(--cds-shadow, var(--color-grey-225-10-85)); --font-family: "IBM Plex Sans", sans-serif; + --font-size-group: 15px; --font-size-base: 14px; --font-size-input: 14px; --font-size-label: 12px; @@ -183,6 +185,11 @@ margin-right: 0; } +.fjs-container .cds--grid .cds--grid .cds--row { + margin-left: -1rem; + margin-right: -1rem; +} + @media (max-width: 66rem) { .cds--col { flex-basis: unset !important; @@ -210,7 +217,7 @@ display: flex; flex-direction: column; flex-grow: 1; - min-height: 100px; + min-height: 80px; } .fjs-container .fjs-element { @@ -296,6 +303,52 @@ color: var(--color-text-lighter); } +.fjs-container .fjs-form-field-group { + padding: 10px 6px 0 6px; + margin: 0 10px; +} + +.fjs-container .fjs-form-field-group .cds--grid { + padding: 4px 16px; +} + +.fjs-container .fjs-form-field-group .fjs-form-field-group .fjs-layout-column:first-child > .fjs-element > .fjs-form-field-group:not(.fjs-editor-container .fjs-form-field-group), +.fjs-container .fjs-layout-column:first-child > .fjs-element > .fjs-form-field-group:not(.fjs-editor-container .fjs-form-field-group) { + margin-left: -6px; +} + +.fjs-container .fjs-form-field-group .fjs-form-field-group .fjs-layout-column:last-child > .fjs-element > .fjs-form-field-group:not(.fjs-editor-container .fjs-form-field-group), +.fjs-container .fjs-layout-column:last-child > .fjs-element > .fjs-form-field-group:not(.fjs-editor-container .fjs-form-field-group) { + margin-right: -6px; +} + +.fjs-container .fjs-form-field-group .fjs-layout-column:first-child > .fjs-element > .fjs-form-field-group:not(.fjs-editor-container .fjs-form-field-group) { + margin-left: 11px; +} + +.fjs-container .fjs-form-field-group .fjs-layout-column:last-child > .fjs-element > .fjs-form-field-group:not(.fjs-editor-container .fjs-form-field-group) { + margin-right: 11px; +} + +.fjs-container .fjs-form-field-group.fjs-outlined { + outline: solid var(--color-borders-group) 2px; +} + +.fjs-container .fjs-form-field-group label { + font-size: var(--font-size-label); +} + +.fjs-container .fjs-form-field-group .fjs-form-field-group .cds--grid { + padding-left: 2rem; + padding-right: 2rem; +} + +.fjs-container .fjs-form-field-group > label { + font-size: var(--font-size-group); + line-height: var(--line-height-input); + margin-left: 7px; +} + .fjs-container .fjs-form-field-checkbox .fjs-form-field-label, .fjs-container .fjs-form-field-checklist .fjs-form-field-label:not(:first-child), .fjs-container .fjs-form-field-radio .fjs-form-field-label:not(:first-child) { @@ -3493,4 +3546,4 @@ span.flatpickr-weekday { } span.flatpickr-day.selected { font-weight: bold; -} \ No newline at end of file +} diff --git a/src/main/resources/public/js/form-viewer.umd.js b/src/main/resources/public/js/form-viewer.umd.js index 93526f6..ea76ae3 100644 --- a/src/main/resources/public/js/form-viewer.umd.js +++ b/src/main/resources/public/js/form-viewer.umd.js @@ -316,6 +316,18 @@ } + /** + * Get the values in the collection. + * + * @param {Object|Array} collection + * + * @return {Array} + */ + function values(collection) { + return map(collection, (val) => val); + } + + /** * Group collection members by attribute. * @@ -481,1029 +493,1029 @@ return isUndefined$1(currentTarget) ? defaultValue : currentTarget; } - /* - * big.js v6.2.1 - * A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic. - * Copyright (c) 2022 Michael Mclaughlin - * https://github.com/MikeMcl/big.js/LICENCE.md - */ - - - /************************************** EDITABLE DEFAULTS *****************************************/ - - - // The default values below must be integers within the stated ranges. - - /* - * The maximum number of decimal places (DP) of the results of operations involving division: - * div and sqrt, and pow with negative exponents. - */ - var DP = 20, // 0 to MAX_DP - - /* - * The rounding mode (RM) used when rounding to the above decimal places. - * - * 0 Towards zero (i.e. truncate, no rounding). (ROUND_DOWN) - * 1 To nearest neighbour. If equidistant, round up. (ROUND_HALF_UP) - * 2 To nearest neighbour. If equidistant, to even. (ROUND_HALF_EVEN) - * 3 Away from zero. (ROUND_UP) - */ - RM = 1, // 0, 1, 2 or 3 - - // The maximum value of DP and Big.DP. - MAX_DP = 1E6, // 0 to 1000000 - - // The maximum magnitude of the exponent argument to the pow method. - MAX_POWER = 1E6, // 1 to 1000000 - - /* - * The negative exponent (NE) at and beneath which toString returns exponential notation. - * (JavaScript numbers: -7) - * -1000000 is the minimum recommended exponent value of a Big. - */ - NE = -7, // 0 to -1000000 - - /* - * The positive exponent (PE) at and above which toString returns exponential notation. - * (JavaScript numbers: 21) - * 1000000 is the maximum recommended exponent value of a Big, but this limit is not enforced. - */ - PE = 21, // 0 to 1000000 - - /* - * When true, an error will be thrown if a primitive number is passed to the Big constructor, - * or if valueOf is called, or if toNumber is called on a Big which cannot be converted to a - * primitive number without a loss of precision. - */ - STRICT = false, // true or false - - - /**************************************************************************************************/ - - - // Error messages. - NAME = '[big.js] ', - INVALID$3 = NAME + 'Invalid ', - INVALID_DP = INVALID$3 + 'decimal places', - INVALID_RM = INVALID$3 + 'rounding mode', - DIV_BY_ZERO = NAME + 'Division by zero', - - // The shared prototype object. - P$2 = {}, - UNDEFINED = void 0, - NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; - - - /* - * Create and return a Big constructor. - */ - function _Big_() { - - /* - * The Big constructor and exported function. - * Create and return a new instance of a Big number object. - * - * n {number|string|Big} A numeric value. - */ - function Big(n) { - var x = this; - - // Enable constructor usage without new. - if (!(x instanceof Big)) return n === UNDEFINED ? _Big_() : new Big(n); - - // Duplicate. - if (n instanceof Big) { - x.s = n.s; - x.e = n.e; - x.c = n.c.slice(); - } else { - if (typeof n !== 'string') { - if (Big.strict === true && typeof n !== 'bigint') { - throw TypeError(INVALID$3 + 'value'); - } - - // Minus zero? - n = n === 0 && 1 / n < 0 ? '-0' : String(n); - } - - parse$1(x, n); - } - - // Retain a reference to this Big constructor. - // Shadow Big.prototype.constructor which points to Object. - x.constructor = Big; - } - - Big.prototype = P$2; - Big.DP = DP; - Big.RM = RM; - Big.NE = NE; - Big.PE = PE; - Big.strict = STRICT; - Big.roundDown = 0; - Big.roundHalfUp = 1; - Big.roundHalfEven = 2; - Big.roundUp = 3; - - return Big; - } - - - /* - * Parse the number or string value passed to a Big constructor. - * - * x {Big} A Big number instance. - * n {number|string} A numeric value. - */ - function parse$1(x, n) { - var e, i, nl; - - if (!NUMERIC.test(n)) { - throw Error(INVALID$3 + 'number'); - } - - // Determine sign. - x.s = n.charAt(0) == '-' ? (n = n.slice(1), -1) : 1; - - // Decimal point? - if ((e = n.indexOf('.')) > -1) n = n.replace('.', ''); - - // Exponential form? - if ((i = n.search(/e/i)) > 0) { - - // Determine exponent. - if (e < 0) e = i; - e += +n.slice(i + 1); - n = n.substring(0, i); - } else if (e < 0) { - - // Integer. - e = n.length; - } - - nl = n.length; - - // Determine leading zeros. - for (i = 0; i < nl && n.charAt(i) == '0';) ++i; - - if (i == nl) { - - // Zero. - x.c = [x.e = 0]; - } else { - - // Determine trailing zeros. - for (; nl > 0 && n.charAt(--nl) == '0';); - x.e = e - i - 1; - x.c = []; - - // Convert string to array of digits without leading/trailing zeros. - for (e = 0; i <= nl;) x.c[e++] = +n.charAt(i++); - } - - return x; - } - - - /* - * Round Big x to a maximum of sd significant digits using rounding mode rm. - * - * x {Big} The Big to round. - * sd {number} Significant digits: integer, 0 to MAX_DP inclusive. - * rm {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). - * [more] {boolean} Whether the result of division was truncated. - */ - function round$1(x, sd, rm, more) { - var xc = x.c; - - if (rm === UNDEFINED) rm = x.constructor.RM; - if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) { - throw Error(INVALID_RM); - } - - if (sd < 1) { - more = - rm === 3 && (more || !!xc[0]) || sd === 0 && ( - rm === 1 && xc[0] >= 5 || - rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED)) - ); - - xc.length = 1; - - if (more) { - - // 1, 0.1, 0.01, 0.001, 0.0001 etc. - x.e = x.e - sd + 1; - xc[0] = 1; - } else { - - // Zero. - xc[0] = x.e = 0; - } - } else if (sd < xc.length) { - - // xc[sd] is the digit after the digit that may be rounded up. - more = - rm === 1 && xc[sd] >= 5 || - rm === 2 && (xc[sd] > 5 || xc[sd] === 5 && - (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) || - rm === 3 && (more || !!xc[0]); - - // Remove any digits after the required precision. - xc.length = sd; - - // Round up? - if (more) { - - // Rounding up may mean the previous digit has to be rounded up. - for (; ++xc[--sd] > 9;) { - xc[sd] = 0; - if (sd === 0) { - ++x.e; - xc.unshift(1); - break; - } - } - } - - // Remove trailing zeros. - for (sd = xc.length; !xc[--sd];) xc.pop(); - } - - return x; - } - - - /* - * Return a string representing the value of Big x in normal or exponential notation. - * Handles P.toExponential, P.toFixed, P.toJSON, P.toPrecision, P.toString and P.valueOf. - */ - function stringify(x, doExponential, isNonzero) { - var e = x.e, - s = x.c.join(''), - n = s.length; - - // Exponential notation? - if (doExponential) { - s = s.charAt(0) + (n > 1 ? '.' + s.slice(1) : '') + (e < 0 ? 'e' : 'e+') + e; - - // Normal notation. - } else if (e < 0) { - for (; ++e;) s = '0' + s; - s = '0.' + s; - } else if (e > 0) { - if (++e > n) { - for (e -= n; e--;) s += '0'; - } else if (e < n) { - s = s.slice(0, e) + '.' + s.slice(e); - } - } else if (n > 1) { - s = s.charAt(0) + '.' + s.slice(1); - } - - return x.s < 0 && isNonzero ? '-' + s : s; - } - - - // Prototype/instance methods - - - /* - * Return a new Big whose value is the absolute value of this Big. - */ - P$2.abs = function () { - var x = new this.constructor(this); - x.s = 1; - return x; - }; - - - /* - * Return 1 if the value of this Big is greater than the value of Big y, - * -1 if the value of this Big is less than the value of Big y, or - * 0 if they have the same value. - */ - P$2.cmp = function (y) { - var isneg, - x = this, - xc = x.c, - yc = (y = new x.constructor(y)).c, - i = x.s, - j = y.s, - k = x.e, - l = y.e; - - // Either zero? - if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i; - - // Signs differ? - if (i != j) return i; - - isneg = i < 0; - - // Compare exponents. - if (k != l) return k > l ^ isneg ? 1 : -1; - - j = (k = xc.length) < (l = yc.length) ? k : l; - - // Compare digit by digit. - for (i = -1; ++i < j;) { - if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1; - } - - // Compare lengths. - return k == l ? 0 : k > l ^ isneg ? 1 : -1; - }; - - - /* - * Return a new Big whose value is the value of this Big divided by the value of Big y, rounded, - * if necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM. - */ - P$2.div = function (y) { - var x = this, - Big = x.constructor, - a = x.c, // dividend - b = (y = new Big(y)).c, // divisor - k = x.s == y.s ? 1 : -1, - dp = Big.DP; - - if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { - throw Error(INVALID_DP); - } - - // Divisor is zero? - if (!b[0]) { - throw Error(DIV_BY_ZERO); - } - - // Dividend is 0? Return +-0. - if (!a[0]) { - y.s = k; - y.c = [y.e = 0]; - return y; - } - - var bl, bt, n, cmp, ri, - bz = b.slice(), - ai = bl = b.length, - al = a.length, - r = a.slice(0, bl), // remainder - rl = r.length, - q = y, // quotient - qc = q.c = [], - qi = 0, - p = dp + (q.e = x.e - y.e) + 1; // precision of the result - - q.s = k; - k = p < 0 ? 0 : p; - - // Create version of divisor with leading zero. - bz.unshift(0); - - // Add zeros to make remainder as long as divisor. - for (; rl++ < bl;) r.push(0); - - do { - - // n is how many times the divisor goes into current remainder. - for (n = 0; n < 10; n++) { - - // Compare divisor and remainder. - if (bl != (rl = r.length)) { - cmp = bl > rl ? 1 : -1; - } else { - for (ri = -1, cmp = 0; ++ri < bl;) { - if (b[ri] != r[ri]) { - cmp = b[ri] > r[ri] ? 1 : -1; - break; - } - } - } - - // If divisor < remainder, subtract divisor from remainder. - if (cmp < 0) { - - // Remainder can't be more than 1 digit longer than divisor. - // Equalise lengths using divisor with extra leading zero? - for (bt = rl == bl ? b : bz; rl;) { - if (r[--rl] < bt[rl]) { - ri = rl; - for (; ri && !r[--ri];) r[ri] = 9; - --r[ri]; - r[rl] += 10; - } - r[rl] -= bt[rl]; - } - - for (; !r[0];) r.shift(); - } else { - break; - } - } - - // Add the digit n to the result array. - qc[qi++] = cmp ? n : ++n; - - // Update the remainder. - if (r[0] && cmp) r[rl] = a[ai] || 0; - else r = [a[ai]]; - - } while ((ai++ < al || r[0] !== UNDEFINED) && k--); - - // Leading zero? Do not remove if result is simply zero (qi == 1). - if (!qc[0] && qi != 1) { - - // There can't be more than one zero. - qc.shift(); - q.e--; - p--; - } - - // Round? - if (qi > p) round$1(q, p, Big.RM, r[0] !== UNDEFINED); - - return q; - }; - - - /* - * Return true if the value of this Big is equal to the value of Big y, otherwise return false. - */ - P$2.eq = function (y) { - return this.cmp(y) === 0; - }; - - - /* - * Return true if the value of this Big is greater than the value of Big y, otherwise return - * false. - */ - P$2.gt = function (y) { - return this.cmp(y) > 0; - }; - - - /* - * Return true if the value of this Big is greater than or equal to the value of Big y, otherwise - * return false. - */ - P$2.gte = function (y) { - return this.cmp(y) > -1; - }; - - - /* - * Return true if the value of this Big is less than the value of Big y, otherwise return false. - */ - P$2.lt = function (y) { - return this.cmp(y) < 0; - }; - - - /* - * Return true if the value of this Big is less than or equal to the value of Big y, otherwise - * return false. - */ - P$2.lte = function (y) { - return this.cmp(y) < 1; - }; - - - /* - * Return a new Big whose value is the value of this Big minus the value of Big y. - */ - P$2.minus = P$2.sub = function (y) { - var i, j, t, xlty, - x = this, - Big = x.constructor, - a = x.s, - b = (y = new Big(y)).s; - - // Signs differ? - if (a != b) { - y.s = -b; - return x.plus(y); - } - - var xc = x.c.slice(), - xe = x.e, - yc = y.c, - ye = y.e; - - // Either zero? - if (!xc[0] || !yc[0]) { - if (yc[0]) { - y.s = -b; - } else if (xc[0]) { - y = new Big(x); - } else { - y.s = 1; - } - return y; - } - - // Determine which is the bigger number. Prepend zeros to equalise exponents. - if (a = xe - ye) { - - if (xlty = a < 0) { - a = -a; - t = xc; - } else { - ye = xe; - t = yc; - } - - t.reverse(); - for (b = a; b--;) t.push(0); - t.reverse(); - } else { - - // Exponents equal. Check digit by digit. - j = ((xlty = xc.length < yc.length) ? xc : yc).length; - - for (a = b = 0; b < j; b++) { - if (xc[b] != yc[b]) { - xlty = xc[b] < yc[b]; - break; - } - } - } - - // x < y? Point xc to the array of the bigger number. - if (xlty) { - t = xc; - xc = yc; - yc = t; - y.s = -y.s; - } - - /* - * Append zeros to xc if shorter. No need to add zeros to yc if shorter as subtraction only - * needs to start at yc.length. - */ - if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--;) xc[i++] = 0; - - // Subtract yc from xc. - for (b = i; j > a;) { - if (xc[--j] < yc[j]) { - for (i = j; i && !xc[--i];) xc[i] = 9; - --xc[i]; - xc[j] += 10; - } - - xc[j] -= yc[j]; - } - - // Remove trailing zeros. - for (; xc[--b] === 0;) xc.pop(); - - // Remove leading zeros and adjust exponent accordingly. - for (; xc[0] === 0;) { - xc.shift(); - --ye; - } - - if (!xc[0]) { - - // n - n = +0 - y.s = 1; - - // Result must be zero. - xc = [ye = 0]; - } - - y.c = xc; - y.e = ye; - - return y; - }; - - - /* - * Return a new Big whose value is the value of this Big modulo the value of Big y. - */ - P$2.mod = function (y) { - var ygtx, - x = this, - Big = x.constructor, - a = x.s, - b = (y = new Big(y)).s; - - if (!y.c[0]) { - throw Error(DIV_BY_ZERO); - } - - x.s = y.s = 1; - ygtx = y.cmp(x) == 1; - x.s = a; - y.s = b; - - if (ygtx) return new Big(x); - - a = Big.DP; - b = Big.RM; - Big.DP = Big.RM = 0; - x = x.div(y); - Big.DP = a; - Big.RM = b; - - return this.minus(x.times(y)); - }; - - - /* - * Return a new Big whose value is the value of this Big negated. - */ - P$2.neg = function () { - var x = new this.constructor(this); - x.s = -x.s; - return x; - }; - - - /* - * Return a new Big whose value is the value of this Big plus the value of Big y. - */ - P$2.plus = P$2.add = function (y) { - var e, k, t, - x = this, - Big = x.constructor; - - y = new Big(y); - - // Signs differ? - if (x.s != y.s) { - y.s = -y.s; - return x.minus(y); - } - - var xe = x.e, - xc = x.c, - ye = y.e, - yc = y.c; - - // Either zero? - if (!xc[0] || !yc[0]) { - if (!yc[0]) { - if (xc[0]) { - y = new Big(x); - } else { - y.s = x.s; - } - } - return y; - } - - xc = xc.slice(); - - // Prepend zeros to equalise exponents. - // Note: reverse faster than unshifts. - if (e = xe - ye) { - if (e > 0) { - ye = xe; - t = yc; - } else { - e = -e; - t = xc; - } - - t.reverse(); - for (; e--;) t.push(0); - t.reverse(); - } - - // Point xc to the longer array. - if (xc.length - yc.length < 0) { - t = yc; - yc = xc; - xc = t; - } - - e = yc.length; - - // Only start adding at yc.length - 1 as the further digits of xc can be left as they are. - for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0; - - // No need to check for zero, as +x + +y != 0 && -x + -y != 0 - - if (k) { - xc.unshift(k); - ++ye; - } - - // Remove trailing zeros. - for (e = xc.length; xc[--e] === 0;) xc.pop(); - - y.c = xc; - y.e = ye; - - return y; - }; - - - /* - * Return a Big whose value is the value of this Big raised to the power n. - * If n is negative, round to a maximum of Big.DP decimal places using rounding - * mode Big.RM. - * - * n {number} Integer, -MAX_POWER to MAX_POWER inclusive. - */ - P$2.pow = function (n) { - var x = this, - one = new x.constructor('1'), - y = one, - isneg = n < 0; - - if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) { - throw Error(INVALID$3 + 'exponent'); - } - - if (isneg) n = -n; - - for (;;) { - if (n & 1) y = y.times(x); - n >>= 1; - if (!n) break; - x = x.times(x); - } - - return isneg ? one.div(y) : y; - }; - - - /* - * Return a new Big whose value is the value of this Big rounded to a maximum precision of sd - * significant digits using rounding mode rm, or Big.RM if rm is not specified. - * - * sd {number} Significant digits: integer, 1 to MAX_DP inclusive. - * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). - */ - P$2.prec = function (sd, rm) { - if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { - throw Error(INVALID$3 + 'precision'); - } - return round$1(new this.constructor(this), sd, rm); - }; - - - /* - * Return a new Big whose value is the value of this Big rounded to a maximum of dp decimal places - * using rounding mode rm, or Big.RM if rm is not specified. - * If dp is negative, round to an integer which is a multiple of 10**-dp. - * If dp is not specified, round to 0 decimal places. - * - * dp? {number} Integer, -MAX_DP to MAX_DP inclusive. - * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). - */ - P$2.round = function (dp, rm) { - if (dp === UNDEFINED) dp = 0; - else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP) { - throw Error(INVALID_DP); - } - return round$1(new this.constructor(this), dp + this.e + 1, rm); - }; - - - /* - * Return a new Big whose value is the square root of the value of this Big, rounded, if - * necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM. - */ - P$2.sqrt = function () { - var r, c, t, - x = this, - Big = x.constructor, - s = x.s, - e = x.e, - half = new Big('0.5'); - - // Zero? - if (!x.c[0]) return new Big(x); - - // Negative? - if (s < 0) { - throw Error(NAME + 'No square root'); - } - - // Estimate. - s = Math.sqrt(x + ''); - - // Math.sqrt underflow/overflow? - // Re-estimate: pass x coefficient to Math.sqrt as integer, then adjust the result exponent. - if (s === 0 || s === 1 / 0) { - c = x.c.join(''); - if (!(c.length + e & 1)) c += '0'; - s = Math.sqrt(c); - e = ((e + 1) / 2 | 0) - (e < 0 || e & 1); - r = new Big((s == 1 / 0 ? '5e' : (s = s.toExponential()).slice(0, s.indexOf('e') + 1)) + e); - } else { - r = new Big(s + ''); - } - - e = r.e + (Big.DP += 4); - - // Newton-Raphson iteration. - do { - t = r; - r = half.times(t.plus(x.div(t))); - } while (t.c.slice(0, e).join('') !== r.c.slice(0, e).join('')); - - return round$1(r, (Big.DP -= 4) + r.e + 1, Big.RM); - }; - - - /* - * Return a new Big whose value is the value of this Big times the value of Big y. - */ - P$2.times = P$2.mul = function (y) { - var c, - x = this, - Big = x.constructor, - xc = x.c, - yc = (y = new Big(y)).c, - a = xc.length, - b = yc.length, - i = x.e, - j = y.e; - - // Determine sign of result. - y.s = x.s == y.s ? 1 : -1; - - // Return signed 0 if either 0. - if (!xc[0] || !yc[0]) { - y.c = [y.e = 0]; - return y; - } - - // Initialise exponent of result as x.e + y.e. - y.e = i + j; - - // If array xc has fewer digits than yc, swap xc and yc, and lengths. - if (a < b) { - c = xc; - xc = yc; - yc = c; - j = a; - a = b; - b = j; - } - - // Initialise coefficient array of result with zeros. - for (c = new Array(j = a + b); j--;) c[j] = 0; - - // Multiply. - - // i is initially xc.length. - for (i = b; i--;) { - b = 0; - - // a is yc.length. - for (j = a + i; j > i;) { - - // Current sum of products at this digit position, plus carry. - b = c[j] + yc[i] * xc[j - i - 1] + b; - c[j--] = b % 10; - - // carry - b = b / 10 | 0; - } - - c[j] = b; - } - - // Increment result exponent if there is a final carry, otherwise remove leading zero. - if (b) ++y.e; - else c.shift(); - - // Remove trailing zeros. - for (i = c.length; !c[--i];) c.pop(); - y.c = c; - - return y; - }; - - - /* - * Return a string representing the value of this Big in exponential notation rounded to dp fixed - * decimal places using rounding mode rm, or Big.RM if rm is not specified. - * - * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive. - * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). - */ - P$2.toExponential = function (dp, rm) { - var x = this, - n = x.c[0]; - - if (dp !== UNDEFINED) { - if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { - throw Error(INVALID_DP); - } - x = round$1(new x.constructor(x), ++dp, rm); - for (; x.c.length < dp;) x.c.push(0); - } - - return stringify(x, true, !!n); - }; - - - /* - * Return a string representing the value of this Big in normal notation rounded to dp fixed - * decimal places using rounding mode rm, or Big.RM if rm is not specified. - * - * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive. - * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). - * - * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'. - * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. - */ - P$2.toFixed = function (dp, rm) { - var x = this, - n = x.c[0]; - - if (dp !== UNDEFINED) { - if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { - throw Error(INVALID_DP); - } - x = round$1(new x.constructor(x), dp + x.e + 1, rm); - - // x.e may have changed if the value is rounded up. - for (dp = dp + x.e + 1; x.c.length < dp;) x.c.push(0); - } - - return stringify(x, false, !!n); - }; - - - /* - * Return a string representing the value of this Big. - * Return exponential notation if this Big has a positive exponent equal to or greater than - * Big.PE, or a negative exponent equal to or less than Big.NE. - * Omit the sign for negative zero. - */ - P$2[Symbol.for('nodejs.util.inspect.custom')] = P$2.toJSON = P$2.toString = function () { - var x = this, - Big = x.constructor; - return stringify(x, x.e <= Big.NE || x.e >= Big.PE, !!x.c[0]); - }; - - - /* - * Return the value of this Big as a primitve number. - */ - P$2.toNumber = function () { - var n = Number(stringify(this, true, true)); - if (this.constructor.strict === true && !this.eq(n.toString())) { - throw Error(NAME + 'Imprecise conversion'); - } - return n; - }; - - - /* - * Return a string representing the value of this Big rounded to sd significant digits using - * rounding mode rm, or Big.RM if rm is not specified. - * Use exponential notation if sd is less than the number of digits necessary to represent - * the integer part of the value in normal notation. - * - * sd {number} Significant digits: integer, 1 to MAX_DP inclusive. - * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). - */ - P$2.toPrecision = function (sd, rm) { - var x = this, - Big = x.constructor, - n = x.c[0]; - - if (sd !== UNDEFINED) { - if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { - throw Error(INVALID$3 + 'precision'); - } - x = round$1(new Big(x), sd, rm); - for (; x.c.length < sd;) x.c.push(0); - } - - return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, !!n); - }; - - - /* - * Return a string representing the value of this Big. - * Return exponential notation if this Big has a positive exponent equal to or greater than - * Big.PE, or a negative exponent equal to or less than Big.NE. - * Include the sign for negative zero. - */ - P$2.valueOf = function () { - var x = this, - Big = x.constructor; - if (Big.strict === true) { - throw Error(NAME + 'valueOf disallowed'); - } - return stringify(x, x.e <= Big.NE || x.e >= Big.PE, true); - }; - - - // Export - - + /* + * big.js v6.2.1 + * A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic. + * Copyright (c) 2022 Michael Mclaughlin + * https://github.com/MikeMcl/big.js/LICENCE.md + */ + + + /************************************** EDITABLE DEFAULTS *****************************************/ + + + // The default values below must be integers within the stated ranges. + + /* + * The maximum number of decimal places (DP) of the results of operations involving division: + * div and sqrt, and pow with negative exponents. + */ + var DP = 20, // 0 to MAX_DP + + /* + * The rounding mode (RM) used when rounding to the above decimal places. + * + * 0 Towards zero (i.e. truncate, no rounding). (ROUND_DOWN) + * 1 To nearest neighbour. If equidistant, round up. (ROUND_HALF_UP) + * 2 To nearest neighbour. If equidistant, to even. (ROUND_HALF_EVEN) + * 3 Away from zero. (ROUND_UP) + */ + RM = 1, // 0, 1, 2 or 3 + + // The maximum value of DP and Big.DP. + MAX_DP = 1E6, // 0 to 1000000 + + // The maximum magnitude of the exponent argument to the pow method. + MAX_POWER = 1E6, // 1 to 1000000 + + /* + * The negative exponent (NE) at and beneath which toString returns exponential notation. + * (JavaScript numbers: -7) + * -1000000 is the minimum recommended exponent value of a Big. + */ + NE = -7, // 0 to -1000000 + + /* + * The positive exponent (PE) at and above which toString returns exponential notation. + * (JavaScript numbers: 21) + * 1000000 is the maximum recommended exponent value of a Big, but this limit is not enforced. + */ + PE = 21, // 0 to 1000000 + + /* + * When true, an error will be thrown if a primitive number is passed to the Big constructor, + * or if valueOf is called, or if toNumber is called on a Big which cannot be converted to a + * primitive number without a loss of precision. + */ + STRICT = false, // true or false + + + /**************************************************************************************************/ + + + // Error messages. + NAME = '[big.js] ', + INVALID$3 = NAME + 'Invalid ', + INVALID_DP = INVALID$3 + 'decimal places', + INVALID_RM = INVALID$3 + 'rounding mode', + DIV_BY_ZERO = NAME + 'Division by zero', + + // The shared prototype object. + P$2 = {}, + UNDEFINED = void 0, + NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; + + + /* + * Create and return a Big constructor. + */ + function _Big_() { + + /* + * The Big constructor and exported function. + * Create and return a new instance of a Big number object. + * + * n {number|string|Big} A numeric value. + */ + function Big(n) { + var x = this; + + // Enable constructor usage without new. + if (!(x instanceof Big)) return n === UNDEFINED ? _Big_() : new Big(n); + + // Duplicate. + if (n instanceof Big) { + x.s = n.s; + x.e = n.e; + x.c = n.c.slice(); + } else { + if (typeof n !== 'string') { + if (Big.strict === true && typeof n !== 'bigint') { + throw TypeError(INVALID$3 + 'value'); + } + + // Minus zero? + n = n === 0 && 1 / n < 0 ? '-0' : String(n); + } + + parse$1(x, n); + } + + // Retain a reference to this Big constructor. + // Shadow Big.prototype.constructor which points to Object. + x.constructor = Big; + } + + Big.prototype = P$2; + Big.DP = DP; + Big.RM = RM; + Big.NE = NE; + Big.PE = PE; + Big.strict = STRICT; + Big.roundDown = 0; + Big.roundHalfUp = 1; + Big.roundHalfEven = 2; + Big.roundUp = 3; + + return Big; + } + + + /* + * Parse the number or string value passed to a Big constructor. + * + * x {Big} A Big number instance. + * n {number|string} A numeric value. + */ + function parse$1(x, n) { + var e, i, nl; + + if (!NUMERIC.test(n)) { + throw Error(INVALID$3 + 'number'); + } + + // Determine sign. + x.s = n.charAt(0) == '-' ? (n = n.slice(1), -1) : 1; + + // Decimal point? + if ((e = n.indexOf('.')) > -1) n = n.replace('.', ''); + + // Exponential form? + if ((i = n.search(/e/i)) > 0) { + + // Determine exponent. + if (e < 0) e = i; + e += +n.slice(i + 1); + n = n.substring(0, i); + } else if (e < 0) { + + // Integer. + e = n.length; + } + + nl = n.length; + + // Determine leading zeros. + for (i = 0; i < nl && n.charAt(i) == '0';) ++i; + + if (i == nl) { + + // Zero. + x.c = [x.e = 0]; + } else { + + // Determine trailing zeros. + for (; nl > 0 && n.charAt(--nl) == '0';); + x.e = e - i - 1; + x.c = []; + + // Convert string to array of digits without leading/trailing zeros. + for (e = 0; i <= nl;) x.c[e++] = +n.charAt(i++); + } + + return x; + } + + + /* + * Round Big x to a maximum of sd significant digits using rounding mode rm. + * + * x {Big} The Big to round. + * sd {number} Significant digits: integer, 0 to MAX_DP inclusive. + * rm {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + * [more] {boolean} Whether the result of division was truncated. + */ + function round$1(x, sd, rm, more) { + var xc = x.c; + + if (rm === UNDEFINED) rm = x.constructor.RM; + if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) { + throw Error(INVALID_RM); + } + + if (sd < 1) { + more = + rm === 3 && (more || !!xc[0]) || sd === 0 && ( + rm === 1 && xc[0] >= 5 || + rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED)) + ); + + xc.length = 1; + + if (more) { + + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + x.e = x.e - sd + 1; + xc[0] = 1; + } else { + + // Zero. + xc[0] = x.e = 0; + } + } else if (sd < xc.length) { + + // xc[sd] is the digit after the digit that may be rounded up. + more = + rm === 1 && xc[sd] >= 5 || + rm === 2 && (xc[sd] > 5 || xc[sd] === 5 && + (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) || + rm === 3 && (more || !!xc[0]); + + // Remove any digits after the required precision. + xc.length = sd; + + // Round up? + if (more) { + + // Rounding up may mean the previous digit has to be rounded up. + for (; ++xc[--sd] > 9;) { + xc[sd] = 0; + if (sd === 0) { + ++x.e; + xc.unshift(1); + break; + } + } + } + + // Remove trailing zeros. + for (sd = xc.length; !xc[--sd];) xc.pop(); + } + + return x; + } + + + /* + * Return a string representing the value of Big x in normal or exponential notation. + * Handles P.toExponential, P.toFixed, P.toJSON, P.toPrecision, P.toString and P.valueOf. + */ + function stringify(x, doExponential, isNonzero) { + var e = x.e, + s = x.c.join(''), + n = s.length; + + // Exponential notation? + if (doExponential) { + s = s.charAt(0) + (n > 1 ? '.' + s.slice(1) : '') + (e < 0 ? 'e' : 'e+') + e; + + // Normal notation. + } else if (e < 0) { + for (; ++e;) s = '0' + s; + s = '0.' + s; + } else if (e > 0) { + if (++e > n) { + for (e -= n; e--;) s += '0'; + } else if (e < n) { + s = s.slice(0, e) + '.' + s.slice(e); + } + } else if (n > 1) { + s = s.charAt(0) + '.' + s.slice(1); + } + + return x.s < 0 && isNonzero ? '-' + s : s; + } + + + // Prototype/instance methods + + + /* + * Return a new Big whose value is the absolute value of this Big. + */ + P$2.abs = function () { + var x = new this.constructor(this); + x.s = 1; + return x; + }; + + + /* + * Return 1 if the value of this Big is greater than the value of Big y, + * -1 if the value of this Big is less than the value of Big y, or + * 0 if they have the same value. + */ + P$2.cmp = function (y) { + var isneg, + x = this, + xc = x.c, + yc = (y = new x.constructor(y)).c, + i = x.s, + j = y.s, + k = x.e, + l = y.e; + + // Either zero? + if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i; + + // Signs differ? + if (i != j) return i; + + isneg = i < 0; + + // Compare exponents. + if (k != l) return k > l ^ isneg ? 1 : -1; + + j = (k = xc.length) < (l = yc.length) ? k : l; + + // Compare digit by digit. + for (i = -1; ++i < j;) { + if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1; + } + + // Compare lengths. + return k == l ? 0 : k > l ^ isneg ? 1 : -1; + }; + + + /* + * Return a new Big whose value is the value of this Big divided by the value of Big y, rounded, + * if necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM. + */ + P$2.div = function (y) { + var x = this, + Big = x.constructor, + a = x.c, // dividend + b = (y = new Big(y)).c, // divisor + k = x.s == y.s ? 1 : -1, + dp = Big.DP; + + if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { + throw Error(INVALID_DP); + } + + // Divisor is zero? + if (!b[0]) { + throw Error(DIV_BY_ZERO); + } + + // Dividend is 0? Return +-0. + if (!a[0]) { + y.s = k; + y.c = [y.e = 0]; + return y; + } + + var bl, bt, n, cmp, ri, + bz = b.slice(), + ai = bl = b.length, + al = a.length, + r = a.slice(0, bl), // remainder + rl = r.length, + q = y, // quotient + qc = q.c = [], + qi = 0, + p = dp + (q.e = x.e - y.e) + 1; // precision of the result + + q.s = k; + k = p < 0 ? 0 : p; + + // Create version of divisor with leading zero. + bz.unshift(0); + + // Add zeros to make remainder as long as divisor. + for (; rl++ < bl;) r.push(0); + + do { + + // n is how many times the divisor goes into current remainder. + for (n = 0; n < 10; n++) { + + // Compare divisor and remainder. + if (bl != (rl = r.length)) { + cmp = bl > rl ? 1 : -1; + } else { + for (ri = -1, cmp = 0; ++ri < bl;) { + if (b[ri] != r[ri]) { + cmp = b[ri] > r[ri] ? 1 : -1; + break; + } + } + } + + // If divisor < remainder, subtract divisor from remainder. + if (cmp < 0) { + + // Remainder can't be more than 1 digit longer than divisor. + // Equalise lengths using divisor with extra leading zero? + for (bt = rl == bl ? b : bz; rl;) { + if (r[--rl] < bt[rl]) { + ri = rl; + for (; ri && !r[--ri];) r[ri] = 9; + --r[ri]; + r[rl] += 10; + } + r[rl] -= bt[rl]; + } + + for (; !r[0];) r.shift(); + } else { + break; + } + } + + // Add the digit n to the result array. + qc[qi++] = cmp ? n : ++n; + + // Update the remainder. + if (r[0] && cmp) r[rl] = a[ai] || 0; + else r = [a[ai]]; + + } while ((ai++ < al || r[0] !== UNDEFINED) && k--); + + // Leading zero? Do not remove if result is simply zero (qi == 1). + if (!qc[0] && qi != 1) { + + // There can't be more than one zero. + qc.shift(); + q.e--; + p--; + } + + // Round? + if (qi > p) round$1(q, p, Big.RM, r[0] !== UNDEFINED); + + return q; + }; + + + /* + * Return true if the value of this Big is equal to the value of Big y, otherwise return false. + */ + P$2.eq = function (y) { + return this.cmp(y) === 0; + }; + + + /* + * Return true if the value of this Big is greater than the value of Big y, otherwise return + * false. + */ + P$2.gt = function (y) { + return this.cmp(y) > 0; + }; + + + /* + * Return true if the value of this Big is greater than or equal to the value of Big y, otherwise + * return false. + */ + P$2.gte = function (y) { + return this.cmp(y) > -1; + }; + + + /* + * Return true if the value of this Big is less than the value of Big y, otherwise return false. + */ + P$2.lt = function (y) { + return this.cmp(y) < 0; + }; + + + /* + * Return true if the value of this Big is less than or equal to the value of Big y, otherwise + * return false. + */ + P$2.lte = function (y) { + return this.cmp(y) < 1; + }; + + + /* + * Return a new Big whose value is the value of this Big minus the value of Big y. + */ + P$2.minus = P$2.sub = function (y) { + var i, j, t, xlty, + x = this, + Big = x.constructor, + a = x.s, + b = (y = new Big(y)).s; + + // Signs differ? + if (a != b) { + y.s = -b; + return x.plus(y); + } + + var xc = x.c.slice(), + xe = x.e, + yc = y.c, + ye = y.e; + + // Either zero? + if (!xc[0] || !yc[0]) { + if (yc[0]) { + y.s = -b; + } else if (xc[0]) { + y = new Big(x); + } else { + y.s = 1; + } + return y; + } + + // Determine which is the bigger number. Prepend zeros to equalise exponents. + if (a = xe - ye) { + + if (xlty = a < 0) { + a = -a; + t = xc; + } else { + ye = xe; + t = yc; + } + + t.reverse(); + for (b = a; b--;) t.push(0); + t.reverse(); + } else { + + // Exponents equal. Check digit by digit. + j = ((xlty = xc.length < yc.length) ? xc : yc).length; + + for (a = b = 0; b < j; b++) { + if (xc[b] != yc[b]) { + xlty = xc[b] < yc[b]; + break; + } + } + } + + // x < y? Point xc to the array of the bigger number. + if (xlty) { + t = xc; + xc = yc; + yc = t; + y.s = -y.s; + } + + /* + * Append zeros to xc if shorter. No need to add zeros to yc if shorter as subtraction only + * needs to start at yc.length. + */ + if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--;) xc[i++] = 0; + + // Subtract yc from xc. + for (b = i; j > a;) { + if (xc[--j] < yc[j]) { + for (i = j; i && !xc[--i];) xc[i] = 9; + --xc[i]; + xc[j] += 10; + } + + xc[j] -= yc[j]; + } + + // Remove trailing zeros. + for (; xc[--b] === 0;) xc.pop(); + + // Remove leading zeros and adjust exponent accordingly. + for (; xc[0] === 0;) { + xc.shift(); + --ye; + } + + if (!xc[0]) { + + // n - n = +0 + y.s = 1; + + // Result must be zero. + xc = [ye = 0]; + } + + y.c = xc; + y.e = ye; + + return y; + }; + + + /* + * Return a new Big whose value is the value of this Big modulo the value of Big y. + */ + P$2.mod = function (y) { + var ygtx, + x = this, + Big = x.constructor, + a = x.s, + b = (y = new Big(y)).s; + + if (!y.c[0]) { + throw Error(DIV_BY_ZERO); + } + + x.s = y.s = 1; + ygtx = y.cmp(x) == 1; + x.s = a; + y.s = b; + + if (ygtx) return new Big(x); + + a = Big.DP; + b = Big.RM; + Big.DP = Big.RM = 0; + x = x.div(y); + Big.DP = a; + Big.RM = b; + + return this.minus(x.times(y)); + }; + + + /* + * Return a new Big whose value is the value of this Big negated. + */ + P$2.neg = function () { + var x = new this.constructor(this); + x.s = -x.s; + return x; + }; + + + /* + * Return a new Big whose value is the value of this Big plus the value of Big y. + */ + P$2.plus = P$2.add = function (y) { + var e, k, t, + x = this, + Big = x.constructor; + + y = new Big(y); + + // Signs differ? + if (x.s != y.s) { + y.s = -y.s; + return x.minus(y); + } + + var xe = x.e, + xc = x.c, + ye = y.e, + yc = y.c; + + // Either zero? + if (!xc[0] || !yc[0]) { + if (!yc[0]) { + if (xc[0]) { + y = new Big(x); + } else { + y.s = x.s; + } + } + return y; + } + + xc = xc.slice(); + + // Prepend zeros to equalise exponents. + // Note: reverse faster than unshifts. + if (e = xe - ye) { + if (e > 0) { + ye = xe; + t = yc; + } else { + e = -e; + t = xc; + } + + t.reverse(); + for (; e--;) t.push(0); + t.reverse(); + } + + // Point xc to the longer array. + if (xc.length - yc.length < 0) { + t = yc; + yc = xc; + xc = t; + } + + e = yc.length; + + // Only start adding at yc.length - 1 as the further digits of xc can be left as they are. + for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0; + + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + + if (k) { + xc.unshift(k); + ++ye; + } + + // Remove trailing zeros. + for (e = xc.length; xc[--e] === 0;) xc.pop(); + + y.c = xc; + y.e = ye; + + return y; + }; + + + /* + * Return a Big whose value is the value of this Big raised to the power n. + * If n is negative, round to a maximum of Big.DP decimal places using rounding + * mode Big.RM. + * + * n {number} Integer, -MAX_POWER to MAX_POWER inclusive. + */ + P$2.pow = function (n) { + var x = this, + one = new x.constructor('1'), + y = one, + isneg = n < 0; + + if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) { + throw Error(INVALID$3 + 'exponent'); + } + + if (isneg) n = -n; + + for (;;) { + if (n & 1) y = y.times(x); + n >>= 1; + if (!n) break; + x = x.times(x); + } + + return isneg ? one.div(y) : y; + }; + + + /* + * Return a new Big whose value is the value of this Big rounded to a maximum precision of sd + * significant digits using rounding mode rm, or Big.RM if rm is not specified. + * + * sd {number} Significant digits: integer, 1 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P$2.prec = function (sd, rm) { + if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { + throw Error(INVALID$3 + 'precision'); + } + return round$1(new this.constructor(this), sd, rm); + }; + + + /* + * Return a new Big whose value is the value of this Big rounded to a maximum of dp decimal places + * using rounding mode rm, or Big.RM if rm is not specified. + * If dp is negative, round to an integer which is a multiple of 10**-dp. + * If dp is not specified, round to 0 decimal places. + * + * dp? {number} Integer, -MAX_DP to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P$2.round = function (dp, rm) { + if (dp === UNDEFINED) dp = 0; + else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP) { + throw Error(INVALID_DP); + } + return round$1(new this.constructor(this), dp + this.e + 1, rm); + }; + + + /* + * Return a new Big whose value is the square root of the value of this Big, rounded, if + * necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM. + */ + P$2.sqrt = function () { + var r, c, t, + x = this, + Big = x.constructor, + s = x.s, + e = x.e, + half = new Big('0.5'); + + // Zero? + if (!x.c[0]) return new Big(x); + + // Negative? + if (s < 0) { + throw Error(NAME + 'No square root'); + } + + // Estimate. + s = Math.sqrt(x + ''); + + // Math.sqrt underflow/overflow? + // Re-estimate: pass x coefficient to Math.sqrt as integer, then adjust the result exponent. + if (s === 0 || s === 1 / 0) { + c = x.c.join(''); + if (!(c.length + e & 1)) c += '0'; + s = Math.sqrt(c); + e = ((e + 1) / 2 | 0) - (e < 0 || e & 1); + r = new Big((s == 1 / 0 ? '5e' : (s = s.toExponential()).slice(0, s.indexOf('e') + 1)) + e); + } else { + r = new Big(s + ''); + } + + e = r.e + (Big.DP += 4); + + // Newton-Raphson iteration. + do { + t = r; + r = half.times(t.plus(x.div(t))); + } while (t.c.slice(0, e).join('') !== r.c.slice(0, e).join('')); + + return round$1(r, (Big.DP -= 4) + r.e + 1, Big.RM); + }; + + + /* + * Return a new Big whose value is the value of this Big times the value of Big y. + */ + P$2.times = P$2.mul = function (y) { + var c, + x = this, + Big = x.constructor, + xc = x.c, + yc = (y = new Big(y)).c, + a = xc.length, + b = yc.length, + i = x.e, + j = y.e; + + // Determine sign of result. + y.s = x.s == y.s ? 1 : -1; + + // Return signed 0 if either 0. + if (!xc[0] || !yc[0]) { + y.c = [y.e = 0]; + return y; + } + + // Initialise exponent of result as x.e + y.e. + y.e = i + j; + + // If array xc has fewer digits than yc, swap xc and yc, and lengths. + if (a < b) { + c = xc; + xc = yc; + yc = c; + j = a; + a = b; + b = j; + } + + // Initialise coefficient array of result with zeros. + for (c = new Array(j = a + b); j--;) c[j] = 0; + + // Multiply. + + // i is initially xc.length. + for (i = b; i--;) { + b = 0; + + // a is yc.length. + for (j = a + i; j > i;) { + + // Current sum of products at this digit position, plus carry. + b = c[j] + yc[i] * xc[j - i - 1] + b; + c[j--] = b % 10; + + // carry + b = b / 10 | 0; + } + + c[j] = b; + } + + // Increment result exponent if there is a final carry, otherwise remove leading zero. + if (b) ++y.e; + else c.shift(); + + // Remove trailing zeros. + for (i = c.length; !c[--i];) c.pop(); + y.c = c; + + return y; + }; + + + /* + * Return a string representing the value of this Big in exponential notation rounded to dp fixed + * decimal places using rounding mode rm, or Big.RM if rm is not specified. + * + * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P$2.toExponential = function (dp, rm) { + var x = this, + n = x.c[0]; + + if (dp !== UNDEFINED) { + if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { + throw Error(INVALID_DP); + } + x = round$1(new x.constructor(x), ++dp, rm); + for (; x.c.length < dp;) x.c.push(0); + } + + return stringify(x, true, !!n); + }; + + + /* + * Return a string representing the value of this Big in normal notation rounded to dp fixed + * decimal places using rounding mode rm, or Big.RM if rm is not specified. + * + * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + * + * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'. + * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. + */ + P$2.toFixed = function (dp, rm) { + var x = this, + n = x.c[0]; + + if (dp !== UNDEFINED) { + if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { + throw Error(INVALID_DP); + } + x = round$1(new x.constructor(x), dp + x.e + 1, rm); + + // x.e may have changed if the value is rounded up. + for (dp = dp + x.e + 1; x.c.length < dp;) x.c.push(0); + } + + return stringify(x, false, !!n); + }; + + + /* + * Return a string representing the value of this Big. + * Return exponential notation if this Big has a positive exponent equal to or greater than + * Big.PE, or a negative exponent equal to or less than Big.NE. + * Omit the sign for negative zero. + */ + P$2[Symbol.for('nodejs.util.inspect.custom')] = P$2.toJSON = P$2.toString = function () { + var x = this, + Big = x.constructor; + return stringify(x, x.e <= Big.NE || x.e >= Big.PE, !!x.c[0]); + }; + + + /* + * Return the value of this Big as a primitve number. + */ + P$2.toNumber = function () { + var n = Number(stringify(this, true, true)); + if (this.constructor.strict === true && !this.eq(n.toString())) { + throw Error(NAME + 'Imprecise conversion'); + } + return n; + }; + + + /* + * Return a string representing the value of this Big rounded to sd significant digits using + * rounding mode rm, or Big.RM if rm is not specified. + * Use exponential notation if sd is less than the number of digits necessary to represent + * the integer part of the value in normal notation. + * + * sd {number} Significant digits: integer, 1 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P$2.toPrecision = function (sd, rm) { + var x = this, + Big = x.constructor, + n = x.c[0]; + + if (sd !== UNDEFINED) { + if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { + throw Error(INVALID$3 + 'precision'); + } + x = round$1(new Big(x), sd, rm); + for (; x.c.length < sd;) x.c.push(0); + } + + return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, !!n); + }; + + + /* + * Return a string representing the value of this Big. + * Return exponential notation if this Big has a positive exponent equal to or greater than + * Big.PE, or a negative exponent equal to or less than Big.NE. + * Include the sign for negative zero. + */ + P$2.valueOf = function () { + var x = this, + Big = x.constructor; + if (Big.strict === true) { + throw Error(NAME + 'valueOf disallowed'); + } + return stringify(x, x.e <= Big.NE || x.e >= Big.PE, true); + }; + + + // Export + + var Big = _Big_(); // these aren't really private, but nor are they really useful to document @@ -18758,9 +18770,9 @@ let sharedChunks = findSharedChunks(a, b, textDiff); let sideA = new SpanCursor(a, sharedChunks, minPointSize); let sideB = new SpanCursor(b, sharedChunks, minPointSize); - textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator)); + textDiff.iterGaps((fromA, fromB, length) => compare$1(sideA, fromA, sideB, fromB, length, comparator)); if (textDiff.empty && textDiff.length == 0) - compare(sideA, 0, sideB, 0, 0, comparator); + compare$1(sideA, 0, sideB, 0, 0, comparator); } /** Compare the contents of two groups of range sets, returning true @@ -19234,7 +19246,7 @@ return open; } } - function compare(a, startA, b, startB, length, comparator) { + function compare$1(a, startA, b, startB, length, comparator) { a.goto(startA); b.goto(startB); let endB = startB + length; @@ -31190,365 +31202,365 @@ })); }; - syntaxHighlighting(HighlightStyle.define([ - { tag: tags.strong, fontWeight: 'bold' }, - { tag: tags.emphasis, fontStyle: 'italic' }, - ])); - - EditorView.theme({ - '& .cm-lintRange': { - position: 'relative', - }, - '& .cm-lintRange::after': { - content: '""', - width: '100%', - position: 'absolute', - left: '0px', - bottom: '-2px', - height: '3px', - backgroundRepeat: 'repeat-x', - }, - '& .cm-lintRange.cm-lintRange-warning, & .cm-lintRange.cm-lintRange-error': { - backgroundImage: 'none', - }, - '& .cm-lintPoint::after': { - bottom: '-2px' - } - }); - - const _urlify = (color) => `%23${color.slice(1)}`; - - const colors = { - black: '#1f2b36', - darkGrey: '#2f3d58', - grey: '#404a5c', - midGrey: '#576071', - lightGrey: '#c5d1e5', - offWhite: '#d9e0f5', - snowWhite: '#eaf1ff', - white: '#ffffff', - mossGreen: '#7ab6aa', - iceBlue: '#6cbfd8', - waterBlue: '#065aaa', - brightBlue: '#0a56b9', - deepBlue: '#355472', - red: '#9f1c15', - orangeBrown: '#b4502f', - yellow: '#debd71', - lila: '#9a4890', - purple: '#5b2c83' - }; - - const colorByRole = { - lightBackground: colors.white, - darkBackground: colors.snowWhite, - selection: colors.snowWhite, - tooltipBackground: colors.offWhite, - error: colors.red, - warning: colors.yellow, - invalid: '#b40000' - }; - - EditorView.theme( - { - '&': { color: colors.black, backgroundColor: colorByRole.lightBackground }, - '.cm-content': { caretColor: colors.darkGrey }, - '.cm-cursor, .cm-dropCursor': { borderLeftColor: colors.darkGrey }, - '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': - { backgroundColor: colorByRole.selection }, - - '.cm-panels': { backgroundColor: colorByRole.darkBackground, color: colors.grey }, - '.cm-panels.cm-panels-top': { borderBottom: `2px solid ${ colors.black }` }, - '.cm-panels.cm-panels-bottom': { borderTop: `2px solid ${ colors.black }` }, - - '.cm-searchMatch': { - backgroundColor: '#72a1ff59', - outline: `1px solid ${colors.midGrey}` - }, - '.cm-searchMatch.cm-searchMatch-selected': { backgroundColor: colors.offWhite }, - '.cm-activeLine': { backgroundColor: colorByRole.selection }, - '.cm-selectionMatch': { backgroundColor: colors.offWhite }, - - '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { - outline: `1px solid ${colors.grey}` - }, - - '&.cm-focused .cm-matchingBracket': { - backgroundColor: colors.snowWhite - }, - - '.cm-gutters': { - backgroundColor: '#f3f7fe', - color: '#52668d', - border: 'none', - padding: '0 5px' - }, - - '.cm-activeLineGutter': { - backgroundColor: colorByRole.selection - }, - - '.cm-foldPlaceholder': { - backgroundColor: 'transparent', - border: 'none', - color: '#ddd' - }, - - '.cm-tooltip': { - border: 'none', - backgroundColor: colorByRole.tooltipBackground - }, - '.cm-tooltip .cm-tooltip-arrow:before': { - borderTopColor: 'transparent', - borderBottomColor: 'transparent' - }, - '.cm-tooltip .cm-tooltip-arrow:after': { - borderTopColor: colorByRole.tooltipBackground, - borderBottomColor: colorByRole.tooltipBackground - }, - '.cm-tooltip-autocomplete': { - '& > ul > li[aria-selected]': { - backgroundColor: colorByRole.darkBackground, - color: colors.midGrey - } - }, - '& .cm-lintRange.cm-lintRange-warning::after': { - backgroundImage: `url("data:image/svg+xml,")`, - }, - '& .cm-lintRange.cm-lintRange-error::after': { - backgroundImage: `url("data:image/svg+xml,")`, - }, - '& .cm-diagnostic-warning': { - border: `1px solid ${colorByRole.warning}`, - borderLeft: `5px solid ${colorByRole.warning}`, - background: colorByRole.lightBackground, - }, - '& .cm-diagnostic-error': { - border: `1px solid ${colorByRole.error}`, - borderLeft: `5px solid ${colorByRole.error}`, - background: colorByRole.lightBackground - }, - '& .cm-diagnostic': { - padding: '3px 8px' - } - }, - { dark: false } - ); - - syntaxHighlighting(HighlightStyle.define([ - { - tag: [ tags.macroName, tags.variableName ], - color: colors.waterBlue - }, - { - tag: [ tags.special(tags.bracket) ], - color: colors.waterBlue, - fontWeight: 'bold' - }, - { - tag: [ tags.color, tags.name, tags.definition(tags.name), tags.constant(tags.name), tags.standard(tags.name), tags.propertyName, ], - color: colors.deepBlue - }, - { - tag: [ tags.definition(tags.variableName), tags.function(tags.variableName), tags.function(tags.propertyName) ], - color: colors.brightBlue, - }, - { tag: [ tags.labelName ], color: colors.orangeBrown }, - { - tag: [ tags.annotation ], - color: colorByRole.invalid - }, - { - tag: [ tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace, tags.atom, tags.bool, tags.special(tags.variableName) ], - color: colors.red - }, - { - tag: [ tags.typeName, tags.className, tags.attributeName ], - color: colors.lila - }, - { - tag: [ tags.operator, tags.operatorKeyword, tags.tagName, tags.keyword ], - color: colors.purple - }, - { - tag: [ tags.angleBracket, tags.squareBracket, tags.brace, tags.separator, tags.punctuation ], - color: colors.midGrey - }, - { - tag: [ tags.regexp ], - color: colors.deepBlue - }, - { - tag: [ tags.quote ], - color: colors.darkGrey - }, - { tag: [ tags.string, tags.character, tags.deleted ], color: colors.orangeBrown }, - { - tag: tags.link, - color: colors.mossGreen, - textDecoration: 'underline', - textUnderlinePosition: 'under' - }, - { - tag: [ tags.url, tags.escape, tags.special(tags.string) ], - color: colors.red - }, - { tag: [ tags.meta ], color: colors.iceBlue }, - { tag: [ tags.comment ], color: colors.midGrey, fontStyle: 'italic' }, - { tag: tags.strong, fontWeight: 'bold', color: colors.deepBlue }, - { tag: tags.emphasis, fontStyle: 'italic', color: colors.deepBlue }, - { tag: tags.strikethrough, textDecoration: 'line-through' }, - { tag: tags.heading, fontWeight: 'bold', color: colors.midGray }, - { tag: tags.special(tags.heading1), fontWeight: 'bold', color: colors.darkGrey }, - { - tag: [ tags.heading1, tags.heading2, tags.heading3, tags.heading4 ], - fontWeight: 'bold', - color: colors.midGrey - }, - { tag: [ tags.heading5, tags.heading6, tags.processingInstruction, tags.inserted ], color: colors.grey }, - { - tag: [ tags.contentSeparator ], - color: colors.yellow - }, - { tag: tags.invalid, color: colors.midGrey, borderBottom: `1px dotted ${colorByRole.invalid}` } - ])); - - const ivory = '#abb2bf', - peach = '#f07178', - stone = '#7d8799', - invalid = '#ffffff', - pastelYellow = '#fffce1', - pastelOrange = '#ec9e6f', - raisinBlack = '#21252b', - highlightBackground = 'rgba(0, 0, 0, 0.5)', - background = '#292d3e', - tooltipBackground = '#353a42', - selection = 'rgba(128, 203, 196, 0.2)', - cursor = '#ffcc00'; - - const urlHash = '%23'; - const warningColorHex = 'fff890'; - const errorColor = 'red'; - const warningBackgroundColor = '#281e16'; - const errorBackgroundColor = '#281616'; - - EditorView.theme( - { - '&': { - color: '#ffffff', - backgroundColor: background - }, - '.cm-content': { - caretColor: cursor - }, - '&.cm-focused .cm-cursor': { - borderLeftColor: cursor - }, - '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': - { backgroundColor: selection }, - '.cm-panels': { backgroundColor: raisinBlack, color: '#ffffff' }, - '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' }, - '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' }, - '.cm-searchMatch': { - backgroundColor: '#72a1ff59', - outline: '1px solid #457dff' - }, - '.cm-searchMatch.cm-searchMatch-selected': { - backgroundColor: '#6199ff2f' - }, - '.cm-activeLine': { backgroundColor: highlightBackground }, - '.cm-selectionMatch': { backgroundColor: '#aafe661a' }, - '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { - backgroundColor: '#bad0f847', - outline: '1px solid #515a6b' - }, - '.cm-gutters': { - background: '#292d3e', - color: '#676e95', - border: 'none', - padding: '0 5px' - }, - '.cm-activeLineGutter': { - backgroundColor: highlightBackground - }, - '.cm-foldPlaceholder': { - backgroundColor: 'transparent', - border: 'none', - color: '#ddd' - }, - '.cm-tooltip': { - border: 'none', - backgroundColor: tooltipBackground - }, - '.cm-tooltip .cm-tooltip-arrow:before': { - borderTopColor: 'transparent', - borderBottomColor: 'transparent' - }, - '.cm-tooltip .cm-tooltip-arrow:after': { - borderTopColor: tooltipBackground, - borderBottomColor: tooltipBackground - }, - '.cm-tooltip-autocomplete': { - '& > ul > li[aria-selected]': { - backgroundColor: highlightBackground, - color: ivory - } - }, - '& .cm-lintRange.cm-lintRange-warning::after': { - backgroundImage: `url("data:image/svg+xml,")`, - }, - '& .cm-lintRange.cm-lintRange-error::after': { - backgroundImage: `url("data:image/svg+xml,")`, - }, - '& .cm-diagnostic-warning': { - borderLeft: `5px solid #${warningColorHex}`, - background: warningBackgroundColor - }, - '& .cm-diagnostic-error': { - borderLeft: `5px solid ${errorColor}`, - background: errorBackgroundColor - }, - '& .cm-diagnostic': { - borderRadius: '2px', - padding: '3px 8px' - } - }, - { dark: true } - ); - - syntaxHighlighting(HighlightStyle.define([ - - // Markdown headings - { tag: tags.heading1, color: pastelYellow }, - { tag: tags.heading2, color: pastelYellow }, - { tag: tags.heading3, color: pastelYellow }, - { tag: tags.heading4, color: pastelYellow }, - { tag: tags.heading5, color: pastelYellow }, - { tag: tags.heading6, color: pastelYellow }, - - // Feelers - { tag: tags.special(tags.bracket), color: pastelOrange, fontWeight: 'bold' }, - - // Everything else - { tag: tags.keyword, color: '#c792ea' }, - { tag: tags.operator, color: '#89ddff' }, - { tag: tags.special(tags.variableName), color: '#eeffff' }, - { tag: tags.typeName, color: '#f07178' }, - { tag: tags.atom, color: '#f78c6c' }, - { tag: tags.number, color: '#ff5370' }, - { tag: tags.bool, color: '#ff5370' }, - { tag: tags.definition(tags.variableName), color: '#82aaff' }, - { tag: tags.string, color: '#c3e88d' }, - { tag: tags.comment, color: stone }, - { tag: tags.tagName, color: '#ff5370' }, - { tag: tags.bracket, color: '#a2a1a4' }, - { tag: tags.meta, color: '#ffcb6b' }, - { tag: tags.special(tags.string), color: peach }, - { tag: tags.propertyName, color: pastelOrange }, - { tag: tags.variableName, color: pastelOrange }, - { tag: tags.attributeName, color: peach }, - { tag: tags.className, color: peach }, - { tag: tags.invalid, color: invalid } + syntaxHighlighting(HighlightStyle.define([ + { tag: tags.strong, fontWeight: 'bold' }, + { tag: tags.emphasis, fontStyle: 'italic' }, + ])); + + EditorView.theme({ + '& .cm-lintRange': { + position: 'relative', + }, + '& .cm-lintRange::after': { + content: '""', + width: '100%', + position: 'absolute', + left: '0px', + bottom: '-2px', + height: '3px', + backgroundRepeat: 'repeat-x', + }, + '& .cm-lintRange.cm-lintRange-warning, & .cm-lintRange.cm-lintRange-error': { + backgroundImage: 'none', + }, + '& .cm-lintPoint::after': { + bottom: '-2px' + } + }); + + const _urlify = (color) => `%23${color.slice(1)}`; + + const colors = { + black: '#1f2b36', + darkGrey: '#2f3d58', + grey: '#404a5c', + midGrey: '#576071', + lightGrey: '#c5d1e5', + offWhite: '#d9e0f5', + snowWhite: '#eaf1ff', + white: '#ffffff', + mossGreen: '#7ab6aa', + iceBlue: '#6cbfd8', + waterBlue: '#065aaa', + brightBlue: '#0a56b9', + deepBlue: '#355472', + red: '#9f1c15', + orangeBrown: '#b4502f', + yellow: '#debd71', + lila: '#9a4890', + purple: '#5b2c83' + }; + + const colorByRole = { + lightBackground: colors.white, + darkBackground: colors.snowWhite, + selection: colors.snowWhite, + tooltipBackground: colors.offWhite, + error: colors.red, + warning: colors.yellow, + invalid: '#b40000' + }; + + EditorView.theme( + { + '&': { color: colors.black, backgroundColor: colorByRole.lightBackground }, + '.cm-content': { caretColor: colors.darkGrey }, + '.cm-cursor, .cm-dropCursor': { borderLeftColor: colors.darkGrey }, + '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': + { backgroundColor: colorByRole.selection }, + + '.cm-panels': { backgroundColor: colorByRole.darkBackground, color: colors.grey }, + '.cm-panels.cm-panels-top': { borderBottom: `2px solid ${ colors.black }` }, + '.cm-panels.cm-panels-bottom': { borderTop: `2px solid ${ colors.black }` }, + + '.cm-searchMatch': { + backgroundColor: '#72a1ff59', + outline: `1px solid ${colors.midGrey}` + }, + '.cm-searchMatch.cm-searchMatch-selected': { backgroundColor: colors.offWhite }, + '.cm-activeLine': { backgroundColor: colorByRole.selection }, + '.cm-selectionMatch': { backgroundColor: colors.offWhite }, + + '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { + outline: `1px solid ${colors.grey}` + }, + + '&.cm-focused .cm-matchingBracket': { + backgroundColor: colors.snowWhite + }, + + '.cm-gutters': { + backgroundColor: '#f3f7fe', + color: '#52668d', + border: 'none', + padding: '0 5px' + }, + + '.cm-activeLineGutter': { + backgroundColor: colorByRole.selection + }, + + '.cm-foldPlaceholder': { + backgroundColor: 'transparent', + border: 'none', + color: '#ddd' + }, + + '.cm-tooltip': { + border: 'none', + backgroundColor: colorByRole.tooltipBackground + }, + '.cm-tooltip .cm-tooltip-arrow:before': { + borderTopColor: 'transparent', + borderBottomColor: 'transparent' + }, + '.cm-tooltip .cm-tooltip-arrow:after': { + borderTopColor: colorByRole.tooltipBackground, + borderBottomColor: colorByRole.tooltipBackground + }, + '.cm-tooltip-autocomplete': { + '& > ul > li[aria-selected]': { + backgroundColor: colorByRole.darkBackground, + color: colors.midGrey + } + }, + '& .cm-lintRange.cm-lintRange-warning::after': { + backgroundImage: `url("data:image/svg+xml,")`, + }, + '& .cm-lintRange.cm-lintRange-error::after': { + backgroundImage: `url("data:image/svg+xml,")`, + }, + '& .cm-diagnostic-warning': { + border: `1px solid ${colorByRole.warning}`, + borderLeft: `5px solid ${colorByRole.warning}`, + background: colorByRole.lightBackground, + }, + '& .cm-diagnostic-error': { + border: `1px solid ${colorByRole.error}`, + borderLeft: `5px solid ${colorByRole.error}`, + background: colorByRole.lightBackground + }, + '& .cm-diagnostic': { + padding: '3px 8px' + } + }, + { dark: false } + ); + + syntaxHighlighting(HighlightStyle.define([ + { + tag: [ tags.macroName, tags.variableName ], + color: colors.waterBlue + }, + { + tag: [ tags.special(tags.bracket) ], + color: colors.waterBlue, + fontWeight: 'bold' + }, + { + tag: [ tags.color, tags.name, tags.definition(tags.name), tags.constant(tags.name), tags.standard(tags.name), tags.propertyName, ], + color: colors.deepBlue + }, + { + tag: [ tags.definition(tags.variableName), tags.function(tags.variableName), tags.function(tags.propertyName) ], + color: colors.brightBlue, + }, + { tag: [ tags.labelName ], color: colors.orangeBrown }, + { + tag: [ tags.annotation ], + color: colorByRole.invalid + }, + { + tag: [ tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace, tags.atom, tags.bool, tags.special(tags.variableName) ], + color: colors.red + }, + { + tag: [ tags.typeName, tags.className, tags.attributeName ], + color: colors.lila + }, + { + tag: [ tags.operator, tags.operatorKeyword, tags.tagName, tags.keyword ], + color: colors.purple + }, + { + tag: [ tags.angleBracket, tags.squareBracket, tags.brace, tags.separator, tags.punctuation ], + color: colors.midGrey + }, + { + tag: [ tags.regexp ], + color: colors.deepBlue + }, + { + tag: [ tags.quote ], + color: colors.darkGrey + }, + { tag: [ tags.string, tags.character, tags.deleted ], color: colors.orangeBrown }, + { + tag: tags.link, + color: colors.mossGreen, + textDecoration: 'underline', + textUnderlinePosition: 'under' + }, + { + tag: [ tags.url, tags.escape, tags.special(tags.string) ], + color: colors.red + }, + { tag: [ tags.meta ], color: colors.iceBlue }, + { tag: [ tags.comment ], color: colors.midGrey, fontStyle: 'italic' }, + { tag: tags.strong, fontWeight: 'bold', color: colors.deepBlue }, + { tag: tags.emphasis, fontStyle: 'italic', color: colors.deepBlue }, + { tag: tags.strikethrough, textDecoration: 'line-through' }, + { tag: tags.heading, fontWeight: 'bold', color: colors.midGray }, + { tag: tags.special(tags.heading1), fontWeight: 'bold', color: colors.darkGrey }, + { + tag: [ tags.heading1, tags.heading2, tags.heading3, tags.heading4 ], + fontWeight: 'bold', + color: colors.midGrey + }, + { tag: [ tags.heading5, tags.heading6, tags.processingInstruction, tags.inserted ], color: colors.grey }, + { + tag: [ tags.contentSeparator ], + color: colors.yellow + }, + { tag: tags.invalid, color: colors.midGrey, borderBottom: `1px dotted ${colorByRole.invalid}` } + ])); + + const ivory = '#abb2bf', + peach = '#f07178', + stone = '#7d8799', + invalid = '#ffffff', + pastelYellow = '#fffce1', + pastelOrange = '#ec9e6f', + raisinBlack = '#21252b', + highlightBackground = 'rgba(0, 0, 0, 0.5)', + background = '#292d3e', + tooltipBackground = '#353a42', + selection = 'rgba(128, 203, 196, 0.2)', + cursor = '#ffcc00'; + + const urlHash = '%23'; + const warningColorHex = 'fff890'; + const errorColor = 'red'; + const warningBackgroundColor = '#281e16'; + const errorBackgroundColor = '#281616'; + + EditorView.theme( + { + '&': { + color: '#ffffff', + backgroundColor: background + }, + '.cm-content': { + caretColor: cursor + }, + '&.cm-focused .cm-cursor': { + borderLeftColor: cursor + }, + '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': + { backgroundColor: selection }, + '.cm-panels': { backgroundColor: raisinBlack, color: '#ffffff' }, + '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' }, + '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' }, + '.cm-searchMatch': { + backgroundColor: '#72a1ff59', + outline: '1px solid #457dff' + }, + '.cm-searchMatch.cm-searchMatch-selected': { + backgroundColor: '#6199ff2f' + }, + '.cm-activeLine': { backgroundColor: highlightBackground }, + '.cm-selectionMatch': { backgroundColor: '#aafe661a' }, + '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { + backgroundColor: '#bad0f847', + outline: '1px solid #515a6b' + }, + '.cm-gutters': { + background: '#292d3e', + color: '#676e95', + border: 'none', + padding: '0 5px' + }, + '.cm-activeLineGutter': { + backgroundColor: highlightBackground + }, + '.cm-foldPlaceholder': { + backgroundColor: 'transparent', + border: 'none', + color: '#ddd' + }, + '.cm-tooltip': { + border: 'none', + backgroundColor: tooltipBackground + }, + '.cm-tooltip .cm-tooltip-arrow:before': { + borderTopColor: 'transparent', + borderBottomColor: 'transparent' + }, + '.cm-tooltip .cm-tooltip-arrow:after': { + borderTopColor: tooltipBackground, + borderBottomColor: tooltipBackground + }, + '.cm-tooltip-autocomplete': { + '& > ul > li[aria-selected]': { + backgroundColor: highlightBackground, + color: ivory + } + }, + '& .cm-lintRange.cm-lintRange-warning::after': { + backgroundImage: `url("data:image/svg+xml,")`, + }, + '& .cm-lintRange.cm-lintRange-error::after': { + backgroundImage: `url("data:image/svg+xml,")`, + }, + '& .cm-diagnostic-warning': { + borderLeft: `5px solid #${warningColorHex}`, + background: warningBackgroundColor + }, + '& .cm-diagnostic-error': { + borderLeft: `5px solid ${errorColor}`, + background: errorBackgroundColor + }, + '& .cm-diagnostic': { + borderRadius: '2px', + padding: '3px 8px' + } + }, + { dark: true } + ); + + syntaxHighlighting(HighlightStyle.define([ + + // Markdown headings + { tag: tags.heading1, color: pastelYellow }, + { tag: tags.heading2, color: pastelYellow }, + { tag: tags.heading3, color: pastelYellow }, + { tag: tags.heading4, color: pastelYellow }, + { tag: tags.heading5, color: pastelYellow }, + { tag: tags.heading6, color: pastelYellow }, + + // Feelers + { tag: tags.special(tags.bracket), color: pastelOrange, fontWeight: 'bold' }, + + // Everything else + { tag: tags.keyword, color: '#c792ea' }, + { tag: tags.operator, color: '#89ddff' }, + { tag: tags.special(tags.variableName), color: '#eeffff' }, + { tag: tags.typeName, color: '#f07178' }, + { tag: tags.atom, color: '#f78c6c' }, + { tag: tags.number, color: '#ff5370' }, + { tag: tags.bool, color: '#ff5370' }, + { tag: tags.definition(tags.variableName), color: '#82aaff' }, + { tag: tags.string, color: '#c3e88d' }, + { tag: tags.comment, color: stone }, + { tag: tags.tagName, color: '#ff5370' }, + { tag: tags.bracket, color: '#a2a1a4' }, + { tag: tags.meta, color: '#ffcb6b' }, + { tag: tags.special(tags.string), color: peach }, + { tag: tags.propertyName, color: pastelOrange }, + { tag: tags.variableName, color: pastelOrange }, + { tag: tags.attributeName, color: peach }, + { tag: tags.className, color: peach }, + { tag: tags.invalid, color: invalid } ])); // This file was generated by lezer-generator. You probably shouldn't edit it. @@ -31556,85 +31568,85 @@ FeelBlock = 2, SimpleTextBlock = 3; - /* global console */ - - const CHAR_TABLE = { - '{': 123, - '}': 125 - }; - - const isClosingFeelScope = (input, offset = 0) => { - - const isReadingCloseCurrent = input.peek(offset) === CHAR_TABLE['}']; - const isReadingCloseAhead = input.peek(offset + 1) === CHAR_TABLE['}']; - - const isReadingClose = isReadingCloseCurrent && isReadingCloseAhead; - - return isReadingClose || input.peek(offset) === -1; - - }; - - const feelBlock = new ExternalTokenizer((input, stack) => { - - let lookAhead = 0; - - // check if we haven't reached the end of a templating tag - while (!isClosingFeelScope(input, lookAhead)) { lookAhead++; } - - if (lookAhead > 0) { - input.advance(lookAhead); - input.acceptToken(FeelBlock); - } - - }); - - const isClosingTextScope = (input, offset = 0) => { - const isReadingOpenCurrent = input.peek(offset) === CHAR_TABLE['{']; - const isReadingOpenAhead = input.peek(offset + 1) === CHAR_TABLE['{']; - - const isReadOpen = isReadingOpenCurrent && isReadingOpenAhead; - - return isReadOpen || input.peek(offset) === -1; - }; - - - const simpleTextBlock = new ExternalTokenizer((input, stack) => { - - let lookAhead = 0; - - // check if we haven't reached the start of a templating tag - while (!isClosingTextScope(input, lookAhead)) { lookAhead++; } - - if (lookAhead > 0) { - input.advance(lookAhead); - input.acceptToken(SimpleTextBlock); - } - - }); - - // Anytime this tokenizer is run, simply tag the rest of the input as FEEL - const feel = new ExternalTokenizer((input, stack) => { - - let lookAhead = 0; - - while (input.peek(lookAhead) !== -1) { lookAhead++; } - - if (lookAhead > 0) { - input.advance(lookAhead); - input.acceptToken(Feel); - } - + /* global console */ + + const CHAR_TABLE = { + '{': 123, + '}': 125 + }; + + const isClosingFeelScope = (input, offset = 0) => { + + const isReadingCloseCurrent = input.peek(offset) === CHAR_TABLE['}']; + const isReadingCloseAhead = input.peek(offset + 1) === CHAR_TABLE['}']; + + const isReadingClose = isReadingCloseCurrent && isReadingCloseAhead; + + return isReadingClose || input.peek(offset) === -1; + + }; + + const feelBlock = new ExternalTokenizer((input, stack) => { + + let lookAhead = 0; + + // check if we haven't reached the end of a templating tag + while (!isClosingFeelScope(input, lookAhead)) { lookAhead++; } + + if (lookAhead > 0) { + input.advance(lookAhead); + input.acceptToken(FeelBlock); + } + + }); + + const isClosingTextScope = (input, offset = 0) => { + const isReadingOpenCurrent = input.peek(offset) === CHAR_TABLE['{']; + const isReadingOpenAhead = input.peek(offset + 1) === CHAR_TABLE['{']; + + const isReadOpen = isReadingOpenCurrent && isReadingOpenAhead; + + return isReadOpen || input.peek(offset) === -1; + }; + + + const simpleTextBlock = new ExternalTokenizer((input, stack) => { + + let lookAhead = 0; + + // check if we haven't reached the start of a templating tag + while (!isClosingTextScope(input, lookAhead)) { lookAhead++; } + + if (lookAhead > 0) { + input.advance(lookAhead); + input.acceptToken(SimpleTextBlock); + } + + }); + + // Anytime this tokenizer is run, simply tag the rest of the input as FEEL + const feel = new ExternalTokenizer((input, stack) => { + + let lookAhead = 0; + + while (input.peek(lookAhead) !== -1) { lookAhead++; } + + if (lookAhead > 0) { + input.advance(lookAhead); + input.acceptToken(Feel); + } + }); - const feelersHighlighting = styleTags({ - ConditionalSpanner: tags.special(tags.bracket), - ConditionalSpannerClose: tags.special(tags.bracket), - ConditionalSpannerCloseNl: tags.special(tags.bracket), - LoopSpanner: tags.special(tags.bracket), - LoopSpannerClose: tags.special(tags.bracket), - LoopSpannerCloseNl: tags.special(tags.bracket), - EmptyInsert: tags.special(tags.bracket), - Insert: tags.special(tags.bracket), + const feelersHighlighting = styleTags({ + ConditionalSpanner: tags.special(tags.bracket), + ConditionalSpannerClose: tags.special(tags.bracket), + ConditionalSpannerCloseNl: tags.special(tags.bracket), + LoopSpanner: tags.special(tags.bracket), + LoopSpannerClose: tags.special(tags.bracket), + LoopSpannerCloseNl: tags.special(tags.bracket), + EmptyInsert: tags.special(tags.bracket), + Insert: tags.special(tags.bracket), }); // This file was generated by lezer-generator. You probably shouldn't edit it. @@ -31654,282 +31666,282 @@ tokenPrec: 0 }); - function buildSimpleTree(parseTree, templateString) { - - const stack = [ { children: [] } ]; - const isLeafNode = (node) => [ 'SimpleTextBlock', 'Feel', 'FeelBlock' ].includes(node.type.name); - - parseTree.iterate({ - enter: (node, pos, type) => { - - const nodeRepresentation = { - name: node.type.name, - children: [] - }; - - if (isLeafNode(node)) { - nodeRepresentation.content = templateString.slice(node.from, node.to); - } - - stack.push(nodeRepresentation); - }, - leave: (node, pos, type) => { - const result = stack.pop(); - const parent = stack[stack.length - 1]; - result.parent = parent; - parent.children.push(result); - } - }); - - return stack[0].children[0]; - } - - /** - * @typedef {object} EvaluationOptions - * @property {boolean} [debug=false] - whether to enable debug mode, which displays errors inline instead of throwing them - * @property {function} [buildDebugString=(e) => `{{ ${e.message.toLowerCase()} }}`] - function that takes an error and returns the string to display in debug mode - * @property {boolean} [strict=false] - whether to expect strict data types out of our FEEL expression, e.g. boolean for conditionals - */ - - /** - * @param {string} templateString - the template string to evaluate - * @param {object} [context={}] - the context object to evaluate the template string against - * @param {EvaluationOptions} [options={}] - options to configure the evaluation - * @return {string} the evaluated template string - */ - const evaluate = (templateString, context = {}, options = {}) => { - - const { - debug = false, - buildDebugString = (e) => `{{ ${e.message.toLowerCase()} }}`, - strict = false - } = options; - - const parseTree = parser.parse(templateString); - - const simpleTreeRoot = buildSimpleTree(parseTree, templateString); - - const evaluateNode = buildNodeEvaluator(debug, buildDebugString, strict); - - return evaluateNode(simpleTreeRoot, enhanceContext(context, null)); - - }; - - const buildNodeEvaluator = (debug, buildDebugString, strict) => { - - const errorHandler = (error) => { - - if (debug) { - return buildDebugString(error); - } - - throw error; - }; - - const evaluateNodeValue = (node, context = {}) => { - - switch (node.name) { - - case 'SimpleTextBlock': - return node.content; - - case 'Insert': { - const feel = node.children[0].content; - - try { - return evaluate$1(feel, context); - } - catch { - return errorHandler(new Error(`FEEL expression ${feel} couldn't be evaluated`)); - } - } - - case 'EmptyInsert': - return ''; - - case 'Feel': - case 'FeelBlock': { - try { - return evaluate$1(node.content, context); - } - catch { - return errorHandler(new Error(`FEEL expression ${node.content} couldn't be evaluated`)); - } - } - - case 'Feelers': - return node.children.map(child => evaluateNode(child, context)).join(''); - - case 'ConditionalSpanner': { - const feel = node.children[0].content; - let shouldRender; - - try { - shouldRender = evaluate$1(feel, context); - } - catch { - return errorHandler(new Error(`FEEL expression ${feel} couldn't be evaluated`)); - } - - if (strict && typeof(shouldRender) !== 'boolean') { - return errorHandler(new Error(`FEEL expression ${feel} expected to evaluate to a boolean`)); - } - - if (shouldRender) { - const children = node.children.slice(1, node.children.length - 1); - const innerRender = children.map(child => evaluateNode(child, context)).join(''); - - const closeNode = node.children[node.children.length - 1]; - const shouldAddNewline = closeNode.name.endsWith('Nl') && !innerRender.endsWith('\n'); - - return innerRender + (shouldAddNewline ? '\n' : ''); - } - - return ''; - } - - case 'LoopSpanner': { - const feel = node.children[0].content; - let loopArray; - - try { - loopArray = evaluate$1(feel, context); - } - catch { - return errorHandler(new Error(`FEEL expression ${feel} couldn't be evaluated`)); - } - - if (!Array.isArray(loopArray)) { - - if (strict) { - return errorHandler(new Error(`FEEL expression ${feel} expected to evaluate to an array`)); - } - - // if not strict, we treat undefined/null as an empty array - else if (loopArray === undefined || loopArray === null) { - loopArray = []; - } - - // if not strict, we treat a single item as an array with one item - else { - loopArray = [ loopArray ]; - } - - } - - const childrenToLoop = node.children.slice(1, node.children.length - 1); - - const evaluateChildren = (arrayElement, parentContext) => { - const childContext = enhanceContext(arrayElement, parentContext); - return childrenToLoop.map(child => evaluateNode(child, childContext)).join(''); - }; - - const innerRender = loopArray.map(arrayElement => evaluateChildren(arrayElement, context)).join(''); - const closeNode = node.children[node.children.length - 1]; - const shouldAddNewline = closeNode.name.endsWith('Nl') && !innerRender.endsWith('\n'); - - return innerRender + (shouldAddNewline ? '\n' : ''); - }} - - }; - - const evaluateNode = (node, context = {}) => { - try { - return evaluateNodeValue(node, context); - } catch (error) { - return errorHandler(error); - } - }; - - return evaluateNode; - + function buildSimpleTree(parseTree, templateString) { + + const stack = [ { children: [] } ]; + const isLeafNode = (node) => [ 'SimpleTextBlock', 'Feel', 'FeelBlock' ].includes(node.type.name); + + parseTree.iterate({ + enter: (node, pos, type) => { + + const nodeRepresentation = { + name: node.type.name, + children: [] + }; + + if (isLeafNode(node)) { + nodeRepresentation.content = templateString.slice(node.from, node.to); + } + + stack.push(nodeRepresentation); + }, + leave: (node, pos, type) => { + const result = stack.pop(); + const parent = stack[stack.length - 1]; + result.parent = parent; + parent.children.push(result); + } + }); + + return stack[0].children[0]; + } + + /** + * @typedef {object} EvaluationOptions + * @property {boolean} [debug=false] - whether to enable debug mode, which displays errors inline instead of throwing them + * @property {function} [buildDebugString=(e) => `{{ ${e.message.toLowerCase()} }}`] - function that takes an error and returns the string to display in debug mode + * @property {boolean} [strict=false] - whether to expect strict data types out of our FEEL expression, e.g. boolean for conditionals + */ + + /** + * @param {string} templateString - the template string to evaluate + * @param {object} [context={}] - the context object to evaluate the template string against + * @param {EvaluationOptions} [options={}] - options to configure the evaluation + * @return {string} the evaluated template string + */ + const evaluate = (templateString, context = {}, options = {}) => { + + const { + debug = false, + buildDebugString = (e) => `{{ ${e.message.toLowerCase()} }}`, + strict = false + } = options; + + const parseTree = parser.parse(templateString); + + const simpleTreeRoot = buildSimpleTree(parseTree, templateString); + + const evaluateNode = buildNodeEvaluator(debug, buildDebugString, strict); + + return evaluateNode(simpleTreeRoot, enhanceContext(context, null)); + + }; + + const buildNodeEvaluator = (debug, buildDebugString, strict) => { + + const errorHandler = (error) => { + + if (debug) { + return buildDebugString(error); + } + + throw error; + }; + + const evaluateNodeValue = (node, context = {}) => { + + switch (node.name) { + + case 'SimpleTextBlock': + return node.content; + + case 'Insert': { + const feel = node.children[0].content; + + try { + return evaluate$1(feel, context); + } + catch { + return errorHandler(new Error(`FEEL expression ${feel} couldn't be evaluated`)); + } + } + + case 'EmptyInsert': + return ''; + + case 'Feel': + case 'FeelBlock': { + try { + return evaluate$1(node.content, context); + } + catch { + return errorHandler(new Error(`FEEL expression ${node.content} couldn't be evaluated`)); + } + } + + case 'Feelers': + return node.children.map(child => evaluateNode(child, context)).join(''); + + case 'ConditionalSpanner': { + const feel = node.children[0].content; + let shouldRender; + + try { + shouldRender = evaluate$1(feel, context); + } + catch { + return errorHandler(new Error(`FEEL expression ${feel} couldn't be evaluated`)); + } + + if (strict && typeof(shouldRender) !== 'boolean') { + return errorHandler(new Error(`FEEL expression ${feel} expected to evaluate to a boolean`)); + } + + if (shouldRender) { + const children = node.children.slice(1, node.children.length - 1); + const innerRender = children.map(child => evaluateNode(child, context)).join(''); + + const closeNode = node.children[node.children.length - 1]; + const shouldAddNewline = closeNode.name.endsWith('Nl') && !innerRender.endsWith('\n'); + + return innerRender + (shouldAddNewline ? '\n' : ''); + } + + return ''; + } + + case 'LoopSpanner': { + const feel = node.children[0].content; + let loopArray; + + try { + loopArray = evaluate$1(feel, context); + } + catch { + return errorHandler(new Error(`FEEL expression ${feel} couldn't be evaluated`)); + } + + if (!Array.isArray(loopArray)) { + + if (strict) { + return errorHandler(new Error(`FEEL expression ${feel} expected to evaluate to an array`)); + } + + // if not strict, we treat undefined/null as an empty array + else if (loopArray === undefined || loopArray === null) { + loopArray = []; + } + + // if not strict, we treat a single item as an array with one item + else { + loopArray = [ loopArray ]; + } + + } + + const childrenToLoop = node.children.slice(1, node.children.length - 1); + + const evaluateChildren = (arrayElement, parentContext) => { + const childContext = enhanceContext(arrayElement, parentContext); + return childrenToLoop.map(child => evaluateNode(child, childContext)).join(''); + }; + + const innerRender = loopArray.map(arrayElement => evaluateChildren(arrayElement, context)).join(''); + const closeNode = node.children[node.children.length - 1]; + const shouldAddNewline = closeNode.name.endsWith('Nl') && !innerRender.endsWith('\n'); + + return innerRender + (shouldAddNewline ? '\n' : ''); + }} + + }; + + const evaluateNode = (node, context = {}) => { + try { + return evaluateNodeValue(node, context); + } catch (error) { + return errorHandler(error); + } + }; + + return evaluateNode; + + }; + + const enhanceContext = (context, parentContext) => { + + if (typeof(context) === 'object') { + return { this: context, parent: parentContext, ...context, _this_: context, _parent_: parentContext }; + } + + return { this: context, parent: parentContext, _this_: context, _parent_: parentContext }; + }; - const enhanceContext = (context, parentContext) => { - - if (typeof(context) === 'object') { - return { this: context, parent: parentContext, ...context, _this_: context, _parent_: parentContext }; - } - - return { this: context, parent: parentContext, _this_: context, _parent_: parentContext }; - - }; - - /** - * Create warnings for empty inserts in the given tree. - * - * @param {Tree} syntaxTree - * @returns {LintMessage[]} array of syntax errors - */ - function lintEmptyInserts(syntaxTree) { - - const lintMessages = []; - - syntaxTree.iterate({ - enter: node => { - if (node.type.name === 'EmptyInsert') { - lintMessages.push( - { - from: node.from, - to: node.to, - severity: 'warning', - message: 'this insert is empty and will be ignored', - type: 'emptyInsert' - } - ); - } - } - }); - - return lintMessages; - } - - /** - * Generates lint messages for the given syntax tree. - * - * @param {Tree} syntaxTree - * @returns {LintMessage[]} array of all lint messages - */ - function lintAll(syntaxTree) { - - const lintMessages = [ - - ...lintEmptyInserts(syntaxTree) - ]; - - return lintMessages; - } - - - /** - * CodeMirror extension that provides linting for FEEL expressions. - * - * @param {EditorView} editorView - * @returns {Source} CodeMirror linting source - */ - function cmFeelersLinter() { - const lintFeel = cmFeelLinter(); - return editorView => { - - const feelMessages = lintFeel(editorView); - - // don't lint if the Editor is empty - if (editorView.state.doc.length === 0) { - return []; - } - - const tree = syntaxTree(editorView.state); - - const feelersMessages = lintAll(tree); - - return [ - ...feelMessages, - ...feelersMessages.map(message => ({ - ...message, - source: 'feelers linter' - })) - ]; - }; + /** + * Create warnings for empty inserts in the given tree. + * + * @param {Tree} syntaxTree + * @returns {LintMessage[]} array of syntax errors + */ + function lintEmptyInserts(syntaxTree) { + + const lintMessages = []; + + syntaxTree.iterate({ + enter: node => { + if (node.type.name === 'EmptyInsert') { + lintMessages.push( + { + from: node.from, + to: node.to, + severity: 'warning', + message: 'this insert is empty and will be ignored', + type: 'emptyInsert' + } + ); + } + } + }); + + return lintMessages; + } + + /** + * Generates lint messages for the given syntax tree. + * + * @param {Tree} syntaxTree + * @returns {LintMessage[]} array of all lint messages + */ + function lintAll(syntaxTree) { + + const lintMessages = [ + + ...lintEmptyInserts(syntaxTree) + ]; + + return lintMessages; + } + + + /** + * CodeMirror extension that provides linting for FEEL expressions. + * + * @param {EditorView} editorView + * @returns {Source} CodeMirror linting source + */ + function cmFeelersLinter() { + const lintFeel = cmFeelLinter(); + return editorView => { + + const feelMessages = lintFeel(editorView); + + // don't lint if the Editor is empty + if (editorView.state.doc.length === 0) { + return []; + } + + const tree = syntaxTree(editorView.state); + + const feelersMessages = lintAll(tree); + + return [ + ...feelMessages, + ...feelersMessages.map(message => ({ + ...message, + source: 'feelers linter' + })) + ]; + }; } linter(cmFeelersLinter()); @@ -35034,7 +35046,7 @@ var showdown$1 = {exports: {}}; (function (module) { - (function(){ + (function(){ /** * Created by Tivie on 13-07-2015. */ @@ -35230,7 +35242,7 @@ } return ret; } - + /** * Created by Tivie on 06-01-2015. */ @@ -35596,7 +35608,7 @@ } return true; }; - + /** * showdownjs helper functions */ @@ -37181,7 +37193,7 @@ 'octocat': ':octocat:', 'showdown': 'S' }; - + /** * Created by Estevao on 31-05-2015. */ @@ -37783,7 +37795,7 @@ metadata.raw = raw; }; }; - + /** * Turn Markdown link shortcuts into XHTML tags. */ @@ -37881,7 +37893,7 @@ text = globals.converter._dispatch('anchors.after', text, options, globals); return text; }); - + // url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-] var simpleURLRegex = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi, @@ -37957,7 +37969,7 @@ return text; }); - + /** * These are all the transformations that form block-level * tags like paragraphs, headers, and list items. @@ -37989,7 +38001,7 @@ return text; }); - + showdown.subParser('blockQuotes', function (text, options, globals) { text = globals.converter._dispatch('blockQuotes.before', text, options, globals); @@ -38031,7 +38043,7 @@ text = globals.converter._dispatch('blockQuotes.after', text, options, globals); return text; }); - + /** * Process Markdown `
` blocks.
   	 */
@@ -38069,7 +38081,7 @@
   	  text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 *
   	 *   *  Backtick quotes are used for  spans.
@@ -38117,7 +38129,7 @@
   	  text = globals.converter._dispatch('codeSpans.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Create a full HTML document from the processed markdown
   	 */
@@ -38179,7 +38191,7 @@
   	  text = globals.converter._dispatch('completeHTMLDocument.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Convert all tabs to spaces
   	 */
@@ -38212,7 +38224,7 @@
   	  text = globals.converter._dispatch('detab.after', text, options, globals);
   	  return text;
   	});
-
+
   	showdown.subParser('ellipsis', function (text, options, globals) {
 
   	  if (!options.ellipsis) {
@@ -38227,7 +38239,7 @@
 
   	  return text;
   	});
-
+
   	/**
   	 * Turn emoji codes into emojis
   	 *
@@ -38254,7 +38266,7 @@
 
   	  return text;
   	});
-
+
   	/**
   	 * Smart processing for ampersands and angle brackets that need to be encoded.
   	 */
@@ -38277,7 +38289,7 @@
   	  text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Returns the string, with after processing the following backslash escape sequences.
   	 *
@@ -38298,7 +38310,7 @@
   	  text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Encode/escape certain characters inside Markdown code runs.
   	 * The point is that in code, these characters are literals,
@@ -38321,7 +38333,7 @@
   	  text = globals.converter._dispatch('encodeCode.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they
   	 * don't conflict with their use in Markdown for code, italics and strong.
@@ -38347,7 +38359,7 @@
   	  text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Handle github codeblocks prior to running HashHTML so that
   	 * HTML contained within the codeblock gets escaped properly
@@ -38393,7 +38405,7 @@
 
   	  return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
   	});
-
+
   	showdown.subParser('hashBlock', function (text, options, globals) {
   	  text = globals.converter._dispatch('hashBlock.before', text, options, globals);
   	  text = text.replace(/(^\n+|\n+$)/g, '');
@@ -38401,7 +38413,7 @@
   	  text = globals.converter._dispatch('hashBlock.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Hash and escape  elements that should not be parsed as markdown
   	 */
@@ -38419,7 +38431,7 @@
   	  text = globals.converter._dispatch('hashCodeTags.after', text, options, globals);
   	  return text;
   	});
-
+
   	showdown.subParser('hashElement', function (text, options, globals) {
 
   	  return function (wholeMatch, m1) {
@@ -38438,7 +38450,7 @@
   	    return blockText;
   	  };
   	});
-
+
   	showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
   	  text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals);
 
@@ -38536,7 +38548,7 @@
   	  text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Hash span elements that should not be parsed as markdown
   	 */
@@ -38599,7 +38611,7 @@
   	  text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Hash and escape 
 elements that should not be parsed as markdown
   	 */
@@ -38618,7 +38630,7 @@
   	  text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals);
   	  return text;
   	});
-
+
   	showdown.subParser('headers', function (text, options, globals) {
 
   	  text = globals.converter._dispatch('headers.before', text, options, globals);
@@ -38744,7 +38756,7 @@
   	  text = globals.converter._dispatch('headers.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Turn Markdown link shortcuts into XHTML  tags.
   	 */
@@ -38759,7 +38771,7 @@
   	  text = globals.converter._dispatch('horizontalRule.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Turn Markdown image shortcuts into  tags.
   	 */
@@ -38863,7 +38875,7 @@
   	  text = globals.converter._dispatch('images.after', text, options, globals);
   	  return text;
   	});
-
+
   	showdown.subParser('italicsAndBold', function (text, options, globals) {
 
   	  text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
@@ -38933,7 +38945,7 @@
   	  text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Form HTML ordered (numbered) and unordered (bulleted) lists.
   	 */
@@ -39136,7 +39148,7 @@
   	  text = globals.converter._dispatch('lists.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Parse metadata at the top of the document
   	 */
@@ -39185,7 +39197,7 @@
   	  text = globals.converter._dispatch('metadata.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 * Remove one level of line-leading tabs or spaces
   	 */
@@ -39202,7 +39214,7 @@
   	  text = globals.converter._dispatch('outdent.after', text, options, globals);
   	  return text;
   	});
-
+
   	/**
   	 *
   	 */
@@ -39272,7 +39284,7 @@
   	  text = text.replace(/\n+$/g, '');
   	  return globals.converter._dispatch('paragraphs.after', text, options, globals);
   	});
-
+
   	/**
   	 * Run extension
   	 */
@@ -39292,7 +39304,7 @@
 
   	  return text;
   	});
-
+
   	/**
   	 * These are all the transformations that occur *within* block-level
   	 * tags like paragraphs, headers, and list items.
@@ -39341,7 +39353,7 @@
   	  text = globals.converter._dispatch('spanGamut.after', text, options, globals);
   	  return text;
   	});
-
+
   	showdown.subParser('strikethrough', function (text, options, globals) {
 
   	  function parseInside (txt) {
@@ -39359,7 +39371,7 @@
 
   	  return text;
   	});
-
+
   	/**
   	 * Strips link definitions from text, stores the URLs and titles in
   	 * hash references.
@@ -39417,7 +39429,7 @@
 
   	  return text;
   	});
-
+
   	showdown.subParser('tables', function (text, options, globals) {
 
   	  if (!options.tables) {
@@ -39557,7 +39569,7 @@
 
   	  return text;
   	});
-
+
   	showdown.subParser('underline', function (text, options, globals) {
 
   	  if (!options.underline) {
@@ -39589,7 +39601,7 @@
 
   	  return text;
   	});
-
+
   	/**
   	 * Swap back in all the special characters we've hidden.
   	 */
@@ -39604,7 +39616,7 @@
   	  text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals);
   	  return text;
   	});
-
+
   	showdown.subParser('makeMarkdown.blockquote', function (node, globals) {
 
   	  var txt = '';
@@ -39626,19 +39638,19 @@
   	  txt = '> ' + txt.split('\n').join('\n> ');
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.codeBlock', function (node, globals) {
 
   	  var lang = node.getAttribute('language'),
   	      num  = node.getAttribute('precodenum');
   	  return '```' + lang + '\n' + globals.preList[num] + '\n```';
   	});
-
+
   	showdown.subParser('makeMarkdown.codeSpan', function (node) {
 
   	  return '`' + node.innerHTML + '`';
   	});
-
+
   	showdown.subParser('makeMarkdown.emphasis', function (node, globals) {
 
   	  var txt = '';
@@ -39653,7 +39665,7 @@
   	  }
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.header', function (node, globals, headerLevel) {
 
   	  var headerMark = new Array(headerLevel + 1).join('#'),
@@ -39670,12 +39682,12 @@
   	  }
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.hr', function () {
 
   	  return '---';
   	});
-
+
   	showdown.subParser('makeMarkdown.image', function (node) {
 
   	  var txt = '';
@@ -39693,7 +39705,7 @@
   	  }
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.links', function (node, globals) {
 
   	  var txt = '';
@@ -39713,7 +39725,7 @@
   	  }
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.list', function (node, globals, type) {
 
   	  var txt = '';
@@ -39746,7 +39758,7 @@
   	  txt += '\n\n';
   	  return txt.trim();
   	});
-
+
   	showdown.subParser('makeMarkdown.listItem', function (node, globals) {
 
   	  var listItemTxt = '';
@@ -39771,7 +39783,7 @@
 
   	  return listItemTxt;
   	});
-
+
 
 
   	showdown.subParser('makeMarkdown.node', function (node, globals, spansOnly) {
@@ -39891,7 +39903,7 @@
 
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.paragraph', function (node, globals) {
 
   	  var txt = '';
@@ -39908,13 +39920,13 @@
 
   	  return txt;
   	});
-
+
   	showdown.subParser('makeMarkdown.pre', function (node, globals) {
 
   	  var num  = node.getAttribute('prenum');
   	  return '
' + globals.preList[num] + '
'; }); - + showdown.subParser('makeMarkdown.strikethrough', function (node, globals) { var txt = ''; @@ -39929,7 +39941,7 @@ } return txt; }); - + showdown.subParser('makeMarkdown.strong', function (node, globals) { var txt = ''; @@ -39944,7 +39956,7 @@ } return txt; }); - + showdown.subParser('makeMarkdown.table', function (node, globals) { var txt = '', @@ -40014,7 +40026,7 @@ return txt.trim(); }); - + showdown.subParser('makeMarkdown.tableCell', function (node, globals) { var txt = ''; @@ -40029,7 +40041,7 @@ } return txt.trim(); }); - + showdown.subParser('makeMarkdown.txt', function (node) { var txt = node.nodeValue; @@ -40072,7 +40084,7 @@ return txt; }); - + var root = this; // AMD Loader @@ -40083,7 +40095,7 @@ } else { root.showdown = showdown; } - }).call(commonjsGlobal); + }).call(commonjsGlobal); } (showdown$1)); @@ -40464,14 +40476,144 @@ } FeelersTemplating.$inject = []; + // config /////////////////// + + const MINUTES_IN_DAY = 60 * 24; + const DATETIME_SUBTYPES = { + DATE: 'date', + TIME: 'time', + DATETIME: 'datetime' + }; + const TIME_SERIALISING_FORMATS = { + UTC_OFFSET: 'utc_offset', + UTC_NORMALIZED: 'utc_normalized', + NO_TIMEZONE: 'no_timezone' + }; + const DATETIME_SUBTYPE_PATH = ['subtype']; + const DATE_LABEL_PATH = ['dateLabel']; + + function createInjector(bootstrapModules) { + const injector = new Injector(bootstrapModules); + injector.init(); + return injector; + } + + /** + * @param {string?} prefix + * + * @returns Element + */ + function createFormContainer(prefix = 'fjs') { + const container = document.createElement('div'); + container.classList.add(`${prefix}-container`); + return container; + } + + const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression']; + const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text']; + + /** + * @template T + * @param {T} data + * @param {(this: any, key: string, value: any) => any} [replacer] + * @return {T} + */ + function clone(data, replacer) { + return JSON.parse(JSON.stringify(data, replacer)); + } + + /** + * Parse the schema for input variables a form might make use of + * + * @param {any} schema + * + * @return {string[]} + */ + function getSchemaVariables(schema, options = {}) { + const { + expressionLanguage = new FeelExpressionLanguage(null), + templating = new FeelersTemplating(), + inputs = true, + outputs = true + } = options; + if (!schema.components) { + return []; + } + const getAllComponents = node => { + const components = []; + if (node.components) { + node.components.forEach(component => { + components.push(component); + components.push(...getAllComponents(component)); + }); + } + return components; + }; + const variables = getAllComponents(schema).reduce((variables, component) => { + const { + valuesKey + } = component; + + // collect input-only variables + if (inputs) { + if (valuesKey) { + variables = [...variables, valuesKey]; + } + EXPRESSION_PROPERTIES.forEach(prop => { + const property = get(component, prop.split('.')); + if (property && expressionLanguage.isExpression(property)) { + const expressionVariables = expressionLanguage.getVariableNames(property, { + type: 'expression' + }); + variables = [...variables, ...expressionVariables]; + } + }); + TEMPLATE_PROPERTIES.forEach(prop => { + const property = get(component, prop.split('.')); + if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) { + const templateVariables = templating.getVariableNames(property); + variables = [...variables, ...templateVariables]; + } + }); + } + return variables.filter(variable => variable !== undefined || variable !== null); + }, []); + const getBindingVariables = node => { + const bindingVariable = []; + + // c.f. https://github.com/bpmn-io/form-js/issues/778 @Skaiir to remove? + if (node.type === 'button') { + return []; + } else if (node.key) { + return [node.key.split('.')[0]]; + } else if (node.path) { + return [node.path.split('.')[0]]; + } else if (node.components) { + node.components.forEach(component => { + bindingVariable.push(...getBindingVariables(component)); + }); + } + return bindingVariable; + }; + + // collect binding variables + if (inputs || outputs) { + variables.push(...getBindingVariables(schema)); + } + + // remove duplicates + return Array.from(new Set(variables)); + } + /** * @typedef {object} Condition * @property {string} [hide] */ class ConditionChecker { - constructor(formFieldRegistry, eventBus) { + constructor(formFieldRegistry, pathRegistry, eventBus) { this._formFieldRegistry = formFieldRegistry; + this._pathRegistry = pathRegistry; this._eventBus = eventBus; } @@ -40482,19 +40624,27 @@ * @param {Object} data */ applyConditions(properties, data = {}) { - const conditions = this._getConditions(); - const newProperties = { - ...properties - }; - for (const { - key, - condition - } of conditions) { - const shouldRemove = this._checkHideCondition(condition, data); - if (shouldRemove) { - delete newProperties[key]; - } + const newProperties = clone(properties); + const form = this._formFieldRegistry.getAll().find(field => field.type === 'default'); + if (!form) { + throw new Error('form field registry has no form'); } + this._pathRegistry.executeRecursivelyOnFields(form, ({ + field, + isClosed, + context + }) => { + const { + conditional: condition + } = field; + context.isHidden = context.isHidden || condition && this._checkHideCondition(condition, data); + + // only clear the leaf nodes, as groups may both point to the same path + if (context.isHidden && isClosed) { + const valuePath = this._pathRegistry.getValuePath(field); + this._clearObjectValueRecursively(valuePath, newProperties); + } + }); return newProperties; } @@ -40539,24 +40689,18 @@ const result = this.check(condition.hide, data); return result === true; } - _getConditions() { - const formFields = this._formFieldRegistry.getAll(); - return formFields.reduce((conditions, formField) => { - const { - key, - conditional: condition - } = formField; - if (key && condition) { - return [...conditions, { - key, - condition - }]; - } - return conditions; - }, []); + _clearObjectValueRecursively(valuePath, obj) { + const workingValuePath = [...valuePath]; + let recurse = false; + do { + set(obj, workingValuePath, undefined); + workingValuePath.pop(); + const parentObject = get(obj, workingValuePath); + recurse = isObject(parentObject) && !values(parentObject).length && !!workingValuePath.length; + } while (recurse); } } - ConditionChecker.$inject = ['formFieldRegistry', 'eventBus']; + ConditionChecker.$inject = ['formFieldRegistry', 'pathRegistry', 'eventBus']; var ExpressionLanguageModule = { __init__: ['expressionLanguage', 'templating', 'conditionChecker'], @@ -41061,136 +41205,6 @@ commandStack: ['type', CommandStack] }; - // config /////////////////// - - const MINUTES_IN_DAY = 60 * 24; - const DATETIME_SUBTYPES = { - DATE: 'date', - TIME: 'time', - DATETIME: 'datetime' - }; - const TIME_SERIALISING_FORMATS = { - UTC_OFFSET: 'utc_offset', - UTC_NORMALIZED: 'utc_normalized', - NO_TIMEZONE: 'no_timezone' - }; - const DATETIME_SUBTYPE_PATH = ['subtype']; - const DATE_LABEL_PATH = ['dateLabel']; - - function createInjector(bootstrapModules) { - const injector = new Injector(bootstrapModules); - injector.init(); - return injector; - } - - /** - * @param {string?} prefix - * - * @returns Element - */ - function createFormContainer(prefix = 'fjs') { - const container = document.createElement('div'); - container.classList.add(`${prefix}-container`); - return container; - } - - const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression']; - const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text']; - function findErrors(errors, path) { - return errors[pathStringify(path)]; - } - function pathStringify(path) { - if (!path) { - return ''; - } - return path.join('.'); - } - const indices = {}; - function generateIndexForType(type) { - if (type in indices) { - indices[type]++; - } else { - indices[type] = 1; - } - return indices[type]; - } - function generateIdForType(type) { - return `${type}${generateIndexForType(type)}`; - } - - /** - * @template T - * @param {T} data - * @param {(this: any, key: string, value: any) => any} [replacer] - * @return {T} - */ - function clone(data, replacer) { - return JSON.parse(JSON.stringify(data, replacer)); - } - - /** - * Parse the schema for input variables a form might make use of - * - * @param {any} schema - * - * @return {string[]} - */ - function getSchemaVariables(schema, options = {}) { - const { - expressionLanguage = new FeelExpressionLanguage(null), - templating = new FeelersTemplating(), - inputs = true, - outputs = true - } = options; - if (!schema.components) { - return []; - } - const variables = schema.components.reduce((variables, component) => { - const { - key, - valuesKey, - type - } = component; - if (['button'].includes(type)) { - return variables; - } - - // collect bi-directional variables - if (inputs || outputs) { - if (key) { - variables = [...variables, key]; - } - } - - // collect input-only variables - if (inputs) { - if (valuesKey) { - variables = [...variables, valuesKey]; - } - EXPRESSION_PROPERTIES.forEach(prop => { - const property = get(component, prop.split('.')); - if (property && expressionLanguage.isExpression(property)) { - const expressionVariables = expressionLanguage.getVariableNames(property, { - type: 'expression' - }); - variables = [...variables, ...expressionVariables]; - } - }); - TEMPLATE_PROPERTIES.forEach(prop => { - const property = get(component, prop.split('.')); - if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) { - const templateVariables = templating.getVariableNames(property); - variables = [...variables, ...templateVariables]; - } - }); - } - return variables.filter(variable => variable !== undefined || variable !== null); - }, []); - - // remove duplicates - return Array.from(new Set(variables)); - } - class UpdateFieldValidationHandler { constructor(form, validator) { this._form = form; @@ -41201,15 +41215,12 @@ field, value } = context; - const { - _path - } = field; const { errors } = this._form._getState(); context.oldErrors = clone(errors); const fieldErrors = this._validator.validateField(field, value); - const updatedErrors = set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined); + const updatedErrors = set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined); this._form._setState({ errors: updatedErrors }); @@ -41892,54 +41903,397 @@ return evaluatedValidate; } - class FormFieldRegistry { - constructor(eventBus) { - this._eventBus = eventBus; - this._formFields = {}; - eventBus.on('form.clear', () => this.clear()); - this._ids = new Ids([32, 36, 1]); - this._keys = new Ids([32, 36, 1]); + class Importer { + /** + * @constructor + * @param { import('./FormFieldRegistry').default } formFieldRegistry + * @param { import('./PathRegistry').default } pathRegistry + * @param { import('./FieldFactory').default } fieldFactory + * @param { import('./FormLayouter').default } formLayouter + */ + constructor(formFieldRegistry, pathRegistry, fieldFactory, formLayouter) { + this._formFieldRegistry = formFieldRegistry; + this._pathRegistry = pathRegistry; + this._fieldFactory = fieldFactory; + this._formLayouter = formLayouter; } - add(formField) { + + /** + * Import schema creating rows, fields, attaching additional + * information to each field and adding fields to the + * field registry. + * + * Additional information attached: + * + * * `id` (unless present) + * * `_parent` + * * `_path` + * + * @param {any} schema + * + * @typedef {{ warnings: Error[], schema: any }} ImportResult + * @returns {ImportResult} + */ + importSchema(schema) { + // TODO: Add warnings + const warnings = []; + try { + this._cleanup(); + const importedSchema = this.importFormField(clone(schema)); + this._formLayouter.calculateLayout(clone(importedSchema)); + return { + schema: importedSchema, + warnings + }; + } catch (err) { + this._cleanup(); + err.warnings = warnings; + throw err; + } + } + _cleanup() { + this._formLayouter.clear(); + this._formFieldRegistry.clear(); + this._pathRegistry.clear(); + } + + /** + * @param {{[x: string]: any}} fieldAttrs + * @param {String} [parentId] + * @param {number} [index] + * + * @return {any} field + */ + importFormField(fieldAttrs, parentId, index) { const { - id - } = formField; - if (this._formFields[id]) { - throw new Error(`form field with ID ${id} already exists`); + components + } = fieldAttrs; + let parent, path; + if (parentId) { + parent = this._formFieldRegistry.get(parentId); } - this._eventBus.fire('formField.add', { - formField + + // set form field path + path = parent ? [...parent._path, 'components', index] : []; + const field = this._fieldFactory.create({ + ...fieldAttrs, + _path: path, + _parent: parentId + }, false); + this._formFieldRegistry.add(field); + if (components) { + field.components = this.importFormFields(components, field.id); + } + return field; + } + + /** + * @param {Array} components + * @param {string} parentId + * + * @return {Array} imported components + */ + importFormFields(components, parentId) { + return components.map((component, index) => { + return this.importFormField(component, parentId, index); }); - this._formFields[id] = formField; } - remove(formField) { + } + Importer.$inject = ['formFieldRegistry', 'pathRegistry', 'fieldFactory', 'formLayouter']; + + class FieldFactory { + /** + * @constructor + * + * @param formFieldRegistry + * @param formFields + */ + constructor(formFieldRegistry, pathRegistry, formFields) { + this._formFieldRegistry = formFieldRegistry; + this._pathRegistry = pathRegistry; + this._formFields = formFields; + } + create(attrs, applyDefaults = true) { const { - id - } = formField; - if (!this._formFields[id]) { - return; + id, + type, + key, + path, + _parent + } = attrs; + const fieldDefinition = this._formFields.get(type); + if (!fieldDefinition) { + throw new Error(`form field of type <${type}> not supported`); } - this._eventBus.fire('formField.remove', { - formField + const { + config + } = fieldDefinition; + if (!config) { + throw new Error(`form field of type <${type}> has no config`); + } + if (id && this._formFieldRegistry._ids.assigned(id)) { + throw new Error(`form field with id <${id}> already exists`); + } + + // ensure that we can claim the path + + const parent = _parent && this._formFieldRegistry.get(_parent); + const parentPath = parent && this._pathRegistry.getValuePath(parent) || []; + if (config.keyed && key && !this._pathRegistry.canClaimPath([...parentPath, ...key.split('.')], true)) { + throw new Error(`binding path '${[...parentPath, key].join('.')}' is already claimed`); + } + if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], false)) { + throw new Error(`binding path '${[...parentPath, ...path.split('.')].join('.')}' is already claimed`); + } + const labelAttrs = applyDefaults && config.label ? { + label: config.label + } : {}; + const field = config.create({ + ...labelAttrs, + ...attrs }); - delete this._formFields[id]; + this._ensureId(field); + if (config.keyed) { + this._ensureKey(field); + } + if (config.pathed && path) { + this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), false); + } + return field; } - get(id) { - return this._formFields[id]; + _ensureId(field) { + if (field.id) { + this._formFieldRegistry._ids.claim(field.id, field); + return; + } + let prefix = 'Field'; + if (field.type === 'default') { + prefix = 'Form'; + } + field.id = this._formFieldRegistry._ids.nextPrefixed(`${prefix}_`, field); } - getAll() { - return Object.values(this._formFields); + _ensureKey(field) { + if (!field.key) { + let random; + const parent = this._formFieldRegistry.get(field._parent); + + // ensure key uniqueness at level + do { + random = Math.random().toString(36).substring(7); + } while (parent && parent.components.some(child => child.key === random)); + field.key = `${field.type}_${random}`; + } + this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), true); } - forEach(callback) { - this.getAll().forEach(formField => callback(formField)); + } + FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields']; + + /** + * The PathRegistry class manages a hierarchical structure of paths associated with form fields. + * It enables claiming, unclaiming, and validating paths within this structure. + * + * Example Tree Structure: + * + * [ + * { + * segment: 'root', + * claimCount: 1, + * children: [ + * { + * segment: 'child1', + * claimCount: 2, + * children: null // A leaf node (closed path) + * }, + * { + * segment: 'child2', + * claimCount: 1, + * children: [ + * { + * segment: 'subChild1', + * claimCount: 1, + * children: [] // An open node (open path) + * } + * ] + * } + * ] + * } + * ] + */ + class PathRegistry { + constructor(formFieldRegistry, formFields) { + this._formFieldRegistry = formFieldRegistry; + this._formFields = formFields; + this._dataPaths = []; + } + canClaimPath(path, closed = false) { + let node = { + children: this._dataPaths + }; + for (const segment of path) { + node = _getNextSegment(node, segment); + + // if no node at that path, we can claim it no matter what + if (!node) { + return true; + } + + // if we reach a leaf node, definitely not claimable + if (node.children === null) { + return false; + } + } + + // if after all segments we reach a node with children, we can claim it only openly + return !closed; + } + claimPath(path, closed = false) { + if (!this.canClaimPath(path, closed)) { + throw new Error(`cannot claim path '${path.join('.')}'`); + } + let node = { + children: this._dataPaths + }; + for (const segment of path) { + let child = _getNextSegment(node, segment); + if (!child) { + child = { + segment, + claimCount: 1, + children: [] + }; + node.children.push(child); + } else { + child.claimCount++; + } + node = child; + } + if (closed) { + node.children = null; + } + } + unclaimPath(path) { + // verification Pass + let node = { + children: this._dataPaths + }; + for (const segment of path) { + const child = _getNextSegment(node, segment); + if (!child) { + throw new Error(`no open path found for '${path.join('.')}'`); + } + node = child; + } + + // mutation Pass + node = { + children: this._dataPaths + }; + for (const segment of path) { + const child = _getNextSegment(node, segment); + child.claimCount--; + if (child.claimCount === 0) { + node.children.splice(node.children.indexOf(child), 1); + break; // Abort early if claimCount reaches zero + } + + node = child; + } + } + + /** + * Applies a function (fn) recursively on a given field and its children. + * + * - `field`: Starting field object. + * - `fn`: Function to apply. + * - `context`: Optional object for passing data between calls. + * + * Stops early if `fn` returns `false`. Useful for traversing the form field tree. + * + * @returns {boolean} Success status based on function execution. + */ + executeRecursivelyOnFields(field, fn, context = {}) { + let result = true; + const formFieldConfig = this._formFields.get(field.type).config; + if (formFieldConfig.keyed) { + const callResult = fn({ + field, + isClosed: true, + context + }); + return result && callResult; + } else if (formFieldConfig.pathed) { + const callResult = fn({ + field, + isClosed: false, + context + }); + result = result && callResult; + } + if (field.components) { + for (const child of field.components) { + const callResult = this.executeRecursivelyOnFields(child, fn, clone(context)); + result = result && callResult; + + // only stop executing if false is specifically returned, not if undefined + if (result === false) { + return result; + } + } + } + return result; + } + + /** + * Generates an array representing the binding path to an underlying data object for a form field. + * + * @param {Object} field - The field object with properties: `key`, `path`, `id`, and optionally `_parent`. + * @param {Object} [options={}] - Configuration options. + * @param {Object} [options.replacements={}] - A map of field IDs to alternative path arrays. + * @param {Object} [options.cutoffNode] - The ID of the parent field at which to stop generating the path. + * + * @returns {(Array|undefined)} An array of strings representing the binding path, or undefined if not determinable. + */ + getValuePath(field, options = {}) { + const { + replacements = {}, + cutoffNode = null + } = options; + let localValuePath = []; + const hasReplacement = Object.prototype.hasOwnProperty.call(replacements, field.id); + const formFieldConfig = this._formFields.get(field.type).config; + if (hasReplacement) { + const replacement = replacements[field.id]; + if (replacement === null || replacement === undefined || replacement === '') { + localValuePath = []; + } else if (typeof replacement === 'string') { + localValuePath = replacement.split('.'); + } else if (Array.isArray(replacement)) { + localValuePath = replacement; + } else { + throw new Error(`replacements for field ${field.id} must be a string, array or null/undefined`); + } + } else if (formFieldConfig.keyed) { + localValuePath = field.key.split('.'); + } else if (formFieldConfig.pathed && field.path) { + localValuePath = field.path.split('.'); + } + if (field._parent && field._parent !== cutoffNode) { + const parent = this._formFieldRegistry.get(field._parent); + return [...(this.getValuePath(parent, options) || []), ...localValuePath]; + } + return localValuePath; } clear() { - this._formFields = {}; - this._ids.clear(); - this._keys.clear(); + this._dataPaths = []; } } - FormFieldRegistry.$inject = ['eventBus']; + const _getNextSegment = (node, segment) => { + if (isArray$2(node.children)) { + return node.children.find(node => node.segment === segment) || null; + } + return null; + }; + PathRegistry.$inject = ['formFieldRegistry', 'formFields']; /** * @typedef { { id: String, components: Array } } FormRow @@ -42031,7 +42385,7 @@ type, components } = formField; - if (type !== 'default' || !components) { + if (type !== 'default' && type !== 'group' || !components) { return; } @@ -42086,147 +42440,52 @@ return flatten$2(formRows.map(c => c.rows)); } - class Importer { - /** - * @constructor - * @param { import('../core').FormFieldRegistry } formFieldRegistry - * @param { import('../render/FormFields').default } formFields - * @param { import('../core').FormLayouter } formLayouter - */ - constructor(formFieldRegistry, formFields, formLayouter) { - this._formFieldRegistry = formFieldRegistry; - this._formFields = formFields; - this._formLayouter = formLayouter; + class FormFieldRegistry { + constructor(eventBus) { + this._eventBus = eventBus; + this._formFields = {}; + eventBus.on('form.clear', () => this.clear()); + this._ids = new Ids([32, 36, 1]); } - - /** - * Import schema adding `id`, `_parent` and `_path` - * information to each field and adding it to the - * form field registry. - * - * @param {any} schema - * @param {any} [data] - * - * @return { { warnings: Array, schema: any, data: any } } - */ - importSchema(schema, data = {}) { - // TODO: Add warnings - https://github.com/bpmn-io/form-js/issues/289 - const warnings = []; - try { - this._formLayouter.clear(); - const importedSchema = this.importFormField(clone(schema)), - initializedData = this.initializeFieldValues(clone(data)); - this._formLayouter.calculateLayout(clone(importedSchema)); - return { - warnings, - schema: importedSchema, - data: initializedData - }; - } catch (err) { - err.warnings = warnings; - throw err; + add(formField) { + const { + id + } = formField; + if (this._formFields[id]) { + throw new Error(`form field with ID ${id} already exists`); } + this._eventBus.fire('formField.add', { + formField + }); + this._formFields[id] = formField; } - - /** - * @param {any} formField - * @param {string} [parentId] - * - * @return {any} importedField - */ - importFormField(formField, parentId) { + remove(formField) { const { - components, - key, - type, - id = generateIdForType(type) + id } = formField; - if (parentId) { - // set form field parent - formField._parent = parentId; - } - if (!this._formFields.get(type)) { - throw new Error(`form field of type <${type}> not supported`); - } - if (key) { - // validate uniqueness - if (this._formFieldRegistry._keys.assigned(key)) { - throw new Error(`form field with key <${key}> already exists`); - } - this._formFieldRegistry._keys.claim(key, formField); - - // TODO: buttons should not have key - if (type !== 'button') { - // set form field path - formField._path = [key]; - } - } - if (id) { - // validate uniqueness - if (this._formFieldRegistry._ids.assigned(id)) { - throw new Error(`form field with id <${id}> already exists`); - } - this._formFieldRegistry._ids.claim(id, formField); - } - - // set form field ID - formField.id = id; - this._formFieldRegistry.add(formField); - if (components) { - this.importFormFields(components, id); + if (!this._formFields[id]) { + return; } - return formField; - } - importFormFields(components, parentId) { - components.forEach(component => { - this.importFormField(component, parentId); + this._eventBus.fire('formField.remove', { + formField }); + delete this._formFields[id]; } - - /** - * @param {Object} data - * - * @return {Object} initializedData - */ - initializeFieldValues(data) { - return this._formFieldRegistry.getAll().reduce((initializedData, formField) => { - const { - defaultValue, - _path, - type - } = formField; - - // try to get value from data - // if unavailable - try to get default value from form field - // if unavailable - get empty value from form field - - if (_path) { - const { - config: fieldConfig - } = this._formFields.get(type); - let valueData = get(data, _path); - if (!isUndefined$1(valueData) && fieldConfig.sanitizeValue) { - valueData = fieldConfig.sanitizeValue({ - formField, - data, - value: valueData - }); - } - const initializedFieldValue = !isUndefined$1(valueData) ? valueData : !isUndefined$1(defaultValue) ? defaultValue : fieldConfig.emptyValue; - initializedData = { - ...initializedData, - [_path[0]]: initializedFieldValue - }; - } - return initializedData; - }, data); + get(id) { + return this._formFields[id]; + } + getAll() { + return Object.values(this._formFields); + } + forEach(callback) { + this.getAll().forEach(formField => callback(formField)); + } + clear() { + this._formFields = {}; + this._ids.clear(); } } - Importer.$inject = ['formFieldRegistry', 'formFields', 'formLayouter']; - - var importModule = { - importer: ['type', Importer] - }; + FormFieldRegistry.$inject = ['eventBus']; function formFieldClasses(type, { errors = [], @@ -42281,7 +42540,7 @@ } Button.config = { type: type$c, - keyed: true, + keyed: false, label: 'Button', group: 'action', create: (options = {}) => ({ @@ -42291,6 +42550,9 @@ }; const FormRenderContext = D$1({ + EmptyRoot: props => { + return null; + }, Empty: props => { return null; }, @@ -42320,6 +42582,10 @@ class: props.class, children: props.children }); + }, + hoveredId: [], + setHoveredId: newValue => { + console.log(`setHoveredId not defined, called with '${newValue}'`); } }); var FormRenderContext$1 = FormRenderContext; @@ -42441,6 +42707,37 @@ return readonly || false; } + function usePrevious(value, defaultValue, dependencies) { + const ref = s(defaultValue); + y(() => ref.current = value, dependencies); + return ref.current; + } + + /** + * A custom hook to manage state changes with deep comparison. + * + * @param {any} value - The current value to manage. + * @param {any} defaultValue - The initial default value for the state. + * @returns {any} - Returns the current state. + */ + function useDeepCompareState(value, defaultValue) { + const [state, setState] = l$1(defaultValue); + const previous = usePrevious(value, defaultValue, [value]); + const changed = !compare(previous, value); + y(() => { + if (changed) { + setState(value); + } + }, [changed, value]); + return state; + } + + // helpers ////////////////////////// + + function compare(a, b) { + return JSON.stringify(a) === JSON.stringify(b); + } + /** * Template a string reactively based on form data. If the string is not a template, it is returned as is. * Memoised to minimize re-renders @@ -42661,6 +42958,21 @@ function _isValueSomething(value) { return value || value === 0 || value === false; } + function createEmptyOptions(options = {}) { + const defaults = {}; + + // provide default values if valuesKey and valuesExpression are not set + if (!options.valuesKey && !options.valuesExpression) { + defaults.values = [{ + label: 'Value', + value: 'value' + }]; + } + return { + ...defaults, + ...options + }; + } /** * @enum { String } @@ -42695,11 +43007,8 @@ state: LOAD_STATES.LOADING }); const initialData = useService('form')._getState().initialData; - const evaluatedValues = d(() => { - if (valuesExpression) { - return useExpressionEvaluation(valuesExpression); - } - }, [valuesExpression]); + const expressionEvaluation = useExpressionEvaluation(valuesExpression); + const evaluatedValues = useDeepCompareState(expressionEvaluation || [], []); y(() => { let values = []; @@ -42715,8 +43024,10 @@ values = Array.isArray(staticValues) ? staticValues : []; // expression - } else if (evaluatedValues && Array.isArray(evaluatedValues)) { - values = evaluatedValues; + } else if (valuesExpression) { + if (evaluatedValues && Array.isArray(evaluatedValues)) { + values = evaluatedValues; + } } else { setValuesGetter(buildErrorState('No values source defined in the form definition')); return; @@ -42725,7 +43036,7 @@ // normalize data to support primitives and partially defined objects values = normalizeValuesData(values); setValuesGetter(buildLoadedState(values)); - }, [valuesKey, staticValues, initialData]); + }, [valuesKey, staticValues, initialData, valuesExpression, evaluatedValues]); return valuesGetter; } const buildErrorState = error => ({ @@ -43037,21 +43348,7 @@ group: 'selection', emptyValue: [], sanitizeValue: sanitizeMultiSelectValue, - create: (options = {}) => { - const defaults = {}; - - // provide default values if valuesKey isn't set - if (!options.valuesKey) { - defaults.values = [{ - label: 'Value', - value: 'value' - }]; - } - return { - ...defaults, - ...options - }; - } + create: createEmptyOptions }; const noop$1 = () => false; @@ -43062,6 +43359,7 @@ } = props; const formFields = useService('formFields'), viewerCommands = useService('viewerCommands', false), + pathRegistry = useService('pathRegistry'), form = useService('form'); const { initialData, @@ -43078,10 +43376,10 @@ if (!FormFieldComponent) { throw new Error(`cannot render field <${field.type}>`); } - const initialValue = d(() => get(initialData, field._path), [initialData, field._path]); - const value = get(data, field._path); - const fieldErrors = findErrors(errors, field._path); + const valuePath = d(() => pathRegistry.getValuePath(field), [field, pathRegistry]); + const initialValue = d(() => get(initialData, valuePath), [initialData, valuePath]); const readonly = useReadonly(field, properties); + const value = get(data, valuePath); // add precedence: global readonly > form field disabled const disabled = !properties.readOnly && (properties.disabled || field.disabled || false); @@ -43108,7 +43406,7 @@ children: e$2(FormFieldComponent, { ...props, disabled: disabled, - errors: fieldErrors, + errors: errors[field.id], onChange: disabled || readonly ? noop$1 : onChange, onBlur: disabled || readonly ? noop$1 : onBlur, readonly: readonly, @@ -43118,14 +43416,14 @@ }); } - function Default(props) { + function Grid(props) { const { Children, - Empty, Row } = F(FormRenderContext$1); const { - field + field, + Empty } = props; const { id, @@ -43162,7 +43460,20 @@ }), components.length ? null : e$2(Empty, {})] }); } - Default.config = { + + function FormComponent$1(props) { + const { + EmptyRoot + } = F(FormRenderContext$1); + const fullProps = { + ...props, + Empty: EmptyRoot + }; + return e$2(Grid, { + ...fullProps + }); + } + FormComponent$1.config = { type: 'default', keyed: false, label: null, @@ -43191,6 +43502,74 @@ }; var CalendarIcon = SvgCalendar; + /** + * Returns date format for the provided locale. + * If the locale is not provided, uses the browser's locale. + * + * @param {string} [locale] - The locale to get date format for. + * @returns {string} The date format for the locale. + */ + function getLocaleDateFormat(locale = 'default') { + const parts = new Intl.DateTimeFormat(locale).formatToParts(new Date(Date.UTC(2020, 5, 5))); + return parts.map(part => { + const len = part.value.length; + switch (part.type) { + case 'day': + return 'd'.repeat(len); + case 'month': + return 'M'.repeat(len); + case 'year': + return 'y'.repeat(len); + default: + return part.value; + } + }).join(''); + } + + /** + * Returns readable date format for the provided locale. + * If the locale is not provided, uses the browser's locale. + * + * @param {string} [locale] - The locale to get readable date format for. + * @returns {string} The readable date format for the locale. + */ + function getLocaleReadableDateFormat(locale) { + let format = getLocaleDateFormat(locale).toLowerCase(); + + // Ensure month is in 'mm' format + if (!format.includes('mm')) { + format = format.replace('m', 'mm'); + } + + // Ensure day is in 'dd' format + if (!format.includes('dd')) { + format = format.replace('d', 'dd'); + } + return format; + } + + /** + * Returns flatpickr config for the provided locale. + * If the locale is not provided, uses the browser's locale. + * + * @param {string} [locale] - The locale to get flatpickr config for. + * @returns {object} The flatpickr config for the locale. + */ + function getLocaleDateFlatpickrConfig(locale) { + return flatpickerizeDateFormat(getLocaleDateFormat(locale)); + } + function flatpickerizeDateFormat(dateFormat) { + const useLeadingZero = { + day: dateFormat.includes('dd'), + month: dateFormat.includes('MM'), + year: dateFormat.includes('yyyy') + }; + dateFormat = useLeadingZero.day ? dateFormat.replace('dd', 'd') : dateFormat.replace('d', 'j'); + dateFormat = useLeadingZero.month ? dateFormat.replace('MM', 'm') : dateFormat.replace('M', 'n'); + dateFormat = useLeadingZero.year ? dateFormat.replace('yyyy', 'Y') : dateFormat.replace('yy', 'y'); + return dateFormat; + } + function InputAdorner(props) { const { pre, @@ -43265,7 +43644,7 @@ y(() => { let config = { allowInput: true, - dateFormat: 'm/d/Y', + dateFormat: getLocaleDateFlatpickrConfig(), static: true, clickOpens: false, // TODO: support dates prior to 1900 (https://github.com/bpmn-io/form-js/issues/533) @@ -43357,7 +43736,7 @@ class: "fjs-input", disabled: disabled, readOnly: readonly, - placeholder: "mm/dd/yyyy", + placeholder: getLocaleReadableDateFormat(), autoComplete: "off", onFocus: onInputFocus, onKeyDown: onInputKeyDown, @@ -43442,7 +43821,8 @@ y(() => { const individualEntries = dropdownContainer.current.children; if (individualEntries.length && !mouseControl) { - individualEntries[focusedValueIndex].scrollIntoView({ + const focusedEntry = individualEntries[focusedValueIndex]; + focusedEntry && focusedEntry.scrollIntoView({ block: 'nearest', inline: 'nearest' }); @@ -43978,6 +44358,52 @@ }); } + function Group(props) { + const { + field + } = props; + const { + label, + id, + type, + showOutline + } = field; + const { + formId + } = F(FormContext$1); + const { + Empty + } = F(FormRenderContext$1); + const fullProps = { + ...props, + Empty + }; + return e$2("div", { + className: classNames(formFieldClasses(type), { + 'fjs-outlined': showOutline + }), + role: "group", + "aria-labelledby": prefixId(id, formId), + children: [e$2(Label, { + id: prefixId(id, formId), + label: label + }), e$2(Grid, { + ...fullProps + })] + }); + } + Group.config = { + type: 'group', + pathed: true, + label: 'Group', + group: 'presentation', + create: (options = {}) => ({ + components: [], + showOutline: true, + ...options + }) + }; + const NODE_TYPE_TEXT = 3, NODE_TYPE_ELEMENT = 1; const ALLOWED_NODES = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'em', 'a', 'p', 'div', 'ul', 'ol', 'li', 'hr', 'blockquote', 'img', 'pre', 'code', 'br', 'strong', 'table', 'thead', 'tbody', 'tr', 'th', 'td']; @@ -44566,21 +44992,7 @@ group: 'selection', emptyValue: null, sanitizeValue: sanitizeSingleSelectValue, - create: (options = {}) => { - const defaults = {}; - - // provide default values if valuesKey isn't set - if (!options.valuesKey) { - defaults.values = [{ - label: 'Value', - value: 'value' - }]; - } - return { - ...defaults, - ...options - }; - } + create: createEmptyOptions }; var _path$d; @@ -44932,21 +45344,7 @@ group: 'selection', emptyValue: null, sanitizeValue: sanitizeSingleSelectValue, - create: (options = {}) => { - const defaults = {}; - - // provide default values if valuesKey isn't set - if (!options.valuesKey) { - defaults.values = [{ - label: 'Value', - value: 'value' - }]; - } - return { - ...defaults, - ...options - }; - } + create: createEmptyOptions }; const type$4 = 'spacer'; @@ -45174,21 +45572,7 @@ group: 'selection', emptyValue: [], sanitizeValue: sanitizeMultiSelectValue, - create: (options = {}) => { - const defaults = {}; - - // provide default values if valuesKey isn't set - if (!options.valuesKey) { - defaults.values = [{ - label: 'Value', - value: 'value' - }]; - } - return { - ...defaults, - ...options - }; - } + create: createEmptyOptions }; const type$2 = 'text'; @@ -45467,7 +45851,7 @@ textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden'; }; - const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Datetime, Radio, Select, Spacer, Taglist, Text, Textfield, Textarea]; + const formFields = [Button, Checkbox, Checklist, FormComponent$1, Group, Image, Numberfield, Datetime, Radio, Select, Spacer, Taglist, Text, Textfield, Textarea]; class FormFields { constructor() { @@ -45543,9 +45927,12 @@ }; var core = { - __depends__: [importModule, renderModule], + __depends__: [renderModule], eventBus: ['type', EventBus], + importer: ['type', Importer], + fieldFactory: ['type', FieldFactory], formFieldRegistry: ['type', FormFieldRegistry], + pathRegistry: ['type', PathRegistry], formLayouter: ['type', FormLayouter], validator: ['type', Validator] }; @@ -45660,9 +46047,9 @@ this.clear(); const { schema: importedSchema, - data: initializedData, warnings - } = this.get('importer').importSchema(schema, data); + } = this.get('importer').importSchema(schema); + const initializedData = this._initializeFieldData(clone(data)); this._setState({ data: initializedData, errors: {}, @@ -45720,21 +46107,21 @@ */ validate() { const formFieldRegistry = this.get('formFieldRegistry'), + pathRegistry = this.get('pathRegistry'), validator = this.get('validator'); const { data } = this._getState(); const errors = formFieldRegistry.getAll().reduce((errors, field) => { const { - disabled, - _path + disabled } = field; if (disabled) { return errors; } - const value = get(data, _path); + const value = get(data, pathRegistry.getValuePath(field)); const fieldErrors = validator.validateField(field, value); - return set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined); + return set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined); }, /** @type {Errors} */{}); this._setState({ errors @@ -45840,16 +46227,14 @@ value } = update; const { - _path - } = field; - let { data, errors } = this._getState(); - const validator = this.get('validator'); + const validator = this.get('validator'), + pathRegistry = this.get('pathRegistry'); const fieldErrors = validator.validateField(field, value); - set(data, _path, value); - set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined); + set(data, pathRegistry.getValuePath(field), value); + set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined); this._setState({ data: clone(data), errors: clone(errors) @@ -45892,23 +46277,26 @@ * @internal */ _getSubmitData() { - const formFieldRegistry = this.get('formFieldRegistry'); + const formFieldRegistry = this.get('formFieldRegistry'), + pathRegistry = this.get('pathRegistry'), + formFields = this.get('formFields'); const formData = this._getState().data; const submitData = formFieldRegistry.getAll().reduce((previous, field) => { const { disabled, - _path + type } = field; + const { + config: fieldConfig + } = formFields.get(type); - // do not submit disabled form fields - if (disabled || !_path) { + // do not submit disabled form fields or routing fields + if (disabled || !fieldConfig.keyed) { return previous; } - const value = get(formData, _path); - return { - ...previous, - [_path[0]]: value - }; + const valuePath = pathRegistry.getValuePath(field); + const value = get(formData, valuePath); + return set(previous, valuePath, value); }, {}); const filteredSubmitData = this._applyConditions(submitData, formData); return filteredSubmitData; @@ -45921,20 +46309,57 @@ const conditionChecker = this.get('conditionChecker'); return conditionChecker.applyConditions(toFilter, data); } + + /** + * @internal + */ + _initializeFieldData(data) { + const formFieldRegistry = this.get('formFieldRegistry'), + formFields = this.get('formFields'), + pathRegistry = this.get('pathRegistry'); + return formFieldRegistry.getAll().reduce((initializedData, formField) => { + const { + defaultValue, + type + } = formField; + + // try to get value from data + // if unavailable - try to get default value from form field + // if unavailable - get empty value from form field + + const valuePath = pathRegistry.getValuePath(formField); + if (valuePath) { + const { + config: fieldConfig + } = formFields.get(type); + let valueData = get(data, valuePath); + if (!isUndefined$1(valueData) && fieldConfig.sanitizeValue) { + valueData = fieldConfig.sanitizeValue({ + formField, + data, + value: valueData + }); + } + const initializedFieldValue = !isUndefined$1(valueData) ? valueData : !isUndefined$1(defaultValue) ? defaultValue : fieldConfig.emptyValue; + return set(initializedData, valuePath, initializedFieldValue); + } + return initializedData; + }, data); + } } - const schemaVersion = 10; + const schemaVersion = 11; - /** - * @typedef { import('./types').CreateFormOptions } CreateFormOptions + /** + * @typedef { import('./types').CreateFormOptions } CreateFormOptions */ - /** - * Create a form. - * - * @param {CreateFormOptions} options - * - * @return {Promise
} + /** + * Create a form. + * + * @param {CreateFormOptions} options + * + * @return {Promise} */ function createForm(options) { const { @@ -45953,4 +46378,4 @@ exports.getSchemaVariables = getSchemaVariables; exports.schemaVersion = schemaVersion; -})); \ No newline at end of file +}));