From 69670e9ff607c14c210974be2d8f05206b4e76aa Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Fri, 27 Oct 2023 09:49:33 +0200 Subject: [PATCH] update --- .obsidian/app.json | 8 +- .obsidian/core-plugins-migration.json | 3 +- .../plugins/alx-folder-note-folderv/data.json | 2 +- .obsidian/plugins/dataview/main.js | 19847 +-- .obsidian/plugins/dataview/manifest.json | 2 +- .obsidian/plugins/dataview/styles.css | 2 +- .obsidian/plugins/homepage/main.js | 4 +- .obsidian/plugins/homepage/manifest.json | 2 +- .../plugins/obsidian-icon-folder/data.json | 2 +- .../plugins/obsidian-icon-folder/main.js | 500 +- .../obsidian-icon-folder/manifest.json | 2 +- .obsidian/plugins/obsidian-projects/data.json | 2 +- .obsidian/plugins/obsidian-projects/main.js | 2483 +- .../plugins/obsidian-projects/manifest.json | 4 +- .../plugins/obsidian-style-settings/main.js | 4118 +- .../obsidian-style-settings/manifest.json | 16 +- .obsidian/plugins/rpg-manager/main.js | 102077 ++++++++++++--- .obsidian/plugins/rpg-manager/manifest.json | 8 +- .obsidian/plugins/rpg-manager/styles.css | 4379 +- .obsidian/vault-stats.json | 2 +- Locations/Cité Franche.md | 2 +- Locations/Quartier du Vieux Port.md | 2 - Locations/Temple de Forgeron.md | 19 +- Notes/Idée en vrac.canvas | 2 +- Personnages/PNJ/Dieux/Tamerakh.md | 17 +- Quêtes.canvas | 70 +- Sans titre 1.canvas | 1 + Sans titre 2.canvas | 1 + Sans titre.canvas | 1 + Scénario/Scénario.md | 1 - 30 files changed, 101010 insertions(+), 32569 deletions(-) create mode 100644 Sans titre 1.canvas create mode 100644 Sans titre 2.canvas create mode 100644 Sans titre.canvas diff --git a/.obsidian/app.json b/.obsidian/app.json index 25267ad..9f429f8 100644 --- a/.obsidian/app.json +++ b/.obsidian/app.json @@ -39,10 +39,8 @@ ], "showFrontmatter": false, "showLineNumber": true, - "spellcheckLanguages": [ - "fr", - "fr-FR" - ], + "spellcheckLanguages": null, "defaultViewMode": "preview", - "showUnsupportedFiles": true + "showUnsupportedFiles": true, + "propertiesInDocument": "hidden" } \ No newline at end of file diff --git a/.obsidian/core-plugins-migration.json b/.obsidian/core-plugins-migration.json index b58affc..60e9b67 100644 --- a/.obsidian/core-plugins-migration.json +++ b/.obsidian/core-plugins-migration.json @@ -26,5 +26,6 @@ "publish": false, "sync": false, "canvas": true, - "bookmarks": true + "bookmarks": true, + "properties": false } \ No newline at end of file diff --git a/.obsidian/plugins/alx-folder-note-folderv/data.json b/.obsidian/plugins/alx-folder-note-folderv/data.json index 33e2e60..bac3af9 100644 --- a/.obsidian/plugins/alx-folder-note-folderv/data.json +++ b/.obsidian/plugins/alx-folder-note-folderv/data.json @@ -1,5 +1,5 @@ { - "h1AsTitleSource": true, + "h1AsTitleSource": false, "briefMax": 256, "titleField": "title", "descField": "description" diff --git a/.obsidian/plugins/dataview/main.js b/.obsidian/plugins/dataview/main.js index 82a0608..d4804b4 100644 --- a/.obsidian/plugins/dataview/main.js +++ b/.obsidian/plugins/dataview/main.js @@ -695,7 +695,7 @@ function intlConfigString(localeStr, numberingSystem, outputCalendar) { function mapMonths(f) { const ms = []; for (let i = 1; i <= 12; i++) { - const dt = DateTime.utc(2016, i, 1); + const dt = DateTime.utc(2009, i, 1); ms.push(f(dt)); } return ms; @@ -710,8 +710,8 @@ function mapWeekdays(f) { return ms; } -function listStuff(loc, length, defaultOK, englishFn, intlFn) { - const mode = loc.listingMode(defaultOK); +function listStuff(loc, length, englishFn, intlFn) { + const mode = loc.listingMode(); if (mode === "error") { return null; @@ -772,9 +772,13 @@ class PolyNumberFormatter { class PolyDateFormatter { constructor(dt, intl, opts) { this.opts = opts; + this.originalZone = undefined; let z = undefined; - if (dt.zone.isUniversal) { + if (this.opts.timeZone) { + // Don't apply any workarounds if a timeZone is explicitly provided in opts + this.dt = dt; + } else if (dt.zone.type === "fixed") { // UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like. // That is why fixed-offset TZ is set to that unless it is: // 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT. @@ -787,25 +791,23 @@ class PolyDateFormatter { z = offsetZ; this.dt = dt; } else { - // Not all fixed-offset zones like Etc/+4:30 are present in tzdata. - // So we have to make do. Two cases: - // 1. The format options tell us to show the zone. We can't do that, so the best - // we can do is format the date in UTC. - // 2. The format options don't tell us to show the zone. Then we can adjust them - // the time and tell the formatter to show it to us in UTC, so that the time is right - // and the bad zone doesn't show up. + // Not all fixed-offset zones like Etc/+4:30 are present in tzdata so + // we manually apply the offset and substitute the zone as needed. z = "UTC"; - if (opts.timeZoneName) { - this.dt = dt; - } else { - this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000); - } + this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset }); + this.originalZone = dt.zone; } } else if (dt.zone.type === "system") { this.dt = dt; - } else { + } else if (dt.zone.type === "iana") { this.dt = dt; z = dt.zone.name; + } else { + // Custom zones can have any offset / offsetName so we just manually + // apply the offset and substitute the zone as needed. + z = "UTC"; + this.dt = dt.setZone("UTC").plus({ minutes: dt.offset }); + this.originalZone = dt.zone; } const intlOpts = { ...this.opts }; @@ -814,11 +816,35 @@ class PolyDateFormatter { } format() { + if (this.originalZone) { + // If we have to substitute in the actual zone name, we have to use + // formatToParts so that the timezone can be replaced. + return this.formatToParts() + .map(({ value }) => value) + .join(""); + } return this.dtf.format(this.dt.toJSDate()); } formatToParts() { - return this.dtf.formatToParts(this.dt.toJSDate()); + const parts = this.dtf.formatToParts(this.dt.toJSDate()); + if (this.originalZone) { + return parts.map((part) => { + if (part.type === "timeZoneName") { + const offsetName = this.originalZone.offsetName(this.dt.ts, { + locale: this.dt.locale, + format: this.opts.timeZoneName, + }); + return { + ...part, + value: offsetName, + }; + } else { + return part; + } + }); + } + return parts; } resolvedOptions() { @@ -937,8 +963,8 @@ class Locale { return this.clone({ ...alts, defaultToEN: false }); } - months(length, format = false, defaultOK = true) { - return listStuff(this, length, defaultOK, months, () => { + months(length, format = false) { + return listStuff(this, length, months, () => { const intl = format ? { month: length, day: "numeric" } : { month: length }, formatStr = format ? "format" : "standalone"; if (!this.monthsCache[formatStr][length]) { @@ -948,8 +974,8 @@ class Locale { }); } - weekdays(length, format = false, defaultOK = true) { - return listStuff(this, length, defaultOK, weekdays, () => { + weekdays(length, format = false) { + return listStuff(this, length, weekdays, () => { const intl = format ? { weekday: length, year: "numeric", month: "long", day: "numeric" } : { weekday: length }, @@ -963,11 +989,10 @@ class Locale { }); } - meridiems(defaultOK = true) { + meridiems() { return listStuff( this, undefined, - defaultOK, () => meridiems, () => { // In theory there could be aribitrary day periods. We're gonna assume there are exactly two @@ -984,8 +1009,8 @@ class Locale { ); } - eras(length, defaultOK = true) { - return listStuff(this, length, defaultOK, eras, () => { + eras(length) { + return listStuff(this, length, eras, () => { const intl = { era: length }; // This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates @@ -1211,7 +1236,7 @@ function normalizeZone(input, defaultZone) { else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input); } else if (isNumber(input)) { return FixedOffsetZone.instance(input); - } else if (typeof input === "object" && input.offset && typeof input.offset === "number") { + } else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") { // This is dumb, but the instanceof check above doesn't seem to really work // so we're duck checking it return input; @@ -1328,10 +1353,10 @@ class Settings { /** * Set the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century. * @type {number} - * @example Settings.twoDigitCutoffYear = 0 // cut-off year is 0, so all 'yy' are interpretted as current century + * @example Settings.twoDigitCutoffYear = 0 // cut-off year is 0, so all 'yy' are interpreted as current century * @example Settings.twoDigitCutoffYear = 50 // '49' -> 1949; '50' -> 2050 - * @example Settings.twoDigitCutoffYear = 1950 // interpretted as 50 - * @example Settings.twoDigitCutoffYear = 2050 // ALSO interpretted as 50 + * @example Settings.twoDigitCutoffYear = 1950 // interpreted as 50 + * @example Settings.twoDigitCutoffYear = 2050 // ALSO interpreted as 50 */ static set twoDigitCutoffYear(cutoffYear) { twoDigitCutoffYear = cutoffYear % 100; @@ -1513,7 +1538,7 @@ function daysInMonth(year, month) { } } -// covert a calendar object to a local timestamp (epoch, but with the offset baked in) +// convert a calendar object to a local timestamp (epoch, but with the offset baked in) function objToLocalTS(obj) { let d = Date.UTC( obj.year, @@ -1528,7 +1553,10 @@ function objToLocalTS(obj) { // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that if (obj.year < 100 && obj.year >= 0) { d = new Date(d); - d.setUTCFullYear(d.getUTCFullYear() - 1900); + // set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not + // so if obj.year is in 99, but obj.day makes it roll over into year 100, + // the calculations done by Date.UTC are using year 2000 - which is incorrect + d.setUTCFullYear(obj.year, obj.month - 1, obj.day); } return +d; } @@ -1836,6 +1864,9 @@ class Formatter { } static parseFormat(fmt) { + // white-space is always considered a literal in user-provided formats + // the " " token has a special meaning (see unitForToken) + let current = null, currentFull = "", bracketed = false; @@ -1844,7 +1875,7 @@ class Formatter { const c = fmt.charAt(i); if (c === "'") { if (currentFull.length > 0) { - splits.push({ literal: bracketed, val: currentFull }); + splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull }); } current = null; currentFull = ""; @@ -1855,7 +1886,7 @@ class Formatter { currentFull += c; } else { if (currentFull.length > 0) { - splits.push({ literal: false, val: currentFull }); + splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull }); } currentFull = c; current = c; @@ -1863,7 +1894,7 @@ class Formatter { } if (currentFull.length > 0) { - splits.push({ literal: bracketed, val: currentFull }); + splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull }); } return splits; @@ -1887,24 +1918,25 @@ class Formatter { return df.format(); } - formatDateTime(dt, opts = {}) { - const df = this.loc.dtFormatter(dt, { ...this.opts, ...opts }); - return df.format(); + dtFormatter(dt, opts = {}) { + return this.loc.dtFormatter(dt, { ...this.opts, ...opts }); } - formatDateTimeParts(dt, opts = {}) { - const df = this.loc.dtFormatter(dt, { ...this.opts, ...opts }); - return df.formatToParts(); + formatDateTime(dt, opts) { + return this.dtFormatter(dt, opts).format(); } - formatInterval(interval, opts = {}) { - const df = this.loc.dtFormatter(interval.start, { ...this.opts, ...opts }); + formatDateTimeParts(dt, opts) { + return this.dtFormatter(dt, opts).formatToParts(); + } + + formatInterval(interval, opts) { + const df = this.dtFormatter(interval.start, opts); return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate()); } - resolvedOptions(dt, opts = {}) { - const df = this.loc.dtFormatter(dt, { ...this.opts, ...opts }); - return df.resolvedOptions(); + resolvedOptions(dt, opts) { + return this.dtFormatter(dt, opts).resolvedOptions(); } num(n, p = 0) { @@ -1959,7 +1991,7 @@ class Formatter { era = (length) => knownEnglish ? eraForDateTime(dt, length) : string({ era: length }, "era"), tokenToString = (token) => { - // Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles + // Where possible: https://cldr.unicode.org/translation/date-time/date-time-symbols switch (token) { // ms case "S": @@ -2636,28 +2668,61 @@ function clone$1(dur, alts, clear = false) { return new Duration(conf); } -function antiTrunc(n) { - return n < 0 ? Math.floor(n) : Math.ceil(n); -} - -// NB: mutates parameters -function convert(matrix, fromMap, fromUnit, toMap, toUnit) { - const conv = matrix[toUnit][fromUnit], - raw = fromMap[fromUnit] / conv, - sameSign = Math.sign(raw) === Math.sign(toMap[toUnit]), - // ok, so this is wild, but see the matrix in the tests - added = - !sameSign && toMap[toUnit] !== 0 && Math.abs(raw) <= 1 ? antiTrunc(raw) : Math.trunc(raw); - toMap[toUnit] += added; - fromMap[fromUnit] -= added * conv; +function durationToMillis(matrix, vals) { + let sum = vals.milliseconds ?? 0; + for (const unit of reverseUnits.slice(1)) { + if (vals[unit]) { + sum += vals[unit] * matrix[unit]["milliseconds"]; + } + } + return sum; } // NB: mutates parameters function normalizeValues(matrix, vals) { - reverseUnits.reduce((previous, current) => { + // the logic below assumes the overall value of the duration is positive + // if this is not the case, factor is used to make it so + const factor = durationToMillis(matrix, vals) < 0 ? -1 : 1; + + orderedUnits$1.reduceRight((previous, current) => { if (!isUndefined(vals[current])) { if (previous) { - convert(matrix, vals, previous, vals, current); + const previousVal = vals[previous] * factor; + const conv = matrix[current][previous]; + + // if (previousVal < 0): + // lower order unit is negative (e.g. { years: 2, days: -2 }) + // normalize this by reducing the higher order unit by the appropriate amount + // and increasing the lower order unit + // this can never make the higher order unit negative, because this function only operates + // on positive durations, so the amount of time represented by the lower order unit cannot + // be larger than the higher order unit + // else: + // lower order unit is positive (e.g. { years: 2, days: 450 } or { years: -2, days: 450 }) + // in this case we attempt to convert as much as possible from the lower order unit into + // the higher order one + // + // Math.floor takes care of both of these cases, rounding away from 0 + // if previousVal < 0 it makes the absolute value larger + // if previousVal >= it makes the absolute value smaller + const rollUp = Math.floor(previousVal / conv); + vals[current] += rollUp * factor; + vals[previous] -= rollUp * conv * factor; + } + return current; + } else { + return previous; + } + }, null); + + // try to convert any decimals into smaller units if possible + // for example for { years: 2.5, days: 0, seconds: 0 } we want to get { years: 2, days: 182, hours: 12 } + orderedUnits$1.reduce((previous, current) => { + if (!isUndefined(vals[current])) { + if (previous) { + const fraction = vals[previous] % 1; + vals[previous] -= fraction; + vals[current] += fraction * matrix[previous][current]; } return current; } else { @@ -2973,6 +3038,8 @@ class Duration { * ``` */ toHuman(opts = {}) { + if (!this.isValid) return INVALID$2; + const l = orderedUnits$1 .map((unit) => { const val = this.values[unit]; @@ -3059,26 +3126,11 @@ class Duration { includePrefix: false, format: "extended", ...opts, + includeOffset: false, }; - const value = this.shiftTo("hours", "minutes", "seconds", "milliseconds"); - - let fmt = opts.format === "basic" ? "hhmm" : "hh:mm"; - - if (!opts.suppressSeconds || value.seconds !== 0 || value.milliseconds !== 0) { - fmt += opts.format === "basic" ? "ss" : ":ss"; - if (!opts.suppressMilliseconds || value.milliseconds !== 0) { - fmt += ".SSS"; - } - } - - let str = value.toFormat(fmt); - - if (opts.includePrefix) { - str = "T" + str; - } - - return str; + const dateTime = DateTime.fromMillis(millis, { zone: "UTC" }); + return dateTime.toISOTime(opts); } /** @@ -3102,7 +3154,9 @@ class Duration { * @return {number} */ toMillis() { - return this.as("milliseconds"); + if (!this.isValid) return NaN; + + return durationToMillis(this.matrix, this.values); } /** @@ -3212,8 +3266,17 @@ class Duration { /** * Reduce this Duration to its canonical representation in its current units. + * Assuming the overall value of the Duration is positive, this means: + * - excessive values for lower-order units are converted to higher-order units (if possible, see first and second example) + * - negative lower-order units are converted to higher order units (there must be such a higher order unit, otherwise + * the overall value would be negative, see second example) + * - fractional values for higher-order units are converted to lower-order units (if possible, see fourth example) + * + * If the overall value is negative, the result of this method is equivalent to `this.negate().normalize().negate()`. * @example Duration.fromObject({ years: 2, days: 5000 }).normalize().toObject() //=> { years: 15, days: 255 } + * @example Duration.fromObject({ days: 5000 }).normalize().toObject() //=> { days: 5000 } * @example Duration.fromObject({ hours: 12, minutes: -45 }).normalize().toObject() //=> { hours: 11, minutes: 15 } + * @example Duration.fromObject({ years: 2.5, days: 0, hours: 0 }).normalize().toObject() //=> { years: 2, days: 182, hours: 12 } * @return {Duration} */ normalize() { @@ -3270,16 +3333,12 @@ class Duration { own += vals[k]; } + // only keep the integer part for now in the hopes of putting any decimal part + // into a smaller unit later const i = Math.trunc(own); built[k] = i; accumulated[k] = (own * 1000 - i * 1000) / 1000; - // plus anything further down the chain that should be rolled up in to this - for (const down in vals) { - if (orderedUnits$1.indexOf(down) > orderedUnits$1.indexOf(k)) { - convert(this.matrix, vals, down, built, k); - } - } // otherwise, keep it in the wings to boil it later } else if (isNumber(vals[k])) { accumulated[k] = vals[k]; @@ -3295,7 +3354,8 @@ class Duration { } } - return clone$1(this, { values: built }, true).normalize(); + normalizeValues(this.matrix, built); + return clone$1(this, { values: built }, true); } /** @@ -3692,7 +3752,7 @@ class Interval { if (!this.isValid) return NaN; const start = this.start.startOf(unit), end = this.end.startOf(unit); - return Math.floor(end.diff(start, unit).get(unit)) + 1; + return Math.floor(end.diff(start, unit).get(unit)) + (end.valueOf() !== this.end.valueOf()); } /** @@ -4275,6 +4335,14 @@ function highOrderDiffs(cursor, later, units) { const earlier = cursor; let lowestOrder, highWater; + /* This loop tries to diff using larger units first. + If we overshoot, we backtrack and try the next smaller unit. + "cursor" starts out at the earlier timestamp and moves closer and closer to "later" + as we use smaller and smaller units. + highWater keeps track of where we would be if we added one more of the smallest unit, + this is used later to potentially convert any difference smaller than the smallest higher order unit + into a fraction of that smallest higher order unit + */ for (const [unit, differ] of differs) { if (units.indexOf(unit) >= 0) { lowestOrder = unit; @@ -4283,8 +4351,20 @@ function highOrderDiffs(cursor, later, units) { highWater = earlier.plus(results); if (highWater > later) { + // we overshot the end point, backtrack cursor by 1 results[unit]--; cursor = earlier.plus(results); + + // if we are still overshooting now, we need to backtrack again + // this happens in certain situations when diffing times in different zones, + // because this calculation ignores time zones + if (cursor > later) { + // keep the "overshot by 1" around as highWater + highWater = cursor; + // backtrack cursor by 1 + results[unit]--; + cursor = earlier.plus(results); + } } else { cursor = highWater; } @@ -4447,6 +4527,10 @@ function escapeToken(value) { return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); } +/** + * @param token + * @param {Locale} loc + */ function unitForToken(token, loc) { const one = digitRegex(loc), two = digitRegex(loc, "{2}"), @@ -4467,9 +4551,9 @@ function unitForToken(token, loc) { switch (t.val) { // era case "G": - return oneOf(loc.eras("short", false), 0); + return oneOf(loc.eras("short"), 0); case "GG": - return oneOf(loc.eras("long", false), 0); + return oneOf(loc.eras("long"), 0); // years case "y": return intUnit(oneToSix); @@ -4487,17 +4571,17 @@ function unitForToken(token, loc) { case "MM": return intUnit(two); case "MMM": - return oneOf(loc.months("short", true, false), 1); + return oneOf(loc.months("short", true), 1); case "MMMM": - return oneOf(loc.months("long", true, false), 1); + return oneOf(loc.months("long", true), 1); case "L": return intUnit(oneOrTwo); case "LL": return intUnit(two); case "LLL": - return oneOf(loc.months("short", false, false), 1); + return oneOf(loc.months("short", false), 1); case "LLLL": - return oneOf(loc.months("long", false, false), 1); + return oneOf(loc.months("long", false), 1); // dates case "d": return intUnit(oneOrTwo); @@ -4557,13 +4641,13 @@ function unitForToken(token, loc) { case "c": return intUnit(one); case "EEE": - return oneOf(loc.weekdays("short", false, false), 1); + return oneOf(loc.weekdays("short", false), 1); case "EEEE": - return oneOf(loc.weekdays("long", false, false), 1); + return oneOf(loc.weekdays("long", false), 1); case "ccc": - return oneOf(loc.weekdays("short", true, false), 1); + return oneOf(loc.weekdays("short", true), 1); case "cccc": - return oneOf(loc.weekdays("long", true, false), 1); + return oneOf(loc.weekdays("long", true), 1); // offset/zone case "Z": case "ZZ": @@ -4574,6 +4658,10 @@ function unitForToken(token, loc) { // because we don't have any way to figure out what they are case "z": return simple(/[a-z_+-/]{1,256}?/i); + // this special-case "token" represents a place where a macro-token expanded into a white-space literal + // in this case we accept any non-newline white-space + case " ": + return simple(/[^\S\n\r]/); default: return literal(t); } @@ -4609,10 +4697,14 @@ const partTypeStyleToTokenVal = { }, dayperiod: "a", dayPeriod: "a", - hour: { + hour12: { numeric: "h", "2-digit": "hh", }, + hour24: { + numeric: "H", + "2-digit": "HH", + }, minute: { numeric: "m", "2-digit": "mm", @@ -4627,19 +4719,39 @@ const partTypeStyleToTokenVal = { }, }; -function tokenForPart(part, formatOpts) { +function tokenForPart(part, formatOpts, resolvedOpts) { const { type, value } = part; if (type === "literal") { + const isSpace = /^\s+$/.test(value); return { - literal: true, - val: value, + literal: !isSpace, + val: isSpace ? " " : value, }; } const style = formatOpts[type]; - let val = partTypeStyleToTokenVal[type]; + // The user might have explicitly specified hour12 or hourCycle + // if so, respect their decision + // if not, refer back to the resolvedOpts, which are based on the locale + let actualType = type; + if (type === "hour") { + if (formatOpts.hour12 != null) { + actualType = formatOpts.hour12 ? "hour12" : "hour24"; + } else if (formatOpts.hourCycle != null) { + if (formatOpts.hourCycle === "h11" || formatOpts.hourCycle === "h12") { + actualType = "hour12"; + } else { + actualType = "hour24"; + } + } else { + // tokens only differentiate between 24 hours or not, + // so we do not need to check hourCycle here, which is less supported anyways + actualType = resolvedOpts.hour12 ? "hour12" : "hour24"; + } + } + let val = partTypeStyleToTokenVal[actualType]; if (typeof val === "object") { val = val[style]; } @@ -4828,8 +4940,10 @@ function formatOptsToTokens(formatOpts, locale) { } const formatter = Formatter.create(locale, formatOpts); - const parts = formatter.formatDateTimeParts(getDummyDateTime()); - return parts.map((p) => tokenForPart(p, formatOpts)); + const df = formatter.dtFormatter(getDummyDateTime()); + const parts = df.formatToParts(); + const resolvedOpts = df.resolvedOptions(); + return parts.map((p) => tokenForPart(p, formatOpts, resolvedOpts)); } const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], @@ -5103,7 +5217,7 @@ function adjustTime(inst, dur) { // by handling the zone options function parseDataToDateTime(parsed, parsedZone, opts, format, text, specificOffset) { const { setZone, zone } = opts; - if (parsed && Object.keys(parsed).length !== 0) { + if ((parsed && Object.keys(parsed).length !== 0) || parsedZone) { const interpretationZone = parsedZone || zone, inst = DateTime.fromObject(parsed, { ...opts, @@ -5159,14 +5273,14 @@ function toISOTime( if (extended) { c += ":"; c += padStart(o.c.minute); - if (o.c.second !== 0 || !suppressSeconds) { + if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) { c += ":"; } } else { c += padStart(o.c.minute); } - if (o.c.second !== 0 || !suppressSeconds) { + if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) { c += padStart(o.c.second); if (o.c.millisecond !== 0 || !suppressMilliseconds) { @@ -5829,7 +5943,7 @@ class DateTime { /** * Create an invalid DateTime. - * @param {DateTime} reason - simple string of why this DateTime is invalid. Should not contain parameters or anything else data-dependent + * @param {string} reason - simple string of why this DateTime is invalid. Should not contain parameters or anything else data-dependent. * @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information * @return {DateTime} */ @@ -6178,6 +6292,43 @@ class DateTime { } } + /** + * Get those DateTimes which have the same local time as this DateTime, but a different offset from UTC + * in this DateTime's zone. During DST changes local time can be ambiguous, for example + * `2023-10-29T02:30:00` in `Europe/Berlin` can have offset `+01:00` or `+02:00`. + * This method will return both possible DateTimes if this DateTime's local time is ambiguous. + * @returns {DateTime[]} + */ + getPossibleOffsets() { + if (!this.isValid || this.isOffsetFixed) { + return [this]; + } + const dayMs = 86400000; + const minuteMs = 60000; + const localTS = objToLocalTS(this.c); + const oEarlier = this.zone.offset(localTS - dayMs); + const oLater = this.zone.offset(localTS + dayMs); + + const o1 = this.zone.offset(localTS - oEarlier * minuteMs); + const o2 = this.zone.offset(localTS - oLater * minuteMs); + if (o1 === o2) { + return [this]; + } + const ts1 = localTS - o1 * minuteMs; + const ts2 = localTS - o2 * minuteMs; + const c1 = tsToObj(ts1, o1); + const c2 = tsToObj(ts2, o2); + if ( + c1.hour === c2.hour && + c1.minute === c2.minute && + c1.second === c2.second && + c1.millisecond === c2.millisecond + ) { + return [clone(this, { ts: ts1 }), clone(this, { ts: ts2 })]; + } + return [this]; + } + /** * Returns true if this DateTime is in a leap year, false otherwise * @example DateTime.local(2016).isInLeapYear //=> true @@ -7180,7 +7331,7 @@ function friendlyDateTime(dateTimeish) { } } -const VERSION = "3.2.1"; +const VERSION = "3.4.3"; var Luxon = /*#__PURE__*/Object.freeze({ __proto__: null, @@ -7197,2292 +7348,2303 @@ var Luxon = /*#__PURE__*/Object.freeze({ Settings: Settings }); -//////////////////// -// Query Settings // -//////////////////// -const DEFAULT_QUERY_SETTINGS = { - renderNullAs: "\\-", - taskCompletionTracking: false, - taskCompletionUseEmojiShorthand: false, - taskCompletionText: "completion", - taskCompletionDateFormat: "yyyy-MM-dd", - recursiveSubTaskCompletion: false, - warnOnEmptyResult: true, - refreshEnabled: true, - refreshInterval: 2500, - defaultDateFormat: "MMMM dd, yyyy", - defaultDateTimeFormat: "h:mm a - MMMM dd, yyyy", - maxRecursiveRenderDepth: 4, - tableIdColumnName: "File", - tableGroupColumnName: "Group", - showResultCount: true, -}; -const DEFAULT_EXPORT_SETTINGS = { - allowHtml: true, -}; -/** Default settings for dataview on install. */ -const DEFAULT_SETTINGS = { - ...DEFAULT_QUERY_SETTINGS, - ...DEFAULT_EXPORT_SETTINGS, - ...{ - inlineQueryPrefix: "=", - inlineJsQueryPrefix: "$=", - inlineQueriesInCodeblocks: true, - enableInlineDataview: true, - enableDataviewJs: false, - enableInlineDataviewJs: false, - prettyRenderInlineFields: true, - dataviewJsKeyword: "dataviewjs", - }, +//////////////////// +// Query Settings // +//////////////////// +const DEFAULT_QUERY_SETTINGS = { + renderNullAs: "\\-", + taskCompletionTracking: false, + taskCompletionUseEmojiShorthand: false, + taskCompletionText: "completion", + taskCompletionDateFormat: "yyyy-MM-dd", + recursiveSubTaskCompletion: false, + warnOnEmptyResult: true, + refreshEnabled: true, + refreshInterval: 2500, + defaultDateFormat: "MMMM dd, yyyy", + defaultDateTimeFormat: "h:mm a - MMMM dd, yyyy", + maxRecursiveRenderDepth: 4, + tableIdColumnName: "File", + tableGroupColumnName: "Group", + showResultCount: true, +}; +const DEFAULT_EXPORT_SETTINGS = { + allowHtml: true, +}; +/** Default settings for dataview on install. */ +const DEFAULT_SETTINGS = { + ...DEFAULT_QUERY_SETTINGS, + ...DEFAULT_EXPORT_SETTINGS, + ...{ + inlineQueryPrefix: "=", + inlineJsQueryPrefix: "$=", + inlineQueriesInCodeblocks: true, + enableInlineDataview: true, + enableDataviewJs: false, + enableInlineDataviewJs: false, + prettyRenderInlineFields: true, + dataviewJsKeyword: "dataviewjs", + }, }; -/** Functional return type for error handling. */ -class Success { - constructor(value) { - this.value = value; - this.successful = true; - } - map(f) { - return new Success(f(this.value)); - } - flatMap(f) { - return f(this.value); - } - mapErr(f) { - return this; - } - bimap(succ, _fail) { - return this.map(succ); - } - orElse(_value) { - return this.value; - } - cast() { - return this; - } - orElseThrow(_message) { - return this.value; - } -} -/** Functional return type for error handling. */ -class Failure { - constructor(error) { - this.error = error; - this.successful = false; - } - map(_f) { - return this; - } - flatMap(_f) { - return this; - } - mapErr(f) { - return new Failure(f(this.error)); - } - bimap(_succ, fail) { - return this.mapErr(fail); - } - orElse(value) { - return value; - } - cast() { - return this; - } - orElseThrow(message) { - if (message) - throw new Error(message(this.error)); - else - throw new Error("" + this.error); - } -} -/** Monadic 'Result' type which encapsulates whether a procedure succeeded or failed, as well as it's return value. */ -var Result; -(function (Result) { - /** Construct a new success result wrapping the given value. */ - function success(value) { - return new Success(value); - } - Result.success = success; - /** Construct a new failure value wrapping the given error. */ - function failure(error) { - return new Failure(error); - } - Result.failure = failure; - /** Join two results with a bi-function and return a new result. */ - function flatMap2(first, second, f) { - if (first.successful) { - if (second.successful) - return f(first.value, second.value); - else - return failure(second.error); - } - else { - return failure(first.error); - } - } - Result.flatMap2 = flatMap2; - /** Join two results with a bi-function and return a new result. */ - function map2(first, second, f) { - return flatMap2(first, second, (a, b) => success(f(a, b))); - } - Result.map2 = map2; +/** Functional return type for error handling. */ +class Success { + constructor(value) { + this.value = value; + this.successful = true; + } + map(f) { + return new Success(f(this.value)); + } + flatMap(f) { + return f(this.value); + } + mapErr(f) { + return this; + } + bimap(succ, _fail) { + return this.map(succ); + } + orElse(_value) { + return this.value; + } + cast() { + return this; + } + orElseThrow(_message) { + return this.value; + } +} +/** Functional return type for error handling. */ +class Failure { + constructor(error) { + this.error = error; + this.successful = false; + } + map(_f) { + return this; + } + flatMap(_f) { + return this; + } + mapErr(f) { + return new Failure(f(this.error)); + } + bimap(_succ, fail) { + return this.mapErr(fail); + } + orElse(value) { + return value; + } + cast() { + return this; + } + orElseThrow(message) { + if (message) + throw new Error(message(this.error)); + else + throw new Error("" + this.error); + } +} +/** Monadic 'Result' type which encapsulates whether a procedure succeeded or failed, as well as it's return value. */ +var Result; +(function (Result) { + /** Construct a new success result wrapping the given value. */ + function success(value) { + return new Success(value); + } + Result.success = success; + /** Construct a new failure value wrapping the given error. */ + function failure(error) { + return new Failure(error); + } + Result.failure = failure; + /** Join two results with a bi-function and return a new result. */ + function flatMap2(first, second, f) { + if (first.successful) { + if (second.successful) + return f(first.value, second.value); + else + return failure(second.error); + } + else { + return failure(first.error); + } + } + Result.flatMap2 = flatMap2; + /** Join two results with a bi-function and return a new result. */ + function map2(first, second, f) { + return flatMap2(first, second, (a, b) => success(f(a, b))); + } + Result.map2 = map2; })(Result || (Result = {})); var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; -function commonjsRequire (path) { - throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var parsimmon_umd_min = {exports: {}}; +parsimmon_umd_min.exports; + (function (module, exports) { -!function(n,t){module.exports=t();}("undefined"!=typeof self?self:commonjsGlobal,function(){return function(n){var t={};function r(e){if(t[e])return t[e].exports;var u=t[e]={i:e,l:!1,exports:{}};return n[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}return r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e});},r.r=function(n){Object.defineProperty(n,"__esModule",{value:!0});},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=0)}([function(n,t,r){function e(n){if(!(this instanceof e))return new e(n);this._=n;}var u=e.prototype;function o(n,t){for(var r=0;r>7),buf:function(n){var t=i(function(n,t,r,e){return n.concat(r===e.length-1?Buffer.from([t,0]).readUInt16BE(0):e.readUInt16BE(r))},[],n);return Buffer.from(a(function(n){return (n<<1&65535)>>8},t))}(r.buf)};}),r}function c(){return "undefined"!=typeof Buffer}function s(){if(!c())throw new Error("Buffer global does not exist; please use webpack if you need to parse Buffers in the browser.")}function l(n){s();var t=i(function(n,t){return n+t},0,n);if(t%8!=0)throw new Error("The bits ["+n.join(", ")+"] add up to "+t+" which is not an even number of bytes; the total should be divisible by 8");var r,u=t/8,o=(r=function(n){return n>48},i(function(n,t){return n||(r(t)?t:n)},null,n));if(o)throw new Error(o+" bit range requested exceeds 48 bit (6 byte) Number max.");return new e(function(t,r){var e=u+r;return e>t.length?x(r,u.toString()+" bytes"):b(e,i(function(n,t){var r=f(t,n.buf);return {coll:n.coll.concat(r.v),buf:r.buf}},{coll:[],buf:t.slice(r,e)},n).coll)})}function h(n,t){return new e(function(r,e){return s(),e+t>r.length?x(e,t+" bytes for "+n):b(e+t,r.slice(e,e+t))})}function p(n,t){if("number"!=typeof(r=t)||Math.floor(r)!==r||t<0||t>6)throw new Error(n+" requires integer length in range [0, 6].");var r;}function d(n){return p("uintBE",n),h("uintBE("+n+")",n).map(function(t){return t.readUIntBE(0,n)})}function v(n){return p("uintLE",n),h("uintLE("+n+")",n).map(function(t){return t.readUIntLE(0,n)})}function g(n){return p("intBE",n),h("intBE("+n+")",n).map(function(t){return t.readIntBE(0,n)})}function m(n){return p("intLE",n),h("intLE("+n+")",n).map(function(t){return t.readIntLE(0,n)})}function y(n){return n instanceof e}function E(n){return "[object Array]"==={}.toString.call(n)}function w(n){return c()&&Buffer.isBuffer(n)}function b(n,t){return {status:!0,index:n,value:t,furthest:-1,expected:[]}}function x(n,t){return E(t)||(t=[t]),{status:!1,index:-1,value:null,furthest:n,expected:t}}function B(n,t){if(!t)return n;if(n.furthest>t.furthest)return n;var r=n.furthest===t.furthest?function(n,t){if(function(){if(void 0!==e._supportsSet)return e._supportsSet;var n="undefined"!=typeof Set;return e._supportsSet=n,n}()&&Array.from){for(var r=new Set(n),u=0;u=0;){if(i in r){e=r[i].line,0===o&&(o=r[i].lineStart);break}("\n"===n.charAt(i)||"\r"===n.charAt(i)&&"\n"!==n.charAt(i+1))&&(u++,0===o&&(o=i+1)),i--;}var a=e+u,f=t-o;return r[t]={line:a,lineStart:o},{offset:t,line:a+1,column:f+1}}function _(n){if(!y(n))throw new Error("not a parser: "+n)}function L(n,t){return "string"==typeof n?n.charAt(t):n[t]}function O(n){if("number"!=typeof n)throw new Error("not a number: "+n)}function k(n){if("function"!=typeof n)throw new Error("not a function: "+n)}function P(n){if("string"!=typeof n)throw new Error("not a string: "+n)}var q=2,A=3,I=8,F=5*I,M=4*I,z=" ";function R(n,t){return new Array(t+1).join(n)}function U(n,t,r){var e=t-n.length;return e<=0?n:R(r,e)+n}function W(n,t,r,e){return {from:n-t>0?n-t:0,to:n+r>e?e:n+r}}function D(n,t){var r,e,u,o,f,c=t.index,s=c.offset,l=1;if(s===n.length)return "Got the end of the input";if(w(n)){var h=s-s%I,p=s-h,d=W(h,F,M+I,n.length),v=a(function(n){return a(function(n){return U(n.toString(16),2,"0")},n)},function(n,t){var r=n.length,e=[],u=0;if(r<=t)return [n.slice()];for(var o=0;o=4&&(r+=1),l=2,u=a(function(n){return n.length<=4?n.join(" "):n.slice(0,4).join(" ")+" "+n.slice(4).join(" ")},v),(f=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(f=2);}else {var g=n.split(/\r\n|[\n\r\u2028\u2029]/);r=c.column-1,e=c.line-1,o=W(e,q,A,g.length),u=g.slice(o.from,o.to),f=o.to.toString().length;}var m=e-o.from;return w(n)&&(f=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(f=2),i(function(t,e,u){var i,a=u===m,c=a?"> ":z;return i=w(n)?U((8*(o.from+u)).toString(16),f,"0"):U((o.from+u+1).toString(),f," "),[].concat(t,[c+i+" | "+e],a?[z+R(" ",f)+" | "+U("",r," ")+R("^",l)]:[])},[],u).join("\n")}function N(n,t){return ["\n","-- PARSING FAILED "+R("-",50),"\n\n",D(n,t),"\n\n",(r=t.expected,1===r.length?"Expected:\n\n"+r[0]:"Expected one of the following: \n\n"+r.join(", ")),"\n"].join("");var r;}function G(n){return void 0!==n.flags?n.flags:[n.global?"g":"",n.ignoreCase?"i":"",n.multiline?"m":"",n.unicode?"u":"",n.sticky?"y":""].join("")}function C(){for(var n=[].slice.call(arguments),t=n.length,r=0;r=2?O(t):t=0;var r=function(n){return RegExp("^(?:"+n.source+")",G(n))}(n),u=""+n;return e(function(n,e){var o=r.exec(n.slice(e));if(o){if(0<=t&&t<=o.length){var i=o[0],a=o[t];return b(e+i.length,a)}return x(e,"valid match group (0 to "+o.length+") in "+u)}return x(e,u)})}function X(n){return e(function(t,r){return b(r,n)})}function Y(n){return e(function(t,r){return x(r,n)})}function Z(n){if(y(n))return e(function(t,r){var e=n._(t,r);return e.index=r,e.value="",e});if("string"==typeof n)return Z(K(n));if(n instanceof RegExp)return Z(Q(n));throw new Error("not a string, regexp, or parser: "+n)}function $(n){return _(n),e(function(t,r){var e=n._(t,r),u=t.slice(r,e.index);return e.status?x(r,'not "'+u+'"'):b(r,null)})}function nn(n){return k(n),e(function(t,r){var e=L(t,r);return r=n.length?x(t,"any character/byte"):b(t+1,L(n,t))}),on=e(function(n,t){return b(n.length,n.slice(t))}),an=e(function(n,t){return t=0}).desc(t)},e.optWhitespace=hn,e.Parser=e,e.range=function(n,t){return nn(function(r){return n<=r&&r<=t}).desc(n+"-"+t)},e.regex=Q,e.regexp=Q,e.sepBy=V,e.sepBy1=H,e.seq=C,e.seqMap=J,e.seqObj=function(){for(var n,t={},r=0,u=(n=arguments,Array.prototype.slice.call(n)),o=u.length,i=0;i255)throw new Error("Value specified to byte constructor ("+n+"=0x"+n.toString(16)+") is larger in value than a single byte.");var t=(n>15?"0x":"0x0")+n.toString(16);return e(function(r,e){var u=L(r,e);return u===n?b(e+1,u):x(e,t)})},buffer:function(n){return h("buffer",n).map(function(n){return Buffer.from(n)})},encodedString:function(n,t){return h("string",t).map(function(t){return t.toString(n)})},uintBE:d,uint8BE:d(1),uint16BE:d(2),uint32BE:d(4),uintLE:v,uint8LE:v(1),uint16LE:v(2),uint32LE:v(4),intBE:g,int8BE:g(1),int16BE:g(2),int32BE:g(4),intLE:m,int8LE:m(1),int16LE:m(2),int32LE:m(4),floatBE:h("floatBE",4).map(function(n){return n.readFloatBE(0)}),floatLE:h("floatLE",4).map(function(n){return n.readFloatLE(0)}),doubleBE:h("doubleBE",8).map(function(n){return n.readDoubleBE(0)}),doubleLE:h("doubleLE",8).map(function(n){return n.readDoubleLE(0)})},n.exports=e;}])}); -}(parsimmon_umd_min)); + !function(n,t){module.exports=t();}("undefined"!=typeof self?self:commonjsGlobal,function(){return function(n){var t={};function r(e){if(t[e])return t[e].exports;var u=t[e]={i:e,l:!1,exports:{}};return n[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}return r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e});},r.r=function(n){Object.defineProperty(n,"__esModule",{value:!0});},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=0)}([function(n,t,r){function e(n){if(!(this instanceof e))return new e(n);this._=n;}var u=e.prototype;function o(n,t){for(var r=0;r>7),buf:function(n){var t=i(function(n,t,r,e){return n.concat(r===e.length-1?Buffer.from([t,0]).readUInt16BE(0):e.readUInt16BE(r))},[],n);return Buffer.from(a(function(n){return (n<<1&65535)>>8},t))}(r.buf)};}),r}function c(){return "undefined"!=typeof Buffer}function s(){if(!c())throw new Error("Buffer global does not exist; please use webpack if you need to parse Buffers in the browser.")}function l(n){s();var t=i(function(n,t){return n+t},0,n);if(t%8!=0)throw new Error("The bits ["+n.join(", ")+"] add up to "+t+" which is not an even number of bytes; the total should be divisible by 8");var r,u=t/8,o=(r=function(n){return n>48},i(function(n,t){return n||(r(t)?t:n)},null,n));if(o)throw new Error(o+" bit range requested exceeds 48 bit (6 byte) Number max.");return new e(function(t,r){var e=u+r;return e>t.length?x(r,u.toString()+" bytes"):b(e,i(function(n,t){var r=f(t,n.buf);return {coll:n.coll.concat(r.v),buf:r.buf}},{coll:[],buf:t.slice(r,e)},n).coll)})}function h(n,t){return new e(function(r,e){return s(),e+t>r.length?x(e,t+" bytes for "+n):b(e+t,r.slice(e,e+t))})}function p(n,t){if("number"!=typeof(r=t)||Math.floor(r)!==r||t<0||t>6)throw new Error(n+" requires integer length in range [0, 6].");var r;}function d(n){return p("uintBE",n),h("uintBE("+n+")",n).map(function(t){return t.readUIntBE(0,n)})}function v(n){return p("uintLE",n),h("uintLE("+n+")",n).map(function(t){return t.readUIntLE(0,n)})}function g(n){return p("intBE",n),h("intBE("+n+")",n).map(function(t){return t.readIntBE(0,n)})}function m(n){return p("intLE",n),h("intLE("+n+")",n).map(function(t){return t.readIntLE(0,n)})}function y(n){return n instanceof e}function E(n){return "[object Array]"==={}.toString.call(n)}function w(n){return c()&&Buffer.isBuffer(n)}function b(n,t){return {status:!0,index:n,value:t,furthest:-1,expected:[]}}function x(n,t){return E(t)||(t=[t]),{status:!1,index:-1,value:null,furthest:n,expected:t}}function B(n,t){if(!t)return n;if(n.furthest>t.furthest)return n;var r=n.furthest===t.furthest?function(n,t){if(function(){if(void 0!==e._supportsSet)return e._supportsSet;var n="undefined"!=typeof Set;return e._supportsSet=n,n}()&&Array.from){for(var r=new Set(n),u=0;u=0;){if(i in r){e=r[i].line,0===o&&(o=r[i].lineStart);break}("\n"===n.charAt(i)||"\r"===n.charAt(i)&&"\n"!==n.charAt(i+1))&&(u++,0===o&&(o=i+1)),i--;}var a=e+u,f=t-o;return r[t]={line:a,lineStart:o},{offset:t,line:a+1,column:f+1}}function _(n){if(!y(n))throw new Error("not a parser: "+n)}function L(n,t){return "string"==typeof n?n.charAt(t):n[t]}function O(n){if("number"!=typeof n)throw new Error("not a number: "+n)}function k(n){if("function"!=typeof n)throw new Error("not a function: "+n)}function P(n){if("string"!=typeof n)throw new Error("not a string: "+n)}var q=2,A=3,I=8,F=5*I,M=4*I,z=" ";function R(n,t){return new Array(t+1).join(n)}function U(n,t,r){var e=t-n.length;return e<=0?n:R(r,e)+n}function W(n,t,r,e){return {from:n-t>0?n-t:0,to:n+r>e?e:n+r}}function D(n,t){var r,e,u,o,f,c=t.index,s=c.offset,l=1;if(s===n.length)return "Got the end of the input";if(w(n)){var h=s-s%I,p=s-h,d=W(h,F,M+I,n.length),v=a(function(n){return a(function(n){return U(n.toString(16),2,"0")},n)},function(n,t){var r=n.length,e=[],u=0;if(r<=t)return [n.slice()];for(var o=0;o=4&&(r+=1),l=2,u=a(function(n){return n.length<=4?n.join(" "):n.slice(0,4).join(" ")+" "+n.slice(4).join(" ")},v),(f=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(f=2);}else {var g=n.split(/\r\n|[\n\r\u2028\u2029]/);r=c.column-1,e=c.line-1,o=W(e,q,A,g.length),u=g.slice(o.from,o.to),f=o.to.toString().length;}var m=e-o.from;return w(n)&&(f=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(f=2),i(function(t,e,u){var i,a=u===m,c=a?"> ":z;return i=w(n)?U((8*(o.from+u)).toString(16),f,"0"):U((o.from+u+1).toString(),f," "),[].concat(t,[c+i+" | "+e],a?[z+R(" ",f)+" | "+U("",r," ")+R("^",l)]:[])},[],u).join("\n")}function N(n,t){return ["\n","-- PARSING FAILED "+R("-",50),"\n\n",D(n,t),"\n\n",(r=t.expected,1===r.length?"Expected:\n\n"+r[0]:"Expected one of the following: \n\n"+r.join(", ")),"\n"].join("");var r;}function G(n){return void 0!==n.flags?n.flags:[n.global?"g":"",n.ignoreCase?"i":"",n.multiline?"m":"",n.unicode?"u":"",n.sticky?"y":""].join("")}function C(){for(var n=[].slice.call(arguments),t=n.length,r=0;r=2?O(t):t=0;var r=function(n){return RegExp("^(?:"+n.source+")",G(n))}(n),u=""+n;return e(function(n,e){var o=r.exec(n.slice(e));if(o){if(0<=t&&t<=o.length){var i=o[0],a=o[t];return b(e+i.length,a)}return x(e,"valid match group (0 to "+o.length+") in "+u)}return x(e,u)})}function X(n){return e(function(t,r){return b(r,n)})}function Y(n){return e(function(t,r){return x(r,n)})}function Z(n){if(y(n))return e(function(t,r){var e=n._(t,r);return e.index=r,e.value="",e});if("string"==typeof n)return Z(K(n));if(n instanceof RegExp)return Z(Q(n));throw new Error("not a string, regexp, or parser: "+n)}function $(n){return _(n),e(function(t,r){var e=n._(t,r),u=t.slice(r,e.index);return e.status?x(r,'not "'+u+'"'):b(r,null)})}function nn(n){return k(n),e(function(t,r){var e=L(t,r);return r=n.length?x(t,"any character/byte"):b(t+1,L(n,t))}),on=e(function(n,t){return b(n.length,n.slice(t))}),an=e(function(n,t){return t=0}).desc(t)},e.optWhitespace=hn,e.Parser=e,e.range=function(n,t){return nn(function(r){return n<=r&&r<=t}).desc(n+"-"+t)},e.regex=Q,e.regexp=Q,e.sepBy=V,e.sepBy1=H,e.seq=C,e.seqMap=J,e.seqObj=function(){for(var n,t={},r=0,u=(n=arguments,Array.prototype.slice.call(n)),o=u.length,i=0;i255)throw new Error("Value specified to byte constructor ("+n+"=0x"+n.toString(16)+") is larger in value than a single byte.");var t=(n>15?"0x":"0x0")+n.toString(16);return e(function(r,e){var u=L(r,e);return u===n?b(e+1,u):x(e,t)})},buffer:function(n){return h("buffer",n).map(function(n){return Buffer.from(n)})},encodedString:function(n,t){return h("string",t).map(function(t){return t.toString(n)})},uintBE:d,uint8BE:d(1),uint16BE:d(2),uint32BE:d(4),uintLE:v,uint8LE:v(1),uint16LE:v(2),uint32LE:v(4),intBE:g,int8BE:g(1),int16BE:g(2),int32BE:g(4),intLE:m,int8LE:m(1),int16LE:m(2),int32LE:m(4),floatBE:h("floatBE",4).map(function(n){return n.readFloatBE(0)}),floatLE:h("floatLE",4).map(function(n){return n.readFloatLE(0)}),doubleBE:h("doubleBE",8).map(function(n){return n.readDoubleBE(0)}),doubleLE:h("doubleLE",8).map(function(n){return n.readDoubleLE(0)})},n.exports=e;}])}); +} (parsimmon_umd_min, parsimmon_umd_min.exports)); + +var parsimmon_umd_minExports = parsimmon_umd_min.exports; var emojiRegex = () => { // https://mths.be/emoji - return /(?:[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDD-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF6](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7C\uDE80-\uDE86\uDE90-\uDEAC\uDEB0-\uDEBA\uDEC0-\uDEC2\uDED0-\uDED9\uDEE0-\uDEE7]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?))/g; + return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC08\uDC26](?:\u200D\u2B1B)?|[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g; }; -/** Normalize a duration to all of the proper units. */ -function normalizeDuration(dur) { - if (dur === undefined || dur === null) - return dur; - return dur.shiftToAll().normalize(); -} -/** Strip the time components of a date time object. */ -function stripTime(dt) { - if (dt === null || dt === undefined) - return dt; - return DateTime.fromObject({ - year: dt.year, - month: dt.month, - day: dt.day, - }); -} -/** Get the folder containing the given path (i.e., like computing 'path/..'). */ -function getParentFolder(path) { - return path.split("/").slice(0, -1).join("/"); -} -/** Get the "title" for a file, by stripping other parts of the path as well as the extension. */ -function getFileTitle(path) { - if (path.includes("/")) - path = path.substring(path.lastIndexOf("/") + 1); - if (path.endsWith(".md")) - path = path.substring(0, path.length - 3); - return path; -} -/** Get the extension of a file from the file path. */ -function getExtension(path) { - if (!path.includes(".")) - return ""; - return path.substring(path.lastIndexOf(".") + 1); -} -/** Parse all subtags out of the given tag. I.e., #hello/i/am would yield [#hello/i/am, #hello/i, #hello]. */ -function extractSubtags(tag) { - let result = [tag]; - while (tag.includes("/")) { - tag = tag.substring(0, tag.lastIndexOf("/")); - result.push(tag); - } - return result; -} -/** Try calling the given function; on failure, return the error message. */ -function tryOrPropogate(func) { - try { - return func(); - } - catch (error) { - return Result.failure("" + error + "\n\n" + error.stack); - } -} -/** Try asynchronously calling the given function; on failure, return the error message. */ -async function asyncTryOrPropogate(func) { - try { - return await func(); - } - catch (error) { - return Result.failure("" + error + "\n\n" + error.stack); - } -} -/** - * Escape regex characters in a string. - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions. - */ -function escapeRegex(str) { - return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} -/** A parsimmon parser which canonicalizes variable names while properly respecting emoji. */ -const VAR_NAME_CANONICALIZER = parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.regex(new RegExp(emojiRegex(), "")), parsimmon_umd_min.exports.regex(/[0-9\p{Letter}_-]+/u).map(str => str.toLocaleLowerCase()), parsimmon_umd_min.exports.whitespace.map(_ => "-"), parsimmon_umd_min.exports.any.map(_ => "")) - .many() - .map(result => result.join("")); -/** Convert an arbitrary variable name into something JS/query friendly. */ -function canonicalizeVarName(name) { - return VAR_NAME_CANONICALIZER.tryParse(name); -} -const HEADER_CANONICALIZER = parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.regex(new RegExp(emojiRegex(), "")), parsimmon_umd_min.exports.regex(/[0-9\p{Letter}_-]+/u), parsimmon_umd_min.exports.whitespace.map(_ => " "), parsimmon_umd_min.exports.any.map(_ => " ")) - .many() - .map(result => { - return result.join("").split(/\s+/).join(" ").trim(); -}); -/** - * Normalizes the text in a header to be something that is actually linkable to. This mimics - * how Obsidian does it's normalization, collapsing repeated spaces and stripping out control characters. - */ -function normalizeHeaderForLink(header) { - return HEADER_CANONICALIZER.tryParse(header); -} -/** Render a DateTime in a minimal format to save space. */ -function renderMinimalDate(time, settings, locale) { - // If there is no relevant time specified, fall back to just rendering the date. - if (time.second == 0 && time.minute == 0 && time.hour == 0) { - return time.toLocal().toFormat(settings.defaultDateFormat, { locale }); - } - return time.toLocal().toFormat(settings.defaultDateTimeFormat, { locale }); -} -/** Render a duration in a minimal format to save space. */ -function renderMinimalDuration(dur) { - dur = normalizeDuration(dur); - // toHuman outputs zero quantities e.g. "0 seconds" - dur = Duration.fromObject(Object.fromEntries(Object.entries(dur.toObject()).filter(([, quantity]) => quantity > 0))); - return dur.toHuman(); -} -/** Determine if two sets are equal in contents. */ -function setsEqual(first, second) { - if (first.size != second.size) - return false; - for (let elem of first) - if (!second.has(elem)) - return false; - return true; +/** Normalize a duration to all of the proper units. */ +function normalizeDuration(dur) { + if (dur === undefined || dur === null) + return dur; + return dur.shiftToAll().normalize(); +} +/** Strip the time components of a date time object. */ +function stripTime(dt) { + if (dt === null || dt === undefined) + return dt; + return DateTime.fromObject({ + year: dt.year, + month: dt.month, + day: dt.day, + }); +} +/** Get the folder containing the given path (i.e., like computing 'path/..'). */ +function getParentFolder(path) { + return path.split("/").slice(0, -1).join("/"); +} +/** Get the "title" for a file, by stripping other parts of the path as well as the extension. */ +function getFileTitle(path) { + if (path.includes("/")) + path = path.substring(path.lastIndexOf("/") + 1); + if (path.endsWith(".md")) + path = path.substring(0, path.length - 3); + return path; +} +/** Get the extension of a file from the file path. */ +function getExtension(path) { + if (!path.includes(".")) + return ""; + return path.substring(path.lastIndexOf(".") + 1); +} +/** Parse all subtags out of the given tag. I.e., #hello/i/am would yield [#hello/i/am, #hello/i, #hello]. */ +function extractSubtags(tag) { + let result = [tag]; + while (tag.includes("/")) { + tag = tag.substring(0, tag.lastIndexOf("/")); + result.push(tag); + } + return result; +} +/** Try calling the given function; on failure, return the error message. */ +function tryOrPropogate(func) { + try { + return func(); + } + catch (error) { + return Result.failure("" + error + "\n\n" + error.stack); + } +} +/** Try asynchronously calling the given function; on failure, return the error message. */ +async function asyncTryOrPropogate(func) { + try { + return await func(); + } + catch (error) { + return Result.failure("" + error + "\n\n" + error.stack); + } +} +/** + * Escape regex characters in a string. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions. + */ +function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} +/** A parsimmon parser which canonicalizes variable names while properly respecting emoji. */ +const VAR_NAME_CANONICALIZER = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regex(new RegExp(emojiRegex(), "")), parsimmon_umd_minExports.regex(/[0-9\p{Letter}_-]+/u).map(str => str.toLocaleLowerCase()), parsimmon_umd_minExports.whitespace.map(_ => "-"), parsimmon_umd_minExports.any.map(_ => "")) + .many() + .map(result => result.join("")); +/** Convert an arbitrary variable name into something JS/query friendly. */ +function canonicalizeVarName(name) { + return VAR_NAME_CANONICALIZER.tryParse(name); +} +const HEADER_CANONICALIZER = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regex(new RegExp(emojiRegex(), "")), parsimmon_umd_minExports.regex(/[0-9\p{Letter}_-]+/u), parsimmon_umd_minExports.whitespace.map(_ => " "), parsimmon_umd_minExports.any.map(_ => " ")) + .many() + .map(result => { + return result.join("").split(/\s+/).join(" ").trim(); +}); +/** + * Normalizes the text in a header to be something that is actually linkable to. This mimics + * how Obsidian does it's normalization, collapsing repeated spaces and stripping out control characters. + */ +function normalizeHeaderForLink(header) { + return HEADER_CANONICALIZER.tryParse(header); +} +/** Render a DateTime in a minimal format to save space. */ +function renderMinimalDate(time, settings, locale) { + // If there is no relevant time specified, fall back to just rendering the date. + if (time.second == 0 && time.minute == 0 && time.hour == 0) { + return time.toLocal().toFormat(settings.defaultDateFormat, { locale }); + } + return time.toLocal().toFormat(settings.defaultDateTimeFormat, { locale }); +} +/** Render a duration in a minimal format to save space. */ +function renderMinimalDuration(dur) { + dur = normalizeDuration(dur); + // toHuman outputs zero quantities e.g. "0 seconds" + dur = Duration.fromObject(Object.fromEntries(Object.entries(dur.toObject()).filter(([, quantity]) => quantity != 0))); + return dur.toHuman(); +} +/** Determine if two sets are equal in contents. */ +function setsEqual(first, second) { + if (first.size != second.size) + return false; + for (let elem of first) + if (!second.has(elem)) + return false; + return true; } -var Values; -(function (Values) { - /** Convert an arbitrary value into a reasonable, Markdown-friendly string if possible. */ - function toString(field, setting = DEFAULT_QUERY_SETTINGS, recursive = false) { - let wrapped = wrapValue(field); - if (!wrapped) - return setting.renderNullAs; - switch (wrapped.type) { - case "null": - return setting.renderNullAs; - case "string": - return wrapped.value; - case "number": - case "boolean": - return "" + wrapped.value; - case "html": - return wrapped.value.outerHTML; - case "widget": - return wrapped.value.markdown(); - case "link": - return wrapped.value.markdown(); - case "function": - return ""; - case "array": - let result = ""; - if (recursive) - result += "["; - result += wrapped.value.map(f => toString(f, setting, true)).join(", "); - if (recursive) - result += "]"; - return result; - case "object": - return ("{ " + - Object.entries(wrapped.value) - .map(e => e[0] + ": " + toString(e[1], setting, true)) - .join(", ") + - " }"); - case "date": - if (wrapped.value.second == 0 && wrapped.value.hour == 0 && wrapped.value.minute == 0) { - return wrapped.value.toFormat(setting.defaultDateFormat); - } - return wrapped.value.toFormat(setting.defaultDateTimeFormat); - case "duration": - return renderMinimalDuration(wrapped.value); - } - } - Values.toString = toString; - /** Wrap a literal value so you can switch on it easily. */ - function wrapValue(val) { - if (isNull(val)) - return { type: "null", value: val }; - else if (isNumber(val)) - return { type: "number", value: val }; - else if (isString(val)) - return { type: "string", value: val }; - else if (isBoolean(val)) - return { type: "boolean", value: val }; - else if (isDuration(val)) - return { type: "duration", value: val }; - else if (isDate(val)) - return { type: "date", value: val }; - else if (isWidget(val)) - return { type: "widget", value: val }; - else if (isArray(val)) - return { type: "array", value: val }; - else if (isLink(val)) - return { type: "link", value: val }; - else if (isFunction(val)) - return { type: "function", value: val }; - else if (isHtml(val)) - return { type: "html", value: val }; - else if (isObject(val)) - return { type: "object", value: val }; - else - return undefined; - } - Values.wrapValue = wrapValue; - /** Recursively map complex objects at the leaves. */ - function mapLeaves(val, func) { - if (isObject(val)) { - let result = {}; - for (let [key, value] of Object.entries(val)) - result[key] = mapLeaves(value, func); - return result; - } - else if (isArray(val)) { - let result = []; - for (let value of val) - result.push(mapLeaves(value, func)); - return result; - } - else { - return func(val); - } - } - Values.mapLeaves = mapLeaves; - /** Compare two arbitrary JavaScript values. Produces a total ordering over ANY possible dataview value. */ - function compareValue(val1, val2, linkNormalizer) { - var _a, _b; - // Handle undefined/nulls first. - if (val1 === undefined) - val1 = null; - if (val2 === undefined) - val2 = null; - if (val1 === null && val2 === null) - return 0; - else if (val1 === null) - return -1; - else if (val2 === null) - return 1; - // A non-null value now which we can wrap & compare on. - let wrap1 = wrapValue(val1); - let wrap2 = wrapValue(val2); - if (wrap1 === undefined && wrap2 === undefined) - return 0; - else if (wrap1 === undefined) - return -1; - else if (wrap2 === undefined) - return 1; - // Short-circuit on different types or on reference equality. - if (wrap1.type != wrap2.type) - return wrap1.type.localeCompare(wrap2.type); - if (wrap1.value === wrap2.value) - return 0; - switch (wrap1.type) { - case "string": - return wrap1.value.localeCompare(wrap2.value); - case "number": - if (wrap1.value < wrap2.value) - return -1; - else if (wrap1.value == wrap2.value) - return 0; - return 1; - case "null": - return 0; - case "boolean": - if (wrap1.value == wrap2.value) - return 0; - else - return wrap1.value ? 1 : -1; - case "link": - let link1 = wrap1.value; - let link2 = wrap2.value; - let normalize = linkNormalizer !== null && linkNormalizer !== void 0 ? linkNormalizer : ((x) => x); - // We can't compare by file name or display, since that would break link equality. Compare by path. - let pathCompare = normalize(link1.path).localeCompare(normalize(link2.path)); - if (pathCompare != 0) - return pathCompare; - // Then compare by type. - let typeCompare = link1.type.localeCompare(link2.type); - if (typeCompare != 0) - return typeCompare; - // Then compare by subpath existence. - if (link1.subpath && !link2.subpath) - return 1; - if (!link1.subpath && link2.subpath) - return -1; - if (!link1.subpath && !link2.subpath) - return 0; - // Since both have a subpath, compare by subpath. - return ((_a = link1.subpath) !== null && _a !== void 0 ? _a : "").localeCompare((_b = link2.subpath) !== null && _b !== void 0 ? _b : ""); - case "date": - return wrap1.value < wrap2.value - ? -1 - : wrap1.value.equals(wrap2.value) - ? 0 - : 1; - case "duration": - return wrap1.value < wrap2.value - ? -1 - : wrap1.value.equals(wrap2.value) - ? 0 - : 1; - case "array": - let f1 = wrap1.value; - let f2 = wrap2.value; - for (let index = 0; index < Math.min(f1.length, f2.length); index++) { - let comp = compareValue(f1[index], f2[index]); - if (comp != 0) - return comp; - } - return f1.length - f2.length; - case "object": - let o1 = wrap1.value; - let o2 = wrap2.value; - let k1 = Array.from(Object.keys(o1)); - let k2 = Array.from(Object.keys(o2)); - k1.sort(); - k2.sort(); - let keyCompare = compareValue(k1, k2); - if (keyCompare != 0) - return keyCompare; - for (let key of k1) { - let comp = compareValue(o1[key], o2[key]); - if (comp != 0) - return comp; - } - return 0; - case "widget": - case "html": - case "function": - return 0; - } - } - Values.compareValue = compareValue; - /** Find the corresponding Dataveiw type for an arbitrary value. */ - function typeOf(val) { - var _a; - return (_a = wrapValue(val)) === null || _a === void 0 ? void 0 : _a.type; - } - Values.typeOf = typeOf; - /** Determine if the given value is "truthy" (i.e., is non-null and has data in it). */ - function isTruthy(field) { - let wrapped = wrapValue(field); - if (!wrapped) - return false; - switch (wrapped.type) { - case "number": - return wrapped.value != 0; - case "string": - return wrapped.value.length > 0; - case "boolean": - return wrapped.value; - case "link": - return !!wrapped.value.path; - case "date": - return wrapped.value.toMillis() != 0; - case "duration": - return wrapped.value.as("seconds") != 0; - case "object": - return Object.keys(wrapped.value).length > 0; - case "array": - return wrapped.value.length > 0; - case "null": - return false; - case "html": - case "widget": - case "function": - return true; - } - } - Values.isTruthy = isTruthy; - /** Deep copy a field. */ - function deepCopy(field) { - if (field === null || field === undefined) - return field; - if (Values.isArray(field)) { - return [].concat(field.map(v => deepCopy(v))); - } - else if (Values.isObject(field)) { - let result = {}; - for (let [key, value] of Object.entries(field)) - result[key] = deepCopy(value); - return result; - } - else { - return field; - } - } - Values.deepCopy = deepCopy; - function isString(val) { - return typeof val == "string"; - } - Values.isString = isString; - function isNumber(val) { - return typeof val == "number"; - } - Values.isNumber = isNumber; - function isDate(val) { - return val instanceof DateTime; - } - Values.isDate = isDate; - function isDuration(val) { - return val instanceof Duration; - } - Values.isDuration = isDuration; - function isNull(val) { - return val === null || val === undefined; - } - Values.isNull = isNull; - function isArray(val) { - return Array.isArray(val); - } - Values.isArray = isArray; - function isBoolean(val) { - return typeof val === "boolean"; - } - Values.isBoolean = isBoolean; - function isLink(val) { - return val instanceof Link; - } - Values.isLink = isLink; - function isWidget(val) { - return val instanceof Widget; - } - Values.isWidget = isWidget; - function isHtml(val) { - if (typeof HTMLElement !== "undefined") { - return val instanceof HTMLElement; - } - else { - return false; - } - } - Values.isHtml = isHtml; - /** Checks if the given value is an object (and not any other dataview-recognized object-like type). */ - function isObject(val) { - return (typeof val == "object" && - !isHtml(val) && - !isWidget(val) && - !isArray(val) && - !isDuration(val) && - !isDate(val) && - !isLink(val) && - val !== undefined && - !isNull(val)); - } - Values.isObject = isObject; - function isFunction(val) { - return typeof val == "function"; - } - Values.isFunction = isFunction; -})(Values || (Values = {})); -/////////////// -// Groupings // -/////////////// -var Groupings; -(function (Groupings) { - /** Determines if the given group entry is a standalone value, or a grouping of sub-entries. */ - function isElementGroup(entry) { - return Values.isObject(entry) && Object.keys(entry).length == 2 && "key" in entry && "rows" in entry; - } - Groupings.isElementGroup = isElementGroup; - /** Determines if the given array is a grouping array. */ - function isGrouping(entry) { - for (let element of entry) - if (!isElementGroup(element)) - return false; - return true; - } - Groupings.isGrouping = isGrouping; - /** Count the total number of elements in a recursive grouping. */ - function count(elements) { - if (isGrouping(elements)) { - let result = 0; - for (let subgroup of elements) - result += count(subgroup.rows); - return result; - } - else { - return elements.length; - } - } - Groupings.count = count; -})(Groupings || (Groupings = {})); -////////// -// LINK // -////////// -/** The Obsidian 'link', used for uniquely describing a file, header, or block. */ -class Link { - constructor(fields) { - Object.assign(this, fields); - } - /** Create a link to a specific file. */ - static file(path, embed = false, display) { - return new Link({ - path, - embed, - display, - subpath: undefined, - type: "file", - }); - } - static infer(linkpath, embed = false, display) { - if (linkpath.includes("#^")) { - let split = linkpath.split("#^"); - return Link.block(split[0], split[1], embed, display); - } - else if (linkpath.includes("#")) { - let split = linkpath.split("#"); - return Link.header(split[0], split[1], embed, display); - } - else - return Link.file(linkpath, embed, display); - } - /** Create a link to a specific file and header in that file. */ - static header(path, header, embed, display) { - // Headers need to be normalized to alpha-numeric & with extra spacing removed. - return new Link({ - path, - embed, - display, - subpath: normalizeHeaderForLink(header), - type: "header", - }); - } - /** Create a link to a specific file and block in that file. */ - static block(path, blockId, embed, display) { - return new Link({ - path, - embed, - display, - subpath: blockId, - type: "block", - }); - } - static fromObject(object) { - return new Link(object); - } - /** Checks for link equality (i.e., that the links are pointing to the same exact location). */ - equals(other) { - if (other == undefined || other == null) - return false; - return this.path == other.path && this.type == other.type && this.subpath == other.subpath; - } - /** Convert this link to it's markdown representation. */ - toString() { - return this.markdown(); - } - /** Convert this link to a raw object which is serialization-friendly. */ - toObject() { - return { path: this.path, type: this.type, subpath: this.subpath, display: this.display, embed: this.embed }; - } - /** Update this link with a new path. */ - //@ts-ignore; error appeared after updating Obsidian to 0.15.4; it also updated other packages but didn't say which - withPath(path) { - return new Link(Object.assign({}, this, { path })); - } - /** Return a new link which points to the same location but with a new display value. */ - withDisplay(display) { - return new Link(Object.assign({}, this, { display })); - } - /** Convert a file link into a link to a specific header. */ - withHeader(header) { - return Link.header(this.path, header, this.embed, this.display); - } - /** Convert any link into a link to its file. */ - toFile() { - return Link.file(this.path, this.embed, this.display); - } - /** Convert this link into an embedded link. */ - toEmbed() { - if (this.embed) { - return this; - } - else { - let link = new Link(this); - link.embed = true; - return link; - } - } - /** Convert this link into a non-embedded link. */ - fromEmbed() { - if (!this.embed) { - return this; - } - else { - let link = new Link(this); - link.embed = false; - return link; - } - } - /** Convert this link to markdown so it can be rendered. */ - markdown() { - let result = (this.embed ? "!" : "") + "[[" + this.obsidianLink(); - if (this.display) { - result += "|" + this.display; - } - else { - result += "|" + getFileTitle(this.path); - if (this.type == "header" || this.type == "block") - result += " > " + this.subpath; - } - result += "]]"; - return result; - } - /** Convert the inner part of the link to something that Obsidian can open / understand. */ - obsidianLink() { - var _a, _b; - const escaped = this.path.replace("|", "\\|"); - if (this.type == "header") - return escaped + "#" + ((_a = this.subpath) === null || _a === void 0 ? void 0 : _a.replace("|", "\\|")); - if (this.type == "block") - return escaped + "#^" + ((_b = this.subpath) === null || _b === void 0 ? void 0 : _b.replace("|", "\\|")); - else - return escaped; - } - /** The stripped name of the file this link points to. */ - fileName() { - return getFileTitle(this.path).replace(".md", ""); - } -} -///////////////// -// WIDGET BASE // -///////////////// -/** - * A trivial base class which just defines the '$widget' identifier type. Subtypes of - * widget are responsible for adding whatever metadata is relevant. If you want your widget - * to have rendering functionality (which you probably do), you should extend `RenderWidget`. - */ -class Widget { - constructor($widget) { - this.$widget = $widget; - } -} -/** A trivial widget which renders a (key, value) pair, and allows accessing the key and value. */ -class ListPairWidget extends Widget { - constructor(key, value) { - super("dataview:list-pair"); - this.key = key; - this.value = value; - } - markdown() { - return `${Values.toString(this.key)}: ${Values.toString(this.value)}`; - } -} -/** A simple widget which renders an external link. */ -class ExternalLinkWidget extends Widget { - constructor(url, display) { - super("dataview:external-link"); - this.url = url; - this.display = display; - } - markdown() { - var _a; - return `[${(_a = this.display) !== null && _a !== void 0 ? _a : this.url}](${this.url})`; - } -} -var Widgets; -(function (Widgets) { - /** Create a list pair widget matching the given key and value. */ - function listPair(key, value) { - return new ListPairWidget(key, value); - } - Widgets.listPair = listPair; - /** Create an external link widget which renders an external Obsidian link. */ - function externalLink(url, display) { - return new ExternalLinkWidget(url, display); - } - Widgets.externalLink = externalLink; - /** Checks if the given widget is a list pair widget. */ - function isListPair(widget) { - return widget.$widget === "dataview:list-pair"; - } - Widgets.isListPair = isListPair; - function isExternalLink(widget) { - return widget.$widget === "dataview:external-link"; - } - Widgets.isExternalLink = isExternalLink; - /** Determines if the given widget is any kind of built-in widget with special rendering handling. */ - function isBuiltin(widget) { - return isListPair(widget) || isExternalLink(widget); - } - Widgets.isBuiltin = isBuiltin; +var Values; +(function (Values) { + /** Convert an arbitrary value into a reasonable, Markdown-friendly string if possible. */ + function toString(field, setting = DEFAULT_QUERY_SETTINGS, recursive = false) { + let wrapped = wrapValue(field); + if (!wrapped) + return setting.renderNullAs; + switch (wrapped.type) { + case "null": + return setting.renderNullAs; + case "string": + return wrapped.value; + case "number": + case "boolean": + return "" + wrapped.value; + case "html": + return wrapped.value.outerHTML; + case "widget": + return wrapped.value.markdown(); + case "link": + return wrapped.value.markdown(); + case "function": + return ""; + case "array": + let result = ""; + if (recursive) + result += "["; + result += wrapped.value.map(f => toString(f, setting, true)).join(", "); + if (recursive) + result += "]"; + return result; + case "object": + return ("{ " + + Object.entries(wrapped.value) + .map(e => e[0] + ": " + toString(e[1], setting, true)) + .join(", ") + + " }"); + case "date": + if (wrapped.value.second == 0 && wrapped.value.hour == 0 && wrapped.value.minute == 0) { + return wrapped.value.toFormat(setting.defaultDateFormat); + } + return wrapped.value.toFormat(setting.defaultDateTimeFormat); + case "duration": + return renderMinimalDuration(wrapped.value); + } + } + Values.toString = toString; + /** Wrap a literal value so you can switch on it easily. */ + function wrapValue(val) { + if (isNull(val)) + return { type: "null", value: val }; + else if (isNumber(val)) + return { type: "number", value: val }; + else if (isString(val)) + return { type: "string", value: val }; + else if (isBoolean(val)) + return { type: "boolean", value: val }; + else if (isDuration(val)) + return { type: "duration", value: val }; + else if (isDate(val)) + return { type: "date", value: val }; + else if (isWidget(val)) + return { type: "widget", value: val }; + else if (isArray(val)) + return { type: "array", value: val }; + else if (isLink(val)) + return { type: "link", value: val }; + else if (isFunction(val)) + return { type: "function", value: val }; + else if (isHtml(val)) + return { type: "html", value: val }; + else if (isObject(val)) + return { type: "object", value: val }; + else + return undefined; + } + Values.wrapValue = wrapValue; + /** Recursively map complex objects at the leaves. */ + function mapLeaves(val, func) { + if (isObject(val)) { + let result = {}; + for (let [key, value] of Object.entries(val)) + result[key] = mapLeaves(value, func); + return result; + } + else if (isArray(val)) { + let result = []; + for (let value of val) + result.push(mapLeaves(value, func)); + return result; + } + else { + return func(val); + } + } + Values.mapLeaves = mapLeaves; + /** Compare two arbitrary JavaScript values. Produces a total ordering over ANY possible dataview value. */ + function compareValue(val1, val2, linkNormalizer) { + var _a, _b; + // Handle undefined/nulls first. + if (val1 === undefined) + val1 = null; + if (val2 === undefined) + val2 = null; + if (val1 === null && val2 === null) + return 0; + else if (val1 === null) + return -1; + else if (val2 === null) + return 1; + // A non-null value now which we can wrap & compare on. + let wrap1 = wrapValue(val1); + let wrap2 = wrapValue(val2); + if (wrap1 === undefined && wrap2 === undefined) + return 0; + else if (wrap1 === undefined) + return -1; + else if (wrap2 === undefined) + return 1; + // Short-circuit on different types or on reference equality. + if (wrap1.type != wrap2.type) + return wrap1.type.localeCompare(wrap2.type); + if (wrap1.value === wrap2.value) + return 0; + switch (wrap1.type) { + case "string": + return wrap1.value.localeCompare(wrap2.value); + case "number": + if (wrap1.value < wrap2.value) + return -1; + else if (wrap1.value == wrap2.value) + return 0; + return 1; + case "null": + return 0; + case "boolean": + if (wrap1.value == wrap2.value) + return 0; + else + return wrap1.value ? 1 : -1; + case "link": + let link1 = wrap1.value; + let link2 = wrap2.value; + let normalize = linkNormalizer !== null && linkNormalizer !== void 0 ? linkNormalizer : ((x) => x); + // We can't compare by file name or display, since that would break link equality. Compare by path. + let pathCompare = normalize(link1.path).localeCompare(normalize(link2.path)); + if (pathCompare != 0) + return pathCompare; + // Then compare by type. + let typeCompare = link1.type.localeCompare(link2.type); + if (typeCompare != 0) + return typeCompare; + // Then compare by subpath existence. + if (link1.subpath && !link2.subpath) + return 1; + if (!link1.subpath && link2.subpath) + return -1; + if (!link1.subpath && !link2.subpath) + return 0; + // Since both have a subpath, compare by subpath. + return ((_a = link1.subpath) !== null && _a !== void 0 ? _a : "").localeCompare((_b = link2.subpath) !== null && _b !== void 0 ? _b : ""); + case "date": + return wrap1.value < wrap2.value + ? -1 + : wrap1.value.equals(wrap2.value) + ? 0 + : 1; + case "duration": + return wrap1.value < wrap2.value + ? -1 + : wrap1.value.equals(wrap2.value) + ? 0 + : 1; + case "array": + let f1 = wrap1.value; + let f2 = wrap2.value; + for (let index = 0; index < Math.min(f1.length, f2.length); index++) { + let comp = compareValue(f1[index], f2[index]); + if (comp != 0) + return comp; + } + return f1.length - f2.length; + case "object": + let o1 = wrap1.value; + let o2 = wrap2.value; + let k1 = Array.from(Object.keys(o1)); + let k2 = Array.from(Object.keys(o2)); + k1.sort(); + k2.sort(); + let keyCompare = compareValue(k1, k2); + if (keyCompare != 0) + return keyCompare; + for (let key of k1) { + let comp = compareValue(o1[key], o2[key]); + if (comp != 0) + return comp; + } + return 0; + case "widget": + case "html": + case "function": + return 0; + } + } + Values.compareValue = compareValue; + /** Find the corresponding Dataveiw type for an arbitrary value. */ + function typeOf(val) { + var _a; + return (_a = wrapValue(val)) === null || _a === void 0 ? void 0 : _a.type; + } + Values.typeOf = typeOf; + /** Determine if the given value is "truthy" (i.e., is non-null and has data in it). */ + function isTruthy(field) { + let wrapped = wrapValue(field); + if (!wrapped) + return false; + switch (wrapped.type) { + case "number": + return wrapped.value != 0; + case "string": + return wrapped.value.length > 0; + case "boolean": + return wrapped.value; + case "link": + return !!wrapped.value.path; + case "date": + return wrapped.value.toMillis() != 0; + case "duration": + return wrapped.value.as("seconds") != 0; + case "object": + return Object.keys(wrapped.value).length > 0; + case "array": + return wrapped.value.length > 0; + case "null": + return false; + case "html": + case "widget": + case "function": + return true; + } + } + Values.isTruthy = isTruthy; + /** Deep copy a field. */ + function deepCopy(field) { + if (field === null || field === undefined) + return field; + if (Values.isArray(field)) { + return [].concat(field.map(v => deepCopy(v))); + } + else if (Values.isObject(field)) { + let result = {}; + for (let [key, value] of Object.entries(field)) + result[key] = deepCopy(value); + return result; + } + else { + return field; + } + } + Values.deepCopy = deepCopy; + function isString(val) { + return typeof val == "string"; + } + Values.isString = isString; + function isNumber(val) { + return typeof val == "number"; + } + Values.isNumber = isNumber; + function isDate(val) { + return val instanceof DateTime; + } + Values.isDate = isDate; + function isDuration(val) { + return val instanceof Duration; + } + Values.isDuration = isDuration; + function isNull(val) { + return val === null || val === undefined; + } + Values.isNull = isNull; + function isArray(val) { + return Array.isArray(val); + } + Values.isArray = isArray; + function isBoolean(val) { + return typeof val === "boolean"; + } + Values.isBoolean = isBoolean; + function isLink(val) { + return val instanceof Link; + } + Values.isLink = isLink; + function isWidget(val) { + return val instanceof Widget; + } + Values.isWidget = isWidget; + function isHtml(val) { + if (typeof HTMLElement !== "undefined") { + return val instanceof HTMLElement; + } + else { + return false; + } + } + Values.isHtml = isHtml; + /** Checks if the given value is an object (and not any other dataview-recognized object-like type). */ + function isObject(val) { + return (typeof val == "object" && + !isHtml(val) && + !isWidget(val) && + !isArray(val) && + !isDuration(val) && + !isDate(val) && + !isLink(val) && + val !== undefined && + !isNull(val)); + } + Values.isObject = isObject; + function isFunction(val) { + return typeof val == "function"; + } + Values.isFunction = isFunction; +})(Values || (Values = {})); +/////////////// +// Groupings // +/////////////// +var Groupings; +(function (Groupings) { + /** Determines if the given group entry is a standalone value, or a grouping of sub-entries. */ + function isElementGroup(entry) { + return Values.isObject(entry) && Object.keys(entry).length == 2 && "key" in entry && "rows" in entry; + } + Groupings.isElementGroup = isElementGroup; + /** Determines if the given array is a grouping array. */ + function isGrouping(entry) { + for (let element of entry) + if (!isElementGroup(element)) + return false; + return true; + } + Groupings.isGrouping = isGrouping; + /** Count the total number of elements in a recursive grouping. */ + function count(elements) { + if (isGrouping(elements)) { + let result = 0; + for (let subgroup of elements) + result += count(subgroup.rows); + return result; + } + else { + return elements.length; + } + } + Groupings.count = count; +})(Groupings || (Groupings = {})); +////////// +// LINK // +////////// +/** The Obsidian 'link', used for uniquely describing a file, header, or block. */ +class Link { + /** Create a link to a specific file. */ + static file(path, embed = false, display) { + return new Link({ + path, + embed, + display, + subpath: undefined, + type: "file", + }); + } + static infer(linkpath, embed = false, display) { + if (linkpath.includes("#^")) { + let split = linkpath.split("#^"); + return Link.block(split[0], split[1], embed, display); + } + else if (linkpath.includes("#")) { + let split = linkpath.split("#"); + return Link.header(split[0], split[1], embed, display); + } + else + return Link.file(linkpath, embed, display); + } + /** Create a link to a specific file and header in that file. */ + static header(path, header, embed, display) { + // Headers need to be normalized to alpha-numeric & with extra spacing removed. + return new Link({ + path, + embed, + display, + subpath: normalizeHeaderForLink(header), + type: "header", + }); + } + /** Create a link to a specific file and block in that file. */ + static block(path, blockId, embed, display) { + return new Link({ + path, + embed, + display, + subpath: blockId, + type: "block", + }); + } + static fromObject(object) { + return new Link(object); + } + constructor(fields) { + Object.assign(this, fields); + } + /** Checks for link equality (i.e., that the links are pointing to the same exact location). */ + equals(other) { + if (other == undefined || other == null) + return false; + return this.path == other.path && this.type == other.type && this.subpath == other.subpath; + } + /** Convert this link to it's markdown representation. */ + toString() { + return this.markdown(); + } + /** Convert this link to a raw object which is serialization-friendly. */ + toObject() { + return { path: this.path, type: this.type, subpath: this.subpath, display: this.display, embed: this.embed }; + } + /** Update this link with a new path. */ + //@ts-ignore; error appeared after updating Obsidian to 0.15.4; it also updated other packages but didn't say which + withPath(path) { + return new Link(Object.assign({}, this, { path })); + } + /** Return a new link which points to the same location but with a new display value. */ + withDisplay(display) { + return new Link(Object.assign({}, this, { display })); + } + /** Convert a file link into a link to a specific header. */ + withHeader(header) { + return Link.header(this.path, header, this.embed, this.display); + } + /** Convert any link into a link to its file. */ + toFile() { + return Link.file(this.path, this.embed, this.display); + } + /** Convert this link into an embedded link. */ + toEmbed() { + if (this.embed) { + return this; + } + else { + let link = new Link(this); + link.embed = true; + return link; + } + } + /** Convert this link into a non-embedded link. */ + fromEmbed() { + if (!this.embed) { + return this; + } + else { + let link = new Link(this); + link.embed = false; + return link; + } + } + /** Convert this link to markdown so it can be rendered. */ + markdown() { + let result = (this.embed ? "!" : "") + "[[" + this.obsidianLink(); + if (this.display) { + result += "|" + this.display; + } + else { + result += "|" + getFileTitle(this.path); + if (this.type == "header" || this.type == "block") + result += " > " + this.subpath; + } + result += "]]"; + return result; + } + /** Convert the inner part of the link to something that Obsidian can open / understand. */ + obsidianLink() { + var _a, _b; + const escaped = this.path.replace("|", "\\|"); + if (this.type == "header") + return escaped + "#" + ((_a = this.subpath) === null || _a === void 0 ? void 0 : _a.replace("|", "\\|")); + if (this.type == "block") + return escaped + "#^" + ((_b = this.subpath) === null || _b === void 0 ? void 0 : _b.replace("|", "\\|")); + else + return escaped; + } + /** The stripped name of the file this link points to. */ + fileName() { + return getFileTitle(this.path).replace(".md", ""); + } +} +///////////////// +// WIDGET BASE // +///////////////// +/** + * A trivial base class which just defines the '$widget' identifier type. Subtypes of + * widget are responsible for adding whatever metadata is relevant. If you want your widget + * to have rendering functionality (which you probably do), you should extend `RenderWidget`. + */ +class Widget { + constructor($widget) { + this.$widget = $widget; + } +} +/** A trivial widget which renders a (key, value) pair, and allows accessing the key and value. */ +class ListPairWidget extends Widget { + constructor(key, value) { + super("dataview:list-pair"); + this.key = key; + this.value = value; + } + markdown() { + return `${Values.toString(this.key)}: ${Values.toString(this.value)}`; + } +} +/** A simple widget which renders an external link. */ +class ExternalLinkWidget extends Widget { + constructor(url, display) { + super("dataview:external-link"); + this.url = url; + this.display = display; + } + markdown() { + var _a; + return `[${(_a = this.display) !== null && _a !== void 0 ? _a : this.url}](${this.url})`; + } +} +var Widgets; +(function (Widgets) { + /** Create a list pair widget matching the given key and value. */ + function listPair(key, value) { + return new ListPairWidget(key, value); + } + Widgets.listPair = listPair; + /** Create an external link widget which renders an external Obsidian link. */ + function externalLink(url, display) { + return new ExternalLinkWidget(url, display); + } + Widgets.externalLink = externalLink; + /** Checks if the given widget is a list pair widget. */ + function isListPair(widget) { + return widget.$widget === "dataview:list-pair"; + } + Widgets.isListPair = isListPair; + function isExternalLink(widget) { + return widget.$widget === "dataview:external-link"; + } + Widgets.isExternalLink = isExternalLink; + /** Determines if the given widget is any kind of built-in widget with special rendering handling. */ + function isBuiltin(widget) { + return isListPair(widget) || isExternalLink(widget); + } + Widgets.isBuiltin = isBuiltin; })(Widgets || (Widgets = {})); -/** Implementation of DataArray, minus the dynamic variable access, which is implemented via proxy. */ -class DataArrayImpl { - constructor(values, settings, defaultComparator = Values.compareValue) { - this.values = values; - this.settings = settings; - this.defaultComparator = defaultComparator; - this.length = values.length; - } - static wrap(arr, settings, defaultComparator = Values.compareValue) { - return new Proxy(new DataArrayImpl(arr, settings, defaultComparator), DataArrayImpl.ARRAY_PROXY); - } - lwrap(values) { - return DataArrayImpl.wrap(values, this.settings, this.defaultComparator); - } - where(predicate) { - return this.lwrap(this.values.filter(predicate)); - } - filter(predicate) { - return this.where(predicate); - } - map(f) { - return this.lwrap(this.values.map(f)); - } - flatMap(f) { - let result = []; - for (let index = 0; index < this.length; index++) { - let value = f(this.values[index], index, this.values); - if (!value || value.length == 0) - continue; - for (let r of value) - result.push(r); - } - return this.lwrap(result); - } - mutate(f) { - for (let index = 0; index < this.values.length; index++) { - f(this.values[index], index, this.values); - } - return this; - } - limit(count) { - return this.lwrap(this.values.slice(0, count)); - } - slice(start, end) { - return this.lwrap(this.values.slice(start, end)); - } - concat(other) { - return this.lwrap(this.values.concat(other.values)); - } - /** Return the first index of the given (optionally starting the search) */ - indexOf(element, fromIndex) { - return this.findIndex(e => this.defaultComparator(e, element) == 0, fromIndex); - } - /** Return the first element that satisfies the given predicate. */ - find(pred) { - let index = this.findIndex(pred); - if (index == -1) - return undefined; - else - return this.values[index]; - } - findIndex(pred, fromIndex) { - for (let index = fromIndex !== null && fromIndex !== void 0 ? fromIndex : 0; index < this.length; index++) { - if (pred(this.values[index], index, this.values)) - return index; - } - return -1; - } - includes(element) { - return this.indexOf(element, 0) != -1; - } - join(sep) { - return this.map(s => Values.toString(s, this.settings)) - .array() - .join(sep !== null && sep !== void 0 ? sep : ", "); - } - sort(key, direction, comparator) { - if (this.values.length == 0) - return this; - let realComparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; - let realKey = key !== null && key !== void 0 ? key : ((l) => l); - // Associate each entry with it's index for the key function, and then do a normal sort. - let copy = [].concat(this.array()).map((elem, index) => { - return { index: index, value: elem }; - }); - copy.sort((a, b) => { - let aKey = realKey(a.value, a.index, this.values); - let bKey = realKey(b.value, b.index, this.values); - return direction === "desc" ? -realComparator(aKey, bKey) : realComparator(aKey, bKey); - }); - return this.lwrap(copy.map(e => e.value)); - } - sortInPlace(key, direction, comparator) { - if (this.values.length == 0) - return this; - let realComparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; - let realKey = key !== null && key !== void 0 ? key : ((l) => l); - this.values.sort((a, b) => { - let aKey = realKey(a); - let bKey = realKey(b); - return direction == "desc" ? -realComparator(aKey, bKey) : realComparator(aKey, bKey); - }); - return this; - } - groupBy(key, comparator) { - if (this.values.length == 0) - return this.lwrap([]); - // JavaScript sucks and we can't make hash maps over arbitrary types (only strings/ints), so - // we do a poor man algorithm where we SORT, followed by grouping. - let intermediate = this.sort(key, "asc", comparator); - comparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; - let result = []; - let currentRow = [intermediate[0]]; - let current = key(intermediate[0], 0, intermediate.values); - for (let index = 1; index < intermediate.length; index++) { - let newKey = key(intermediate[index], index, intermediate.values); - if (comparator(current, newKey) != 0) { - result.push({ key: current, rows: this.lwrap(currentRow) }); - current = newKey; - currentRow = [intermediate[index]]; - } - else { - currentRow.push(intermediate[index]); - } - } - result.push({ key: current, rows: this.lwrap(currentRow) }); - return this.lwrap(result); - } - groupIn(key, comparator) { - if (Groupings.isGrouping(this.values)) { - return this.map(v => { - return { - key: v.key, - rows: DataArray.wrap(v.rows, this.settings).groupIn(key, comparator), - }; - }); - } - else { - return this.groupBy(key, comparator); - } - } - distinct(key, comparator) { - if (this.values.length == 0) - return this; - let realKey = key !== null && key !== void 0 ? key : (x => x); - // For similar reasons to groupBy, do a sort and take the first element of each block. - let intermediate = this.map((x, index) => { - return { key: realKey(x, index, this.values), value: x }; - }).sort(x => x.key, "asc", comparator); - comparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; - let result = [intermediate[0].value]; - for (let index = 1; index < intermediate.length; index++) { - if (comparator(intermediate[index - 1].key, intermediate[index].key) != 0) { - result.push(intermediate[index].value); - } - } - return this.lwrap(result); - } - every(f) { - return this.values.every(f); - } - some(f) { - return this.values.some(f); - } - none(f) { - return this.values.every((v, i, a) => !f(v, i, a)); - } - first() { - return this.values.length > 0 ? this.values[0] : undefined; - } - last() { - return this.values.length > 0 ? this.values[this.values.length - 1] : undefined; - } - to(key) { - let result = []; - for (let child of this.values) { - let value = child[key]; - if (value === undefined || value === null) - continue; - if (Array.isArray(value) || DataArray.isDataArray(value)) - value.forEach(v => result.push(v)); - else - result.push(value); - } - return this.lwrap(result); - } - into(key) { - let result = []; - for (let child of this.values) { - let value = child[key]; - if (value === undefined || value === null) - continue; - result.push(value); - } - return this.lwrap(result); - } - expand(key) { - let result = []; - let queue = [].concat(this.values); - while (queue.length > 0) { - let next = queue.pop(); - let value = next[key]; - if (value === undefined || value === null) - continue; - if (Array.isArray(value)) - value.forEach(v => queue.push(v)); - else if (value instanceof DataArrayImpl) - value.forEach(v => queue.push(v)); - else - queue.push(value); - result.push(next); - } - return this.lwrap(result); - } - forEach(f) { - for (let index = 0; index < this.values.length; index++) { - f(this.values[index], index, this.values); - } - } - array() { - return [].concat(this.values); - } - [Symbol.iterator]() { - return this.values[Symbol.iterator](); - } - toString() { - return "[" + this.values.join(", ") + "]"; - } -} -DataArrayImpl.ARRAY_FUNCTIONS = new Set([ - "where", - "filter", - "map", - "flatMap", - "mutate", - "slice", - "concat", - "indexOf", - "limit", - "find", - "findIndex", - "includes", - "join", - "sort", - "sortInPlace", - "groupBy", - "groupIn", - "distinct", - "every", - "some", - "none", - "first", - "last", - "to", - "into", - "lwrap", - "expand", - "forEach", - "length", - "values", - "array", - "defaultComparator", - "toString", - "settings", -]); -DataArrayImpl.ARRAY_PROXY = { - get: function (target, prop, reciever) { - if (typeof prop === "symbol") - return target[prop]; - else if (typeof prop === "number") - return target.values[prop]; - else if (prop === "constructor") - return target.values.constructor; - else if (!isNaN(parseInt(prop))) - return target.values[parseInt(prop)]; - else if (DataArrayImpl.ARRAY_FUNCTIONS.has(prop.toString())) - return target[prop.toString()]; - return target.to(prop); - }, -}; -/** Provides utility functions for generating data arrays. */ -var DataArray; -(function (DataArray) { - /** Create a new Dataview data array. */ - function wrap(raw, settings) { - if (isDataArray(raw)) - return raw; - return DataArrayImpl.wrap(raw, settings); - } - DataArray.wrap = wrap; - /** Create a new DataArray from an iterable object. */ - function from(raw, settings) { - if (isDataArray(raw)) - return raw; - let data = []; - for (let elem of raw) - data.push(elem); - return DataArrayImpl.wrap(data, settings); - } - DataArray.from = from; - /** Return true if the given object is a data array. */ - function isDataArray(obj) { - return obj instanceof DataArrayImpl; - } - DataArray.isDataArray = isDataArray; -})(DataArray || (DataArray = {})); -// A scary looking polyfill, sure, but it fixes up data array/array interop for us. -const oldArrayIsArray = Array.isArray; -Array.isArray = (arg) => { - return oldArrayIsArray(arg) || DataArray.isDataArray(arg); +/** Implementation of DataArray, minus the dynamic variable access, which is implemented via proxy. */ +class DataArrayImpl { + static wrap(arr, settings, defaultComparator = Values.compareValue) { + return new Proxy(new DataArrayImpl(arr, settings, defaultComparator), DataArrayImpl.ARRAY_PROXY); + } + constructor(values, settings, defaultComparator = Values.compareValue) { + this.values = values; + this.settings = settings; + this.defaultComparator = defaultComparator; + this.length = values.length; + } + lwrap(values) { + return DataArrayImpl.wrap(values, this.settings, this.defaultComparator); + } + where(predicate) { + return this.lwrap(this.values.filter(predicate)); + } + filter(predicate) { + return this.where(predicate); + } + map(f) { + return this.lwrap(this.values.map(f)); + } + flatMap(f) { + let result = []; + for (let index = 0; index < this.length; index++) { + let value = f(this.values[index], index, this.values); + if (!value || value.length == 0) + continue; + for (let r of value) + result.push(r); + } + return this.lwrap(result); + } + mutate(f) { + for (let index = 0; index < this.values.length; index++) { + f(this.values[index], index, this.values); + } + return this; + } + limit(count) { + return this.lwrap(this.values.slice(0, count)); + } + slice(start, end) { + return this.lwrap(this.values.slice(start, end)); + } + concat(other) { + return this.lwrap(this.values.concat(other.values)); + } + /** Return the first index of the given (optionally starting the search) */ + indexOf(element, fromIndex) { + return this.findIndex(e => this.defaultComparator(e, element) == 0, fromIndex); + } + /** Return the first element that satisfies the given predicate. */ + find(pred) { + let index = this.findIndex(pred); + if (index == -1) + return undefined; + else + return this.values[index]; + } + findIndex(pred, fromIndex) { + for (let index = fromIndex !== null && fromIndex !== void 0 ? fromIndex : 0; index < this.length; index++) { + if (pred(this.values[index], index, this.values)) + return index; + } + return -1; + } + includes(element) { + return this.indexOf(element, 0) != -1; + } + join(sep) { + return this.map(s => Values.toString(s, this.settings)) + .array() + .join(sep !== null && sep !== void 0 ? sep : ", "); + } + sort(key, direction, comparator) { + if (this.values.length == 0) + return this; + let realComparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; + let realKey = key !== null && key !== void 0 ? key : ((l) => l); + // Associate each entry with it's index for the key function, and then do a normal sort. + let copy = [].concat(this.array()).map((elem, index) => { + return { index: index, value: elem }; + }); + copy.sort((a, b) => { + let aKey = realKey(a.value, a.index, this.values); + let bKey = realKey(b.value, b.index, this.values); + return direction === "desc" ? -realComparator(aKey, bKey) : realComparator(aKey, bKey); + }); + return this.lwrap(copy.map(e => e.value)); + } + sortInPlace(key, direction, comparator) { + if (this.values.length == 0) + return this; + let realComparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; + let realKey = key !== null && key !== void 0 ? key : ((l) => l); + this.values.sort((a, b) => { + let aKey = realKey(a); + let bKey = realKey(b); + return direction == "desc" ? -realComparator(aKey, bKey) : realComparator(aKey, bKey); + }); + return this; + } + groupBy(key, comparator) { + if (this.values.length == 0) + return this.lwrap([]); + // JavaScript sucks and we can't make hash maps over arbitrary types (only strings/ints), so + // we do a poor man algorithm where we SORT, followed by grouping. + let intermediate = this.sort(key, "asc", comparator); + comparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; + let result = []; + let currentRow = [intermediate[0]]; + let current = key(intermediate[0], 0, intermediate.values); + for (let index = 1; index < intermediate.length; index++) { + let newKey = key(intermediate[index], index, intermediate.values); + if (comparator(current, newKey) != 0) { + result.push({ key: current, rows: this.lwrap(currentRow) }); + current = newKey; + currentRow = [intermediate[index]]; + } + else { + currentRow.push(intermediate[index]); + } + } + result.push({ key: current, rows: this.lwrap(currentRow) }); + return this.lwrap(result); + } + groupIn(key, comparator) { + if (Groupings.isGrouping(this.values)) { + return this.map(v => { + return { + key: v.key, + rows: DataArray.wrap(v.rows, this.settings).groupIn(key, comparator), + }; + }); + } + else { + return this.groupBy(key, comparator); + } + } + distinct(key, comparator) { + if (this.values.length == 0) + return this; + let realKey = key !== null && key !== void 0 ? key : (x => x); + // For similar reasons to groupBy, do a sort and take the first element of each block. + let intermediate = this.map((x, index) => { + return { key: realKey(x, index, this.values), value: x }; + }).sort(x => x.key, "asc", comparator); + comparator = comparator !== null && comparator !== void 0 ? comparator : this.defaultComparator; + let result = [intermediate[0].value]; + for (let index = 1; index < intermediate.length; index++) { + if (comparator(intermediate[index - 1].key, intermediate[index].key) != 0) { + result.push(intermediate[index].value); + } + } + return this.lwrap(result); + } + every(f) { + return this.values.every(f); + } + some(f) { + return this.values.some(f); + } + none(f) { + return this.values.every((v, i, a) => !f(v, i, a)); + } + first() { + return this.values.length > 0 ? this.values[0] : undefined; + } + last() { + return this.values.length > 0 ? this.values[this.values.length - 1] : undefined; + } + to(key) { + let result = []; + for (let child of this.values) { + let value = child[key]; + if (value === undefined || value === null) + continue; + if (Array.isArray(value) || DataArray.isDataArray(value)) + value.forEach(v => result.push(v)); + else + result.push(value); + } + return this.lwrap(result); + } + into(key) { + let result = []; + for (let child of this.values) { + let value = child[key]; + if (value === undefined || value === null) + continue; + result.push(value); + } + return this.lwrap(result); + } + expand(key) { + let result = []; + let queue = [].concat(this.values); + while (queue.length > 0) { + let next = queue.pop(); + let value = next[key]; + if (value === undefined || value === null) + continue; + if (Array.isArray(value)) + value.forEach(v => queue.push(v)); + else if (value instanceof DataArrayImpl) + value.forEach(v => queue.push(v)); + else + queue.push(value); + result.push(next); + } + return this.lwrap(result); + } + forEach(f) { + for (let index = 0; index < this.values.length; index++) { + f(this.values[index], index, this.values); + } + } + array() { + return [].concat(this.values); + } + [Symbol.iterator]() { + return this.values[Symbol.iterator](); + } + toString() { + return "[" + this.values.join(", ") + "]"; + } +} +DataArrayImpl.ARRAY_FUNCTIONS = new Set([ + "where", + "filter", + "map", + "flatMap", + "mutate", + "slice", + "concat", + "indexOf", + "limit", + "find", + "findIndex", + "includes", + "join", + "sort", + "sortInPlace", + "groupBy", + "groupIn", + "distinct", + "every", + "some", + "none", + "first", + "last", + "to", + "into", + "lwrap", + "expand", + "forEach", + "length", + "values", + "array", + "defaultComparator", + "toString", + "settings", +]); +DataArrayImpl.ARRAY_PROXY = { + get: function (target, prop, reciever) { + if (typeof prop === "symbol") + return target[prop]; + else if (typeof prop === "number") + return target.values[prop]; + else if (prop === "constructor") + return target.values.constructor; + else if (!isNaN(parseInt(prop))) + return target.values[parseInt(prop)]; + else if (DataArrayImpl.ARRAY_FUNCTIONS.has(prop.toString())) + return target[prop.toString()]; + return target.to(prop); + }, +}; +/** Provides utility functions for generating data arrays. */ +var DataArray; +(function (DataArray) { + /** Create a new Dataview data array. */ + function wrap(raw, settings) { + if (isDataArray(raw)) + return raw; + return DataArrayImpl.wrap(raw, settings); + } + DataArray.wrap = wrap; + /** Create a new DataArray from an iterable object. */ + function from(raw, settings) { + if (isDataArray(raw)) + return raw; + let data = []; + for (let elem of raw) + data.push(elem); + return DataArrayImpl.wrap(data, settings); + } + DataArray.from = from; + /** Return true if the given object is a data array. */ + function isDataArray(obj) { + return obj instanceof DataArrayImpl; + } + DataArray.isDataArray = isDataArray; +})(DataArray || (DataArray = {})); +// A scary looking polyfill, sure, but it fixes up data array/array interop for us. +const oldArrayIsArray = Array.isArray; +Array.isArray = (arg) => { + return oldArrayIsArray(arg) || DataArray.isDataArray(arg); }; -/** Test-environment-friendly function which fetches the current system locale. */ -function currentLocale() { - if (typeof window === "undefined") - return "en-US"; - return window.navigator.language; +/** Test-environment-friendly function which fetches the current system locale. */ +function currentLocale() { + if (typeof window === "undefined") + return "en-US"; + return window.navigator.language; } -/** Render simple fields compactly, removing wrapping content like paragraph and span. */ -async function renderCompactMarkdown(markdown, container, sourcePath, component) { - let subcontainer = container.createSpan(); - await obsidian.MarkdownRenderer.renderMarkdown(markdown, subcontainer, sourcePath, component); - let paragraph = subcontainer.querySelector(":scope > p"); - if (subcontainer.children.length == 1 && paragraph) { - while (paragraph.firstChild) { - subcontainer.appendChild(paragraph.firstChild); - } - subcontainer.removeChild(paragraph); - } -} -/** Render a pre block with an error in it; returns the element to allow for dynamic updating. */ -function renderErrorPre(container, error) { - let pre = container.createEl("pre", { cls: ["dataview", "dataview-error"] }); - pre.appendText(error); - return pre; -} -/** Render a static codeblock. */ -function renderCodeBlock(container, source, language) { - let code = container.createEl("code", { cls: ["dataview"] }); - if (language) - code.classList.add("language-" + language); - code.appendText(source); - return code; -} -/** Prettily render a value into a container with the given settings. */ -async function renderValue(field, container, originFile, component, settings, expandList = false, context = "root", depth = 0) { - var _a, _b, _c; - // Prevent infinite recursion. - if (depth > settings.maxRecursiveRenderDepth) { - container.appendText("..."); - return; - } - if (Values.isNull(field)) { - await renderCompactMarkdown(settings.renderNullAs, container, originFile, component); - } - else if (Values.isDate(field)) { - container.appendText(renderMinimalDate(field, settings, currentLocale())); - } - else if (Values.isDuration(field)) { - container.appendText(renderMinimalDuration(field)); - } - else if (Values.isString(field) || Values.isBoolean(field) || Values.isNumber(field)) { - await renderCompactMarkdown("" + field, container, originFile, component); - } - else if (Values.isLink(field)) { - await renderCompactMarkdown(field.markdown(), container, originFile, component); - } - else if (Values.isHtml(field)) { - container.appendChild(field); - } - else if (Values.isWidget(field)) { - if (Widgets.isListPair(field)) { - await renderValue(field.key, container, originFile, component, settings, expandList, context, depth); - container.appendText(": "); - await renderValue(field.value, container, originFile, component, settings, expandList, context, depth); - } - else if (Widgets.isExternalLink(field)) { - let elem = document.createElement("a"); - elem.textContent = (_a = field.display) !== null && _a !== void 0 ? _a : field.url; - elem.rel = "noopener"; - elem.target = "_blank"; - elem.classList.add("external-link"); - elem.href = field.url; - container.appendChild(elem); - } - else { - container.appendText(``); - } - } - else if (Values.isFunction(field)) { - container.appendText(""); - } - else if (Values.isArray(field) || DataArray.isDataArray(field)) { - if (expandList) { - let list = container.createEl("ul", { - cls: [ - "dataview", - "dataview-ul", - context == "list" ? "dataview-result-list-ul" : "dataview-result-list-root-ul", - ], - }); - for (let child of field) { - let li = list.createEl("li", { cls: "dataview-result-list-li" }); - await renderValue(child, li, originFile, component, settings, expandList, "list", depth + 1); - } - } - else { - if (field.length == 0) { - container.appendText(""); - return; - } - let span = container.createEl("span", { cls: ["dataview", "dataview-result-list-span"] }); - let first = true; - for (let val of field) { - if (first) - first = false; - else - span.appendText(", "); - await renderValue(val, span, originFile, component, settings, expandList, "list", depth + 1); - } - } - } - else if (Values.isObject(field)) { - // Don't render classes in case they have recursive references; spoopy. - if (((_b = field === null || field === void 0 ? void 0 : field.constructor) === null || _b === void 0 ? void 0 : _b.name) && ((_c = field === null || field === void 0 ? void 0 : field.constructor) === null || _c === void 0 ? void 0 : _c.name) != "Object") { - container.appendText(`<${field.constructor.name}>`); - return; - } - if (expandList) { - let list = container.createEl("ul", { cls: ["dataview", "dataview-ul", "dataview-result-object-ul"] }); - for (let [key, value] of Object.entries(field)) { - let li = list.createEl("li", { cls: ["dataview", "dataview-li", "dataview-result-object-li"] }); - li.appendText(key + ": "); - await renderValue(value, li, originFile, component, settings, expandList, "list", depth + 1); - } - } - else { - if (Object.keys(field).length == 0) { - container.appendText(""); - return; - } - let span = container.createEl("span", { cls: ["dataview", "dataview-result-object-span"] }); - let first = true; - for (let [key, value] of Object.entries(field)) { - if (first) - first = false; - else - span.appendText(", "); - span.appendText(key + ": "); - await renderValue(value, span, originFile, component, settings, expandList, "list", depth + 1); - } - } - } - else { - container.appendText("Unrecognized: " + JSON.stringify(field)); - } +/** Render simple fields compactly, removing wrapping content like paragraph and span. */ +async function renderCompactMarkdown(markdown, container, sourcePath, component) { + let subcontainer = container.createSpan(); + await obsidian.MarkdownRenderer.renderMarkdown(markdown, subcontainer, sourcePath, component); + let paragraph = subcontainer.querySelector(":scope > p"); + if (subcontainer.children.length == 1 && paragraph) { + while (paragraph.firstChild) { + subcontainer.appendChild(paragraph.firstChild); + } + subcontainer.removeChild(paragraph); + } +} +/** Render a pre block with an error in it; returns the element to allow for dynamic updating. */ +function renderErrorPre(container, error) { + let pre = container.createEl("pre", { cls: ["dataview", "dataview-error"] }); + pre.appendText(error); + return pre; +} +/** Render a static codeblock. */ +function renderCodeBlock(container, source, language) { + let code = container.createEl("code", { cls: ["dataview"] }); + if (language) + code.classList.add("language-" + language); + code.appendText(source); + return code; +} +/** Prettily render a value into a container with the given settings. */ +async function renderValue(field, container, originFile, component, settings, expandList = false, context = "root", depth = 0) { + var _a, _b, _c; + // Prevent infinite recursion. + if (depth > settings.maxRecursiveRenderDepth) { + container.appendText("..."); + return; + } + if (Values.isNull(field)) { + await renderCompactMarkdown(settings.renderNullAs, container, originFile, component); + } + else if (Values.isDate(field)) { + container.appendText(renderMinimalDate(field, settings, currentLocale())); + } + else if (Values.isDuration(field)) { + container.appendText(renderMinimalDuration(field)); + } + else if (Values.isString(field) || Values.isBoolean(field) || Values.isNumber(field)) { + await renderCompactMarkdown("" + field, container, originFile, component); + } + else if (Values.isLink(field)) { + await renderCompactMarkdown(field.markdown(), container, originFile, component); + } + else if (Values.isHtml(field)) { + container.appendChild(field); + } + else if (Values.isWidget(field)) { + if (Widgets.isListPair(field)) { + await renderValue(field.key, container, originFile, component, settings, expandList, context, depth); + container.appendText(": "); + await renderValue(field.value, container, originFile, component, settings, expandList, context, depth); + } + else if (Widgets.isExternalLink(field)) { + let elem = document.createElement("a"); + elem.textContent = (_a = field.display) !== null && _a !== void 0 ? _a : field.url; + elem.rel = "noopener"; + elem.target = "_blank"; + elem.classList.add("external-link"); + elem.href = field.url; + container.appendChild(elem); + } + else { + container.appendText(``); + } + } + else if (Values.isFunction(field)) { + container.appendText(""); + } + else if (Values.isArray(field) || DataArray.isDataArray(field)) { + if (expandList) { + let list = container.createEl("ul", { + cls: [ + "dataview", + "dataview-ul", + context == "list" ? "dataview-result-list-ul" : "dataview-result-list-root-ul", + ], + }); + for (let child of field) { + let li = list.createEl("li", { cls: "dataview-result-list-li" }); + await renderValue(child, li, originFile, component, settings, expandList, "list", depth + 1); + } + } + else { + if (field.length == 0) { + container.appendText(""); + return; + } + let span = container.createEl("span", { cls: ["dataview", "dataview-result-list-span"] }); + let first = true; + for (let val of field) { + if (first) + first = false; + else + span.appendText(", "); + await renderValue(val, span, originFile, component, settings, expandList, "list", depth + 1); + } + } + } + else if (Values.isObject(field)) { + // Don't render classes in case they have recursive references; spoopy. + if (((_b = field === null || field === void 0 ? void 0 : field.constructor) === null || _b === void 0 ? void 0 : _b.name) && ((_c = field === null || field === void 0 ? void 0 : field.constructor) === null || _c === void 0 ? void 0 : _c.name) != "Object") { + container.appendText(`<${field.constructor.name}>`); + return; + } + if (expandList) { + let list = container.createEl("ul", { cls: ["dataview", "dataview-ul", "dataview-result-object-ul"] }); + for (let [key, value] of Object.entries(field)) { + let li = list.createEl("li", { cls: ["dataview", "dataview-li", "dataview-result-object-li"] }); + li.appendText(key + ": "); + await renderValue(value, li, originFile, component, settings, expandList, "list", depth + 1); + } + } + else { + if (Object.keys(field).length == 0) { + container.appendText(""); + return; + } + let span = container.createEl("span", { cls: ["dataview", "dataview-result-object-span"] }); + let first = true; + for (let [key, value] of Object.entries(field)) { + if (first) + first = false; + else + span.appendText(", "); + span.appendText(key + ": "); + await renderValue(value, span, originFile, component, settings, expandList, "list", depth + 1); + } + } + } + else { + container.appendText("Unrecognized: " + JSON.stringify(field)); + } } var papaparse_min = {exports: {}}; /* @license Papa Parse -v5.3.2 +v5.4.1 https://github.com/mholt/PapaParse License: MIT */ +papaparse_min.exports; (function (module, exports) { -!function(e,t){module.exports=t();}(commonjsGlobal,function s(){var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=n&&/blob:/i.test((f.location||{}).protocol),a={},h=0,b={parse:function(e,t){var i=(t=t||{}).dynamicTyping||!1;M(i)&&(t.dynamicTypingFunction=i,i={});if(t.dynamicTyping=i,t.transform=!!M(t.transform)&&t.transform,t.worker&&b.WORKERS_SUPPORTED){var r=function(){if(!b.WORKERS_SUPPORTED)return !1;var e=(i=f.URL||f.webkitURL||null,r=s.toString(),b.BLOB_URL||(b.BLOB_URL=i.createObjectURL(new Blob(["(",r,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var i,r;return t.onmessage=_,t.id=h++,a[t.id]=t}();return r.userStep=t.step,r.userChunk=t.chunk,r.userComplete=t.complete,r.userError=t.error,t.step=M(t.step),t.chunk=M(t.chunk),t.complete=M(t.complete),t.error=M(t.error),delete t.worker,void r.postMessage({input:e,config:t,workerId:r.id})}var n=null;b.NODE_STREAM_INPUT,"string"==typeof e?n=t.download?new l(t):new p(t):!0===e.readable&&M(e.read)&&M(e.on)?n=new g(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var n=!1,_=!0,m=",",y="\r\n",s='"',a=s+s,i=!1,r=null,o=!1;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||b.BAD_DELIMITERS.filter(function(e){return -1!==t.delimiter.indexOf(e)}).length||(m=t.delimiter);("boolean"==typeof t.quotes||"function"==typeof t.quotes||Array.isArray(t.quotes))&&(n=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(i=t.skipEmptyLines);"string"==typeof t.newline&&(y=t.newline);"string"==typeof t.quoteChar&&(s=t.quoteChar);"boolean"==typeof t.header&&(_=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");r=t.columns;}void 0!==t.escapeChar&&(a=t.escapeChar+s);("boolean"==typeof t.escapeFormulae||t.escapeFormulae instanceof RegExp)&&(o=t.escapeFormulae instanceof RegExp?t.escapeFormulae:/^[=+\-@\t\r].*$/);}();var h=new RegExp(j(s),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return u(null,e,i);if("object"==typeof e[0])return u(r||Object.keys(e[0]),e,i)}else if("object"==typeof e)return "string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields||r),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:"object"==typeof e.data[0]?Object.keys(e.data[0]):[]),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),u(e.fields||[],e.data||[],i);throw new Error("Unable to serialize unrecognized input");function u(e,t,i){var r="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(M(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0;}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!M(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0;},this._sendError=function(e){M(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1});};}function l(e){var r;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded();}:function(){this._readChunk();},this.stream=function(e){this._input=e,this._nextChunk();},this._readChunk=function(){if(this._finished)this._chunkLoaded();else {if(r=new XMLHttpRequest,this._config.withCredentials&&(r.withCredentials=this._config.withCredentials),n||(r.onload=v(this._chunkLoaded,this),r.onerror=v(this._chunkError,this)),r.open(this._config.downloadRequestBody?"POST":"GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)r.setRequestHeader(t,e[t]);}if(this._config.chunkSize){var i=this._start+this._config.chunkSize-1;r.setRequestHeader("Range","bytes="+this._start+"-"+i);}try{r.send(this._config.downloadRequestBody);}catch(e){this._chunkError(e.message);}n&&0===r.status&&this._chunkError();}},this._chunkLoaded=function(){4===r.readyState&&(r.status<200||400<=r.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:r.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return -1;return parseInt(t.substring(t.lastIndexOf("/")+1))}(r),this.parseChunk(r.responseText)));},this._chunkError=function(e){var t=r.statusText||e;this._sendError(new Error(t));};}function c(e){var r,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((r=new FileReader).onload=v(this._chunkLoaded,this),r.onerror=v(this._chunkError,this)):r=new FileReaderSync,this._nextChunk();},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result);},this._chunkError=function(){this._sendError(r.error);};}function p(e){var i;u.call(this,e=e||{}),this.stream=function(e){return i=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,t=this._config.chunkSize;return t?(e=i.substring(0,t),i=i.substring(t)):(e=i,i=""),this._finished=!i,this.parseChunk(e)}};}function g(e){u.call(this,e=e||{});var t=[],i=!0,r=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause();},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume();},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError);},this._checkIsFinished=function(){r&&1===t.length&&(this._finished=!0);},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):i=!0;},this._streamData=v(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),i&&(i=!1,this._checkIsFinished(),this.parseChunk(t.shift()));}catch(e){this._streamError(e);}},this),this._streamError=v(function(e){this._streamCleanUp(),this._sendError(e);},this),this._streamEnd=v(function(){this._streamCleanUp(),r=!0,this._streamData("");},this),this._streamCleanUp=v(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError);},this);}function i(m){var a,o,h,r=Math.pow(2,53),n=-r,s=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,u=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))$/,t=this,i=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(M(m.step)){var p=m.step;m.step=function(e){if(c=e,_())g();else {if(g(),0===c.data.length)return;i+=e.data.length,m.preview&&i>m.preview?o.abort():(c.data=c.data[0],p(c,t));}};}function y(e){return "greedy"===m.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function g(){return c&&h&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),h=!1),m.skipEmptyLines&&(c.data=c.data.filter(function(e){return !y(e)})),_()&&function(){if(!c)return;function e(e,t){M(m.transformHeader)&&(e=m.transformHeader(e,t)),l.push(e);}if(Array.isArray(c.data[0])){for(var t=0;_()&&t=l.length?"__parsed_extra":l[i]),m.transform&&(s=m.transform(s,n)),s=v(n,s),"__parsed_extra"===n?(r[n]=r[n]||[],r[n].push(s)):r[n]=s;}return m.header&&(i>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+i,f+t):i=r.length/2?"\r\n":"\r"}(e,r)),h=!1,m.delimiter)M(m.delimiter)&&(m.delimiter=m.delimiter(e),c.meta.delimiter=m.delimiter);else {var n=function(e,t,i,r,n){var s,a,o,h;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var u=0;u=D)return C(!0)}else for(m=F,F++;;){if(-1===(m=r.indexOf(S,m+1)))return i||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:F}),E();if(m===n-1)return E(r.substring(F,m).replace(_,S));if(S!==L||r[m+1]!==L){if(S===L||0===m||r[m-1]!==L){-1!==p&&p=D)return C(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:F}),m++;}}else m++;}return E();function k(e){h.push(e),d=F;}function b(e){var t=0;if(-1!==e){var i=r.substring(m+1,e);i&&""===i.trim()&&(t=i.length);}return t}function E(e){return i||(void 0===e&&(e=r.substring(F)),f.push(e),F=n,k(f),o&&R()),C()}function w(e){F=e,k(f),f=[],g=r.indexOf(x,F);}function C(e){return {data:h,errors:u,meta:{delimiter:O,linebreak:x,aborted:z,truncated:!!e,cursor:d+(t||0)}}}function R(){T(C()),h=[],u=[];}},this.abort=function(){z=!0;},this.getCharIndex=function(){return F};}function _(e){var t=e.data,i=a[t.workerId],r=!1;if(t.error)i.userError(t.error,t.file);else if(t.results&&t.results.data){var n={abort:function(){r=!0,m(t.workerId,{data:[],errors:[],meta:{aborted:!0}});},pause:y,resume:y};if(M(i.userStep)){for(var s=0;s=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(J(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0;}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!J(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0;},this._sendError=function(e){J(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1});};}function l(e){var i;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),h.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded();}:function(){this._readChunk();},this.stream=function(e){this._input=e,this._nextChunk();},this._readChunk=function(){if(this._finished)this._chunkLoaded();else {if(i=new XMLHttpRequest,this._config.withCredentials&&(i.withCredentials=this._config.withCredentials),n||(i.onload=v(this._chunkLoaded,this),i.onerror=v(this._chunkError,this)),i.open(this._config.downloadRequestBody?"POST":"GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)i.setRequestHeader(t,e[t]);}if(this._config.chunkSize){var r=this._start+this._config.chunkSize-1;i.setRequestHeader("Range","bytes="+this._start+"-"+r);}try{i.send(this._config.downloadRequestBody);}catch(e){this._chunkError(e.message);}n&&0===i.status&&this._chunkError();}},this._chunkLoaded=function(){4===i.readyState&&(i.status<200||400<=i.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:i.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return -1;return parseInt(t.substring(t.lastIndexOf("/")+1))}(i),this.parseChunk(i.responseText)));},this._chunkError=function(e){var t=i.statusText||e;this._sendError(new Error(t));};}function c(e){var i,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),h.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((i=new FileReader).onload=v(this._chunkLoaded,this),i.onerror=v(this._chunkError,this)):i=new FileReaderSync,this._nextChunk();},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result);},this._chunkError=function(){this._sendError(i.error);};}function p(e){var r;h.call(this,e=e||{}),this.stream=function(e){return r=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,t=this._config.chunkSize;return t?(e=r.substring(0,t),r=r.substring(t)):(e=r,r=""),this._finished=!r,this.parseChunk(e)}};}function g(e){h.call(this,e=e||{});var t=[],r=!0,i=!1;this.pause=function(){h.prototype.pause.apply(this,arguments),this._input.pause();},this.resume=function(){h.prototype.resume.apply(this,arguments),this._input.resume();},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError);},this._checkIsFinished=function(){i&&1===t.length&&(this._finished=!0);},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):r=!0;},this._streamData=v(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),r&&(r=!1,this._checkIsFinished(),this.parseChunk(t.shift()));}catch(e){this._streamError(e);}},this),this._streamError=v(function(e){this._streamCleanUp(),this._sendError(e);},this),this._streamEnd=v(function(){this._streamCleanUp(),i=!0,this._streamData("");},this),this._streamCleanUp=v(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError);},this);}function r(m){var a,o,u,i=Math.pow(2,53),n=-i,s=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,h=/^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/,t=this,r=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(J(m.step)){var p=m.step;m.step=function(e){if(c=e,_())g();else {if(g(),0===c.data.length)return;r+=e.data.length,m.preview&&r>m.preview?o.abort():(c.data=c.data[0],p(c,t));}};}function y(e){return "greedy"===m.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function g(){return c&&u&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),u=!1),m.skipEmptyLines&&(c.data=c.data.filter(function(e){return !y(e)})),_()&&function(){if(!c)return;function e(e,t){J(m.transformHeader)&&(e=m.transformHeader(e,t)),l.push(e);}if(Array.isArray(c.data[0])){for(var t=0;_()&&t=l.length?"__parsed_extra":l[r]),m.transform&&(s=m.transform(s,n)),s=v(n,s),"__parsed_extra"===n?(i[n]=i[n]||[],i[n].push(s)):i[n]=s;}return m.header&&(r>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+r,f+t):r=i.length/2?"\r\n":"\r"}(e,i)),u=!1,m.delimiter)J(m.delimiter)&&(m.delimiter=m.delimiter(e),c.meta.delimiter=m.delimiter);else {var n=function(e,t,r,i,n){var s,a,o,u;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var h=0;h=N)return L(!0)}else for(S=W,W++;;){if(-1===(S=i.indexOf(z,S+1)))return r||h.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:u.length,index:W}),T();if(S===n-1)return T(i.substring(W,S).replace(C,z));if(z!==K||i[S+1]!==K){if(z===K||0===S||i[S-1]!==K){-1!==w&&w=N)return L(!0);break}h.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:u.length,index:W}),S++;}}else S++;}return T();function I(e){u.push(e),d=W;}function A(e){var t=0;if(-1!==e){var r=i.substring(S+1,e);r&&""===r.trim()&&(t=r.length);}return t}function T(e){return r||(void 0===e&&(e=i.substring(W)),f.push(e),W=n,I(f),o&&F()),L()}function D(e){W=e,I(f),f=[],R=i.indexOf(P,W);}function L(e){return {data:u,errors:h,meta:{delimiter:M,linebreak:P,aborted:H,truncated:!!e,cursor:d+(t||0)}}}function F(){q(L()),u=[],h=[];}},this.abort=function(){H=!0;},this.getCharIndex=function(){return W};}function _(e){var t=e.data,r=a[t.workerId],i=!1;if(t.error)r.userError(t.error,t.file);else if(t.results&&t.results.data){var n={abort:function(){i=!0,m(t.workerId,{data:[],errors:[],meta:{aborted:!0}});},pause:y,resume:y};if(J(r.userStep)){for(var s=0;s" || op == ">=" || op == "!=" || op == "="; - } - Fields.isCompareOp = isCompareOp; - Fields.NULL = Fields.literal(null); +var papaparse_minExports = papaparse_min.exports; + +/** Utility methods for creating & comparing fields. */ +var Fields; +(function (Fields) { + function variable(name) { + return { type: "variable", name }; + } + Fields.variable = variable; + function literal(value) { + return { type: "literal", value }; + } + Fields.literal = literal; + function binaryOp(left, op, right) { + return { type: "binaryop", left, op, right }; + } + Fields.binaryOp = binaryOp; + function index(obj, index) { + return { type: "index", object: obj, index }; + } + Fields.index = index; + /** Converts a string in dot-notation-format into a variable which indexes. */ + function indexVariable(name) { + let parts = name.split("."); + let result = Fields.variable(parts[0]); + for (let index = 1; index < parts.length; index++) { + result = Fields.index(result, Fields.literal(parts[index])); + } + return result; + } + Fields.indexVariable = indexVariable; + function lambda(args, value) { + return { type: "lambda", arguments: args, value }; + } + Fields.lambda = lambda; + function func(func, args) { + return { type: "function", func, arguments: args }; + } + Fields.func = func; + function list(values) { + return { type: "list", values }; + } + Fields.list = list; + function object(values) { + return { type: "object", values }; + } + Fields.object = object; + function negate(child) { + return { type: "negated", child }; + } + Fields.negate = negate; + function isCompareOp(op) { + return op == "<=" || op == "<" || op == ">" || op == ">=" || op == "!=" || op == "="; + } + Fields.isCompareOp = isCompareOp; + Fields.NULL = Fields.literal(null); })(Fields || (Fields = {})); -/** AST implementation for queries over data sources. */ -/** Utility functions for creating and manipulating sources. */ -var Sources; -(function (Sources) { - /** Create a source which searches from a tag. */ - function tag(tag) { - return { type: "tag", tag }; - } - Sources.tag = tag; - /** Create a source which fetches from a CSV file. */ - function csv(path) { - return { type: "csv", path }; - } - Sources.csv = csv; - /** Create a source which searches for files under a folder prefix. */ - function folder(prefix) { - return { type: "folder", folder: prefix }; - } - Sources.folder = folder; - /** Create a source which searches for files which link to/from a given file. */ - function link(file, incoming) { - return { type: "link", file, direction: incoming ? "incoming" : "outgoing" }; - } - Sources.link = link; - /** Create a source which joins two sources by a logical operator (and/or). */ - function binaryOp(left, op, right) { - return { type: "binaryop", left, op, right }; - } - Sources.binaryOp = binaryOp; - /** Create a source which takes the intersection of two sources. */ - function and(left, right) { - return { type: "binaryop", left, op: "&", right }; - } - Sources.and = and; - /** Create a source which takes the union of two sources. */ - function or(left, right) { - return { type: "binaryop", left, op: "|", right }; - } - Sources.or = or; - /** Create a source which negates the underlying source. */ - function negate(child) { - return { type: "negate", child }; - } - Sources.negate = negate; - function empty() { - return { type: "empty" }; - } - Sources.empty = empty; +/** AST implementation for queries over data sources. */ +/** Utility functions for creating and manipulating sources. */ +var Sources; +(function (Sources) { + /** Create a source which searches from a tag. */ + function tag(tag) { + return { type: "tag", tag }; + } + Sources.tag = tag; + /** Create a source which fetches from a CSV file. */ + function csv(path) { + return { type: "csv", path }; + } + Sources.csv = csv; + /** Create a source which searches for files under a folder prefix. */ + function folder(prefix) { + return { type: "folder", folder: prefix }; + } + Sources.folder = folder; + /** Create a source which searches for files which link to/from a given file. */ + function link(file, incoming) { + return { type: "link", file, direction: incoming ? "incoming" : "outgoing" }; + } + Sources.link = link; + /** Create a source which joins two sources by a logical operator (and/or). */ + function binaryOp(left, op, right) { + return { type: "binaryop", left, op, right }; + } + Sources.binaryOp = binaryOp; + /** Create a source which takes the intersection of two sources. */ + function and(left, right) { + return { type: "binaryop", left, op: "&", right }; + } + Sources.and = and; + /** Create a source which takes the union of two sources. */ + function or(left, right) { + return { type: "binaryop", left, op: "|", right }; + } + Sources.or = or; + /** Create a source which negates the underlying source. */ + function negate(child) { + return { type: "negate", child }; + } + Sources.negate = negate; + function empty() { + return { type: "empty" }; + } + Sources.empty = empty; })(Sources || (Sources = {})); -/** Emoji regex without any additional flags. */ -const EMOJI_REGEX = new RegExp(emojiRegex(), ""); -/** Provides a lookup table for unit durations of the given type. */ -const DURATION_TYPES = { - year: Duration.fromObject({ years: 1 }), - years: Duration.fromObject({ years: 1 }), - yr: Duration.fromObject({ years: 1 }), - yrs: Duration.fromObject({ years: 1 }), - month: Duration.fromObject({ months: 1 }), - months: Duration.fromObject({ months: 1 }), - mo: Duration.fromObject({ months: 1 }), - mos: Duration.fromObject({ months: 1 }), - week: Duration.fromObject({ weeks: 1 }), - weeks: Duration.fromObject({ weeks: 1 }), - wk: Duration.fromObject({ weeks: 1 }), - wks: Duration.fromObject({ weeks: 1 }), - w: Duration.fromObject({ weeks: 1 }), - day: Duration.fromObject({ days: 1 }), - days: Duration.fromObject({ days: 1 }), - d: Duration.fromObject({ days: 1 }), - hour: Duration.fromObject({ hours: 1 }), - hours: Duration.fromObject({ hours: 1 }), - hr: Duration.fromObject({ hours: 1 }), - hrs: Duration.fromObject({ hours: 1 }), - h: Duration.fromObject({ hours: 1 }), - minute: Duration.fromObject({ minutes: 1 }), - minutes: Duration.fromObject({ minutes: 1 }), - min: Duration.fromObject({ minutes: 1 }), - mins: Duration.fromObject({ minutes: 1 }), - m: Duration.fromObject({ minutes: 1 }), - second: Duration.fromObject({ seconds: 1 }), - seconds: Duration.fromObject({ seconds: 1 }), - sec: Duration.fromObject({ seconds: 1 }), - secs: Duration.fromObject({ seconds: 1 }), - s: Duration.fromObject({ seconds: 1 }), -}; -/** Shorthand for common dates (relative to right now). */ -const DATE_SHORTHANDS = { - now: () => DateTime.local(), - today: () => DateTime.local().startOf("day"), - yesterday: () => DateTime.local() - .startOf("day") - .minus(Duration.fromObject({ days: 1 })), - tomorrow: () => DateTime.local() - .startOf("day") - .plus(Duration.fromObject({ days: 1 })), - sow: () => DateTime.local().startOf("week"), - "start-of-week": () => DateTime.local().startOf("week"), - eow: () => DateTime.local().endOf("week"), - "end-of-week": () => DateTime.local().endOf("week"), - soy: () => DateTime.local().startOf("year"), - "start-of-year": () => DateTime.local().startOf("year"), - eoy: () => DateTime.local().endOf("year"), - "end-of-year": () => DateTime.local().endOf("year"), - som: () => DateTime.local().startOf("month"), - "start-of-month": () => DateTime.local().startOf("month"), - eom: () => DateTime.local().endOf("month"), - "end-of-month": () => DateTime.local().endOf("month"), -}; -/** - * Keywords which cannot be used as variables directly. Use `row.` if it is a variable you have defined and want - * to access. - */ -const KEYWORDS = ["FROM", "WHERE", "LIMIT", "GROUP", "FLATTEN"]; -/////////////// -// Utilities // -/////////////// -/** Split on unescaped pipes in an inner link. */ -function splitOnUnescapedPipe(link) { - let pipe = -1; - while ((pipe = link.indexOf("|", pipe + 1)) >= 0) { - if (pipe > 0 && link[pipe - 1] == "\\") - continue; - return [link.substring(0, pipe).replace(/\\\|/g, "|"), link.substring(pipe + 1)]; - } - return [link.replace(/\\\|/g, "|"), undefined]; -} -/** Attempt to parse the inside of a link to pull out display name, subpath, etc. */ -function parseInnerLink(rawlink) { - let [link, display] = splitOnUnescapedPipe(rawlink); - return Link.infer(link, false, display); -} -/** Create a left-associative binary parser which parses the given sub-element and separator. Handles whitespace. */ -function createBinaryParser(child, sep, combine) { - return parsimmon_umd_min.exports.seqMap(child, parsimmon_umd_min.exports.seq(parsimmon_umd_min.exports.optWhitespace, sep, parsimmon_umd_min.exports.optWhitespace, child).many(), (first, rest) => { - if (rest.length == 0) - return first; - let node = combine(first, rest[0][1], rest[0][3]); - for (let index = 1; index < rest.length; index++) { - node = combine(node, rest[index][1], rest[index][3]); - } - return node; - }); -} -function chainOpt(base, ...funcs) { - return parsimmon_umd_min.exports.custom((success, failure) => { - return (input, i) => { - let result = base._(input, i); - if (!result.status) - return result; - for (let func of funcs) { - let next = func(result.value)._(input, result.index); - if (!next.status) - return result; - result = next; - } - return result; - }; - }); -} -const EXPRESSION = parsimmon_umd_min.exports.createLanguage({ - // A floating point number; the decimal point is optional. - number: q => parsimmon_umd_min.exports.regexp(/-?[0-9]+(\.[0-9]+)?/) - .map(str => Number.parseFloat(str)) - .desc("number"), - // A quote-surrounded string which supports escape characters ('\'). - string: q => parsimmon_umd_min.exports.string('"') - .then(parsimmon_umd_min.exports.alt(q.escapeCharacter, parsimmon_umd_min.exports.noneOf('"\\')) - .atLeast(0) - .map(chars => chars.join(""))) - .skip(parsimmon_umd_min.exports.string('"')) - .desc("string"), - escapeCharacter: _ => parsimmon_umd_min.exports.string("\\") - .then(parsimmon_umd_min.exports.any) - .map(escaped => { - // If we are escaping a backslash or a quote, pass in on in escaped form - if (escaped === '"') - return '"'; - if (escaped === "\\") - return "\\"; - else - return "\\" + escaped; - }), - // A boolean true/false value. - bool: _ => parsimmon_umd_min.exports.regexp(/true|false|True|False/) - .map(str => str.toLowerCase() == "true") - .desc("boolean ('true' or 'false')"), - // A tag of the form '#stuff/hello-there'. - tag: _ => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("#"), parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.regexp(/[^\u2000-\u206F\u2E00-\u2E7F'!"#$%&()*+,.:;<=>?@^`{|}~\[\]\\\s]/).desc("text")).many(), (start, rest) => start + rest.join("")).desc("tag ('#hello/stuff')"), - // A variable identifier, which is alphanumeric and must start with a letter or... emoji. - identifier: _ => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.regexp(/\p{Letter}/u), parsimmon_umd_min.exports.regexp(EMOJI_REGEX).desc("text")), parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.regexp(/[0-9\p{Letter}_-]/u), parsimmon_umd_min.exports.regexp(EMOJI_REGEX).desc("text")).many(), (first, rest) => first + rest.join("")).desc("variable identifier"), - // An Obsidian link of the form [[]]. - link: _ => parsimmon_umd_min.exports.regexp(/\[\[([^\[\]]*?)\]\]/u, 1) - .map(linkInner => parseInnerLink(linkInner)) - .desc("file link"), - // An embeddable link which can start with '!'. This overlaps with the normal negation operator, so it is only - // provided for metadata parsing. - embedLink: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("!").atMost(1), q.link, (p, l) => { - if (p.length > 0) - l.embed = true; - return l; - }).desc("file link"), - // Binary plus or minus operator. - binaryPlusMinus: _ => parsimmon_umd_min.exports.regexp(/\+|-/) - .map(str => str) - .desc("'+' or '-'"), - // Binary times or divide operator. - binaryMulDiv: _ => parsimmon_umd_min.exports.regexp(/\*|\/|%/) - .map(str => str) - .desc("'*' or '/' or '%'"), - // Binary comparison operator. - binaryCompareOp: _ => parsimmon_umd_min.exports.regexp(/>=|<=|!=|>|<|=/) - .map(str => str) - .desc("'>=' or '<=' or '!=' or '=' or '>' or '<'"), - // Binary boolean combination operator. - binaryBooleanOp: _ => parsimmon_umd_min.exports.regexp(/and|or|&|\|/i) - .map(str => { - if (str.toLowerCase() == "and") - return "&"; - else if (str.toLowerCase() == "or") - return "|"; - else - return str; - }) - .desc("'and' or 'or'"), - // A date which can be YYYY-MM[-DDTHH:mm:ss]. - rootDate: _ => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.regexp(/\d{4}/), parsimmon_umd_min.exports.string("-"), parsimmon_umd_min.exports.regexp(/\d{2}/), (year, _, month) => { - return DateTime.fromObject({ year: Number.parseInt(year), month: Number.parseInt(month) }); - }).desc("date in format YYYY-MM[-DDTHH-MM-SS.MS]"), - dateShorthand: _ => parsimmon_umd_min.exports.alt(...Object.keys(DATE_SHORTHANDS) - .sort((a, b) => b.length - a.length) - .map(parsimmon_umd_min.exports.string)), - date: q => chainOpt(q.rootDate, (ym) => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("-"), parsimmon_umd_min.exports.regexp(/\d{2}/), (_, day) => ym.set({ day: Number.parseInt(day) })), (ymd) => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("T"), parsimmon_umd_min.exports.regexp(/\d{2}/), (_, hour) => ymd.set({ hour: Number.parseInt(hour) })), (ymdh) => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string(":"), parsimmon_umd_min.exports.regexp(/\d{2}/), (_, minute) => ymdh.set({ minute: Number.parseInt(minute) })), (ymdhm) => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string(":"), parsimmon_umd_min.exports.regexp(/\d{2}/), (_, second) => ymdhm.set({ second: Number.parseInt(second) })), (ymdhms) => parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("."), parsimmon_umd_min.exports.regexp(/\d{3}/), (_, millisecond) => ymdhms.set({ millisecond: Number.parseInt(millisecond) })), parsimmon_umd_min.exports.succeed(ymdhms) // pass - ), (dt) => parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("+").or(parsimmon_umd_min.exports.string("-")), parsimmon_umd_min.exports.regexp(/\d{1,2}(:\d{2})?/), (pm, hr) => dt.setZone("UTC" + pm + hr, { keepLocalTime: true })), parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("Z"), () => dt.setZone("utc", { keepLocalTime: true })), parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("["), parsimmon_umd_min.exports.regexp(/[0-9A-Za-z+-\/]+/u), parsimmon_umd_min.exports.string("]"), (_a, zone, _b) => dt.setZone(zone, { keepLocalTime: true })))) - .assert((dt) => dt.isValid, "valid date") - .desc("date in format YYYY-MM[-DDTHH-MM-SS.MS]"), - // A date, plus various shorthand times of day it could be. - datePlus: q => parsimmon_umd_min.exports.alt(q.dateShorthand.map(d => DATE_SHORTHANDS[d]()), q.date).desc("date in format YYYY-MM[-DDTHH-MM-SS.MS] or in shorthand"), - // A duration of time. - durationType: _ => parsimmon_umd_min.exports.alt(...Object.keys(DURATION_TYPES) - .sort((a, b) => b.length - a.length) - .map(parsimmon_umd_min.exports.string)), - duration: q => parsimmon_umd_min.exports.seqMap(q.number, parsimmon_umd_min.exports.optWhitespace, q.durationType, (count, _, t) => DURATION_TYPES[t].mapUnits(x => x * count)) - .sepBy1(parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace).or(parsimmon_umd_min.exports.optWhitespace)) - .map(durations => durations.reduce((p, c) => p.plus(c))) - .desc("duration like 4hr2min"), - // A raw null value. - rawNull: _ => parsimmon_umd_min.exports.string("null"), - // Source parsing. - tagSource: q => q.tag.map(tag => Sources.tag(tag)), - csvSource: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("csv(").skip(parsimmon_umd_min.exports.optWhitespace), q.string, parsimmon_umd_min.exports.string(")"), (_1, path, _2) => Sources.csv(path)), - linkIncomingSource: q => q.link.map(link => Sources.link(link.path, true)), - linkOutgoingSource: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("outgoing(").skip(parsimmon_umd_min.exports.optWhitespace), q.link, parsimmon_umd_min.exports.string(")"), (_1, link, _2) => Sources.link(link.path, false)), - folderSource: q => q.string.map(str => Sources.folder(str)), - parensSource: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("("), parsimmon_umd_min.exports.optWhitespace, q.source, parsimmon_umd_min.exports.optWhitespace, parsimmon_umd_min.exports.string(")"), (_1, _2, field, _3, _4) => field), - negateSource: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.string("-"), parsimmon_umd_min.exports.string("!")), q.atomSource, (_, source) => Sources.negate(source)), - atomSource: q => parsimmon_umd_min.exports.alt(q.parensSource, q.negateSource, q.linkOutgoingSource, q.linkIncomingSource, q.folderSource, q.tagSource, q.csvSource), - binaryOpSource: q => createBinaryParser(q.atomSource, q.binaryBooleanOp.map(s => s), Sources.binaryOp), - source: q => q.binaryOpSource, - // Field parsing. - variableField: q => q.identifier - .chain(r => { - if (KEYWORDS.includes(r.toUpperCase())) { - return parsimmon_umd_min.exports.fail("Variable fields cannot be a keyword (" + KEYWORDS.join(" or ") + ")"); - } - else { - return parsimmon_umd_min.exports.succeed(Fields.variable(r)); - } - }) - .desc("variable"), - numberField: q => q.number.map(val => Fields.literal(val)).desc("number"), - stringField: q => q.string.map(val => Fields.literal(val)).desc("string"), - boolField: q => q.bool.map(val => Fields.literal(val)).desc("boolean"), - dateField: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("date("), parsimmon_umd_min.exports.optWhitespace, q.datePlus, parsimmon_umd_min.exports.optWhitespace, parsimmon_umd_min.exports.string(")"), (prefix, _1, date, _2, postfix) => Fields.literal(date)).desc("date"), - durationField: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("dur("), parsimmon_umd_min.exports.optWhitespace, q.duration, parsimmon_umd_min.exports.optWhitespace, parsimmon_umd_min.exports.string(")"), (prefix, _1, dur, _2, postfix) => Fields.literal(dur)).desc("duration"), - nullField: q => q.rawNull.map(_ => Fields.NULL), - linkField: q => q.link.map(f => Fields.literal(f)), - listField: q => q.field - .sepBy(parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace)) - .wrap(parsimmon_umd_min.exports.string("[").skip(parsimmon_umd_min.exports.optWhitespace), parsimmon_umd_min.exports.optWhitespace.then(parsimmon_umd_min.exports.string("]"))) - .map(l => Fields.list(l)) - .desc("list ('[1, 2, 3]')"), - objectField: q => parsimmon_umd_min.exports.seqMap(q.identifier.or(q.string), parsimmon_umd_min.exports.string(":").trim(parsimmon_umd_min.exports.optWhitespace), q.field, (name, _sep, value) => { - return { name, value }; - }) - .sepBy(parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace)) - .wrap(parsimmon_umd_min.exports.string("{").skip(parsimmon_umd_min.exports.optWhitespace), parsimmon_umd_min.exports.optWhitespace.then(parsimmon_umd_min.exports.string("}"))) - .map(vals => { - let res = {}; - for (let entry of vals) - res[entry.name] = entry.value; - return Fields.object(res); - }) - .desc("object ('{ a: 1, b: 2 }')"), - atomInlineField: q => parsimmon_umd_min.exports.alt(q.date, q.duration.map(d => normalizeDuration(d)), q.string, q.tag, q.embedLink, q.bool, q.number, q.rawNull), - inlineFieldList: q => q.atomInlineField.sepBy(parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace).lookahead(q.atomInlineField)), - inlineField: q => parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.seqMap(q.atomInlineField, parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace), q.inlineFieldList, (f, _s, l) => [f].concat(l)), q.atomInlineField), - atomField: q => parsimmon_umd_min.exports.alt( - // Place embed links above negated fields as they are the special parser case '![[thing]]' and are generally unambigious. - q.embedLink.map(l => Fields.literal(l)), q.negatedField, q.linkField, q.listField, q.objectField, q.lambdaField, q.parensField, q.boolField, q.numberField, q.stringField, q.dateField, q.durationField, q.nullField, q.variableField), - indexField: q => parsimmon_umd_min.exports.seqMap(q.atomField, parsimmon_umd_min.exports.alt(q.dotPostfix, q.indexPostfix, q.functionPostfix).many(), (obj, postfixes) => { - let result = obj; - for (let post of postfixes) { - switch (post.type) { - case "dot": - result = Fields.index(result, Fields.literal(post.field)); - break; - case "index": - result = Fields.index(result, post.field); - break; - case "function": - result = Fields.func(result, post.fields); - break; - } - } - return result; - }), - negatedField: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("!"), q.indexField, (_, field) => Fields.negate(field)).desc("negated field"), - parensField: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("("), parsimmon_umd_min.exports.optWhitespace, q.field, parsimmon_umd_min.exports.optWhitespace, parsimmon_umd_min.exports.string(")"), (_1, _2, field, _3, _4) => field), - lambdaField: q => parsimmon_umd_min.exports.seqMap(q.identifier - .sepBy(parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace)) - .wrap(parsimmon_umd_min.exports.string("(").trim(parsimmon_umd_min.exports.optWhitespace), parsimmon_umd_min.exports.string(")").trim(parsimmon_umd_min.exports.optWhitespace)), parsimmon_umd_min.exports.string("=>").trim(parsimmon_umd_min.exports.optWhitespace), q.field, (ident, _ignore, value) => { - return { type: "lambda", arguments: ident, value }; - }), - dotPostfix: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("."), q.identifier, (_, field) => { - return { type: "dot", field: field }; - }), - indexPostfix: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("["), parsimmon_umd_min.exports.optWhitespace, q.field, parsimmon_umd_min.exports.optWhitespace, parsimmon_umd_min.exports.string("]"), (_, _2, field, _3, _4) => { - return { type: "index", field }; - }), - functionPostfix: q => parsimmon_umd_min.exports.seqMap(parsimmon_umd_min.exports.string("("), parsimmon_umd_min.exports.optWhitespace, q.field.sepBy(parsimmon_umd_min.exports.string(",").trim(parsimmon_umd_min.exports.optWhitespace)), parsimmon_umd_min.exports.optWhitespace, parsimmon_umd_min.exports.string(")"), (_, _1, fields, _2, _3) => { - return { type: "function", fields }; - }), - // The precedence hierarchy of operators - multiply/divide, add/subtract, compare, and then boolean operations. - binaryMulDivField: q => createBinaryParser(q.indexField, q.binaryMulDiv, Fields.binaryOp), - binaryPlusMinusField: q => createBinaryParser(q.binaryMulDivField, q.binaryPlusMinus, Fields.binaryOp), - binaryCompareField: q => createBinaryParser(q.binaryPlusMinusField, q.binaryCompareOp, Fields.binaryOp), - binaryBooleanField: q => createBinaryParser(q.binaryCompareField, q.binaryBooleanOp, Fields.binaryOp), - binaryOpField: q => q.binaryBooleanField, - field: q => q.binaryOpField, -}); -/** - * Attempt to parse a field from the given text, returning a string error if the - * parse failed. - */ -function parseField(text) { - try { - return Result.success(EXPRESSION.field.tryParse(text)); - } - catch (error) { - return Result.failure("" + error); - } +/** Emoji regex without any additional flags. */ +const EMOJI_REGEX = new RegExp(emojiRegex(), ""); +/** Provides a lookup table for unit durations of the given type. */ +const DURATION_TYPES = { + year: Duration.fromObject({ years: 1 }), + years: Duration.fromObject({ years: 1 }), + yr: Duration.fromObject({ years: 1 }), + yrs: Duration.fromObject({ years: 1 }), + month: Duration.fromObject({ months: 1 }), + months: Duration.fromObject({ months: 1 }), + mo: Duration.fromObject({ months: 1 }), + mos: Duration.fromObject({ months: 1 }), + week: Duration.fromObject({ weeks: 1 }), + weeks: Duration.fromObject({ weeks: 1 }), + wk: Duration.fromObject({ weeks: 1 }), + wks: Duration.fromObject({ weeks: 1 }), + w: Duration.fromObject({ weeks: 1 }), + day: Duration.fromObject({ days: 1 }), + days: Duration.fromObject({ days: 1 }), + d: Duration.fromObject({ days: 1 }), + hour: Duration.fromObject({ hours: 1 }), + hours: Duration.fromObject({ hours: 1 }), + hr: Duration.fromObject({ hours: 1 }), + hrs: Duration.fromObject({ hours: 1 }), + h: Duration.fromObject({ hours: 1 }), + minute: Duration.fromObject({ minutes: 1 }), + minutes: Duration.fromObject({ minutes: 1 }), + min: Duration.fromObject({ minutes: 1 }), + mins: Duration.fromObject({ minutes: 1 }), + m: Duration.fromObject({ minutes: 1 }), + second: Duration.fromObject({ seconds: 1 }), + seconds: Duration.fromObject({ seconds: 1 }), + sec: Duration.fromObject({ seconds: 1 }), + secs: Duration.fromObject({ seconds: 1 }), + s: Duration.fromObject({ seconds: 1 }), +}; +/** Shorthand for common dates (relative to right now). */ +const DATE_SHORTHANDS = { + now: () => DateTime.local(), + today: () => DateTime.local().startOf("day"), + yesterday: () => DateTime.local() + .startOf("day") + .minus(Duration.fromObject({ days: 1 })), + tomorrow: () => DateTime.local() + .startOf("day") + .plus(Duration.fromObject({ days: 1 })), + sow: () => DateTime.local().startOf("week"), + "start-of-week": () => DateTime.local().startOf("week"), + eow: () => DateTime.local().endOf("week"), + "end-of-week": () => DateTime.local().endOf("week"), + soy: () => DateTime.local().startOf("year"), + "start-of-year": () => DateTime.local().startOf("year"), + eoy: () => DateTime.local().endOf("year"), + "end-of-year": () => DateTime.local().endOf("year"), + som: () => DateTime.local().startOf("month"), + "start-of-month": () => DateTime.local().startOf("month"), + eom: () => DateTime.local().endOf("month"), + "end-of-month": () => DateTime.local().endOf("month"), +}; +/** + * Keywords which cannot be used as variables directly. Use `row.` if it is a variable you have defined and want + * to access. + */ +const KEYWORDS = ["FROM", "WHERE", "LIMIT", "GROUP", "FLATTEN"]; +/////////////// +// Utilities // +/////////////// +/** Split on unescaped pipes in an inner link. */ +function splitOnUnescapedPipe(link) { + let pipe = -1; + while ((pipe = link.indexOf("|", pipe + 1)) >= 0) { + if (pipe > 0 && link[pipe - 1] == "\\") + continue; + return [link.substring(0, pipe).replace(/\\\|/g, "|"), link.substring(pipe + 1)]; + } + return [link.replace(/\\\|/g, "|"), undefined]; +} +/** Attempt to parse the inside of a link to pull out display name, subpath, etc. */ +function parseInnerLink(rawlink) { + let [link, display] = splitOnUnescapedPipe(rawlink); + return Link.infer(link, false, display); +} +/** Create a left-associative binary parser which parses the given sub-element and separator. Handles whitespace. */ +function createBinaryParser(child, sep, combine) { + return parsimmon_umd_minExports.seqMap(child, parsimmon_umd_minExports.seq(parsimmon_umd_minExports.optWhitespace, sep, parsimmon_umd_minExports.optWhitespace, child).many(), (first, rest) => { + if (rest.length == 0) + return first; + let node = combine(first, rest[0][1], rest[0][3]); + for (let index = 1; index < rest.length; index++) { + node = combine(node, rest[index][1], rest[index][3]); + } + return node; + }); +} +function chainOpt(base, ...funcs) { + return parsimmon_umd_minExports.custom((success, failure) => { + return (input, i) => { + let result = base._(input, i); + if (!result.status) + return result; + for (let func of funcs) { + let next = func(result.value)._(input, result.index); + if (!next.status) + return result; + result = next; + } + return result; + }; + }); +} +const EXPRESSION = parsimmon_umd_minExports.createLanguage({ + // A floating point number; the decimal point is optional. + number: q => parsimmon_umd_minExports.regexp(/-?[0-9]+(\.[0-9]+)?/) + .map(str => Number.parseFloat(str)) + .desc("number"), + // A quote-surrounded string which supports escape characters ('\'). + string: q => parsimmon_umd_minExports.string('"') + .then(parsimmon_umd_minExports.alt(q.escapeCharacter, parsimmon_umd_minExports.noneOf('"\\')) + .atLeast(0) + .map(chars => chars.join(""))) + .skip(parsimmon_umd_minExports.string('"')) + .desc("string"), + escapeCharacter: _ => parsimmon_umd_minExports.string("\\") + .then(parsimmon_umd_minExports.any) + .map(escaped => { + // If we are escaping a backslash or a quote, pass in on in escaped form + if (escaped === '"') + return '"'; + if (escaped === "\\") + return "\\"; + else + return "\\" + escaped; + }), + // A boolean true/false value. + bool: _ => parsimmon_umd_minExports.regexp(/true|false|True|False/) + .map(str => str.toLowerCase() == "true") + .desc("boolean ('true' or 'false')"), + // A tag of the form '#stuff/hello-there'. + tag: _ => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("#"), parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/[^\u2000-\u206F\u2E00-\u2E7F'!"#$%&()*+,.:;<=>?@^`{|}~\[\]\\\s]/).desc("text")).many(), (start, rest) => start + rest.join("")).desc("tag ('#hello/stuff')"), + // A variable identifier, which is alphanumeric and must start with a letter or... emoji. + identifier: _ => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/\p{Letter}/u), parsimmon_umd_minExports.regexp(EMOJI_REGEX).desc("text")), parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/[0-9\p{Letter}_-]/u), parsimmon_umd_minExports.regexp(EMOJI_REGEX).desc("text")).many(), (first, rest) => first + rest.join("")).desc("variable identifier"), + // An Obsidian link of the form [[]]. + link: _ => parsimmon_umd_minExports.regexp(/\[\[([^\[\]]*?)\]\]/u, 1) + .map(linkInner => parseInnerLink(linkInner)) + .desc("file link"), + // An embeddable link which can start with '!'. This overlaps with the normal negation operator, so it is only + // provided for metadata parsing. + embedLink: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("!").atMost(1), q.link, (p, l) => { + if (p.length > 0) + l.embed = true; + return l; + }).desc("file link"), + // Binary plus or minus operator. + binaryPlusMinus: _ => parsimmon_umd_minExports.regexp(/\+|-/) + .map(str => str) + .desc("'+' or '-'"), + // Binary times or divide operator. + binaryMulDiv: _ => parsimmon_umd_minExports.regexp(/\*|\/|%/) + .map(str => str) + .desc("'*' or '/' or '%'"), + // Binary comparison operator. + binaryCompareOp: _ => parsimmon_umd_minExports.regexp(/>=|<=|!=|>|<|=/) + .map(str => str) + .desc("'>=' or '<=' or '!=' or '=' or '>' or '<'"), + // Binary boolean combination operator. + binaryBooleanOp: _ => parsimmon_umd_minExports.regexp(/and|or|&|\|/i) + .map(str => { + if (str.toLowerCase() == "and") + return "&"; + else if (str.toLowerCase() == "or") + return "|"; + else + return str; + }) + .desc("'and' or 'or'"), + // A date which can be YYYY-MM[-DDTHH:mm:ss]. + rootDate: _ => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/\d{4}/), parsimmon_umd_minExports.string("-"), parsimmon_umd_minExports.regexp(/\d{2}/), (year, _, month) => { + return DateTime.fromObject({ year: Number.parseInt(year), month: Number.parseInt(month) }); + }).desc("date in format YYYY-MM[-DDTHH-MM-SS.MS]"), + dateShorthand: _ => parsimmon_umd_minExports.alt(...Object.keys(DATE_SHORTHANDS) + .sort((a, b) => b.length - a.length) + .map(parsimmon_umd_minExports.string)), + date: q => chainOpt(q.rootDate, (ym) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("-"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, day) => ym.set({ day: Number.parseInt(day) })), (ymd) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("T"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, hour) => ymd.set({ hour: Number.parseInt(hour) })), (ymdh) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string(":"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, minute) => ymdh.set({ minute: Number.parseInt(minute) })), (ymdhm) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string(":"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, second) => ymdhm.set({ second: Number.parseInt(second) })), (ymdhms) => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("."), parsimmon_umd_minExports.regexp(/\d{3}/), (_, millisecond) => ymdhms.set({ millisecond: Number.parseInt(millisecond) })), parsimmon_umd_minExports.succeed(ymdhms) // pass + ), (dt) => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("+").or(parsimmon_umd_minExports.string("-")), parsimmon_umd_minExports.regexp(/\d{1,2}(:\d{2})?/), (pm, hr) => dt.setZone("UTC" + pm + hr, { keepLocalTime: true })), parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("Z"), () => dt.setZone("utc", { keepLocalTime: true })), parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("["), parsimmon_umd_minExports.regexp(/[0-9A-Za-z+-\/]+/u), parsimmon_umd_minExports.string("]"), (_a, zone, _b) => dt.setZone(zone, { keepLocalTime: true })))) + .assert((dt) => dt.isValid, "valid date") + .desc("date in format YYYY-MM[-DDTHH-MM-SS.MS]"), + // A date, plus various shorthand times of day it could be. + datePlus: q => parsimmon_umd_minExports.alt(q.dateShorthand.map(d => DATE_SHORTHANDS[d]()), q.date).desc("date in format YYYY-MM[-DDTHH-MM-SS.MS] or in shorthand"), + // A duration of time. + durationType: _ => parsimmon_umd_minExports.alt(...Object.keys(DURATION_TYPES) + .sort((a, b) => b.length - a.length) + .map(parsimmon_umd_minExports.string)), + duration: q => parsimmon_umd_minExports.seqMap(q.number, parsimmon_umd_minExports.optWhitespace, q.durationType, (count, _, t) => DURATION_TYPES[t].mapUnits(x => x * count)) + .sepBy1(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace).or(parsimmon_umd_minExports.optWhitespace)) + .map(durations => durations.reduce((p, c) => p.plus(c))) + .desc("duration like 4hr2min"), + // A raw null value. + rawNull: _ => parsimmon_umd_minExports.string("null"), + // Source parsing. + tagSource: q => q.tag.map(tag => Sources.tag(tag)), + csvSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("csv(").skip(parsimmon_umd_minExports.optWhitespace), q.string, parsimmon_umd_minExports.string(")"), (_1, path, _2) => Sources.csv(path)), + linkIncomingSource: q => q.link.map(link => Sources.link(link.path, true)), + linkOutgoingSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("outgoing(").skip(parsimmon_umd_minExports.optWhitespace), q.link, parsimmon_umd_minExports.string(")"), (_1, link, _2) => Sources.link(link.path, false)), + folderSource: q => q.string.map(str => Sources.folder(str)), + parensSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("("), parsimmon_umd_minExports.optWhitespace, q.source, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (_1, _2, field, _3, _4) => field), + negateSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.alt(parsimmon_umd_minExports.string("-"), parsimmon_umd_minExports.string("!")), q.atomSource, (_, source) => Sources.negate(source)), + atomSource: q => parsimmon_umd_minExports.alt(q.parensSource, q.negateSource, q.linkOutgoingSource, q.linkIncomingSource, q.folderSource, q.tagSource, q.csvSource), + binaryOpSource: q => createBinaryParser(q.atomSource, q.binaryBooleanOp.map(s => s), Sources.binaryOp), + source: q => q.binaryOpSource, + // Field parsing. + variableField: q => q.identifier + .chain(r => { + if (KEYWORDS.includes(r.toUpperCase())) { + return parsimmon_umd_minExports.fail("Variable fields cannot be a keyword (" + KEYWORDS.join(" or ") + ")"); + } + else { + return parsimmon_umd_minExports.succeed(Fields.variable(r)); + } + }) + .desc("variable"), + numberField: q => q.number.map(val => Fields.literal(val)).desc("number"), + stringField: q => q.string.map(val => Fields.literal(val)).desc("string"), + boolField: q => q.bool.map(val => Fields.literal(val)).desc("boolean"), + dateField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("date("), parsimmon_umd_minExports.optWhitespace, q.datePlus, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (prefix, _1, date, _2, postfix) => Fields.literal(date)).desc("date"), + durationField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("dur("), parsimmon_umd_minExports.optWhitespace, q.duration, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (prefix, _1, dur, _2, postfix) => Fields.literal(dur)).desc("duration"), + nullField: q => q.rawNull.map(_ => Fields.NULL), + linkField: q => q.link.map(f => Fields.literal(f)), + listField: q => q.field + .sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)) + .wrap(parsimmon_umd_minExports.string("[").skip(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.optWhitespace.then(parsimmon_umd_minExports.string("]"))) + .map(l => Fields.list(l)) + .desc("list ('[1, 2, 3]')"), + objectField: q => parsimmon_umd_minExports.seqMap(q.identifier.or(q.string), parsimmon_umd_minExports.string(":").trim(parsimmon_umd_minExports.optWhitespace), q.field, (name, _sep, value) => { + return { name, value }; + }) + .sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)) + .wrap(parsimmon_umd_minExports.string("{").skip(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.optWhitespace.then(parsimmon_umd_minExports.string("}"))) + .map(vals => { + let res = {}; + for (let entry of vals) + res[entry.name] = entry.value; + return Fields.object(res); + }) + .desc("object ('{ a: 1, b: 2 }')"), + atomInlineField: q => parsimmon_umd_minExports.alt(q.date, q.duration.map(d => normalizeDuration(d)), q.string, q.tag, q.embedLink, q.bool, q.number, q.rawNull), + inlineFieldList: q => q.atomInlineField.sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace).lookahead(q.atomInlineField)), + inlineField: q => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.seqMap(q.atomInlineField, parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace), q.inlineFieldList, (f, _s, l) => [f].concat(l)), q.atomInlineField), + atomField: q => parsimmon_umd_minExports.alt( + // Place embed links above negated fields as they are the special parser case '![[thing]]' and are generally unambigious. + q.embedLink.map(l => Fields.literal(l)), q.negatedField, q.linkField, q.listField, q.objectField, q.lambdaField, q.parensField, q.boolField, q.numberField, q.stringField, q.dateField, q.durationField, q.nullField, q.variableField), + indexField: q => parsimmon_umd_minExports.seqMap(q.atomField, parsimmon_umd_minExports.alt(q.dotPostfix, q.indexPostfix, q.functionPostfix).many(), (obj, postfixes) => { + let result = obj; + for (let post of postfixes) { + switch (post.type) { + case "dot": + result = Fields.index(result, Fields.literal(post.field)); + break; + case "index": + result = Fields.index(result, post.field); + break; + case "function": + result = Fields.func(result, post.fields); + break; + } + } + return result; + }), + negatedField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("!"), q.indexField, (_, field) => Fields.negate(field)).desc("negated field"), + parensField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("("), parsimmon_umd_minExports.optWhitespace, q.field, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (_1, _2, field, _3, _4) => field), + lambdaField: q => parsimmon_umd_minExports.seqMap(q.identifier + .sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)) + .wrap(parsimmon_umd_minExports.string("(").trim(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.string(")").trim(parsimmon_umd_minExports.optWhitespace)), parsimmon_umd_minExports.string("=>").trim(parsimmon_umd_minExports.optWhitespace), q.field, (ident, _ignore, value) => { + return { type: "lambda", arguments: ident, value }; + }), + dotPostfix: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("."), q.identifier, (_, field) => { + return { type: "dot", field: field }; + }), + indexPostfix: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("["), parsimmon_umd_minExports.optWhitespace, q.field, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string("]"), (_, _2, field, _3, _4) => { + return { type: "index", field }; + }), + functionPostfix: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("("), parsimmon_umd_minExports.optWhitespace, q.field.sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)), parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (_, _1, fields, _2, _3) => { + return { type: "function", fields }; + }), + // The precedence hierarchy of operators - multiply/divide, add/subtract, compare, and then boolean operations. + binaryMulDivField: q => createBinaryParser(q.indexField, q.binaryMulDiv, Fields.binaryOp), + binaryPlusMinusField: q => createBinaryParser(q.binaryMulDivField, q.binaryPlusMinus, Fields.binaryOp), + binaryCompareField: q => createBinaryParser(q.binaryPlusMinusField, q.binaryCompareOp, Fields.binaryOp), + binaryBooleanField: q => createBinaryParser(q.binaryCompareField, q.binaryBooleanOp, Fields.binaryOp), + binaryOpField: q => q.binaryBooleanField, + field: q => q.binaryOpField, +}); +/** + * Attempt to parse a field from the given text, returning a string error if the + * parse failed. + */ +function parseField(text) { + try { + return Result.success(EXPRESSION.field.tryParse(text)); + } + catch (error) { + return Result.failure("" + error); + } } -/** Parse inline fields and other embedded metadata in a line. */ -/** The wrapper characters that can be used to define an inline field. */ -const INLINE_FIELD_WRAPPERS = Object.freeze({ - "[": "]", - "(": ")", -}); -/** - * Find a matching closing bracket that occurs at or after `start`, respecting nesting and escapes. If found, - * returns the value contained within and the string index after the end of the value. - */ -function findClosing(line, start, open, close) { - let nesting = 0; - let escaped = false; - for (let index = start; index < line.length; index++) { - let char = line.charAt(index); - // Allows for double escapes like '\\' to be rendered normally. - if (char == "\\") { - escaped = !escaped; - continue; - } - // If escaped, ignore the next character for computing nesting, regardless of what it is. - if (escaped) { - escaped = false; - continue; - } - if (char == open) - nesting++; - else if (char == close) - nesting--; - // Only occurs if we are on a close character and trhere is no more nesting. - if (nesting < 0) - return { value: line.substring(start, index).trim(), endIndex: index + 1 }; - escaped = false; - } - return undefined; -} -/** Find the '::' separator in an inline field. */ -function findSeparator(line, start) { - let sep = line.indexOf("::", start); - if (sep < 0) - return undefined; - return { key: line.substring(start, sep).trim(), valueIndex: sep + 2 }; -} -/** Try to completely parse an inline field starting at the given position. Assuems `start` is on a wrapping character. */ -function findSpecificInlineField(line, start) { - let open = line.charAt(start); - let key = findSeparator(line, start + 1); - if (key === undefined) - return undefined; - // Fail the match if we find any separator characters (not allowed in keys). - for (let sep of Object.keys(INLINE_FIELD_WRAPPERS).concat(Object.values(INLINE_FIELD_WRAPPERS))) { - if (key.key.includes(sep)) - return undefined; - } - let value = findClosing(line, key.valueIndex, open, INLINE_FIELD_WRAPPERS[open]); - if (value === undefined) - return undefined; - return { - key: key.key, - value: value.value, - start: start, - startValue: key.valueIndex, - end: value.endIndex, - wrapping: open, - }; -} -/** Parse a textual inline field value into something we can work with. */ -function parseInlineValue(value) { - // Empty inline values (i.e., no text) should map to null to match long-term Dataview semantics. - // Null is also a more universal type to deal with than strings, since all functions accept nulls. - if (value.trim() == "") - return null; - // The stripped literal field parser understands all of the non-array/non-object fields and can parse them for us. - // Inline field objects are not currently supported; inline array objects have to be handled by the parser - // separately. - let inline = EXPRESSION.inlineField.parse(value); - if (inline.status) - return inline.value; - else - return value; -} -/** Extracts inline fields of the form '[key:: value]' from a line of text. This is done in a relatively - * "robust" way to avoid failing due to bad nesting or other interfering Markdown symbols: - * - * - Look for any wrappers ('[' and '(') in the line, trying to parse whatever comes after it as an inline key::. - * - If successful, scan until you find a matching end bracket, and parse whatever remains as an inline value. - */ -function extractInlineFields(line, includeTaskFields = false) { - let fields = []; - for (let wrapper of Object.keys(INLINE_FIELD_WRAPPERS)) { - let foundIndex = line.indexOf(wrapper); - while (foundIndex >= 0) { - let parsedField = findSpecificInlineField(line, foundIndex); - if (!parsedField) { - foundIndex = line.indexOf(wrapper, foundIndex + 1); - continue; - } - fields.push(parsedField); - foundIndex = line.indexOf(wrapper, parsedField.end); - } - } - if (includeTaskFields) - fields = fields.concat(extractSpecialTaskFields(line)); - fields.sort((a, b) => a.start - b.start); - let filteredFields = []; - for (let i = 0; i < fields.length; i++) { - if (i == 0 || filteredFields[filteredFields.length - 1].end < fields[i].start) { - filteredFields.push(fields[i]); - } - } - return filteredFields; -} -/** Validates that a raw field name has a valid form. */ -const FULL_LINE_KEY_PART = parsimmon_umd_min.exports.alt(parsimmon_umd_min.exports.regexp(new RegExp(emojiRegex(), "u")), parsimmon_umd_min.exports.regexp(/[0-9\p{Letter}\w\s_/-]+/u)) - .many() - .map(parts => parts.join("")); -parsimmon_umd_min.exports.regexp(/[^0-9\w\p{Letter}]*/u) - .then(FULL_LINE_KEY_PART) - .skip(parsimmon_umd_min.exports.regexp(/[_\*~`]*/u)); -const CREATED_DATE_REGEX = /\u{2795}\s*(\d{4}-\d{2}-\d{2})/u; -const DUE_DATE_REGEX = /(?:\u{1F4C5}|\u{1F4C6}|\u{1F5D3}\u{FE0F}?)\s*(\d{4}-\d{2}-\d{2})/u; -const DONE_DATE_REGEX = /\u{2705}\s*(\d{4}-\d{2}-\d{2})/u; -const SCHEDULED_DATE_REGEX = /[\u{23F3}\u{231B}]\s*(\d{4}-\d{2}-\d{2})/u; -const START_DATE_REGEX = /\u{1F6EB}\s*(\d{4}-\d{2}-\d{2})/u; -const EMOJI_REGEXES = [ - { regex: CREATED_DATE_REGEX, key: "created" }, - { regex: START_DATE_REGEX, key: "start" }, - { regex: SCHEDULED_DATE_REGEX, key: "scheduled" }, - { regex: DUE_DATE_REGEX, key: "due" }, - { regex: DONE_DATE_REGEX, key: "completion" }, -]; -/** Parse special completed/due/done task fields which are marked via emoji. */ -function extractSpecialTaskFields(line) { - let results = []; - for (let { regex, key } of EMOJI_REGEXES) { - const match = regex.exec(line); - if (!match) - continue; - results.push({ - key, - value: match[1], - start: match.index, - startValue: match.index + 1, - end: match.index + match[0].length, - wrapping: "emoji-shorthand", - }); - } - return results; -} -/** Sets or replaces the value of an inline field; if the value is 'undefined', deletes the key. */ -function setInlineField(source, key, value) { - let existing = extractInlineFields(source); - let existingKeys = existing.filter(f => f.key == key); - // Don't do anything if there are duplicate keys OR the key already doesn't exist. - if (existingKeys.length > 2 || (existingKeys.length == 0 && !value)) - return source; - let existingKey = existingKeys[0]; - let annotation = value ? `[${key}:: ${value}]` : ""; - if (existingKey) { - let prefix = source.substring(0, existingKey.start); - let suffix = source.substring(existingKey.end); - if (annotation) - return `${prefix}${annotation}${suffix}`; - else - return `${prefix}${suffix.trimStart()}`; - } - else if (annotation) { - return `${source.trimEnd()} ${annotation}`; - } - return source; -} -function setEmojiShorthandCompletionField(source, value) { - const existing = extractInlineFields(source, true); - const existingKeys = existing.filter(f => f.key === "completion" && f.wrapping === "emoji-shorthand"); - // Don't do anything if there are duplicate keys OR the key already doesn't exist. - if (existingKeys.length > 2 || (existingKeys.length == 0 && !value)) - return source; - /* No wrapper, add own spacing at start */ - const annotation = value ? ` ✅ ${value}` : ""; - let existingKey = existingKeys[0]; - if (existingKey) { - const prefix = source.substring(0, existingKey.start); - const suffix = source.substring(existingKey.end); - return `${prefix.trimEnd()}${annotation}${suffix}`; - } - else { - return `${source.trimEnd()}${annotation}`; - } +/** Parse inline fields and other embedded metadata in a line. */ +/** The wrapper characters that can be used to define an inline field. */ +const INLINE_FIELD_WRAPPERS = Object.freeze({ + "[": "]", + "(": ")", +}); +/** + * Find a matching closing bracket that occurs at or after `start`, respecting nesting and escapes. If found, + * returns the value contained within and the string index after the end of the value. + */ +function findClosing(line, start, open, close) { + let nesting = 0; + let escaped = false; + for (let index = start; index < line.length; index++) { + let char = line.charAt(index); + // Allows for double escapes like '\\' to be rendered normally. + if (char == "\\") { + escaped = !escaped; + continue; + } + // If escaped, ignore the next character for computing nesting, regardless of what it is. + if (escaped) { + escaped = false; + continue; + } + if (char == open) + nesting++; + else if (char == close) + nesting--; + // Only occurs if we are on a close character and trhere is no more nesting. + if (nesting < 0) + return { value: line.substring(start, index).trim(), endIndex: index + 1 }; + escaped = false; + } + return undefined; +} +/** Find the '::' separator in an inline field. */ +function findSeparator(line, start) { + let sep = line.indexOf("::", start); + if (sep < 0) + return undefined; + return { key: line.substring(start, sep).trim(), valueIndex: sep + 2 }; +} +/** Try to completely parse an inline field starting at the given position. Assuems `start` is on a wrapping character. */ +function findSpecificInlineField(line, start) { + let open = line.charAt(start); + let key = findSeparator(line, start + 1); + if (key === undefined) + return undefined; + // Fail the match if we find any separator characters (not allowed in keys). + for (let sep of Object.keys(INLINE_FIELD_WRAPPERS).concat(Object.values(INLINE_FIELD_WRAPPERS))) { + if (key.key.includes(sep)) + return undefined; + } + let value = findClosing(line, key.valueIndex, open, INLINE_FIELD_WRAPPERS[open]); + if (value === undefined) + return undefined; + return { + key: key.key, + value: value.value, + start: start, + startValue: key.valueIndex, + end: value.endIndex, + wrapping: open, + }; +} +/** Parse a textual inline field value into something we can work with. */ +function parseInlineValue(value) { + // Empty inline values (i.e., no text) should map to null to match long-term Dataview semantics. + // Null is also a more universal type to deal with than strings, since all functions accept nulls. + if (value.trim() == "") + return null; + // The stripped literal field parser understands all of the non-array/non-object fields and can parse them for us. + // Inline field objects are not currently supported; inline array objects have to be handled by the parser + // separately. + let inline = EXPRESSION.inlineField.parse(value); + if (inline.status) + return inline.value; + else + return value; +} +/** Extracts inline fields of the form '[key:: value]' from a line of text. This is done in a relatively + * "robust" way to avoid failing due to bad nesting or other interfering Markdown symbols: + * + * - Look for any wrappers ('[' and '(') in the line, trying to parse whatever comes after it as an inline key::. + * - If successful, scan until you find a matching end bracket, and parse whatever remains as an inline value. + */ +function extractInlineFields(line, includeTaskFields = false) { + let fields = []; + for (let wrapper of Object.keys(INLINE_FIELD_WRAPPERS)) { + let foundIndex = line.indexOf(wrapper); + while (foundIndex >= 0) { + let parsedField = findSpecificInlineField(line, foundIndex); + if (!parsedField) { + foundIndex = line.indexOf(wrapper, foundIndex + 1); + continue; + } + fields.push(parsedField); + foundIndex = line.indexOf(wrapper, parsedField.end); + } + } + if (includeTaskFields) + fields = fields.concat(extractSpecialTaskFields(line)); + fields.sort((a, b) => a.start - b.start); + let filteredFields = []; + for (let i = 0; i < fields.length; i++) { + if (i == 0 || filteredFields[filteredFields.length - 1].end < fields[i].start) { + filteredFields.push(fields[i]); + } + } + return filteredFields; +} +/** Validates that a raw field name has a valid form. */ +const FULL_LINE_KEY_PART = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(new RegExp(emojiRegex(), "u")), parsimmon_umd_minExports.regexp(/[0-9\p{Letter}\w\s_/-]+/u)) + .many() + .map(parts => parts.join("")); +parsimmon_umd_minExports.regexp(/[^0-9\w\p{Letter}]*/u) + .then(FULL_LINE_KEY_PART) + .skip(parsimmon_umd_minExports.regexp(/[_\*~`]*/u)); +const CREATED_DATE_REGEX = /\u{2795}\s*(\d{4}-\d{2}-\d{2})/u; +const DUE_DATE_REGEX = /(?:\u{1F4C5}|\u{1F4C6}|\u{1F5D3}\u{FE0F}?)\s*(\d{4}-\d{2}-\d{2})/u; +const DONE_DATE_REGEX = /\u{2705}\s*(\d{4}-\d{2}-\d{2})/u; +const SCHEDULED_DATE_REGEX = /[\u{23F3}\u{231B}]\s*(\d{4}-\d{2}-\d{2})/u; +const START_DATE_REGEX = /\u{1F6EB}\s*(\d{4}-\d{2}-\d{2})/u; +const EMOJI_REGEXES = [ + { regex: CREATED_DATE_REGEX, key: "created" }, + { regex: START_DATE_REGEX, key: "start" }, + { regex: SCHEDULED_DATE_REGEX, key: "scheduled" }, + { regex: DUE_DATE_REGEX, key: "due" }, + { regex: DONE_DATE_REGEX, key: "completion" }, +]; +/** Parse special completed/due/done task fields which are marked via emoji. */ +function extractSpecialTaskFields(line) { + let results = []; + for (let { regex, key } of EMOJI_REGEXES) { + const match = regex.exec(line); + if (!match) + continue; + results.push({ + key, + value: match[1], + start: match.index, + startValue: match.index + 1, + end: match.index + match[0].length, + wrapping: "emoji-shorthand", + }); + } + return results; +} +/** Sets or replaces the value of an inline field; if the value is 'undefined', deletes the key. */ +function setInlineField(source, key, value) { + let existing = extractInlineFields(source); + let existingKeys = existing.filter(f => f.key == key); + // Don't do anything if there are duplicate keys OR the key already doesn't exist. + if (existingKeys.length > 2 || (existingKeys.length == 0 && !value)) + return source; + let existingKey = existingKeys[0]; + let annotation = value ? `[${key}:: ${value}]` : ""; + if (existingKey) { + let prefix = source.substring(0, existingKey.start); + let suffix = source.substring(existingKey.end); + if (annotation) + return `${prefix}${annotation}${suffix}`; + else + return `${prefix}${suffix.trimStart()}`; + } + else if (annotation) { + return `${source.trimEnd()} ${annotation}`; + } + return source; +} +function setEmojiShorthandCompletionField(source, value) { + const existing = extractInlineFields(source, true); + const existingKeys = existing.filter(f => f.key === "completion" && f.wrapping === "emoji-shorthand"); + // Don't do anything if there are duplicate keys OR the key already doesn't exist. + if (existingKeys.length > 2 || (existingKeys.length == 0 && !value)) + return source; + /* No wrapper, add own spacing at start */ + const annotation = value ? ` ✅ ${value}` : ""; + let existingKey = existingKeys[0]; + if (existingKey) { + const prefix = source.substring(0, existingKey.start); + const suffix = source.substring(existingKey.end); + return `${prefix.trimEnd()}${annotation}${suffix}`; + } + else { + return `${source.trimEnd()}${annotation}`; + } } -/** All extracted markdown file metadata obtained from a file. */ -class PageMetadata { - constructor(path, init) { - this.path = path; - this.fields = new Map(); - this.frontmatter = {}; - this.tags = new Set(); - this.aliases = new Set(); - this.links = []; - Object.assign(this, init); - this.lists = (this.lists || []).map(l => new ListItem$1(l)); - } - /** Canonicalize raw links and other data in partial data with normalizers, returning a completed object. */ - static canonicalize(data, linkNormalizer) { - // Mutate the data for now, which is probably a bad idea but... all well. - if (data.frontmatter) { - data.frontmatter = Values.mapLeaves(data.frontmatter, t => Values.isLink(t) ? linkNormalizer(t) : t); - } - if (data.fields) { - for (let [key, value] of data.fields.entries()) { - data.fields.set(key, Values.mapLeaves(value, t => (Values.isLink(t) ? linkNormalizer(t) : t))); - } - } - if (data.lists) { - for (let item of data.lists) { - for (let [key, value] of item.fields.entries()) { - item.fields.set(key, value.map(x => Values.mapLeaves(x, t => (Values.isLink(t) ? linkNormalizer(t) : t)))); - } - } - } - if (data.links) { - data.links = data.links.map(l => linkNormalizer(l)); - } - // This is pretty ugly, but it's not possible to normalize on the worker thread that does parsing. - // The best way to improve this is to instead just canonicalize the entire data object; I can try to - // optimize `Values.mapLeaves` to only mutate if it actually changes things. - return new PageMetadata(data.path, data); - } - /** The name (based on path) of this file. */ - name() { - return getFileTitle(this.path); - } - /** The containing folder (based on path) of this file. */ - folder() { - return getParentFolder(this.path); - } - /** The extension of this file (likely 'md'). */ - extension() { - return getExtension(this.path); - } - /** Return a set of tags AND all of their parent tags (so #hello/yes would become #hello, #hello/yes). */ - fullTags() { - let result = new Set(); - for (let tag of this.tags) { - for (let subtag of extractSubtags(tag)) - result.add(subtag); - } - return result; - } - /** Convert all links in this file to file links. */ - fileLinks() { - // We want to make them distinct, but where links are not raw links we - // now keep the additional metadata. - let distinctLinks = new Set(this.links); - return Array.from(distinctLinks); - } - /** Map this metadata to a full object; uses the index for additional data lookups. */ - serialize(index, cache) { - // Convert list items via the canonicalization cache. - let realCache = cache !== null && cache !== void 0 ? cache : new ListSerializationCache(this.lists); - let result = { - file: { - path: this.path, - folder: this.folder(), - name: this.name(), - link: Link.file(this.path), - outlinks: this.fileLinks(), - inlinks: Array.from(index.links.getInverse(this.path)).map(l => Link.file(l)), - etags: Array.from(this.tags), - tags: Array.from(this.fullTags()), - aliases: Array.from(this.aliases), - lists: this.lists.map(l => realCache.get(l.line)), - tasks: this.lists.filter(l => !!l.task).map(l => realCache.get(l.line)), - ctime: this.ctime, - cday: stripTime(this.ctime), - mtime: this.mtime, - mday: stripTime(this.mtime), - size: this.size, - starred: index.starred.starred(this.path), - frontmatter: Values.deepCopy(this.frontmatter), - ext: this.extension(), - }, - }; - // Add the current day if present. - if (this.day) - result.file.day = this.day; - // Then append the computed fields. - for (let [key, value] of this.fields.entries()) { - if (key in result) - continue; // Don't allow fields to override existing keys. - result[key] = value; - } - return result; - } -} -/** A list item inside of a list. */ -class ListItem$1 { - constructor(init) { - Object.assign(this, init); - this.fields = this.fields || new Map(); - this.tags = this.tags || new Set(); - this.children = this.children || []; - this.links = this.links || []; - } - id() { - return `${this.file().path}-${this.line}`; - } - file() { - return this.link.toFile(); - } - markdown() { - if (this.task) - return `${this.symbol} [${this.task.completed ? "x" : " "}] ${this.text}`; - else - return `${this.symbol} ${this.text}`; - } - created() { - var _a, _b, _c; - return (_c = ((_b = (_a = this.fields.get("created")) !== null && _a !== void 0 ? _a : this.fields.get("ctime")) !== null && _b !== void 0 ? _b : this.fields.get("cday"))) === null || _c === void 0 ? void 0 : _c[0]; - } - due() { - var _a, _b, _c; - return (_c = ((_b = (_a = this.fields.get("due")) !== null && _a !== void 0 ? _a : this.fields.get("duetime")) !== null && _b !== void 0 ? _b : this.fields.get("dueday"))) === null || _c === void 0 ? void 0 : _c[0]; - } - completed() { - var _a, _b, _c, _d; - return (_d = ((_c = (_b = (_a = this.fields.get("completed")) !== null && _a !== void 0 ? _a : this.fields.get("completion")) !== null && _b !== void 0 ? _b : this.fields.get("comptime")) !== null && _c !== void 0 ? _c : this.fields.get("compday"))) === null || _d === void 0 ? void 0 : _d[0]; - } - start() { - var _a; - return (_a = this.fields.get("start")) === null || _a === void 0 ? void 0 : _a[0]; - } - scheduled() { - var _a; - return (_a = this.fields.get("scheduled")) === null || _a === void 0 ? void 0 : _a[0]; - } - /** Create an API-friendly copy of this list item. De-duplication is done via the provided cache. */ - serialize(cache) { - // Map children to their serialized/de-duplicated equivalents right away. - let children = this.children.map(l => cache.get(l)).filter((l) => l !== undefined); - let result = { - symbol: this.symbol, - link: this.link, - section: this.section, - text: this.text, - tags: Array.from(this.tags), - line: this.line, - lineCount: this.lineCount, - list: this.list, - outlinks: Array.from(this.links), - path: this.link.path, - children: children, - task: !!this.task, - annotated: this.fields.size > 0, - position: Values.deepCopy(this.position), - subtasks: children, - real: !!this.task, - header: this.section, // @deprecated, use 'item.section' instead. - }; - if (this.parent || this.parent === 0) - result.parent = this.parent; - if (this.blockId) - result.blockId = this.blockId; - addFields(this.fields, result); - if (this.task) { - result.status = this.task.status; - result.checked = this.task.checked; - result.completed = this.task.completed; - result.fullyCompleted = this.task.fullyCompleted; - let created = this.created(), due = this.due(), completed = this.completed(), start = this.start(), scheduled = this.scheduled(); - if (created) - result.created = Values.deepCopy(created); - if (due) - result.due = Values.deepCopy(due); - if (completed) - result.completion = Values.deepCopy(completed); - if (start) - result.start = Values.deepCopy(start); - if (scheduled) - result.scheduled = Values.deepCopy(scheduled); - } - return result; - } -} -////////////////////////////////////////// -// Conversion / Serialization Utilities // -////////////////////////////////////////// -/** De-duplicates list items across section metadata and page metadata. */ -class ListSerializationCache { - constructor(listItems) { - this.listItems = {}; - this.cache = {}; - this.seen = new Set(); - for (let item of listItems) - this.listItems[item.line] = item; - } - get(lineno) { - if (lineno in this.cache) - return this.cache[lineno]; - else if (this.seen.has(lineno)) { - console.log(`Dataview: Encountered a circular list (line number ${lineno}; children ${this.listItems[lineno].children.join(", ")})`); - return undefined; - } - this.seen.add(lineno); - let result = this.listItems[lineno].serialize(this); - this.cache[lineno] = result; - return result; - } -} -function addFields(fields, target) { - for (let [key, values] of fields.entries()) { - if (key in target) - continue; - target[key] = values.length == 1 ? values[0] : values; - } - return target; +/** All extracted markdown file metadata obtained from a file. */ +class PageMetadata { + constructor(path, init) { + this.path = path; + this.fields = new Map(); + this.frontmatter = {}; + this.tags = new Set(); + this.aliases = new Set(); + this.links = []; + Object.assign(this, init); + this.lists = (this.lists || []).map(l => new ListItem$1(l)); + } + /** Canonicalize raw links and other data in partial data with normalizers, returning a completed object. */ + static canonicalize(data, linkNormalizer) { + // Mutate the data for now, which is probably a bad idea but... all well. + if (data.frontmatter) { + data.frontmatter = Values.mapLeaves(data.frontmatter, t => Values.isLink(t) ? linkNormalizer(t) : t); + } + if (data.fields) { + for (let [key, value] of data.fields.entries()) { + data.fields.set(key, Values.mapLeaves(value, t => (Values.isLink(t) ? linkNormalizer(t) : t))); + } + } + if (data.lists) { + for (let item of data.lists) { + for (let [key, value] of item.fields.entries()) { + item.fields.set(key, value.map(x => Values.mapLeaves(x, t => (Values.isLink(t) ? linkNormalizer(t) : t)))); + } + } + } + if (data.links) { + data.links = data.links.map(l => linkNormalizer(l)); + } + // This is pretty ugly, but it's not possible to normalize on the worker thread that does parsing. + // The best way to improve this is to instead just canonicalize the entire data object; I can try to + // optimize `Values.mapLeaves` to only mutate if it actually changes things. + return new PageMetadata(data.path, data); + } + /** The name (based on path) of this file. */ + name() { + return getFileTitle(this.path); + } + /** The containing folder (based on path) of this file. */ + folder() { + return getParentFolder(this.path); + } + /** The extension of this file (likely 'md'). */ + extension() { + return getExtension(this.path); + } + /** Return a set of tags AND all of their parent tags (so #hello/yes would become #hello, #hello/yes). */ + fullTags() { + let result = new Set(); + for (let tag of this.tags) { + for (let subtag of extractSubtags(tag)) + result.add(subtag); + } + return result; + } + /** Convert all links in this file to file links. */ + fileLinks() { + // We want to make them distinct, but where links are not raw links we + // now keep the additional metadata. + let distinctLinks = new Set(this.links); + return Array.from(distinctLinks); + } + /** Map this metadata to a full object; uses the index for additional data lookups. */ + serialize(index, cache) { + // Convert list items via the canonicalization cache. + let realCache = cache !== null && cache !== void 0 ? cache : new ListSerializationCache(this.lists); + let result = { + file: { + path: this.path, + folder: this.folder(), + name: this.name(), + link: Link.file(this.path), + outlinks: this.fileLinks(), + inlinks: Array.from(index.links.getInverse(this.path)).map(l => Link.file(l)), + etags: Array.from(this.tags), + tags: Array.from(this.fullTags()), + aliases: Array.from(this.aliases), + lists: this.lists.map(l => realCache.get(l.line)), + tasks: this.lists.filter(l => !!l.task).map(l => realCache.get(l.line)), + ctime: this.ctime, + cday: stripTime(this.ctime), + mtime: this.mtime, + mday: stripTime(this.mtime), + size: this.size, + starred: index.starred.starred(this.path), + frontmatter: Values.deepCopy(this.frontmatter), + ext: this.extension(), + }, + }; + // Add the current day if present. + if (this.day) + result.file.day = this.day; + // Then append the computed fields. + for (let [key, value] of this.fields.entries()) { + if (key in result) + continue; // Don't allow fields to override existing keys. + result[key] = value; + } + return result; + } +} +/** A list item inside of a list. */ +class ListItem$1 { + constructor(init) { + Object.assign(this, init); + this.fields = this.fields || new Map(); + this.tags = this.tags || new Set(); + this.children = this.children || []; + this.links = this.links || []; + } + id() { + return `${this.file().path}-${this.line}`; + } + file() { + return this.link.toFile(); + } + markdown() { + if (this.task) + return `${this.symbol} [${this.task.completed ? "x" : " "}] ${this.text}`; + else + return `${this.symbol} ${this.text}`; + } + created() { + var _a, _b, _c; + return (_c = ((_b = (_a = this.fields.get("created")) !== null && _a !== void 0 ? _a : this.fields.get("ctime")) !== null && _b !== void 0 ? _b : this.fields.get("cday"))) === null || _c === void 0 ? void 0 : _c[0]; + } + due() { + var _a, _b, _c; + return (_c = ((_b = (_a = this.fields.get("due")) !== null && _a !== void 0 ? _a : this.fields.get("duetime")) !== null && _b !== void 0 ? _b : this.fields.get("dueday"))) === null || _c === void 0 ? void 0 : _c[0]; + } + completed() { + var _a, _b, _c, _d; + return (_d = ((_c = (_b = (_a = this.fields.get("completed")) !== null && _a !== void 0 ? _a : this.fields.get("completion")) !== null && _b !== void 0 ? _b : this.fields.get("comptime")) !== null && _c !== void 0 ? _c : this.fields.get("compday"))) === null || _d === void 0 ? void 0 : _d[0]; + } + start() { + var _a; + return (_a = this.fields.get("start")) === null || _a === void 0 ? void 0 : _a[0]; + } + scheduled() { + var _a; + return (_a = this.fields.get("scheduled")) === null || _a === void 0 ? void 0 : _a[0]; + } + /** Create an API-friendly copy of this list item. De-duplication is done via the provided cache. */ + serialize(cache) { + // Map children to their serialized/de-duplicated equivalents right away. + let children = this.children.map(l => cache.get(l)).filter((l) => l !== undefined); + let result = { + symbol: this.symbol, + link: this.link, + section: this.section, + text: this.text, + tags: Array.from(this.tags), + line: this.line, + lineCount: this.lineCount, + list: this.list, + outlinks: Array.from(this.links), + path: this.link.path, + children: children, + task: !!this.task, + annotated: this.fields.size > 0, + position: Values.deepCopy(this.position), + subtasks: children, + real: !!this.task, + header: this.section, // @deprecated, use 'item.section' instead. + }; + if (this.parent || this.parent === 0) + result.parent = this.parent; + if (this.blockId) + result.blockId = this.blockId; + addFields(this.fields, result); + if (this.task) { + result.status = this.task.status; + result.checked = this.task.checked; + result.completed = this.task.completed; + result.fullyCompleted = this.task.fullyCompleted; + let created = this.created(), due = this.due(), completed = this.completed(), start = this.start(), scheduled = this.scheduled(); + if (created) + result.created = Values.deepCopy(created); + if (due) + result.due = Values.deepCopy(due); + if (completed) + result.completion = Values.deepCopy(completed); + if (start) + result.start = Values.deepCopy(start); + if (scheduled) + result.scheduled = Values.deepCopy(scheduled); + } + return result; + } +} +////////////////////////////////////////// +// Conversion / Serialization Utilities // +////////////////////////////////////////// +/** De-duplicates list items across section metadata and page metadata. */ +class ListSerializationCache { + constructor(listItems) { + this.listItems = {}; + this.cache = {}; + this.seen = new Set(); + for (let item of listItems) + this.listItems[item.line] = item; + } + get(lineno) { + if (lineno in this.cache) + return this.cache[lineno]; + else if (this.seen.has(lineno)) { + console.log(`Dataview: Encountered a circular list (line number ${lineno}; children ${this.listItems[lineno].children.join(", ")})`); + return undefined; + } + this.seen.add(lineno); + let result = this.listItems[lineno].serialize(this); + this.cache[lineno] = result; + return result; + } +} +function addFields(fields, target) { + for (let [key, values] of fields.entries()) { + if (key in target) + continue; + target[key] = values.length == 1 ? values[0] : values; + } + return target; } -/** Importer for markdown documents. */ -// TODO: Consider using an actual parser in leiu of a more expensive regex. -const LIST_ITEM_REGEX = /^[\s>]*(\d+\.|\d+\)|\*|-|\+)\s*(\[.{0,1}\])?\s*(.*)$/mu; -/** Recursively convert frontmatter into fields. We have to dance around YAML structure. */ -function parseFrontmatter(value) { - if (value == null) { - return null; - } - else if (typeof value === "object") { - if (Array.isArray(value)) { - let result = []; - for (let child of value) { - result.push(parseFrontmatter(child)); - } - return result; - } - else if (value instanceof Date) { - let dateParse = DateTime.fromJSDate(value); - return dateParse; - } - else { - let object = value; - let result = {}; - for (let key in object) { - result[key] = parseFrontmatter(object[key]); - } - return result; - } - } - else if (typeof value === "number") { - return value; - } - else if (typeof value === "boolean") { - return value; - } - else if (typeof value === "string") { - let dateParse = EXPRESSION.date.parse(value); - if (dateParse.status) - return dateParse.value; - let durationParse = EXPRESSION.duration.parse(value); - if (durationParse.status) - return durationParse.value; - let linkParse = EXPRESSION.embedLink.parse(value); - if (linkParse.status) - return linkParse.value; - return value; - } - // Backup if we don't understand the type. - return null; +/** Importer for markdown documents. */ +// TODO: Consider using an actual parser in leiu of a more expensive regex. +const LIST_ITEM_REGEX = /^[\s>]*(\d+\.|\d+\)|\*|-|\+)\s*(\[.{0,1}\])?\s*(.*)$/mu; +/** Recursively convert frontmatter into fields. We have to dance around YAML structure. */ +function parseFrontmatter(value) { + if (value == null) { + return null; + } + else if (typeof value === "object") { + if (Array.isArray(value)) { + let result = []; + for (let child of value) { + result.push(parseFrontmatter(child)); + } + return result; + } + else if (value instanceof Date) { + let dateParse = DateTime.fromJSDate(value); + return dateParse; + } + else { + let object = value; + let result = {}; + for (let key in object) { + result[key] = parseFrontmatter(object[key]); + } + return result; + } + } + else if (typeof value === "number") { + return value; + } + else if (typeof value === "boolean") { + return value; + } + else if (typeof value === "string") { + let dateParse = EXPRESSION.date.parse(value); + if (dateParse.status) + return dateParse.value; + let durationParse = EXPRESSION.duration.parse(value); + if (durationParse.status) + return durationParse.value; + let linkParse = EXPRESSION.embedLink.parse(value); + if (linkParse.status) + return linkParse.value; + return value; + } + // Backup if we don't understand the type. + return null; } -/** Parse a CSV file into a collection of data rows. */ -function parseCsv(content) { - let parsed = papaparse_min.exports.parse(content, { - header: true, - skipEmptyLines: true, - comments: "#", - dynamicTyping: true, - }); - let rows = []; - for (let parsedRow of parsed.data) { - let fields = parseFrontmatter(parsedRow); - let result = {}; - for (let [key, value] of Object.entries(fields)) { - result[key] = value; - result[canonicalizeVarName(key)] = value; - } - rows.push(result); - } - return rows; +/** Parse a CSV file into a collection of data rows. */ +function parseCsv(content) { + let parsed = papaparse_minExports.parse(content, { + header: true, + skipEmptyLines: true, + comments: "#", + dynamicTyping: true, + }); + let rows = []; + for (let parsedRow of parsed.data) { + let fields = parseFrontmatter(parsedRow); + let result = {}; + for (let [key, value] of Object.entries(fields)) { + result[key] = value; + result[canonicalizeVarName(key)] = value; + } + rows.push(result); + } + return rows; } -/** Simplifies passing dataview values across the JS web worker barrier. */ -var Transferable; -(function (Transferable) { - /** Convert a literal value to a serializer-friendly transferable value. */ - function transferable(value) { - // Handle simple universal types first. - if (value instanceof Map) { - let copied = new Map(); - for (let [key, val] of value.entries()) - copied.set(transferable(key), transferable(val)); - return copied; - } - else if (value instanceof Set) { - let copied = new Set(); - for (let val of value) - copied.add(transferable(val)); - return copied; - } - let wrapped = Values.wrapValue(value); - if (wrapped === undefined) - throw Error("Unrecognized transferable value: " + value); - switch (wrapped.type) { - case "null": - case "number": - case "string": - case "boolean": - return wrapped.value; - case "date": - return { - "___transfer-type": "date", - value: transferable(wrapped.value.toObject()), - options: { - zone: wrapped.value.zone.equals(SystemZone.instance) ? undefined : wrapped.value.zoneName, - }, - }; - case "duration": - return { "___transfer-type": "duration", value: transferable(wrapped.value.toObject()) }; - case "array": - return wrapped.value.map(v => transferable(v)); - case "link": - return { "___transfer-type": "link", value: transferable(wrapped.value.toObject()) }; - case "object": - let result = {}; - for (let [key, value] of Object.entries(wrapped.value)) - result[key] = transferable(value); - return result; - } - } - Transferable.transferable = transferable; - /** Convert a transferable value back to a literal value we can work with. */ - function value(transferable) { - if (transferable === null) { - return null; - } - else if (transferable === undefined) { - return undefined; - } - else if (transferable instanceof Map) { - let real = new Map(); - for (let [key, val] of transferable.entries()) - real.set(value(key), value(val)); - return real; - } - else if (transferable instanceof Set) { - let real = new Set(); - for (let val of transferable) - real.add(value(val)); - return real; - } - else if (Array.isArray(transferable)) { - return transferable.map(v => value(v)); - } - else if (typeof transferable === "object") { - if ("___transfer-type" in transferable) { - switch (transferable["___transfer-type"]) { - case "date": - let dateOpts = value(transferable.options); - let dateData = value(transferable.value); - return DateTime.fromObject(dateData, { zone: dateOpts.zone }); - case "duration": - return Duration.fromObject(value(transferable.value)); - case "link": - return Link.fromObject(value(transferable.value)); - default: - throw Error(`Unrecognized transfer type '${transferable["___transfer-type"]}'`); - } - } - let result = {}; - for (let [key, val] of Object.entries(transferable)) - result[key] = value(val); - return result; - } - return transferable; - } - Transferable.value = value; +/** Simplifies passing dataview values across the JS web worker barrier. */ +var Transferable; +(function (Transferable) { + /** Convert a literal value to a serializer-friendly transferable value. */ + function transferable(value) { + // Handle simple universal types first. + if (value instanceof Map) { + let copied = new Map(); + for (let [key, val] of value.entries()) + copied.set(transferable(key), transferable(val)); + return copied; + } + else if (value instanceof Set) { + let copied = new Set(); + for (let val of value) + copied.add(transferable(val)); + return copied; + } + let wrapped = Values.wrapValue(value); + if (wrapped === undefined) + throw Error("Unrecognized transferable value: " + value); + switch (wrapped.type) { + case "null": + case "number": + case "string": + case "boolean": + return wrapped.value; + case "date": + return { + "___transfer-type": "date", + value: transferable(wrapped.value.toObject()), + options: { + zone: wrapped.value.zone.equals(SystemZone.instance) ? undefined : wrapped.value.zoneName, + }, + }; + case "duration": + return { "___transfer-type": "duration", value: transferable(wrapped.value.toObject()) }; + case "array": + return wrapped.value.map(v => transferable(v)); + case "link": + return { "___transfer-type": "link", value: transferable(wrapped.value.toObject()) }; + case "object": + let result = {}; + for (let [key, value] of Object.entries(wrapped.value)) + result[key] = transferable(value); + return result; + } + } + Transferable.transferable = transferable; + /** Convert a transferable value back to a literal value we can work with. */ + function value(transferable) { + if (transferable === null) { + return null; + } + else if (transferable === undefined) { + return undefined; + } + else if (transferable instanceof Map) { + let real = new Map(); + for (let [key, val] of transferable.entries()) + real.set(value(key), value(val)); + return real; + } + else if (transferable instanceof Set) { + let real = new Set(); + for (let val of transferable) + real.add(value(val)); + return real; + } + else if (Array.isArray(transferable)) { + return transferable.map(v => value(v)); + } + else if (typeof transferable === "object") { + if ("___transfer-type" in transferable) { + switch (transferable["___transfer-type"]) { + case "date": + let dateOpts = value(transferable.options); + let dateData = value(transferable.value); + return DateTime.fromObject(dateData, { zone: dateOpts.zone }); + case "duration": + return Duration.fromObject(value(transferable.value)); + case "link": + return Link.fromObject(value(transferable.value)); + default: + throw Error(`Unrecognized transfer type '${transferable["___transfer-type"]}'`); + } + } + let result = {}; + for (let [key, val] of Object.entries(transferable)) + result[key] = value(val); + return result; + } + return transferable; + } + Transferable.value = value; })(Transferable || (Transferable = {})); +function commonjsRequire(path) { + throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); +} + var localforage$1 = {exports: {}}; /*! @@ -9491,2877 +9653,2879 @@ var localforage$1 = {exports: {}}; https://localforage.github.io/localForage (c) 2013-2017 Mozilla, Apache License 2.0 */ +localforage$1.exports; (function (module, exports) { -(function(f){{module.exports=f();}})(function(){return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof commonjsRequire=="function"&&commonjsRequire;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw (f.code="MODULE_NOT_FOUND", f)}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r);}return n[o].exports}var i=typeof commonjsRequire=="function"&&commonjsRequire;for(var o=0;o element; its readystatechange event will be fired asynchronously once it is inserted - // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called. - var scriptEl = global.document.createElement('script'); - scriptEl.onreadystatechange = function () { - nextTick(); + // Create a