@appsemble/lang-sdk
Version:
Language SDK for Appsemble
920 lines • 35.1 kB
JavaScript
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