9867 lines
357 KiB
JavaScript
9867 lines
357 KiB
JavaScript
/**
|
||
* Copyright (c) 2014-present, Facebook, Inc.
|
||
*
|
||
* This source code is licensed under the MIT license found in the
|
||
* LICENSE file in the root directory of this source tree.
|
||
*/
|
||
|
||
var runtime = (function (exports) {
|
||
"use strict";
|
||
|
||
var Op = Object.prototype;
|
||
var hasOwn = Op.hasOwnProperty;
|
||
var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; };
|
||
var undefined; // More compressible than void 0.
|
||
var $Symbol = typeof Symbol === "function" ? Symbol : {};
|
||
var iteratorSymbol = $Symbol.iterator || "@@iterator";
|
||
var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
|
||
var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
|
||
|
||
function define(obj, key, value) {
|
||
Object.defineProperty(obj, key, {
|
||
value: value,
|
||
enumerable: true,
|
||
configurable: true,
|
||
writable: true
|
||
});
|
||
return obj[key];
|
||
}
|
||
try {
|
||
// IE 8 has a broken Object.defineProperty that only works on DOM objects.
|
||
define({}, "");
|
||
} catch (err) {
|
||
define = function(obj, key, value) {
|
||
return obj[key] = value;
|
||
};
|
||
}
|
||
|
||
function wrap(innerFn, outerFn, self, tryLocsList) {
|
||
// If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
|
||
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
|
||
var generator = Object.create(protoGenerator.prototype);
|
||
var context = new Context(tryLocsList || []);
|
||
|
||
// The ._invoke method unifies the implementations of the .next,
|
||
// .throw, and .return methods.
|
||
defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) });
|
||
|
||
return generator;
|
||
}
|
||
exports.wrap = wrap;
|
||
|
||
// Try/catch helper to minimize deoptimizations. Returns a completion
|
||
// record like context.tryEntries[i].completion. This interface could
|
||
// have been (and was previously) designed to take a closure to be
|
||
// invoked without arguments, but in all the cases we care about we
|
||
// already have an existing method we want to call, so there's no need
|
||
// to create a new function object. We can even get away with assuming
|
||
// the method takes exactly one argument, since that happens to be true
|
||
// in every case, so we don't have to touch the arguments object. The
|
||
// only additional allocation required is the completion record, which
|
||
// has a stable shape and so hopefully should be cheap to allocate.
|
||
function tryCatch(fn, obj, arg) {
|
||
try {
|
||
return { type: "normal", arg: fn.call(obj, arg) };
|
||
} catch (err) {
|
||
return { type: "throw", arg: err };
|
||
}
|
||
}
|
||
|
||
var GenStateSuspendedStart = "suspendedStart";
|
||
var GenStateSuspendedYield = "suspendedYield";
|
||
var GenStateExecuting = "executing";
|
||
var GenStateCompleted = "completed";
|
||
|
||
// Returning this object from the innerFn has the same effect as
|
||
// breaking out of the dispatch switch statement.
|
||
var ContinueSentinel = {};
|
||
|
||
// Dummy constructor functions that we use as the .constructor and
|
||
// .constructor.prototype properties for functions that return Generator
|
||
// objects. For full spec compliance, you may wish to configure your
|
||
// minifier not to mangle the names of these two functions.
|
||
function Generator() {}
|
||
function GeneratorFunction() {}
|
||
function GeneratorFunctionPrototype() {}
|
||
|
||
// This is a polyfill for %IteratorPrototype% for environments that
|
||
// don't natively support it.
|
||
var IteratorPrototype = {};
|
||
define(IteratorPrototype, iteratorSymbol, function () {
|
||
return this;
|
||
});
|
||
|
||
var getProto = Object.getPrototypeOf;
|
||
var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
|
||
if (NativeIteratorPrototype &&
|
||
NativeIteratorPrototype !== Op &&
|
||
hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
|
||
// This environment has a native %IteratorPrototype%; use it instead
|
||
// of the polyfill.
|
||
IteratorPrototype = NativeIteratorPrototype;
|
||
}
|
||
|
||
var Gp = GeneratorFunctionPrototype.prototype =
|
||
Generator.prototype = Object.create(IteratorPrototype);
|
||
GeneratorFunction.prototype = GeneratorFunctionPrototype;
|
||
defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true });
|
||
defineProperty(
|
||
GeneratorFunctionPrototype,
|
||
"constructor",
|
||
{ value: GeneratorFunction, configurable: true }
|
||
);
|
||
GeneratorFunction.displayName = define(
|
||
GeneratorFunctionPrototype,
|
||
toStringTagSymbol,
|
||
"GeneratorFunction"
|
||
);
|
||
|
||
// Helper for defining the .next, .throw, and .return methods of the
|
||
// Iterator interface in terms of a single ._invoke method.
|
||
function defineIteratorMethods(prototype) {
|
||
["next", "throw", "return"].forEach(function(method) {
|
||
define(prototype, method, function(arg) {
|
||
return this._invoke(method, arg);
|
||
});
|
||
});
|
||
}
|
||
|
||
exports.isGeneratorFunction = function(genFun) {
|
||
var ctor = typeof genFun === "function" && genFun.constructor;
|
||
return ctor
|
||
? ctor === GeneratorFunction ||
|
||
// For the native GeneratorFunction constructor, the best we can
|
||
// do is to check its .name property.
|
||
(ctor.displayName || ctor.name) === "GeneratorFunction"
|
||
: false;
|
||
};
|
||
|
||
exports.mark = function(genFun) {
|
||
if (Object.setPrototypeOf) {
|
||
Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
|
||
} else {
|
||
genFun.__proto__ = GeneratorFunctionPrototype;
|
||
define(genFun, toStringTagSymbol, "GeneratorFunction");
|
||
}
|
||
genFun.prototype = Object.create(Gp);
|
||
return genFun;
|
||
};
|
||
|
||
// Within the body of any async function, `await x` is transformed to
|
||
// `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
|
||
// `hasOwn.call(value, "__await")` to determine if the yielded value is
|
||
// meant to be awaited.
|
||
exports.awrap = function(arg) {
|
||
return { __await: arg };
|
||
};
|
||
|
||
function AsyncIterator(generator, PromiseImpl) {
|
||
function invoke(method, arg, resolve, reject) {
|
||
var record = tryCatch(generator[method], generator, arg);
|
||
if (record.type === "throw") {
|
||
reject(record.arg);
|
||
} else {
|
||
var result = record.arg;
|
||
var value = result.value;
|
||
if (value &&
|
||
typeof value === "object" &&
|
||
hasOwn.call(value, "__await")) {
|
||
return PromiseImpl.resolve(value.__await).then(function(value) {
|
||
invoke("next", value, resolve, reject);
|
||
}, function(err) {
|
||
invoke("throw", err, resolve, reject);
|
||
});
|
||
}
|
||
|
||
return PromiseImpl.resolve(value).then(function(unwrapped) {
|
||
// When a yielded Promise is resolved, its final value becomes
|
||
// the .value of the Promise<{value,done}> result for the
|
||
// current iteration.
|
||
result.value = unwrapped;
|
||
resolve(result);
|
||
}, function(error) {
|
||
// If a rejected Promise was yielded, throw the rejection back
|
||
// into the async generator function so it can be handled there.
|
||
return invoke("throw", error, resolve, reject);
|
||
});
|
||
}
|
||
}
|
||
|
||
var previousPromise;
|
||
|
||
function enqueue(method, arg) {
|
||
function callInvokeWithMethodAndArg() {
|
||
return new PromiseImpl(function(resolve, reject) {
|
||
invoke(method, arg, resolve, reject);
|
||
});
|
||
}
|
||
|
||
return previousPromise =
|
||
// If enqueue has been called before, then we want to wait until
|
||
// all previous Promises have been resolved before calling invoke,
|
||
// so that results are always delivered in the correct order. If
|
||
// enqueue has not been called before, then it is important to
|
||
// call invoke immediately, without waiting on a callback to fire,
|
||
// so that the async generator function has the opportunity to do
|
||
// any necessary setup in a predictable way. This predictability
|
||
// is why the Promise constructor synchronously invokes its
|
||
// executor callback, and why async functions synchronously
|
||
// execute code before the first await. Since we implement simple
|
||
// async functions in terms of async generators, it is especially
|
||
// important to get this right, even though it requires care.
|
||
previousPromise ? previousPromise.then(
|
||
callInvokeWithMethodAndArg,
|
||
// Avoid propagating failures to Promises returned by later
|
||
// invocations of the iterator.
|
||
callInvokeWithMethodAndArg
|
||
) : callInvokeWithMethodAndArg();
|
||
}
|
||
|
||
// Define the unified helper method that is used to implement .next,
|
||
// .throw, and .return (see defineIteratorMethods).
|
||
defineProperty(this, "_invoke", { value: enqueue });
|
||
}
|
||
|
||
defineIteratorMethods(AsyncIterator.prototype);
|
||
define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
|
||
return this;
|
||
});
|
||
exports.AsyncIterator = AsyncIterator;
|
||
|
||
// Note that simple async functions are implemented on top of
|
||
// AsyncIterator objects; they just return a Promise for the value of
|
||
// the final result produced by the iterator.
|
||
exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) {
|
||
if (PromiseImpl === void 0) PromiseImpl = Promise;
|
||
|
||
var iter = new AsyncIterator(
|
||
wrap(innerFn, outerFn, self, tryLocsList),
|
||
PromiseImpl
|
||
);
|
||
|
||
return exports.isGeneratorFunction(outerFn)
|
||
? iter // If outerFn is a generator, return the full iterator.
|
||
: iter.next().then(function(result) {
|
||
return result.done ? result.value : iter.next();
|
||
});
|
||
};
|
||
|
||
function makeInvokeMethod(innerFn, self, context) {
|
||
var state = GenStateSuspendedStart;
|
||
|
||
return function invoke(method, arg) {
|
||
if (state === GenStateExecuting) {
|
||
throw new Error("Generator is already running");
|
||
}
|
||
|
||
if (state === GenStateCompleted) {
|
||
if (method === "throw") {
|
||
throw arg;
|
||
}
|
||
|
||
// Be forgiving, per GeneratorResume behavior specified since ES2015:
|
||
// ES2015 spec, step 3: https://262.ecma-international.org/6.0/#sec-generatorresume
|
||
// Latest spec, step 2: https://tc39.es/ecma262/#sec-generatorresume
|
||
return doneResult();
|
||
}
|
||
|
||
context.method = method;
|
||
context.arg = arg;
|
||
|
||
while (true) {
|
||
var delegate = context.delegate;
|
||
if (delegate) {
|
||
var delegateResult = maybeInvokeDelegate(delegate, context);
|
||
if (delegateResult) {
|
||
if (delegateResult === ContinueSentinel) continue;
|
||
return delegateResult;
|
||
}
|
||
}
|
||
|
||
if (context.method === "next") {
|
||
// Setting context._sent for legacy support of Babel's
|
||
// function.sent implementation.
|
||
context.sent = context._sent = context.arg;
|
||
|
||
} else if (context.method === "throw") {
|
||
if (state === GenStateSuspendedStart) {
|
||
state = GenStateCompleted;
|
||
throw context.arg;
|
||
}
|
||
|
||
context.dispatchException(context.arg);
|
||
|
||
} else if (context.method === "return") {
|
||
context.abrupt("return", context.arg);
|
||
}
|
||
|
||
state = GenStateExecuting;
|
||
|
||
var record = tryCatch(innerFn, self, context);
|
||
if (record.type === "normal") {
|
||
// If an exception is thrown from innerFn, we leave state ===
|
||
// GenStateExecuting and loop back for another invocation.
|
||
state = context.done
|
||
? GenStateCompleted
|
||
: GenStateSuspendedYield;
|
||
|
||
if (record.arg === ContinueSentinel) {
|
||
continue;
|
||
}
|
||
|
||
return {
|
||
value: record.arg,
|
||
done: context.done
|
||
};
|
||
|
||
} else if (record.type === "throw") {
|
||
state = GenStateCompleted;
|
||
// Dispatch the exception by looping back around to the
|
||
// context.dispatchException(context.arg) call above.
|
||
context.method = "throw";
|
||
context.arg = record.arg;
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
// Call delegate.iterator[context.method](context.arg) and handle the
|
||
// result, either by returning a { value, done } result from the
|
||
// delegate iterator, or by modifying context.method and context.arg,
|
||
// setting context.delegate to null, and returning the ContinueSentinel.
|
||
function maybeInvokeDelegate(delegate, context) {
|
||
var methodName = context.method;
|
||
var method = delegate.iterator[methodName];
|
||
if (method === undefined) {
|
||
// A .throw or .return when the delegate iterator has no .throw
|
||
// method, or a missing .next method, always terminate the
|
||
// yield* loop.
|
||
context.delegate = null;
|
||
|
||
// Note: ["return"] must be used for ES3 parsing compatibility.
|
||
if (methodName === "throw" && delegate.iterator["return"]) {
|
||
// If the delegate iterator has a return method, give it a
|
||
// chance to clean up.
|
||
context.method = "return";
|
||
context.arg = undefined;
|
||
maybeInvokeDelegate(delegate, context);
|
||
|
||
if (context.method === "throw") {
|
||
// If maybeInvokeDelegate(context) changed context.method from
|
||
// "return" to "throw", let that override the TypeError below.
|
||
return ContinueSentinel;
|
||
}
|
||
}
|
||
if (methodName !== "return") {
|
||
context.method = "throw";
|
||
context.arg = new TypeError(
|
||
"The iterator does not provide a '" + methodName + "' method");
|
||
}
|
||
|
||
return ContinueSentinel;
|
||
}
|
||
|
||
var record = tryCatch(method, delegate.iterator, context.arg);
|
||
|
||
if (record.type === "throw") {
|
||
context.method = "throw";
|
||
context.arg = record.arg;
|
||
context.delegate = null;
|
||
return ContinueSentinel;
|
||
}
|
||
|
||
var info = record.arg;
|
||
|
||
if (! info) {
|
||
context.method = "throw";
|
||
context.arg = new TypeError("iterator result is not an object");
|
||
context.delegate = null;
|
||
return ContinueSentinel;
|
||
}
|
||
|
||
if (info.done) {
|
||
// Assign the result of the finished delegate to the temporary
|
||
// variable specified by delegate.resultName (see delegateYield).
|
||
context[delegate.resultName] = info.value;
|
||
|
||
// Resume execution at the desired location (see delegateYield).
|
||
context.next = delegate.nextLoc;
|
||
|
||
// If context.method was "throw" but the delegate handled the
|
||
// exception, let the outer generator proceed normally. If
|
||
// context.method was "next", forget context.arg since it has been
|
||
// "consumed" by the delegate iterator. If context.method was
|
||
// "return", allow the original .return call to continue in the
|
||
// outer generator.
|
||
if (context.method !== "return") {
|
||
context.method = "next";
|
||
context.arg = undefined;
|
||
}
|
||
|
||
} else {
|
||
// Re-yield the result returned by the delegate method.
|
||
return info;
|
||
}
|
||
|
||
// The delegate iterator is finished, so forget it and continue with
|
||
// the outer generator.
|
||
context.delegate = null;
|
||
return ContinueSentinel;
|
||
}
|
||
|
||
// Define Generator.prototype.{next,throw,return} in terms of the
|
||
// unified ._invoke helper method.
|
||
defineIteratorMethods(Gp);
|
||
|
||
define(Gp, toStringTagSymbol, "Generator");
|
||
|
||
// A Generator should always return itself as the iterator object when the
|
||
// @@iterator function is called on it. Some browsers' implementations of the
|
||
// iterator prototype chain incorrectly implement this, causing the Generator
|
||
// object to not be returned from this call. This ensures that doesn't happen.
|
||
// See https://github.com/facebook/regenerator/issues/274 for more details.
|
||
define(Gp, iteratorSymbol, function() {
|
||
return this;
|
||
});
|
||
|
||
define(Gp, "toString", function() {
|
||
return "[object Generator]";
|
||
});
|
||
|
||
function pushTryEntry(locs) {
|
||
var entry = { tryLoc: locs[0] };
|
||
|
||
if (1 in locs) {
|
||
entry.catchLoc = locs[1];
|
||
}
|
||
|
||
if (2 in locs) {
|
||
entry.finallyLoc = locs[2];
|
||
entry.afterLoc = locs[3];
|
||
}
|
||
|
||
this.tryEntries.push(entry);
|
||
}
|
||
|
||
function resetTryEntry(entry) {
|
||
var record = entry.completion || {};
|
||
record.type = "normal";
|
||
delete record.arg;
|
||
entry.completion = record;
|
||
}
|
||
|
||
function Context(tryLocsList) {
|
||
// The root entry object (effectively a try statement without a catch
|
||
// or a finally block) gives us a place to store values thrown from
|
||
// locations where there is no enclosing try statement.
|
||
this.tryEntries = [{ tryLoc: "root" }];
|
||
tryLocsList.forEach(pushTryEntry, this);
|
||
this.reset(true);
|
||
}
|
||
|
||
exports.keys = function(val) {
|
||
var object = Object(val);
|
||
var keys = [];
|
||
for (var key in object) {
|
||
keys.push(key);
|
||
}
|
||
keys.reverse();
|
||
|
||
// Rather than returning an object with a next method, we keep
|
||
// things simple and return the next function itself.
|
||
return function next() {
|
||
while (keys.length) {
|
||
var key = keys.pop();
|
||
if (key in object) {
|
||
next.value = key;
|
||
next.done = false;
|
||
return next;
|
||
}
|
||
}
|
||
|
||
// To avoid creating an additional object, we just hang the .value
|
||
// and .done properties off the next function object itself. This
|
||
// also ensures that the minifier will not anonymize the function.
|
||
next.done = true;
|
||
return next;
|
||
};
|
||
};
|
||
|
||
function values(iterable) {
|
||
if (iterable != null) {
|
||
var iteratorMethod = iterable[iteratorSymbol];
|
||
if (iteratorMethod) {
|
||
return iteratorMethod.call(iterable);
|
||
}
|
||
|
||
if (typeof iterable.next === "function") {
|
||
return iterable;
|
||
}
|
||
|
||
if (!isNaN(iterable.length)) {
|
||
var i = -1, next = function next() {
|
||
while (++i < iterable.length) {
|
||
if (hasOwn.call(iterable, i)) {
|
||
next.value = iterable[i];
|
||
next.done = false;
|
||
return next;
|
||
}
|
||
}
|
||
|
||
next.value = undefined;
|
||
next.done = true;
|
||
|
||
return next;
|
||
};
|
||
|
||
return next.next = next;
|
||
}
|
||
}
|
||
|
||
throw new TypeError(typeof iterable + " is not iterable");
|
||
}
|
||
exports.values = values;
|
||
|
||
function doneResult() {
|
||
return { value: undefined, done: true };
|
||
}
|
||
|
||
Context.prototype = {
|
||
constructor: Context,
|
||
|
||
reset: function(skipTempReset) {
|
||
this.prev = 0;
|
||
this.next = 0;
|
||
// Resetting context._sent for legacy support of Babel's
|
||
// function.sent implementation.
|
||
this.sent = this._sent = undefined;
|
||
this.done = false;
|
||
this.delegate = null;
|
||
|
||
this.method = "next";
|
||
this.arg = undefined;
|
||
|
||
this.tryEntries.forEach(resetTryEntry);
|
||
|
||
if (!skipTempReset) {
|
||
for (var name in this) {
|
||
// Not sure about the optimal order of these conditions:
|
||
if (name.charAt(0) === "t" &&
|
||
hasOwn.call(this, name) &&
|
||
!isNaN(+name.slice(1))) {
|
||
this[name] = undefined;
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
stop: function() {
|
||
this.done = true;
|
||
|
||
var rootEntry = this.tryEntries[0];
|
||
var rootRecord = rootEntry.completion;
|
||
if (rootRecord.type === "throw") {
|
||
throw rootRecord.arg;
|
||
}
|
||
|
||
return this.rval;
|
||
},
|
||
|
||
dispatchException: function(exception) {
|
||
if (this.done) {
|
||
throw exception;
|
||
}
|
||
|
||
var context = this;
|
||
function handle(loc, caught) {
|
||
record.type = "throw";
|
||
record.arg = exception;
|
||
context.next = loc;
|
||
|
||
if (caught) {
|
||
// If the dispatched exception was caught by a catch block,
|
||
// then let that catch block handle the exception normally.
|
||
context.method = "next";
|
||
context.arg = undefined;
|
||
}
|
||
|
||
return !! caught;
|
||
}
|
||
|
||
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
||
var entry = this.tryEntries[i];
|
||
var record = entry.completion;
|
||
|
||
if (entry.tryLoc === "root") {
|
||
// Exception thrown outside of any try block that could handle
|
||
// it, so set the completion value of the entire function to
|
||
// throw the exception.
|
||
return handle("end");
|
||
}
|
||
|
||
if (entry.tryLoc <= this.prev) {
|
||
var hasCatch = hasOwn.call(entry, "catchLoc");
|
||
var hasFinally = hasOwn.call(entry, "finallyLoc");
|
||
|
||
if (hasCatch && hasFinally) {
|
||
if (this.prev < entry.catchLoc) {
|
||
return handle(entry.catchLoc, true);
|
||
} else if (this.prev < entry.finallyLoc) {
|
||
return handle(entry.finallyLoc);
|
||
}
|
||
|
||
} else if (hasCatch) {
|
||
if (this.prev < entry.catchLoc) {
|
||
return handle(entry.catchLoc, true);
|
||
}
|
||
|
||
} else if (hasFinally) {
|
||
if (this.prev < entry.finallyLoc) {
|
||
return handle(entry.finallyLoc);
|
||
}
|
||
|
||
} else {
|
||
throw new Error("try statement without catch or finally");
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
abrupt: function(type, arg) {
|
||
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
||
var entry = this.tryEntries[i];
|
||
if (entry.tryLoc <= this.prev &&
|
||
hasOwn.call(entry, "finallyLoc") &&
|
||
this.prev < entry.finallyLoc) {
|
||
var finallyEntry = entry;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (finallyEntry &&
|
||
(type === "break" ||
|
||
type === "continue") &&
|
||
finallyEntry.tryLoc <= arg &&
|
||
arg <= finallyEntry.finallyLoc) {
|
||
// Ignore the finally entry if control is not jumping to a
|
||
// location outside the try/catch block.
|
||
finallyEntry = null;
|
||
}
|
||
|
||
var record = finallyEntry ? finallyEntry.completion : {};
|
||
record.type = type;
|
||
record.arg = arg;
|
||
|
||
if (finallyEntry) {
|
||
this.method = "next";
|
||
this.next = finallyEntry.finallyLoc;
|
||
return ContinueSentinel;
|
||
}
|
||
|
||
return this.complete(record);
|
||
},
|
||
|
||
complete: function(record, afterLoc) {
|
||
if (record.type === "throw") {
|
||
throw record.arg;
|
||
}
|
||
|
||
if (record.type === "break" ||
|
||
record.type === "continue") {
|
||
this.next = record.arg;
|
||
} else if (record.type === "return") {
|
||
this.rval = this.arg = record.arg;
|
||
this.method = "return";
|
||
this.next = "end";
|
||
} else if (record.type === "normal" && afterLoc) {
|
||
this.next = afterLoc;
|
||
}
|
||
|
||
return ContinueSentinel;
|
||
},
|
||
|
||
finish: function(finallyLoc) {
|
||
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
||
var entry = this.tryEntries[i];
|
||
if (entry.finallyLoc === finallyLoc) {
|
||
this.complete(entry.completion, entry.afterLoc);
|
||
resetTryEntry(entry);
|
||
return ContinueSentinel;
|
||
}
|
||
}
|
||
},
|
||
|
||
"catch": function(tryLoc) {
|
||
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
||
var entry = this.tryEntries[i];
|
||
if (entry.tryLoc === tryLoc) {
|
||
var record = entry.completion;
|
||
if (record.type === "throw") {
|
||
var thrown = record.arg;
|
||
resetTryEntry(entry);
|
||
}
|
||
return thrown;
|
||
}
|
||
}
|
||
|
||
// The context.catch method must only be called with a location
|
||
// argument that corresponds to a known catch block.
|
||
throw new Error("illegal catch attempt");
|
||
},
|
||
|
||
delegateYield: function(iterable, resultName, nextLoc) {
|
||
this.delegate = {
|
||
iterator: values(iterable),
|
||
resultName: resultName,
|
||
nextLoc: nextLoc
|
||
};
|
||
|
||
if (this.method === "next") {
|
||
// Deliberately forget the last sent value so that we don't
|
||
// accidentally pass it on to the delegate.
|
||
this.arg = undefined;
|
||
}
|
||
|
||
return ContinueSentinel;
|
||
}
|
||
};
|
||
|
||
// Regardless of whether this script is executing as a CommonJS module
|
||
// or not, return the runtime object so that we can declare the variable
|
||
// regeneratorRuntime in the outer scope, which allows this module to be
|
||
// injected easily by `bin/regenerator --include-runtime script.js`.
|
||
return exports;
|
||
|
||
}(
|
||
// If this script is executing as a CommonJS module, use module.exports
|
||
// as the regeneratorRuntime namespace. Otherwise create a new empty
|
||
// object. Either way, the resulting object will be used to initialize
|
||
// the regeneratorRuntime variable at the top of this file.
|
||
typeof module === "object" ? module.exports : {}
|
||
));
|
||
|
||
try {
|
||
regeneratorRuntime = runtime;
|
||
} catch (accidentalStrictMode) {
|
||
// This module should not be running in strict mode, so the above
|
||
// assignment should always work unless something is misconfigured. Just
|
||
// in case runtime.js accidentally runs in strict mode, in modern engines
|
||
// we can explicitly access globalThis. In older engines we can escape
|
||
// strict mode using a global Function call. This could conceivably fail
|
||
// if a Content Security Policy forbids using Function, but in that case
|
||
// the proper solution is to fix the accidental strict mode problem. If
|
||
// you've misconfigured your bundler to force strict mode and applied a
|
||
// CSP to forbid Function, and you're not willing to fix either of those
|
||
// problems, please detail your unique predicament in a GitHub issue.
|
||
if (typeof globalThis === "object") {
|
||
globalThis.regeneratorRuntime = runtime;
|
||
} else {
|
||
Function("r", "regeneratorRuntime = r")(runtime);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* © Copyright IBM Corp. 2018 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
// This file contains polyfills (cut and pasted from MDN docs) required for the ES5 package
|
||
|
||
Number.isInteger = Number.isInteger || function (value) {
|
||
return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
|
||
};
|
||
if (!String.fromCodePoint) (function (stringFromCharCode) {
|
||
var fromCodePoint = function (_) {
|
||
var codeUnits = [],
|
||
codeLen = 0,
|
||
result = "";
|
||
for (var index = 0, len = arguments.length; index !== len; ++index) {
|
||
var codePoint = +arguments[index];
|
||
// correctly handles all cases including `NaN`, `-Infinity`, `+Infinity`
|
||
// The surrounding `!(...)` is required to correctly handle `NaN` cases
|
||
// The (codePoint>>>0) === codePoint clause handles decimals and negatives
|
||
if (!(codePoint < 0x10FFFF && codePoint >>> 0 === codePoint)) throw RangeError("Invalid code point: " + codePoint);
|
||
if (codePoint <= 0xFFFF) {
|
||
// BMP code point
|
||
codeLen = codeUnits.push(codePoint);
|
||
} else {
|
||
// Astral code point; split in surrogate halves
|
||
// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
||
codePoint -= 0x10000;
|
||
codeLen = codeUnits.push((codePoint >> 10) + 0xD800,
|
||
// highSurrogate
|
||
codePoint % 0x400 + 0xDC00 // lowSurrogate
|
||
);
|
||
}
|
||
if (codeLen >= 0x3fff) {
|
||
result += stringFromCharCode.apply(null, codeUnits);
|
||
codeUnits.length = 0;
|
||
}
|
||
}
|
||
return result + stringFromCharCode.apply(null, codeUnits);
|
||
};
|
||
try {
|
||
// IE 8 only supports `Object.defineProperty` on DOM elements
|
||
Object.defineProperty(String, "fromCodePoint", {
|
||
"value": fromCodePoint,
|
||
"configurable": true,
|
||
"writable": true
|
||
});
|
||
} catch (e) {
|
||
String.fromCodePoint = fromCodePoint;
|
||
}
|
||
})(String.fromCharCode);
|
||
if (!Object.is) {
|
||
Object.is = function (x, y) {
|
||
// SameValue algorithm
|
||
if (x === y) {
|
||
// Steps 1-5, 7-10
|
||
// Steps 6.b-6.e: +0 != -0
|
||
return x !== 0 || 1 / x === 1 / y;
|
||
} else {
|
||
// Step 6.a: NaN == NaN
|
||
return x !== x && y !== y;
|
||
}
|
||
};
|
||
}
|
||
|
||
/*! https://mths.be/codepointat v0.2.0 by @mathias */
|
||
if (!String.prototype.codePointAt) {
|
||
(function () {
|
||
'use strict';
|
||
|
||
// needed to support `apply`/`call` with `undefined`/`null`
|
||
var defineProperty = function () {
|
||
// IE 8 only supports `Object.defineProperty` on DOM elements
|
||
try {
|
||
var object = {};
|
||
var $defineProperty = Object.defineProperty;
|
||
var result = $defineProperty(object, object, object) && $defineProperty;
|
||
} catch (error) {}
|
||
return result;
|
||
}();
|
||
var codePointAt = function (position) {
|
||
if (this == null) {
|
||
throw TypeError();
|
||
}
|
||
var string = String(this);
|
||
var size = string.length;
|
||
// `ToInteger`
|
||
var index = position ? Number(position) : 0;
|
||
if (index != index) {
|
||
// better `isNaN`
|
||
index = 0;
|
||
}
|
||
// Account for out-of-bounds indices:
|
||
if (index < 0 || index >= size) {
|
||
return undefined;
|
||
}
|
||
// Get the first code unit
|
||
var first = string.charCodeAt(index);
|
||
var second;
|
||
if (
|
||
// check if it’s the start of a surrogate pair
|
||
first >= 0xD800 && first <= 0xDBFF &&
|
||
// high surrogate
|
||
size > index + 1 // there is a next code unit
|
||
) {
|
||
second = string.charCodeAt(index + 1);
|
||
if (second >= 0xDC00 && second <= 0xDFFF) {
|
||
// low surrogate
|
||
// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
||
return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
|
||
}
|
||
}
|
||
return first;
|
||
};
|
||
if (defineProperty) {
|
||
defineProperty(String.prototype, 'codePointAt', {
|
||
'value': codePointAt,
|
||
'configurable': true,
|
||
'writable': true
|
||
});
|
||
} else {
|
||
String.prototype.codePointAt = codePointAt;
|
||
}
|
||
})();
|
||
}
|
||
Math.log10 = Math.log10 || function (x) {
|
||
return Math.log(x) * Math.LOG10E;
|
||
};
|
||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsonata = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||
"use strict";
|
||
|
||
/**
|
||
* © Copyright IBM Corp. 2018 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
var utils = require('./utils');
|
||
|
||
/**
|
||
* DateTime formatting and parsing functions
|
||
* Implements the xpath-functions format-date-time specification
|
||
* @type {{formatInteger, formatDateTime, parseInteger, parseDateTime}}
|
||
*/
|
||
var dateTime = function () {
|
||
'use strict';
|
||
|
||
var stringToArray = utils.stringToArray;
|
||
var few = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'];
|
||
var ordinals = ['Zeroth', 'First', 'Second', 'Third', 'Fourth', 'Fifth', 'Sixth', 'Seventh', 'Eighth', 'Ninth', 'Tenth', 'Eleventh', 'Twelfth', 'Thirteenth', 'Fourteenth', 'Fifteenth', 'Sixteenth', 'Seventeenth', 'Eighteenth', 'Nineteenth'];
|
||
var decades = ['Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety', 'Hundred'];
|
||
var magnitudes = ['Thousand', 'Million', 'Billion', 'Trillion'];
|
||
|
||
/**
|
||
* converts a number into english words
|
||
* @param {string} value - the value to format
|
||
* @param {boolean} ordinal - ordinal or cardinal form
|
||
* @returns {string} - representation in words
|
||
*/
|
||
function numberToWords(value, ordinal) {
|
||
var lookup = function lookup(num, prev, ord) {
|
||
var words = '';
|
||
if (num <= 19) {
|
||
words = (prev ? ' and ' : '') + (ord ? ordinals[num] : few[num]);
|
||
} else if (num < 100) {
|
||
var tens = Math.floor(num / 10);
|
||
var remainder = num % 10;
|
||
words = (prev ? ' and ' : '') + decades[tens - 2];
|
||
if (remainder > 0) {
|
||
words += '-' + lookup(remainder, false, ord);
|
||
} else if (ord) {
|
||
words = words.substring(0, words.length - 1) + 'ieth';
|
||
}
|
||
} else if (num < 1000) {
|
||
var hundreds = Math.floor(num / 100);
|
||
var _remainder = num % 100;
|
||
words = (prev ? ', ' : '') + few[hundreds] + ' Hundred';
|
||
if (_remainder > 0) {
|
||
words += lookup(_remainder, true, ord);
|
||
} else if (ord) {
|
||
words += 'th';
|
||
}
|
||
} else {
|
||
var mag = Math.floor(Math.log10(num) / 3);
|
||
if (mag > magnitudes.length) {
|
||
mag = magnitudes.length; // the largest word
|
||
}
|
||
var factor = Math.pow(10, mag * 3);
|
||
var mant = Math.floor(num / factor);
|
||
var _remainder2 = num - mant * factor;
|
||
words = (prev ? ', ' : '') + lookup(mant, false, false) + ' ' + magnitudes[mag - 1];
|
||
if (_remainder2 > 0) {
|
||
words += lookup(_remainder2, true, ord);
|
||
} else if (ord) {
|
||
words += 'th';
|
||
}
|
||
}
|
||
return words;
|
||
};
|
||
var words = lookup(value, false, ordinal);
|
||
return words;
|
||
}
|
||
var wordValues = {};
|
||
few.forEach(function (word, index) {
|
||
wordValues[word.toLowerCase()] = index;
|
||
});
|
||
ordinals.forEach(function (word, index) {
|
||
wordValues[word.toLowerCase()] = index;
|
||
});
|
||
decades.forEach(function (word, index) {
|
||
var lword = word.toLowerCase();
|
||
wordValues[lword] = (index + 2) * 10;
|
||
wordValues[lword.substring(0, word.length - 1) + 'ieth'] = wordValues[lword];
|
||
});
|
||
wordValues.hundredth = 100;
|
||
magnitudes.forEach(function (word, index) {
|
||
var lword = word.toLowerCase();
|
||
var val = Math.pow(10, (index + 1) * 3);
|
||
wordValues[lword] = val;
|
||
wordValues[lword + 'th'] = val;
|
||
});
|
||
|
||
/**
|
||
* Converts a number in english words to numeric value
|
||
* @param {string} text - the number in words
|
||
* @returns {number} - the numeric value
|
||
*/
|
||
function wordsToNumber(text) {
|
||
var parts = text.split(/,\s|\sand\s|[\s\\-]/);
|
||
var values = parts.map(function (part) {
|
||
return wordValues[part];
|
||
});
|
||
var segs = [0];
|
||
values.forEach(function (value) {
|
||
if (value < 100) {
|
||
var top = segs.pop();
|
||
if (top >= 1000) {
|
||
segs.push(top);
|
||
top = 0;
|
||
}
|
||
segs.push(top + value);
|
||
} else {
|
||
segs.push(segs.pop() * value);
|
||
}
|
||
});
|
||
var result = segs.reduce(function (a, b) {
|
||
return a + b;
|
||
}, 0);
|
||
return result;
|
||
}
|
||
var romanNumerals = [[1000, 'm'], [900, 'cm'], [500, 'd'], [400, 'cd'], [100, 'c'], [90, 'xc'], [50, 'l'], [40, 'xl'], [10, 'x'], [9, 'ix'], [5, 'v'], [4, 'iv'], [1, 'i']];
|
||
var romanValues = {
|
||
'M': 1000,
|
||
'D': 500,
|
||
'C': 100,
|
||
'L': 50,
|
||
'X': 10,
|
||
'V': 5,
|
||
'I': 1
|
||
};
|
||
|
||
/**
|
||
* converts a number to roman numerals
|
||
* @param {number} value - the number
|
||
* @returns {string} - the number in roman numerals
|
||
*/
|
||
function decimalToRoman(value) {
|
||
for (var index = 0; index < romanNumerals.length; index++) {
|
||
var numeral = romanNumerals[index];
|
||
if (value >= numeral[0]) {
|
||
return numeral[1] + decimalToRoman(value - numeral[0]);
|
||
}
|
||
}
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* converts roman numerals to a number
|
||
* @param {string} roman - roman number
|
||
* @returns {number} - the numeric value
|
||
*/
|
||
function romanToDecimal(roman) {
|
||
var decimal = 0;
|
||
var max = 1;
|
||
for (var i = roman.length - 1; i >= 0; i--) {
|
||
var digit = roman[i];
|
||
var value = romanValues[digit];
|
||
if (value < max) {
|
||
decimal -= value;
|
||
} else {
|
||
max = value;
|
||
decimal += value;
|
||
}
|
||
}
|
||
return decimal;
|
||
}
|
||
|
||
/**
|
||
* converts a number to spreadsheet style letters
|
||
* @param {number} value - the number
|
||
* @param {string} aChar - the character representing the start of the sequence, e.g. 'A'
|
||
* @returns {string} - the letters
|
||
*/
|
||
function decimalToLetters(value, aChar) {
|
||
var letters = [];
|
||
var aCode = aChar.charCodeAt(0);
|
||
while (value > 0) {
|
||
letters.unshift(String.fromCharCode((value - 1) % 26 + aCode));
|
||
value = Math.floor((value - 1) / 26);
|
||
}
|
||
return letters.join('');
|
||
}
|
||
|
||
/**
|
||
* converts spreadsheet style letters to a number
|
||
* @param {string} letters - the letters
|
||
* @param {string} aChar - the character representing the start of the sequence, e.g. 'A'
|
||
* @returns {number} - the numeric value
|
||
*/
|
||
function lettersToDecimal(letters, aChar) {
|
||
var aCode = aChar.charCodeAt(0);
|
||
var decimal = 0;
|
||
for (var i = 0; i < letters.length; i++) {
|
||
decimal += (letters.charCodeAt(letters.length - i - 1) - aCode + 1) * Math.pow(26, i);
|
||
}
|
||
return decimal;
|
||
}
|
||
|
||
/**
|
||
* Formats an integer as specified by the XPath fn:format-integer function
|
||
* See https://www.w3.org/TR/xpath-functions-31/#func-format-integer
|
||
* @param {number} value - the number to be formatted
|
||
* @param {string} picture - the picture string that specifies the format
|
||
* @returns {string} - the formatted number
|
||
*/
|
||
function formatInteger(value, picture) {
|
||
if (typeof value === 'undefined') {
|
||
return undefined;
|
||
}
|
||
value = Math.floor(value);
|
||
var format = analyseIntegerPicture(picture);
|
||
return _formatInteger(value, format);
|
||
}
|
||
var formats = {
|
||
DECIMAL: 'decimal',
|
||
LETTERS: 'letters',
|
||
ROMAN: 'roman',
|
||
WORDS: 'words',
|
||
SEQUENCE: 'sequence'
|
||
};
|
||
var tcase = {
|
||
UPPER: 'upper',
|
||
LOWER: 'lower',
|
||
TITLE: 'title'
|
||
};
|
||
|
||
/**
|
||
* formats an integer using a preprocessed representation of the picture string
|
||
* @param {number} value - the number to be formatted
|
||
* @param {object} format - the preprocessed representation of the pucture string
|
||
* @returns {string} - the formatted number
|
||
* @private
|
||
*/
|
||
function _formatInteger(value, format) {
|
||
var formattedInteger;
|
||
var negative = value < 0;
|
||
value = Math.abs(value);
|
||
switch (format.primary) {
|
||
case formats.LETTERS:
|
||
formattedInteger = decimalToLetters(value, format["case"] === tcase.UPPER ? 'A' : 'a');
|
||
break;
|
||
case formats.ROMAN:
|
||
formattedInteger = decimalToRoman(value);
|
||
if (format["case"] === tcase.UPPER) {
|
||
formattedInteger = formattedInteger.toUpperCase();
|
||
}
|
||
break;
|
||
case formats.WORDS:
|
||
formattedInteger = numberToWords(value, format.ordinal);
|
||
if (format["case"] === tcase.UPPER) {
|
||
formattedInteger = formattedInteger.toUpperCase();
|
||
} else if (format["case"] === tcase.LOWER) {
|
||
formattedInteger = formattedInteger.toLowerCase();
|
||
}
|
||
break;
|
||
case formats.DECIMAL:
|
||
formattedInteger = '' + value;
|
||
// TODO use functionPad
|
||
var padLength = format.mandatoryDigits - formattedInteger.length;
|
||
if (padLength > 0) {
|
||
var padding = new Array(padLength + 1).join('0');
|
||
formattedInteger = padding + formattedInteger;
|
||
}
|
||
if (format.zeroCode !== 0x30) {
|
||
formattedInteger = stringToArray(formattedInteger).map(function (code) {
|
||
return String.fromCodePoint(code.codePointAt(0) + format.zeroCode - 0x30);
|
||
}).join('');
|
||
}
|
||
// insert the grouping-separator-signs, if any
|
||
if (format.regular) {
|
||
var n = Math.floor((formattedInteger.length - 1) / format.groupingSeparators.position);
|
||
for (var ii = n; ii > 0; ii--) {
|
||
var pos = formattedInteger.length - ii * format.groupingSeparators.position;
|
||
formattedInteger = formattedInteger.substr(0, pos) + format.groupingSeparators.character + formattedInteger.substr(pos);
|
||
}
|
||
} else {
|
||
format.groupingSeparators.reverse().forEach(function (separator) {
|
||
var pos = formattedInteger.length - separator.position;
|
||
formattedInteger = formattedInteger.substr(0, pos) + separator.character + formattedInteger.substr(pos);
|
||
});
|
||
}
|
||
if (format.ordinal) {
|
||
var suffix123 = {
|
||
'1': 'st',
|
||
'2': 'nd',
|
||
'3': 'rd'
|
||
};
|
||
var lastDigit = formattedInteger[formattedInteger.length - 1];
|
||
var suffix = suffix123[lastDigit];
|
||
if (!suffix || formattedInteger.length > 1 && formattedInteger[formattedInteger.length - 2] === '1') {
|
||
suffix = 'th';
|
||
}
|
||
formattedInteger = formattedInteger + suffix;
|
||
}
|
||
break;
|
||
case formats.SEQUENCE:
|
||
throw {
|
||
code: 'D3130',
|
||
value: format.token
|
||
};
|
||
}
|
||
if (negative) {
|
||
formattedInteger = '-' + formattedInteger;
|
||
}
|
||
return formattedInteger;
|
||
}
|
||
|
||
//TODO what about decimal groups in the unicode supplementary planes (surrogate pairs) ???
|
||
var decimalGroups = [0x30, 0x0660, 0x06F0, 0x07C0, 0x0966, 0x09E6, 0x0A66, 0x0AE6, 0x0B66, 0x0BE6, 0x0C66, 0x0CE6, 0x0D66, 0x0DE6, 0x0E50, 0x0ED0, 0x0F20, 0x1040, 0x1090, 0x17E0, 0x1810, 0x1946, 0x19D0, 0x1A80, 0x1A90, 0x1B50, 0x1BB0, 0x1C40, 0x1C50, 0xA620, 0xA8D0, 0xA900, 0xA9D0, 0xA9F0, 0xAA50, 0xABF0, 0xFF10];
|
||
|
||
/**
|
||
* preprocesses the picture string
|
||
* @param {string} picture - picture string
|
||
* @returns {{type: string, primary: string, case: string, ordinal: boolean}} - analysed picture
|
||
*/
|
||
function analyseIntegerPicture(picture) {
|
||
var format = {
|
||
type: 'integer',
|
||
primary: formats.DECIMAL,
|
||
"case": tcase.LOWER,
|
||
ordinal: false
|
||
};
|
||
var primaryFormat, formatModifier;
|
||
var semicolon = picture.lastIndexOf(';');
|
||
if (semicolon === -1) {
|
||
primaryFormat = picture;
|
||
} else {
|
||
primaryFormat = picture.substring(0, semicolon);
|
||
formatModifier = picture.substring(semicolon + 1);
|
||
if (formatModifier[0] === 'o') {
|
||
format.ordinal = true;
|
||
}
|
||
}
|
||
|
||
/* eslnt-disable-next no-fallthrough */
|
||
switch (primaryFormat) {
|
||
case 'A':
|
||
format["case"] = tcase.UPPER;
|
||
/* eslnt-disable-next-line no-fallthrough */
|
||
case 'a':
|
||
format.primary = formats.LETTERS;
|
||
break;
|
||
case 'I':
|
||
format["case"] = tcase.UPPER;
|
||
/* eslnt-disable-next-line no-fallthrough */
|
||
case 'i':
|
||
format.primary = formats.ROMAN;
|
||
break;
|
||
case 'W':
|
||
format["case"] = tcase.UPPER;
|
||
format.primary = formats.WORDS;
|
||
break;
|
||
case 'Ww':
|
||
format["case"] = tcase.TITLE;
|
||
format.primary = formats.WORDS;
|
||
break;
|
||
case 'w':
|
||
format.primary = formats.WORDS;
|
||
break;
|
||
default:
|
||
{
|
||
// this is a decimal-digit-pattern if it contains a decimal digit (from any unicode decimal digit group)
|
||
var zeroCode = null;
|
||
var mandatoryDigits = 0;
|
||
var optionalDigits = 0;
|
||
var groupingSeparators = [];
|
||
var separatorPosition = 0;
|
||
var formatCodepoints = stringToArray(primaryFormat).map(function (c) {
|
||
return c.codePointAt(0);
|
||
}).reverse(); // reverse the array to determine positions of grouping-separator-signs
|
||
formatCodepoints.forEach(function (codePoint) {
|
||
// step though each char in the picture to determine the digit group
|
||
var digit = false;
|
||
for (var ii = 0; ii < decimalGroups.length; ii++) {
|
||
var group = decimalGroups[ii];
|
||
if (codePoint >= group && codePoint <= group + 9) {
|
||
// codepoint is part of this decimal group
|
||
digit = true;
|
||
mandatoryDigits++;
|
||
separatorPosition++;
|
||
if (zeroCode === null) {
|
||
zeroCode = group;
|
||
} else if (group !== zeroCode) {
|
||
// error! different decimal groups in the same pattern
|
||
throw {
|
||
code: 'D3131'
|
||
};
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (!digit) {
|
||
if (codePoint === 0x23) {
|
||
// # - optional-digit-sign
|
||
separatorPosition++;
|
||
optionalDigits++;
|
||
} else {
|
||
// neither a decimal-digit-sign ot optional-digit-sign, assume it is a grouping-separator-sign
|
||
groupingSeparators.push({
|
||
position: separatorPosition,
|
||
character: String.fromCodePoint(codePoint)
|
||
});
|
||
}
|
||
}
|
||
});
|
||
if (mandatoryDigits > 0) {
|
||
format.primary = formats.DECIMAL;
|
||
// TODO validate decimal-digit-pattern
|
||
|
||
// the decimal digit family (codepoint offset)
|
||
format.zeroCode = zeroCode;
|
||
// the number of mandatory digits
|
||
format.mandatoryDigits = mandatoryDigits;
|
||
// the number of optional digits
|
||
format.optionalDigits = optionalDigits;
|
||
// grouping separator template
|
||
// are the grouping-separator-signs 'regular'?
|
||
var regularRepeat = function regularRepeat(separators) {
|
||
// are the grouping positions regular? i.e. same interval between each of them
|
||
// is there at least one separator?
|
||
if (separators.length === 0) {
|
||
return 0;
|
||
}
|
||
// are all the characters the same?
|
||
var sepChar = separators[0].character;
|
||
for (var ii = 1; ii < separators.length; ii++) {
|
||
if (separators[ii].character !== sepChar) {
|
||
return 0;
|
||
}
|
||
}
|
||
// are they equally spaced?
|
||
var indexes = separators.map(function (separator) {
|
||
return separator.position;
|
||
});
|
||
var gcd = function gcd(a, b) {
|
||
return b === 0 ? a : gcd(b, a % b);
|
||
};
|
||
// find the greatest common divisor of all the positions
|
||
var factor = indexes.reduce(gcd);
|
||
// is every position separated by this divisor? If so, it's regular
|
||
for (var index = 1; index <= indexes.length; index++) {
|
||
if (indexes.indexOf(index * factor) === -1) {
|
||
return 0;
|
||
}
|
||
}
|
||
return factor;
|
||
};
|
||
var regular = regularRepeat(groupingSeparators);
|
||
if (regular > 0) {
|
||
format.regular = true;
|
||
format.groupingSeparators = {
|
||
position: regular,
|
||
character: groupingSeparators[0].character
|
||
};
|
||
} else {
|
||
format.regular = false;
|
||
format.groupingSeparators = groupingSeparators;
|
||
}
|
||
} else {
|
||
// this is a 'numbering sequence' which the spec says is implementation-defined
|
||
// this implementation doesn't support any numbering sequences at the moment.
|
||
format.primary = formats.SEQUENCE;
|
||
format.token = primaryFormat;
|
||
}
|
||
}
|
||
}
|
||
return format;
|
||
}
|
||
var defaultPresentationModifiers = {
|
||
Y: '1',
|
||
M: '1',
|
||
D: '1',
|
||
d: '1',
|
||
F: 'n',
|
||
W: '1',
|
||
w: '1',
|
||
X: '1',
|
||
x: '1',
|
||
H: '1',
|
||
h: '1',
|
||
P: 'n',
|
||
m: '01',
|
||
s: '01',
|
||
f: '1',
|
||
Z: '01:01',
|
||
z: '01:01',
|
||
C: 'n',
|
||
E: 'n'
|
||
};
|
||
|
||
// §9.8.4.1 the format specifier is an array of string literals and variable markers
|
||
/**
|
||
* analyse the date-time picture string
|
||
* @param {string} picture - picture string
|
||
* @returns {{type: string, parts: Array}} - the analysed string
|
||
*/
|
||
function analyseDateTimePicture(picture) {
|
||
var spec = [];
|
||
var format = {
|
||
type: 'datetime',
|
||
parts: spec
|
||
};
|
||
var addLiteral = function addLiteral(start, end) {
|
||
if (end > start) {
|
||
var literal = picture.substring(start, end);
|
||
// replace any doubled ]] with single ]
|
||
// what if there are instances of single ']' ? - the spec doesn't say
|
||
literal = literal.split(']]').join(']');
|
||
spec.push({
|
||
type: 'literal',
|
||
value: literal
|
||
});
|
||
}
|
||
};
|
||
var start = 0,
|
||
pos = 0;
|
||
while (pos < picture.length) {
|
||
if (picture.charAt(pos) === '[') {
|
||
// check it's not a doubled [[
|
||
if (picture.charAt(pos + 1) === '[') {
|
||
// literal [
|
||
addLiteral(start, pos);
|
||
spec.push({
|
||
type: 'literal',
|
||
value: '['
|
||
});
|
||
pos += 2;
|
||
start = pos;
|
||
continue;
|
||
}
|
||
// start of variable marker
|
||
// push the string literal (if there is one) onto the array
|
||
addLiteral(start, pos);
|
||
start = pos;
|
||
// search forward to closing ]
|
||
pos = picture.indexOf(']', start);
|
||
// TODO handle error case if pos === -1
|
||
if (pos === -1) {
|
||
// error - no closing bracket
|
||
throw {
|
||
code: 'D3135'
|
||
};
|
||
}
|
||
var marker = picture.substring(start + 1, pos);
|
||
// whitespace within a variable marker is ignored (i.e. remove it)
|
||
marker = marker.split(/\s+/).join('');
|
||
var def = {
|
||
type: 'marker',
|
||
component: marker.charAt(0) // 1. The component specifier is always present and is always a single letter.
|
||
};
|
||
var comma = marker.lastIndexOf(','); // 2. The width modifier may be recognized by the presence of a comma
|
||
var presMod; // the presentation modifiers
|
||
if (comma !== -1) {
|
||
// §9.8.4.2 The Width Modifier
|
||
var widthMod = marker.substring(comma + 1);
|
||
var dash = widthMod.indexOf('-');
|
||
var min = void 0,
|
||
max = void 0;
|
||
var parseWidth = function parseWidth(wm) {
|
||
if (typeof wm === 'undefined' || wm === '*') {
|
||
return undefined;
|
||
} else {
|
||
// TODO validate wm is an unsigned int
|
||
return parseInt(wm);
|
||
}
|
||
};
|
||
if (dash === -1) {
|
||
min = widthMod;
|
||
} else {
|
||
min = widthMod.substring(0, dash);
|
||
max = widthMod.substring(dash + 1);
|
||
}
|
||
var widthDef = {
|
||
min: parseWidth(min),
|
||
max: parseWidth(max)
|
||
};
|
||
def.width = widthDef;
|
||
presMod = marker.substring(1, comma);
|
||
} else {
|
||
presMod = marker.substring(1);
|
||
}
|
||
if (presMod.length === 1) {
|
||
def.presentation1 = presMod; // first presentation modifier
|
||
//TODO validate the first presentation modifier - it's either N, n, Nn or it passes analyseIntegerPicture
|
||
} else if (presMod.length > 1) {
|
||
var lastChar = presMod.charAt(presMod.length - 1);
|
||
if ('atco'.indexOf(lastChar) !== -1) {
|
||
def.presentation2 = lastChar;
|
||
if (lastChar === 'o') {
|
||
def.ordinal = true;
|
||
}
|
||
// 'c' means 'cardinal' and is the default (i.e. not 'ordinal')
|
||
// 'a' & 't' are ignored (not sure of their relevance to English numbering)
|
||
def.presentation1 = presMod.substring(0, presMod.length - 1);
|
||
} else {
|
||
def.presentation1 = presMod;
|
||
//TODO validate the first presentation modifier - it's either N, n, Nn or it passes analyseIntegerPicture,
|
||
// doesn't use ] as grouping separator, and if grouping separator is , then must have width modifier
|
||
}
|
||
} else {
|
||
// no presentation modifier specified - apply the default;
|
||
def.presentation1 = defaultPresentationModifiers[def.component];
|
||
}
|
||
if (typeof def.presentation1 === 'undefined') {
|
||
// unknown component specifier
|
||
throw {
|
||
code: 'D3132',
|
||
value: def.component
|
||
};
|
||
}
|
||
if (def.presentation1[0] === 'n') {
|
||
def.names = tcase.LOWER;
|
||
} else if (def.presentation1[0] === 'N') {
|
||
if (def.presentation1[1] === 'n') {
|
||
def.names = tcase.TITLE;
|
||
} else {
|
||
def.names = tcase.UPPER;
|
||
}
|
||
} else if ('YMDdFWwXxHhmsf'.indexOf(def.component) !== -1) {
|
||
var integerPattern = def.presentation1;
|
||
if (def.presentation2) {
|
||
integerPattern += ';' + def.presentation2;
|
||
}
|
||
def.integerFormat = analyseIntegerPicture(integerPattern);
|
||
if (def.width && def.width.min !== undefined) {
|
||
if (def.integerFormat.mandatoryDigits < def.width.min) {
|
||
def.integerFormat.mandatoryDigits = def.width.min;
|
||
}
|
||
}
|
||
if ('YMD'.indexOf(def.component) !== -1) {
|
||
// §9.8.4.4
|
||
def.n = -1;
|
||
if (def.width && def.width.max !== undefined) {
|
||
def.n = def.width.max;
|
||
def.integerFormat.mandatoryDigits = def.n;
|
||
} else {
|
||
var w = def.integerFormat.mandatoryDigits + def.integerFormat.optionalDigits;
|
||
if (w >= 2) {
|
||
def.n = w;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (def.component === 'Z' || def.component === 'z') {
|
||
def.integerFormat = analyseIntegerPicture(def.presentation1);
|
||
}
|
||
spec.push(def);
|
||
start = pos + 1;
|
||
}
|
||
pos++;
|
||
}
|
||
addLiteral(start, pos);
|
||
return format;
|
||
}
|
||
var days = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||
var millisInADay = 1000 * 60 * 60 * 24;
|
||
var startOfFirstWeek = function startOfFirstWeek(ym) {
|
||
// ISO 8601 defines the first week of the year to be the week that contains the first Thursday
|
||
// XPath F&O extends this same definition for the first week of a month
|
||
// the week starts on a Monday - calculate the millis for the start of the first week
|
||
// millis for given 1st Jan of that year (at 00:00 UTC)
|
||
var jan1 = Date.UTC(ym.year, ym.month);
|
||
var dayOfJan1 = new Date(jan1).getUTCDay();
|
||
if (dayOfJan1 === 0) {
|
||
dayOfJan1 = 7;
|
||
}
|
||
// if Jan 1 is Fri, Sat or Sun, then add the number of days (in millis) to jan1 to get the start of week 1
|
||
return dayOfJan1 > 4 ? jan1 + (8 - dayOfJan1) * millisInADay : jan1 - (dayOfJan1 - 1) * millisInADay;
|
||
};
|
||
var yearMonth = function yearMonth(year, month) {
|
||
return {
|
||
year: year,
|
||
month: month,
|
||
nextMonth: function nextMonth() {
|
||
return month === 11 ? yearMonth(year + 1, 0) : yearMonth(year, month + 1);
|
||
},
|
||
previousMonth: function previousMonth() {
|
||
return month === 0 ? yearMonth(year - 1, 11) : yearMonth(year, month - 1);
|
||
},
|
||
nextYear: function nextYear() {
|
||
return yearMonth(year + 1, month);
|
||
},
|
||
previousYear: function previousYear() {
|
||
return yearMonth(year - 1, month);
|
||
}
|
||
};
|
||
};
|
||
var deltaWeeks = function deltaWeeks(start, end) {
|
||
return (end - start) / (millisInADay * 7) + 1;
|
||
};
|
||
var getDateTimeFragment = function getDateTimeFragment(date, component) {
|
||
var componentValue;
|
||
switch (component) {
|
||
case 'Y':
|
||
// year
|
||
componentValue = date.getUTCFullYear();
|
||
break;
|
||
case 'M':
|
||
// month in year
|
||
componentValue = date.getUTCMonth() + 1;
|
||
break;
|
||
case 'D':
|
||
// day in month
|
||
componentValue = date.getUTCDate();
|
||
break;
|
||
case 'd':
|
||
{
|
||
// day in year
|
||
// millis for given date (at 00:00 UTC)
|
||
var today = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
||
// millis for given 1st Jan of that year (at 00:00 UTC)
|
||
var firstJan = Date.UTC(date.getUTCFullYear(), 0);
|
||
componentValue = (today - firstJan) / millisInADay + 1;
|
||
break;
|
||
}
|
||
case 'F':
|
||
// day of week
|
||
componentValue = date.getUTCDay();
|
||
if (componentValue === 0) {
|
||
// ISO 8601 defines days 1-7: Mon-Sun
|
||
componentValue = 7;
|
||
}
|
||
break;
|
||
case 'W':
|
||
{
|
||
// week in year
|
||
var thisYear = yearMonth(date.getUTCFullYear(), 0);
|
||
var startOfWeek1 = startOfFirstWeek(thisYear);
|
||
var _today = Date.UTC(thisYear.year, date.getUTCMonth(), date.getUTCDate());
|
||
var week = deltaWeeks(startOfWeek1, _today);
|
||
if (week > 52) {
|
||
// might be first week of the following year
|
||
var startOfFollowingYear = startOfFirstWeek(thisYear.nextYear());
|
||
if (_today >= startOfFollowingYear) {
|
||
week = 1;
|
||
}
|
||
} else if (week < 1) {
|
||
// must be end of the previous year
|
||
var startOfPreviousYear = startOfFirstWeek(thisYear.previousYear());
|
||
week = deltaWeeks(startOfPreviousYear, _today);
|
||
}
|
||
componentValue = Math.floor(week);
|
||
break;
|
||
}
|
||
case 'w':
|
||
{
|
||
// week in month
|
||
var thisMonth = yearMonth(date.getUTCFullYear(), date.getUTCMonth());
|
||
var _startOfWeek = startOfFirstWeek(thisMonth);
|
||
var _today2 = Date.UTC(thisMonth.year, thisMonth.month, date.getUTCDate());
|
||
var _week = deltaWeeks(_startOfWeek, _today2);
|
||
if (_week > 4) {
|
||
// might be first week of the following month
|
||
var startOfFollowingMonth = startOfFirstWeek(thisMonth.nextMonth());
|
||
if (_today2 >= startOfFollowingMonth) {
|
||
_week = 1;
|
||
}
|
||
} else if (_week < 1) {
|
||
// must be end of the previous month
|
||
var startOfPreviousMonth = startOfFirstWeek(thisMonth.previousMonth());
|
||
_week = deltaWeeks(startOfPreviousMonth, _today2);
|
||
}
|
||
componentValue = Math.floor(_week);
|
||
break;
|
||
}
|
||
case 'X':
|
||
{
|
||
// ISO week-numbering year
|
||
// Extension: The F&O spec says nothing about how to access the year associated with the week-of-the-year
|
||
// e.g. Sat 1 Jan 2005 is in the 53rd week of 2004.
|
||
// The 'W' component specifier gives 53, but 'Y' will give 2005.
|
||
// I propose to add 'X' as the component specifier to give the ISO week-numbering year (2004 in this example)
|
||
var _thisYear = yearMonth(date.getUTCFullYear(), 0);
|
||
var startOfISOYear = startOfFirstWeek(_thisYear);
|
||
var endOfISOYear = startOfFirstWeek(_thisYear.nextYear());
|
||
var now = date.getTime();
|
||
if (now < startOfISOYear) {
|
||
componentValue = _thisYear.year - 1;
|
||
} else if (now >= endOfISOYear) {
|
||
componentValue = _thisYear.year + 1;
|
||
} else {
|
||
componentValue = _thisYear.year;
|
||
}
|
||
break;
|
||
}
|
||
case 'x':
|
||
{
|
||
// ISO week-numbering month
|
||
// Extension: The F&O spec says nothing about how to access the month associated with the week-of-the-month
|
||
// e.g. Sat 1 Jan 2005 is in the 5th week of December 2004.
|
||
// The 'w' component specifier gives 5, but 'W' will give January and 'Y' will give 2005.
|
||
// I propose to add 'x' as the component specifier to give the 'week-numbering' month (December in this example)
|
||
var _thisMonth = yearMonth(date.getUTCFullYear(), date.getUTCMonth());
|
||
var startOfISOMonth = startOfFirstWeek(_thisMonth);
|
||
var nextMonth = _thisMonth.nextMonth();
|
||
var endOfISOMonth = startOfFirstWeek(nextMonth);
|
||
var _now = date.getTime();
|
||
if (_now < startOfISOMonth) {
|
||
componentValue = _thisMonth.previousMonth().month + 1;
|
||
} else if (_now >= endOfISOMonth) {
|
||
componentValue = nextMonth.month + 1;
|
||
} else {
|
||
componentValue = _thisMonth.month + 1;
|
||
}
|
||
break;
|
||
}
|
||
case 'H':
|
||
// hour in day (24 hours)
|
||
componentValue = date.getUTCHours();
|
||
break;
|
||
case 'h':
|
||
// hour in half-day (12 hours)
|
||
componentValue = date.getUTCHours();
|
||
componentValue = componentValue % 12;
|
||
if (componentValue === 0) {
|
||
componentValue = 12;
|
||
}
|
||
break;
|
||
case 'P':
|
||
// am/pm marker
|
||
componentValue = date.getUTCHours() >= 12 ? 'pm' : 'am';
|
||
break;
|
||
case 'm':
|
||
// minute in hour
|
||
componentValue = date.getUTCMinutes();
|
||
break;
|
||
case 's':
|
||
// second in minute
|
||
componentValue = date.getUTCSeconds();
|
||
break;
|
||
case 'f':
|
||
// fractional seconds
|
||
componentValue = date.getUTCMilliseconds();
|
||
break;
|
||
case 'Z': // timezone
|
||
case 'z':
|
||
// since the date object is constructed from epoch millis, the TZ component is always be UTC.
|
||
break;
|
||
case 'C':
|
||
// calendar name
|
||
componentValue = 'ISO';
|
||
break;
|
||
case 'E':
|
||
// era
|
||
componentValue = 'ISO';
|
||
break;
|
||
}
|
||
return componentValue;
|
||
};
|
||
var iso8601Spec = null;
|
||
|
||
/**
|
||
* formats the date/time as specified by the XPath fn:format-dateTime function
|
||
* @param {number} millis - the timestamp to be formatted, in millis since the epoch
|
||
* @param {string} picture - the picture string that specifies the format
|
||
* @param {string} timezone - the timezone to use
|
||
* @returns {string} - the formatted timestamp
|
||
*/
|
||
function formatDateTime(millis, picture, timezone) {
|
||
var offsetHours = 0;
|
||
var offsetMinutes = 0;
|
||
if (typeof timezone !== 'undefined') {
|
||
// parse the hour and minute offsets
|
||
// assume for now the format supplied is +hhmm
|
||
var offset = parseInt(timezone);
|
||
offsetHours = Math.floor(offset / 100);
|
||
offsetMinutes = offset % 100;
|
||
}
|
||
var formatComponent = function formatComponent(date, markerSpec) {
|
||
var componentValue = getDateTimeFragment(date, markerSpec.component);
|
||
|
||
// §9.8.4.3 Formatting Integer-Valued Date/Time Components
|
||
if ('YMDdFWwXxHhms'.indexOf(markerSpec.component) !== -1) {
|
||
if (markerSpec.component === 'Y') {
|
||
// §9.8.4.4 Formatting the Year Component
|
||
if (markerSpec.n !== -1) {
|
||
componentValue = componentValue % Math.pow(10, markerSpec.n);
|
||
}
|
||
}
|
||
if (markerSpec.names) {
|
||
if (markerSpec.component === 'M' || markerSpec.component === 'x') {
|
||
componentValue = months[componentValue - 1];
|
||
} else if (markerSpec.component === 'F') {
|
||
componentValue = days[componentValue];
|
||
} else {
|
||
throw {
|
||
code: 'D3133',
|
||
value: markerSpec.component
|
||
};
|
||
}
|
||
if (markerSpec.names === tcase.UPPER) {
|
||
componentValue = componentValue.toUpperCase();
|
||
} else if (markerSpec.names === tcase.LOWER) {
|
||
componentValue = componentValue.toLowerCase();
|
||
}
|
||
if (markerSpec.width && componentValue.length > markerSpec.width.max) {
|
||
componentValue = componentValue.substring(0, markerSpec.width.max);
|
||
}
|
||
} else {
|
||
componentValue = _formatInteger(componentValue, markerSpec.integerFormat);
|
||
}
|
||
} else if (markerSpec.component === 'f') {
|
||
// TODO §9.8.4.5 Formatting Fractional Seconds
|
||
componentValue = _formatInteger(componentValue, markerSpec.integerFormat);
|
||
} else if (markerSpec.component === 'Z' || markerSpec.component === 'z') {
|
||
// §9.8.4.6 Formatting timezones
|
||
var _offset = offsetHours * 100 + offsetMinutes;
|
||
if (markerSpec.integerFormat.regular) {
|
||
componentValue = _formatInteger(_offset, markerSpec.integerFormat);
|
||
} else {
|
||
var numDigits = markerSpec.integerFormat.mandatoryDigits;
|
||
if (numDigits === 1 || numDigits === 2) {
|
||
componentValue = _formatInteger(offsetHours, markerSpec.integerFormat);
|
||
if (offsetMinutes !== 0) {
|
||
componentValue += ':' + formatInteger(offsetMinutes, '00');
|
||
}
|
||
} else if (numDigits === 3 || numDigits === 4) {
|
||
componentValue = _formatInteger(_offset, markerSpec.integerFormat);
|
||
} else {
|
||
throw {
|
||
code: 'D3134',
|
||
value: numDigits
|
||
};
|
||
}
|
||
}
|
||
if (_offset >= 0) {
|
||
componentValue = '+' + componentValue;
|
||
}
|
||
if (markerSpec.component === 'z') {
|
||
componentValue = 'GMT' + componentValue;
|
||
}
|
||
if (_offset === 0 && markerSpec.presentation2 === 't') {
|
||
componentValue = 'Z';
|
||
}
|
||
} else if (markerSpec.component === 'P') {
|
||
// §9.8.4.7 Formatting Other Components
|
||
// Formatting P for am/pm
|
||
// getDateTimeFragment() always returns am/pm lower case so check for UPPER here
|
||
if (markerSpec.names === tcase.UPPER) {
|
||
componentValue = componentValue.toUpperCase();
|
||
}
|
||
}
|
||
return componentValue;
|
||
};
|
||
var formatSpec;
|
||
if (typeof picture === 'undefined') {
|
||
// default to ISO 8601 format
|
||
if (iso8601Spec === null) {
|
||
iso8601Spec = analyseDateTimePicture('[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].[f001][Z01:01t]');
|
||
}
|
||
formatSpec = iso8601Spec;
|
||
} else {
|
||
formatSpec = analyseDateTimePicture(picture);
|
||
}
|
||
var offsetMillis = (60 * offsetHours + offsetMinutes) * 60 * 1000;
|
||
var dateTime = new Date(millis + offsetMillis);
|
||
var result = '';
|
||
formatSpec.parts.forEach(function (part) {
|
||
if (part.type === 'literal') {
|
||
result += part.value;
|
||
} else {
|
||
result += formatComponent(dateTime, part);
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Generate a regex to parse integers or timestamps
|
||
* @param {object} formatSpec - object representing the format
|
||
* @returns {object} - regex
|
||
*/
|
||
function generateRegex(formatSpec) {
|
||
var matcher = {};
|
||
if (formatSpec.type === 'datetime') {
|
||
matcher.type = 'datetime';
|
||
matcher.parts = formatSpec.parts.map(function (part) {
|
||
var res = {};
|
||
if (part.type === 'literal') {
|
||
res.regex = part.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||
} else if (part.component === 'Z' || part.component === 'z') {
|
||
// timezone
|
||
var separator;
|
||
if (!Array.isArray(part.integerFormat.groupingSeparators)) {
|
||
separator = part.integerFormat.groupingSeparators;
|
||
}
|
||
res.regex = '';
|
||
if (part.component === 'z') {
|
||
res.regex = 'GMT';
|
||
}
|
||
res.regex += '[-+][0-9]+';
|
||
if (separator) {
|
||
res.regex += separator.character + '[0-9]+';
|
||
}
|
||
res.parse = function (value) {
|
||
if (part.component === 'z') {
|
||
value = value.substring(3); // remove the leading GMT
|
||
}
|
||
var offsetHours = 0,
|
||
offsetMinutes = 0;
|
||
if (separator) {
|
||
offsetHours = Number.parseInt(value.substring(0, value.indexOf(separator.character)));
|
||
offsetMinutes = Number.parseInt(value.substring(value.indexOf(separator.character) + 1));
|
||
} else {
|
||
// depends on number of digits
|
||
var numdigits = value.length - 1;
|
||
if (numdigits <= 2) {
|
||
// just hour offset
|
||
offsetHours = Number.parseInt(value);
|
||
} else {
|
||
offsetHours = Number.parseInt(value.substring(0, 3));
|
||
offsetMinutes = Number.parseInt(value.substring(3));
|
||
}
|
||
}
|
||
return offsetHours * 60 + offsetMinutes;
|
||
};
|
||
} else if (part.integerFormat) {
|
||
part.integerFormat.n = part.n;
|
||
res = generateRegex(part.integerFormat);
|
||
} else {
|
||
// must be a month or day name
|
||
res.regex = '[a-zA-Z]+';
|
||
var lookup = {};
|
||
if (part.component === 'M' || part.component === 'x') {
|
||
// months
|
||
months.forEach(function (name, index) {
|
||
if (part.width && part.width.max) {
|
||
lookup[name.substring(0, part.width.max)] = index + 1;
|
||
} else {
|
||
lookup[name] = index + 1;
|
||
}
|
||
});
|
||
} else if (part.component === 'F') {
|
||
// days
|
||
days.forEach(function (name, index) {
|
||
if (index > 0) {
|
||
if (part.width && part.width.max) {
|
||
lookup[name.substring(0, part.width.max)] = index;
|
||
} else {
|
||
lookup[name] = index;
|
||
}
|
||
}
|
||
});
|
||
} else if (part.component === 'P') {
|
||
lookup = {
|
||
'am': 0,
|
||
'AM': 0,
|
||
'pm': 1,
|
||
'PM': 1
|
||
};
|
||
} else {
|
||
// unsupported 'name' option for this component
|
||
throw {
|
||
code: 'D3133',
|
||
value: part.component
|
||
};
|
||
}
|
||
res.parse = function (value) {
|
||
return lookup[value];
|
||
};
|
||
}
|
||
res.component = part.component;
|
||
return res;
|
||
});
|
||
} else {
|
||
// type === 'integer'
|
||
matcher.type = 'integer';
|
||
var isUpper = formatSpec["case"] === tcase.UPPER;
|
||
var occurrences;
|
||
if (formatSpec.n && formatSpec.n > 0) {
|
||
if (formatSpec.optionalDigits === 0) {
|
||
occurrences = "{".concat(formatSpec.n, "}");
|
||
} else {
|
||
occurrences = "{".concat(formatSpec.n - formatSpec.optionalDigits, ",").concat(formatSpec.n, "}");
|
||
}
|
||
} else {
|
||
occurrences = '+';
|
||
}
|
||
switch (formatSpec.primary) {
|
||
case formats.LETTERS:
|
||
matcher.regex = isUpper ? '[A-Z]+' : '[a-z]+';
|
||
matcher.parse = function (value) {
|
||
return lettersToDecimal(value, isUpper ? 'A' : 'a');
|
||
};
|
||
break;
|
||
case formats.ROMAN:
|
||
matcher.regex = isUpper ? '[MDCLXVI]+' : '[mdclxvi]+';
|
||
matcher.parse = function (value) {
|
||
return romanToDecimal(isUpper ? value : value.toUpperCase());
|
||
};
|
||
break;
|
||
case formats.WORDS:
|
||
matcher.regex = '(?:' + Object.keys(wordValues).concat('and', '[\\-, ]').join('|') + ')+';
|
||
matcher.parse = function (value) {
|
||
return wordsToNumber(value.toLowerCase());
|
||
};
|
||
break;
|
||
case formats.DECIMAL:
|
||
matcher.regex = "[0-9]".concat(occurrences);
|
||
if (formatSpec.ordinal) {
|
||
// ordinals
|
||
matcher.regex += '(?:th|st|nd|rd)';
|
||
}
|
||
matcher.parse = function (value) {
|
||
var digits = value;
|
||
if (formatSpec.ordinal) {
|
||
// strip off the suffix
|
||
digits = value.substring(0, value.length - 2);
|
||
}
|
||
// strip out the separators
|
||
if (formatSpec.regular) {
|
||
digits = digits.split(',').join('');
|
||
} else {
|
||
formatSpec.groupingSeparators.forEach(function (sep) {
|
||
digits = digits.split(sep.character).join('');
|
||
});
|
||
}
|
||
if (formatSpec.zeroCode !== 0x30) {
|
||
// apply offset
|
||
digits = digits.split('').map(function (_char) {
|
||
return String.fromCodePoint(_char.codePointAt(0) - formatSpec.zeroCode + 0x30);
|
||
}).join('');
|
||
}
|
||
return parseInt(digits);
|
||
};
|
||
break;
|
||
case formats.SEQUENCE:
|
||
throw {
|
||
code: 'D3130',
|
||
value: formatSpec.token
|
||
};
|
||
}
|
||
}
|
||
return matcher;
|
||
}
|
||
|
||
/**
|
||
* parse a string containing an integer as specified by the picture string
|
||
* @param {string} value - the string to parse
|
||
* @param {string} picture - the picture string
|
||
* @returns {number} - the parsed number
|
||
*/
|
||
function parseInteger(value, picture) {
|
||
if (typeof value === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var formatSpec = analyseIntegerPicture(picture);
|
||
var matchSpec = generateRegex(formatSpec);
|
||
//const fullRegex = '^' + matchSpec.regex + '$';
|
||
//const matcher = new RegExp(fullRegex);
|
||
// TODO validate input based on the matcher regex
|
||
var result = matchSpec.parse(value);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* parse a string containing a timestamp as specified by the picture string
|
||
* @param {string} timestamp - the string to parse
|
||
* @param {string} picture - the picture string
|
||
* @returns {number} - the parsed timestamp in millis since the epoch
|
||
*/
|
||
function parseDateTime(timestamp, picture) {
|
||
var formatSpec = analyseDateTimePicture(picture);
|
||
var matchSpec = generateRegex(formatSpec);
|
||
var fullRegex = '^' + matchSpec.parts.map(function (part) {
|
||
return '(' + part.regex + ')';
|
||
}).join('') + '$';
|
||
var matcher = new RegExp(fullRegex, 'i'); // TODO can cache this against the picture
|
||
var info = matcher.exec(timestamp);
|
||
if (info !== null) {
|
||
// validate what we've just parsed - do we have enough information to create a timestamp?
|
||
// rules:
|
||
// The date is specified by one of:
|
||
// {Y, M, D} (dateA)
|
||
// or {Y, d} (dateB)
|
||
// or {Y, x, w, F} (dateC)
|
||
// or {X, W, F} (dateD)
|
||
// The time is specified by one of:
|
||
// {H, m, s, f} (timeA)
|
||
// or {P, h, m, s, f} (timeB)
|
||
// All sets can have an optional Z
|
||
// To create a timestamp (epoch millis) we need both date and time, but we can default missing
|
||
// information according to the following rules:
|
||
// - line up one combination of the above from date, and one from time, most significant value (MSV) to least significant (LSV
|
||
// - for the values that have been captured, if there are any gaps between MSV and LSV, then throw an error
|
||
// (e.g.) if hour and seconds, but not minutes is given - throw
|
||
// (e.g.) if month, hour and minutes, but not day-of-month is given - throw
|
||
// - anything right of the LSV should be defaulted to zero
|
||
// (e.g.) if hour and minutes given, default seconds and fractional seconds to zero
|
||
// (e.g.) if date only given, default the time to 0:00:00.000 (midnight)
|
||
// - anything left of the MSV should be defaulted to the value of that component returned by $now()
|
||
// (e.g.) if time only given, default the date to today
|
||
// (e.g.) if month and date given, default to this year (and midnight, by previous rule)
|
||
// -- default values for X, x, W, w, F will be derived from the values returned by $now()
|
||
|
||
// implement the above rules
|
||
// determine which of the above date/time combinations we have by using bit masks
|
||
|
||
// Y X M x W w d D F P H h m s f Z
|
||
// dateA 1 0 1 0 0 0 0 1 ? 0 - must not appear
|
||
// dateB 1 0 0 0 0 0 1 0 ? 1 - can appear - relevant
|
||
// dateC 0 1 0 1 0 1 0 0 1 ? - can appear - ignored
|
||
// dateD 0 1 0 0 1 0 0 0 1
|
||
// timeA 0 1 0 1 1 1
|
||
// timeB 1 0 1 1 1 1
|
||
|
||
// create bitmasks based on the above
|
||
// date mask YXMxWwdD
|
||
var dmA = 161; // binary 10100001
|
||
var dmB = 130; // binary 10000010
|
||
var dmC = 84; // binary 01010100
|
||
var dmD = 72; // binary 01001000
|
||
// time mask PHhmsf
|
||
var tmA = 23; // binary 010111
|
||
var tmB = 47; // binary 101111
|
||
|
||
var components = {};
|
||
for (var i = 1; i < info.length; i++) {
|
||
var mpart = matchSpec.parts[i - 1];
|
||
if (mpart.parse) {
|
||
components[mpart.component] = mpart.parse(info[i]);
|
||
}
|
||
}
|
||
if (Object.getOwnPropertyNames(components).length === 0) {
|
||
// nothing specified
|
||
return undefined;
|
||
}
|
||
var mask = 0;
|
||
var shift = function shift(bit) {
|
||
mask <<= 1;
|
||
mask += bit ? 1 : 0;
|
||
};
|
||
var isType = function isType(type) {
|
||
// shouldn't match any 0's, must match at least one 1
|
||
return !(~type & mask) && !!(type & mask);
|
||
};
|
||
'YXMxWwdD'.split('').forEach(function (part) {
|
||
return shift(components[part]);
|
||
});
|
||
var dateA = isType(dmA);
|
||
var dateB = !dateA && isType(dmB);
|
||
var dateC = isType(dmC);
|
||
var dateD = !dateC && isType(dmD);
|
||
mask = 0;
|
||
'PHhmsf'.split('').forEach(function (part) {
|
||
return shift(components[part]);
|
||
});
|
||
var timeA = isType(tmA);
|
||
var timeB = !timeA && isType(tmB);
|
||
|
||
// should only be zero or one date type and zero or one time type
|
||
|
||
var dateComps = dateB ? 'YD' : dateC ? 'XxwF' : dateD ? 'XWF' : 'YMD';
|
||
var timeComps = timeB ? 'Phmsf' : 'Hmsf';
|
||
var comps = dateComps + timeComps;
|
||
|
||
// step through the candidate parts from most significant to least significant
|
||
// default the most significant unspecified parts to current timestamp component
|
||
// default the least significant unspecified parts to zero
|
||
// if any gaps in between the specified parts, throw an error
|
||
|
||
var now = this.environment.timestamp; // must get the fixed timestamp from jsonata
|
||
|
||
var startSpecified = false;
|
||
var endSpecified = false;
|
||
comps.split('').forEach(function (part) {
|
||
if (typeof components[part] === 'undefined') {
|
||
if (startSpecified) {
|
||
// past the specified block - default to zero
|
||
components[part] = 'MDd'.indexOf(part) !== -1 ? 1 : 0;
|
||
endSpecified = true;
|
||
} else {
|
||
// haven't hit the specified block yet, default to current timestamp
|
||
components[part] = getDateTimeFragment(now, part);
|
||
}
|
||
} else {
|
||
startSpecified = true;
|
||
if (endSpecified) {
|
||
throw {
|
||
code: 'D3136'
|
||
};
|
||
}
|
||
}
|
||
});
|
||
|
||
// validate and fill in components
|
||
if (components.M > 0) {
|
||
components.M -= 1; // Date.UTC requires a zero-indexed month
|
||
} else {
|
||
components.M = 0; // default to January
|
||
}
|
||
if (dateB) {
|
||
// millis for given 1st Jan of that year (at 00:00 UTC)
|
||
var firstJan = Date.UTC(components.Y, 0);
|
||
var offsetMillis = (components.d - 1) * 1000 * 60 * 60 * 24;
|
||
var derivedDate = new Date(firstJan + offsetMillis);
|
||
components.M = derivedDate.getUTCMonth();
|
||
components.D = derivedDate.getUTCDate();
|
||
}
|
||
if (dateC) {
|
||
// TODO implement this
|
||
// parsing this format not currently supported
|
||
throw {
|
||
code: 'D3136'
|
||
};
|
||
}
|
||
if (dateD) {
|
||
// TODO implement this
|
||
// parsing this format (ISO week date) not currently supported
|
||
throw {
|
||
code: 'D3136'
|
||
};
|
||
}
|
||
if (timeB) {
|
||
// 12hr to 24hr
|
||
components.H = components.h === 12 ? 0 : components.h;
|
||
if (components.P === 1) {
|
||
components.H += 12;
|
||
}
|
||
}
|
||
var millis = Date.UTC(components.Y, components.M, components.D, components.H, components.m, components.s, components.f);
|
||
if (components.Z || components.z) {
|
||
// adjust for timezone
|
||
millis -= (components.Z || components.z) * 60 * 1000;
|
||
}
|
||
return millis;
|
||
}
|
||
}
|
||
|
||
// Regular expression to match an ISO 8601 formatted timestamp
|
||
var iso8601regex = new RegExp('^\\d{4}(-[01]\\d)*(-[0-3]\\d)*(T[0-2]\\d:[0-5]\\d:[0-5]\\d)*(\\.\\d+)?([+-][0-2]\\d:?[0-5]\\d|Z)?$');
|
||
|
||
/**
|
||
* Converts an ISO 8601 timestamp to milliseconds since the epoch
|
||
*
|
||
* @param {string} timestamp - the timestamp to be converted
|
||
* @param {string} [picture] - the picture string defining the format of the timestamp (defaults to ISO 8601)
|
||
* @returns {Number} - milliseconds since the epoch
|
||
*/
|
||
function toMillis(timestamp, picture) {
|
||
// undefined inputs always return undefined
|
||
if (typeof timestamp === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (typeof picture === 'undefined') {
|
||
if (!iso8601regex.test(timestamp)) {
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3110",
|
||
value: timestamp
|
||
};
|
||
}
|
||
return Date.parse(timestamp);
|
||
} else {
|
||
return parseDateTime.call(this, timestamp, picture);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Converts milliseconds since the epoch to an ISO 8601 timestamp
|
||
* @param {Number} millis - milliseconds since the epoch to be converted
|
||
* @param {string} [picture] - the picture string defining the format of the timestamp (defaults to ISO 8601)
|
||
* @param {string} [timezone] - the timezone to format the timestamp in (defaults to UTC)
|
||
* @returns {String} - the formatted timestamp
|
||
*/
|
||
function fromMillis(millis, picture, timezone) {
|
||
// undefined inputs always return undefined
|
||
if (typeof millis === 'undefined') {
|
||
return undefined;
|
||
}
|
||
return formatDateTime.call(this, millis, picture, timezone);
|
||
}
|
||
return {
|
||
formatInteger: formatInteger,
|
||
parseInteger: parseInteger,
|
||
fromMillis: fromMillis,
|
||
toMillis: toMillis
|
||
};
|
||
}();
|
||
module.exports = dateTime;
|
||
},{"./utils":6}],2:[function(require,module,exports){
|
||
(function (global){(function (){
|
||
"use strict";
|
||
|
||
function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
|
||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
||
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
||
/**
|
||
* © Copyright IBM Corp. 2016, 2018 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
var utils = require('./utils');
|
||
var functions = function () {
|
||
'use strict';
|
||
|
||
var isNumeric = utils.isNumeric;
|
||
var isArrayOfStrings = utils.isArrayOfStrings;
|
||
var isArrayOfNumbers = utils.isArrayOfNumbers;
|
||
var createSequence = utils.createSequence;
|
||
var isSequence = utils.isSequence;
|
||
var isFunction = utils.isFunction;
|
||
var isLambda = utils.isLambda;
|
||
var isPromise = utils.isPromise;
|
||
var getFunctionArity = utils.getFunctionArity;
|
||
var deepEquals = utils.isDeepEqual;
|
||
var stringToArray = utils.stringToArray;
|
||
|
||
/**
|
||
* Sum function
|
||
* @param {Object} args - Arguments
|
||
* @returns {number} Total value of arguments
|
||
*/
|
||
function sum(args) {
|
||
// undefined inputs always return undefined
|
||
if (typeof args === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var total = 0;
|
||
args.forEach(function (num) {
|
||
total += num;
|
||
});
|
||
return total;
|
||
}
|
||
|
||
/**
|
||
* Count function
|
||
* @param {Object} args - Arguments
|
||
* @returns {number} Number of elements in the array
|
||
*/
|
||
function count(args) {
|
||
// undefined inputs always return undefined
|
||
if (typeof args === 'undefined') {
|
||
return 0;
|
||
}
|
||
return args.length;
|
||
}
|
||
|
||
/**
|
||
* Max function
|
||
* @param {Object} args - Arguments
|
||
* @returns {number} Max element in the array
|
||
*/
|
||
function max(args) {
|
||
// undefined inputs always return undefined
|
||
if (typeof args === 'undefined' || args.length === 0) {
|
||
return undefined;
|
||
}
|
||
return Math.max.apply(Math, args);
|
||
}
|
||
|
||
/**
|
||
* Min function
|
||
* @param {Object} args - Arguments
|
||
* @returns {number} Min element in the array
|
||
*/
|
||
function min(args) {
|
||
// undefined inputs always return undefined
|
||
if (typeof args === 'undefined' || args.length === 0) {
|
||
return undefined;
|
||
}
|
||
return Math.min.apply(Math, args);
|
||
}
|
||
|
||
/**
|
||
* Average function
|
||
* @param {Object} args - Arguments
|
||
* @returns {number} Average element in the array
|
||
*/
|
||
function average(args) {
|
||
// undefined inputs always return undefined
|
||
if (typeof args === 'undefined' || args.length === 0) {
|
||
return undefined;
|
||
}
|
||
var total = 0;
|
||
args.forEach(function (num) {
|
||
total += num;
|
||
});
|
||
return total / args.length;
|
||
}
|
||
|
||
/**
|
||
* Stringify arguments
|
||
* @param {Object} arg - Arguments
|
||
* @param {boolean} [prettify] - Pretty print the result
|
||
* @returns {String} String from arguments
|
||
*/
|
||
function string(arg) {
|
||
var prettify = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var str;
|
||
if (typeof arg === 'string') {
|
||
// already a string
|
||
str = arg;
|
||
} else if (isFunction(arg)) {
|
||
// functions (built-in and lambda convert to empty string
|
||
str = '';
|
||
} else if (typeof arg === 'number' && !isFinite(arg)) {
|
||
throw {
|
||
code: "D3001",
|
||
value: arg,
|
||
stack: new Error().stack
|
||
};
|
||
} else {
|
||
var space = prettify ? 2 : 0;
|
||
if (Array.isArray(arg) && arg.outerWrapper) {
|
||
arg = arg[0];
|
||
}
|
||
str = JSON.stringify(arg, function (key, val) {
|
||
return typeof val !== 'undefined' && val !== null && val.toPrecision && isNumeric(val) ? Number(val.toPrecision(15)) : val && isFunction(val) ? '' : val;
|
||
}, space);
|
||
}
|
||
return str;
|
||
}
|
||
|
||
/**
|
||
* Create substring based on character number and length
|
||
* @param {String} str - String to evaluate
|
||
* @param {Integer} start - Character number to start substring
|
||
* @param {Integer} [length] - Number of characters in substring
|
||
* @returns {string|*} Substring
|
||
*/
|
||
function substring(str, start, length) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var strArray = stringToArray(str);
|
||
var strLength = strArray.length;
|
||
if (strLength + start < 0) {
|
||
start = 0;
|
||
}
|
||
if (typeof length !== 'undefined') {
|
||
if (length <= 0) {
|
||
return '';
|
||
}
|
||
var end = start >= 0 ? start + length : strLength + start + length;
|
||
return strArray.slice(start, end).join('');
|
||
}
|
||
return strArray.slice(start).join('');
|
||
}
|
||
|
||
/**
|
||
* Create substring up until a character
|
||
* @param {String} str - String to evaluate
|
||
* @param {String} chars - Character to define substring boundary
|
||
* @returns {*} Substring
|
||
*/
|
||
function substringBefore(str, chars) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var pos = str.indexOf(chars);
|
||
if (pos > -1) {
|
||
return str.substr(0, pos);
|
||
} else {
|
||
return str;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create substring after a character
|
||
* @param {String} str - String to evaluate
|
||
* @param {String} chars - Character to define substring boundary
|
||
* @returns {*} Substring
|
||
*/
|
||
function substringAfter(str, chars) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var pos = str.indexOf(chars);
|
||
if (pos > -1) {
|
||
return str.substr(pos + chars.length);
|
||
} else {
|
||
return str;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Lowercase a string
|
||
* @param {String} str - String to evaluate
|
||
* @returns {string} Lowercase string
|
||
*/
|
||
function lowercase(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
return str.toLowerCase();
|
||
}
|
||
|
||
/**
|
||
* Uppercase a string
|
||
* @param {String} str - String to evaluate
|
||
* @returns {string} Uppercase string
|
||
*/
|
||
function uppercase(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
return str.toUpperCase();
|
||
}
|
||
|
||
/**
|
||
* length of a string
|
||
* @param {String} str - string
|
||
* @returns {Number} The number of characters in the string
|
||
*/
|
||
function length(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
return stringToArray(str).length;
|
||
}
|
||
|
||
/**
|
||
* Normalize and trim whitespace within a string
|
||
* @param {string} str - string to be trimmed
|
||
* @returns {string} - trimmed string
|
||
*/
|
||
function trim(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
// normalize whitespace
|
||
var result = str.replace(/[ \t\n\r]+/gm, ' ');
|
||
if (result.charAt(0) === ' ') {
|
||
// strip leading space
|
||
result = result.substring(1);
|
||
}
|
||
if (result.charAt(result.length - 1) === ' ') {
|
||
// strip trailing space
|
||
result = result.substring(0, result.length - 1);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Pad a string to a minimum width by adding characters to the start or end
|
||
* @param {string} str - string to be padded
|
||
* @param {number} width - the minimum width; +ve pads to the right, -ve pads to the left
|
||
* @param {string} [char] - the pad character(s); defaults to ' '
|
||
* @returns {string} - padded string
|
||
*/
|
||
function pad(str, width, _char) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (typeof _char === 'undefined' || _char.length === 0) {
|
||
_char = ' ';
|
||
}
|
||
var result;
|
||
var padLength = Math.abs(width) - length(str);
|
||
if (padLength > 0) {
|
||
var padding = new Array(padLength + 1).join(_char);
|
||
if (_char.length > 1) {
|
||
padding = substring(padding, 0, padLength);
|
||
}
|
||
if (width > 0) {
|
||
result = str + padding;
|
||
} else {
|
||
result = padding + str;
|
||
}
|
||
} else {
|
||
result = str;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate the matcher function against the str arg
|
||
*
|
||
* @param {*} matcher - matching function (native or lambda)
|
||
* @param {string} str - the string to match against
|
||
* @returns {object} - structure that represents the match(es)
|
||
*/
|
||
function evaluateMatcher(_x, _x2) {
|
||
return _evaluateMatcher.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Tests if the str contains the token
|
||
* @param {String} str - string to test
|
||
* @param {String} token - substring or regex to find
|
||
* @returns {Boolean} - true if str contains token
|
||
*/
|
||
function _evaluateMatcher() {
|
||
_evaluateMatcher = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(matcher, str) {
|
||
var result;
|
||
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
||
while (1) switch (_context.prev = _context.next) {
|
||
case 0:
|
||
result = matcher.apply(this, [str]); // eslint-disable-line no-useless-call
|
||
if (!isPromise(result)) {
|
||
_context.next = 5;
|
||
break;
|
||
}
|
||
_context.next = 4;
|
||
return result;
|
||
case 4:
|
||
result = _context.sent;
|
||
case 5:
|
||
if (!(result && !(typeof result.start === 'number' || result.end === 'number' || Array.isArray(result.groups) || isFunction(result.next)))) {
|
||
_context.next = 7;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T1010",
|
||
stack: new Error().stack
|
||
};
|
||
case 7:
|
||
return _context.abrupt("return", result);
|
||
case 8:
|
||
case "end":
|
||
return _context.stop();
|
||
}
|
||
}, _callee, this);
|
||
}));
|
||
return _evaluateMatcher.apply(this, arguments);
|
||
}
|
||
function contains(_x3, _x4) {
|
||
return _contains.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Match a string with a regex returning an array of object containing details of each match
|
||
* @param {String} str - string
|
||
* @param {String} regex - the regex applied to the string
|
||
* @param {Integer} [limit] - max number of matches to return
|
||
* @returns {Array} The array of match objects
|
||
*/
|
||
function _contains() {
|
||
_contains = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(str, token) {
|
||
var result, matches;
|
||
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
||
while (1) switch (_context2.prev = _context2.next) {
|
||
case 0:
|
||
if (!(typeof str === 'undefined')) {
|
||
_context2.next = 2;
|
||
break;
|
||
}
|
||
return _context2.abrupt("return", undefined);
|
||
case 2:
|
||
if (!(typeof token === 'string')) {
|
||
_context2.next = 6;
|
||
break;
|
||
}
|
||
result = str.indexOf(token) !== -1;
|
||
_context2.next = 10;
|
||
break;
|
||
case 6:
|
||
_context2.next = 8;
|
||
return evaluateMatcher(token, str);
|
||
case 8:
|
||
matches = _context2.sent;
|
||
result = typeof matches !== 'undefined';
|
||
case 10:
|
||
return _context2.abrupt("return", result);
|
||
case 11:
|
||
case "end":
|
||
return _context2.stop();
|
||
}
|
||
}, _callee2);
|
||
}));
|
||
return _contains.apply(this, arguments);
|
||
}
|
||
function match(_x5, _x6, _x7) {
|
||
return _match.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Match a string with a regex returning an array of object containing details of each match
|
||
* @param {String} str - string
|
||
* @param {String} pattern - the substring/regex applied to the string
|
||
* @param {String} replacement - text to replace the matched substrings
|
||
* @param {Integer} [limit] - max number of matches to return
|
||
* @returns {Array} The array of match objects
|
||
*/
|
||
function _match() {
|
||
_match = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(str, regex, limit) {
|
||
var result, count, matches;
|
||
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
||
while (1) switch (_context3.prev = _context3.next) {
|
||
case 0:
|
||
if (!(typeof str === 'undefined')) {
|
||
_context3.next = 2;
|
||
break;
|
||
}
|
||
return _context3.abrupt("return", undefined);
|
||
case 2:
|
||
if (!(limit < 0)) {
|
||
_context3.next = 4;
|
||
break;
|
||
}
|
||
throw {
|
||
stack: new Error().stack,
|
||
value: limit,
|
||
code: 'D3040',
|
||
index: 3
|
||
};
|
||
case 4:
|
||
result = createSequence();
|
||
if (!(typeof limit === 'undefined' || limit > 0)) {
|
||
_context3.next = 19;
|
||
break;
|
||
}
|
||
count = 0;
|
||
_context3.next = 9;
|
||
return evaluateMatcher(regex, str);
|
||
case 9:
|
||
matches = _context3.sent;
|
||
if (!(typeof matches !== 'undefined')) {
|
||
_context3.next = 19;
|
||
break;
|
||
}
|
||
case 11:
|
||
if (!(typeof matches !== 'undefined' && (typeof limit === 'undefined' || count < limit))) {
|
||
_context3.next = 19;
|
||
break;
|
||
}
|
||
result.push({
|
||
match: matches.match,
|
||
index: matches.start,
|
||
groups: matches.groups
|
||
});
|
||
_context3.next = 15;
|
||
return evaluateMatcher(matches.next);
|
||
case 15:
|
||
matches = _context3.sent;
|
||
count++;
|
||
_context3.next = 11;
|
||
break;
|
||
case 19:
|
||
return _context3.abrupt("return", result);
|
||
case 20:
|
||
case "end":
|
||
return _context3.stop();
|
||
}
|
||
}, _callee3);
|
||
}));
|
||
return _match.apply(this, arguments);
|
||
}
|
||
function replace(_x8, _x9, _x10, _x11) {
|
||
return _replace.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Base64 encode a string
|
||
* @param {String} str - string
|
||
* @returns {String} Base 64 encoding of the binary data
|
||
*/
|
||
function _replace() {
|
||
_replace = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(str, pattern, replacement, limit) {
|
||
var self, replacer, result, position, count, index, matches, replacedWith;
|
||
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
||
while (1) switch (_context4.prev = _context4.next) {
|
||
case 0:
|
||
if (!(typeof str === 'undefined')) {
|
||
_context4.next = 2;
|
||
break;
|
||
}
|
||
return _context4.abrupt("return", undefined);
|
||
case 2:
|
||
self = this; // pattern cannot be an empty string
|
||
if (!(pattern === '')) {
|
||
_context4.next = 5;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "D3010",
|
||
stack: new Error().stack,
|
||
value: pattern,
|
||
index: 2
|
||
};
|
||
case 5:
|
||
if (!(limit < 0)) {
|
||
_context4.next = 7;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "D3011",
|
||
stack: new Error().stack,
|
||
value: limit,
|
||
index: 4
|
||
};
|
||
case 7:
|
||
if (typeof replacement === 'string') {
|
||
replacer = function replacer(regexMatch) {
|
||
var substitute = '';
|
||
// scan forward, copying the replacement text into the substitute string
|
||
// and replace any occurrence of $n with the values matched by the regex
|
||
var position = 0;
|
||
var index = replacement.indexOf('$', position);
|
||
while (index !== -1 && position < replacement.length) {
|
||
substitute += replacement.substring(position, index);
|
||
position = index + 1;
|
||
var dollarVal = replacement.charAt(position);
|
||
if (dollarVal === '$') {
|
||
// literal $
|
||
substitute += '$';
|
||
position++;
|
||
} else if (dollarVal === '0') {
|
||
substitute += regexMatch.match;
|
||
position++;
|
||
} else {
|
||
var maxDigits;
|
||
if (regexMatch.groups.length === 0) {
|
||
// no sub-matches; any $ followed by a digit will be replaced by an empty string
|
||
maxDigits = 1;
|
||
} else {
|
||
// max number of digits to parse following the $
|
||
maxDigits = Math.floor(Math.log(regexMatch.groups.length) * Math.LOG10E) + 1;
|
||
}
|
||
index = parseInt(replacement.substring(position, position + maxDigits), 10);
|
||
if (maxDigits > 1 && index > regexMatch.groups.length) {
|
||
index = parseInt(replacement.substring(position, position + maxDigits - 1), 10);
|
||
}
|
||
if (!isNaN(index)) {
|
||
if (regexMatch.groups.length > 0) {
|
||
var submatch = regexMatch.groups[index - 1];
|
||
if (typeof submatch !== 'undefined') {
|
||
substitute += submatch;
|
||
}
|
||
}
|
||
position += index.toString().length;
|
||
} else {
|
||
// not a capture group, treat the $ as literal
|
||
substitute += '$';
|
||
}
|
||
}
|
||
index = replacement.indexOf('$', position);
|
||
}
|
||
substitute += replacement.substring(position);
|
||
return substitute;
|
||
};
|
||
} else {
|
||
replacer = replacement;
|
||
}
|
||
result = '';
|
||
position = 0;
|
||
if (!(typeof limit === 'undefined' || limit > 0)) {
|
||
_context4.next = 47;
|
||
break;
|
||
}
|
||
count = 0;
|
||
if (!(typeof pattern === 'string')) {
|
||
_context4.next = 18;
|
||
break;
|
||
}
|
||
index = str.indexOf(pattern, position);
|
||
while (index !== -1 && (typeof limit === 'undefined' || count < limit)) {
|
||
result += str.substring(position, index);
|
||
result += replacement;
|
||
position = index + pattern.length;
|
||
count++;
|
||
index = str.indexOf(pattern, position);
|
||
}
|
||
result += str.substring(position);
|
||
_context4.next = 45;
|
||
break;
|
||
case 18:
|
||
_context4.next = 20;
|
||
return evaluateMatcher(pattern, str);
|
||
case 20:
|
||
matches = _context4.sent;
|
||
if (!(typeof matches !== 'undefined')) {
|
||
_context4.next = 44;
|
||
break;
|
||
}
|
||
case 22:
|
||
if (!(typeof matches !== 'undefined' && (typeof limit === 'undefined' || count < limit))) {
|
||
_context4.next = 41;
|
||
break;
|
||
}
|
||
result += str.substring(position, matches.start);
|
||
replacedWith = replacer.apply(self, [matches]);
|
||
if (!isPromise(replacedWith)) {
|
||
_context4.next = 29;
|
||
break;
|
||
}
|
||
_context4.next = 28;
|
||
return replacedWith;
|
||
case 28:
|
||
replacedWith = _context4.sent;
|
||
case 29:
|
||
if (!(typeof replacedWith === 'string')) {
|
||
_context4.next = 33;
|
||
break;
|
||
}
|
||
result += replacedWith;
|
||
_context4.next = 34;
|
||
break;
|
||
case 33:
|
||
throw {
|
||
code: "D3012",
|
||
stack: new Error().stack,
|
||
value: replacedWith
|
||
};
|
||
case 34:
|
||
position = matches.start + matches.match.length;
|
||
count++;
|
||
_context4.next = 38;
|
||
return evaluateMatcher(matches.next);
|
||
case 38:
|
||
matches = _context4.sent;
|
||
_context4.next = 22;
|
||
break;
|
||
case 41:
|
||
result += str.substring(position);
|
||
_context4.next = 45;
|
||
break;
|
||
case 44:
|
||
result = str;
|
||
case 45:
|
||
_context4.next = 48;
|
||
break;
|
||
case 47:
|
||
result = str;
|
||
case 48:
|
||
return _context4.abrupt("return", result);
|
||
case 49:
|
||
case "end":
|
||
return _context4.stop();
|
||
}
|
||
}, _callee4, this);
|
||
}));
|
||
return _replace.apply(this, arguments);
|
||
}
|
||
function base64encode(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
// Use btoa in a browser, or Buffer in Node.js
|
||
|
||
var btoa = typeof window !== 'undefined' ? /* istanbul ignore next */window.btoa : function (str) {
|
||
// Simply doing `new Buffer` at this point causes Browserify to pull
|
||
// in the entire Buffer browser library, which is large and unnecessary.
|
||
// Using `global.Buffer` defeats this.
|
||
return new global.Buffer.from(str, 'binary').toString('base64'); // eslint-disable-line new-cap
|
||
};
|
||
return btoa(str);
|
||
}
|
||
|
||
/**
|
||
* Base64 decode a string
|
||
* @param {String} str - string
|
||
* @returns {String} Base 64 encoding of the binary data
|
||
*/
|
||
function base64decode(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
// Use btoa in a browser, or Buffer in Node.js
|
||
var atob = typeof window !== 'undefined' ? /* istanbul ignore next */window.atob : function (str) {
|
||
// Simply doing `new Buffer` at this point causes Browserify to pull
|
||
// in the entire Buffer browser library, which is large and unnecessary.
|
||
// Using `global.Buffer` defeats this.
|
||
return new global.Buffer.from(str, 'base64').toString('binary'); // eslint-disable-line new-cap
|
||
};
|
||
return atob(str);
|
||
}
|
||
|
||
/**
|
||
* Encode a string into a component for a url
|
||
* @param {String} str - String to encode
|
||
* @returns {string} Encoded string
|
||
*/
|
||
function encodeUrlComponent(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
// Catch URIErrors when URI sequence is malformed
|
||
var returnVal;
|
||
try {
|
||
returnVal = encodeURIComponent(str);
|
||
} catch (e) {
|
||
throw {
|
||
code: "D3140",
|
||
stack: new Error().stack,
|
||
value: str,
|
||
functionName: "encodeUrlComponent"
|
||
};
|
||
}
|
||
return returnVal;
|
||
}
|
||
|
||
/**
|
||
* Encode a string into a url
|
||
* @param {String} str - String to encode
|
||
* @returns {string} Encoded string
|
||
*/
|
||
function encodeUrl(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
// Catch URIErrors when URI sequence is malformed
|
||
var returnVal;
|
||
try {
|
||
returnVal = encodeURI(str);
|
||
} catch (e) {
|
||
throw {
|
||
code: "D3140",
|
||
stack: new Error().stack,
|
||
value: str,
|
||
functionName: "encodeUrl"
|
||
};
|
||
}
|
||
return returnVal;
|
||
}
|
||
|
||
/**
|
||
* Decode a string from a component for a url
|
||
* @param {String} str - String to decode
|
||
* @returns {string} Decoded string
|
||
*/
|
||
function decodeUrlComponent(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
// Catch URIErrors when URI sequence is malformed
|
||
var returnVal;
|
||
try {
|
||
returnVal = decodeURIComponent(str);
|
||
} catch (e) {
|
||
throw {
|
||
code: "D3140",
|
||
stack: new Error().stack,
|
||
value: str,
|
||
functionName: "decodeUrlComponent"
|
||
};
|
||
}
|
||
return returnVal;
|
||
}
|
||
|
||
/**
|
||
* Decode a string from a url
|
||
* @param {String} str - String to decode
|
||
* @returns {string} Decoded string
|
||
*/
|
||
function decodeUrl(str) {
|
||
// undefined inputs always return undefined
|
||
if (typeof str === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
// Catch URIErrors when URI sequence is malformed
|
||
var returnVal;
|
||
try {
|
||
returnVal = decodeURI(str);
|
||
} catch (e) {
|
||
throw {
|
||
code: "D3140",
|
||
stack: new Error().stack,
|
||
value: str,
|
||
functionName: "decodeUrl"
|
||
};
|
||
}
|
||
return returnVal;
|
||
}
|
||
|
||
/**
|
||
* Split a string into an array of substrings
|
||
* @param {String} str - string
|
||
* @param {String} separator - the token or regex that splits the string
|
||
* @param {Integer} [limit] - max number of substrings
|
||
* @returns {Array} The array of string
|
||
*/
|
||
function split(_x12, _x13, _x14) {
|
||
return _split.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Join an array of strings
|
||
* @param {Array} strs - array of string
|
||
* @param {String} [separator] - the token that splits the string
|
||
* @returns {String} The concatenated string
|
||
*/
|
||
function _split() {
|
||
_split = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(str, separator, limit) {
|
||
var result, count, matches, start;
|
||
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
|
||
while (1) switch (_context5.prev = _context5.next) {
|
||
case 0:
|
||
if (!(typeof str === 'undefined')) {
|
||
_context5.next = 2;
|
||
break;
|
||
}
|
||
return _context5.abrupt("return", undefined);
|
||
case 2:
|
||
if (!(limit < 0)) {
|
||
_context5.next = 4;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "D3020",
|
||
stack: new Error().stack,
|
||
value: limit,
|
||
index: 3
|
||
};
|
||
case 4:
|
||
result = [];
|
||
if (!(typeof limit === 'undefined' || limit > 0)) {
|
||
_context5.next = 29;
|
||
break;
|
||
}
|
||
if (!(typeof separator === 'string')) {
|
||
_context5.next = 10;
|
||
break;
|
||
}
|
||
result = str.split(separator, limit);
|
||
_context5.next = 29;
|
||
break;
|
||
case 10:
|
||
count = 0;
|
||
_context5.next = 13;
|
||
return evaluateMatcher(separator, str);
|
||
case 13:
|
||
matches = _context5.sent;
|
||
if (!(typeof matches !== 'undefined')) {
|
||
_context5.next = 28;
|
||
break;
|
||
}
|
||
start = 0;
|
||
case 16:
|
||
if (!(typeof matches !== 'undefined' && (typeof limit === 'undefined' || count < limit))) {
|
||
_context5.next = 25;
|
||
break;
|
||
}
|
||
result.push(str.substring(start, matches.start));
|
||
start = matches.end;
|
||
_context5.next = 21;
|
||
return evaluateMatcher(matches.next);
|
||
case 21:
|
||
matches = _context5.sent;
|
||
count++;
|
||
_context5.next = 16;
|
||
break;
|
||
case 25:
|
||
if (typeof limit === 'undefined' || count < limit) {
|
||
result.push(str.substring(start));
|
||
}
|
||
_context5.next = 29;
|
||
break;
|
||
case 28:
|
||
result.push(str);
|
||
case 29:
|
||
return _context5.abrupt("return", result);
|
||
case 30:
|
||
case "end":
|
||
return _context5.stop();
|
||
}
|
||
}, _callee5);
|
||
}));
|
||
return _split.apply(this, arguments);
|
||
}
|
||
function join(strs, separator) {
|
||
// undefined inputs always return undefined
|
||
if (typeof strs === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
// if separator is not specified, default to empty string
|
||
if (typeof separator === 'undefined') {
|
||
separator = "";
|
||
}
|
||
return strs.join(separator);
|
||
}
|
||
|
||
/**
|
||
* Formats a number into a decimal string representation using XPath 3.1 F&O fn:format-number spec
|
||
* @param {number} value - number to format
|
||
* @param {String} picture - picture string definition
|
||
* @param {Object} [options] - override locale defaults
|
||
* @returns {String} The formatted string
|
||
*/
|
||
function formatNumber(value, picture, options) {
|
||
// undefined inputs always return undefined
|
||
if (typeof value === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var defaults = {
|
||
"decimal-separator": ".",
|
||
"grouping-separator": ",",
|
||
"exponent-separator": "e",
|
||
"infinity": "Infinity",
|
||
"minus-sign": "-",
|
||
"NaN": "NaN",
|
||
"percent": "%",
|
||
"per-mille": "\u2030",
|
||
"zero-digit": "0",
|
||
"digit": "#",
|
||
"pattern-separator": ";"
|
||
};
|
||
|
||
// if `options` is specified, then its entries override defaults
|
||
var properties = defaults;
|
||
if (typeof options !== 'undefined') {
|
||
Object.keys(options).forEach(function (key) {
|
||
properties[key] = options[key];
|
||
});
|
||
}
|
||
var decimalDigitFamily = [];
|
||
var zeroCharCode = properties['zero-digit'].charCodeAt(0);
|
||
for (var ii = zeroCharCode; ii < zeroCharCode + 10; ii++) {
|
||
decimalDigitFamily.push(String.fromCharCode(ii));
|
||
}
|
||
var activeChars = decimalDigitFamily.concat([properties['decimal-separator'], properties['exponent-separator'], properties['grouping-separator'], properties.digit, properties['pattern-separator']]);
|
||
var subPictures = picture.split(properties['pattern-separator']);
|
||
if (subPictures.length > 2) {
|
||
throw {
|
||
code: 'D3080',
|
||
stack: new Error().stack
|
||
};
|
||
}
|
||
var splitParts = function splitParts(subpicture) {
|
||
var prefix = function () {
|
||
var ch;
|
||
for (var ii = 0; ii < subpicture.length; ii++) {
|
||
ch = subpicture.charAt(ii);
|
||
if (activeChars.indexOf(ch) !== -1 && ch !== properties['exponent-separator']) {
|
||
return subpicture.substring(0, ii);
|
||
}
|
||
}
|
||
}();
|
||
var suffix = function () {
|
||
var ch;
|
||
for (var ii = subpicture.length - 1; ii >= 0; ii--) {
|
||
ch = subpicture.charAt(ii);
|
||
if (activeChars.indexOf(ch) !== -1 && ch !== properties['exponent-separator']) {
|
||
return subpicture.substring(ii + 1);
|
||
}
|
||
}
|
||
}();
|
||
var activePart = subpicture.substring(prefix.length, subpicture.length - suffix.length);
|
||
var mantissaPart, exponentPart, integerPart, fractionalPart;
|
||
var exponentPosition = subpicture.indexOf(properties['exponent-separator'], prefix.length);
|
||
if (exponentPosition === -1 || exponentPosition > subpicture.length - suffix.length) {
|
||
mantissaPart = activePart;
|
||
exponentPart = undefined;
|
||
} else {
|
||
mantissaPart = activePart.substring(0, exponentPosition);
|
||
exponentPart = activePart.substring(exponentPosition + 1);
|
||
}
|
||
var decimalPosition = mantissaPart.indexOf(properties['decimal-separator']);
|
||
if (decimalPosition === -1) {
|
||
integerPart = mantissaPart;
|
||
fractionalPart = suffix;
|
||
} else {
|
||
integerPart = mantissaPart.substring(0, decimalPosition);
|
||
fractionalPart = mantissaPart.substring(decimalPosition + 1);
|
||
}
|
||
return {
|
||
prefix: prefix,
|
||
suffix: suffix,
|
||
activePart: activePart,
|
||
mantissaPart: mantissaPart,
|
||
exponentPart: exponentPart,
|
||
integerPart: integerPart,
|
||
fractionalPart: fractionalPart,
|
||
subpicture: subpicture
|
||
};
|
||
};
|
||
|
||
// validate the picture string, F&O 4.7.3
|
||
var validate = function validate(parts) {
|
||
var error;
|
||
var ii;
|
||
var subpicture = parts.subpicture;
|
||
var decimalPos = subpicture.indexOf(properties['decimal-separator']);
|
||
if (decimalPos !== subpicture.lastIndexOf(properties['decimal-separator'])) {
|
||
error = 'D3081';
|
||
}
|
||
if (subpicture.indexOf(properties.percent) !== subpicture.lastIndexOf(properties.percent)) {
|
||
error = 'D3082';
|
||
}
|
||
if (subpicture.indexOf(properties['per-mille']) !== subpicture.lastIndexOf(properties['per-mille'])) {
|
||
error = 'D3083';
|
||
}
|
||
if (subpicture.indexOf(properties.percent) !== -1 && subpicture.indexOf(properties['per-mille']) !== -1) {
|
||
error = 'D3084';
|
||
}
|
||
var valid = false;
|
||
for (ii = 0; ii < parts.mantissaPart.length; ii++) {
|
||
var ch = parts.mantissaPart.charAt(ii);
|
||
if (decimalDigitFamily.indexOf(ch) !== -1 || ch === properties.digit) {
|
||
valid = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!valid) {
|
||
error = 'D3085';
|
||
}
|
||
var charTypes = parts.activePart.split('').map(function (_char2) {
|
||
return activeChars.indexOf(_char2) === -1 ? 'p' : 'a';
|
||
}).join('');
|
||
if (charTypes.indexOf('p') !== -1) {
|
||
error = 'D3086';
|
||
}
|
||
if (decimalPos !== -1) {
|
||
if (subpicture.charAt(decimalPos - 1) === properties['grouping-separator'] || subpicture.charAt(decimalPos + 1) === properties['grouping-separator']) {
|
||
error = 'D3087';
|
||
}
|
||
} else if (parts.integerPart.charAt(parts.integerPart.length - 1) === properties['grouping-separator']) {
|
||
error = 'D3088';
|
||
}
|
||
if (subpicture.indexOf(properties['grouping-separator'] + properties['grouping-separator']) !== -1) {
|
||
error = 'D3089';
|
||
}
|
||
var optionalDigitPos = parts.integerPart.indexOf(properties.digit);
|
||
if (optionalDigitPos !== -1 && parts.integerPart.substring(0, optionalDigitPos).split('').filter(function (_char3) {
|
||
return decimalDigitFamily.indexOf(_char3) > -1;
|
||
}).length > 0) {
|
||
error = 'D3090';
|
||
}
|
||
optionalDigitPos = parts.fractionalPart.lastIndexOf(properties.digit);
|
||
if (optionalDigitPos !== -1 && parts.fractionalPart.substring(optionalDigitPos).split('').filter(function (_char4) {
|
||
return decimalDigitFamily.indexOf(_char4) > -1;
|
||
}).length > 0) {
|
||
error = 'D3091';
|
||
}
|
||
var exponentExists = typeof parts.exponentPart === 'string';
|
||
if (exponentExists && parts.exponentPart.length > 0 && (subpicture.indexOf(properties.percent) !== -1 || subpicture.indexOf(properties['per-mille']) !== -1)) {
|
||
error = 'D3092';
|
||
}
|
||
if (exponentExists && (parts.exponentPart.length === 0 || parts.exponentPart.split('').filter(function (_char5) {
|
||
return decimalDigitFamily.indexOf(_char5) === -1;
|
||
}).length > 0)) {
|
||
error = 'D3093';
|
||
}
|
||
if (error) {
|
||
throw {
|
||
code: error,
|
||
stack: new Error().stack
|
||
};
|
||
}
|
||
};
|
||
|
||
// analyse the picture string, F&O 4.7.4
|
||
var analyse = function analyse(parts) {
|
||
var getGroupingPositions = function getGroupingPositions(part, toLeft) {
|
||
var positions = [];
|
||
var groupingPosition = part.indexOf(properties['grouping-separator']);
|
||
while (groupingPosition !== -1) {
|
||
var charsToTheRight = (toLeft ? part.substring(0, groupingPosition) : part.substring(groupingPosition)).split('').filter(function (_char6) {
|
||
return decimalDigitFamily.indexOf(_char6) !== -1 || _char6 === properties.digit;
|
||
}).length;
|
||
positions.push(charsToTheRight);
|
||
groupingPosition = parts.integerPart.indexOf(properties['grouping-separator'], groupingPosition + 1);
|
||
}
|
||
return positions;
|
||
};
|
||
var integerPartGroupingPositions = getGroupingPositions(parts.integerPart);
|
||
var regular = function regular(indexes) {
|
||
// are the grouping positions regular? i.e. same interval between each of them
|
||
if (indexes.length === 0) {
|
||
return 0;
|
||
}
|
||
var gcd = function gcd(a, b) {
|
||
return b === 0 ? a : gcd(b, a % b);
|
||
};
|
||
// find the greatest common divisor of all the positions
|
||
var factor = indexes.reduce(gcd);
|
||
// is every position separated by this divisor? If so, it's regular
|
||
for (var index = 1; index <= indexes.length; index++) {
|
||
if (indexes.indexOf(index * factor) === -1) {
|
||
return 0;
|
||
}
|
||
}
|
||
return factor;
|
||
};
|
||
var regularGrouping = regular(integerPartGroupingPositions);
|
||
var fractionalPartGroupingPositions = getGroupingPositions(parts.fractionalPart, true);
|
||
var minimumIntegerPartSize = parts.integerPart.split('').filter(function (_char7) {
|
||
return decimalDigitFamily.indexOf(_char7) !== -1;
|
||
}).length;
|
||
var scalingFactor = minimumIntegerPartSize;
|
||
var fractionalPartArray = parts.fractionalPart.split('');
|
||
var minimumFactionalPartSize = fractionalPartArray.filter(function (_char8) {
|
||
return decimalDigitFamily.indexOf(_char8) !== -1;
|
||
}).length;
|
||
var maximumFactionalPartSize = fractionalPartArray.filter(function (_char9) {
|
||
return decimalDigitFamily.indexOf(_char9) !== -1 || _char9 === properties.digit;
|
||
}).length;
|
||
var exponentPresent = typeof parts.exponentPart === 'string';
|
||
if (minimumIntegerPartSize === 0 && maximumFactionalPartSize === 0) {
|
||
if (exponentPresent) {
|
||
minimumFactionalPartSize = 1;
|
||
maximumFactionalPartSize = 1;
|
||
} else {
|
||
minimumIntegerPartSize = 1;
|
||
}
|
||
}
|
||
if (exponentPresent && minimumIntegerPartSize === 0 && parts.integerPart.indexOf(properties.digit) !== -1) {
|
||
minimumIntegerPartSize = 1;
|
||
}
|
||
if (minimumIntegerPartSize === 0 && minimumFactionalPartSize === 0) {
|
||
minimumFactionalPartSize = 1;
|
||
}
|
||
var minimumExponentSize = 0;
|
||
if (exponentPresent) {
|
||
minimumExponentSize = parts.exponentPart.split('').filter(function (_char10) {
|
||
return decimalDigitFamily.indexOf(_char10) !== -1;
|
||
}).length;
|
||
}
|
||
return {
|
||
integerPartGroupingPositions: integerPartGroupingPositions,
|
||
regularGrouping: regularGrouping,
|
||
minimumIntegerPartSize: minimumIntegerPartSize,
|
||
scalingFactor: scalingFactor,
|
||
prefix: parts.prefix,
|
||
fractionalPartGroupingPositions: fractionalPartGroupingPositions,
|
||
minimumFactionalPartSize: minimumFactionalPartSize,
|
||
maximumFactionalPartSize: maximumFactionalPartSize,
|
||
minimumExponentSize: minimumExponentSize,
|
||
suffix: parts.suffix,
|
||
picture: parts.subpicture
|
||
};
|
||
};
|
||
var parts = subPictures.map(splitParts);
|
||
parts.forEach(validate);
|
||
var variables = parts.map(analyse);
|
||
var minus_sign = properties['minus-sign'];
|
||
var zero_digit = properties['zero-digit'];
|
||
var decimal_separator = properties['decimal-separator'];
|
||
var grouping_separator = properties['grouping-separator'];
|
||
if (variables.length === 1) {
|
||
variables.push(JSON.parse(JSON.stringify(variables[0])));
|
||
variables[1].prefix = minus_sign + variables[1].prefix;
|
||
}
|
||
|
||
// TODO cache the result of the analysis
|
||
|
||
// format the number
|
||
// bullet 1: TODO: NaN - not sure we'd ever get this in JSON
|
||
var pic;
|
||
// bullet 2:
|
||
if (value >= 0) {
|
||
pic = variables[0];
|
||
} else {
|
||
pic = variables[1];
|
||
}
|
||
var adjustedNumber;
|
||
// bullet 3:
|
||
if (pic.picture.indexOf(properties.percent) !== -1) {
|
||
adjustedNumber = value * 100;
|
||
} else if (pic.picture.indexOf(properties['per-mille']) !== -1) {
|
||
adjustedNumber = value * 1000;
|
||
} else {
|
||
adjustedNumber = value;
|
||
}
|
||
// bullet 4:
|
||
// TODO: infinity - not sure we'd ever get this in JSON
|
||
// bullet 5:
|
||
var mantissa, exponent;
|
||
if (pic.minimumExponentSize === 0) {
|
||
mantissa = adjustedNumber;
|
||
} else {
|
||
// mantissa * 10^exponent = adjustedNumber
|
||
var maxMantissa = Math.pow(10, pic.scalingFactor);
|
||
var minMantissa = Math.pow(10, pic.scalingFactor - 1);
|
||
mantissa = adjustedNumber;
|
||
exponent = 0;
|
||
while (mantissa < minMantissa) {
|
||
mantissa *= 10;
|
||
exponent -= 1;
|
||
}
|
||
while (mantissa > maxMantissa) {
|
||
mantissa /= 10;
|
||
exponent += 1;
|
||
}
|
||
}
|
||
// bullet 6:
|
||
var roundedNumber = round(mantissa, pic.maximumFactionalPartSize);
|
||
// bullet 7:
|
||
var makeString = function makeString(value, dp) {
|
||
var str = Math.abs(value).toFixed(dp);
|
||
if (zero_digit !== '0') {
|
||
str = str.split('').map(function (digit) {
|
||
if (digit >= '0' && digit <= '9') {
|
||
return decimalDigitFamily[digit.charCodeAt(0) - 48];
|
||
} else {
|
||
return digit;
|
||
}
|
||
}).join('');
|
||
}
|
||
return str;
|
||
};
|
||
var stringValue = makeString(roundedNumber, pic.maximumFactionalPartSize);
|
||
var decimalPos = stringValue.indexOf('.');
|
||
if (decimalPos === -1) {
|
||
stringValue = stringValue + decimal_separator;
|
||
} else {
|
||
stringValue = stringValue.replace('.', decimal_separator);
|
||
}
|
||
while (stringValue.charAt(0) === zero_digit) {
|
||
stringValue = stringValue.substring(1);
|
||
}
|
||
while (stringValue.charAt(stringValue.length - 1) === zero_digit) {
|
||
stringValue = stringValue.substring(0, stringValue.length - 1);
|
||
}
|
||
// bullets 8 & 9:
|
||
decimalPos = stringValue.indexOf(decimal_separator);
|
||
var padLeft = pic.minimumIntegerPartSize - decimalPos;
|
||
var padRight = pic.minimumFactionalPartSize - (stringValue.length - decimalPos - 1);
|
||
stringValue = (padLeft > 0 ? new Array(padLeft + 1).join(zero_digit) : '') + stringValue;
|
||
stringValue = stringValue + (padRight > 0 ? new Array(padRight + 1).join(zero_digit) : '');
|
||
decimalPos = stringValue.indexOf(decimal_separator);
|
||
// bullet 10:
|
||
if (pic.regularGrouping > 0) {
|
||
var groupCount = Math.floor((decimalPos - 1) / pic.regularGrouping);
|
||
for (var group = 1; group <= groupCount; group++) {
|
||
stringValue = [stringValue.slice(0, decimalPos - group * pic.regularGrouping), grouping_separator, stringValue.slice(decimalPos - group * pic.regularGrouping)].join('');
|
||
}
|
||
} else {
|
||
pic.integerPartGroupingPositions.forEach(function (pos) {
|
||
stringValue = [stringValue.slice(0, decimalPos - pos), grouping_separator, stringValue.slice(decimalPos - pos)].join('');
|
||
decimalPos++;
|
||
});
|
||
}
|
||
// bullet 11:
|
||
decimalPos = stringValue.indexOf(decimal_separator);
|
||
pic.fractionalPartGroupingPositions.forEach(function (pos) {
|
||
stringValue = [stringValue.slice(0, pos + decimalPos + 1), grouping_separator, stringValue.slice(pos + decimalPos + 1)].join('');
|
||
});
|
||
// bullet 12:
|
||
decimalPos = stringValue.indexOf(decimal_separator);
|
||
if (pic.picture.indexOf(decimal_separator) === -1 || decimalPos === stringValue.length - 1) {
|
||
stringValue = stringValue.substring(0, stringValue.length - 1);
|
||
}
|
||
// bullet 13:
|
||
if (typeof exponent !== 'undefined') {
|
||
var stringExponent = makeString(exponent, 0);
|
||
padLeft = pic.minimumExponentSize - stringExponent.length;
|
||
if (padLeft > 0) {
|
||
stringExponent = new Array(padLeft + 1).join(zero_digit) + stringExponent;
|
||
}
|
||
stringValue = stringValue + properties['exponent-separator'] + (exponent < 0 ? minus_sign : '') + stringExponent;
|
||
}
|
||
// bullet 14:
|
||
stringValue = pic.prefix + stringValue + pic.suffix;
|
||
return stringValue;
|
||
}
|
||
|
||
/**
|
||
* Converts a number to a string using a specified number base
|
||
* @param {number} value - the number to convert
|
||
* @param {number} [radix] - the number base; must be between 2 and 36. Defaults to 10
|
||
* @returns {string} - the converted string
|
||
*/
|
||
function formatBase(value, radix) {
|
||
// undefined inputs always return undefined
|
||
if (typeof value === 'undefined') {
|
||
return undefined;
|
||
}
|
||
value = round(value);
|
||
if (typeof radix === 'undefined') {
|
||
radix = 10;
|
||
} else {
|
||
radix = round(radix);
|
||
}
|
||
if (radix < 2 || radix > 36) {
|
||
throw {
|
||
code: 'D3100',
|
||
stack: new Error().stack,
|
||
value: radix
|
||
};
|
||
}
|
||
var result = value.toString(radix);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Cast argument to number
|
||
* @param {Object} arg - Argument
|
||
* @returns {Number} numeric value of argument
|
||
*/
|
||
function number(arg) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (typeof arg === 'number') {
|
||
// already a number
|
||
result = arg;
|
||
} else if (typeof arg === 'string' && /^-?[0-9]+(\.[0-9]+)?([Ee][-+]?[0-9]+)?$/.test(arg) && !isNaN(parseFloat(arg)) && isFinite(arg)) {
|
||
result = parseFloat(arg);
|
||
} else if (typeof arg === 'string' && /^(0[xX][0-9A-Fa-f]+)|(0[oO][0-7]+)|(0[bB][0-1]+)$/.test(arg)) {
|
||
result = Number(arg);
|
||
} else if (arg === true) {
|
||
// boolean true casts to 1
|
||
result = 1;
|
||
} else if (arg === false) {
|
||
// boolean false casts to 0
|
||
result = 0;
|
||
} else {
|
||
throw {
|
||
code: "D3030",
|
||
value: arg,
|
||
stack: new Error().stack,
|
||
index: 1
|
||
};
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Absolute value of a number
|
||
* @param {Number} arg - Argument
|
||
* @returns {Number} absolute value of argument
|
||
*/
|
||
function abs(arg) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
result = Math.abs(arg);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Rounds a number down to integer
|
||
* @param {Number} arg - Argument
|
||
* @returns {Number} rounded integer
|
||
*/
|
||
function floor(arg) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
result = Math.floor(arg);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Rounds a number up to integer
|
||
* @param {Number} arg - Argument
|
||
* @returns {Number} rounded integer
|
||
*/
|
||
function ceil(arg) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
result = Math.ceil(arg);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Round to half even
|
||
* @param {Number} arg - Argument
|
||
* @param {Number} [precision] - number of decimal places
|
||
* @returns {Number} rounded integer
|
||
*/
|
||
function round(arg, precision) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (precision) {
|
||
// shift the decimal place - this needs to be done in a string since multiplying
|
||
// by a power of ten can introduce floating point precision errors which mess up
|
||
// this rounding algorithm - See 'Decimal rounding' in
|
||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
|
||
// Shift
|
||
var value = arg.toString().split('e');
|
||
arg = +(value[0] + 'e' + (value[1] ? +value[1] + precision : precision));
|
||
}
|
||
|
||
// round up to nearest int
|
||
result = Math.round(arg);
|
||
var diff = result - arg;
|
||
if (Math.abs(diff) === 0.5 && Math.abs(result % 2) === 1) {
|
||
// rounded the wrong way - adjust to nearest even number
|
||
result = result - 1;
|
||
}
|
||
if (precision) {
|
||
// Shift back
|
||
value = result.toString().split('e');
|
||
/* istanbul ignore next */
|
||
result = +(value[0] + 'e' + (value[1] ? +value[1] - precision : -precision));
|
||
}
|
||
if (Object.is(result, -0)) {
|
||
// ESLint rule 'no-compare-neg-zero' suggests this way
|
||
// JSON doesn't do -0
|
||
result = 0;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Square root of number
|
||
* @param {Number} arg - Argument
|
||
* @returns {Number} square root
|
||
*/
|
||
function sqrt(arg) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (arg < 0) {
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3060",
|
||
index: 1,
|
||
value: arg
|
||
};
|
||
}
|
||
result = Math.sqrt(arg);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Raises number to the power of the second number
|
||
* @param {Number} arg - the base
|
||
* @param {Number} exp - the exponent
|
||
* @returns {Number} rounded integer
|
||
*/
|
||
function power(arg, exp) {
|
||
var result;
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
result = Math.pow(arg, exp);
|
||
if (!isFinite(result)) {
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3061",
|
||
index: 1,
|
||
value: arg,
|
||
exp: exp
|
||
};
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Returns a random number 0 <= n < 1
|
||
* @returns {number} random number
|
||
*/
|
||
function random() {
|
||
return Math.random();
|
||
}
|
||
|
||
/**
|
||
* Evaluate an input and return a boolean
|
||
* @param {*} arg - Arguments
|
||
* @returns {boolean} Boolean
|
||
*/
|
||
function _boolean(arg) {
|
||
// cast arg to its effective boolean value
|
||
// boolean: unchanged
|
||
// string: zero-length -> false; otherwise -> true
|
||
// number: 0 -> false; otherwise -> true
|
||
// null -> false
|
||
// array: empty -> false; length > 1 -> true
|
||
// object: empty -> false; non-empty -> true
|
||
// function -> false
|
||
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var result = false;
|
||
if (Array.isArray(arg)) {
|
||
if (arg.length === 1) {
|
||
result = _boolean(arg[0]);
|
||
} else if (arg.length > 1) {
|
||
var trues = arg.filter(function (val) {
|
||
return _boolean(val);
|
||
});
|
||
result = trues.length > 0;
|
||
}
|
||
} else if (typeof arg === 'string') {
|
||
if (arg.length > 0) {
|
||
result = true;
|
||
}
|
||
} else if (isNumeric(arg)) {
|
||
if (arg !== 0) {
|
||
result = true;
|
||
}
|
||
} else if (arg !== null && _typeof(arg) === 'object') {
|
||
if (Object.keys(arg).length > 0) {
|
||
result = true;
|
||
}
|
||
} else if (typeof arg === 'boolean' && arg === true) {
|
||
result = true;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* returns the Boolean NOT of the arg
|
||
* @param {*} arg - argument
|
||
* @returns {boolean} - NOT arg
|
||
*/
|
||
function not(arg) {
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
return !_boolean(arg);
|
||
}
|
||
|
||
/**
|
||
* Helper function to build the arguments to be supplied to the function arg of the
|
||
* HOFs map, filter, each, sift and single
|
||
* @param {function} func - the function to be invoked
|
||
* @param {*} arg1 - the first (required) arg - the value
|
||
* @param {*} arg2 - the second (optional) arg - the position (index or key)
|
||
* @param {*} arg3 - the third (optional) arg - the whole structure (array or object)
|
||
* @returns {*[]} the argument list
|
||
*/
|
||
function hofFuncArgs(func, arg1, arg2, arg3) {
|
||
var func_args = [arg1]; // the first arg (the value) is required
|
||
// the other two are optional - only supply it if the function can take it
|
||
var length = getFunctionArity(func);
|
||
if (length >= 2) {
|
||
func_args.push(arg2);
|
||
}
|
||
if (length >= 3) {
|
||
func_args.push(arg3);
|
||
}
|
||
return func_args;
|
||
}
|
||
|
||
/**
|
||
* Create a map from an array of arguments
|
||
* @param {Array} [arr] - array to map over
|
||
* @param {Function} func - function to apply
|
||
* @returns {Array} Map array
|
||
*/
|
||
function map(_x15, _x16) {
|
||
return _map.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Create a map from an array of arguments
|
||
* @param {Array} [arr] - array to filter
|
||
* @param {Function} func - predicate function
|
||
* @returns {Array} Map array
|
||
*/
|
||
function _map() {
|
||
_map = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(arr, func) {
|
||
var result, i, func_args, res;
|
||
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
|
||
while (1) switch (_context6.prev = _context6.next) {
|
||
case 0:
|
||
if (!(typeof arr === 'undefined')) {
|
||
_context6.next = 2;
|
||
break;
|
||
}
|
||
return _context6.abrupt("return", undefined);
|
||
case 2:
|
||
result = createSequence(); // do the map - iterate over the arrays, and invoke func
|
||
i = 0;
|
||
case 4:
|
||
if (!(i < arr.length)) {
|
||
_context6.next = 13;
|
||
break;
|
||
}
|
||
func_args = hofFuncArgs(func, arr[i], i, arr); // invoke func
|
||
_context6.next = 8;
|
||
return func.apply(this, func_args);
|
||
case 8:
|
||
res = _context6.sent;
|
||
if (typeof res !== 'undefined') {
|
||
result.push(res);
|
||
}
|
||
case 10:
|
||
i++;
|
||
_context6.next = 4;
|
||
break;
|
||
case 13:
|
||
return _context6.abrupt("return", result);
|
||
case 14:
|
||
case "end":
|
||
return _context6.stop();
|
||
}
|
||
}, _callee6, this);
|
||
}));
|
||
return _map.apply(this, arguments);
|
||
}
|
||
function filter(_x17, _x18) {
|
||
return _filter.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Given an array, find the single element matching a specified condition
|
||
* Throws an exception if the number of matching elements is not exactly one
|
||
* @param {Array} [arr] - array to filter
|
||
* @param {Function} [func] - predicate function
|
||
* @returns {*} Matching element
|
||
*/
|
||
function _filter() {
|
||
_filter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(arr, func) {
|
||
var result, i, entry, func_args, res;
|
||
return _regeneratorRuntime().wrap(function _callee7$(_context7) {
|
||
while (1) switch (_context7.prev = _context7.next) {
|
||
case 0:
|
||
if (!(typeof arr === 'undefined')) {
|
||
_context7.next = 2;
|
||
break;
|
||
}
|
||
return _context7.abrupt("return", undefined);
|
||
case 2:
|
||
result = createSequence();
|
||
i = 0;
|
||
case 4:
|
||
if (!(i < arr.length)) {
|
||
_context7.next = 14;
|
||
break;
|
||
}
|
||
entry = arr[i];
|
||
func_args = hofFuncArgs(func, entry, i, arr); // invoke func
|
||
_context7.next = 9;
|
||
return func.apply(this, func_args);
|
||
case 9:
|
||
res = _context7.sent;
|
||
if (_boolean(res)) {
|
||
result.push(entry);
|
||
}
|
||
case 11:
|
||
i++;
|
||
_context7.next = 4;
|
||
break;
|
||
case 14:
|
||
return _context7.abrupt("return", result);
|
||
case 15:
|
||
case "end":
|
||
return _context7.stop();
|
||
}
|
||
}, _callee7, this);
|
||
}));
|
||
return _filter.apply(this, arguments);
|
||
}
|
||
function single(_x19, _x20) {
|
||
return _single.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Convolves (zips) each value from a set of arrays
|
||
* @param {Array} [args] - arrays to zip
|
||
* @returns {Array} Zipped array
|
||
*/
|
||
function _single() {
|
||
_single = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(arr, func) {
|
||
var hasFoundMatch, result, i, entry, positiveResult, func_args, res;
|
||
return _regeneratorRuntime().wrap(function _callee8$(_context8) {
|
||
while (1) switch (_context8.prev = _context8.next) {
|
||
case 0:
|
||
if (!(typeof arr === 'undefined')) {
|
||
_context8.next = 2;
|
||
break;
|
||
}
|
||
return _context8.abrupt("return", undefined);
|
||
case 2:
|
||
hasFoundMatch = false;
|
||
i = 0;
|
||
case 4:
|
||
if (!(i < arr.length)) {
|
||
_context8.next = 23;
|
||
break;
|
||
}
|
||
entry = arr[i];
|
||
positiveResult = true;
|
||
if (!(typeof func !== 'undefined')) {
|
||
_context8.next = 13;
|
||
break;
|
||
}
|
||
func_args = hofFuncArgs(func, entry, i, arr); // invoke func
|
||
_context8.next = 11;
|
||
return func.apply(this, func_args);
|
||
case 11:
|
||
res = _context8.sent;
|
||
positiveResult = _boolean(res);
|
||
case 13:
|
||
if (!positiveResult) {
|
||
_context8.next = 20;
|
||
break;
|
||
}
|
||
if (hasFoundMatch) {
|
||
_context8.next = 19;
|
||
break;
|
||
}
|
||
result = entry;
|
||
hasFoundMatch = true;
|
||
_context8.next = 20;
|
||
break;
|
||
case 19:
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3138",
|
||
index: i
|
||
};
|
||
case 20:
|
||
i++;
|
||
_context8.next = 4;
|
||
break;
|
||
case 23:
|
||
if (hasFoundMatch) {
|
||
_context8.next = 25;
|
||
break;
|
||
}
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3139"
|
||
};
|
||
case 25:
|
||
return _context8.abrupt("return", result);
|
||
case 26:
|
||
case "end":
|
||
return _context8.stop();
|
||
}
|
||
}, _callee8, this);
|
||
}));
|
||
return _single.apply(this, arguments);
|
||
}
|
||
function zip() {
|
||
// this can take a variable number of arguments
|
||
var result = [];
|
||
var args = Array.prototype.slice.call(arguments);
|
||
// length of the shortest array
|
||
var length = Math.min.apply(Math, args.map(function (arg) {
|
||
if (Array.isArray(arg)) {
|
||
return arg.length;
|
||
}
|
||
return 0;
|
||
}));
|
||
for (var i = 0; i < length; i++) {
|
||
var tuple = args.map(function (arg) {
|
||
return arg[i];
|
||
});
|
||
result.push(tuple);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Fold left function
|
||
* @param {Array} sequence - Sequence
|
||
* @param {Function} func - Function
|
||
* @param {Object} init - Initial value
|
||
* @returns {*} Result
|
||
*/
|
||
function foldLeft(_x21, _x22, _x23) {
|
||
return _foldLeft.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Return keys for an object
|
||
* @param {Object} arg - Object
|
||
* @returns {Array} Array of keys
|
||
*/
|
||
function _foldLeft() {
|
||
_foldLeft = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(sequence, func, init) {
|
||
var result, arity, index, args;
|
||
return _regeneratorRuntime().wrap(function _callee9$(_context9) {
|
||
while (1) switch (_context9.prev = _context9.next) {
|
||
case 0:
|
||
if (!(typeof sequence === 'undefined')) {
|
||
_context9.next = 2;
|
||
break;
|
||
}
|
||
return _context9.abrupt("return", undefined);
|
||
case 2:
|
||
arity = getFunctionArity(func);
|
||
if (!(arity < 2)) {
|
||
_context9.next = 5;
|
||
break;
|
||
}
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3050",
|
||
index: 1
|
||
};
|
||
case 5:
|
||
if (typeof init === 'undefined' && sequence.length > 0) {
|
||
result = sequence[0];
|
||
index = 1;
|
||
} else {
|
||
result = init;
|
||
index = 0;
|
||
}
|
||
case 6:
|
||
if (!(index < sequence.length)) {
|
||
_context9.next = 16;
|
||
break;
|
||
}
|
||
args = [result, sequence[index]];
|
||
if (arity >= 3) {
|
||
args.push(index);
|
||
}
|
||
if (arity >= 4) {
|
||
args.push(sequence);
|
||
}
|
||
_context9.next = 12;
|
||
return func.apply(this, args);
|
||
case 12:
|
||
result = _context9.sent;
|
||
index++;
|
||
_context9.next = 6;
|
||
break;
|
||
case 16:
|
||
return _context9.abrupt("return", result);
|
||
case 17:
|
||
case "end":
|
||
return _context9.stop();
|
||
}
|
||
}, _callee9, this);
|
||
}));
|
||
return _foldLeft.apply(this, arguments);
|
||
}
|
||
function keys(arg) {
|
||
var result = createSequence();
|
||
if (Array.isArray(arg)) {
|
||
// merge the keys of all of the items in the array
|
||
var merge = {};
|
||
arg.forEach(function (item) {
|
||
var allkeys = keys(item);
|
||
allkeys.forEach(function (key) {
|
||
merge[key] = true;
|
||
});
|
||
});
|
||
result = keys(merge);
|
||
} else if (arg !== null && _typeof(arg) === 'object' && !isFunction(arg)) {
|
||
Object.keys(arg).forEach(function (key) {
|
||
return result.push(key);
|
||
});
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Return value from an object for a given key
|
||
* @param {Object} input - Object/Array
|
||
* @param {String} key - Key in object
|
||
* @returns {*} Value of key in object
|
||
*/
|
||
function lookup(input, key) {
|
||
// lookup the 'name' item in the input
|
||
var result;
|
||
if (Array.isArray(input)) {
|
||
result = createSequence();
|
||
for (var ii = 0; ii < input.length; ii++) {
|
||
var res = lookup(input[ii], key);
|
||
if (typeof res !== 'undefined') {
|
||
if (Array.isArray(res)) {
|
||
res.forEach(function (val) {
|
||
return result.push(val);
|
||
});
|
||
} else {
|
||
result.push(res);
|
||
}
|
||
}
|
||
}
|
||
} else if (input !== null && _typeof(input) === 'object' && !isFunction(input)) {
|
||
result = input[key];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Append second argument to first
|
||
* @param {Array|Object} arg1 - First argument
|
||
* @param {Array|Object} arg2 - Second argument
|
||
* @returns {*} Appended arguments
|
||
*/
|
||
function append(arg1, arg2) {
|
||
// disregard undefined args
|
||
if (typeof arg1 === 'undefined') {
|
||
return arg2;
|
||
}
|
||
if (typeof arg2 === 'undefined') {
|
||
return arg1;
|
||
}
|
||
// if either argument is not an array, make it so
|
||
if (!Array.isArray(arg1)) {
|
||
arg1 = createSequence(arg1);
|
||
}
|
||
if (!Array.isArray(arg2)) {
|
||
arg2 = [arg2];
|
||
}
|
||
return arg1.concat(arg2);
|
||
}
|
||
|
||
/**
|
||
* Determines if the argument is undefined
|
||
* @param {*} arg - argument
|
||
* @returns {boolean} False if argument undefined, otherwise true
|
||
*/
|
||
function exists(arg) {
|
||
if (typeof arg === 'undefined') {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Splits an object into an array of object with one property each
|
||
* @param {*} arg - the object to split
|
||
* @returns {*} - the array
|
||
*/
|
||
function spread(arg) {
|
||
var result = createSequence();
|
||
if (Array.isArray(arg)) {
|
||
// spread all of the items in the array
|
||
arg.forEach(function (item) {
|
||
result = append(result, spread(item));
|
||
});
|
||
} else if (arg !== null && _typeof(arg) === 'object' && !isLambda(arg)) {
|
||
for (var key in arg) {
|
||
var obj = {};
|
||
obj[key] = arg[key];
|
||
result.push(obj);
|
||
}
|
||
} else {
|
||
result = arg;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Merges an array of objects into a single object. Duplicate properties are
|
||
* overridden by entries later in the array
|
||
* @param {*} arg - the objects to merge
|
||
* @returns {*} - the object
|
||
*/
|
||
function merge(arg) {
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
var result = {};
|
||
arg.forEach(function (obj) {
|
||
for (var prop in obj) {
|
||
result[prop] = obj[prop];
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Reverses the order of items in an array
|
||
* @param {Array} arr - the array to reverse
|
||
* @returns {Array} - the reversed array
|
||
*/
|
||
function reverse(arr) {
|
||
// undefined inputs always return undefined
|
||
if (typeof arr === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (arr.length <= 1) {
|
||
return arr;
|
||
}
|
||
var length = arr.length;
|
||
var result = new Array(length);
|
||
for (var i = 0; i < length; i++) {
|
||
result[length - i - 1] = arr[i];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {*} obj - the input object to iterate over
|
||
* @param {*} func - the function to apply to each key/value pair
|
||
* @returns {Array} - the resultant array
|
||
*/
|
||
function each(_x24, _x25) {
|
||
return _each.apply(this, arguments);
|
||
}
|
||
/**
|
||
*
|
||
* @param {string} [message] - the message to attach to the error
|
||
* @throws custom error with code 'D3137'
|
||
*/
|
||
function _each() {
|
||
_each = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(obj, func) {
|
||
var result, key, func_args, val;
|
||
return _regeneratorRuntime().wrap(function _callee10$(_context10) {
|
||
while (1) switch (_context10.prev = _context10.next) {
|
||
case 0:
|
||
result = createSequence();
|
||
_context10.t0 = _regeneratorRuntime().keys(obj);
|
||
case 2:
|
||
if ((_context10.t1 = _context10.t0()).done) {
|
||
_context10.next = 11;
|
||
break;
|
||
}
|
||
key = _context10.t1.value;
|
||
func_args = hofFuncArgs(func, obj[key], key, obj); // invoke func
|
||
_context10.next = 7;
|
||
return func.apply(this, func_args);
|
||
case 7:
|
||
val = _context10.sent;
|
||
if (typeof val !== 'undefined') {
|
||
result.push(val);
|
||
}
|
||
_context10.next = 2;
|
||
break;
|
||
case 11:
|
||
return _context10.abrupt("return", result);
|
||
case 12:
|
||
case "end":
|
||
return _context10.stop();
|
||
}
|
||
}, _callee10, this);
|
||
}));
|
||
return _each.apply(this, arguments);
|
||
}
|
||
function error(message) {
|
||
throw {
|
||
code: "D3137",
|
||
stack: new Error().stack,
|
||
message: message || "$error() function evaluated"
|
||
};
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {boolean} condition - the condition to evaluate
|
||
* @param {string} [message] - the message to attach to the error
|
||
* @throws custom error with code 'D3137'
|
||
* @returns {undefined}
|
||
*/
|
||
function assert(condition, message) {
|
||
if (!condition) {
|
||
throw {
|
||
code: "D3141",
|
||
stack: new Error().stack,
|
||
message: message || "$assert() statement failed"
|
||
};
|
||
}
|
||
return undefined;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {*} [value] - the input to which the type will be checked
|
||
* @returns {string} - the type of the input
|
||
*/
|
||
function type(value) {
|
||
if (value === undefined) {
|
||
return undefined;
|
||
}
|
||
if (value === null) {
|
||
return 'null';
|
||
}
|
||
if (isNumeric(value)) {
|
||
return 'number';
|
||
}
|
||
if (typeof value === 'string') {
|
||
return 'string';
|
||
}
|
||
if (typeof value === 'boolean') {
|
||
return 'boolean';
|
||
}
|
||
if (Array.isArray(value)) {
|
||
return 'array';
|
||
}
|
||
if (isFunction(value)) {
|
||
return 'function';
|
||
}
|
||
return 'object';
|
||
}
|
||
|
||
/**
|
||
* Implements the merge sort (stable) with optional comparator function
|
||
*
|
||
* @param {Array} arr - the array to sort
|
||
* @param {*} comparator - comparator function
|
||
* @returns {Array} - sorted array
|
||
*/
|
||
function sort(_x26, _x27) {
|
||
return _sort.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Randomly shuffles the contents of an array
|
||
* @param {Array} arr - the input array
|
||
* @returns {Array} the shuffled array
|
||
*/
|
||
function _sort() {
|
||
_sort = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15(arr, comparator) {
|
||
var comp, merge, msort, result;
|
||
return _regeneratorRuntime().wrap(function _callee15$(_context15) {
|
||
while (1) switch (_context15.prev = _context15.next) {
|
||
case 0:
|
||
if (!(typeof arr === 'undefined')) {
|
||
_context15.next = 2;
|
||
break;
|
||
}
|
||
return _context15.abrupt("return", undefined);
|
||
case 2:
|
||
if (!(arr.length <= 1)) {
|
||
_context15.next = 4;
|
||
break;
|
||
}
|
||
return _context15.abrupt("return", arr);
|
||
case 4:
|
||
if (!(typeof comparator === 'undefined')) {
|
||
_context15.next = 10;
|
||
break;
|
||
}
|
||
if (!(!isArrayOfNumbers(arr) && !isArrayOfStrings(arr))) {
|
||
_context15.next = 7;
|
||
break;
|
||
}
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3070",
|
||
index: 1
|
||
};
|
||
case 7:
|
||
comp = /*#__PURE__*/function () {
|
||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11(a, b) {
|
||
return _regeneratorRuntime().wrap(function _callee11$(_context11) {
|
||
while (1) switch (_context11.prev = _context11.next) {
|
||
case 0:
|
||
return _context11.abrupt("return", a > b);
|
||
case 1:
|
||
case "end":
|
||
return _context11.stop();
|
||
}
|
||
}, _callee11);
|
||
}));
|
||
return function comp(_x30, _x31) {
|
||
return _ref.apply(this, arguments);
|
||
};
|
||
}();
|
||
_context15.next = 11;
|
||
break;
|
||
case 10:
|
||
// for internal usage of functionSort (i.e. order-by syntax)
|
||
comp = comparator;
|
||
case 11:
|
||
merge = /*#__PURE__*/function () {
|
||
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee13(l, r) {
|
||
var merge_iter, merged;
|
||
return _regeneratorRuntime().wrap(function _callee13$(_context13) {
|
||
while (1) switch (_context13.prev = _context13.next) {
|
||
case 0:
|
||
merge_iter = /*#__PURE__*/function () {
|
||
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee12(result, left, right) {
|
||
return _regeneratorRuntime().wrap(function _callee12$(_context12) {
|
||
while (1) switch (_context12.prev = _context12.next) {
|
||
case 0:
|
||
if (!(left.length === 0)) {
|
||
_context12.next = 4;
|
||
break;
|
||
}
|
||
Array.prototype.push.apply(result, right);
|
||
_context12.next = 19;
|
||
break;
|
||
case 4:
|
||
if (!(right.length === 0)) {
|
||
_context12.next = 8;
|
||
break;
|
||
}
|
||
Array.prototype.push.apply(result, left);
|
||
_context12.next = 19;
|
||
break;
|
||
case 8:
|
||
_context12.next = 10;
|
||
return comp(left[0], right[0]);
|
||
case 10:
|
||
if (!_context12.sent) {
|
||
_context12.next = 16;
|
||
break;
|
||
}
|
||
// invoke the comparator function
|
||
// if it returns true - swap left and right
|
||
result.push(right[0]);
|
||
_context12.next = 14;
|
||
return merge_iter(result, left, right.slice(1));
|
||
case 14:
|
||
_context12.next = 19;
|
||
break;
|
||
case 16:
|
||
// otherwise keep the same order
|
||
result.push(left[0]);
|
||
_context12.next = 19;
|
||
return merge_iter(result, left.slice(1), right);
|
||
case 19:
|
||
case "end":
|
||
return _context12.stop();
|
||
}
|
||
}, _callee12);
|
||
}));
|
||
return function merge_iter(_x34, _x35, _x36) {
|
||
return _ref3.apply(this, arguments);
|
||
};
|
||
}();
|
||
merged = [];
|
||
_context13.next = 4;
|
||
return merge_iter(merged, l, r);
|
||
case 4:
|
||
return _context13.abrupt("return", merged);
|
||
case 5:
|
||
case "end":
|
||
return _context13.stop();
|
||
}
|
||
}, _callee13);
|
||
}));
|
||
return function merge(_x32, _x33) {
|
||
return _ref2.apply(this, arguments);
|
||
};
|
||
}();
|
||
msort = /*#__PURE__*/function () {
|
||
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee14(array) {
|
||
var middle, left, right;
|
||
return _regeneratorRuntime().wrap(function _callee14$(_context14) {
|
||
while (1) switch (_context14.prev = _context14.next) {
|
||
case 0:
|
||
if (!(!Array.isArray(array) || array.length <= 1)) {
|
||
_context14.next = 4;
|
||
break;
|
||
}
|
||
return _context14.abrupt("return", array);
|
||
case 4:
|
||
middle = Math.floor(array.length / 2);
|
||
left = array.slice(0, middle);
|
||
right = array.slice(middle);
|
||
_context14.next = 9;
|
||
return msort(left);
|
||
case 9:
|
||
left = _context14.sent;
|
||
_context14.next = 12;
|
||
return msort(right);
|
||
case 12:
|
||
right = _context14.sent;
|
||
_context14.next = 15;
|
||
return merge(left, right);
|
||
case 15:
|
||
return _context14.abrupt("return", _context14.sent);
|
||
case 16:
|
||
case "end":
|
||
return _context14.stop();
|
||
}
|
||
}, _callee14);
|
||
}));
|
||
return function msort(_x37) {
|
||
return _ref4.apply(this, arguments);
|
||
};
|
||
}();
|
||
_context15.next = 15;
|
||
return msort(arr);
|
||
case 15:
|
||
result = _context15.sent;
|
||
return _context15.abrupt("return", result);
|
||
case 17:
|
||
case "end":
|
||
return _context15.stop();
|
||
}
|
||
}, _callee15);
|
||
}));
|
||
return _sort.apply(this, arguments);
|
||
}
|
||
function shuffle(arr) {
|
||
// undefined inputs always return undefined
|
||
if (typeof arr === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (arr.length <= 1) {
|
||
return arr;
|
||
}
|
||
|
||
// shuffle using the 'inside-out' variant of the Fisher-Yates algorithm
|
||
var result = new Array(arr.length);
|
||
for (var i = 0; i < arr.length; i++) {
|
||
var j = Math.floor(Math.random() * (i + 1)); // random integer such that 0 ≤ j ≤ i
|
||
if (i !== j) {
|
||
result[i] = result[j];
|
||
}
|
||
result[j] = arr[i];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Returns the values that appear in a sequence, with duplicates eliminated.
|
||
* @param {Array} arr - An array or sequence of values
|
||
* @returns {Array} - sequence of distinct values
|
||
*/
|
||
function distinct(arr) {
|
||
// undefined inputs always return undefined
|
||
if (typeof arr === 'undefined') {
|
||
return undefined;
|
||
}
|
||
if (!Array.isArray(arr) || arr.length <= 1) {
|
||
return arr;
|
||
}
|
||
var results = isSequence(arr) ? createSequence() : [];
|
||
for (var ii = 0; ii < arr.length; ii++) {
|
||
var value = arr[ii];
|
||
// is this value already in the result sequence?
|
||
var includes = false;
|
||
for (var jj = 0; jj < results.length; jj++) {
|
||
if (deepEquals(value, results[jj])) {
|
||
includes = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!includes) {
|
||
results.push(value);
|
||
}
|
||
}
|
||
return results;
|
||
}
|
||
|
||
/**
|
||
* Applies a predicate function to each key/value pair in an object, and returns an object containing
|
||
* only the key/value pairs that passed the predicate
|
||
*
|
||
* @param {object} arg - the object to be sifted
|
||
* @param {object} func - the predicate function (lambda or native)
|
||
* @returns {object} - sifted object
|
||
*/
|
||
function sift(_x28, _x29) {
|
||
return _sift.apply(this, arguments);
|
||
}
|
||
function _sift() {
|
||
_sift = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee16(arg, func) {
|
||
var result, item, entry, func_args, res;
|
||
return _regeneratorRuntime().wrap(function _callee16$(_context16) {
|
||
while (1) switch (_context16.prev = _context16.next) {
|
||
case 0:
|
||
result = {};
|
||
_context16.t0 = _regeneratorRuntime().keys(arg);
|
||
case 2:
|
||
if ((_context16.t1 = _context16.t0()).done) {
|
||
_context16.next = 12;
|
||
break;
|
||
}
|
||
item = _context16.t1.value;
|
||
entry = arg[item];
|
||
func_args = hofFuncArgs(func, entry, item, arg); // invoke func
|
||
_context16.next = 8;
|
||
return func.apply(this, func_args);
|
||
case 8:
|
||
res = _context16.sent;
|
||
if (_boolean(res)) {
|
||
result[item] = entry;
|
||
}
|
||
_context16.next = 2;
|
||
break;
|
||
case 12:
|
||
// empty objects should be changed to undefined
|
||
if (Object.keys(result).length === 0) {
|
||
result = undefined;
|
||
}
|
||
return _context16.abrupt("return", result);
|
||
case 14:
|
||
case "end":
|
||
return _context16.stop();
|
||
}
|
||
}, _callee16, this);
|
||
}));
|
||
return _sift.apply(this, arguments);
|
||
}
|
||
return {
|
||
sum: sum,
|
||
count: count,
|
||
max: max,
|
||
min: min,
|
||
average: average,
|
||
string: string,
|
||
substring: substring,
|
||
substringBefore: substringBefore,
|
||
substringAfter: substringAfter,
|
||
lowercase: lowercase,
|
||
uppercase: uppercase,
|
||
length: length,
|
||
trim: trim,
|
||
pad: pad,
|
||
match: match,
|
||
contains: contains,
|
||
replace: replace,
|
||
split: split,
|
||
join: join,
|
||
formatNumber: formatNumber,
|
||
formatBase: formatBase,
|
||
number: number,
|
||
floor: floor,
|
||
ceil: ceil,
|
||
round: round,
|
||
abs: abs,
|
||
sqrt: sqrt,
|
||
power: power,
|
||
random: random,
|
||
"boolean": _boolean,
|
||
not: not,
|
||
map: map,
|
||
zip: zip,
|
||
filter: filter,
|
||
single: single,
|
||
foldLeft: foldLeft,
|
||
sift: sift,
|
||
keys: keys,
|
||
lookup: lookup,
|
||
append: append,
|
||
exists: exists,
|
||
spread: spread,
|
||
merge: merge,
|
||
reverse: reverse,
|
||
each: each,
|
||
error: error,
|
||
assert: assert,
|
||
type: type,
|
||
sort: sort,
|
||
shuffle: shuffle,
|
||
distinct: distinct,
|
||
base64encode: base64encode,
|
||
base64decode: base64decode,
|
||
encodeUrlComponent: encodeUrlComponent,
|
||
encodeUrl: encodeUrl,
|
||
decodeUrlComponent: decodeUrlComponent,
|
||
decodeUrl: decodeUrl
|
||
};
|
||
}();
|
||
module.exports = functions;
|
||
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
},{"./utils":6}],3:[function(require,module,exports){
|
||
"use strict";
|
||
|
||
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
||
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||
function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
|
||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
||
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
||
/**
|
||
* © Copyright IBM Corp. 2016, 2017 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
/**
|
||
* @module JSONata
|
||
* @description JSON query and transformation language
|
||
*/
|
||
|
||
var datetime = require('./datetime');
|
||
var fn = require('./functions');
|
||
var utils = require('./utils');
|
||
var parser = require('./parser');
|
||
var parseSignature = require('./signature');
|
||
|
||
/**
|
||
* jsonata
|
||
* @function
|
||
* @param {Object} expr - JSONata expression
|
||
* @returns {{evaluate: evaluate, assign: assign}} Evaluated expression
|
||
*/
|
||
var jsonata = function () {
|
||
'use strict';
|
||
|
||
var isNumeric = utils.isNumeric;
|
||
var isArrayOfStrings = utils.isArrayOfStrings;
|
||
var isArrayOfNumbers = utils.isArrayOfNumbers;
|
||
var createSequence = utils.createSequence;
|
||
var isSequence = utils.isSequence;
|
||
var isFunction = utils.isFunction;
|
||
var isLambda = utils.isLambda;
|
||
var isIterable = utils.isIterable;
|
||
var isPromise = utils.isPromise;
|
||
var getFunctionArity = utils.getFunctionArity;
|
||
var isDeepEqual = utils.isDeepEqual;
|
||
|
||
// Start of Evaluator code
|
||
|
||
var staticFrame = createFrame(null);
|
||
|
||
/**
|
||
* Evaluate expression against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluate2(_x, _x2, _x3) {
|
||
return _evaluate.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate path expression against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluate() {
|
||
_evaluate = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(expr, input, environment) {
|
||
var result, entryCallback, ii, exitCallback;
|
||
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
||
while (1) switch (_context4.prev = _context4.next) {
|
||
case 0:
|
||
entryCallback = environment.lookup('__evaluate_entry');
|
||
if (!entryCallback) {
|
||
_context4.next = 4;
|
||
break;
|
||
}
|
||
_context4.next = 4;
|
||
return entryCallback(expr, input, environment);
|
||
case 4:
|
||
_context4.t0 = expr.type;
|
||
_context4.next = _context4.t0 === 'path' ? 7 : _context4.t0 === 'binary' ? 11 : _context4.t0 === 'unary' ? 15 : _context4.t0 === 'name' ? 19 : _context4.t0 === 'string' ? 21 : _context4.t0 === 'number' ? 21 : _context4.t0 === 'value' ? 21 : _context4.t0 === 'wildcard' ? 23 : _context4.t0 === 'descendant' ? 25 : _context4.t0 === 'parent' ? 27 : _context4.t0 === 'condition' ? 29 : _context4.t0 === 'block' ? 33 : _context4.t0 === 'bind' ? 37 : _context4.t0 === 'regex' ? 41 : _context4.t0 === 'function' ? 43 : _context4.t0 === 'variable' ? 47 : _context4.t0 === 'lambda' ? 49 : _context4.t0 === 'partial' ? 51 : _context4.t0 === 'apply' ? 55 : _context4.t0 === 'transform' ? 59 : 61;
|
||
break;
|
||
case 7:
|
||
_context4.next = 9;
|
||
return evaluatePath(expr, input, environment);
|
||
case 9:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 11:
|
||
_context4.next = 13;
|
||
return evaluateBinary(expr, input, environment);
|
||
case 13:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 15:
|
||
_context4.next = 17;
|
||
return evaluateUnary(expr, input, environment);
|
||
case 17:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 19:
|
||
result = evaluateName(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 21:
|
||
result = evaluateLiteral(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 23:
|
||
result = evaluateWildcard(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 25:
|
||
result = evaluateDescendants(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 27:
|
||
result = environment.lookup(expr.slot.label);
|
||
return _context4.abrupt("break", 61);
|
||
case 29:
|
||
_context4.next = 31;
|
||
return evaluateCondition(expr, input, environment);
|
||
case 31:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 33:
|
||
_context4.next = 35;
|
||
return evaluateBlock(expr, input, environment);
|
||
case 35:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 37:
|
||
_context4.next = 39;
|
||
return evaluateBindExpression(expr, input, environment);
|
||
case 39:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 41:
|
||
result = evaluateRegex(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 43:
|
||
_context4.next = 45;
|
||
return evaluateFunction(expr, input, environment);
|
||
case 45:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 47:
|
||
result = evaluateVariable(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 49:
|
||
result = evaluateLambda(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 51:
|
||
_context4.next = 53;
|
||
return evaluatePartialApplication(expr, input, environment);
|
||
case 53:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 55:
|
||
_context4.next = 57;
|
||
return evaluateApplyExpression(expr, input, environment);
|
||
case 57:
|
||
result = _context4.sent;
|
||
return _context4.abrupt("break", 61);
|
||
case 59:
|
||
result = evaluateTransformExpression(expr, input, environment);
|
||
return _context4.abrupt("break", 61);
|
||
case 61:
|
||
if (!Object.prototype.hasOwnProperty.call(expr, 'predicate')) {
|
||
_context4.next = 70;
|
||
break;
|
||
}
|
||
ii = 0;
|
||
case 63:
|
||
if (!(ii < expr.predicate.length)) {
|
||
_context4.next = 70;
|
||
break;
|
||
}
|
||
_context4.next = 66;
|
||
return evaluateFilter(expr.predicate[ii].expr, result, environment);
|
||
case 66:
|
||
result = _context4.sent;
|
||
case 67:
|
||
ii++;
|
||
_context4.next = 63;
|
||
break;
|
||
case 70:
|
||
if (!(expr.type !== 'path' && Object.prototype.hasOwnProperty.call(expr, 'group'))) {
|
||
_context4.next = 74;
|
||
break;
|
||
}
|
||
_context4.next = 73;
|
||
return evaluateGroupExpression(expr.group, result, environment);
|
||
case 73:
|
||
result = _context4.sent;
|
||
case 74:
|
||
exitCallback = environment.lookup('__evaluate_exit');
|
||
if (!exitCallback) {
|
||
_context4.next = 78;
|
||
break;
|
||
}
|
||
_context4.next = 78;
|
||
return exitCallback(expr, input, environment, result);
|
||
case 78:
|
||
if (result && isSequence(result) && !result.tupleStream) {
|
||
if (expr.keepArray) {
|
||
result.keepSingleton = true;
|
||
}
|
||
if (result.length === 0) {
|
||
result = undefined;
|
||
} else if (result.length === 1) {
|
||
result = result.keepSingleton ? result : result[0];
|
||
}
|
||
}
|
||
return _context4.abrupt("return", result);
|
||
case 80:
|
||
case "end":
|
||
return _context4.stop();
|
||
}
|
||
}, _callee4);
|
||
}));
|
||
return _evaluate.apply(this, arguments);
|
||
}
|
||
function evaluatePath(_x4, _x5, _x6) {
|
||
return _evaluatePath.apply(this, arguments);
|
||
}
|
||
function _evaluatePath() {
|
||
_evaluatePath = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(expr, input, environment) {
|
||
var inputSequence, resultSequence, isTupleStream, tupleBindings, ii, step;
|
||
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
|
||
while (1) switch (_context5.prev = _context5.next) {
|
||
case 0:
|
||
// expr is an array of steps
|
||
// if the first step is a variable reference ($...), including root reference ($$),
|
||
// then the path is absolute rather than relative
|
||
if (Array.isArray(input) && expr.steps[0].type !== 'variable') {
|
||
inputSequence = input;
|
||
} else {
|
||
// if input is not an array, make it so
|
||
inputSequence = createSequence(input);
|
||
}
|
||
isTupleStream = false;
|
||
tupleBindings = undefined; // evaluate each step in turn
|
||
ii = 0;
|
||
case 4:
|
||
if (!(ii < expr.steps.length)) {
|
||
_context5.next = 28;
|
||
break;
|
||
}
|
||
step = expr.steps[ii];
|
||
if (step.tuple) {
|
||
isTupleStream = true;
|
||
}
|
||
|
||
// if the first step is an explicit array constructor, then just evaluate that (i.e. don't iterate over a context array)
|
||
if (!(ii === 0 && step.consarray)) {
|
||
_context5.next = 13;
|
||
break;
|
||
}
|
||
_context5.next = 10;
|
||
return _evaluate2(step, inputSequence, environment);
|
||
case 10:
|
||
resultSequence = _context5.sent;
|
||
_context5.next = 22;
|
||
break;
|
||
case 13:
|
||
if (!isTupleStream) {
|
||
_context5.next = 19;
|
||
break;
|
||
}
|
||
_context5.next = 16;
|
||
return evaluateTupleStep(step, inputSequence, tupleBindings, environment);
|
||
case 16:
|
||
tupleBindings = _context5.sent;
|
||
_context5.next = 22;
|
||
break;
|
||
case 19:
|
||
_context5.next = 21;
|
||
return evaluateStep(step, inputSequence, environment, ii === expr.steps.length - 1);
|
||
case 21:
|
||
resultSequence = _context5.sent;
|
||
case 22:
|
||
if (!(!isTupleStream && (typeof resultSequence === 'undefined' || resultSequence.length === 0))) {
|
||
_context5.next = 24;
|
||
break;
|
||
}
|
||
return _context5.abrupt("break", 28);
|
||
case 24:
|
||
if (typeof step.focus === 'undefined') {
|
||
inputSequence = resultSequence;
|
||
}
|
||
case 25:
|
||
ii++;
|
||
_context5.next = 4;
|
||
break;
|
||
case 28:
|
||
if (isTupleStream) {
|
||
if (expr.tuple) {
|
||
// tuple stream is carrying ancestry information - keep this
|
||
resultSequence = tupleBindings;
|
||
} else {
|
||
resultSequence = createSequence();
|
||
for (ii = 0; ii < tupleBindings.length; ii++) {
|
||
resultSequence.push(tupleBindings[ii]['@']);
|
||
}
|
||
}
|
||
}
|
||
if (expr.keepSingletonArray) {
|
||
// if the array is explicitly constructed in the expression and marked to promote singleton sequences to array
|
||
if (Array.isArray(resultSequence) && resultSequence.cons && !resultSequence.sequence) {
|
||
resultSequence = createSequence(resultSequence);
|
||
}
|
||
resultSequence.keepSingleton = true;
|
||
}
|
||
if (!expr.hasOwnProperty('group')) {
|
||
_context5.next = 34;
|
||
break;
|
||
}
|
||
_context5.next = 33;
|
||
return evaluateGroupExpression(expr.group, isTupleStream ? tupleBindings : resultSequence, environment);
|
||
case 33:
|
||
resultSequence = _context5.sent;
|
||
case 34:
|
||
return _context5.abrupt("return", resultSequence);
|
||
case 35:
|
||
case "end":
|
||
return _context5.stop();
|
||
}
|
||
}, _callee5);
|
||
}));
|
||
return _evaluatePath.apply(this, arguments);
|
||
}
|
||
function createFrameFromTuple(environment, tuple) {
|
||
var frame = createFrame(environment);
|
||
for (var prop in tuple) {
|
||
frame.bind(prop, tuple[prop]);
|
||
}
|
||
return frame;
|
||
}
|
||
|
||
/**
|
||
* Evaluate a step within a path
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @param {boolean} lastStep - flag the last step in a path
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateStep(_x7, _x8, _x9, _x10) {
|
||
return _evaluateStep.apply(this, arguments);
|
||
}
|
||
function _evaluateStep() {
|
||
_evaluateStep = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(expr, input, environment, lastStep) {
|
||
var result, ii, res, ss, resultSequence;
|
||
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
|
||
while (1) switch (_context6.prev = _context6.next) {
|
||
case 0:
|
||
if (!(expr.type === 'sort')) {
|
||
_context6.next = 9;
|
||
break;
|
||
}
|
||
_context6.next = 3;
|
||
return evaluateSortExpression(expr, input, environment);
|
||
case 3:
|
||
result = _context6.sent;
|
||
if (!expr.stages) {
|
||
_context6.next = 8;
|
||
break;
|
||
}
|
||
_context6.next = 7;
|
||
return evaluateStages(expr.stages, result, environment);
|
||
case 7:
|
||
result = _context6.sent;
|
||
case 8:
|
||
return _context6.abrupt("return", result);
|
||
case 9:
|
||
result = createSequence();
|
||
ii = 0;
|
||
case 11:
|
||
if (!(ii < input.length)) {
|
||
_context6.next = 28;
|
||
break;
|
||
}
|
||
_context6.next = 14;
|
||
return _evaluate2(expr, input[ii], environment);
|
||
case 14:
|
||
res = _context6.sent;
|
||
if (!expr.stages) {
|
||
_context6.next = 24;
|
||
break;
|
||
}
|
||
ss = 0;
|
||
case 17:
|
||
if (!(ss < expr.stages.length)) {
|
||
_context6.next = 24;
|
||
break;
|
||
}
|
||
_context6.next = 20;
|
||
return evaluateFilter(expr.stages[ss].expr, res, environment);
|
||
case 20:
|
||
res = _context6.sent;
|
||
case 21:
|
||
ss++;
|
||
_context6.next = 17;
|
||
break;
|
||
case 24:
|
||
if (typeof res !== 'undefined') {
|
||
result.push(res);
|
||
}
|
||
case 25:
|
||
ii++;
|
||
_context6.next = 11;
|
||
break;
|
||
case 28:
|
||
resultSequence = createSequence();
|
||
if (lastStep && result.length === 1 && Array.isArray(result[0]) && !isSequence(result[0])) {
|
||
resultSequence = result[0];
|
||
} else {
|
||
// flatten the sequence
|
||
result.forEach(function (res) {
|
||
if (!Array.isArray(res) || res.cons) {
|
||
// it's not an array - just push into the result sequence
|
||
resultSequence.push(res);
|
||
} else {
|
||
// res is a sequence - flatten it into the parent sequence
|
||
res.forEach(function (val) {
|
||
return resultSequence.push(val);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
return _context6.abrupt("return", resultSequence);
|
||
case 31:
|
||
case "end":
|
||
return _context6.stop();
|
||
}
|
||
}, _callee6);
|
||
}));
|
||
return _evaluateStep.apply(this, arguments);
|
||
}
|
||
function evaluateStages(_x11, _x12, _x13) {
|
||
return _evaluateStages.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate a step within a path
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} tupleBindings - The tuple stream
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateStages() {
|
||
_evaluateStages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(stages, input, environment) {
|
||
var result, ss, stage, ee, tuple;
|
||
return _regeneratorRuntime().wrap(function _callee7$(_context7) {
|
||
while (1) switch (_context7.prev = _context7.next) {
|
||
case 0:
|
||
result = input;
|
||
ss = 0;
|
||
case 2:
|
||
if (!(ss < stages.length)) {
|
||
_context7.next = 16;
|
||
break;
|
||
}
|
||
stage = stages[ss];
|
||
_context7.t0 = stage.type;
|
||
_context7.next = _context7.t0 === 'filter' ? 7 : _context7.t0 === 'index' ? 11 : 13;
|
||
break;
|
||
case 7:
|
||
_context7.next = 9;
|
||
return evaluateFilter(stage.expr, result, environment);
|
||
case 9:
|
||
result = _context7.sent;
|
||
return _context7.abrupt("break", 13);
|
||
case 11:
|
||
for (ee = 0; ee < result.length; ee++) {
|
||
tuple = result[ee];
|
||
tuple[stage.value] = ee;
|
||
}
|
||
return _context7.abrupt("break", 13);
|
||
case 13:
|
||
ss++;
|
||
_context7.next = 2;
|
||
break;
|
||
case 16:
|
||
return _context7.abrupt("return", result);
|
||
case 17:
|
||
case "end":
|
||
return _context7.stop();
|
||
}
|
||
}, _callee7);
|
||
}));
|
||
return _evaluateStages.apply(this, arguments);
|
||
}
|
||
function evaluateTupleStep(_x14, _x15, _x16, _x17) {
|
||
return _evaluateTupleStep.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Apply filter predicate to input data
|
||
* @param {Object} predicate - filter expression
|
||
* @param {Object} input - Input data to apply predicates against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Result after applying predicates
|
||
*/
|
||
function _evaluateTupleStep() {
|
||
_evaluateTupleStep = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(expr, input, tupleBindings, environment) {
|
||
var result, sorted, ss, tuple, stepEnv, ee, res, bb;
|
||
return _regeneratorRuntime().wrap(function _callee8$(_context8) {
|
||
while (1) switch (_context8.prev = _context8.next) {
|
||
case 0:
|
||
if (!(expr.type === 'sort')) {
|
||
_context8.next = 18;
|
||
break;
|
||
}
|
||
if (!tupleBindings) {
|
||
_context8.next = 7;
|
||
break;
|
||
}
|
||
_context8.next = 4;
|
||
return evaluateSortExpression(expr, tupleBindings, environment);
|
||
case 4:
|
||
result = _context8.sent;
|
||
_context8.next = 13;
|
||
break;
|
||
case 7:
|
||
_context8.next = 9;
|
||
return evaluateSortExpression(expr, input, environment);
|
||
case 9:
|
||
sorted = _context8.sent;
|
||
result = createSequence();
|
||
result.tupleStream = true;
|
||
for (ss = 0; ss < sorted.length; ss++) {
|
||
tuple = {
|
||
'@': sorted[ss]
|
||
};
|
||
tuple[expr.index] = ss;
|
||
result.push(tuple);
|
||
}
|
||
case 13:
|
||
if (!expr.stages) {
|
||
_context8.next = 17;
|
||
break;
|
||
}
|
||
_context8.next = 16;
|
||
return evaluateStages(expr.stages, result, environment);
|
||
case 16:
|
||
result = _context8.sent;
|
||
case 17:
|
||
return _context8.abrupt("return", result);
|
||
case 18:
|
||
result = createSequence();
|
||
result.tupleStream = true;
|
||
stepEnv = environment;
|
||
if (tupleBindings === undefined) {
|
||
tupleBindings = input.map(function (item) {
|
||
return {
|
||
'@': item
|
||
};
|
||
});
|
||
}
|
||
ee = 0;
|
||
case 23:
|
||
if (!(ee < tupleBindings.length)) {
|
||
_context8.next = 32;
|
||
break;
|
||
}
|
||
stepEnv = createFrameFromTuple(environment, tupleBindings[ee]);
|
||
_context8.next = 27;
|
||
return _evaluate2(expr, tupleBindings[ee]['@'], stepEnv);
|
||
case 27:
|
||
res = _context8.sent;
|
||
// res is the binding sequence for the output tuple stream
|
||
if (typeof res !== 'undefined') {
|
||
if (!Array.isArray(res)) {
|
||
res = [res];
|
||
}
|
||
for (bb = 0; bb < res.length; bb++) {
|
||
tuple = {};
|
||
Object.assign(tuple, tupleBindings[ee]);
|
||
if (res.tupleStream) {
|
||
Object.assign(tuple, res[bb]);
|
||
} else {
|
||
if (expr.focus) {
|
||
tuple[expr.focus] = res[bb];
|
||
tuple['@'] = tupleBindings[ee]['@'];
|
||
} else {
|
||
tuple['@'] = res[bb];
|
||
}
|
||
if (expr.index) {
|
||
tuple[expr.index] = bb;
|
||
}
|
||
if (expr.ancestor) {
|
||
tuple[expr.ancestor.label] = tupleBindings[ee]['@'];
|
||
}
|
||
}
|
||
result.push(tuple);
|
||
}
|
||
}
|
||
case 29:
|
||
ee++;
|
||
_context8.next = 23;
|
||
break;
|
||
case 32:
|
||
if (!expr.stages) {
|
||
_context8.next = 36;
|
||
break;
|
||
}
|
||
_context8.next = 35;
|
||
return evaluateStages(expr.stages, result, environment);
|
||
case 35:
|
||
result = _context8.sent;
|
||
case 36:
|
||
return _context8.abrupt("return", result);
|
||
case 37:
|
||
case "end":
|
||
return _context8.stop();
|
||
}
|
||
}, _callee8);
|
||
}));
|
||
return _evaluateTupleStep.apply(this, arguments);
|
||
}
|
||
function evaluateFilter(_x18, _x19, _x20) {
|
||
return _evaluateFilter.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate binary expression against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateFilter() {
|
||
_evaluateFilter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(predicate, input, environment) {
|
||
var results, index, item, context, env, res;
|
||
return _regeneratorRuntime().wrap(function _callee9$(_context9) {
|
||
while (1) switch (_context9.prev = _context9.next) {
|
||
case 0:
|
||
results = createSequence();
|
||
if (input && input.tupleStream) {
|
||
results.tupleStream = true;
|
||
}
|
||
if (!Array.isArray(input)) {
|
||
input = createSequence(input);
|
||
}
|
||
if (!(predicate.type === 'number')) {
|
||
_context9.next = 10;
|
||
break;
|
||
}
|
||
index = Math.floor(predicate.value); // round it down
|
||
if (index < 0) {
|
||
// count in from end of array
|
||
index = input.length + index;
|
||
}
|
||
item = input[index];
|
||
if (typeof item !== 'undefined') {
|
||
if (Array.isArray(item)) {
|
||
results = item;
|
||
} else {
|
||
results.push(item);
|
||
}
|
||
}
|
||
_context9.next = 24;
|
||
break;
|
||
case 10:
|
||
index = 0;
|
||
case 11:
|
||
if (!(index < input.length)) {
|
||
_context9.next = 24;
|
||
break;
|
||
}
|
||
item = input[index];
|
||
context = item;
|
||
env = environment;
|
||
if (input.tupleStream) {
|
||
context = item['@'];
|
||
env = createFrameFromTuple(environment, item);
|
||
}
|
||
_context9.next = 18;
|
||
return _evaluate2(predicate, context, env);
|
||
case 18:
|
||
res = _context9.sent;
|
||
if (isNumeric(res)) {
|
||
res = [res];
|
||
}
|
||
if (isArrayOfNumbers(res)) {
|
||
res.forEach(function (ires) {
|
||
// round it down
|
||
var ii = Math.floor(ires);
|
||
if (ii < 0) {
|
||
// count in from end of array
|
||
ii = input.length + ii;
|
||
}
|
||
if (ii === index) {
|
||
results.push(item);
|
||
}
|
||
});
|
||
} else if (fn["boolean"](res)) {
|
||
// truthy
|
||
results.push(item);
|
||
}
|
||
case 21:
|
||
index++;
|
||
_context9.next = 11;
|
||
break;
|
||
case 24:
|
||
return _context9.abrupt("return", results);
|
||
case 25:
|
||
case "end":
|
||
return _context9.stop();
|
||
}
|
||
}, _callee9);
|
||
}));
|
||
return _evaluateFilter.apply(this, arguments);
|
||
}
|
||
function evaluateBinary(_x21, _x22, _x23) {
|
||
return _evaluateBinary.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate unary expression against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateBinary() {
|
||
_evaluateBinary = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11(expr, input, environment) {
|
||
var result, lhs, op, evalrhs, rhs;
|
||
return _regeneratorRuntime().wrap(function _callee11$(_context11) {
|
||
while (1) switch (_context11.prev = _context11.next) {
|
||
case 0:
|
||
_context11.next = 2;
|
||
return _evaluate2(expr.lhs, input, environment);
|
||
case 2:
|
||
lhs = _context11.sent;
|
||
op = expr.value; //defer evaluation of RHS to allow short-circuiting
|
||
evalrhs = /*#__PURE__*/function () {
|
||
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10() {
|
||
return _regeneratorRuntime().wrap(function _callee10$(_context10) {
|
||
while (1) switch (_context10.prev = _context10.next) {
|
||
case 0:
|
||
_context10.next = 2;
|
||
return _evaluate2(expr.rhs, input, environment);
|
||
case 2:
|
||
return _context10.abrupt("return", _context10.sent);
|
||
case 3:
|
||
case "end":
|
||
return _context10.stop();
|
||
}
|
||
}, _callee10);
|
||
}));
|
||
return function evalrhs() {
|
||
return _ref3.apply(this, arguments);
|
||
};
|
||
}();
|
||
if (!(op === "and" || op === "or")) {
|
||
_context11.next = 17;
|
||
break;
|
||
}
|
||
_context11.prev = 6;
|
||
_context11.next = 9;
|
||
return evaluateBooleanExpression(lhs, evalrhs, op);
|
||
case 9:
|
||
return _context11.abrupt("return", _context11.sent);
|
||
case 12:
|
||
_context11.prev = 12;
|
||
_context11.t0 = _context11["catch"](6);
|
||
_context11.t0.position = expr.position;
|
||
_context11.t0.token = op;
|
||
throw _context11.t0;
|
||
case 17:
|
||
_context11.next = 19;
|
||
return evalrhs();
|
||
case 19:
|
||
rhs = _context11.sent;
|
||
_context11.prev = 20;
|
||
_context11.t1 = op;
|
||
_context11.next = _context11.t1 === '+' ? 24 : _context11.t1 === '-' ? 24 : _context11.t1 === '*' ? 24 : _context11.t1 === '/' ? 24 : _context11.t1 === '%' ? 24 : _context11.t1 === '=' ? 26 : _context11.t1 === '!=' ? 26 : _context11.t1 === '<' ? 28 : _context11.t1 === '<=' ? 28 : _context11.t1 === '>' ? 28 : _context11.t1 === '>=' ? 28 : _context11.t1 === '&' ? 30 : _context11.t1 === '..' ? 32 : _context11.t1 === 'in' ? 34 : 36;
|
||
break;
|
||
case 24:
|
||
result = evaluateNumericExpression(lhs, rhs, op);
|
||
return _context11.abrupt("break", 36);
|
||
case 26:
|
||
result = evaluateEqualityExpression(lhs, rhs, op);
|
||
return _context11.abrupt("break", 36);
|
||
case 28:
|
||
result = evaluateComparisonExpression(lhs, rhs, op);
|
||
return _context11.abrupt("break", 36);
|
||
case 30:
|
||
result = evaluateStringConcat(lhs, rhs);
|
||
return _context11.abrupt("break", 36);
|
||
case 32:
|
||
result = evaluateRangeExpression(lhs, rhs);
|
||
return _context11.abrupt("break", 36);
|
||
case 34:
|
||
result = evaluateIncludesExpression(lhs, rhs);
|
||
return _context11.abrupt("break", 36);
|
||
case 36:
|
||
_context11.next = 43;
|
||
break;
|
||
case 38:
|
||
_context11.prev = 38;
|
||
_context11.t2 = _context11["catch"](20);
|
||
_context11.t2.position = expr.position;
|
||
_context11.t2.token = op;
|
||
throw _context11.t2;
|
||
case 43:
|
||
return _context11.abrupt("return", result);
|
||
case 44:
|
||
case "end":
|
||
return _context11.stop();
|
||
}
|
||
}, _callee11, null, [[6, 12], [20, 38]]);
|
||
}));
|
||
return _evaluateBinary.apply(this, arguments);
|
||
}
|
||
function evaluateUnary(_x24, _x25, _x26) {
|
||
return _evaluateUnary.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate name object against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateUnary() {
|
||
_evaluateUnary = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee13(expr, input, environment) {
|
||
var result, generators, _iterator, _step, generator, _generator, item, value;
|
||
return _regeneratorRuntime().wrap(function _callee13$(_context13) {
|
||
while (1) switch (_context13.prev = _context13.next) {
|
||
case 0:
|
||
_context13.t0 = expr.value;
|
||
_context13.next = _context13.t0 === '-' ? 3 : _context13.t0 === '[' ? 16 : _context13.t0 === '{' ? 24 : 28;
|
||
break;
|
||
case 3:
|
||
_context13.next = 5;
|
||
return _evaluate2(expr.expression, input, environment);
|
||
case 5:
|
||
result = _context13.sent;
|
||
if (!(typeof result === 'undefined')) {
|
||
_context13.next = 10;
|
||
break;
|
||
}
|
||
result = undefined;
|
||
_context13.next = 15;
|
||
break;
|
||
case 10:
|
||
if (!isNumeric(result)) {
|
||
_context13.next = 14;
|
||
break;
|
||
}
|
||
result = -result;
|
||
_context13.next = 15;
|
||
break;
|
||
case 14:
|
||
throw {
|
||
code: "D1002",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
token: expr.value,
|
||
value: result
|
||
};
|
||
case 15:
|
||
return _context13.abrupt("break", 28);
|
||
case 16:
|
||
// array constructor - evaluate each item
|
||
result = [];
|
||
_context13.next = 19;
|
||
return Promise.all(expr.expressions.map( /*#__PURE__*/function () {
|
||
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee12(item, idx) {
|
||
return _regeneratorRuntime().wrap(function _callee12$(_context12) {
|
||
while (1) switch (_context12.prev = _context12.next) {
|
||
case 0:
|
||
environment.isParallelCall = idx > 0;
|
||
_context12.t0 = item;
|
||
_context12.next = 4;
|
||
return _evaluate2(item, input, environment);
|
||
case 4:
|
||
_context12.t1 = _context12.sent;
|
||
return _context12.abrupt("return", [_context12.t0, _context12.t1]);
|
||
case 6:
|
||
case "end":
|
||
return _context12.stop();
|
||
}
|
||
}, _callee12);
|
||
}));
|
||
return function (_x75, _x76) {
|
||
return _ref4.apply(this, arguments);
|
||
};
|
||
}()));
|
||
case 19:
|
||
generators = _context13.sent;
|
||
_iterator = _createForOfIteratorHelper(generators);
|
||
try {
|
||
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
||
generator = _step.value;
|
||
_generator = _slicedToArray(generator, 2), item = _generator[0], value = _generator[1];
|
||
if (typeof value !== 'undefined') {
|
||
if (item.value === '[') {
|
||
result.push(value);
|
||
} else {
|
||
result = fn.append(result, value);
|
||
}
|
||
}
|
||
}
|
||
} catch (err) {
|
||
_iterator.e(err);
|
||
} finally {
|
||
_iterator.f();
|
||
}
|
||
if (expr.consarray) {
|
||
Object.defineProperty(result, 'cons', {
|
||
enumerable: false,
|
||
configurable: false,
|
||
value: true
|
||
});
|
||
}
|
||
return _context13.abrupt("break", 28);
|
||
case 24:
|
||
_context13.next = 26;
|
||
return evaluateGroupExpression(expr, input, environment);
|
||
case 26:
|
||
result = _context13.sent;
|
||
return _context13.abrupt("break", 28);
|
||
case 28:
|
||
return _context13.abrupt("return", result);
|
||
case 29:
|
||
case "end":
|
||
return _context13.stop();
|
||
}
|
||
}, _callee13);
|
||
}));
|
||
return _evaluateUnary.apply(this, arguments);
|
||
}
|
||
function evaluateName(expr, input, environment) {
|
||
// lookup the 'name' item in the input
|
||
return fn.lookup(input, expr.value);
|
||
}
|
||
|
||
/**
|
||
* Evaluate literal against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateLiteral(expr) {
|
||
return expr.value;
|
||
}
|
||
|
||
/**
|
||
* Evaluate wildcard against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateWildcard(expr, input) {
|
||
var results = createSequence();
|
||
if (Array.isArray(input) && input.outerWrapper && input.length > 0) {
|
||
input = input[0];
|
||
}
|
||
if (input !== null && _typeof(input) === 'object') {
|
||
Object.keys(input).forEach(function (key) {
|
||
var value = input[key];
|
||
if (Array.isArray(value)) {
|
||
value = flatten(value);
|
||
results = fn.append(results, value);
|
||
} else {
|
||
results.push(value);
|
||
}
|
||
});
|
||
}
|
||
|
||
// result = normalizeSequence(results);
|
||
return results;
|
||
}
|
||
|
||
/**
|
||
* Returns a flattened array
|
||
* @param {Array} arg - the array to be flatten
|
||
* @param {Array} flattened - carries the flattened array - if not defined, will initialize to []
|
||
* @returns {Array} - the flattened array
|
||
*/
|
||
function flatten(arg, flattened) {
|
||
if (typeof flattened === 'undefined') {
|
||
flattened = [];
|
||
}
|
||
if (Array.isArray(arg)) {
|
||
arg.forEach(function (item) {
|
||
flatten(item, flattened);
|
||
});
|
||
} else {
|
||
flattened.push(arg);
|
||
}
|
||
return flattened;
|
||
}
|
||
|
||
/**
|
||
* Evaluate descendants against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateDescendants(expr, input) {
|
||
var result;
|
||
var resultSequence = createSequence();
|
||
if (typeof input !== 'undefined') {
|
||
// traverse all descendants of this object/array
|
||
recurseDescendants(input, resultSequence);
|
||
if (resultSequence.length === 1) {
|
||
result = resultSequence[0];
|
||
} else {
|
||
result = resultSequence;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Recurse through descendants
|
||
* @param {Object} input - Input data
|
||
* @param {Object} results - Results
|
||
*/
|
||
function recurseDescendants(input, results) {
|
||
// this is the equivalent of //* in XPath
|
||
if (!Array.isArray(input)) {
|
||
results.push(input);
|
||
}
|
||
if (Array.isArray(input)) {
|
||
input.forEach(function (member) {
|
||
recurseDescendants(member, results);
|
||
});
|
||
} else if (input !== null && _typeof(input) === 'object') {
|
||
Object.keys(input).forEach(function (key) {
|
||
recurseDescendants(input[key], results);
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Evaluate numeric expression against input data
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Object} rhs - RHS value
|
||
* @param {Object} op - opcode
|
||
* @returns {*} Result
|
||
*/
|
||
function evaluateNumericExpression(lhs, rhs, op) {
|
||
var result;
|
||
if (typeof lhs !== 'undefined' && !isNumeric(lhs)) {
|
||
throw {
|
||
code: "T2001",
|
||
stack: new Error().stack,
|
||
value: lhs
|
||
};
|
||
}
|
||
if (typeof rhs !== 'undefined' && !isNumeric(rhs)) {
|
||
throw {
|
||
code: "T2002",
|
||
stack: new Error().stack,
|
||
value: rhs
|
||
};
|
||
}
|
||
if (typeof lhs === 'undefined' || typeof rhs === 'undefined') {
|
||
// if either side is undefined, the result is undefined
|
||
return result;
|
||
}
|
||
switch (op) {
|
||
case '+':
|
||
result = lhs + rhs;
|
||
break;
|
||
case '-':
|
||
result = lhs - rhs;
|
||
break;
|
||
case '*':
|
||
result = lhs * rhs;
|
||
break;
|
||
case '/':
|
||
result = lhs / rhs;
|
||
break;
|
||
case '%':
|
||
result = lhs % rhs;
|
||
break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate equality expression against input data
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Object} rhs - RHS value
|
||
* @param {Object} op - opcode
|
||
* @returns {*} Result
|
||
*/
|
||
function evaluateEqualityExpression(lhs, rhs, op) {
|
||
var result;
|
||
|
||
// type checks
|
||
var ltype = _typeof(lhs);
|
||
var rtype = _typeof(rhs);
|
||
if (ltype === 'undefined' || rtype === 'undefined') {
|
||
// if either side is undefined, the result is false
|
||
return false;
|
||
}
|
||
switch (op) {
|
||
case '=':
|
||
result = isDeepEqual(lhs, rhs);
|
||
break;
|
||
case '!=':
|
||
result = !isDeepEqual(lhs, rhs);
|
||
break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate comparison expression against input data
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Object} rhs - RHS value
|
||
* @param {Object} op - opcode
|
||
* @returns {*} Result
|
||
*/
|
||
function evaluateComparisonExpression(lhs, rhs, op) {
|
||
var result;
|
||
|
||
// type checks
|
||
var ltype = _typeof(lhs);
|
||
var rtype = _typeof(rhs);
|
||
var lcomparable = ltype === 'undefined' || ltype === 'string' || ltype === 'number';
|
||
var rcomparable = rtype === 'undefined' || rtype === 'string' || rtype === 'number';
|
||
|
||
// if either aa or bb are not comparable (string or numeric) values, then throw an error
|
||
if (!lcomparable || !rcomparable) {
|
||
throw {
|
||
code: "T2010",
|
||
stack: new Error().stack,
|
||
value: !(ltype === 'string' || ltype === 'number') ? lhs : rhs
|
||
};
|
||
}
|
||
|
||
// if either side is undefined, the result is undefined
|
||
if (ltype === 'undefined' || rtype === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
//if aa and bb are not of the same type
|
||
if (ltype !== rtype) {
|
||
throw {
|
||
code: "T2009",
|
||
stack: new Error().stack,
|
||
value: lhs,
|
||
value2: rhs
|
||
};
|
||
}
|
||
switch (op) {
|
||
case '<':
|
||
result = lhs < rhs;
|
||
break;
|
||
case '<=':
|
||
result = lhs <= rhs;
|
||
break;
|
||
case '>':
|
||
result = lhs > rhs;
|
||
break;
|
||
case '>=':
|
||
result = lhs >= rhs;
|
||
break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Inclusion operator - in
|
||
*
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Object} rhs - RHS value
|
||
* @returns {boolean} - true if lhs is a member of rhs
|
||
*/
|
||
function evaluateIncludesExpression(lhs, rhs) {
|
||
var result = false;
|
||
if (typeof lhs === 'undefined' || typeof rhs === 'undefined') {
|
||
// if either side is undefined, the result is false
|
||
return false;
|
||
}
|
||
if (!Array.isArray(rhs)) {
|
||
rhs = [rhs];
|
||
}
|
||
for (var i = 0; i < rhs.length; i++) {
|
||
if (rhs[i] === lhs) {
|
||
result = true;
|
||
break;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate boolean expression against input data
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Function} evalrhs - function to evaluate RHS value
|
||
* @param {Object} op - opcode
|
||
* @returns {*} Result
|
||
*/
|
||
function evaluateBooleanExpression(_x27, _x28, _x29) {
|
||
return _evaluateBooleanExpression.apply(this, arguments);
|
||
}
|
||
function _evaluateBooleanExpression() {
|
||
_evaluateBooleanExpression = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee14(lhs, evalrhs, op) {
|
||
var result, lBool;
|
||
return _regeneratorRuntime().wrap(function _callee14$(_context14) {
|
||
while (1) switch (_context14.prev = _context14.next) {
|
||
case 0:
|
||
lBool = boolize(lhs);
|
||
_context14.t0 = op;
|
||
_context14.next = _context14.t0 === 'and' ? 4 : _context14.t0 === 'or' ? 13 : 22;
|
||
break;
|
||
case 4:
|
||
_context14.t1 = lBool;
|
||
if (!_context14.t1) {
|
||
_context14.next = 11;
|
||
break;
|
||
}
|
||
_context14.t2 = boolize;
|
||
_context14.next = 9;
|
||
return evalrhs();
|
||
case 9:
|
||
_context14.t3 = _context14.sent;
|
||
_context14.t1 = (0, _context14.t2)(_context14.t3);
|
||
case 11:
|
||
result = _context14.t1;
|
||
return _context14.abrupt("break", 22);
|
||
case 13:
|
||
_context14.t4 = lBool;
|
||
if (_context14.t4) {
|
||
_context14.next = 20;
|
||
break;
|
||
}
|
||
_context14.t5 = boolize;
|
||
_context14.next = 18;
|
||
return evalrhs();
|
||
case 18:
|
||
_context14.t6 = _context14.sent;
|
||
_context14.t4 = (0, _context14.t5)(_context14.t6);
|
||
case 20:
|
||
result = _context14.t4;
|
||
return _context14.abrupt("break", 22);
|
||
case 22:
|
||
return _context14.abrupt("return", result);
|
||
case 23:
|
||
case "end":
|
||
return _context14.stop();
|
||
}
|
||
}, _callee14);
|
||
}));
|
||
return _evaluateBooleanExpression.apply(this, arguments);
|
||
}
|
||
function boolize(value) {
|
||
var booledValue = fn["boolean"](value);
|
||
return typeof booledValue === 'undefined' ? false : booledValue;
|
||
}
|
||
|
||
/**
|
||
* Evaluate string concatenation against input data
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Object} rhs - RHS value
|
||
* @returns {string|*} Concatenated string
|
||
*/
|
||
function evaluateStringConcat(lhs, rhs) {
|
||
var result;
|
||
var lstr = '';
|
||
var rstr = '';
|
||
if (typeof lhs !== 'undefined') {
|
||
lstr = fn.string(lhs);
|
||
}
|
||
if (typeof rhs !== 'undefined') {
|
||
rstr = fn.string(rhs);
|
||
}
|
||
result = lstr.concat(rstr);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate group expression against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {{}} Evaluated input data
|
||
*/
|
||
function evaluateGroupExpression(_x30, _x31, _x32) {
|
||
return _evaluateGroupExpression.apply(this, arguments);
|
||
}
|
||
function _evaluateGroupExpression() {
|
||
_evaluateGroupExpression = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee16(expr, input, environment) {
|
||
var result, groups, reduce, itemIndex, item, env, pairIndex, pair, key, entry, generators, _iterator2, _step2, generator, _yield$generator, _yield$generator2, value;
|
||
return _regeneratorRuntime().wrap(function _callee16$(_context16) {
|
||
while (1) switch (_context16.prev = _context16.next) {
|
||
case 0:
|
||
result = {};
|
||
groups = {};
|
||
reduce = input && input.tupleStream ? true : false; // group the input sequence by 'key' expression
|
||
if (!Array.isArray(input)) {
|
||
input = createSequence(input);
|
||
}
|
||
// if the array is empty, add an undefined entry to enable literal JSON object to be generated
|
||
if (input.length === 0) {
|
||
input.push(undefined);
|
||
}
|
||
itemIndex = 0;
|
||
case 6:
|
||
if (!(itemIndex < input.length)) {
|
||
_context16.next = 32;
|
||
break;
|
||
}
|
||
item = input[itemIndex];
|
||
env = reduce ? createFrameFromTuple(environment, item) : environment;
|
||
pairIndex = 0;
|
||
case 10:
|
||
if (!(pairIndex < expr.lhs.length)) {
|
||
_context16.next = 29;
|
||
break;
|
||
}
|
||
pair = expr.lhs[pairIndex];
|
||
_context16.next = 14;
|
||
return _evaluate2(pair[0], reduce ? item['@'] : item, env);
|
||
case 14:
|
||
key = _context16.sent;
|
||
if (!(typeof key !== 'string' && key !== undefined)) {
|
||
_context16.next = 17;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T1003",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
value: key
|
||
};
|
||
case 17:
|
||
if (!(key !== undefined)) {
|
||
_context16.next = 26;
|
||
break;
|
||
}
|
||
entry = {
|
||
data: item,
|
||
exprIndex: pairIndex
|
||
};
|
||
if (!groups.hasOwnProperty(key)) {
|
||
_context16.next = 25;
|
||
break;
|
||
}
|
||
if (!(groups[key].exprIndex !== pairIndex)) {
|
||
_context16.next = 22;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "D1009",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
value: key
|
||
};
|
||
case 22:
|
||
// append it as an array
|
||
groups[key].data = fn.append(groups[key].data, item);
|
||
_context16.next = 26;
|
||
break;
|
||
case 25:
|
||
groups[key] = entry;
|
||
case 26:
|
||
pairIndex++;
|
||
_context16.next = 10;
|
||
break;
|
||
case 29:
|
||
itemIndex++;
|
||
_context16.next = 6;
|
||
break;
|
||
case 32:
|
||
_context16.next = 34;
|
||
return Promise.all(Object.keys(groups).map( /*#__PURE__*/function () {
|
||
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15(key, idx) {
|
||
var entry, context, env, tuple;
|
||
return _regeneratorRuntime().wrap(function _callee15$(_context15) {
|
||
while (1) switch (_context15.prev = _context15.next) {
|
||
case 0:
|
||
entry = groups[key];
|
||
context = entry.data;
|
||
env = environment;
|
||
if (reduce) {
|
||
tuple = reduceTupleStream(entry.data);
|
||
context = tuple['@'];
|
||
delete tuple['@'];
|
||
env = createFrameFromTuple(environment, tuple);
|
||
}
|
||
environment.isParallelCall = idx > 0;
|
||
_context15.t0 = key;
|
||
_context15.next = 8;
|
||
return _evaluate2(expr.lhs[entry.exprIndex][1], context, env);
|
||
case 8:
|
||
_context15.t1 = _context15.sent;
|
||
return _context15.abrupt("return", [_context15.t0, _context15.t1]);
|
||
case 10:
|
||
case "end":
|
||
return _context15.stop();
|
||
}
|
||
}, _callee15);
|
||
}));
|
||
return function (_x77, _x78) {
|
||
return _ref5.apply(this, arguments);
|
||
};
|
||
}()));
|
||
case 34:
|
||
generators = _context16.sent;
|
||
_iterator2 = _createForOfIteratorHelper(generators);
|
||
_context16.prev = 36;
|
||
_iterator2.s();
|
||
case 38:
|
||
if ((_step2 = _iterator2.n()).done) {
|
||
_context16.next = 49;
|
||
break;
|
||
}
|
||
generator = _step2.value;
|
||
_context16.next = 42;
|
||
return generator;
|
||
case 42:
|
||
_yield$generator = _context16.sent;
|
||
_yield$generator2 = _slicedToArray(_yield$generator, 2);
|
||
key = _yield$generator2[0];
|
||
value = _yield$generator2[1];
|
||
if (typeof value !== 'undefined') {
|
||
result[key] = value;
|
||
}
|
||
case 47:
|
||
_context16.next = 38;
|
||
break;
|
||
case 49:
|
||
_context16.next = 54;
|
||
break;
|
||
case 51:
|
||
_context16.prev = 51;
|
||
_context16.t0 = _context16["catch"](36);
|
||
_iterator2.e(_context16.t0);
|
||
case 54:
|
||
_context16.prev = 54;
|
||
_iterator2.f();
|
||
return _context16.finish(54);
|
||
case 57:
|
||
return _context16.abrupt("return", result);
|
||
case 58:
|
||
case "end":
|
||
return _context16.stop();
|
||
}
|
||
}, _callee16, null, [[36, 51, 54, 57]]);
|
||
}));
|
||
return _evaluateGroupExpression.apply(this, arguments);
|
||
}
|
||
function reduceTupleStream(tupleStream) {
|
||
if (!Array.isArray(tupleStream)) {
|
||
return tupleStream;
|
||
}
|
||
var result = {};
|
||
Object.assign(result, tupleStream[0]);
|
||
for (var ii = 1; ii < tupleStream.length; ii++) {
|
||
for (var prop in tupleStream[ii]) {
|
||
result[prop] = fn.append(result[prop], tupleStream[ii][prop]);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate range expression against input data
|
||
* @param {Object} lhs - LHS value
|
||
* @param {Object} rhs - RHS value
|
||
* @returns {Array} Resultant array
|
||
*/
|
||
function evaluateRangeExpression(lhs, rhs) {
|
||
var result;
|
||
if (typeof lhs !== 'undefined' && !Number.isInteger(lhs)) {
|
||
throw {
|
||
code: "T2003",
|
||
stack: new Error().stack,
|
||
value: lhs
|
||
};
|
||
}
|
||
if (typeof rhs !== 'undefined' && !Number.isInteger(rhs)) {
|
||
throw {
|
||
code: "T2004",
|
||
stack: new Error().stack,
|
||
value: rhs
|
||
};
|
||
}
|
||
if (typeof lhs === 'undefined' || typeof rhs === 'undefined') {
|
||
// if either side is undefined, the result is undefined
|
||
return result;
|
||
}
|
||
if (lhs > rhs) {
|
||
// if the lhs is greater than the rhs, return undefined
|
||
return result;
|
||
}
|
||
|
||
// limit the size of the array to ten million entries (1e7)
|
||
// this is an implementation defined limit to protect against
|
||
// memory and performance issues. This value may increase in the future.
|
||
var size = rhs - lhs + 1;
|
||
if (size > 1e7) {
|
||
throw {
|
||
code: "D2014",
|
||
stack: new Error().stack,
|
||
value: size
|
||
};
|
||
}
|
||
result = new Array(size);
|
||
for (var item = lhs, index = 0; item <= rhs; item++, index++) {
|
||
result[index] = item;
|
||
}
|
||
result.sequence = true;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Evaluate bind expression against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateBindExpression(_x33, _x34, _x35) {
|
||
return _evaluateBindExpression.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate condition against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateBindExpression() {
|
||
_evaluateBindExpression = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee17(expr, input, environment) {
|
||
var value;
|
||
return _regeneratorRuntime().wrap(function _callee17$(_context17) {
|
||
while (1) switch (_context17.prev = _context17.next) {
|
||
case 0:
|
||
_context17.next = 2;
|
||
return _evaluate2(expr.rhs, input, environment);
|
||
case 2:
|
||
value = _context17.sent;
|
||
environment.bind(expr.lhs.value, value);
|
||
return _context17.abrupt("return", value);
|
||
case 5:
|
||
case "end":
|
||
return _context17.stop();
|
||
}
|
||
}, _callee17);
|
||
}));
|
||
return _evaluateBindExpression.apply(this, arguments);
|
||
}
|
||
function evaluateCondition(_x36, _x37, _x38) {
|
||
return _evaluateCondition.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate block against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateCondition() {
|
||
_evaluateCondition = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18(expr, input, environment) {
|
||
var result, condition;
|
||
return _regeneratorRuntime().wrap(function _callee18$(_context18) {
|
||
while (1) switch (_context18.prev = _context18.next) {
|
||
case 0:
|
||
_context18.next = 2;
|
||
return _evaluate2(expr.condition, input, environment);
|
||
case 2:
|
||
condition = _context18.sent;
|
||
if (!fn["boolean"](condition)) {
|
||
_context18.next = 9;
|
||
break;
|
||
}
|
||
_context18.next = 6;
|
||
return _evaluate2(expr.then, input, environment);
|
||
case 6:
|
||
result = _context18.sent;
|
||
_context18.next = 13;
|
||
break;
|
||
case 9:
|
||
if (!(typeof expr["else"] !== 'undefined')) {
|
||
_context18.next = 13;
|
||
break;
|
||
}
|
||
_context18.next = 12;
|
||
return _evaluate2(expr["else"], input, environment);
|
||
case 12:
|
||
result = _context18.sent;
|
||
case 13:
|
||
return _context18.abrupt("return", result);
|
||
case 14:
|
||
case "end":
|
||
return _context18.stop();
|
||
}
|
||
}, _callee18);
|
||
}));
|
||
return _evaluateCondition.apply(this, arguments);
|
||
}
|
||
function evaluateBlock(_x39, _x40, _x41) {
|
||
return _evaluateBlock.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Prepare a regex
|
||
* @param {Object} expr - expression containing regex
|
||
* @returns {Function} Higher order function representing prepared regex
|
||
*/
|
||
function _evaluateBlock() {
|
||
_evaluateBlock = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee19(expr, input, environment) {
|
||
var result, frame, ii;
|
||
return _regeneratorRuntime().wrap(function _callee19$(_context19) {
|
||
while (1) switch (_context19.prev = _context19.next) {
|
||
case 0:
|
||
// create a new frame to limit the scope of variable assignments
|
||
// TODO, only do this if the post-parse stage has flagged this as required
|
||
frame = createFrame(environment); // invoke each expression in turn
|
||
// only return the result of the last one
|
||
ii = 0;
|
||
case 2:
|
||
if (!(ii < expr.expressions.length)) {
|
||
_context19.next = 9;
|
||
break;
|
||
}
|
||
_context19.next = 5;
|
||
return _evaluate2(expr.expressions[ii], input, frame);
|
||
case 5:
|
||
result = _context19.sent;
|
||
case 6:
|
||
ii++;
|
||
_context19.next = 2;
|
||
break;
|
||
case 9:
|
||
return _context19.abrupt("return", result);
|
||
case 10:
|
||
case "end":
|
||
return _context19.stop();
|
||
}
|
||
}, _callee19);
|
||
}));
|
||
return _evaluateBlock.apply(this, arguments);
|
||
}
|
||
function evaluateRegex(expr) {
|
||
var re = new jsonata.RegexEngine(expr.value);
|
||
var closure = function closure(str, fromIndex) {
|
||
var result;
|
||
re.lastIndex = fromIndex || 0;
|
||
var match = re.exec(str);
|
||
if (match !== null) {
|
||
result = {
|
||
match: match[0],
|
||
start: match.index,
|
||
end: match.index + match[0].length,
|
||
groups: []
|
||
};
|
||
if (match.length > 1) {
|
||
for (var i = 1; i < match.length; i++) {
|
||
result.groups.push(match[i]);
|
||
}
|
||
}
|
||
result.next = function () {
|
||
if (re.lastIndex >= str.length) {
|
||
return undefined;
|
||
} else {
|
||
var next = closure(str, re.lastIndex);
|
||
if (next && next.match === '') {
|
||
// matches zero length string; this will never progress
|
||
throw {
|
||
code: "D1004",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
value: expr.value.source
|
||
};
|
||
}
|
||
return next;
|
||
}
|
||
};
|
||
}
|
||
return result;
|
||
};
|
||
return closure;
|
||
}
|
||
|
||
/**
|
||
* Evaluate variable against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateVariable(expr, input, environment) {
|
||
// lookup the variable value in the environment
|
||
var result;
|
||
// if the variable name is empty string, then it refers to context value
|
||
if (expr.value === '') {
|
||
result = input && input.outerWrapper ? input[0] : input;
|
||
} else {
|
||
result = environment.lookup(expr.value);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* sort / order-by operator
|
||
* @param {Object} expr - AST for operator
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Ordered sequence
|
||
*/
|
||
function evaluateSortExpression(_x42, _x43, _x44) {
|
||
return _evaluateSortExpression.apply(this, arguments);
|
||
}
|
||
/**
|
||
* create a transformer function
|
||
* @param {Object} expr - AST for operator
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} tranformer function
|
||
*/
|
||
function _evaluateSortExpression() {
|
||
_evaluateSortExpression = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(expr, input, environment) {
|
||
var result, lhs, isTupleSort, comparator, focus;
|
||
return _regeneratorRuntime().wrap(function _callee21$(_context21) {
|
||
while (1) switch (_context21.prev = _context21.next) {
|
||
case 0:
|
||
// evaluate the lhs, then sort the results in order according to rhs expression
|
||
lhs = input;
|
||
isTupleSort = input.tupleStream ? true : false; // sort the lhs array
|
||
// use comparator function
|
||
comparator = /*#__PURE__*/function () {
|
||
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee20(a, b) {
|
||
var comp, index, term, context, env, aa, bb, atype, btype;
|
||
return _regeneratorRuntime().wrap(function _callee20$(_context20) {
|
||
while (1) switch (_context20.prev = _context20.next) {
|
||
case 0:
|
||
// expr.terms is an array of order-by in priority order
|
||
comp = 0;
|
||
index = 0;
|
||
case 2:
|
||
if (!(comp === 0 && index < expr.terms.length)) {
|
||
_context20.next = 37;
|
||
break;
|
||
}
|
||
term = expr.terms[index]; //evaluate the sort term in the context of a
|
||
context = a;
|
||
env = environment;
|
||
if (isTupleSort) {
|
||
context = a['@'];
|
||
env = createFrameFromTuple(environment, a);
|
||
}
|
||
_context20.next = 9;
|
||
return _evaluate2(term.expression, context, env);
|
||
case 9:
|
||
aa = _context20.sent;
|
||
//evaluate the sort term in the context of b
|
||
context = b;
|
||
env = environment;
|
||
if (isTupleSort) {
|
||
context = b['@'];
|
||
env = createFrameFromTuple(environment, b);
|
||
}
|
||
_context20.next = 15;
|
||
return _evaluate2(term.expression, context, env);
|
||
case 15:
|
||
bb = _context20.sent;
|
||
// type checks
|
||
atype = _typeof(aa);
|
||
btype = _typeof(bb); // undefined should be last in sort order
|
||
if (!(atype === 'undefined')) {
|
||
_context20.next = 21;
|
||
break;
|
||
}
|
||
// swap them, unless btype is also undefined
|
||
comp = btype === 'undefined' ? 0 : 1;
|
||
return _context20.abrupt("continue", 34);
|
||
case 21:
|
||
if (!(btype === 'undefined')) {
|
||
_context20.next = 24;
|
||
break;
|
||
}
|
||
comp = -1;
|
||
return _context20.abrupt("continue", 34);
|
||
case 24:
|
||
if (!(!(atype === 'string' || atype === 'number') || !(btype === 'string' || btype === 'number'))) {
|
||
_context20.next = 26;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T2008",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
value: !(atype === 'string' || atype === 'number') ? aa : bb
|
||
};
|
||
case 26:
|
||
if (!(atype !== btype)) {
|
||
_context20.next = 28;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T2007",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
value: aa,
|
||
value2: bb
|
||
};
|
||
case 28:
|
||
if (!(aa === bb)) {
|
||
_context20.next = 32;
|
||
break;
|
||
}
|
||
return _context20.abrupt("continue", 34);
|
||
case 32:
|
||
if (aa < bb) {
|
||
comp = -1;
|
||
} else {
|
||
comp = 1;
|
||
}
|
||
case 33:
|
||
if (term.descending === true) {
|
||
comp = -comp;
|
||
}
|
||
case 34:
|
||
index++;
|
||
_context20.next = 2;
|
||
break;
|
||
case 37:
|
||
return _context20.abrupt("return", comp === 1);
|
||
case 38:
|
||
case "end":
|
||
return _context20.stop();
|
||
}
|
||
}, _callee20);
|
||
}));
|
||
return function comparator(_x79, _x80) {
|
||
return _ref6.apply(this, arguments);
|
||
};
|
||
}();
|
||
focus = {
|
||
environment: environment,
|
||
input: input
|
||
}; // the `focus` is passed in as the `this` for the invoked function
|
||
_context21.next = 6;
|
||
return fn.sort.apply(focus, [lhs, comparator]);
|
||
case 6:
|
||
result = _context21.sent;
|
||
return _context21.abrupt("return", result);
|
||
case 8:
|
||
case "end":
|
||
return _context21.stop();
|
||
}
|
||
}, _callee21);
|
||
}));
|
||
return _evaluateSortExpression.apply(this, arguments);
|
||
}
|
||
function evaluateTransformExpression(expr, input, environment) {
|
||
// create a function to implement the transform definition
|
||
var transformer = /*#__PURE__*/function () {
|
||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(obj) {
|
||
var cloneFunction, result, matches, ii, match, update, updateType, prop, deletions, val, jj;
|
||
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
||
while (1) switch (_context.prev = _context.next) {
|
||
case 0:
|
||
if (!(typeof obj === 'undefined')) {
|
||
_context.next = 2;
|
||
break;
|
||
}
|
||
return _context.abrupt("return", undefined);
|
||
case 2:
|
||
// this function returns a copy of obj with changes specified by the pattern/operation
|
||
cloneFunction = environment.lookup('clone');
|
||
if (isFunction(cloneFunction)) {
|
||
_context.next = 5;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T2013",
|
||
stack: new Error().stack,
|
||
position: expr.position
|
||
};
|
||
case 5:
|
||
_context.next = 7;
|
||
return apply(cloneFunction, [obj], null, environment);
|
||
case 7:
|
||
result = _context.sent;
|
||
_context.next = 10;
|
||
return _evaluate2(expr.pattern, result, environment);
|
||
case 10:
|
||
matches = _context.sent;
|
||
if (!(typeof matches !== 'undefined')) {
|
||
_context.next = 39;
|
||
break;
|
||
}
|
||
if (!Array.isArray(matches)) {
|
||
matches = [matches];
|
||
}
|
||
ii = 0;
|
||
case 14:
|
||
if (!(ii < matches.length)) {
|
||
_context.next = 39;
|
||
break;
|
||
}
|
||
match = matches[ii];
|
||
if (!(match && (match.isPrototypeOf(result) || match instanceof Object.constructor))) {
|
||
_context.next = 18;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "D1010",
|
||
stack: new Error().stack,
|
||
position: expr.position
|
||
};
|
||
case 18:
|
||
_context.next = 20;
|
||
return _evaluate2(expr.update, match, environment);
|
||
case 20:
|
||
update = _context.sent;
|
||
// update must be an object
|
||
updateType = _typeof(update);
|
||
if (!(updateType !== 'undefined')) {
|
||
_context.next = 26;
|
||
break;
|
||
}
|
||
if (!(updateType !== 'object' || update === null || Array.isArray(update))) {
|
||
_context.next = 25;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T2011",
|
||
stack: new Error().stack,
|
||
position: expr.update.position,
|
||
value: update
|
||
};
|
||
case 25:
|
||
// merge the update
|
||
for (prop in update) {
|
||
match[prop] = update[prop];
|
||
}
|
||
case 26:
|
||
if (!(typeof expr["delete"] !== 'undefined')) {
|
||
_context.next = 36;
|
||
break;
|
||
}
|
||
_context.next = 29;
|
||
return _evaluate2(expr["delete"], match, environment);
|
||
case 29:
|
||
deletions = _context.sent;
|
||
if (!(typeof deletions !== 'undefined')) {
|
||
_context.next = 36;
|
||
break;
|
||
}
|
||
val = deletions;
|
||
if (!Array.isArray(deletions)) {
|
||
deletions = [deletions];
|
||
}
|
||
if (isArrayOfStrings(deletions)) {
|
||
_context.next = 35;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T2012",
|
||
stack: new Error().stack,
|
||
position: expr["delete"].position,
|
||
value: val
|
||
};
|
||
case 35:
|
||
for (jj = 0; jj < deletions.length; jj++) {
|
||
if (_typeof(match) === 'object' && match !== null) {
|
||
delete match[deletions[jj]];
|
||
}
|
||
}
|
||
case 36:
|
||
ii++;
|
||
_context.next = 14;
|
||
break;
|
||
case 39:
|
||
return _context.abrupt("return", result);
|
||
case 40:
|
||
case "end":
|
||
return _context.stop();
|
||
}
|
||
}, _callee);
|
||
}));
|
||
return function transformer(_x45) {
|
||
return _ref.apply(this, arguments);
|
||
};
|
||
}();
|
||
return defineFunction(transformer, '<(oa):o>');
|
||
}
|
||
var chainAST = parser('function($f, $g) { function($x){ $g($f($x)) } }');
|
||
|
||
/**
|
||
* Apply the function on the RHS using the sequence on the LHS as the first argument
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluateApplyExpression(_x46, _x47, _x48) {
|
||
return _evaluateApplyExpression.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate function against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function _evaluateApplyExpression() {
|
||
_evaluateApplyExpression = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee22(expr, input, environment) {
|
||
var result, lhs, func, chain;
|
||
return _regeneratorRuntime().wrap(function _callee22$(_context22) {
|
||
while (1) switch (_context22.prev = _context22.next) {
|
||
case 0:
|
||
_context22.next = 2;
|
||
return _evaluate2(expr.lhs, input, environment);
|
||
case 2:
|
||
lhs = _context22.sent;
|
||
if (!(expr.rhs.type === 'function')) {
|
||
_context22.next = 9;
|
||
break;
|
||
}
|
||
_context22.next = 6;
|
||
return evaluateFunction(expr.rhs, input, environment, {
|
||
context: lhs
|
||
});
|
||
case 6:
|
||
result = _context22.sent;
|
||
_context22.next = 26;
|
||
break;
|
||
case 9:
|
||
_context22.next = 11;
|
||
return _evaluate2(expr.rhs, input, environment);
|
||
case 11:
|
||
func = _context22.sent;
|
||
if (isFunction(func)) {
|
||
_context22.next = 14;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T2006",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
value: func
|
||
};
|
||
case 14:
|
||
if (!isFunction(lhs)) {
|
||
_context22.next = 23;
|
||
break;
|
||
}
|
||
_context22.next = 17;
|
||
return _evaluate2(chainAST, null, environment);
|
||
case 17:
|
||
chain = _context22.sent;
|
||
_context22.next = 20;
|
||
return apply(chain, [lhs, func], null, environment);
|
||
case 20:
|
||
result = _context22.sent;
|
||
_context22.next = 26;
|
||
break;
|
||
case 23:
|
||
_context22.next = 25;
|
||
return apply(func, [lhs], null, environment);
|
||
case 25:
|
||
result = _context22.sent;
|
||
case 26:
|
||
return _context22.abrupt("return", result);
|
||
case 27:
|
||
case "end":
|
||
return _context22.stop();
|
||
}
|
||
}, _callee22);
|
||
}));
|
||
return _evaluateApplyExpression.apply(this, arguments);
|
||
}
|
||
function evaluateFunction(_x49, _x50, _x51, _x52) {
|
||
return _evaluateFunction.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Apply procedure or function
|
||
* @param {Object} proc - Procedure
|
||
* @param {Array} args - Arguments
|
||
* @param {Object} input - input
|
||
* @param {Object} environment - environment
|
||
* @returns {*} Result of procedure
|
||
*/
|
||
function _evaluateFunction() {
|
||
_evaluateFunction = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee24(expr, input, environment, applyto) {
|
||
var result, proc, evaluatedArgs, _loop, jj, procName;
|
||
return _regeneratorRuntime().wrap(function _callee24$(_context25) {
|
||
while (1) switch (_context25.prev = _context25.next) {
|
||
case 0:
|
||
_context25.next = 2;
|
||
return _evaluate2(expr.procedure, input, environment);
|
||
case 2:
|
||
proc = _context25.sent;
|
||
if (!(typeof proc === 'undefined' && expr.procedure.type === 'path' && environment.lookup(expr.procedure.steps[0].value))) {
|
||
_context25.next = 5;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T1005",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
token: expr.procedure.steps[0].value
|
||
};
|
||
case 5:
|
||
evaluatedArgs = [];
|
||
if (typeof applyto !== 'undefined') {
|
||
evaluatedArgs.push(applyto.context);
|
||
}
|
||
// eager evaluation - evaluate the arguments
|
||
_loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
|
||
var arg, closure;
|
||
return _regeneratorRuntime().wrap(function _loop$(_context24) {
|
||
while (1) switch (_context24.prev = _context24.next) {
|
||
case 0:
|
||
_context24.next = 2;
|
||
return _evaluate2(expr.arguments[jj], input, environment);
|
||
case 2:
|
||
arg = _context24.sent;
|
||
if (isFunction(arg)) {
|
||
// wrap this in a closure
|
||
closure = /*#__PURE__*/function () {
|
||
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee23() {
|
||
var _len,
|
||
params,
|
||
_key,
|
||
_args23 = arguments;
|
||
return _regeneratorRuntime().wrap(function _callee23$(_context23) {
|
||
while (1) switch (_context23.prev = _context23.next) {
|
||
case 0:
|
||
for (_len = _args23.length, params = new Array(_len), _key = 0; _key < _len; _key++) {
|
||
params[_key] = _args23[_key];
|
||
}
|
||
_context23.next = 3;
|
||
return apply(arg, params, null, environment);
|
||
case 3:
|
||
return _context23.abrupt("return", _context23.sent);
|
||
case 4:
|
||
case "end":
|
||
return _context23.stop();
|
||
}
|
||
}, _callee23);
|
||
}));
|
||
return function closure() {
|
||
return _ref7.apply(this, arguments);
|
||
};
|
||
}();
|
||
closure.arity = getFunctionArity(arg);
|
||
evaluatedArgs.push(closure);
|
||
} else {
|
||
evaluatedArgs.push(arg);
|
||
}
|
||
case 4:
|
||
case "end":
|
||
return _context24.stop();
|
||
}
|
||
}, _loop);
|
||
});
|
||
jj = 0;
|
||
case 9:
|
||
if (!(jj < expr.arguments.length)) {
|
||
_context25.next = 14;
|
||
break;
|
||
}
|
||
return _context25.delegateYield(_loop(), "t0", 11);
|
||
case 11:
|
||
jj++;
|
||
_context25.next = 9;
|
||
break;
|
||
case 14:
|
||
// apply the procedure
|
||
procName = expr.procedure.type === 'path' ? expr.procedure.steps[0].value : expr.procedure.value;
|
||
_context25.prev = 15;
|
||
if (_typeof(proc) === 'object') {
|
||
proc.token = procName;
|
||
proc.position = expr.position;
|
||
}
|
||
_context25.next = 19;
|
||
return apply(proc, evaluatedArgs, input, environment);
|
||
case 19:
|
||
result = _context25.sent;
|
||
_context25.next = 27;
|
||
break;
|
||
case 22:
|
||
_context25.prev = 22;
|
||
_context25.t1 = _context25["catch"](15);
|
||
if (!_context25.t1.position) {
|
||
// add the position field to the error
|
||
_context25.t1.position = expr.position;
|
||
}
|
||
if (!_context25.t1.token) {
|
||
// and the function identifier
|
||
_context25.t1.token = procName;
|
||
}
|
||
throw _context25.t1;
|
||
case 27:
|
||
return _context25.abrupt("return", result);
|
||
case 28:
|
||
case "end":
|
||
return _context25.stop();
|
||
}
|
||
}, _callee24, null, [[15, 22]]);
|
||
}));
|
||
return _evaluateFunction.apply(this, arguments);
|
||
}
|
||
function apply(_x53, _x54, _x55, _x56) {
|
||
return _apply.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Apply procedure or function
|
||
* @param {Object} proc - Procedure
|
||
* @param {Array} args - Arguments
|
||
* @param {Object} input - input
|
||
* @param {Object} environment - environment
|
||
* @returns {*} Result of procedure
|
||
*/
|
||
function _apply() {
|
||
_apply = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25(proc, args, input, environment) {
|
||
var result, next, evaluatedArgs, ii;
|
||
return _regeneratorRuntime().wrap(function _callee25$(_context26) {
|
||
while (1) switch (_context26.prev = _context26.next) {
|
||
case 0:
|
||
_context26.next = 2;
|
||
return applyInner(proc, args, input, environment);
|
||
case 2:
|
||
result = _context26.sent;
|
||
case 3:
|
||
if (!(isLambda(result) && result.thunk === true)) {
|
||
_context26.next = 25;
|
||
break;
|
||
}
|
||
_context26.next = 6;
|
||
return _evaluate2(result.body.procedure, result.input, result.environment);
|
||
case 6:
|
||
next = _context26.sent;
|
||
if (result.body.procedure.type === 'variable') {
|
||
next.token = result.body.procedure.value;
|
||
}
|
||
next.position = result.body.procedure.position;
|
||
evaluatedArgs = [];
|
||
ii = 0;
|
||
case 11:
|
||
if (!(ii < result.body.arguments.length)) {
|
||
_context26.next = 20;
|
||
break;
|
||
}
|
||
_context26.t0 = evaluatedArgs;
|
||
_context26.next = 15;
|
||
return _evaluate2(result.body.arguments[ii], result.input, result.environment);
|
||
case 15:
|
||
_context26.t1 = _context26.sent;
|
||
_context26.t0.push.call(_context26.t0, _context26.t1);
|
||
case 17:
|
||
ii++;
|
||
_context26.next = 11;
|
||
break;
|
||
case 20:
|
||
_context26.next = 22;
|
||
return applyInner(next, evaluatedArgs, input, environment);
|
||
case 22:
|
||
result = _context26.sent;
|
||
_context26.next = 3;
|
||
break;
|
||
case 25:
|
||
return _context26.abrupt("return", result);
|
||
case 26:
|
||
case "end":
|
||
return _context26.stop();
|
||
}
|
||
}, _callee25);
|
||
}));
|
||
return _apply.apply(this, arguments);
|
||
}
|
||
function applyInner(_x57, _x58, _x59, _x60) {
|
||
return _applyInner.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Evaluate lambda against input data
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {{lambda: boolean, input: *, environment: *, arguments: *, body: *}} Evaluated input data
|
||
*/
|
||
function _applyInner() {
|
||
_applyInner = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee26(proc, args, input, environment) {
|
||
var result, validatedArgs, focus;
|
||
return _regeneratorRuntime().wrap(function _callee26$(_context27) {
|
||
while (1) switch (_context27.prev = _context27.next) {
|
||
case 0:
|
||
_context27.prev = 0;
|
||
validatedArgs = args;
|
||
if (proc) {
|
||
validatedArgs = validateArguments(proc.signature, args, input);
|
||
}
|
||
if (!isLambda(proc)) {
|
||
_context27.next = 9;
|
||
break;
|
||
}
|
||
_context27.next = 6;
|
||
return applyProcedure(proc, validatedArgs);
|
||
case 6:
|
||
result = _context27.sent;
|
||
_context27.next = 28;
|
||
break;
|
||
case 9:
|
||
if (!(proc && proc._jsonata_function === true)) {
|
||
_context27.next = 19;
|
||
break;
|
||
}
|
||
focus = {
|
||
environment: environment,
|
||
input: input
|
||
}; // the `focus` is passed in as the `this` for the invoked function
|
||
result = proc.implementation.apply(focus, validatedArgs);
|
||
// `proc.implementation` might be a generator function
|
||
// and `result` might be a generator - if so, yield
|
||
if (isIterable(result)) {
|
||
result = result.next().value;
|
||
}
|
||
if (!isPromise(result)) {
|
||
_context27.next = 17;
|
||
break;
|
||
}
|
||
_context27.next = 16;
|
||
return result;
|
||
case 16:
|
||
result = _context27.sent;
|
||
case 17:
|
||
_context27.next = 28;
|
||
break;
|
||
case 19:
|
||
if (!(typeof proc === 'function')) {
|
||
_context27.next = 27;
|
||
break;
|
||
}
|
||
// typically these are functions that are returned by the invocation of plugin functions
|
||
// the `input` is being passed in as the `this` for the invoked function
|
||
// this is so that functions that return objects containing functions can chain
|
||
// e.g. await (await $func())
|
||
result = proc.apply(input, validatedArgs);
|
||
if (!isPromise(result)) {
|
||
_context27.next = 25;
|
||
break;
|
||
}
|
||
_context27.next = 24;
|
||
return result;
|
||
case 24:
|
||
result = _context27.sent;
|
||
case 25:
|
||
_context27.next = 28;
|
||
break;
|
||
case 27:
|
||
throw {
|
||
code: "T1006",
|
||
stack: new Error().stack
|
||
};
|
||
case 28:
|
||
_context27.next = 34;
|
||
break;
|
||
case 30:
|
||
_context27.prev = 30;
|
||
_context27.t0 = _context27["catch"](0);
|
||
if (proc) {
|
||
if (typeof _context27.t0.token == 'undefined' && typeof proc.token !== 'undefined') {
|
||
_context27.t0.token = proc.token;
|
||
}
|
||
_context27.t0.position = proc.position || _context27.t0.position;
|
||
}
|
||
throw _context27.t0;
|
||
case 34:
|
||
return _context27.abrupt("return", result);
|
||
case 35:
|
||
case "end":
|
||
return _context27.stop();
|
||
}
|
||
}, _callee26, null, [[0, 30]]);
|
||
}));
|
||
return _applyInner.apply(this, arguments);
|
||
}
|
||
function evaluateLambda(expr, input, environment) {
|
||
// make a function (closure)
|
||
var procedure = {
|
||
_jsonata_lambda: true,
|
||
input: input,
|
||
environment: environment,
|
||
arguments: expr.arguments,
|
||
signature: expr.signature,
|
||
body: expr.body
|
||
};
|
||
if (expr.thunk === true) {
|
||
procedure.thunk = true;
|
||
}
|
||
procedure.apply = /*#__PURE__*/function () {
|
||
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(self, args) {
|
||
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
||
while (1) switch (_context2.prev = _context2.next) {
|
||
case 0:
|
||
_context2.next = 2;
|
||
return apply(procedure, args, input, !!self ? self.environment : environment);
|
||
case 2:
|
||
return _context2.abrupt("return", _context2.sent);
|
||
case 3:
|
||
case "end":
|
||
return _context2.stop();
|
||
}
|
||
}, _callee2);
|
||
}));
|
||
return function (_x61, _x62) {
|
||
return _ref2.apply(this, arguments);
|
||
};
|
||
}();
|
||
return procedure;
|
||
}
|
||
|
||
/**
|
||
* Evaluate partial application
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} input - Input data to evaluate against
|
||
* @param {Object} environment - Environment
|
||
* @returns {*} Evaluated input data
|
||
*/
|
||
function evaluatePartialApplication(_x63, _x64, _x65) {
|
||
return _evaluatePartialApplication.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Validate the arguments against the signature validator (if it exists)
|
||
* @param {Function} signature - validator function
|
||
* @param {Array} args - function arguments
|
||
* @param {*} context - context value
|
||
* @returns {Array} - validated arguments
|
||
*/
|
||
function _evaluatePartialApplication() {
|
||
_evaluatePartialApplication = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee27(expr, input, environment) {
|
||
var result, evaluatedArgs, ii, arg, proc;
|
||
return _regeneratorRuntime().wrap(function _callee27$(_context28) {
|
||
while (1) switch (_context28.prev = _context28.next) {
|
||
case 0:
|
||
// partially apply a function
|
||
// evaluate the arguments
|
||
evaluatedArgs = [];
|
||
ii = 0;
|
||
case 2:
|
||
if (!(ii < expr.arguments.length)) {
|
||
_context28.next = 16;
|
||
break;
|
||
}
|
||
arg = expr.arguments[ii];
|
||
if (!(arg.type === 'operator' && arg.value === '?')) {
|
||
_context28.next = 8;
|
||
break;
|
||
}
|
||
evaluatedArgs.push(arg);
|
||
_context28.next = 13;
|
||
break;
|
||
case 8:
|
||
_context28.t0 = evaluatedArgs;
|
||
_context28.next = 11;
|
||
return _evaluate2(arg, input, environment);
|
||
case 11:
|
||
_context28.t1 = _context28.sent;
|
||
_context28.t0.push.call(_context28.t0, _context28.t1);
|
||
case 13:
|
||
ii++;
|
||
_context28.next = 2;
|
||
break;
|
||
case 16:
|
||
_context28.next = 18;
|
||
return _evaluate2(expr.procedure, input, environment);
|
||
case 18:
|
||
proc = _context28.sent;
|
||
if (!(typeof proc === 'undefined' && expr.procedure.type === 'path' && environment.lookup(expr.procedure.steps[0].value))) {
|
||
_context28.next = 21;
|
||
break;
|
||
}
|
||
throw {
|
||
code: "T1007",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
token: expr.procedure.steps[0].value
|
||
};
|
||
case 21:
|
||
if (!isLambda(proc)) {
|
||
_context28.next = 25;
|
||
break;
|
||
}
|
||
result = partialApplyProcedure(proc, evaluatedArgs);
|
||
_context28.next = 34;
|
||
break;
|
||
case 25:
|
||
if (!(proc && proc._jsonata_function === true)) {
|
||
_context28.next = 29;
|
||
break;
|
||
}
|
||
result = partialApplyNativeFunction(proc.implementation, evaluatedArgs);
|
||
_context28.next = 34;
|
||
break;
|
||
case 29:
|
||
if (!(typeof proc === 'function')) {
|
||
_context28.next = 33;
|
||
break;
|
||
}
|
||
result = partialApplyNativeFunction(proc, evaluatedArgs);
|
||
_context28.next = 34;
|
||
break;
|
||
case 33:
|
||
throw {
|
||
code: "T1008",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
token: expr.procedure.type === 'path' ? expr.procedure.steps[0].value : expr.procedure.value
|
||
};
|
||
case 34:
|
||
return _context28.abrupt("return", result);
|
||
case 35:
|
||
case "end":
|
||
return _context28.stop();
|
||
}
|
||
}, _callee27);
|
||
}));
|
||
return _evaluatePartialApplication.apply(this, arguments);
|
||
}
|
||
function validateArguments(signature, args, context) {
|
||
if (typeof signature === 'undefined') {
|
||
// nothing to validate
|
||
return args;
|
||
}
|
||
var validatedArgs = signature.validate(args, context);
|
||
return validatedArgs;
|
||
}
|
||
|
||
/**
|
||
* Apply procedure
|
||
* @param {Object} proc - Procedure
|
||
* @param {Array} args - Arguments
|
||
* @returns {*} Result of procedure
|
||
*/
|
||
function applyProcedure(_x66, _x67) {
|
||
return _applyProcedure.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Partially apply procedure
|
||
* @param {Object} proc - Procedure
|
||
* @param {Array} args - Arguments
|
||
* @returns {{lambda: boolean, input: *, environment: {bind, lookup}, arguments: Array, body: *}} Result of partially applied procedure
|
||
*/
|
||
function _applyProcedure() {
|
||
_applyProcedure = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee28(proc, args) {
|
||
var result, env;
|
||
return _regeneratorRuntime().wrap(function _callee28$(_context29) {
|
||
while (1) switch (_context29.prev = _context29.next) {
|
||
case 0:
|
||
env = createFrame(proc.environment);
|
||
proc.arguments.forEach(function (param, index) {
|
||
env.bind(param.value, args[index]);
|
||
});
|
||
if (!(typeof proc.body === 'function')) {
|
||
_context29.next = 8;
|
||
break;
|
||
}
|
||
_context29.next = 5;
|
||
return applyNativeFunction(proc.body, env);
|
||
case 5:
|
||
result = _context29.sent;
|
||
_context29.next = 11;
|
||
break;
|
||
case 8:
|
||
_context29.next = 10;
|
||
return _evaluate2(proc.body, proc.input, env);
|
||
case 10:
|
||
result = _context29.sent;
|
||
case 11:
|
||
return _context29.abrupt("return", result);
|
||
case 12:
|
||
case "end":
|
||
return _context29.stop();
|
||
}
|
||
}, _callee28);
|
||
}));
|
||
return _applyProcedure.apply(this, arguments);
|
||
}
|
||
function partialApplyProcedure(proc, args) {
|
||
// create a closure, bind the supplied parameters and return a function that takes the remaining (?) parameters
|
||
var env = createFrame(proc.environment);
|
||
var unboundArgs = [];
|
||
proc.arguments.forEach(function (param, index) {
|
||
var arg = args[index];
|
||
if (arg && arg.type === 'operator' && arg.value === '?') {
|
||
unboundArgs.push(param);
|
||
} else {
|
||
env.bind(param.value, arg);
|
||
}
|
||
});
|
||
var procedure = {
|
||
_jsonata_lambda: true,
|
||
input: proc.input,
|
||
environment: env,
|
||
arguments: unboundArgs,
|
||
body: proc.body
|
||
};
|
||
return procedure;
|
||
}
|
||
|
||
/**
|
||
* Partially apply native function
|
||
* @param {Function} native - Native function
|
||
* @param {Array} args - Arguments
|
||
* @returns {{lambda: boolean, input: *, environment: {bind, lookup}, arguments: Array, body: *}} Result of partially applying native function
|
||
*/
|
||
function partialApplyNativeFunction(_native, args) {
|
||
// create a lambda function that wraps and invokes the native function
|
||
// get the list of declared arguments from the native function
|
||
// this has to be picked out from the toString() value
|
||
var sigArgs = getNativeFunctionArguments(_native);
|
||
sigArgs = sigArgs.map(function (sigArg) {
|
||
return '$' + sigArg.trim();
|
||
});
|
||
var body = 'function(' + sigArgs.join(', ') + '){ _ }';
|
||
var bodyAST = parser(body);
|
||
bodyAST.body = _native;
|
||
var partial = partialApplyProcedure(bodyAST, args);
|
||
return partial;
|
||
}
|
||
|
||
/**
|
||
* Apply native function
|
||
* @param {Object} proc - Procedure
|
||
* @param {Object} env - Environment
|
||
* @returns {*} Result of applying native function
|
||
*/
|
||
function applyNativeFunction(_x68, _x69) {
|
||
return _applyNativeFunction.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Get native function arguments
|
||
* @param {Function} func - Function
|
||
* @returns {*|Array} Native function arguments
|
||
*/
|
||
function _applyNativeFunction() {
|
||
_applyNativeFunction = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee29(proc, env) {
|
||
var sigArgs, args, focus, result;
|
||
return _regeneratorRuntime().wrap(function _callee29$(_context30) {
|
||
while (1) switch (_context30.prev = _context30.next) {
|
||
case 0:
|
||
sigArgs = getNativeFunctionArguments(proc); // generate the array of arguments for invoking the function - look them up in the environment
|
||
args = sigArgs.map(function (sigArg) {
|
||
return env.lookup(sigArg.trim());
|
||
});
|
||
focus = {
|
||
environment: env
|
||
};
|
||
result = proc.apply(focus, args);
|
||
if (!isPromise(result)) {
|
||
_context30.next = 8;
|
||
break;
|
||
}
|
||
_context30.next = 7;
|
||
return result;
|
||
case 7:
|
||
result = _context30.sent;
|
||
case 8:
|
||
return _context30.abrupt("return", result);
|
||
case 9:
|
||
case "end":
|
||
return _context30.stop();
|
||
}
|
||
}, _callee29);
|
||
}));
|
||
return _applyNativeFunction.apply(this, arguments);
|
||
}
|
||
function getNativeFunctionArguments(func) {
|
||
var signature = func.toString();
|
||
var sigParens = /\(([^)]*)\)/.exec(signature)[1]; // the contents of the parens
|
||
var sigArgs = sigParens.split(',');
|
||
return sigArgs;
|
||
}
|
||
|
||
/**
|
||
* Creates a function definition
|
||
* @param {Function} func - function implementation in Javascript
|
||
* @param {string} signature - JSONata function signature definition
|
||
* @returns {{implementation: *, signature: *}} function definition
|
||
*/
|
||
function defineFunction(func, signature) {
|
||
var definition = {
|
||
_jsonata_function: true,
|
||
implementation: func
|
||
};
|
||
if (typeof signature !== 'undefined') {
|
||
definition.signature = parseSignature(signature);
|
||
}
|
||
return definition;
|
||
}
|
||
|
||
/**
|
||
* parses and evaluates the supplied expression
|
||
* @param {string} expr - expression to evaluate
|
||
* @returns {*} - result of evaluating the expression
|
||
*/
|
||
function functionEval(_x70, _x71) {
|
||
return _functionEval.apply(this, arguments);
|
||
}
|
||
/**
|
||
* Clones an object
|
||
* @param {Object} arg - object to clone (deep copy)
|
||
* @returns {*} - the cloned object
|
||
*/
|
||
function _functionEval() {
|
||
_functionEval = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee30(expr, focus) {
|
||
var input, ast, result;
|
||
return _regeneratorRuntime().wrap(function _callee30$(_context31) {
|
||
while (1) switch (_context31.prev = _context31.next) {
|
||
case 0:
|
||
if (!(typeof expr === 'undefined')) {
|
||
_context31.next = 2;
|
||
break;
|
||
}
|
||
return _context31.abrupt("return", undefined);
|
||
case 2:
|
||
input = this.input;
|
||
if (typeof focus !== 'undefined') {
|
||
input = focus;
|
||
// if the input is a JSON array, then wrap it in a singleton sequence so it gets treated as a single input
|
||
if (Array.isArray(input) && !isSequence(input)) {
|
||
input = createSequence(input);
|
||
input.outerWrapper = true;
|
||
}
|
||
}
|
||
_context31.prev = 4;
|
||
ast = parser(expr, false);
|
||
_context31.next = 12;
|
||
break;
|
||
case 8:
|
||
_context31.prev = 8;
|
||
_context31.t0 = _context31["catch"](4);
|
||
// error parsing the expression passed to $eval
|
||
populateMessage(_context31.t0);
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3120",
|
||
value: _context31.t0.message,
|
||
error: _context31.t0
|
||
};
|
||
case 12:
|
||
_context31.prev = 12;
|
||
_context31.next = 15;
|
||
return _evaluate2(ast, input, this.environment);
|
||
case 15:
|
||
result = _context31.sent;
|
||
_context31.next = 22;
|
||
break;
|
||
case 18:
|
||
_context31.prev = 18;
|
||
_context31.t1 = _context31["catch"](12);
|
||
// error evaluating the expression passed to $eval
|
||
populateMessage(_context31.t1);
|
||
throw {
|
||
stack: new Error().stack,
|
||
code: "D3121",
|
||
value: _context31.t1.message,
|
||
error: _context31.t1
|
||
};
|
||
case 22:
|
||
return _context31.abrupt("return", result);
|
||
case 23:
|
||
case "end":
|
||
return _context31.stop();
|
||
}
|
||
}, _callee30, this, [[4, 8], [12, 18]]);
|
||
}));
|
||
return _functionEval.apply(this, arguments);
|
||
}
|
||
function functionClone(arg) {
|
||
// undefined inputs always return undefined
|
||
if (typeof arg === 'undefined') {
|
||
return undefined;
|
||
}
|
||
return JSON.parse(fn.string(arg));
|
||
}
|
||
|
||
/**
|
||
* Create frame
|
||
* @param {Object} enclosingEnvironment - Enclosing environment
|
||
* @returns {{bind: bind, lookup: lookup}} Created frame
|
||
*/
|
||
function createFrame(enclosingEnvironment) {
|
||
var bindings = {};
|
||
return {
|
||
bind: function bind(name, value) {
|
||
bindings[name] = value;
|
||
},
|
||
lookup: function lookup(name) {
|
||
var value;
|
||
if (bindings.hasOwnProperty(name)) {
|
||
value = bindings[name];
|
||
} else if (enclosingEnvironment) {
|
||
value = enclosingEnvironment.lookup(name);
|
||
}
|
||
return value;
|
||
},
|
||
timestamp: enclosingEnvironment ? enclosingEnvironment.timestamp : null,
|
||
async: enclosingEnvironment ? enclosingEnvironment.async : false,
|
||
isParallelCall: enclosingEnvironment ? enclosingEnvironment.isParallelCall : false,
|
||
global: enclosingEnvironment ? enclosingEnvironment.global : {
|
||
ancestry: [null]
|
||
}
|
||
};
|
||
}
|
||
|
||
// Function registration
|
||
staticFrame.bind('sum', defineFunction(fn.sum, '<a<n>:n>'));
|
||
staticFrame.bind('count', defineFunction(fn.count, '<a:n>'));
|
||
staticFrame.bind('max', defineFunction(fn.max, '<a<n>:n>'));
|
||
staticFrame.bind('min', defineFunction(fn.min, '<a<n>:n>'));
|
||
staticFrame.bind('average', defineFunction(fn.average, '<a<n>:n>'));
|
||
staticFrame.bind('string', defineFunction(fn.string, '<x-b?:s>'));
|
||
staticFrame.bind('substring', defineFunction(fn.substring, '<s-nn?:s>'));
|
||
staticFrame.bind('substringBefore', defineFunction(fn.substringBefore, '<s-s:s>'));
|
||
staticFrame.bind('substringAfter', defineFunction(fn.substringAfter, '<s-s:s>'));
|
||
staticFrame.bind('lowercase', defineFunction(fn.lowercase, '<s-:s>'));
|
||
staticFrame.bind('uppercase', defineFunction(fn.uppercase, '<s-:s>'));
|
||
staticFrame.bind('length', defineFunction(fn.length, '<s-:n>'));
|
||
staticFrame.bind('trim', defineFunction(fn.trim, '<s-:s>'));
|
||
staticFrame.bind('pad', defineFunction(fn.pad, '<s-ns?:s>'));
|
||
staticFrame.bind('match', defineFunction(fn.match, '<s-f<s:o>n?:a<o>>'));
|
||
staticFrame.bind('contains', defineFunction(fn.contains, '<s-(sf):b>')); // TODO <s-(sf<s:o>):b>
|
||
staticFrame.bind('replace', defineFunction(fn.replace, '<s-(sf)(sf)n?:s>')); // TODO <s-(sf<s:o>)(sf<o:s>)n?:s>
|
||
staticFrame.bind('split', defineFunction(fn.split, '<s-(sf)n?:a<s>>')); // TODO <s-(sf<s:o>)n?:a<s>>
|
||
staticFrame.bind('join', defineFunction(fn.join, '<a<s>s?:s>'));
|
||
staticFrame.bind('formatNumber', defineFunction(fn.formatNumber, '<n-so?:s>'));
|
||
staticFrame.bind('formatBase', defineFunction(fn.formatBase, '<n-n?:s>'));
|
||
staticFrame.bind('formatInteger', defineFunction(datetime.formatInteger, '<n-s:s>'));
|
||
staticFrame.bind('parseInteger', defineFunction(datetime.parseInteger, '<s-s:n>'));
|
||
staticFrame.bind('number', defineFunction(fn.number, '<(nsb)-:n>'));
|
||
staticFrame.bind('floor', defineFunction(fn.floor, '<n-:n>'));
|
||
staticFrame.bind('ceil', defineFunction(fn.ceil, '<n-:n>'));
|
||
staticFrame.bind('round', defineFunction(fn.round, '<n-n?:n>'));
|
||
staticFrame.bind('abs', defineFunction(fn.abs, '<n-:n>'));
|
||
staticFrame.bind('sqrt', defineFunction(fn.sqrt, '<n-:n>'));
|
||
staticFrame.bind('power', defineFunction(fn.power, '<n-n:n>'));
|
||
staticFrame.bind('random', defineFunction(fn.random, '<:n>'));
|
||
staticFrame.bind('boolean', defineFunction(fn["boolean"], '<x-:b>'));
|
||
staticFrame.bind('not', defineFunction(fn.not, '<x-:b>'));
|
||
staticFrame.bind('map', defineFunction(fn.map, '<af>'));
|
||
staticFrame.bind('zip', defineFunction(fn.zip, '<a+>'));
|
||
staticFrame.bind('filter', defineFunction(fn.filter, '<af>'));
|
||
staticFrame.bind('single', defineFunction(fn.single, '<af?>'));
|
||
staticFrame.bind('reduce', defineFunction(fn.foldLeft, '<afj?:j>')); // TODO <f<jj:j>a<j>j?:j>
|
||
staticFrame.bind('sift', defineFunction(fn.sift, '<o-f?:o>'));
|
||
staticFrame.bind('keys', defineFunction(fn.keys, '<x-:a<s>>'));
|
||
staticFrame.bind('lookup', defineFunction(fn.lookup, '<x-s:x>'));
|
||
staticFrame.bind('append', defineFunction(fn.append, '<xx:a>'));
|
||
staticFrame.bind('exists', defineFunction(fn.exists, '<x:b>'));
|
||
staticFrame.bind('spread', defineFunction(fn.spread, '<x-:a<o>>'));
|
||
staticFrame.bind('merge', defineFunction(fn.merge, '<a<o>:o>'));
|
||
staticFrame.bind('reverse', defineFunction(fn.reverse, '<a:a>'));
|
||
staticFrame.bind('each', defineFunction(fn.each, '<o-f:a>'));
|
||
staticFrame.bind('error', defineFunction(fn.error, '<s?:x>'));
|
||
staticFrame.bind('assert', defineFunction(fn.assert, '<bs?:x>'));
|
||
staticFrame.bind('type', defineFunction(fn.type, '<x:s>'));
|
||
staticFrame.bind('sort', defineFunction(fn.sort, '<af?:a>'));
|
||
staticFrame.bind('shuffle', defineFunction(fn.shuffle, '<a:a>'));
|
||
staticFrame.bind('distinct', defineFunction(fn.distinct, '<x:x>'));
|
||
staticFrame.bind('base64encode', defineFunction(fn.base64encode, '<s-:s>'));
|
||
staticFrame.bind('base64decode', defineFunction(fn.base64decode, '<s-:s>'));
|
||
staticFrame.bind('encodeUrlComponent', defineFunction(fn.encodeUrlComponent, '<s-:s>'));
|
||
staticFrame.bind('encodeUrl', defineFunction(fn.encodeUrl, '<s-:s>'));
|
||
staticFrame.bind('decodeUrlComponent', defineFunction(fn.decodeUrlComponent, '<s-:s>'));
|
||
staticFrame.bind('decodeUrl', defineFunction(fn.decodeUrl, '<s-:s>'));
|
||
staticFrame.bind('eval', defineFunction(functionEval, '<sx?:x>'));
|
||
staticFrame.bind('toMillis', defineFunction(datetime.toMillis, '<s-s?:n>'));
|
||
staticFrame.bind('fromMillis', defineFunction(datetime.fromMillis, '<n-s?s?:s>'));
|
||
staticFrame.bind('clone', defineFunction(functionClone, '<(oa)-:o>'));
|
||
|
||
/**
|
||
* Error codes
|
||
*
|
||
* Sxxxx - Static errors (compile time)
|
||
* Txxxx - Type errors
|
||
* Dxxxx - Dynamic errors (evaluate time)
|
||
* 01xx - tokenizer
|
||
* 02xx - parser
|
||
* 03xx - regex parser
|
||
* 04xx - function signature parser/evaluator
|
||
* 10xx - evaluator
|
||
* 20xx - operators
|
||
* 3xxx - functions (blocks of 10 for each function)
|
||
*/
|
||
var errorCodes = {
|
||
"S0101": "String literal must be terminated by a matching quote",
|
||
"S0102": "Number out of range: {{token}}",
|
||
"S0103": "Unsupported escape sequence: \\{{token}}",
|
||
"S0104": "The escape sequence \\u must be followed by 4 hex digits",
|
||
"S0105": "Quoted property name must be terminated with a backquote (`)",
|
||
"S0106": "Comment has no closing tag",
|
||
"S0201": "Syntax error: {{token}}",
|
||
"S0202": "Expected {{value}}, got {{token}}",
|
||
"S0203": "Expected {{value}} before end of expression",
|
||
"S0204": "Unknown operator: {{token}}",
|
||
"S0205": "Unexpected token: {{token}}",
|
||
"S0206": "Unknown expression type: {{token}}",
|
||
"S0207": "Unexpected end of expression",
|
||
"S0208": "Parameter {{value}} of function definition must be a variable name (start with $)",
|
||
"S0209": "A predicate cannot follow a grouping expression in a step",
|
||
"S0210": "Each step can only have one grouping expression",
|
||
"S0211": "The symbol {{token}} cannot be used as a unary operator",
|
||
"S0212": "The left side of := must be a variable name (start with $)",
|
||
"S0213": "The literal value {{value}} cannot be used as a step within a path expression",
|
||
"S0214": "The right side of {{token}} must be a variable name (start with $)",
|
||
"S0215": "A context variable binding must precede any predicates on a step",
|
||
"S0216": "A context variable binding must precede the 'order-by' clause on a step",
|
||
"S0217": "The object representing the 'parent' cannot be derived from this expression",
|
||
"S0301": "Empty regular expressions are not allowed",
|
||
"S0302": "No terminating / in regular expression",
|
||
"S0402": "Choice groups containing parameterized types are not supported",
|
||
"S0401": "Type parameters can only be applied to functions and arrays",
|
||
"S0500": "Attempted to evaluate an expression containing syntax error(s)",
|
||
"T0410": "Argument {{index}} of function {{token}} does not match function signature",
|
||
"T0411": "Context value is not a compatible type with argument {{index}} of function {{token}}",
|
||
"T0412": "Argument {{index}} of function {{token}} must be an array of {{type}}",
|
||
"D1001": "Number out of range: {{value}}",
|
||
"D1002": "Cannot negate a non-numeric value: {{value}}",
|
||
"T1003": "Key in object structure must evaluate to a string; got: {{value}}",
|
||
"D1004": "Regular expression matches zero length string",
|
||
"T1005": "Attempted to invoke a non-function. Did you mean ${{{token}}}?",
|
||
"T1006": "Attempted to invoke a non-function",
|
||
"T1007": "Attempted to partially apply a non-function. Did you mean ${{{token}}}?",
|
||
"T1008": "Attempted to partially apply a non-function",
|
||
"D1009": "Multiple key definitions evaluate to same key: {{value}}",
|
||
"D1010": "Attempted to access the Javascript object prototype",
|
||
// Javascript specific
|
||
"T1010": "The matcher function argument passed to function {{token}} does not return the correct object structure",
|
||
"T2001": "The left side of the {{token}} operator must evaluate to a number",
|
||
"T2002": "The right side of the {{token}} operator must evaluate to a number",
|
||
"T2003": "The left side of the range operator (..) must evaluate to an integer",
|
||
"T2004": "The right side of the range operator (..) must evaluate to an integer",
|
||
"D2005": "The left side of := must be a variable name (start with $)",
|
||
// defunct - replaced by S0212 parser error
|
||
"T2006": "The right side of the function application operator ~> must be a function",
|
||
"T2007": "Type mismatch when comparing values {{value}} and {{value2}} in order-by clause",
|
||
"T2008": "The expressions within an order-by clause must evaluate to numeric or string values",
|
||
"T2009": "The values {{value}} and {{value2}} either side of operator {{token}} must be of the same data type",
|
||
"T2010": "The expressions either side of operator {{token}} must evaluate to numeric or string values",
|
||
"T2011": "The insert/update clause of the transform expression must evaluate to an object: {{value}}",
|
||
"T2012": "The delete clause of the transform expression must evaluate to a string or array of strings: {{value}}",
|
||
"T2013": "The transform expression clones the input object using the $clone() function. This has been overridden in the current scope by a non-function.",
|
||
"D2014": "The size of the sequence allocated by the range operator (..) must not exceed 1e6. Attempted to allocate {{value}}.",
|
||
"D3001": "Attempting to invoke string function on Infinity or NaN",
|
||
"D3010": "Second argument of replace function cannot be an empty string",
|
||
"D3011": "Fourth argument of replace function must evaluate to a positive number",
|
||
"D3012": "Attempted to replace a matched string with a non-string value",
|
||
"D3020": "Third argument of split function must evaluate to a positive number",
|
||
"D3030": "Unable to cast value to a number: {{value}}",
|
||
"D3040": "Third argument of match function must evaluate to a positive number",
|
||
"D3050": "The second argument of reduce function must be a function with at least two arguments",
|
||
"D3060": "The sqrt function cannot be applied to a negative number: {{value}}",
|
||
"D3061": "The power function has resulted in a value that cannot be represented as a JSON number: base={{value}}, exponent={{exp}}",
|
||
"D3070": "The single argument form of the sort function can only be applied to an array of strings or an array of numbers. Use the second argument to specify a comparison function",
|
||
"D3080": "The picture string must only contain a maximum of two sub-pictures",
|
||
"D3081": "The sub-picture must not contain more than one instance of the 'decimal-separator' character",
|
||
"D3082": "The sub-picture must not contain more than one instance of the 'percent' character",
|
||
"D3083": "The sub-picture must not contain more than one instance of the 'per-mille' character",
|
||
"D3084": "The sub-picture must not contain both a 'percent' and a 'per-mille' character",
|
||
"D3085": "The mantissa part of a sub-picture must contain at least one character that is either an 'optional digit character' or a member of the 'decimal digit family'",
|
||
"D3086": "The sub-picture must not contain a passive character that is preceded by an active character and that is followed by another active character",
|
||
"D3087": "The sub-picture must not contain a 'grouping-separator' character that appears adjacent to a 'decimal-separator' character",
|
||
"D3088": "The sub-picture must not contain a 'grouping-separator' at the end of the integer part",
|
||
"D3089": "The sub-picture must not contain two adjacent instances of the 'grouping-separator' character",
|
||
"D3090": "The integer part of the sub-picture must not contain a member of the 'decimal digit family' that is followed by an instance of the 'optional digit character'",
|
||
"D3091": "The fractional part of the sub-picture must not contain an instance of the 'optional digit character' that is followed by a member of the 'decimal digit family'",
|
||
"D3092": "A sub-picture that contains a 'percent' or 'per-mille' character must not contain a character treated as an 'exponent-separator'",
|
||
"D3093": "The exponent part of the sub-picture must comprise only of one or more characters that are members of the 'decimal digit family'",
|
||
"D3100": "The radix of the formatBase function must be between 2 and 36. It was given {{value}}",
|
||
"D3110": "The argument of the toMillis function must be an ISO 8601 formatted timestamp. Given {{value}}",
|
||
"D3120": "Syntax error in expression passed to function eval: {{value}}",
|
||
"D3121": "Dynamic error evaluating the expression passed to function eval: {{value}}",
|
||
"D3130": "Formatting or parsing an integer as a sequence starting with {{value}} is not supported by this implementation",
|
||
"D3131": "In a decimal digit pattern, all digits must be from the same decimal group",
|
||
"D3132": "Unknown component specifier {{value}} in date/time picture string",
|
||
"D3133": "The 'name' modifier can only be applied to months and days in the date/time picture string, not {{value}}",
|
||
"D3134": "The timezone integer format specifier cannot have more than four digits",
|
||
"D3135": "No matching closing bracket ']' in date/time picture string",
|
||
"D3136": "The date/time picture string is missing specifiers required to parse the timestamp",
|
||
"D3137": "{{{message}}}",
|
||
"D3138": "The $single() function expected exactly 1 matching result. Instead it matched more.",
|
||
"D3139": "The $single() function expected exactly 1 matching result. Instead it matched 0.",
|
||
"D3140": "Malformed URL passed to ${{{functionName}}}(): {{value}}",
|
||
"D3141": "{{{message}}}"
|
||
};
|
||
|
||
/**
|
||
* lookup a message template from the catalog and substitute the inserts.
|
||
* Populates `err.message` with the substituted message. Leaves `err.message`
|
||
* untouched if code lookup fails.
|
||
* @param {string} err - error code to lookup
|
||
* @returns {undefined} - `err` is modified in place
|
||
*/
|
||
function populateMessage(err) {
|
||
var template = errorCodes[err.code];
|
||
if (typeof template !== 'undefined') {
|
||
// if there are any handlebars, replace them with the field references
|
||
// triple braces - replace with value
|
||
// double braces - replace with json stringified value
|
||
var message = template.replace(/\{\{\{([^}]+)}}}/g, function () {
|
||
return err[arguments[1]];
|
||
});
|
||
message = message.replace(/\{\{([^}]+)}}/g, function () {
|
||
return JSON.stringify(err[arguments[1]]);
|
||
});
|
||
err.message = message;
|
||
}
|
||
// Otherwise retain the original `err.message`
|
||
}
|
||
|
||
/**
|
||
* JSONata
|
||
* @param {Object} expr - JSONata expression
|
||
* @param {Object} options
|
||
* @param {boolean} options.recover: attempt to recover on parse error
|
||
* @param {Function} options.RegexEngine: RegEx class constructor to use
|
||
* @returns {{evaluate: evaluate, assign: assign}} Evaluated expression
|
||
*/
|
||
function jsonata(expr, options) {
|
||
var _ast;
|
||
var _errors;
|
||
try {
|
||
_ast = parser(expr, options && options.recover);
|
||
_errors = _ast.errors;
|
||
delete _ast.errors;
|
||
} catch (err) {
|
||
// insert error message into structure
|
||
populateMessage(err); // possible side-effects on `err`
|
||
throw err;
|
||
}
|
||
var environment = createFrame(staticFrame);
|
||
var timestamp = new Date(); // will be overridden on each call to evalute()
|
||
environment.bind('now', defineFunction(function (picture, timezone) {
|
||
return datetime.fromMillis(timestamp.getTime(), picture, timezone);
|
||
}, '<s?s?:s>'));
|
||
environment.bind('millis', defineFunction(function () {
|
||
return timestamp.getTime();
|
||
}, '<:n>'));
|
||
if (options && options.RegexEngine) {
|
||
jsonata.RegexEngine = options.RegexEngine;
|
||
} else {
|
||
jsonata.RegexEngine = RegExp;
|
||
}
|
||
return {
|
||
evaluate: function () {
|
||
var _evaluate3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(input, bindings, callback) {
|
||
var err, exec_env, v, it;
|
||
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
||
while (1) switch (_context3.prev = _context3.next) {
|
||
case 0:
|
||
if (!(typeof _errors !== 'undefined')) {
|
||
_context3.next = 4;
|
||
break;
|
||
}
|
||
err = {
|
||
code: 'S0500',
|
||
position: 0
|
||
};
|
||
populateMessage(err); // possible side-effects on `err`
|
||
throw err;
|
||
case 4:
|
||
if (typeof bindings !== 'undefined') {
|
||
// the variable bindings have been passed in - create a frame to hold these
|
||
exec_env = createFrame(environment);
|
||
for (v in bindings) {
|
||
exec_env.bind(v, bindings[v]);
|
||
}
|
||
} else {
|
||
exec_env = environment;
|
||
}
|
||
// put the input document into the environment as the root object
|
||
exec_env.bind('$', input);
|
||
|
||
// capture the timestamp and put it in the execution environment
|
||
// the $now() and $millis() functions will return this value - whenever it is called
|
||
timestamp = new Date();
|
||
exec_env.timestamp = timestamp;
|
||
|
||
// if the input is a JSON array, then wrap it in a singleton sequence so it gets treated as a single input
|
||
if (Array.isArray(input) && !isSequence(input)) {
|
||
input = createSequence(input);
|
||
input.outerWrapper = true;
|
||
}
|
||
_context3.prev = 9;
|
||
_context3.next = 12;
|
||
return _evaluate2(_ast, input, exec_env);
|
||
case 12:
|
||
it = _context3.sent;
|
||
if (typeof callback === "function") {
|
||
callback(null, it);
|
||
}
|
||
return _context3.abrupt("return", it);
|
||
case 17:
|
||
_context3.prev = 17;
|
||
_context3.t0 = _context3["catch"](9);
|
||
// insert error message into structure
|
||
populateMessage(_context3.t0); // possible side-effects on `err`
|
||
throw _context3.t0;
|
||
case 21:
|
||
case "end":
|
||
return _context3.stop();
|
||
}
|
||
}, _callee3, null, [[9, 17]]);
|
||
}));
|
||
function evaluate(_x72, _x73, _x74) {
|
||
return _evaluate3.apply(this, arguments);
|
||
}
|
||
return evaluate;
|
||
}(),
|
||
assign: function assign(name, value) {
|
||
environment.bind(name, value);
|
||
},
|
||
registerFunction: function registerFunction(name, implementation, signature) {
|
||
var func = defineFunction(implementation, signature);
|
||
environment.bind(name, func);
|
||
},
|
||
ast: function ast() {
|
||
return _ast;
|
||
},
|
||
errors: function errors() {
|
||
return _errors;
|
||
}
|
||
};
|
||
}
|
||
jsonata.parser = parser; // TODO remove this in a future release - use ast() instead
|
||
|
||
return jsonata;
|
||
}();
|
||
module.exports = jsonata;
|
||
},{"./datetime":1,"./functions":2,"./parser":4,"./signature":5,"./utils":6}],4:[function(require,module,exports){
|
||
"use strict";
|
||
|
||
/**
|
||
* © Copyright IBM Corp. 2016, 2018 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
var parseSignature = require('./signature');
|
||
var parser = function () {
|
||
'use strict';
|
||
|
||
var operators = {
|
||
'.': 75,
|
||
'[': 80,
|
||
']': 0,
|
||
'{': 70,
|
||
'}': 0,
|
||
'(': 80,
|
||
')': 0,
|
||
',': 0,
|
||
'@': 80,
|
||
'#': 80,
|
||
';': 80,
|
||
':': 80,
|
||
'?': 20,
|
||
'+': 50,
|
||
'-': 50,
|
||
'*': 60,
|
||
'/': 60,
|
||
'%': 60,
|
||
'|': 20,
|
||
'=': 40,
|
||
'<': 40,
|
||
'>': 40,
|
||
'^': 40,
|
||
'**': 60,
|
||
'..': 20,
|
||
':=': 10,
|
||
'!=': 40,
|
||
'<=': 40,
|
||
'>=': 40,
|
||
'~>': 40,
|
||
'and': 30,
|
||
'or': 25,
|
||
'in': 40,
|
||
'&': 50,
|
||
'!': 0,
|
||
// not an operator, but needed as a stop character for name tokens
|
||
'~': 0 // not an operator, but needed as a stop character for name tokens
|
||
};
|
||
var escapes = {
|
||
// JSON string escape sequences - see json.org
|
||
'"': '"',
|
||
'\\': '\\',
|
||
'/': '/',
|
||
'b': '\b',
|
||
'f': '\f',
|
||
'n': '\n',
|
||
'r': '\r',
|
||
't': '\t'
|
||
};
|
||
|
||
// Tokenizer (lexer) - invoked by the parser to return one token at a time
|
||
var tokenizer = function tokenizer(path) {
|
||
var position = 0;
|
||
var length = path.length;
|
||
var create = function create(type, value) {
|
||
var obj = {
|
||
type: type,
|
||
value: value,
|
||
position: position
|
||
};
|
||
return obj;
|
||
};
|
||
var scanRegex = function scanRegex() {
|
||
// the prefix '/' will have been previously scanned. Find the end of the regex.
|
||
// search for closing '/' ignoring any that are escaped, or within brackets
|
||
var start = position;
|
||
var depth = 0;
|
||
var pattern;
|
||
var flags;
|
||
var isClosingSlash = function isClosingSlash(position) {
|
||
if (path.charAt(position) === '/' && depth === 0) {
|
||
var backslashCount = 0;
|
||
while (path.charAt(position - (backslashCount + 1)) === '\\') {
|
||
backslashCount++;
|
||
}
|
||
if (backslashCount % 2 === 0) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
while (position < length) {
|
||
var currentChar = path.charAt(position);
|
||
if (isClosingSlash(position)) {
|
||
// end of regex found
|
||
pattern = path.substring(start, position);
|
||
if (pattern === '') {
|
||
throw {
|
||
code: "S0301",
|
||
stack: new Error().stack,
|
||
position: position
|
||
};
|
||
}
|
||
position++;
|
||
currentChar = path.charAt(position);
|
||
// flags
|
||
start = position;
|
||
while (currentChar === 'i' || currentChar === 'm') {
|
||
position++;
|
||
currentChar = path.charAt(position);
|
||
}
|
||
flags = path.substring(start, position) + 'g';
|
||
return new RegExp(pattern, flags);
|
||
}
|
||
if ((currentChar === '(' || currentChar === '[' || currentChar === '{') && path.charAt(position - 1) !== '\\') {
|
||
depth++;
|
||
}
|
||
if ((currentChar === ')' || currentChar === ']' || currentChar === '}') && path.charAt(position - 1) !== '\\') {
|
||
depth--;
|
||
}
|
||
position++;
|
||
}
|
||
throw {
|
||
code: "S0302",
|
||
stack: new Error().stack,
|
||
position: position
|
||
};
|
||
};
|
||
var next = function next(prefix) {
|
||
if (position >= length) return null;
|
||
var currentChar = path.charAt(position);
|
||
// skip whitespace
|
||
while (position < length && ' \t\n\r\v'.indexOf(currentChar) > -1) {
|
||
position++;
|
||
currentChar = path.charAt(position);
|
||
}
|
||
// skip comments
|
||
if (currentChar === '/' && path.charAt(position + 1) === '*') {
|
||
var commentStart = position;
|
||
position += 2;
|
||
currentChar = path.charAt(position);
|
||
while (!(currentChar === '*' && path.charAt(position + 1) === '/')) {
|
||
currentChar = path.charAt(++position);
|
||
if (position >= length) {
|
||
// no closing tag
|
||
throw {
|
||
code: "S0106",
|
||
stack: new Error().stack,
|
||
position: commentStart
|
||
};
|
||
}
|
||
}
|
||
position += 2;
|
||
currentChar = path.charAt(position);
|
||
return next(prefix); // need this to swallow any following whitespace
|
||
}
|
||
// test for regex
|
||
if (prefix !== true && currentChar === '/') {
|
||
position++;
|
||
return create('regex', scanRegex());
|
||
}
|
||
// handle double-char operators
|
||
if (currentChar === '.' && path.charAt(position + 1) === '.') {
|
||
// double-dot .. range operator
|
||
position += 2;
|
||
return create('operator', '..');
|
||
}
|
||
if (currentChar === ':' && path.charAt(position + 1) === '=') {
|
||
// := assignment
|
||
position += 2;
|
||
return create('operator', ':=');
|
||
}
|
||
if (currentChar === '!' && path.charAt(position + 1) === '=') {
|
||
// !=
|
||
position += 2;
|
||
return create('operator', '!=');
|
||
}
|
||
if (currentChar === '>' && path.charAt(position + 1) === '=') {
|
||
// >=
|
||
position += 2;
|
||
return create('operator', '>=');
|
||
}
|
||
if (currentChar === '<' && path.charAt(position + 1) === '=') {
|
||
// <=
|
||
position += 2;
|
||
return create('operator', '<=');
|
||
}
|
||
if (currentChar === '*' && path.charAt(position + 1) === '*') {
|
||
// ** descendant wildcard
|
||
position += 2;
|
||
return create('operator', '**');
|
||
}
|
||
if (currentChar === '~' && path.charAt(position + 1) === '>') {
|
||
// ~> chain function
|
||
position += 2;
|
||
return create('operator', '~>');
|
||
}
|
||
// test for single char operators
|
||
if (Object.prototype.hasOwnProperty.call(operators, currentChar)) {
|
||
position++;
|
||
return create('operator', currentChar);
|
||
}
|
||
// test for string literals
|
||
if (currentChar === '"' || currentChar === "'") {
|
||
var quoteType = currentChar;
|
||
// double quoted string literal - find end of string
|
||
position++;
|
||
var qstr = "";
|
||
while (position < length) {
|
||
currentChar = path.charAt(position);
|
||
if (currentChar === '\\') {
|
||
// escape sequence
|
||
position++;
|
||
currentChar = path.charAt(position);
|
||
if (Object.prototype.hasOwnProperty.call(escapes, currentChar)) {
|
||
qstr += escapes[currentChar];
|
||
} else if (currentChar === 'u') {
|
||
// \u should be followed by 4 hex digits
|
||
var octets = path.substr(position + 1, 4);
|
||
if (/^[0-9a-fA-F]+$/.test(octets)) {
|
||
var codepoint = parseInt(octets, 16);
|
||
qstr += String.fromCharCode(codepoint);
|
||
position += 4;
|
||
} else {
|
||
throw {
|
||
code: "S0104",
|
||
stack: new Error().stack,
|
||
position: position
|
||
};
|
||
}
|
||
} else {
|
||
// illegal escape sequence
|
||
throw {
|
||
code: "S0103",
|
||
stack: new Error().stack,
|
||
position: position,
|
||
token: currentChar
|
||
};
|
||
}
|
||
} else if (currentChar === quoteType) {
|
||
position++;
|
||
return create('string', qstr);
|
||
} else {
|
||
qstr += currentChar;
|
||
}
|
||
position++;
|
||
}
|
||
throw {
|
||
code: "S0101",
|
||
stack: new Error().stack,
|
||
position: position
|
||
};
|
||
}
|
||
// test for numbers
|
||
var numregex = /^-?(0|([1-9][0-9]*))(\.[0-9]+)?([Ee][-+]?[0-9]+)?/;
|
||
var match = numregex.exec(path.substring(position));
|
||
if (match !== null) {
|
||
var num = parseFloat(match[0]);
|
||
if (!isNaN(num) && isFinite(num)) {
|
||
position += match[0].length;
|
||
return create('number', num);
|
||
} else {
|
||
throw {
|
||
code: "S0102",
|
||
stack: new Error().stack,
|
||
position: position,
|
||
token: match[0]
|
||
};
|
||
}
|
||
}
|
||
// test for quoted names (backticks)
|
||
var name;
|
||
if (currentChar === '`') {
|
||
// scan for closing quote
|
||
position++;
|
||
var end = path.indexOf('`', position);
|
||
if (end !== -1) {
|
||
name = path.substring(position, end);
|
||
position = end + 1;
|
||
return create('name', name);
|
||
}
|
||
position = length;
|
||
throw {
|
||
code: "S0105",
|
||
stack: new Error().stack,
|
||
position: position
|
||
};
|
||
}
|
||
// test for names
|
||
var i = position;
|
||
var ch;
|
||
for (;;) {
|
||
ch = path.charAt(i);
|
||
if (i === length || ' \t\n\r\v'.indexOf(ch) > -1 || Object.prototype.hasOwnProperty.call(operators, ch)) {
|
||
if (path.charAt(position) === '$') {
|
||
// variable reference
|
||
name = path.substring(position + 1, i);
|
||
position = i;
|
||
return create('variable', name);
|
||
} else {
|
||
name = path.substring(position, i);
|
||
position = i;
|
||
switch (name) {
|
||
case 'or':
|
||
case 'in':
|
||
case 'and':
|
||
return create('operator', name);
|
||
case 'true':
|
||
return create('value', true);
|
||
case 'false':
|
||
return create('value', false);
|
||
case 'null':
|
||
return create('value', null);
|
||
default:
|
||
if (position === length && name === '') {
|
||
// whitespace at end of input
|
||
return null;
|
||
}
|
||
return create('name', name);
|
||
}
|
||
}
|
||
} else {
|
||
i++;
|
||
}
|
||
}
|
||
};
|
||
return next;
|
||
};
|
||
|
||
// This parser implements the 'Top down operator precedence' algorithm developed by Vaughan R Pratt; http://dl.acm.org/citation.cfm?id=512931.
|
||
// and builds on the Javascript framework described by Douglas Crockford at http://javascript.crockford.com/tdop/tdop.html
|
||
// and in 'Beautiful Code', edited by Andy Oram and Greg Wilson, Copyright 2007 O'Reilly Media, Inc. 798-0-596-51004-6
|
||
|
||
var parser = function parser(source, recover) {
|
||
var node;
|
||
var lexer;
|
||
var symbol_table = {};
|
||
var errors = [];
|
||
var remainingTokens = function remainingTokens() {
|
||
var remaining = [];
|
||
if (node.id !== '(end)') {
|
||
remaining.push({
|
||
type: node.type,
|
||
value: node.value,
|
||
position: node.position
|
||
});
|
||
}
|
||
var nxt = lexer();
|
||
while (nxt !== null) {
|
||
remaining.push(nxt);
|
||
nxt = lexer();
|
||
}
|
||
return remaining;
|
||
};
|
||
var base_symbol = {
|
||
nud: function nud() {
|
||
// error - symbol has been invoked as a unary operator
|
||
var err = {
|
||
code: 'S0211',
|
||
token: this.value,
|
||
position: this.position
|
||
};
|
||
if (recover) {
|
||
err.remaining = remainingTokens();
|
||
err.type = 'error';
|
||
errors.push(err);
|
||
return err;
|
||
} else {
|
||
err.stack = new Error().stack;
|
||
throw err;
|
||
}
|
||
}
|
||
};
|
||
var symbol = function symbol(id, bp) {
|
||
var s = symbol_table[id];
|
||
bp = bp || 0;
|
||
if (s) {
|
||
if (bp >= s.lbp) {
|
||
s.lbp = bp;
|
||
}
|
||
} else {
|
||
s = Object.create(base_symbol);
|
||
s.id = s.value = id;
|
||
s.lbp = bp;
|
||
symbol_table[id] = s;
|
||
}
|
||
return s;
|
||
};
|
||
var handleError = function handleError(err) {
|
||
if (recover) {
|
||
// tokenize the rest of the buffer and add it to an error token
|
||
err.remaining = remainingTokens();
|
||
errors.push(err);
|
||
var symbol = symbol_table["(error)"];
|
||
node = Object.create(symbol);
|
||
node.error = err;
|
||
node.type = "(error)";
|
||
return node;
|
||
} else {
|
||
err.stack = new Error().stack;
|
||
throw err;
|
||
}
|
||
};
|
||
var advance = function advance(id, infix) {
|
||
if (id && node.id !== id) {
|
||
var code;
|
||
if (node.id === '(end)') {
|
||
// unexpected end of buffer
|
||
code = "S0203";
|
||
} else {
|
||
code = "S0202";
|
||
}
|
||
var err = {
|
||
code: code,
|
||
position: node.position,
|
||
token: node.value,
|
||
value: id
|
||
};
|
||
return handleError(err);
|
||
}
|
||
var next_token = lexer(infix);
|
||
if (next_token === null) {
|
||
node = symbol_table["(end)"];
|
||
node.position = source.length;
|
||
return node;
|
||
}
|
||
var value = next_token.value;
|
||
var type = next_token.type;
|
||
var symbol;
|
||
switch (type) {
|
||
case 'name':
|
||
case 'variable':
|
||
symbol = symbol_table["(name)"];
|
||
break;
|
||
case 'operator':
|
||
symbol = symbol_table[value];
|
||
if (!symbol) {
|
||
return handleError({
|
||
code: "S0204",
|
||
stack: new Error().stack,
|
||
position: next_token.position,
|
||
token: value
|
||
});
|
||
}
|
||
break;
|
||
case 'string':
|
||
case 'number':
|
||
case 'value':
|
||
symbol = symbol_table["(literal)"];
|
||
break;
|
||
case 'regex':
|
||
type = "regex";
|
||
symbol = symbol_table["(regex)"];
|
||
break;
|
||
/* istanbul ignore next */
|
||
default:
|
||
return handleError({
|
||
code: "S0205",
|
||
stack: new Error().stack,
|
||
position: next_token.position,
|
||
token: value
|
||
});
|
||
}
|
||
node = Object.create(symbol);
|
||
node.value = value;
|
||
node.type = type;
|
||
node.position = next_token.position;
|
||
return node;
|
||
};
|
||
|
||
// Pratt's algorithm
|
||
var expression = function expression(rbp) {
|
||
var left;
|
||
var t = node;
|
||
advance(null, true);
|
||
left = t.nud();
|
||
while (rbp < node.lbp) {
|
||
t = node;
|
||
advance();
|
||
left = t.led(left);
|
||
}
|
||
return left;
|
||
};
|
||
var terminal = function terminal(id) {
|
||
var s = symbol(id, 0);
|
||
s.nud = function () {
|
||
return this;
|
||
};
|
||
};
|
||
|
||
// match infix operators
|
||
// <expression> <operator> <expression>
|
||
// left associative
|
||
var infix = function infix(id, bp, led) {
|
||
var bindingPower = bp || operators[id];
|
||
var s = symbol(id, bindingPower);
|
||
s.led = led || function (left) {
|
||
this.lhs = left;
|
||
this.rhs = expression(bindingPower);
|
||
this.type = "binary";
|
||
return this;
|
||
};
|
||
return s;
|
||
};
|
||
|
||
// match infix operators
|
||
// <expression> <operator> <expression>
|
||
// right associative
|
||
var infixr = function infixr(id, bp, led) {
|
||
var s = symbol(id, bp);
|
||
s.led = led;
|
||
return s;
|
||
};
|
||
|
||
// match prefix operators
|
||
// <operator> <expression>
|
||
var prefix = function prefix(id, nud) {
|
||
var s = symbol(id);
|
||
s.nud = nud || function () {
|
||
this.expression = expression(70);
|
||
this.type = "unary";
|
||
return this;
|
||
};
|
||
return s;
|
||
};
|
||
terminal("(end)");
|
||
terminal("(name)");
|
||
terminal("(literal)");
|
||
terminal("(regex)");
|
||
symbol(":");
|
||
symbol(";");
|
||
symbol(",");
|
||
symbol(")");
|
||
symbol("]");
|
||
symbol("}");
|
||
symbol(".."); // range operator
|
||
infix("."); // map operator
|
||
infix("+"); // numeric addition
|
||
infix("-"); // numeric subtraction
|
||
infix("*"); // numeric multiplication
|
||
infix("/"); // numeric division
|
||
infix("%"); // numeric modulus
|
||
infix("="); // equality
|
||
infix("<"); // less than
|
||
infix(">"); // greater than
|
||
infix("!="); // not equal to
|
||
infix("<="); // less than or equal
|
||
infix(">="); // greater than or equal
|
||
infix("&"); // string concatenation
|
||
infix("and"); // Boolean AND
|
||
infix("or"); // Boolean OR
|
||
infix("in"); // is member of array
|
||
terminal("and"); // the 'keywords' can also be used as terminals (field names)
|
||
terminal("or"); //
|
||
terminal("in"); //
|
||
prefix("-"); // unary numeric negation
|
||
infix("~>"); // function application
|
||
|
||
infixr("(error)", 10, function (left) {
|
||
this.lhs = left;
|
||
this.error = node.error;
|
||
this.remaining = remainingTokens();
|
||
this.type = 'error';
|
||
return this;
|
||
});
|
||
|
||
// field wildcard (single level)
|
||
prefix('*', function () {
|
||
this.type = "wildcard";
|
||
return this;
|
||
});
|
||
|
||
// descendant wildcard (multi-level)
|
||
prefix('**', function () {
|
||
this.type = "descendant";
|
||
return this;
|
||
});
|
||
|
||
// parent operator
|
||
prefix('%', function () {
|
||
this.type = "parent";
|
||
return this;
|
||
});
|
||
|
||
// function invocation
|
||
infix("(", operators['('], function (left) {
|
||
// left is is what we are trying to invoke
|
||
this.procedure = left;
|
||
this.type = 'function';
|
||
this.arguments = [];
|
||
if (node.id !== ')') {
|
||
for (;;) {
|
||
if (node.type === 'operator' && node.id === '?') {
|
||
// partial function application
|
||
this.type = 'partial';
|
||
this.arguments.push(node);
|
||
advance('?');
|
||
} else {
|
||
this.arguments.push(expression(0));
|
||
}
|
||
if (node.id !== ',') break;
|
||
advance(',');
|
||
}
|
||
}
|
||
advance(")", true);
|
||
// if the name of the function is 'function' or λ, then this is function definition (lambda function)
|
||
if (left.type === 'name' && (left.value === 'function' || left.value === "\u03BB")) {
|
||
// all of the args must be VARIABLE tokens
|
||
this.arguments.forEach(function (arg, index) {
|
||
if (arg.type !== 'variable') {
|
||
return handleError({
|
||
code: "S0208",
|
||
stack: new Error().stack,
|
||
position: arg.position,
|
||
token: arg.value,
|
||
value: index + 1
|
||
});
|
||
}
|
||
});
|
||
this.type = 'lambda';
|
||
// is the next token a '<' - if so, parse the function signature
|
||
if (node.id === '<') {
|
||
var sigPos = node.position;
|
||
var depth = 1;
|
||
var sig = '<';
|
||
while (depth > 0 && node.id !== '{' && node.id !== '(end)') {
|
||
var tok = advance();
|
||
if (tok.id === '>') {
|
||
depth--;
|
||
} else if (tok.id === '<') {
|
||
depth++;
|
||
}
|
||
sig += tok.value;
|
||
}
|
||
advance('>');
|
||
try {
|
||
this.signature = parseSignature(sig);
|
||
} catch (err) {
|
||
// insert the position into this error
|
||
err.position = sigPos + err.offset;
|
||
return handleError(err);
|
||
}
|
||
}
|
||
// parse the function body
|
||
advance('{');
|
||
this.body = expression(0);
|
||
advance('}');
|
||
}
|
||
return this;
|
||
});
|
||
|
||
// parenthesis - block expression
|
||
prefix("(", function () {
|
||
var expressions = [];
|
||
while (node.id !== ")") {
|
||
expressions.push(expression(0));
|
||
if (node.id !== ";") {
|
||
break;
|
||
}
|
||
advance(";");
|
||
}
|
||
advance(")", true);
|
||
this.type = 'block';
|
||
this.expressions = expressions;
|
||
return this;
|
||
});
|
||
|
||
// array constructor
|
||
prefix("[", function () {
|
||
var a = [];
|
||
if (node.id !== "]") {
|
||
for (;;) {
|
||
var item = expression(0);
|
||
if (node.id === "..") {
|
||
// range operator
|
||
var range = {
|
||
type: "binary",
|
||
value: "..",
|
||
position: node.position,
|
||
lhs: item
|
||
};
|
||
advance("..");
|
||
range.rhs = expression(0);
|
||
item = range;
|
||
}
|
||
a.push(item);
|
||
if (node.id !== ",") {
|
||
break;
|
||
}
|
||
advance(",");
|
||
}
|
||
}
|
||
advance("]", true);
|
||
this.expressions = a;
|
||
this.type = "unary";
|
||
return this;
|
||
});
|
||
|
||
// filter - predicate or array index
|
||
infix("[", operators['['], function (left) {
|
||
if (node.id === "]") {
|
||
// empty predicate means maintain singleton arrays in the output
|
||
var step = left;
|
||
while (step && step.type === 'binary' && step.value === '[') {
|
||
step = step.lhs;
|
||
}
|
||
step.keepArray = true;
|
||
advance("]");
|
||
return left;
|
||
} else {
|
||
this.lhs = left;
|
||
this.rhs = expression(operators[']']);
|
||
this.type = 'binary';
|
||
advance("]", true);
|
||
return this;
|
||
}
|
||
});
|
||
|
||
// order-by
|
||
infix("^", operators['^'], function (left) {
|
||
advance("(");
|
||
var terms = [];
|
||
for (;;) {
|
||
var term = {
|
||
descending: false
|
||
};
|
||
if (node.id === "<") {
|
||
// ascending sort
|
||
advance("<");
|
||
} else if (node.id === ">") {
|
||
// descending sort
|
||
term.descending = true;
|
||
advance(">");
|
||
} else {
|
||
//unspecified - default to ascending
|
||
}
|
||
term.expression = expression(0);
|
||
terms.push(term);
|
||
if (node.id !== ",") {
|
||
break;
|
||
}
|
||
advance(",");
|
||
}
|
||
advance(")");
|
||
this.lhs = left;
|
||
this.rhs = terms;
|
||
this.type = 'binary';
|
||
return this;
|
||
});
|
||
var objectParser = function objectParser(left) {
|
||
var a = [];
|
||
if (node.id !== "}") {
|
||
for (;;) {
|
||
var n = expression(0);
|
||
advance(":");
|
||
var v = expression(0);
|
||
a.push([n, v]); // holds an array of name/value expression pairs
|
||
if (node.id !== ",") {
|
||
break;
|
||
}
|
||
advance(",");
|
||
}
|
||
}
|
||
advance("}", true);
|
||
if (typeof left === 'undefined') {
|
||
// NUD - unary prefix form
|
||
this.lhs = a;
|
||
this.type = "unary";
|
||
} else {
|
||
// LED - binary infix form
|
||
this.lhs = left;
|
||
this.rhs = a;
|
||
this.type = 'binary';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// object constructor
|
||
prefix("{", objectParser);
|
||
|
||
// object grouping
|
||
infix("{", operators['{'], objectParser);
|
||
|
||
// bind variable
|
||
infixr(":=", operators[':='], function (left) {
|
||
if (left.type !== 'variable') {
|
||
return handleError({
|
||
code: "S0212",
|
||
stack: new Error().stack,
|
||
position: left.position,
|
||
token: left.value
|
||
});
|
||
}
|
||
this.lhs = left;
|
||
this.rhs = expression(operators[':='] - 1); // subtract 1 from bindingPower for right associative operators
|
||
this.type = "binary";
|
||
return this;
|
||
});
|
||
|
||
// focus variable bind
|
||
infix("@", operators['@'], function (left) {
|
||
this.lhs = left;
|
||
this.rhs = expression(operators['@']);
|
||
if (this.rhs.type !== 'variable') {
|
||
return handleError({
|
||
code: "S0214",
|
||
stack: new Error().stack,
|
||
position: this.rhs.position,
|
||
token: "@"
|
||
});
|
||
}
|
||
this.type = "binary";
|
||
return this;
|
||
});
|
||
|
||
// index (position) variable bind
|
||
infix("#", operators['#'], function (left) {
|
||
this.lhs = left;
|
||
this.rhs = expression(operators['#']);
|
||
if (this.rhs.type !== 'variable') {
|
||
return handleError({
|
||
code: "S0214",
|
||
stack: new Error().stack,
|
||
position: this.rhs.position,
|
||
token: "#"
|
||
});
|
||
}
|
||
this.type = "binary";
|
||
return this;
|
||
});
|
||
|
||
// if/then/else ternary operator ?:
|
||
infix("?", operators['?'], function (left) {
|
||
this.type = 'condition';
|
||
this.condition = left;
|
||
this.then = expression(0);
|
||
if (node.id === ':') {
|
||
// else condition
|
||
advance(":");
|
||
this["else"] = expression(0);
|
||
}
|
||
return this;
|
||
});
|
||
|
||
// object transformer
|
||
prefix("|", function () {
|
||
this.type = 'transform';
|
||
this.pattern = expression(0);
|
||
advance('|');
|
||
this.update = expression(0);
|
||
if (node.id === ',') {
|
||
advance(',');
|
||
this["delete"] = expression(0);
|
||
}
|
||
advance('|');
|
||
return this;
|
||
});
|
||
|
||
// tail call optimization
|
||
// this is invoked by the post parser to analyse lambda functions to see
|
||
// if they make a tail call. If so, it is replaced by a thunk which will
|
||
// be invoked by the trampoline loop during function application.
|
||
// This enables tail-recursive functions to be written without growing the stack
|
||
var tailCallOptimize = function tailCallOptimize(expr) {
|
||
var result;
|
||
if (expr.type === 'function' && !expr.predicate) {
|
||
var thunk = {
|
||
type: 'lambda',
|
||
thunk: true,
|
||
arguments: [],
|
||
position: expr.position
|
||
};
|
||
thunk.body = expr;
|
||
result = thunk;
|
||
} else if (expr.type === 'condition') {
|
||
// analyse both branches
|
||
expr.then = tailCallOptimize(expr.then);
|
||
if (typeof expr["else"] !== 'undefined') {
|
||
expr["else"] = tailCallOptimize(expr["else"]);
|
||
}
|
||
result = expr;
|
||
} else if (expr.type === 'block') {
|
||
// only the last expression in the block
|
||
var length = expr.expressions.length;
|
||
if (length > 0) {
|
||
expr.expressions[length - 1] = tailCallOptimize(expr.expressions[length - 1]);
|
||
}
|
||
result = expr;
|
||
} else {
|
||
result = expr;
|
||
}
|
||
return result;
|
||
};
|
||
var ancestorLabel = 0;
|
||
var ancestorIndex = 0;
|
||
var ancestry = [];
|
||
var seekParent = function seekParent(node, slot) {
|
||
switch (node.type) {
|
||
case 'name':
|
||
case 'wildcard':
|
||
slot.level--;
|
||
if (slot.level === 0) {
|
||
if (typeof node.ancestor === 'undefined') {
|
||
node.ancestor = slot;
|
||
} else {
|
||
// reuse the existing label
|
||
ancestry[slot.index].slot.label = node.ancestor.label;
|
||
node.ancestor = slot;
|
||
}
|
||
node.tuple = true;
|
||
}
|
||
break;
|
||
case 'parent':
|
||
slot.level++;
|
||
break;
|
||
case 'block':
|
||
// look in last expression in the block
|
||
if (node.expressions.length > 0) {
|
||
node.tuple = true;
|
||
slot = seekParent(node.expressions[node.expressions.length - 1], slot);
|
||
}
|
||
break;
|
||
case 'path':
|
||
// last step in path
|
||
node.tuple = true;
|
||
var index = node.steps.length - 1;
|
||
slot = seekParent(node.steps[index--], slot);
|
||
while (slot.level > 0 && index >= 0) {
|
||
// check previous steps
|
||
slot = seekParent(node.steps[index--], slot);
|
||
}
|
||
break;
|
||
default:
|
||
// error - can't derive ancestor
|
||
throw {
|
||
code: "S0217",
|
||
token: node.type,
|
||
position: node.position
|
||
};
|
||
}
|
||
return slot;
|
||
};
|
||
var pushAncestry = function pushAncestry(result, value) {
|
||
if (typeof value.seekingParent !== 'undefined' || value.type === 'parent') {
|
||
var slots = typeof value.seekingParent !== 'undefined' ? value.seekingParent : [];
|
||
if (value.type === 'parent') {
|
||
slots.push(value.slot);
|
||
}
|
||
if (typeof result.seekingParent === 'undefined') {
|
||
result.seekingParent = slots;
|
||
} else {
|
||
Array.prototype.push.apply(result.seekingParent, slots);
|
||
}
|
||
}
|
||
};
|
||
var resolveAncestry = function resolveAncestry(path) {
|
||
var index = path.steps.length - 1;
|
||
var laststep = path.steps[index];
|
||
var slots = typeof laststep.seekingParent !== 'undefined' ? laststep.seekingParent : [];
|
||
if (laststep.type === 'parent') {
|
||
slots.push(laststep.slot);
|
||
}
|
||
for (var is = 0; is < slots.length; is++) {
|
||
var slot = slots[is];
|
||
index = path.steps.length - 2;
|
||
while (slot.level > 0) {
|
||
if (index < 0) {
|
||
if (typeof path.seekingParent === 'undefined') {
|
||
path.seekingParent = [slot];
|
||
} else {
|
||
path.seekingParent.push(slot);
|
||
}
|
||
break;
|
||
}
|
||
// try previous step
|
||
var step = path.steps[index--];
|
||
// multiple contiguous steps that bind the focus should be skipped
|
||
while (index >= 0 && step.focus && path.steps[index].focus) {
|
||
step = path.steps[index--];
|
||
}
|
||
slot = seekParent(step, slot);
|
||
}
|
||
}
|
||
};
|
||
|
||
// post-parse stage
|
||
// the purpose of this is to add as much semantic value to the parse tree as possible
|
||
// in order to simplify the work of the evaluator.
|
||
// This includes flattening the parts of the AST representing location paths,
|
||
// converting them to arrays of steps which in turn may contain arrays of predicates.
|
||
// following this, nodes containing '.' and '[' should be eliminated from the AST.
|
||
var processAST = function processAST(expr) {
|
||
var result;
|
||
switch (expr.type) {
|
||
case 'binary':
|
||
switch (expr.value) {
|
||
case '.':
|
||
var lstep = processAST(expr.lhs);
|
||
if (lstep.type === 'path') {
|
||
result = lstep;
|
||
} else {
|
||
result = {
|
||
type: 'path',
|
||
steps: [lstep]
|
||
};
|
||
}
|
||
if (lstep.type === 'parent') {
|
||
result.seekingParent = [lstep.slot];
|
||
}
|
||
var rest = processAST(expr.rhs);
|
||
if (rest.type === 'function' && rest.procedure.type === 'path' && rest.procedure.steps.length === 1 && rest.procedure.steps[0].type === 'name' && result.steps[result.steps.length - 1].type === 'function') {
|
||
// next function in chain of functions - will override a thenable
|
||
result.steps[result.steps.length - 1].nextFunction = rest.procedure.steps[0].value;
|
||
}
|
||
if (rest.type === 'path') {
|
||
Array.prototype.push.apply(result.steps, rest.steps);
|
||
} else {
|
||
if (typeof rest.predicate !== 'undefined') {
|
||
rest.stages = rest.predicate;
|
||
delete rest.predicate;
|
||
}
|
||
result.steps.push(rest);
|
||
}
|
||
// any steps within a path that are string literals, should be changed to 'name'
|
||
result.steps.filter(function (step) {
|
||
if (step.type === 'number' || step.type === 'value') {
|
||
// don't allow steps to be numbers or the values true/false/null
|
||
throw {
|
||
code: "S0213",
|
||
stack: new Error().stack,
|
||
position: step.position,
|
||
value: step.value
|
||
};
|
||
}
|
||
return step.type === 'string';
|
||
}).forEach(function (lit) {
|
||
lit.type = 'name';
|
||
});
|
||
// any step that signals keeping a singleton array, should be flagged on the path
|
||
if (result.steps.filter(function (step) {
|
||
return step.keepArray === true;
|
||
}).length > 0) {
|
||
result.keepSingletonArray = true;
|
||
}
|
||
// if first step is a path constructor, flag it for special handling
|
||
var firststep = result.steps[0];
|
||
if (firststep.type === 'unary' && firststep.value === '[') {
|
||
firststep.consarray = true;
|
||
}
|
||
// if the last step is an array constructor, flag it so it doesn't flatten
|
||
var laststep = result.steps[result.steps.length - 1];
|
||
if (laststep.type === 'unary' && laststep.value === '[') {
|
||
laststep.consarray = true;
|
||
}
|
||
resolveAncestry(result);
|
||
break;
|
||
case '[':
|
||
// predicated step
|
||
// LHS is a step or a predicated step
|
||
// RHS is the predicate expr
|
||
result = processAST(expr.lhs);
|
||
var step = result;
|
||
var type = 'predicate';
|
||
if (result.type === 'path') {
|
||
step = result.steps[result.steps.length - 1];
|
||
type = 'stages';
|
||
}
|
||
if (typeof step.group !== 'undefined') {
|
||
throw {
|
||
code: "S0209",
|
||
stack: new Error().stack,
|
||
position: expr.position
|
||
};
|
||
}
|
||
if (typeof step[type] === 'undefined') {
|
||
step[type] = [];
|
||
}
|
||
var predicate = processAST(expr.rhs);
|
||
if (typeof predicate.seekingParent !== 'undefined') {
|
||
predicate.seekingParent.forEach(function (slot) {
|
||
if (slot.level === 1) {
|
||
seekParent(step, slot);
|
||
} else {
|
||
slot.level--;
|
||
}
|
||
});
|
||
pushAncestry(step, predicate);
|
||
}
|
||
step[type].push({
|
||
type: 'filter',
|
||
expr: predicate,
|
||
position: expr.position
|
||
});
|
||
break;
|
||
case '{':
|
||
// group-by
|
||
// LHS is a step or a predicated step
|
||
// RHS is the object constructor expr
|
||
result = processAST(expr.lhs);
|
||
if (typeof result.group !== 'undefined') {
|
||
throw {
|
||
code: "S0210",
|
||
stack: new Error().stack,
|
||
position: expr.position
|
||
};
|
||
}
|
||
// object constructor - process each pair
|
||
result.group = {
|
||
lhs: expr.rhs.map(function (pair) {
|
||
return [processAST(pair[0]), processAST(pair[1])];
|
||
}),
|
||
position: expr.position
|
||
};
|
||
break;
|
||
case '^':
|
||
// order-by
|
||
// LHS is the array to be ordered
|
||
// RHS defines the terms
|
||
result = processAST(expr.lhs);
|
||
if (result.type !== 'path') {
|
||
result = {
|
||
type: 'path',
|
||
steps: [result]
|
||
};
|
||
}
|
||
var sortStep = {
|
||
type: 'sort',
|
||
position: expr.position
|
||
};
|
||
sortStep.terms = expr.rhs.map(function (terms) {
|
||
var expression = processAST(terms.expression);
|
||
pushAncestry(sortStep, expression);
|
||
return {
|
||
descending: terms.descending,
|
||
expression: expression
|
||
};
|
||
});
|
||
result.steps.push(sortStep);
|
||
resolveAncestry(result);
|
||
break;
|
||
case ':=':
|
||
result = {
|
||
type: 'bind',
|
||
value: expr.value,
|
||
position: expr.position
|
||
};
|
||
result.lhs = processAST(expr.lhs);
|
||
result.rhs = processAST(expr.rhs);
|
||
pushAncestry(result, result.rhs);
|
||
break;
|
||
case '@':
|
||
result = processAST(expr.lhs);
|
||
step = result;
|
||
if (result.type === 'path') {
|
||
step = result.steps[result.steps.length - 1];
|
||
}
|
||
// throw error if there are any predicates defined at this point
|
||
// at this point the only type of stages can be predicates
|
||
if (typeof step.stages !== 'undefined' || typeof step.predicate !== 'undefined') {
|
||
throw {
|
||
code: "S0215",
|
||
stack: new Error().stack,
|
||
position: expr.position
|
||
};
|
||
}
|
||
// also throw if this is applied after an 'order-by' clause
|
||
if (step.type === 'sort') {
|
||
throw {
|
||
code: "S0216",
|
||
stack: new Error().stack,
|
||
position: expr.position
|
||
};
|
||
}
|
||
if (expr.keepArray) {
|
||
step.keepArray = true;
|
||
}
|
||
step.focus = expr.rhs.value;
|
||
step.tuple = true;
|
||
break;
|
||
case '#':
|
||
result = processAST(expr.lhs);
|
||
step = result;
|
||
if (result.type === 'path') {
|
||
step = result.steps[result.steps.length - 1];
|
||
} else {
|
||
result = {
|
||
type: 'path',
|
||
steps: [result]
|
||
};
|
||
if (typeof step.predicate !== 'undefined') {
|
||
step.stages = step.predicate;
|
||
delete step.predicate;
|
||
}
|
||
}
|
||
if (typeof step.stages === 'undefined') {
|
||
step.index = expr.rhs.value;
|
||
} else {
|
||
step.stages.push({
|
||
type: 'index',
|
||
value: expr.rhs.value,
|
||
position: expr.position
|
||
});
|
||
}
|
||
step.tuple = true;
|
||
break;
|
||
case '~>':
|
||
result = {
|
||
type: 'apply',
|
||
value: expr.value,
|
||
position: expr.position
|
||
};
|
||
result.lhs = processAST(expr.lhs);
|
||
result.rhs = processAST(expr.rhs);
|
||
break;
|
||
default:
|
||
result = {
|
||
type: expr.type,
|
||
value: expr.value,
|
||
position: expr.position
|
||
};
|
||
result.lhs = processAST(expr.lhs);
|
||
result.rhs = processAST(expr.rhs);
|
||
pushAncestry(result, result.lhs);
|
||
pushAncestry(result, result.rhs);
|
||
}
|
||
break;
|
||
case 'unary':
|
||
result = {
|
||
type: expr.type,
|
||
value: expr.value,
|
||
position: expr.position
|
||
};
|
||
if (expr.value === '[') {
|
||
// array constructor - process each item
|
||
result.expressions = expr.expressions.map(function (item) {
|
||
var value = processAST(item);
|
||
pushAncestry(result, value);
|
||
return value;
|
||
});
|
||
} else if (expr.value === '{') {
|
||
// object constructor - process each pair
|
||
result.lhs = expr.lhs.map(function (pair) {
|
||
var key = processAST(pair[0]);
|
||
pushAncestry(result, key);
|
||
var value = processAST(pair[1]);
|
||
pushAncestry(result, value);
|
||
return [key, value];
|
||
});
|
||
} else {
|
||
// all other unary expressions - just process the expression
|
||
result.expression = processAST(expr.expression);
|
||
// if unary minus on a number, then pre-process
|
||
if (expr.value === '-' && result.expression.type === 'number') {
|
||
result = result.expression;
|
||
result.value = -result.value;
|
||
} else {
|
||
pushAncestry(result, result.expression);
|
||
}
|
||
}
|
||
break;
|
||
case 'function':
|
||
case 'partial':
|
||
result = {
|
||
type: expr.type,
|
||
name: expr.name,
|
||
value: expr.value,
|
||
position: expr.position
|
||
};
|
||
result.arguments = expr.arguments.map(function (arg) {
|
||
var argAST = processAST(arg);
|
||
pushAncestry(result, argAST);
|
||
return argAST;
|
||
});
|
||
result.procedure = processAST(expr.procedure);
|
||
break;
|
||
case 'lambda':
|
||
result = {
|
||
type: expr.type,
|
||
arguments: expr.arguments,
|
||
signature: expr.signature,
|
||
position: expr.position
|
||
};
|
||
var body = processAST(expr.body);
|
||
result.body = tailCallOptimize(body);
|
||
break;
|
||
case 'condition':
|
||
result = {
|
||
type: expr.type,
|
||
position: expr.position
|
||
};
|
||
result.condition = processAST(expr.condition);
|
||
pushAncestry(result, result.condition);
|
||
result.then = processAST(expr.then);
|
||
pushAncestry(result, result.then);
|
||
if (typeof expr["else"] !== 'undefined') {
|
||
result["else"] = processAST(expr["else"]);
|
||
pushAncestry(result, result["else"]);
|
||
}
|
||
break;
|
||
case 'transform':
|
||
result = {
|
||
type: expr.type,
|
||
position: expr.position
|
||
};
|
||
result.pattern = processAST(expr.pattern);
|
||
result.update = processAST(expr.update);
|
||
if (typeof expr["delete"] !== 'undefined') {
|
||
result["delete"] = processAST(expr["delete"]);
|
||
}
|
||
break;
|
||
case 'block':
|
||
result = {
|
||
type: expr.type,
|
||
position: expr.position
|
||
};
|
||
// array of expressions - process each one
|
||
result.expressions = expr.expressions.map(function (item) {
|
||
var part = processAST(item);
|
||
pushAncestry(result, part);
|
||
if (part.consarray || part.type === 'path' && part.steps[0].consarray) {
|
||
result.consarray = true;
|
||
}
|
||
return part;
|
||
});
|
||
// TODO scan the array of expressions to see if any of them assign variables
|
||
// if so, need to mark the block as one that needs to create a new frame
|
||
break;
|
||
case 'name':
|
||
result = {
|
||
type: 'path',
|
||
steps: [expr]
|
||
};
|
||
if (expr.keepArray) {
|
||
result.keepSingletonArray = true;
|
||
}
|
||
break;
|
||
case 'parent':
|
||
result = {
|
||
type: 'parent',
|
||
slot: {
|
||
label: '!' + ancestorLabel++,
|
||
level: 1,
|
||
index: ancestorIndex++
|
||
}
|
||
};
|
||
ancestry.push(result);
|
||
break;
|
||
case 'string':
|
||
case 'number':
|
||
case 'value':
|
||
case 'wildcard':
|
||
case 'descendant':
|
||
case 'variable':
|
||
case 'regex':
|
||
result = expr;
|
||
break;
|
||
case 'operator':
|
||
// the tokens 'and' and 'or' might have been used as a name rather than an operator
|
||
if (expr.value === 'and' || expr.value === 'or' || expr.value === 'in') {
|
||
expr.type = 'name';
|
||
result = processAST(expr);
|
||
} else /* istanbul ignore else */if (expr.value === '?') {
|
||
// partial application
|
||
result = expr;
|
||
} else {
|
||
throw {
|
||
code: "S0201",
|
||
stack: new Error().stack,
|
||
position: expr.position,
|
||
token: expr.value
|
||
};
|
||
}
|
||
break;
|
||
case 'error':
|
||
result = expr;
|
||
if (expr.lhs) {
|
||
result = processAST(expr.lhs);
|
||
}
|
||
break;
|
||
default:
|
||
var code = "S0206";
|
||
/* istanbul ignore else */
|
||
if (expr.id === '(end)') {
|
||
code = "S0207";
|
||
}
|
||
var err = {
|
||
code: code,
|
||
position: expr.position,
|
||
token: expr.value
|
||
};
|
||
if (recover) {
|
||
errors.push(err);
|
||
return {
|
||
type: 'error',
|
||
error: err
|
||
};
|
||
} else {
|
||
err.stack = new Error().stack;
|
||
throw err;
|
||
}
|
||
}
|
||
if (expr.keepArray) {
|
||
result.keepArray = true;
|
||
}
|
||
return result;
|
||
};
|
||
|
||
// now invoke the tokenizer and the parser and return the syntax tree
|
||
lexer = tokenizer(source);
|
||
advance();
|
||
// parse the tokens
|
||
var expr = expression(0);
|
||
if (node.id !== '(end)') {
|
||
var err = {
|
||
code: "S0201",
|
||
position: node.position,
|
||
token: node.value
|
||
};
|
||
handleError(err);
|
||
}
|
||
expr = processAST(expr);
|
||
if (expr.type === 'parent' || typeof expr.seekingParent !== 'undefined') {
|
||
// error - trying to derive ancestor at top level
|
||
throw {
|
||
code: "S0217",
|
||
token: expr.type,
|
||
position: expr.position
|
||
};
|
||
}
|
||
if (errors.length > 0) {
|
||
expr.errors = errors;
|
||
}
|
||
return expr;
|
||
};
|
||
return parser;
|
||
}();
|
||
module.exports = parser;
|
||
},{"./signature":5}],5:[function(require,module,exports){
|
||
"use strict";
|
||
|
||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||
/**
|
||
* © Copyright IBM Corp. 2016, 2018 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
var utils = require('./utils');
|
||
var signature = function () {
|
||
'use strict';
|
||
|
||
// A mapping between the function signature symbols and the full plural of the type
|
||
// Expected to be used in error messages
|
||
var arraySignatureMapping = {
|
||
"a": "arrays",
|
||
"b": "booleans",
|
||
"f": "functions",
|
||
"n": "numbers",
|
||
"o": "objects",
|
||
"s": "strings"
|
||
};
|
||
|
||
/**
|
||
* Parses a function signature definition and returns a validation function
|
||
* @param {string} signature - the signature between the <angle brackets>
|
||
* @returns {Function} validation function
|
||
*/
|
||
function parseSignature(signature) {
|
||
// create a Regex that represents this signature and return a function that when invoked,
|
||
// returns the validated (possibly fixed-up) arguments, or throws a validation error
|
||
// step through the signature, one symbol at a time
|
||
var position = 1;
|
||
var params = [];
|
||
var param = {};
|
||
var prevParam = param;
|
||
while (position < signature.length) {
|
||
var symbol = signature.charAt(position);
|
||
if (symbol === ':') {
|
||
// TODO figure out what to do with the return type
|
||
// ignore it for now
|
||
break;
|
||
}
|
||
var next = function next() {
|
||
params.push(param);
|
||
prevParam = param;
|
||
param = {};
|
||
};
|
||
var findClosingBracket = function findClosingBracket(str, start, openSymbol, closeSymbol) {
|
||
// returns the position of the closing symbol (e.g. bracket) in a string
|
||
// that balances the opening symbol at position start
|
||
var depth = 1;
|
||
var position = start;
|
||
while (position < str.length) {
|
||
position++;
|
||
symbol = str.charAt(position);
|
||
if (symbol === closeSymbol) {
|
||
depth--;
|
||
if (depth === 0) {
|
||
// we're done
|
||
break; // out of while loop
|
||
}
|
||
} else if (symbol === openSymbol) {
|
||
depth++;
|
||
}
|
||
}
|
||
return position;
|
||
};
|
||
switch (symbol) {
|
||
case 's': // string
|
||
case 'n': // number
|
||
case 'b': // boolean
|
||
case 'l': // not so sure about expecting null?
|
||
case 'o':
|
||
// object
|
||
param.regex = '[' + symbol + 'm]';
|
||
param.type = symbol;
|
||
next();
|
||
break;
|
||
case 'a':
|
||
// array
|
||
// normally treat any value as singleton array
|
||
param.regex = '[asnblfom]';
|
||
param.type = symbol;
|
||
param.array = true;
|
||
next();
|
||
break;
|
||
case 'f':
|
||
// function
|
||
param.regex = 'f';
|
||
param.type = symbol;
|
||
next();
|
||
break;
|
||
case 'j':
|
||
// any JSON type
|
||
param.regex = '[asnblom]';
|
||
param.type = symbol;
|
||
next();
|
||
break;
|
||
case 'x':
|
||
// any type
|
||
param.regex = '[asnblfom]';
|
||
param.type = symbol;
|
||
next();
|
||
break;
|
||
case '-':
|
||
// use context if param not supplied
|
||
prevParam.context = true;
|
||
prevParam.contextRegex = new RegExp(prevParam.regex); // pre-compiled to test the context type at runtime
|
||
prevParam.regex += '?';
|
||
break;
|
||
case '?': // optional param
|
||
case '+':
|
||
// one or more
|
||
prevParam.regex += symbol;
|
||
break;
|
||
case '(':
|
||
// choice of types
|
||
// search forward for matching ')'
|
||
var endParen = findClosingBracket(signature, position, '(', ')');
|
||
var choice = signature.substring(position + 1, endParen);
|
||
if (choice.indexOf('<') === -1) {
|
||
// no parameterized types, simple regex
|
||
param.regex = '[' + choice + 'm]';
|
||
} else {
|
||
// TODO harder
|
||
throw {
|
||
code: "S0402",
|
||
stack: new Error().stack,
|
||
value: choice,
|
||
offset: position
|
||
};
|
||
}
|
||
param.type = '(' + choice + ')';
|
||
position = endParen;
|
||
next();
|
||
break;
|
||
case '<':
|
||
// type parameter - can only be applied to 'a' and 'f'
|
||
if (prevParam.type === 'a' || prevParam.type === 'f') {
|
||
// search forward for matching '>'
|
||
var endPos = findClosingBracket(signature, position, '<', '>');
|
||
prevParam.subtype = signature.substring(position + 1, endPos);
|
||
position = endPos;
|
||
} else {
|
||
throw {
|
||
code: "S0401",
|
||
stack: new Error().stack,
|
||
value: prevParam.type,
|
||
offset: position
|
||
};
|
||
}
|
||
break;
|
||
}
|
||
position++;
|
||
}
|
||
var regexStr = '^' + params.map(function (param) {
|
||
return '(' + param.regex + ')';
|
||
}).join('') + '$';
|
||
var regex = new RegExp(regexStr);
|
||
var getSymbol = function getSymbol(value) {
|
||
var symbol;
|
||
if (utils.isFunction(value)) {
|
||
symbol = 'f';
|
||
} else {
|
||
var type = _typeof(value);
|
||
switch (type) {
|
||
case 'string':
|
||
symbol = 's';
|
||
break;
|
||
case 'number':
|
||
symbol = 'n';
|
||
break;
|
||
case 'boolean':
|
||
symbol = 'b';
|
||
break;
|
||
case 'object':
|
||
if (value === null) {
|
||
symbol = 'l';
|
||
} else if (Array.isArray(value)) {
|
||
symbol = 'a';
|
||
} else {
|
||
symbol = 'o';
|
||
}
|
||
break;
|
||
case 'undefined':
|
||
default:
|
||
// any value can be undefined, but should be allowed to match
|
||
symbol = 'm';
|
||
// m for missing
|
||
}
|
||
}
|
||
return symbol;
|
||
};
|
||
var throwValidationError = function throwValidationError(badArgs, badSig) {
|
||
// to figure out where this went wrong we need apply each component of the
|
||
// regex to each argument until we get to the one that fails to match
|
||
var partialPattern = '^';
|
||
var goodTo = 0;
|
||
for (var index = 0; index < params.length; index++) {
|
||
partialPattern += params[index].regex;
|
||
var match = badSig.match(partialPattern);
|
||
if (match === null) {
|
||
// failed here
|
||
throw {
|
||
code: "T0410",
|
||
stack: new Error().stack,
|
||
value: badArgs[goodTo],
|
||
index: goodTo + 1
|
||
};
|
||
}
|
||
goodTo = match[0].length;
|
||
}
|
||
// if it got this far, it's probably because of extraneous arguments (we
|
||
// haven't added the trailing '$' in the regex yet.
|
||
throw {
|
||
code: "T0410",
|
||
stack: new Error().stack,
|
||
value: badArgs[goodTo],
|
||
index: goodTo + 1
|
||
};
|
||
};
|
||
return {
|
||
definition: signature,
|
||
validate: function validate(args, context) {
|
||
var suppliedSig = '';
|
||
args.forEach(function (arg) {
|
||
suppliedSig += getSymbol(arg);
|
||
});
|
||
var isValid = regex.exec(suppliedSig);
|
||
if (isValid) {
|
||
var validatedArgs = [];
|
||
var argIndex = 0;
|
||
params.forEach(function (param, index) {
|
||
var arg = args[argIndex];
|
||
var match = isValid[index + 1];
|
||
if (match === '') {
|
||
if (param.context && param.contextRegex) {
|
||
// substitute context value for missing arg
|
||
// first check that the context value is the right type
|
||
var contextType = getSymbol(context);
|
||
// test contextType against the regex for this arg (without the trailing ?)
|
||
if (param.contextRegex.test(contextType)) {
|
||
validatedArgs.push(context);
|
||
} else {
|
||
// context value not compatible with this argument
|
||
throw {
|
||
code: "T0411",
|
||
stack: new Error().stack,
|
||
value: context,
|
||
index: argIndex + 1
|
||
};
|
||
}
|
||
} else {
|
||
validatedArgs.push(arg);
|
||
argIndex++;
|
||
}
|
||
} else {
|
||
// may have matched multiple args (if the regex ends with a '+'
|
||
// split into single tokens
|
||
match.split('').forEach(function (single) {
|
||
if (param.type === 'a') {
|
||
if (single === 'm') {
|
||
// missing (undefined)
|
||
arg = undefined;
|
||
} else {
|
||
arg = args[argIndex];
|
||
var arrayOK = true;
|
||
// is there type information on the contents of the array?
|
||
if (typeof param.subtype !== 'undefined') {
|
||
if (single !== 'a' && match !== param.subtype) {
|
||
arrayOK = false;
|
||
} else if (single === 'a') {
|
||
if (arg.length > 0) {
|
||
var itemType = getSymbol(arg[0]);
|
||
if (itemType !== param.subtype.charAt(0)) {
|
||
// TODO recurse further
|
||
arrayOK = false;
|
||
} else {
|
||
// make sure every item in the array is this type
|
||
var differentItems = arg.filter(function (val) {
|
||
return getSymbol(val) !== itemType;
|
||
});
|
||
arrayOK = differentItems.length === 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!arrayOK) {
|
||
throw {
|
||
code: "T0412",
|
||
stack: new Error().stack,
|
||
value: arg,
|
||
index: argIndex + 1,
|
||
type: arraySignatureMapping[param.subtype]
|
||
};
|
||
}
|
||
// the function expects an array. If it's not one, make it so
|
||
if (single !== 'a') {
|
||
arg = [arg];
|
||
}
|
||
}
|
||
validatedArgs.push(arg);
|
||
argIndex++;
|
||
} else {
|
||
validatedArgs.push(arg);
|
||
argIndex++;
|
||
}
|
||
});
|
||
}
|
||
});
|
||
return validatedArgs;
|
||
}
|
||
throwValidationError(args, suppliedSig);
|
||
}
|
||
};
|
||
}
|
||
return parseSignature;
|
||
}();
|
||
module.exports = signature;
|
||
},{"./utils":6}],6:[function(require,module,exports){
|
||
"use strict";
|
||
|
||
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||
/**
|
||
* © Copyright IBM Corp. 2016, 2018 All Rights Reserved
|
||
* Project name: JSONata
|
||
* This project is licensed under the MIT License, see LICENSE
|
||
*/
|
||
|
||
var utils = function () {
|
||
'use strict';
|
||
|
||
/**
|
||
* Check if value is a finite number
|
||
* @param {float} n - number to evaluate
|
||
* @returns {boolean} True if n is a finite number
|
||
*/
|
||
function isNumeric(n) {
|
||
var isNum = false;
|
||
if (typeof n === 'number') {
|
||
isNum = !isNaN(n);
|
||
if (isNum && !isFinite(n)) {
|
||
throw {
|
||
code: "D1001",
|
||
value: n,
|
||
stack: new Error().stack
|
||
};
|
||
}
|
||
}
|
||
return isNum;
|
||
}
|
||
|
||
/**
|
||
* Returns true if the arg is an array of strings
|
||
* @param {*} arg - the item to test
|
||
* @returns {boolean} True if arg is an array of strings
|
||
*/
|
||
function isArrayOfStrings(arg) {
|
||
var result = false;
|
||
/* istanbul ignore else */
|
||
if (Array.isArray(arg)) {
|
||
result = arg.filter(function (item) {
|
||
return typeof item !== 'string';
|
||
}).length === 0;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Returns true if the arg is an array of numbers
|
||
* @param {*} arg - the item to test
|
||
* @returns {boolean} True if arg is an array of numbers
|
||
*/
|
||
function isArrayOfNumbers(arg) {
|
||
var result = false;
|
||
if (Array.isArray(arg)) {
|
||
result = arg.filter(function (item) {
|
||
return !isNumeric(item);
|
||
}).length === 0;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Create an empty sequence to contain query results
|
||
* @returns {Array} - empty sequence
|
||
*/
|
||
function createSequence() {
|
||
var sequence = [];
|
||
sequence.sequence = true;
|
||
if (arguments.length === 1) {
|
||
sequence.push(arguments[0]);
|
||
}
|
||
return sequence;
|
||
}
|
||
|
||
/**
|
||
* Tests if a value is a sequence
|
||
* @param {*} value the value to test
|
||
* @returns {boolean} true if it's a sequence
|
||
*/
|
||
function isSequence(value) {
|
||
return value.sequence === true && Array.isArray(value);
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} arg - expression to test
|
||
* @returns {boolean} - true if it is a function (lambda or built-in)
|
||
*/
|
||
function isFunction(arg) {
|
||
return arg && (arg._jsonata_function === true || arg._jsonata_lambda === true) || typeof arg === 'function';
|
||
}
|
||
|
||
/**
|
||
* Returns the arity (number of arguments) of the function
|
||
* @param {*} func - the function
|
||
* @returns {*} - the arity
|
||
*/
|
||
function getFunctionArity(func) {
|
||
var arity = typeof func.arity === 'number' ? func.arity : typeof func.implementation === 'function' ? func.implementation.length : typeof func.length === 'number' ? func.length : func.arguments.length;
|
||
return arity;
|
||
}
|
||
|
||
/**
|
||
* Tests whether arg is a lambda function
|
||
* @param {*} arg - the value to test
|
||
* @returns {boolean} - true if it is a lambda function
|
||
*/
|
||
function isLambda(arg) {
|
||
return arg && arg._jsonata_lambda === true;
|
||
}
|
||
|
||
// istanbul ignore next
|
||
var iteratorSymbol = (typeof Symbol === "function" ? Symbol : {}).iterator || "@@iterator";
|
||
|
||
/**
|
||
* @param {Object} arg - expression to test
|
||
* @returns {boolean} - true if it is iterable
|
||
*/
|
||
function isIterable(arg) {
|
||
return _typeof(arg) === 'object' && arg !== null && iteratorSymbol in arg && 'next' in arg && typeof arg.next === 'function';
|
||
}
|
||
|
||
/**
|
||
* Compares two values for equality
|
||
* @param {*} lhs first value
|
||
* @param {*} rhs second value
|
||
* @returns {boolean} true if they are deep equal
|
||
*/
|
||
function isDeepEqual(lhs, rhs) {
|
||
if (lhs === rhs) {
|
||
return true;
|
||
}
|
||
if (_typeof(lhs) === 'object' && _typeof(rhs) === 'object' && lhs !== null && rhs !== null) {
|
||
if (Array.isArray(lhs) && Array.isArray(rhs)) {
|
||
// both arrays (or sequences)
|
||
// must be the same length
|
||
if (lhs.length !== rhs.length) {
|
||
return false;
|
||
}
|
||
// must contain same values in same order
|
||
for (var ii = 0; ii < lhs.length; ii++) {
|
||
if (!isDeepEqual(lhs[ii], rhs[ii])) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
// both objects
|
||
// must have the same set of keys (in any order)
|
||
var lkeys = Object.getOwnPropertyNames(lhs);
|
||
var rkeys = Object.getOwnPropertyNames(rhs);
|
||
if (lkeys.length !== rkeys.length) {
|
||
return false;
|
||
}
|
||
lkeys = lkeys.sort();
|
||
rkeys = rkeys.sort();
|
||
for (ii = 0; ii < lkeys.length; ii++) {
|
||
if (lkeys[ii] !== rkeys[ii]) {
|
||
return false;
|
||
}
|
||
}
|
||
// must have the same values
|
||
for (ii = 0; ii < lkeys.length; ii++) {
|
||
var key = lkeys[ii];
|
||
if (!isDeepEqual(lhs[key], rhs[key])) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* @param {Object} arg - expression to test
|
||
* @returns {boolean} - true if it is a promise
|
||
*/
|
||
function isPromise(arg) {
|
||
return _typeof(arg) === 'object' && arg !== null && 'then' in arg && typeof arg.then === 'function';
|
||
}
|
||
|
||
/**
|
||
* converts a string to an array of characters
|
||
* @param {string} str - the input string
|
||
* @returns {Array} - the array of characters
|
||
*/
|
||
function stringToArray(str) {
|
||
var arr = [];
|
||
var _iterator = _createForOfIteratorHelper(str),
|
||
_step;
|
||
try {
|
||
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
||
var _char = _step.value;
|
||
arr.push(_char);
|
||
}
|
||
} catch (err) {
|
||
_iterator.e(err);
|
||
} finally {
|
||
_iterator.f();
|
||
}
|
||
return arr;
|
||
}
|
||
return {
|
||
isNumeric: isNumeric,
|
||
isArrayOfStrings: isArrayOfStrings,
|
||
isArrayOfNumbers: isArrayOfNumbers,
|
||
createSequence: createSequence,
|
||
isSequence: isSequence,
|
||
isFunction: isFunction,
|
||
isLambda: isLambda,
|
||
isIterable: isIterable,
|
||
getFunctionArity: getFunctionArity,
|
||
isDeepEqual: isDeepEqual,
|
||
stringToArray: stringToArray,
|
||
isPromise: isPromise
|
||
};
|
||
}();
|
||
module.exports = utils;
|
||
},{}]},{},[3])(3)
|
||
});
|