UNPKG

@appsemble/lang-sdk

Version:

Language SDK for Appsemble

920 lines 35.1 kB
import { filter, literalValues, param } from '@odata/parser'; import { addMilliseconds, endOfMonth, endOfQuarter, endOfWeek, endOfYear, format, parse, parseISO, set as setDate, startOfMonth, startOfQuarter, startOfWeek, startOfYear, } from 'date-fns'; import { utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz'; import equal from 'fast-deep-equal'; import { XMLParser } from 'fast-xml-parser'; import { createEvent } from 'ics'; import parseDuration from 'parse-duration'; import { getDuration, processLocation } from './ics.js'; import { mapValues } from './mapValues.js'; import { has, stripNullValues } from './miscellaneous.js'; class RemapperError extends TypeError { constructor(message, remapper) { super(message); this.name = 'RemapperError'; this.remapper = remapper; } } function isPlainObject(value) { return value != null && typeof value === 'object' && !Array.isArray(value); } function isEqualArray(a, b) { if (a.length !== b.length) { return false; } return a.every((val, i) => val === b[i]); } function isEqualObject(a, b) { const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (aKeys.length !== bKeys.length) { return false; } return aKeys.every((key) => bKeys.includes(key) && equal(a[key], b[key])); } function isNumber(a) { return a !== undefined && a != null && a !== '' && !Number.isNaN(Number(a)); } export function remap(remapper, input, context) { if (typeof remapper === 'string' || typeof remapper === 'number' || typeof remapper === 'boolean' || remapper == null) { return remapper; } let result = input; // Workaround for ts(2589) Type instantiation is excessively deep and possibly infinite const remappers = Array.isArray(remapper) ? remapper.flat(Number.POSITIVE_INFINITY) : [remapper]; for (const mapper of remappers) { const entries = Object.entries(mapper); if (entries.length !== 1) { console.error(mapper); throw new RemapperError(`Remapper has multiple keys: ${Object.keys(mapper) .map((key) => JSON.stringify(key)) .join(', ')}`, mapper); } const [[name, args]] = entries; // eslint-disable-next-line @typescript-eslint/no-use-before-define if (!has(mapperImplementations, name)) { console.error(mapper); throw new RemapperError(`Remapper name does not exist: ${JSON.stringify(name)}`, mapper); } // eslint-disable-next-line @typescript-eslint/no-use-before-define const implementation = mapperImplementations[name]; result = implementation(args, result, { root: input, ...context }); } return result; } // Comparison functions for array.sort const compareNumeric = (aVal, bVal) => { const aNum = Number(aVal); const bNum = Number(bVal); const aIsNaN = Number.isNaN(aNum); const bIsNaN = Number.isNaN(bNum); if (aIsNaN && bIsNaN) { return 0; } if (aIsNaN) { return 1; } if (bIsNaN) { return -1; } return aNum - bNum; }; const compareLexicographic = (aVal, bVal) => String(aVal).localeCompare(String(bVal)); const compareDate = (aVal, bVal) => { const aDate = aVal instanceof Date ? aVal : parseISO(String(aVal)); const bDate = bVal instanceof Date ? bVal : parseISO(String(bVal)); const aInvalid = Number.isNaN(aDate.getTime()); const bInvalid = Number.isNaN(bDate.getTime()); if (aInvalid && bInvalid) { return 0; } if (aInvalid) { return 1; } if (bInvalid) { return -1; } return aDate.getTime() - bDate.getTime(); }; /** * Implementations of all remappers. * * All arguments are deferred from remappers. * * @see Remappers */ const mapperImplementations = { app(prop, input, context) { if (prop === 'id') { return context.appId; } if (prop === 'locale') { return context.locale; } if (prop === 'url') { return context.appUrl; } throw new Error(`Unknown app property: ${prop}`); }, page(prop, input, context) { if (prop === 'data') { return context.pageData; } if (prop === 'url') { return context.url; } if (prop === 'name') { return context.pageName; } throw new Error(`Unknown page property: ${prop}`); }, context(prop, input, context) { let result = context.context; for (const p of String(prop).split('.')) { if (result == null) { return null; } result = result[p]; } return result ?? null; }, variable(name, input, context) { if (context.getVariable) { return context.getVariable(name); } return { variable: name }; }, equals(mappers, input, context) { if (mappers.length <= 1) { return true; } const values = mappers.map((mapper) => remap(mapper, input, context)); return values.every((value) => equal(values[0], value)); }, not(mappers, input, context) { if (mappers.length <= 1) { return !remap(mappers[0], input, context); } const [firstValue, ...otherValues] = mappers.map((mapper) => remap(mapper, input, context)); return !otherValues.some((value) => equal(firstValue, value)); }, or(mappers, input, context) { const values = mappers.map((mapper) => Boolean(remap(mapper, input, context))); return values.length > 0 ? values.includes(true) : true; }, and(mappers, input, context) { const values = mappers.map((mapper) => remap(mapper, input, context)); return values.every(Boolean); }, step(mapper, input, context) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 18048 variable is possibly undefined (strictNullChecks) return context.stepRef.current[mapper]; }, 'tab.name'(mapper, input, context) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 18048 variable is possibly undefined (strictNullChecks) return context.tabRef.current.name; }, gt: ([left, right], input, context) => // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Messed up - 2571 Object is of type 'unknown'. remap(left, input, context) > remap(right, input, context), gte: ([left, right], input, context) => // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Messed up - 2571 Object is of type 'unknown'. remap(left, input, context) >= remap(right, input, context), lt: ([left, right], input, context) => // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Messed up - 2571 Object is of type 'unknown'. remap(left, input, context) < remap(right, input, context), lte: ([left, right], input, context) => // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Messed up - 2571 Object is of type 'unknown'. remap(left, input, context) <= remap(right, input, context), ics(mappers, input, context) { let event; const mappedStart = remap(mappers.start, input, context); const start = mappedStart instanceof Date ? mappedStart : parseISO(mappedStart); const sharedAttributes = { start: [ start.getUTCFullYear(), start.getUTCMonth() + 1, start.getUTCDate(), start.getUTCHours(), start.getUTCMinutes(), ], startInputType: 'utc', startOutputType: 'utc', title: remap(mappers.title, input, context), description: remap(mappers.description ?? null, input, context), url: remap(mappers.url ?? null, input, context), location: remap(mappers.location ?? null, input, context), geo: processLocation(remap(mappers.coordinates ?? null, input, context)), productId: context.appUrl, }; if ('end' in mappers) { const mappedEnd = remap(mappers.end, input, context); const end = mappedEnd instanceof Date ? mappedEnd : parseISO(mappedEnd); event = { ...sharedAttributes, endInputType: 'utc', endOutputType: 'utc', end: [ end.getUTCFullYear(), end.getUTCMonth() + 1, end.getUTCDate(), end.getUTCHours(), end.getUTCMinutes(), ], }; } else { event = { ...sharedAttributes, duration: getDuration(remap(mappers.duration, input, context)), }; } const { error, value } = createEvent(event); if (error) { throw error; } return value; }, if(mappers, input, context) { const condition = remap(mappers.condition, input, context); return remap(condition ? mappers.then : mappers.else, input, context); }, focus({ do: doRemapper, on }, input, context) { const newRoot = remap(on, input, context); return remap(doRemapper, input, { ...context, root: newRoot }); }, match(mappers, input, context) { return (remap(mappers.find((mapper) => remap(mapper.case, input, context))?.value ?? null, input, context) ?? null); }, 'object.from': (mappers, input, context) => mapValues(mappers, (mapper) => remap(mapper, input, context)), 'object.assign': (mappers, input, context) => ({ ...input, ...mapValues(mappers, (mapper) => remap(mapper, input, context)), }), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'object.omit'(keys, input) { const result = { ...input }; for (const key of keys) { if (Array.isArray(key)) { let acc = result; for (const [index, k] of key.entries()) { if (index === key.length - 1) { delete acc[k]; } else { acc = acc?.[k]; } } } else { delete result[key]; } } return result; }, 'object.compare'([remapper1, remapper2], input, context) { const remapped1 = remap(remapper1, input, context); const remapped2 = remap(remapper2, input, context); function deepDiff(object1, object2) { const stack = [{ obj1: object1, obj2: object2, path: [] }]; const diffs = []; while (stack.length !== 0) { const { obj1, obj2, path } = stack.pop(); const keys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]); for (const key of keys) { const val1 = obj1?.[key]; const val2 = obj2?.[key]; const currentPath = [...path, key]; if (isPlainObject(val1) && isPlainObject(val2)) { stack.push({ obj1: val1, obj2: val2, path: currentPath }); } else if (Array.isArray(val1) && Array.isArray(val2) && !isEqualArray(val1, val2)) { diffs.push({ path: currentPath, type: 'changed', from: val1, to: val2 }); } else if (!(key in obj1)) { diffs.push({ path: currentPath, type: 'added', value: val2 }); } else if (!(key in obj2)) { diffs.push({ path: currentPath, type: 'removed', value: val1 }); } else if (val1 !== val2) { diffs.push({ path: currentPath, type: 'changed', from: val1, to: val2 }); } } } return diffs; } if (!isPlainObject(remapped1) || !isPlainObject(remapped2)) { return []; } return deepDiff(remapped1, remapped2); }, 'object.explode'(property, input) { if (!isPlainObject(input)) { return []; } const { [property]: arrayValue, ...rest } = input; if (!Array.isArray(arrayValue)) { return []; } return arrayValue.map((item) => ({ ...rest, ...item, })); }, type(args, input) { // eslint-disable-next-line eqeqeq if (input === null) { return null; } if (Array.isArray(input)) { return 'array'; } return typeof input; }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'array.map': (mapper, input, context) => input?.map((item, index) => remap(mapper, item, { ...context, array: { index, length: input.length, item, prevItem: input[index - 1], nextItem: input[index + 1], }, })) ?? [], 'array.range'(countRemapper, input, context) { const count = remap(countRemapper, input, context); if (typeof count !== 'number' || !Number.isInteger(count) || count < 0) { return []; } return Array.from({ length: count }, (item, idx) => idx); }, 'array.contains'(mapper, input, context) { if (!Array.isArray(input)) { return false; } const remapped = remap(mapper, input, context); if (isPlainObject(remapped)) { return input.some((item) => isEqualObject(item, remapped ?? {})); } if (Array.isArray(remapped)) { return input.some((item) => isEqualArray(item, remapped)); } return input.includes(remapped); }, 'array.join'(separator, input) { if (!Array.isArray(input)) { return input; } return input.join(separator ?? undefined); }, 'array.groupBy'(propertyName, input) { if (!Array.isArray(input)) { return []; } const groups = new Map(); for (const item of input) { const key = item?.[propertyName]; if (!groups.has(key)) { groups.set(key, []); } groups.get(key).push(item); } return [...groups.entries()].map(([key, items]) => ({ key, items })); }, 'array.toObject'({ key: keyMapper, value: valueMapper }, input, context) { if (!Array.isArray(input)) { return {}; } const result = {}; for (const [index, item] of input.entries()) { const itemContext = { ...context, array: { index, length: input.length, item, prevItem: input[index - 1], nextItem: input[index + 1], }, }; const key = remap(keyMapper, item, itemContext); const value = remap(valueMapper, item, itemContext); if (key != null) { result[String(key)] = value; } } return result; }, 'array.sort'(mapper, input) { if (!Array.isArray(input)) { return input; } // Normalize mapper: string becomes { by: string }, null/undefined becomes {} const { by, descending = false, strategy = 'infer', } = typeof mapper === 'string' ? { by: mapper, descending: false, strategy: 'infer' } : (mapper ?? {}); // Extract values for sorting const getValue = (item) => by ? item?.[by] : item; // Determine effective strategy for 'infer' mode let effectiveStrategy = strategy; if (strategy === 'infer') { // Find first non-null value to determine type const firstValue = input.map(getValue).find((v) => v != null); if (typeof firstValue === 'number') { effectiveStrategy = 'numeric'; } else if (firstValue instanceof Date) { effectiveStrategy = 'date'; } else { effectiveStrategy = 'lexicographic'; } } const compare = effectiveStrategy === 'numeric' ? compareNumeric : effectiveStrategy === 'date' ? compareDate : compareLexicographic; const sorted = [...input].sort((a, b) => { const aValue = getValue(a); const bValue = getValue(b); // Handle nullish values - push them to the end if (aValue == null && bValue == null) { return 0; } if (aValue == null) { return 1; } if (bValue == null) { return -1; } const comparison = compare(aValue, bValue); return descending ? -comparison : comparison; }); return sorted; }, 'array.unique'(mapper, input, context) { if (!Array.isArray(input)) { return input; } const remapped = input.map((item, index) => mapper == null ? item : remap(mapper, item, { ...context, array: { index, length: input.length, item, prevItem: input[index - 1], nextItem: input[index + 1], }, })); return input.filter((value, index) => { for (let i = 0; i < index; i += 1) { if (equal(remapped[index], remapped[i])) { return false; } } return true; }); }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) array: (prop, input, context) => context.array?.[prop], // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'array.filter'(mapper, input, context) { if (!Array.isArray(input)) { console.error(`${input} is not an array!`); return null; } return input?.filter((item, index) => { const remapped = remap(mapper, item, { ...context, array: { index, length: input.length, item, prevItem: input[index - 1], nextItem: input[index + 1], }, }); return remapped; }); }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'array.find'(mapper, input, context) { if (!Array.isArray(input)) { console.error(`${input} is not an array!`); return null; } return (input?.find((item) => { const remapped = remap(mapper, item, context); switch (typeof remapped) { case 'boolean': return remap(mapper, item, context) ? item : null; default: return equal(remapped, item) ? item : null; } }) ?? null); }, 'array.from': (mappers, input, context) => mappers.map((mapper) => remap(mapper, input, context)), 'array.append': (mappers, input, context) => Array.isArray(input) ? input.concat(mappers.map((mapper) => remap(mapper, input, context))) : [], 'array.omit'(mappers, input, context) { const indices = new Set(mappers.map((mapper) => { const remapped = remap(mapper, input, context); if (typeof remapped === 'number') { return remapped; } })); return Array.isArray(input) ? input.filter((value, i) => !indices.has(i)) : []; }, 'array.flatten'(mapper, input, context) { if (!Array.isArray(input)) { return input; } const depth = remap(mapper, input, context); return input.flat(depth || Number.POSITIVE_INFINITY); }, static: (input) => input, prop(prop, obj, context) { let result = obj; if (result == null) { return result; } if (Array.isArray(prop)) { if (prop.every((item) => typeof item === 'number' || typeof item === 'string')) { // This runs if the provided value is an array of property names or indexes for (const p of [prop].flat()) { result = result[p]; } } else if (prop.every((item) => typeof item === 'object' && !Array.isArray(item))) { // This runs if the provided value is an array of remappers const remapped = remap(prop, obj, context); if (typeof remapped === 'number' || typeof remapped === 'string') { result = result[remapped]; } else { console.error(`Invalid remapper ${JSON.stringify(prop)}`); } } } else if (typeof prop === 'object') { if (prop == null) { result = result.null; return result; } // This runs if the provided value is a remapper const remapped = remap(prop, result, context); if (typeof remapped === 'number' || typeof remapped === 'string') { result = result[remapped]; } else { console.error(`Invalid remapper ${JSON.stringify(prop)}`); } } else if (typeof prop === 'number' || typeof prop === 'string') { result = Array.isArray(result) && typeof prop === 'number' && prop < 0 ? result[result.length + prop] : result[prop]; } return result; }, 'number.parse'(remapper, input, context) { if (!remapper) { const inputConverted = Number(input); if (!Number.isNaN(inputConverted)) { return inputConverted; } return input; } const remapped = remap(remapper, input, context); const remappedConverted = Number(remapped); if (!Number.isNaN(remappedConverted)) { return remappedConverted; } return remapped; }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'date.parse': (fmt, input) => (fmt ? parse(input, fmt, new Date()) : parseISO(input)), 'date.now': () => new Date(), 'date.add'(time, input) { const expireDuration = parseDuration(time); if (!expireDuration || !input || (!Number.isFinite(input) && !(input instanceof Date))) { return input; } return addMilliseconds(input, expireDuration); }, 'date.format'(args, input) { const date = input instanceof Date ? input : typeof input === 'number' ? new Date(input) : parseISO(String(input)); return args ? format(date, args) : date.toJSON(); }, 'date.startOf'(unit, input) { const date = input instanceof Date ? input : typeof input === 'number' ? new Date(input) : parseISO(String(input)); let result; switch (unit) { case 'year': result = startOfYear(date); break; case 'quarter': result = startOfQuarter(date); break; case 'month': result = startOfMonth(date); break; case 'week': result = startOfWeek(date, { weekStartsOn: 1 }); break; case 'weekSun': result = startOfWeek(date, { weekStartsOn: 0 }); break; default: return input; } return result.toJSON(); }, 'date.endOf'(unit, input) { const date = input instanceof Date ? input : typeof input === 'number' ? new Date(input) : parseISO(String(input)); let result; switch (unit) { case 'year': result = endOfYear(date); break; case 'quarter': result = endOfQuarter(date); break; case 'month': result = endOfMonth(date); break; case 'week': result = endOfWeek(date, { weekStartsOn: 1 }); break; case 'weekSun': result = endOfWeek(date, { weekStartsOn: 0 }); break; default: return input; } return result.toJSON(); }, 'date.set'(args, input, context) { const date = input instanceof Date ? input : typeof input === 'number' ? new Date(input) : parseISO(String(input)); const remapped = mapValues(args, (mapper) => remap(mapper, input, context)); const setValues = {}; if (typeof remapped.year === 'number') { setValues.year = remapped.year; } if (typeof remapped.month === 'number') { // Convert from 1-indexed (user-facing) to 0-indexed (date-fns) setValues.month = remapped.month - 1; } if (typeof remapped.day === 'number') { setValues.date = remapped.day; } // Convert to UTC-zoned date so set operates in UTC const zonedDate = utcToZonedTime(date, 'UTC'); const result = setDate(zonedDate, setValues); return zonedTimeToUtc(result, 'UTC').toJSON(); }, 'null.strip': (args, input) => stripNullValues(input, args || {}), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'random.choice': (args, input) => Array.isArray(input) ? input[Math.floor(Math.random() * input.length)] : input, 'random.integer'(args) { const min = Math.min(...args); const max = Math.max(...args); return Math.floor(Math.random() * (max - min) + min); }, 'random.float'(args) { const min = Math.min(...args); const max = Math.max(...args); return Math.random() * (max - min) + min; }, 'random.string'(args) { const result = []; const characters = [...new Set(args.choice.split(''))]; for (let i = 0; i <= args.length; i += 1) { result.push(characters[Math.floor(Math.random() * characters.length)]); } return result.join(''); }, root: (args, input, context) => context.root, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) len: (args, input) => input?.length, history: (index, input, context) => context.history?.[index], 'from.history': ({ index, props }, input, context) => mapValues(props, (mapper) => remap(mapper, context.history?.[index], context)), 'assign.history': ({ index, props }, input, context) => ({ ...input, ...mapValues(props, (mapper) => remap(mapper, context.history?.[index], context)), }), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'omit.history'({ index, keys }, input, context) { const result = { ...context.history?.[index] }; for (const key of keys) { if (Array.isArray(key)) { let acc = result; for (const [i, k] of key.entries()) { if (i === key.length - 1) { delete acc[k]; } else { acc = acc?.[k]; } } } else { delete result[key]; } } return { ...input, ...result }; }, 'string.case'(stringCase, input) { if (stringCase === 'lower') { return String(input).toLowerCase(); } if (stringCase === 'upper') { return String(input).toUpperCase(); } return input; }, 'string.contains'(stringToCheck, input) { if (!(typeof input === 'string')) { return false; } return input.includes(stringToCheck); }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'string.startsWith'(substring, input) { if (typeof substring === 'string') { return input.startsWith(substring); } if (substring.strict || substring.strict === undefined) { return input.startsWith(substring.substring); } return input.toLowerCase().startsWith(substring.substring.toLowerCase()); }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 ... is not assignable to type (strictNullChecks) 'string.endsWith'(substring, input) { if (typeof substring === 'string') { return input.endsWith(substring); } if (substring.strict || substring.strict === undefined) { return input.endsWith(substring.substring); } return input.toLowerCase().endsWith(substring.substring.toLowerCase()); }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 2322 null is not assignable to type (strictNullChecks) slice(sliceIndex, input) { try { return Array.isArray(sliceIndex) ? input.slice(...sliceIndex) : input.slice(sliceIndex); } catch { return null; } }, log(level, input, context) { console[level ?? 'info'](JSON.stringify({ input, context }, null, 2)); return input; }, 'string.format'({ messageId, template, values }, input, context) { try { const remappedMessageId = remap(messageId ?? null, input, context); const message = context.getMessage({ id: remappedMessageId, defaultMessage: template }); return message.format(values ? mapValues(values, (val) => remap(val, input, context)) : undefined); } catch (error) { if (messageId) { return `{${messageId}}`; } return error.message; } }, 'string.replace'(values, input) { const [[regex, replacer]] = Object.entries(values); return String(input).replaceAll(new RegExp(regex, 'gm'), replacer); }, translate(messageId, input, context) { const remappedId = remap(messageId, input, context); if (typeof remappedId !== 'string') { return null; } const message = context.getMessage({ id: remappedId }); return message.format() || `{${remappedId}}`; }, group: (property, input, context) => context.group?.[property], 'app.member': (property, input, context) => context.appMemberInfo?.[property], container(property, input, context) { // This value is replaced when the request is made // By using the value of the release name const namespace = 'companion-containers-appsemble'; const appName = context.appUrl.split('.')[0].replace(/^https?:\/\//, ''); const endpoint = property.split('/').slice(1).join('/'); const containerName = `${property.split('/')[0]}-${appName}-${context.appId}` .replaceAll(' ', '-') .toLowerCase(); const url = `http://${containerName}.${namespace}.svc.cluster.local/${endpoint}`; return url; }, 'filter.from'(values, input, context) { let result = filter(); for (const [field, { comparator, type, value }] of Object.entries(values)) { const remapped = remap(value, input, context); const remappedDefined = remapped === undefined ? null : remapped; const literal = type === 'String' && remapped != null ? literalValues[type](String(remappedDefined).replaceAll("'", "''").replaceAll('\\', '\\\\')) : literalValues[type === 'Number' ? 'Decimal' : type](remappedDefined); result = result.field(field)[comparator](literal); } return String(param().filter(result)).replace(/^\$filter=/, ''); }, 'order.from'(values) { return String(param().orderby(Object.entries(values).map(([key, order]) => ({ field: key, order })))).replace('$orderby=', ''); }, 'xml.parse'(value, input, context) { const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '', }); try { return parser.parse(remap(value, input, context) || ''); } catch (error) { console.error(error); return {}; } }, defined(value, input, context) { const remapped = remap(value, input, context); return remapped !== undefined && remapped != null; }, maths(value, input, context) { const { a, b, operation } = value; const aRemapped = remap(a, input, context); const bRemapped = remap(b, input, context); if (!isNumber(aRemapped) || !isNumber(bRemapped)) { return -1; } const na = Number(aRemapped); const nb = Number(bRemapped); switch (operation) { case 'add': return na + nb; case 'subtract': return na - nb; case 'multiply': return na * nb; case 'divide': if (nb === 0) { return -1; } return na / nb; case 'mod': return na % nb; default: return -1; } }, }; //# sourceMappingURL=remap.js.map