UNPKG

@jmespath-community/jmespath

Version:

Typescript implementation of the JMESPath Community specification

924 lines 35.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Runtime = exports.InputArgument = void 0; const text_1 = require("./utils/text"); const strings_1 = require("./utils/strings"); var InputArgument; (function (InputArgument) { InputArgument[InputArgument["TYPE_NUMBER"] = 0] = "TYPE_NUMBER"; InputArgument[InputArgument["TYPE_ANY"] = 1] = "TYPE_ANY"; InputArgument[InputArgument["TYPE_STRING"] = 2] = "TYPE_STRING"; InputArgument[InputArgument["TYPE_ARRAY"] = 3] = "TYPE_ARRAY"; InputArgument[InputArgument["TYPE_OBJECT"] = 4] = "TYPE_OBJECT"; InputArgument[InputArgument["TYPE_BOOLEAN"] = 5] = "TYPE_BOOLEAN"; InputArgument[InputArgument["TYPE_EXPREF"] = 6] = "TYPE_EXPREF"; InputArgument[InputArgument["TYPE_NULL"] = 7] = "TYPE_NULL"; InputArgument[InputArgument["TYPE_ARRAY_NUMBER"] = 8] = "TYPE_ARRAY_NUMBER"; InputArgument[InputArgument["TYPE_ARRAY_STRING"] = 9] = "TYPE_ARRAY_STRING"; InputArgument[InputArgument["TYPE_ARRAY_OBJECT"] = 10] = "TYPE_ARRAY_OBJECT"; InputArgument[InputArgument["TYPE_ARRAY_ARRAY"] = 11] = "TYPE_ARRAY_ARRAY"; })(InputArgument = exports.InputArgument || (exports.InputArgument = {})); class Runtime { constructor(interpreter) { this.TYPE_NAME_TABLE = { [InputArgument.TYPE_NUMBER]: 'number', [InputArgument.TYPE_ANY]: 'any', [InputArgument.TYPE_STRING]: 'string', [InputArgument.TYPE_ARRAY]: 'array', [InputArgument.TYPE_OBJECT]: 'object', [InputArgument.TYPE_BOOLEAN]: 'boolean', [InputArgument.TYPE_EXPREF]: 'expression', [InputArgument.TYPE_NULL]: 'null', [InputArgument.TYPE_ARRAY_NUMBER]: 'Array<number>', [InputArgument.TYPE_ARRAY_OBJECT]: 'Array<object>', [InputArgument.TYPE_ARRAY_STRING]: 'Array<string>', [InputArgument.TYPE_ARRAY_ARRAY]: 'Array<Array<any>>', }; this.functionAbs = ([inputValue]) => { return Math.abs(inputValue); }; this.functionAvg = ([inputArray]) => { if (!inputArray || inputArray.length == 0) { return null; } let sum = 0; for (let i = 0; i < inputArray.length; i += 1) { sum += inputArray[i]; } return sum / inputArray.length; }; this.functionCeil = ([inputValue]) => { return Math.ceil(inputValue); }; this.functionContains = ([searchable, searchValue,]) => { if (Array.isArray(searchable)) { const array = searchable; return array.includes(searchValue); } if (typeof searchable === 'string') { const text = searchable; if (typeof searchValue === 'string') { return text.includes(searchValue); } } return null; }; this.functionEndsWith = resolvedArgs => { const [searchStr, suffix] = resolvedArgs; return searchStr.includes(suffix, searchStr.length - suffix.length); }; this.functionFindFirst = resolvedArgs => { const subject = resolvedArgs[0]; const search = resolvedArgs[1]; const start = (resolvedArgs.length > 2 && resolvedArgs[2]) || undefined; const end = (resolvedArgs.length > 3 && resolvedArgs[3]) || undefined; return (0, strings_1.findFirst)(subject, search, start, end); }; this.functionFindLast = resolvedArgs => { const subject = resolvedArgs[0]; const search = resolvedArgs[1]; const start = (resolvedArgs.length > 2 && resolvedArgs[2]) || undefined; const end = (resolvedArgs.length > 3 && resolvedArgs[3]) || undefined; return (0, strings_1.findLast)(subject, search, start, end); }; this.functionFloor = ([inputValue]) => { return Math.floor(inputValue); }; this.functionFromItems = ([array]) => { array.map((pair) => { if (pair.length != 2 || typeof pair[0] !== 'string') { throw new Error('invalid value, each array must contain two elements, a pair of string and value'); } }); return Object.fromEntries(array); }; this.functionGroupBy = ([array, exprefNode]) => { const keyFunction = this.createKeyFunction(exprefNode, [InputArgument.TYPE_STRING]); return array.reduce((acc, cur) => { const k = keyFunction(cur !== null && cur !== void 0 ? cur : {}); const target = (acc[k] = acc[k] || []); target.push(cur); return acc; }, {}); }; this.functionItems = ([inputValue]) => { return Object.entries(inputValue); }; this.functionJoin = resolvedArgs => { const [joinChar, listJoin] = resolvedArgs; return listJoin.join(joinChar); }; this.functionKeys = ([inputObject]) => { return Object.keys(inputObject); }; this.functionLength = ([inputValue]) => { if (typeof inputValue === 'string') { return new text_1.Text(inputValue).length; } if (Array.isArray(inputValue)) { return inputValue.length; } return Object.keys(inputValue).length; }; this.functionLower = ([subject]) => { return (0, strings_1.lower)(subject); }; this.functionMap = ([exprefNode, elements]) => { if (!this._interpreter) { return []; } const mapped = []; const interpreter = this._interpreter; for (let i = 0; i < elements.length; i += 1) { mapped.push(interpreter.visit(exprefNode, elements[i])); } return mapped; }; this.functionMax = ([inputValue]) => { if (!inputValue.length) { return null; } const typeName = this.getTypeName(inputValue[0]); if (typeName === InputArgument.TYPE_NUMBER) { return Math.max(...inputValue); } const elements = inputValue; let maxElement = elements[0]; for (let i = 1; i < elements.length; i += 1) { if (maxElement.localeCompare(elements[i]) < 0) { maxElement = elements[i]; } } return maxElement; }; this.functionMaxBy = resolvedArgs => { const exprefNode = resolvedArgs[1]; const resolvedArray = resolvedArgs[0]; const keyFunction = this.createKeyFunction(exprefNode, [InputArgument.TYPE_NUMBER, InputArgument.TYPE_STRING]); let maxNumber = -Infinity; let maxRecord; let current; for (let i = 0; i < resolvedArray.length; i += 1) { current = keyFunction && keyFunction(resolvedArray[i]); if (current !== undefined && current > maxNumber) { maxNumber = current; maxRecord = resolvedArray[i]; } } return maxRecord || null; }; this.functionMerge = resolvedArgs => { let merged = {}; for (let i = 0; i < resolvedArgs.length; i += 1) { const current = resolvedArgs[i]; merged = Object.assign(merged, current); } return merged; }; this.functionMin = ([inputValue]) => { if (!inputValue.length) { return null; } const typeName = this.getTypeName(inputValue[0]); if (typeName === InputArgument.TYPE_NUMBER) { return Math.min(...inputValue); } const elements = inputValue; let minElement = elements[0]; for (let i = 1; i < elements.length; i += 1) { if (elements[i].localeCompare(minElement) < 0) { minElement = elements[i]; } } return minElement; }; this.functionMinBy = resolvedArgs => { const exprefNode = resolvedArgs[1]; const resolvedArray = resolvedArgs[0]; const keyFunction = this.createKeyFunction(exprefNode, [InputArgument.TYPE_NUMBER, InputArgument.TYPE_STRING]); let minNumber = Infinity; let minRecord; let current; for (let i = 0; i < resolvedArray.length; i += 1) { current = keyFunction && keyFunction(resolvedArray[i]); if (current !== undefined && current < minNumber) { minNumber = current; minRecord = resolvedArray[i]; } } return minRecord || null; }; this.functionNotNull = resolvedArgs => { for (let i = 0; i < resolvedArgs.length; i += 1) { if (this.getTypeName(resolvedArgs[i]) !== InputArgument.TYPE_NULL) { return resolvedArgs[i]; } } return null; }; this.functionPadLeft = resolvedArgs => { const subject = resolvedArgs[0]; const width = resolvedArgs[1]; const padding = (resolvedArgs.length > 2 && resolvedArgs[2]) || undefined; return (0, strings_1.padLeft)(subject, width, padding); }; this.functionPadRight = resolvedArgs => { const subject = resolvedArgs[0]; const width = resolvedArgs[1]; const padding = (resolvedArgs.length > 2 && resolvedArgs[2]) || undefined; return (0, strings_1.padRight)(subject, width, padding); }; this.functionReplace = resolvedArgs => { const subject = resolvedArgs[0]; const string = resolvedArgs[1]; const by = resolvedArgs[2]; return (0, strings_1.replace)(subject, string, by, resolvedArgs.length > 3 ? resolvedArgs[3] : undefined); }; this.functionSplit = resolvedArgs => { const subject = resolvedArgs[0]; const search = resolvedArgs[1]; return (0, strings_1.split)(subject, search, resolvedArgs.length > 2 ? resolvedArgs[2] : undefined); }; this.functionReverse = ([inputValue]) => { const typeName = this.getTypeName(inputValue); if (typeName === InputArgument.TYPE_STRING) { return new text_1.Text(inputValue).reverse(); } const reversedArray = inputValue.slice(0); reversedArray.reverse(); return reversedArray; }; this.functionSort = ([inputValue]) => { if (inputValue.length == 0) { return inputValue; } if (typeof inputValue[0] === 'string') { return [...inputValue].sort(text_1.Text.comparer); } return [...inputValue].sort(); }; this.functionSortBy = resolvedArgs => { const sortedArray = resolvedArgs[0].slice(0); if (sortedArray.length === 0) { return sortedArray; } const interpreter = this._interpreter; const exprefNode = resolvedArgs[1]; const requiredType = this.getTypeName(interpreter.visit(exprefNode, sortedArray[0])); if (requiredType !== undefined && ![InputArgument.TYPE_NUMBER, InputArgument.TYPE_STRING].includes(requiredType)) { throw new Error(`Invalid type: unexpected type (${this.TYPE_NAME_TABLE[requiredType]})`); } function throwInvalidTypeError(rt, item) { throw new Error(`Invalid type: expected (${rt.TYPE_NAME_TABLE[requiredType]}), received ${rt.TYPE_NAME_TABLE[rt.getTypeName(item)]}`); } return sortedArray.sort((a, b) => { const exprA = interpreter.visit(exprefNode, a); const exprB = interpreter.visit(exprefNode, b); if (this.getTypeName(exprA) !== requiredType) { throwInvalidTypeError(this, exprA); } else if (this.getTypeName(exprB) !== requiredType) { throwInvalidTypeError(this, exprB); } if (requiredType === InputArgument.TYPE_STRING) { return text_1.Text.comparer(exprA, exprB); } return exprA - exprB; }); }; this.functionStartsWith = ([searchable, searchStr]) => { return searchable.startsWith(searchStr); }; this.functionSum = ([inputValue]) => { return inputValue.reduce((x, y) => x + y, 0); }; this.functionToArray = ([inputValue]) => { if (this.getTypeName(inputValue) === InputArgument.TYPE_ARRAY) { return inputValue; } return [inputValue]; }; this.functionToNumber = ([inputValue]) => { const typeName = this.getTypeName(inputValue); let convertedValue; if (typeName === InputArgument.TYPE_NUMBER) { return inputValue; } if (typeName === InputArgument.TYPE_STRING) { convertedValue = +inputValue; if (!isNaN(convertedValue)) { return convertedValue; } } return null; }; this.functionToString = ([inputValue]) => { if (this.getTypeName(inputValue) === InputArgument.TYPE_STRING) { return inputValue; } return JSON.stringify(inputValue); }; this.functionTrim = resolvedArgs => { const subject = resolvedArgs[0]; return (0, strings_1.trim)(subject, resolvedArgs.length > 1 ? resolvedArgs[1] : undefined); }; this.functionTrimLeft = resolvedArgs => { const subject = resolvedArgs[0]; return (0, strings_1.trimLeft)(subject, resolvedArgs.length > 1 ? resolvedArgs[1] : undefined); }; this.functionTrimRight = resolvedArgs => { const subject = resolvedArgs[0]; return (0, strings_1.trimRight)(subject, resolvedArgs.length > 1 ? resolvedArgs[1] : undefined); }; this.functionType = ([inputValue]) => { switch (this.getTypeName(inputValue)) { case InputArgument.TYPE_NUMBER: return 'number'; case InputArgument.TYPE_STRING: return 'string'; case InputArgument.TYPE_ARRAY: return 'array'; case InputArgument.TYPE_OBJECT: return 'object'; case InputArgument.TYPE_BOOLEAN: return 'boolean'; case InputArgument.TYPE_NULL: return 'null'; default: throw new Error('invalid-type'); } }; this.functionUpper = ([subject]) => { return (0, strings_1.upper)(subject); }; this.functionValues = ([inputObject]) => { return Object.values(inputObject); }; this.functionZip = array => { const length = Math.min(...array.map(arr => arr.length)); const result = Array(length) .fill(null) .map((_, index) => array.map(arr => arr[index])); return result; }; this.functionTable = { abs: { _func: this.functionAbs, _signature: [ { types: [InputArgument.TYPE_NUMBER], }, ], }, avg: { _func: this.functionAvg, _signature: [ { types: [InputArgument.TYPE_ARRAY_NUMBER], }, ], }, ceil: { _func: this.functionCeil, _signature: [ { types: [InputArgument.TYPE_NUMBER], }, ], }, contains: { _func: this.functionContains, _signature: [ { types: [InputArgument.TYPE_STRING, InputArgument.TYPE_ARRAY], }, { types: [InputArgument.TYPE_ANY], }, ], }, ends_with: { _func: this.functionEndsWith, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, ], }, find_first: { _func: this.functionFindFirst, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_NUMBER], optional: true, }, { types: [InputArgument.TYPE_NUMBER], optional: true, }, ], }, find_last: { _func: this.functionFindLast, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_NUMBER], optional: true, }, { types: [InputArgument.TYPE_NUMBER], optional: true, }, ], }, floor: { _func: this.functionFloor, _signature: [ { types: [InputArgument.TYPE_NUMBER], }, ], }, from_items: { _func: this.functionFromItems, _signature: [ { types: [InputArgument.TYPE_ARRAY_ARRAY], }, ], }, group_by: { _func: this.functionGroupBy, _signature: [{ types: [InputArgument.TYPE_ARRAY] }, { types: [InputArgument.TYPE_EXPREF] }], }, items: { _func: this.functionItems, _signature: [ { types: [InputArgument.TYPE_OBJECT], }, ], }, join: { _func: this.functionJoin, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_ARRAY_STRING], }, ], }, keys: { _func: this.functionKeys, _signature: [ { types: [InputArgument.TYPE_OBJECT], }, ], }, length: { _func: this.functionLength, _signature: [ { types: [InputArgument.TYPE_STRING, InputArgument.TYPE_ARRAY, InputArgument.TYPE_OBJECT], }, ], }, lower: { _func: this.functionLower, _signature: [ { types: [InputArgument.TYPE_STRING], }, ], }, map: { _func: this.functionMap, _signature: [ { types: [InputArgument.TYPE_EXPREF], }, { types: [InputArgument.TYPE_ARRAY], }, ], }, max: { _func: this.functionMax, _signature: [ { types: [InputArgument.TYPE_ARRAY_NUMBER, InputArgument.TYPE_ARRAY_STRING], }, ], }, max_by: { _func: this.functionMaxBy, _signature: [ { types: [InputArgument.TYPE_ARRAY], }, { types: [InputArgument.TYPE_EXPREF], }, ], }, merge: { _func: this.functionMerge, _signature: [ { types: [InputArgument.TYPE_OBJECT], variadic: true, }, ], }, min: { _func: this.functionMin, _signature: [ { types: [InputArgument.TYPE_ARRAY_NUMBER, InputArgument.TYPE_ARRAY_STRING], }, ], }, min_by: { _func: this.functionMinBy, _signature: [ { types: [InputArgument.TYPE_ARRAY], }, { types: [InputArgument.TYPE_EXPREF], }, ], }, not_null: { _func: this.functionNotNull, _signature: [ { types: [InputArgument.TYPE_ANY], variadic: true, }, ], }, pad_left: { _func: this.functionPadLeft, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_NUMBER], }, { types: [InputArgument.TYPE_STRING], optional: true, }, ], }, pad_right: { _func: this.functionPadRight, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_NUMBER], }, { types: [InputArgument.TYPE_STRING], optional: true, }, ], }, replace: { _func: this.functionReplace, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_NUMBER], optional: true, }, ], }, split: { _func: this.functionSplit, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_NUMBER], optional: true, }, ], }, reverse: { _func: this.functionReverse, _signature: [ { types: [InputArgument.TYPE_STRING, InputArgument.TYPE_ARRAY], }, ], }, sort: { _func: this.functionSort, _signature: [ { types: [InputArgument.TYPE_ARRAY_STRING, InputArgument.TYPE_ARRAY_NUMBER], }, ], }, sort_by: { _func: this.functionSortBy, _signature: [ { types: [InputArgument.TYPE_ARRAY], }, { types: [InputArgument.TYPE_EXPREF], }, ], }, starts_with: { _func: this.functionStartsWith, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], }, ], }, sum: { _func: this.functionSum, _signature: [ { types: [InputArgument.TYPE_ARRAY_NUMBER], }, ], }, to_array: { _func: this.functionToArray, _signature: [ { types: [InputArgument.TYPE_ANY], }, ], }, to_number: { _func: this.functionToNumber, _signature: [ { types: [InputArgument.TYPE_ANY], }, ], }, to_string: { _func: this.functionToString, _signature: [ { types: [InputArgument.TYPE_ANY], }, ], }, trim: { _func: this.functionTrim, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], optional: true, }, ], }, trim_left: { _func: this.functionTrimLeft, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], optional: true, }, ], }, trim_right: { _func: this.functionTrimRight, _signature: [ { types: [InputArgument.TYPE_STRING], }, { types: [InputArgument.TYPE_STRING], optional: true, }, ], }, type: { _func: this.functionType, _signature: [ { types: [InputArgument.TYPE_ANY], }, ], }, upper: { _func: this.functionUpper, _signature: [ { types: [InputArgument.TYPE_STRING], }, ], }, values: { _func: this.functionValues, _signature: [ { types: [InputArgument.TYPE_OBJECT], }, ], }, zip: { _func: this.functionZip, _signature: [ { types: [InputArgument.TYPE_ARRAY], variadic: true, }, ], }, }; this._interpreter = interpreter; this._functionTable = this.functionTable; } registerFunction(name, customFunction, signature) { if (name in this._functionTable) { throw new Error(`Function already defined: ${name}()`); } this._functionTable[name] = { _func: customFunction.bind(this), _signature: signature, }; } callFunction(name, resolvedArgs) { const functionEntry = this._functionTable[name]; if (functionEntry === undefined) { throw new Error(`Unknown function: ${name}()`); } this.validateArgs(name, resolvedArgs, functionEntry._signature); return functionEntry._func.call(this, resolvedArgs); } validateInputSignatures(name, signature) { for (let i = 0; i < signature.length; i += 1) { if ('variadic' in signature[i] && i !== signature.length - 1) { throw new Error(`Invalid arity: ${name}() 'variadic' argument ${i + 1} must occur last`); } } } validateArgs(name, args, signature) { var _a, _b; let pluralized; this.validateInputSignatures(name, signature); const numberOfRequiredArgs = signature.filter(argSignature => { var _a; return !((_a = argSignature.optional) !== null && _a !== void 0 ? _a : false); }).length; const lastArgIsVariadic = (_b = (_a = signature[signature.length - 1]) === null || _a === void 0 ? void 0 : _a.variadic) !== null && _b !== void 0 ? _b : false; const tooFewArgs = args.length < numberOfRequiredArgs; const tooManyArgs = args.length > signature.length; const tooFewModifier = tooFewArgs && ((!lastArgIsVariadic && numberOfRequiredArgs > 1) || lastArgIsVariadic) ? 'at least ' : ''; if ((lastArgIsVariadic && tooFewArgs) || (!lastArgIsVariadic && (tooFewArgs || tooManyArgs))) { pluralized = signature.length > 1; throw new Error(`Invalid arity: ${name}() takes ${tooFewModifier}${numberOfRequiredArgs} argument${(pluralized && 's') || ''} but received ${args.length}`); } let currentSpec; let actualType; let typeMatched; for (let i = 0; i < signature.length; i += 1) { typeMatched = false; currentSpec = signature[i].types; actualType = this.getTypeName(args[i]); let j; for (j = 0; j < currentSpec.length; j += 1) { if (actualType !== undefined && this.typeMatches(actualType, currentSpec[j], args[i])) { typeMatched = true; break; } } if (!typeMatched && actualType !== undefined) { const expected = currentSpec .map((typeIdentifier) => { return this.TYPE_NAME_TABLE[typeIdentifier]; }) .join(' | '); throw new Error(`Invalid type: ${name}() expected argument ${i + 1} to be type (${expected}) but received type ${this.TYPE_NAME_TABLE[actualType]} instead.`); } } } typeMatches(actual, expected, argValue) { if (expected === InputArgument.TYPE_ANY) { return true; } if (expected === InputArgument.TYPE_ARRAY_STRING || expected === InputArgument.TYPE_ARRAY_NUMBER || expected === InputArgument.TYPE_ARRAY_OBJECT || expected === InputArgument.TYPE_ARRAY_ARRAY || expected === InputArgument.TYPE_ARRAY) { if (expected === InputArgument.TYPE_ARRAY) { return actual === InputArgument.TYPE_ARRAY; } if (actual === InputArgument.TYPE_ARRAY) { let subtype; if (expected === InputArgument.TYPE_ARRAY_NUMBER) { subtype = InputArgument.TYPE_NUMBER; } else if (expected === InputArgument.TYPE_ARRAY_OBJECT) { subtype = InputArgument.TYPE_OBJECT; } else if (expected === InputArgument.TYPE_ARRAY_STRING) { subtype = InputArgument.TYPE_STRING; } else if (expected === InputArgument.TYPE_ARRAY_ARRAY) { subtype = InputArgument.TYPE_ARRAY; } const array = argValue; for (let i = 0; i < array.length; i += 1) { const typeName = this.getTypeName(array[i]); if (typeName !== undefined && subtype !== undefined && !this.typeMatches(typeName, subtype, array[i])) { return false; } } return true; } } else { return actual === expected; } return false; } getTypeName(obj) { switch (Object.prototype.toString.call(obj)) { case '[object String]': return InputArgument.TYPE_STRING; case '[object Number]': return InputArgument.TYPE_NUMBER; case '[object Array]': return InputArgument.TYPE_ARRAY; case '[object Boolean]': return InputArgument.TYPE_BOOLEAN; case '[object Null]': return InputArgument.TYPE_NULL; case '[object Object]': if (obj.expref) { return InputArgument.TYPE_EXPREF; } return InputArgument.TYPE_OBJECT; default: return; } } createKeyFunction(exprefNode, allowedTypes) { const interpreter = this._interpreter; const keyFunc = (x) => { const current = interpreter.visit(exprefNode, x); if (!allowedTypes.includes(this.getTypeName(current))) { const msg = `Invalid type: expected one of (${allowedTypes .map(t => this.TYPE_NAME_TABLE[t]) .join(' | ')}), received ${this.TYPE_NAME_TABLE[this.getTypeName(current)]}`; throw new Error(msg); } return current; }; return keyFunc; } } exports.Runtime = Runtime; //# sourceMappingURL=Runtime.js.map