module.exports = /******/ (function(modules, runtime) { // webpackBootstrap /******/ "use strict"; /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ __webpack_require__.ab = __dirname + "/"; /******/ /******/ // the startup function /******/ function startup() { /******/ // Load entry module and return exports /******/ return __webpack_require__(492); /******/ }; /******/ /******/ // run startup /******/ return startup(); /******/ }) /************************************************************************/ /******/ ({ /***/ 9: /***/ (function(module, __unusedexports, __webpack_require__) { var once = __webpack_require__(49); var noop = function() {}; var isRequest = function(stream) { return stream.setHeader && typeof stream.abort === 'function'; }; var isChildProcess = function(stream) { return stream.stdio && Array.isArray(stream.stdio) && stream.stdio.length === 3 }; var eos = function(stream, opts, callback) { if (typeof opts === 'function') return eos(stream, null, opts); if (!opts) opts = {}; callback = once(callback || noop); var ws = stream._writableState; var rs = stream._readableState; var readable = opts.readable || (opts.readable !== false && stream.readable); var writable = opts.writable || (opts.writable !== false && stream.writable); var onlegacyfinish = function() { if (!stream.writable) onfinish(); }; var onfinish = function() { writable = false; if (!readable) callback.call(stream); }; var onend = function() { readable = false; if (!writable) callback.call(stream); }; var onexit = function(exitCode) { callback.call(stream, exitCode ? new Error('exited with error code: ' + exitCode) : null); }; var onerror = function(err) { callback.call(stream, err); }; var onclose = function() { if (readable && !(rs && rs.ended)) return callback.call(stream, new Error('premature close')); if (writable && !(ws && ws.ended)) return callback.call(stream, new Error('premature close')); }; var onrequest = function() { stream.req.on('finish', onfinish); }; if (isRequest(stream)) { stream.on('complete', onfinish); stream.on('abort', onclose); if (stream.req) onrequest(); else stream.on('request', onrequest); } else if (writable && !ws) { // legacy streams stream.on('end', onlegacyfinish); stream.on('close', onlegacyfinish); } if (isChildProcess(stream)) stream.on('exit', onexit); stream.on('end', onend); stream.on('finish', onfinish); if (opts.error !== false) stream.on('error', onerror); stream.on('close', onclose); return function() { stream.removeListener('complete', onfinish); stream.removeListener('abort', onclose); stream.removeListener('request', onrequest); if (stream.req) stream.req.removeListener('finish', onfinish); stream.removeListener('end', onlegacyfinish); stream.removeListener('close', onlegacyfinish); stream.removeListener('finish', onfinish); stream.removeListener('exit', onexit); stream.removeListener('end', onend); stream.removeListener('error', onerror); stream.removeListener('close', onclose); }; }; module.exports = eos; /***/ }), /***/ 10: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const is_1 = __webpack_require__(534); exports.default = (url) => { // Cast to URL url = url; const options = { protocol: url.protocol, hostname: is_1.default.string(url.hostname) && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, host: url.host, hash: url.hash, search: url.search, pathname: url.pathname, href: url.href, path: `${url.pathname || ''}${url.search || ''}` }; if (is_1.default.string(url.port) && url.port.length !== 0) { options.port = Number(url.port); } if (url.username || url.password) { options.auth = `${url.username || ''}:${url.password || ''}`; } return options; }; /***/ }), /***/ 11: /***/ (function(module) { // Returns a wrapper function that returns a wrapped callback // The wrapper function should do some stuff, and return a // presumably different callback function. // This makes sure that own properties are retained, so that // decorations and such are not lost along the way. module.exports = wrappy function wrappy (fn, cb) { if (fn && cb) return wrappy(fn)(cb) if (typeof fn !== 'function') throw new TypeError('need wrapper function') Object.keys(fn).forEach(function (k) { wrapper[k] = fn[k] }) return wrapper function wrapper() { var args = new Array(arguments.length) for (var i = 0; i < args.length; i++) { args[i] = arguments[i] } var ret = fn.apply(this, args) var cb = args[args.length-1] if (typeof ret === 'function' && ret !== cb) { Object.keys(cb).forEach(function (k) { ret[k] = cb[k] }) } return ret } } /***/ }), /***/ 16: /***/ (function(module) { module.exports = require("tls"); /***/ }), /***/ 36: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CancelError = exports.ParseError = void 0; const p_cancelable_1 = __webpack_require__(557); Object.defineProperty(exports, "CancelError", { enumerable: true, get: function () { return p_cancelable_1.CancelError; } }); const core_1 = __webpack_require__(946); class ParseError extends core_1.RequestError { constructor(error, response) { const { options } = response.request; super(`${error.message} in "${options.url.toString()}"`, error, response.request); this.name = 'ParseError'; Object.defineProperty(this, 'response', { enumerable: false, value: response }); } } exports.ParseError = ParseError; __exportStar(__webpack_require__(946), exports); /***/ }), /***/ 48: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); class WeakableMap { constructor() { this.weakMap = new WeakMap(); this.map = new Map(); } set(key, value) { if (typeof key === 'object') { this.weakMap.set(key, value); } else { this.map.set(key, value); } } get(key) { if (typeof key === 'object') { return this.weakMap.get(key); } return this.map.get(key); } has(key) { if (typeof key === 'object') { return this.weakMap.has(key); } return this.map.has(key); } } exports.default = WeakableMap; /***/ }), /***/ 49: /***/ (function(module, __unusedexports, __webpack_require__) { var wrappy = __webpack_require__(11) module.exports = wrappy(once) module.exports.strict = wrappy(onceStrict) once.proto = once(function () { Object.defineProperty(Function.prototype, 'once', { value: function () { return once(this) }, configurable: true }) Object.defineProperty(Function.prototype, 'onceStrict', { value: function () { return onceStrict(this) }, configurable: true }) }) function once (fn) { var f = function () { if (f.called) return f.value f.called = true return f.value = fn.apply(this, arguments) } f.called = false return f } function onceStrict (fn) { var f = function () { if (f.called) throw new Error(f.onceError) f.called = true return f.value = fn.apply(this, arguments) } var name = fn.name || 'Function wrapped with `once`' f.onceError = name + " shouldn't be called more than once" f.called = false return f } /***/ }), /***/ 53: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; // TODO: Use the `URL` global when targeting Node.js 10 const URLParser = typeof URL === 'undefined' ? __webpack_require__(835).URL : URL; // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs const DATA_URL_DEFAULT_MIME_TYPE = 'text/plain'; const DATA_URL_DEFAULT_CHARSET = 'us-ascii'; const testParameter = (name, filters) => { return filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name); }; const normalizeDataURL = (urlString, {stripHash}) => { const parts = urlString.match(/^data:(.*?),(.*?)(?:#(.*))?$/); if (!parts) { throw new Error(`Invalid URL: ${urlString}`); } const mediaType = parts[1].split(';'); const body = parts[2]; const hash = stripHash ? '' : parts[3]; let base64 = false; if (mediaType[mediaType.length - 1] === 'base64') { mediaType.pop(); base64 = true; } // Lowercase MIME type const mimeType = (mediaType.shift() || '').toLowerCase(); const attributes = mediaType .map(attribute => { let [key, value = ''] = attribute.split('=').map(string => string.trim()); // Lowercase `charset` if (key === 'charset') { value = value.toLowerCase(); if (value === DATA_URL_DEFAULT_CHARSET) { return ''; } } return `${key}${value ? `=${value}` : ''}`; }) .filter(Boolean); const normalizedMediaType = [ ...attributes ]; if (base64) { normalizedMediaType.push('base64'); } if (normalizedMediaType.length !== 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) { normalizedMediaType.unshift(mimeType); } return `data:${normalizedMediaType.join(';')},${base64 ? body.trim() : body}${hash ? `#${hash}` : ''}`; }; const normalizeUrl = (urlString, options) => { options = { defaultProtocol: 'http:', normalizeProtocol: true, forceHttp: false, forceHttps: false, stripAuthentication: true, stripHash: false, stripWWW: true, removeQueryParameters: [/^utm_\w+/i], removeTrailingSlash: true, removeDirectoryIndex: false, sortQueryParameters: true, ...options }; // TODO: Remove this at some point in the future if (Reflect.has(options, 'normalizeHttps')) { throw new Error('options.normalizeHttps is renamed to options.forceHttp'); } if (Reflect.has(options, 'normalizeHttp')) { throw new Error('options.normalizeHttp is renamed to options.forceHttps'); } if (Reflect.has(options, 'stripFragment')) { throw new Error('options.stripFragment is renamed to options.stripHash'); } urlString = urlString.trim(); // Data URL if (/^data:/i.test(urlString)) { return normalizeDataURL(urlString, options); } const hasRelativeProtocol = urlString.startsWith('//'); const isRelativeUrl = !hasRelativeProtocol && /^\.*\//.test(urlString); // Prepend protocol if (!isRelativeUrl) { urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, options.defaultProtocol); } const urlObj = new URLParser(urlString); if (options.forceHttp && options.forceHttps) { throw new Error('The `forceHttp` and `forceHttps` options cannot be used together'); } if (options.forceHttp && urlObj.protocol === 'https:') { urlObj.protocol = 'http:'; } if (options.forceHttps && urlObj.protocol === 'http:') { urlObj.protocol = 'https:'; } // Remove auth if (options.stripAuthentication) { urlObj.username = ''; urlObj.password = ''; } // Remove hash if (options.stripHash) { urlObj.hash = ''; } // Remove duplicate slashes if not preceded by a protocol if (urlObj.pathname) { // TODO: Use the following instead when targeting Node.js 10 // `urlObj.pathname = urlObj.pathname.replace(/(? { if (/^(?!\/)/g.test(p1)) { return `${p1}/`; } return '/'; }); } // Decode URI octets if (urlObj.pathname) { urlObj.pathname = decodeURI(urlObj.pathname); } // Remove directory index if (options.removeDirectoryIndex === true) { options.removeDirectoryIndex = [/^index\.[a-z]+$/]; } if (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) { let pathComponents = urlObj.pathname.split('/'); const lastComponent = pathComponents[pathComponents.length - 1]; if (testParameter(lastComponent, options.removeDirectoryIndex)) { pathComponents = pathComponents.slice(0, pathComponents.length - 1); urlObj.pathname = pathComponents.slice(1).join('/') + '/'; } } if (urlObj.hostname) { // Remove trailing dot urlObj.hostname = urlObj.hostname.replace(/\.$/, ''); // Remove `www.` if (options.stripWWW && /^www\.([a-z\-\d]{2,63})\.([a-z.]{2,5})$/.test(urlObj.hostname)) { // Each label should be max 63 at length (min: 2). // The extension should be max 5 at length (min: 2). // Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names urlObj.hostname = urlObj.hostname.replace(/^www\./, ''); } } // Remove query unwanted parameters if (Array.isArray(options.removeQueryParameters)) { for (const key of [...urlObj.searchParams.keys()]) { if (testParameter(key, options.removeQueryParameters)) { urlObj.searchParams.delete(key); } } } // Sort query parameters if (options.sortQueryParameters) { urlObj.searchParams.sort(); } if (options.removeTrailingSlash) { urlObj.pathname = urlObj.pathname.replace(/\/$/, ''); } // Take advantage of many of the Node `url` normalizations urlString = urlObj.toString(); // Remove ending `/` if ((options.removeTrailingSlash || urlObj.pathname === '/') && urlObj.hash === '') { urlString = urlString.replace(/\/$/, ''); } // Restore relative protocol, if applicable if (hasRelativeProtocol && !options.normalizeProtocol) { urlString = urlString.replace(/^http:\/\//, '//'); } // Remove http/https if (options.stripProtocol) { urlString = urlString.replace(/^(?:https?:)?\/\//, ''); } return urlString; }; module.exports = normalizeUrl; // TODO: Remove this for the next major release module.exports.default = normalizeUrl; /***/ }), /***/ 77: /***/ (function(module, exports, __webpack_require__) { "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); const url_1 = __webpack_require__(835); const create_1 = __webpack_require__(323); const defaults = { options: { method: 'GET', retry: { limit: 2, methods: [ 'GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE' ], statusCodes: [ 408, 413, 429, 500, 502, 503, 504, 521, 522, 524 ], errorCodes: [ 'ETIMEDOUT', 'ECONNRESET', 'EADDRINUSE', 'ECONNREFUSED', 'EPIPE', 'ENOTFOUND', 'ENETUNREACH', 'EAI_AGAIN' ], maxRetryAfter: undefined, calculateDelay: ({ computedValue }) => computedValue }, timeout: {}, headers: { 'user-agent': 'got (https://github.com/sindresorhus/got)' }, hooks: { init: [], beforeRequest: [], beforeRedirect: [], beforeRetry: [], beforeError: [], afterResponse: [] }, cache: undefined, dnsCache: undefined, decompress: true, throwHttpErrors: true, followRedirect: true, isStream: false, responseType: 'text', resolveBodyOnly: false, maxRedirects: 10, prefixUrl: '', methodRewriting: true, ignoreInvalidCookies: false, context: {}, // TODO: Set this to `true` when Got 12 gets released http2: false, allowGetBody: false, https: undefined, pagination: { transform: (response) => { if (response.request.options.responseType === 'json') { return response.body; } return JSON.parse(response.body); }, paginate: response => { if (!Reflect.has(response.headers, 'link')) { return false; } const items = response.headers.link.split(','); let next; for (const item of items) { const parsed = item.split(';'); if (parsed[1].includes('next')) { next = parsed[0].trimStart().trim(); next = next.slice(1, -1); break; } } if (next) { const options = { url: new url_1.URL(next) }; return options; } return false; }, filter: () => true, shouldContinue: () => true, countLimit: Infinity, backoff: 0, requestLimit: 10000, stackAllItems: true }, parseJson: (text) => JSON.parse(text), stringifyJson: (object) => JSON.stringify(object) }, handlers: [create_1.defaultHandler], mutableDefaults: false }; const got = create_1.default(defaults); exports.default = got; // For CommonJS default export support module.exports = got; module.exports.default = got; module.exports.__esModule = true; // Workaround for TS issue: https://github.com/sindresorhus/got/pull/1267 __exportStar(__webpack_require__(323), exports); __exportStar(__webpack_require__(577), exports); /***/ }), /***/ 87: /***/ (function(module) { module.exports = require("os"); /***/ }), /***/ 89: /***/ (function(module) { "use strict"; // We define these manually to ensure they're always copied // even if they would move up the prototype chain // https://nodejs.org/api/http.html#http_class_http_incomingmessage const knownProps = [ 'destroy', 'setTimeout', 'socket', 'headers', 'trailers', 'rawHeaders', 'statusCode', 'httpVersion', 'httpVersionMinor', 'httpVersionMajor', 'rawTrailers', 'statusMessage' ]; module.exports = (fromStream, toStream) => { const fromProps = new Set(Object.keys(fromStream).concat(knownProps)); for (const prop of fromProps) { // Don't overwrite existing properties if (prop in toStream) { continue; } toStream[prop] = typeof fromStream[prop] === 'function' ? fromStream[prop].bind(fromStream) : fromStream[prop]; } }; /***/ }), /***/ 93: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const Readable = __webpack_require__(413).Readable; const lowercaseKeys = __webpack_require__(474); class Response extends Readable { constructor(statusCode, headers, body, url) { if (typeof statusCode !== 'number') { throw new TypeError('Argument `statusCode` should be a number'); } if (typeof headers !== 'object') { throw new TypeError('Argument `headers` should be an object'); } if (!(body instanceof Buffer)) { throw new TypeError('Argument `body` should be a buffer'); } if (typeof url !== 'string') { throw new TypeError('Argument `url` should be a string'); } super(); this.statusCode = statusCode; this.headers = lowercaseKeys(headers); this.body = body; this.url = url; } _read() { this.push(this.body); this.push(null); } } module.exports = Response; /***/ }), /***/ 151: /***/ (function(module, __unusedexports, __webpack_require__) { // @ts-check const core = __webpack_require__(470); /*** * Authenticate with Vault and retrieve a Vault token that can be used for requests. * @param {string} method * @param {import('got').Got} client */ async function retrieveToken(method, client) { switch (method) { case 'approle': { const vaultRoleId = core.getInput('roleId', { required: true }); const vaultSecretId = core.getInput('secretId', { required: true }); return await getClientToken(client, method, { role_id: vaultRoleId, secret_id: vaultSecretId }); } case 'github': { const githubToken = core.getInput('githubToken', { required: true }); return await getClientToken(client, method, { token: githubToken }); } default: { if (!method || method === 'token') { return core.getInput('token', { required: true }); } else { /** @type {string} */ const payload = core.getInput('authPayload', { required: true }); if (!payload) { throw Error('When using a custom authentication method, you must provide the payload'); } return await getClientToken(client, method, JSON.parse(payload.trim())); } } } } /*** * Call the appropriate login endpoint and parse out the token in the response. * @param {import('got').Got} client * @param {string} method * @param {any} payload */ async function getClientToken(client, method, payload) { /** @type {'json'} */ const responseType = 'json'; var options = { json: payload, responseType, }; core.debug(`Retrieving Vault Token from v1/auth/${method}/login endpoint`); /** @type {import('got').Response} */ const response = await client.post(`v1/auth/${method}/login`, options); if (response && response.body && response.body.auth && response.body.auth.client_token) { core.debug('✔ Vault Token successfully retrieved'); core.startGroup('Token Info'); core.debug(`Operating under policies: ${JSON.stringify(response.body.auth.policies)}`); core.debug(`Token Metadata: ${JSON.stringify(response.body.auth.metadata)}`); core.endGroup(); return response.body.auth.client_token; } else { throw Error(`Unable to retrieve token from ${method}'s login endpoint.`); } } /*** * @typedef {Object} VaultLoginResponse * @property {{ * client_token: string; * accessor: string; * policies: string[]; * metadata: unknown; * lease_duration: number; * renewable: boolean; * }} auth */ module.exports = { retrieveToken, }; /***/ }), /***/ 154: /***/ (function(module) { "use strict"; // rfc7231 6.1 const statusCodeCacheableByDefault = new Set([ 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501, ]); // This implementation does not understand partial responses (206) const understoodStatuses = new Set([ 200, 203, 204, 300, 301, 302, 303, 307, 308, 404, 405, 410, 414, 501, ]); const errorStatusCodes = new Set([ 500, 502, 503, 504, ]); const hopByHopHeaders = { date: true, // included, because we add Age update Date connection: true, 'keep-alive': true, 'proxy-authenticate': true, 'proxy-authorization': true, te: true, trailer: true, 'transfer-encoding': true, upgrade: true, }; const excludedFromRevalidationUpdate = { // Since the old body is reused, it doesn't make sense to change properties of the body 'content-length': true, 'content-encoding': true, 'transfer-encoding': true, 'content-range': true, }; function toNumberOrZero(s) { const n = parseInt(s, 10); return isFinite(n) ? n : 0; } // RFC 5861 function isErrorResponse(response) { // consider undefined response as faulty if(!response) { return true } return errorStatusCodes.has(response.status); } function parseCacheControl(header) { const cc = {}; if (!header) return cc; // TODO: When there is more than one value present for a given directive (e.g., two Expires header fields, multiple Cache-Control: max-age directives), // the directive's value is considered invalid. Caches are encouraged to consider responses that have invalid freshness information to be stale const parts = header.trim().split(/\s*,\s*/); // TODO: lame parsing for (const part of parts) { const [k, v] = part.split(/\s*=\s*/, 2); cc[k] = v === undefined ? true : v.replace(/^"|"$/g, ''); // TODO: lame unquoting } return cc; } function formatCacheControl(cc) { let parts = []; for (const k in cc) { const v = cc[k]; parts.push(v === true ? k : k + '=' + v); } if (!parts.length) { return undefined; } return parts.join(', '); } module.exports = class CachePolicy { constructor( req, res, { shared, cacheHeuristic, immutableMinTimeToLive, ignoreCargoCult, _fromObject, } = {} ) { if (_fromObject) { this._fromObject(_fromObject); return; } if (!res || !res.headers) { throw Error('Response headers missing'); } this._assertRequestHasHeaders(req); this._responseTime = this.now(); this._isShared = shared !== false; this._cacheHeuristic = undefined !== cacheHeuristic ? cacheHeuristic : 0.1; // 10% matches IE this._immutableMinTtl = undefined !== immutableMinTimeToLive ? immutableMinTimeToLive : 24 * 3600 * 1000; this._status = 'status' in res ? res.status : 200; this._resHeaders = res.headers; this._rescc = parseCacheControl(res.headers['cache-control']); this._method = 'method' in req ? req.method : 'GET'; this._url = req.url; this._host = req.headers.host; this._noAuthorization = !req.headers.authorization; this._reqHeaders = res.headers.vary ? req.headers : null; // Don't keep all request headers if they won't be used this._reqcc = parseCacheControl(req.headers['cache-control']); // Assume that if someone uses legacy, non-standard uncecessary options they don't understand caching, // so there's no point stricly adhering to the blindly copy&pasted directives. if ( ignoreCargoCult && 'pre-check' in this._rescc && 'post-check' in this._rescc ) { delete this._rescc['pre-check']; delete this._rescc['post-check']; delete this._rescc['no-cache']; delete this._rescc['no-store']; delete this._rescc['must-revalidate']; this._resHeaders = Object.assign({}, this._resHeaders, { 'cache-control': formatCacheControl(this._rescc), }); delete this._resHeaders.expires; delete this._resHeaders.pragma; } // When the Cache-Control header field is not present in a request, caches MUST consider the no-cache request pragma-directive // as having the same effect as if "Cache-Control: no-cache" were present (see Section 5.2.1). if ( res.headers['cache-control'] == null && /no-cache/.test(res.headers.pragma) ) { this._rescc['no-cache'] = true; } } now() { return Date.now(); } storable() { // The "no-store" request directive indicates that a cache MUST NOT store any part of either this request or any response to it. return !!( !this._reqcc['no-store'] && // A cache MUST NOT store a response to any request, unless: // The request method is understood by the cache and defined as being cacheable, and ('GET' === this._method || 'HEAD' === this._method || ('POST' === this._method && this._hasExplicitExpiration())) && // the response status code is understood by the cache, and understoodStatuses.has(this._status) && // the "no-store" cache directive does not appear in request or response header fields, and !this._rescc['no-store'] && // the "private" response directive does not appear in the response, if the cache is shared, and (!this._isShared || !this._rescc.private) && // the Authorization header field does not appear in the request, if the cache is shared, (!this._isShared || this._noAuthorization || this._allowsStoringAuthenticated()) && // the response either: // contains an Expires header field, or (this._resHeaders.expires || // contains a max-age response directive, or // contains a s-maxage response directive and the cache is shared, or // contains a public response directive. this._rescc['max-age'] || (this._isShared && this._rescc['s-maxage']) || this._rescc.public || // has a status code that is defined as cacheable by default statusCodeCacheableByDefault.has(this._status)) ); } _hasExplicitExpiration() { // 4.2.1 Calculating Freshness Lifetime return ( (this._isShared && this._rescc['s-maxage']) || this._rescc['max-age'] || this._resHeaders.expires ); } _assertRequestHasHeaders(req) { if (!req || !req.headers) { throw Error('Request headers missing'); } } satisfiesWithoutRevalidation(req) { this._assertRequestHasHeaders(req); // When presented with a request, a cache MUST NOT reuse a stored response, unless: // the presented request does not contain the no-cache pragma (Section 5.4), nor the no-cache cache directive, // unless the stored response is successfully validated (Section 4.3), and const requestCC = parseCacheControl(req.headers['cache-control']); if (requestCC['no-cache'] || /no-cache/.test(req.headers.pragma)) { return false; } if (requestCC['max-age'] && this.age() > requestCC['max-age']) { return false; } if ( requestCC['min-fresh'] && this.timeToLive() < 1000 * requestCC['min-fresh'] ) { return false; } // the stored response is either: // fresh, or allowed to be served stale if (this.stale()) { const allowsStale = requestCC['max-stale'] && !this._rescc['must-revalidate'] && (true === requestCC['max-stale'] || requestCC['max-stale'] > this.age() - this.maxAge()); if (!allowsStale) { return false; } } return this._requestMatches(req, false); } _requestMatches(req, allowHeadMethod) { // The presented effective request URI and that of the stored response match, and return ( (!this._url || this._url === req.url) && this._host === req.headers.host && // the request method associated with the stored response allows it to be used for the presented request, and (!req.method || this._method === req.method || (allowHeadMethod && 'HEAD' === req.method)) && // selecting header fields nominated by the stored response (if any) match those presented, and this._varyMatches(req) ); } _allowsStoringAuthenticated() { // following Cache-Control response directives (Section 5.2.2) have such an effect: must-revalidate, public, and s-maxage. return ( this._rescc['must-revalidate'] || this._rescc.public || this._rescc['s-maxage'] ); } _varyMatches(req) { if (!this._resHeaders.vary) { return true; } // A Vary header field-value of "*" always fails to match if (this._resHeaders.vary === '*') { return false; } const fields = this._resHeaders.vary .trim() .toLowerCase() .split(/\s*,\s*/); for (const name of fields) { if (req.headers[name] !== this._reqHeaders[name]) return false; } return true; } _copyWithoutHopByHopHeaders(inHeaders) { const headers = {}; for (const name in inHeaders) { if (hopByHopHeaders[name]) continue; headers[name] = inHeaders[name]; } // 9.1. Connection if (inHeaders.connection) { const tokens = inHeaders.connection.trim().split(/\s*,\s*/); for (const name of tokens) { delete headers[name]; } } if (headers.warning) { const warnings = headers.warning.split(/,/).filter(warning => { return !/^\s*1[0-9][0-9]/.test(warning); }); if (!warnings.length) { delete headers.warning; } else { headers.warning = warnings.join(',').trim(); } } return headers; } responseHeaders() { const headers = this._copyWithoutHopByHopHeaders(this._resHeaders); const age = this.age(); // A cache SHOULD generate 113 warning if it heuristically chose a freshness // lifetime greater than 24 hours and the response's age is greater than 24 hours. if ( age > 3600 * 24 && !this._hasExplicitExpiration() && this.maxAge() > 3600 * 24 ) { headers.warning = (headers.warning ? `${headers.warning}, ` : '') + '113 - "rfc7234 5.5.4"'; } headers.age = `${Math.round(age)}`; headers.date = new Date(this.now()).toUTCString(); return headers; } /** * Value of the Date response header or current time if Date was invalid * @return timestamp */ date() { const serverDate = Date.parse(this._resHeaders.date); if (isFinite(serverDate)) { return serverDate; } return this._responseTime; } /** * Value of the Age header, in seconds, updated for the current time. * May be fractional. * * @return Number */ age() { let age = this._ageValue(); const residentTime = (this.now() - this._responseTime) / 1000; return age + residentTime; } _ageValue() { return toNumberOrZero(this._resHeaders.age); } /** * Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`. * * For an up-to-date value, see `timeToLive()`. * * @return Number */ maxAge() { if (!this.storable() || this._rescc['no-cache']) { return 0; } // Shared responses with cookies are cacheable according to the RFC, but IMHO it'd be unwise to do so by default // so this implementation requires explicit opt-in via public header if ( this._isShared && (this._resHeaders['set-cookie'] && !this._rescc.public && !this._rescc.immutable) ) { return 0; } if (this._resHeaders.vary === '*') { return 0; } if (this._isShared) { if (this._rescc['proxy-revalidate']) { return 0; } // if a response includes the s-maxage directive, a shared cache recipient MUST ignore the Expires field. if (this._rescc['s-maxage']) { return toNumberOrZero(this._rescc['s-maxage']); } } // If a response includes a Cache-Control field with the max-age directive, a recipient MUST ignore the Expires field. if (this._rescc['max-age']) { return toNumberOrZero(this._rescc['max-age']); } const defaultMinTtl = this._rescc.immutable ? this._immutableMinTtl : 0; const serverDate = this.date(); if (this._resHeaders.expires) { const expires = Date.parse(this._resHeaders.expires); // A cache recipient MUST interpret invalid date formats, especially the value "0", as representing a time in the past (i.e., "already expired"). if (Number.isNaN(expires) || expires < serverDate) { return 0; } return Math.max(defaultMinTtl, (expires - serverDate) / 1000); } if (this._resHeaders['last-modified']) { const lastModified = Date.parse(this._resHeaders['last-modified']); if (isFinite(lastModified) && serverDate > lastModified) { return Math.max( defaultMinTtl, ((serverDate - lastModified) / 1000) * this._cacheHeuristic ); } } return defaultMinTtl; } timeToLive() { const age = this.maxAge() - this.age(); const staleIfErrorAge = age + toNumberOrZero(this._rescc['stale-if-error']); const staleWhileRevalidateAge = age + toNumberOrZero(this._rescc['stale-while-revalidate']); return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1000; } stale() { return this.maxAge() <= this.age(); } _useStaleIfError() { return this.maxAge() + toNumberOrZero(this._rescc['stale-if-error']) > this.age(); } useStaleWhileRevalidate() { return this.maxAge() + toNumberOrZero(this._rescc['stale-while-revalidate']) > this.age(); } static fromObject(obj) { return new this(undefined, undefined, { _fromObject: obj }); } _fromObject(obj) { if (this._responseTime) throw Error('Reinitialized'); if (!obj || obj.v !== 1) throw Error('Invalid serialization'); this._responseTime = obj.t; this._isShared = obj.sh; this._cacheHeuristic = obj.ch; this._immutableMinTtl = obj.imm !== undefined ? obj.imm : 24 * 3600 * 1000; this._status = obj.st; this._resHeaders = obj.resh; this._rescc = obj.rescc; this._method = obj.m; this._url = obj.u; this._host = obj.h; this._noAuthorization = obj.a; this._reqHeaders = obj.reqh; this._reqcc = obj.reqcc; } toObject() { return { v: 1, t: this._responseTime, sh: this._isShared, ch: this._cacheHeuristic, imm: this._immutableMinTtl, st: this._status, resh: this._resHeaders, rescc: this._rescc, m: this._method, u: this._url, h: this._host, a: this._noAuthorization, reqh: this._reqHeaders, reqcc: this._reqcc, }; } /** * Headers for sending to the origin server to revalidate stale response. * Allows server to return 304 to allow reuse of the previous response. * * Hop by hop headers are always stripped. * Revalidation headers may be added or removed, depending on request. */ revalidationHeaders(incomingReq) { this._assertRequestHasHeaders(incomingReq); const headers = this._copyWithoutHopByHopHeaders(incomingReq.headers); // This implementation does not understand range requests delete headers['if-range']; if (!this._requestMatches(incomingReq, true) || !this.storable()) { // revalidation allowed via HEAD // not for the same resource, or wasn't allowed to be cached anyway delete headers['if-none-match']; delete headers['if-modified-since']; return headers; } /* MUST send that entity-tag in any cache validation request (using If-Match or If-None-Match) if an entity-tag has been provided by the origin server. */ if (this._resHeaders.etag) { headers['if-none-match'] = headers['if-none-match'] ? `${headers['if-none-match']}, ${this._resHeaders.etag}` : this._resHeaders.etag; } // Clients MAY issue simple (non-subrange) GET requests with either weak validators or strong validators. Clients MUST NOT use weak validators in other forms of request. const forbidsWeakValidators = headers['accept-ranges'] || headers['if-match'] || headers['if-unmodified-since'] || (this._method && this._method != 'GET'); /* SHOULD send the Last-Modified value in non-subrange cache validation requests (using If-Modified-Since) if only a Last-Modified value has been provided by the origin server. Note: This implementation does not understand partial responses (206) */ if (forbidsWeakValidators) { delete headers['if-modified-since']; if (headers['if-none-match']) { const etags = headers['if-none-match'] .split(/,/) .filter(etag => { return !/^\s*W\//.test(etag); }); if (!etags.length) { delete headers['if-none-match']; } else { headers['if-none-match'] = etags.join(',').trim(); } } } else if ( this._resHeaders['last-modified'] && !headers['if-modified-since'] ) { headers['if-modified-since'] = this._resHeaders['last-modified']; } return headers; } /** * Creates new CachePolicy with information combined from the previews response, * and the new revalidation response. * * Returns {policy, modified} where modified is a boolean indicating * whether the response body has been modified, and old cached body can't be used. * * @return {Object} {policy: CachePolicy, modified: Boolean} */ revalidatedPolicy(request, response) { this._assertRequestHasHeaders(request); if(this._useStaleIfError() && isErrorResponse(response)) { // I consider the revalidation request unsuccessful return { modified: false, matches: false, policy: this, }; } if (!response || !response.headers) { throw Error('Response headers missing'); } // These aren't going to be supported exactly, since one CachePolicy object // doesn't know about all the other cached objects. let matches = false; if (response.status !== undefined && response.status != 304) { matches = false; } else if ( response.headers.etag && !/^\s*W\//.test(response.headers.etag) ) { // "All of the stored responses with the same strong validator are selected. // If none of the stored responses contain the same strong validator, // then the cache MUST NOT use the new response to update any stored responses." matches = this._resHeaders.etag && this._resHeaders.etag.replace(/^\s*W\//, '') === response.headers.etag; } else if (this._resHeaders.etag && response.headers.etag) { // "If the new response contains a weak validator and that validator corresponds // to one of the cache's stored responses, // then the most recent of those matching stored responses is selected for update." matches = this._resHeaders.etag.replace(/^\s*W\//, '') === response.headers.etag.replace(/^\s*W\//, ''); } else if (this._resHeaders['last-modified']) { matches = this._resHeaders['last-modified'] === response.headers['last-modified']; } else { // If the new response does not include any form of validator (such as in the case where // a client generates an If-Modified-Since request from a source other than the Last-Modified // response header field), and there is only one stored response, and that stored response also // lacks a validator, then that stored response is selected for update. if ( !this._resHeaders.etag && !this._resHeaders['last-modified'] && !response.headers.etag && !response.headers['last-modified'] ) { matches = true; } } if (!matches) { return { policy: new this.constructor(request, response), // Client receiving 304 without body, even if it's invalid/mismatched has no option // but to reuse a cached body. We don't have a good way to tell clients to do // error recovery in such case. modified: response.status != 304, matches: false, }; } // use other header fields provided in the 304 (Not Modified) response to replace all instances // of the corresponding header fields in the stored response. const headers = {}; for (const k in this._resHeaders) { headers[k] = k in response.headers && !excludedFromRevalidationUpdate[k] ? response.headers[k] : this._resHeaders[k]; } const newResponse = Object.assign({}, response, { status: this._status, method: this._method, headers, }); return { policy: new this.constructor(request, newResponse, { shared: this._isShared, cacheHeuristic: this._cacheHeuristic, immutableMinTimeToLive: this._immutableMinTtl, }), modified: false, matches: true, }; } }; /***/ }), /***/ 157: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const http2 = __webpack_require__(565); const agent = __webpack_require__(899); const ClientRequest = __webpack_require__(181); const IncomingMessage = __webpack_require__(750); const auto = __webpack_require__(988); const request = (url, options, callback) => { return new ClientRequest(url, options, callback); }; const get = (url, options, callback) => { // eslint-disable-next-line unicorn/prevent-abbreviations const req = new ClientRequest(url, options, callback); req.end(); return req; }; module.exports = { ...http2, ClientRequest, IncomingMessage, ...agent, request, get, auto }; /***/ }), /***/ 181: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const http2 = __webpack_require__(565); const {Writable} = __webpack_require__(413); const {Agent, globalAgent} = __webpack_require__(899); const IncomingMessage = __webpack_require__(750); const urlToOptions = __webpack_require__(507); const proxyEvents = __webpack_require__(231); const isRequestPseudoHeader = __webpack_require__(723); const { ERR_INVALID_ARG_TYPE, ERR_INVALID_PROTOCOL, ERR_HTTP_HEADERS_SENT, ERR_INVALID_HTTP_TOKEN, ERR_HTTP_INVALID_HEADER_VALUE, ERR_INVALID_CHAR } = __webpack_require__(699); const { HTTP2_HEADER_STATUS, HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_METHOD_CONNECT } = http2.constants; const kHeaders = Symbol('headers'); const kOrigin = Symbol('origin'); const kSession = Symbol('session'); const kOptions = Symbol('options'); const kFlushedHeaders = Symbol('flushedHeaders'); const kJobs = Symbol('jobs'); const isValidHttpToken = /^[\^`\-\w!#$%&*+.|~]+$/; const isInvalidHeaderValue = /[^\t\u0020-\u007E\u0080-\u00FF]/; class ClientRequest extends Writable { constructor(input, options, callback) { super({ autoDestroy: false }); const hasInput = typeof input === 'string' || input instanceof URL; if (hasInput) { input = urlToOptions(input instanceof URL ? input : new URL(input)); } if (typeof options === 'function' || options === undefined) { // (options, callback) callback = options; options = hasInput ? input : {...input}; } else { // (input, options, callback) options = {...input, ...options}; } if (options.h2session) { this[kSession] = options.h2session; } else if (options.agent === false) { this.agent = new Agent({maxFreeSessions: 0}); } else if (typeof options.agent === 'undefined' || options.agent === null) { if (typeof options.createConnection === 'function') { // This is a workaround - we don't have to create the session on our own. this.agent = new Agent({maxFreeSessions: 0}); this.agent.createConnection = options.createConnection; } else { this.agent = globalAgent; } } else if (typeof options.agent.request === 'function') { this.agent = options.agent; } else { throw new ERR_INVALID_ARG_TYPE('options.agent', ['Agent-like Object', 'undefined', 'false'], options.agent); } if (options.protocol && options.protocol !== 'https:') { throw new ERR_INVALID_PROTOCOL(options.protocol, 'https:'); } const port = options.port || options.defaultPort || (this.agent && this.agent.defaultPort) || 443; const host = options.hostname || options.host || 'localhost'; // Don't enforce the origin via options. It may be changed in an Agent. delete options.hostname; delete options.host; delete options.port; const {timeout} = options; options.timeout = undefined; this[kHeaders] = Object.create(null); this[kJobs] = []; this.socket = null; this.connection = null; this.method = options.method || 'GET'; this.path = options.path; this.res = null; this.aborted = false; this.reusedSocket = false; if (options.headers) { for (const [header, value] of Object.entries(options.headers)) { this.setHeader(header, value); } } if (options.auth && !('authorization' in this[kHeaders])) { this[kHeaders].authorization = 'Basic ' + Buffer.from(options.auth).toString('base64'); } options.session = options.tlsSession; options.path = options.socketPath; this[kOptions] = options; // Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field. if (port === 443) { this[kOrigin] = `https://${host}`; if (!(':authority' in this[kHeaders])) { this[kHeaders][':authority'] = host; } } else { this[kOrigin] = `https://${host}:${port}`; if (!(':authority' in this[kHeaders])) { this[kHeaders][':authority'] = `${host}:${port}`; } } if (timeout) { this.setTimeout(timeout); } if (callback) { this.once('response', callback); } this[kFlushedHeaders] = false; } get method() { return this[kHeaders][HTTP2_HEADER_METHOD]; } set method(value) { if (value) { this[kHeaders][HTTP2_HEADER_METHOD] = value.toUpperCase(); } } get path() { return this[kHeaders][HTTP2_HEADER_PATH]; } set path(value) { if (value) { this[kHeaders][HTTP2_HEADER_PATH] = value; } } get _mustNotHaveABody() { return this.method === 'GET' || this.method === 'HEAD' || this.method === 'DELETE'; } _write(chunk, encoding, callback) { // https://github.com/nodejs/node/blob/654df09ae0c5e17d1b52a900a545f0664d8c7627/lib/internal/http2/util.js#L148-L156 if (this._mustNotHaveABody) { callback(new Error('The GET, HEAD and DELETE methods must NOT have a body')); /* istanbul ignore next: Node.js 12 throws directly */ return; } this.flushHeaders(); const callWrite = () => this._request.write(chunk, encoding, callback); if (this._request) { callWrite(); } else { this[kJobs].push(callWrite); } } _final(callback) { if (this.destroyed) { return; } this.flushHeaders(); const callEnd = () => { // For GET, HEAD and DELETE if (this._mustNotHaveABody) { callback(); return; } this._request.end(callback); }; if (this._request) { callEnd(); } else { this[kJobs].push(callEnd); } } abort() { if (this.res && this.res.complete) { return; } if (!this.aborted) { process.nextTick(() => this.emit('abort')); } this.aborted = true; this.destroy(); } _destroy(error, callback) { if (this.res) { this.res._dump(); } if (this._request) { this._request.destroy(); } callback(error); } async flushHeaders() { if (this[kFlushedHeaders] || this.destroyed) { return; } this[kFlushedHeaders] = true; const isConnectMethod = this.method === HTTP2_METHOD_CONNECT; // The real magic is here const onStream = stream => { this._request = stream; if (this.destroyed) { stream.destroy(); return; } // Forwards `timeout`, `continue`, `close` and `error` events to this instance. if (!isConnectMethod) { proxyEvents(stream, this, ['timeout', 'continue', 'close', 'error']); } // Wait for the `finish` event. We don't want to emit the `response` event // before `request.end()` is called. const waitForEnd = fn => { return (...args) => { if (!this.writable && !this.destroyed) { fn(...args); } else { this.once('finish', () => { fn(...args); }); } }; }; // This event tells we are ready to listen for the data. stream.once('response', waitForEnd((headers, flags, rawHeaders) => { // If we were to emit raw request stream, it would be as fast as the native approach. // Note that wrapping the raw stream in a Proxy instance won't improve the performance (already tested it). const response = new IncomingMessage(this.socket, stream.readableHighWaterMark); this.res = response; response.req = this; response.statusCode = headers[HTTP2_HEADER_STATUS]; response.headers = headers; response.rawHeaders = rawHeaders; response.once('end', () => { if (this.aborted) { response.aborted = true; response.emit('aborted'); } else { response.complete = true; // Has no effect, just be consistent with the Node.js behavior response.socket = null; response.connection = null; } }); if (isConnectMethod) { response.upgrade = true; // The HTTP1 API says the socket is detached here, // but we can't do that so we pass the original HTTP2 request. if (this.emit('connect', response, stream, Buffer.alloc(0))) { this.emit('close'); } else { // No listeners attached, destroy the original request. stream.destroy(); } } else { // Forwards data stream.on('data', chunk => { if (!response._dumped && !response.push(chunk)) { stream.pause(); } }); stream.once('end', () => { response.push(null); }); if (!this.emit('response', response)) { // No listeners attached, dump the response. response._dump(); } } })); // Emits `information` event stream.once('headers', waitForEnd( headers => this.emit('information', {statusCode: headers[HTTP2_HEADER_STATUS]}) )); stream.once('trailers', waitForEnd((trailers, flags, rawTrailers) => { const {res} = this; // Assigns trailers to the response object. res.trailers = trailers; res.rawTrailers = rawTrailers; })); const {socket} = stream.session; this.socket = socket; this.connection = socket; for (const job of this[kJobs]) { job(); } this.emit('socket', this.socket); }; // Makes a HTTP2 request if (this[kSession]) { try { onStream(this[kSession].request(this[kHeaders])); } catch (error) { this.emit('error', error); } } else { this.reusedSocket = true; try { onStream(await this.agent.request(this[kOrigin], this[kOptions], this[kHeaders])); } catch (error) { this.emit('error', error); } } } getHeader(name) { if (typeof name !== 'string') { throw new ERR_INVALID_ARG_TYPE('name', 'string', name); } return this[kHeaders][name.toLowerCase()]; } get headersSent() { return this[kFlushedHeaders]; } removeHeader(name) { if (typeof name !== 'string') { throw new ERR_INVALID_ARG_TYPE('name', 'string', name); } if (this.headersSent) { throw new ERR_HTTP_HEADERS_SENT('remove'); } delete this[kHeaders][name.toLowerCase()]; } setHeader(name, value) { if (this.headersSent) { throw new ERR_HTTP_HEADERS_SENT('set'); } if (typeof name !== 'string' || (!isValidHttpToken.test(name) && !isRequestPseudoHeader(name))) { throw new ERR_INVALID_HTTP_TOKEN('Header name', name); } if (typeof value === 'undefined') { throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name); } if (isInvalidHeaderValue.test(value)) { throw new ERR_INVALID_CHAR('header content', name); } this[kHeaders][name.toLowerCase()] = value; } setNoDelay() { // HTTP2 sockets cannot be malformed, do nothing. } setSocketKeepAlive() { // HTTP2 sockets cannot be malformed, do nothing. } setTimeout(ms, callback) { const applyTimeout = () => this._request.setTimeout(ms, callback); if (this._request) { applyTimeout(); } else { this[kJobs].push(applyTimeout); } return this; } get maxHeadersCount() { if (!this.destroyed && this._request) { return this._request.session.localSettings.maxHeaderListSize; } return undefined; } set maxHeadersCount(_value) { // Updating HTTP2 settings would affect all requests, do nothing. } } module.exports = ClientRequest; /***/ }), /***/ 189: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const alreadyWarned = new Set(); exports.default = (message) => { if (alreadyWarned.has(message)) { return; } alreadyWarned.add(message); // @ts-expect-error Missing types. process.emitWarning(`Got: ${message}`, { type: 'DeprecationWarning' }); }; /***/ }), /***/ 205: /***/ (function(__unusedmodule, exports) { //TODO: handle reviver/dehydrate function like normal //and handle indentation, like normal. //if anyone needs this... please send pull request. exports.stringify = function stringify (o) { if('undefined' == typeof o) return o if(o && Buffer.isBuffer(o)) return JSON.stringify(':base64:' + o.toString('base64')) if(o && o.toJSON) o = o.toJSON() if(o && 'object' === typeof o) { var s = '' var array = Array.isArray(o) s = array ? '[' : '{' var first = true for(var k in o) { var ignore = 'function' == typeof o[k] || (!array && 'undefined' === typeof o[k]) if(Object.hasOwnProperty.call(o, k) && !ignore) { if(!first) s += ',' first = false if (array) { if(o[k] == undefined) s += 'null' else s += stringify(o[k]) } else if (o[k] !== void(0)) { s += stringify(k) + ':' + stringify(o[k]) } } } s += array ? ']' : '}' return s } else if ('string' === typeof o) { return JSON.stringify(/^:/.test(o) ? ':' + o : o) } else if ('undefined' === typeof o) { return 'null'; } else return JSON.stringify(o) } exports.parse = function (s) { return JSON.parse(s, function (key, value) { if('string' === typeof value) { if(/^:base64:/.test(value)) return Buffer.from(value.substring(8), 'base64') else return /^:/.test(value) ? value.substring(1) : value } return value }) } /***/ }), /***/ 211: /***/ (function(module) { module.exports = require("https"); /***/ }), /***/ 231: /***/ (function(module) { "use strict"; module.exports = (from, to, events) => { for (const event of events) { from.on(event, (...args) => to.emit(event, ...args)); } }; /***/ }), /***/ 291: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const is_1 = __webpack_require__(534); function deepFreeze(object) { for (const value of Object.values(object)) { if (is_1.default.plainObject(value) || is_1.default.array(value)) { deepFreeze(value); } } return Object.freeze(object); } exports.default = deepFreeze; /***/ }), /***/ 303: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const EventEmitter = __webpack_require__(614); const JSONB = __webpack_require__(205); const loadStore = opts => { const adapters = { redis: '@keyv/redis', mongodb: '@keyv/mongo', mongo: '@keyv/mongo', sqlite: '@keyv/sqlite', postgresql: '@keyv/postgres', postgres: '@keyv/postgres', mysql: '@keyv/mysql' }; if (opts.adapter || opts.uri) { const adapter = opts.adapter || /^[^:]*/.exec(opts.uri)[0]; return new (require(adapters[adapter]))(opts); } return new Map(); }; class Keyv extends EventEmitter { constructor(uri, opts) { super(); this.opts = Object.assign( { namespace: 'keyv', serialize: JSONB.stringify, deserialize: JSONB.parse }, (typeof uri === 'string') ? { uri } : uri, opts ); if (!this.opts.store) { const adapterOpts = Object.assign({}, this.opts); this.opts.store = loadStore(adapterOpts); } if (typeof this.opts.store.on === 'function') { this.opts.store.on('error', err => this.emit('error', err)); } this.opts.store.namespace = this.opts.namespace; } _getKeyPrefix(key) { return `${this.opts.namespace}:${key}`; } get(key, opts) { const keyPrefixed = this._getKeyPrefix(key); const { store } = this.opts; return Promise.resolve() .then(() => store.get(keyPrefixed)) .then(data => { return (typeof data === 'string') ? this.opts.deserialize(data) : data; }) .then(data => { if (data === undefined) { return undefined; } if (typeof data.expires === 'number' && Date.now() > data.expires) { this.delete(key); return undefined; } return (opts && opts.raw) ? data : data.value; }); } set(key, value, ttl) { const keyPrefixed = this._getKeyPrefix(key); if (typeof ttl === 'undefined') { ttl = this.opts.ttl; } if (ttl === 0) { ttl = undefined; } const { store } = this.opts; return Promise.resolve() .then(() => { const expires = (typeof ttl === 'number') ? (Date.now() + ttl) : null; value = { value, expires }; return this.opts.serialize(value); }) .then(value => store.set(keyPrefixed, value, ttl)) .then(() => true); } delete(key) { const keyPrefixed = this._getKeyPrefix(key); const { store } = this.opts; return Promise.resolve() .then(() => store.delete(keyPrefixed)); } clear() { const { store } = this.opts; return Promise.resolve() .then(() => store.clear()); } } module.exports = Keyv; /***/ }), /***/ 323: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultHandler = void 0; const p_cancelable_1 = __webpack_require__(557); const is_1 = __webpack_require__(534); const as_promise_1 = __webpack_require__(577); const create_rejection_1 = __webpack_require__(910); const core_1 = __webpack_require__(946); const deep_freeze_1 = __webpack_require__(291); const errors = { RequestError: as_promise_1.RequestError, CacheError: as_promise_1.CacheError, ReadError: as_promise_1.ReadError, HTTPError: as_promise_1.HTTPError, MaxRedirectsError: as_promise_1.MaxRedirectsError, TimeoutError: as_promise_1.TimeoutError, ParseError: as_promise_1.ParseError, CancelError: p_cancelable_1.CancelError, UnsupportedProtocolError: as_promise_1.UnsupportedProtocolError, UploadError: as_promise_1.UploadError }; // The `delay` package weighs 10KB (!) const delay = async (ms) => new Promise(resolve => setTimeout(resolve, ms)); const { normalizeArguments, mergeOptions } = as_promise_1.PromisableRequest; const getPromiseOrStream = (options) => options.isStream ? new core_1.default(options.url, options) : as_promise_1.default(options); const isGotInstance = (value) => ('defaults' in value && 'options' in value.defaults); const aliases = [ 'get', 'post', 'put', 'patch', 'head', 'delete' ]; exports.defaultHandler = (options, next) => next(options); const callInitHooks = (hooks, options) => { if (hooks) { for (const hook of hooks) { hook(options); } } }; const create = (defaults) => { // Proxy properties from next handlers defaults._rawHandlers = defaults.handlers; defaults.handlers = defaults.handlers.map(fn => ((options, next) => { // This will be assigned by assigning result let root; const result = fn(options, newOptions => { root = next(newOptions); return root; }); if (result !== root && !options.isStream && root) { const typedResult = result; const { then: promiseThen, catch: promiseCatch, finally: promiseFianlly } = typedResult; Object.setPrototypeOf(typedResult, Object.getPrototypeOf(root)); Object.defineProperties(typedResult, Object.getOwnPropertyDescriptors(root)); // These should point to the new promise // eslint-disable-next-line promise/prefer-await-to-then typedResult.then = promiseThen; typedResult.catch = promiseCatch; typedResult.finally = promiseFianlly; } return result; })); // Got interface const got = ((url, options) => { var _a, _b; let iteration = 0; const iterateHandlers = (newOptions) => { return defaults.handlers[iteration++](newOptions, iteration === defaults.handlers.length ? getPromiseOrStream : iterateHandlers); }; // TODO: Remove this in Got 12. if (is_1.default.plainObject(url)) { const mergedOptions = { ...url, ...options }; core_1.setNonEnumerableProperties([url, options], mergedOptions); options = mergedOptions; url = undefined; } try { // Call `init` hooks let initHookError; try { callInitHooks(defaults.options.hooks.init, options); callInitHooks((_a = options === null || options === void 0 ? void 0 : options.hooks) === null || _a === void 0 ? void 0 : _a.init, options); } catch (error) { initHookError = error; } // Normalize options & call handlers const normalizedOptions = normalizeArguments(url, options, defaults.options); normalizedOptions[core_1.kIsNormalizedAlready] = true; if (initHookError) { throw new as_promise_1.RequestError(initHookError.message, initHookError, normalizedOptions); } return iterateHandlers(normalizedOptions); } catch (error) { if (options === null || options === void 0 ? void 0 : options.isStream) { throw error; } else { return create_rejection_1.default(error, defaults.options.hooks.beforeError, (_b = options === null || options === void 0 ? void 0 : options.hooks) === null || _b === void 0 ? void 0 : _b.beforeError); } } }); got.extend = (...instancesOrOptions) => { const optionsArray = [defaults.options]; let handlers = [...defaults._rawHandlers]; let isMutableDefaults; for (const value of instancesOrOptions) { if (isGotInstance(value)) { optionsArray.push(value.defaults.options); handlers.push(...value.defaults._rawHandlers); isMutableDefaults = value.defaults.mutableDefaults; } else { optionsArray.push(value); if ('handlers' in value) { handlers.push(...value.handlers); } isMutableDefaults = value.mutableDefaults; } } handlers = handlers.filter(handler => handler !== exports.defaultHandler); if (handlers.length === 0) { handlers.push(exports.defaultHandler); } return create({ options: mergeOptions(...optionsArray), handlers, mutableDefaults: Boolean(isMutableDefaults) }); }; // Pagination const paginateEach = (async function* (url, options) { // TODO: Remove this `@ts-expect-error` when upgrading to TypeScript 4. // Error: Argument of type 'Merge> | undefined' is not assignable to parameter of type 'Options | undefined'. // @ts-expect-error let normalizedOptions = normalizeArguments(url, options, defaults.options); normalizedOptions.resolveBodyOnly = false; const pagination = normalizedOptions.pagination; if (!is_1.default.object(pagination)) { throw new TypeError('`options.pagination` must be implemented'); } const all = []; let { countLimit } = pagination; let numberOfRequests = 0; while (numberOfRequests < pagination.requestLimit) { if (numberOfRequests !== 0) { // eslint-disable-next-line no-await-in-loop await delay(pagination.backoff); } // TODO: Throw when result is not an instance of Response // eslint-disable-next-line no-await-in-loop const result = (await got(normalizedOptions)); // eslint-disable-next-line no-await-in-loop const parsed = await pagination.transform(result); const current = []; for (const item of parsed) { if (pagination.filter(item, all, current)) { if (!pagination.shouldContinue(item, all, current)) { return; } yield item; if (pagination.stackAllItems) { all.push(item); } current.push(item); if (--countLimit <= 0) { return; } } } const optionsToMerge = pagination.paginate(result, all, current); if (optionsToMerge === false) { return; } if (optionsToMerge === result.request.options) { normalizedOptions = result.request.options; } else if (optionsToMerge !== undefined) { normalizedOptions = normalizeArguments(undefined, optionsToMerge, normalizedOptions); } numberOfRequests++; } }); got.paginate = ((url, options) => { return paginateEach(url, options); }); got.paginate.all = (async (url, options) => { const results = []; for await (const item of got.paginate(url, options)) { results.push(item); } return results; }); // For those who like very descriptive names got.paginate.each = paginateEach; // Stream API got.stream = ((url, options) => got(url, { ...options, isStream: true })); // Shortcuts for (const method of aliases) { got[method] = ((url, options) => got(url, { ...options, method })); got.stream[method] = ((url, options) => { return got(url, { ...options, method, isStream: true }); }); } Object.assign(got, { ...errors, mergeOptions }); Object.defineProperty(got, 'defaults', { value: defaults.mutableDefaults ? defaults : deep_freeze_1.default(defaults), writable: defaults.mutableDefaults, configurable: defaults.mutableDefaults, enumerable: true }); return got; }; exports.default = create; __exportStar(__webpack_require__(839), exports); /***/ }), /***/ 325: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const PassThrough = __webpack_require__(413).PassThrough; const mimicResponse = __webpack_require__(89); const cloneResponse = response => { if (!(response && response.pipe)) { throw new TypeError('Parameter `response` must be a response stream.'); } const clone = new PassThrough(); mimicResponse(response, clone); return response.pipe(clone); }; module.exports = cloneResponse; /***/ }), /***/ 350: /***/ (function(module) { (function(f){if(true){module.exports=f()}else { var g; }})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=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=require,i=0;i 0) { words += '-' + lookup(remainder, false, ord); } else if (ord) { words = words.substring(0, words.length - 1) + 'ieth'; } } else if (num < 1000) { const hundreds = Math.floor(num / 100); const 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 } const factor = Math.pow(10, mag * 3); const mant = Math.floor(num / factor); const remainder = num - mant * factor; words = (prev ? ', ' : '') + lookup(mant, false, false) + ' ' + magnitudes[mag - 1]; if (remainder > 0) { words += lookup(remainder, true, ord); } else if (ord) { words += 'th'; } } return words; }; var words = lookup(value, false, ordinal); return words; } const wordValues = {}; few.forEach(function (word, index) { wordValues[word.toLowerCase()] = index; }); ordinals.forEach(function (word, index) { wordValues[word.toLowerCase()] = index; }); decades.forEach(function (word, index) { const 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) { const lword = word.toLowerCase(); const 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) { const parts = text.split(/,\s|\sand\s|[\s\\-]/); const values = parts.map(part => wordValues[part]); let segs = [0]; values.forEach(value => { if (value < 100) { let top = segs.pop(); if (top >= 1000) { segs.push(top); top = 0; } segs.push(top + value); } else { segs.push(segs.pop() * value); } }); const result = segs.reduce((a, b) => a + b, 0); return result; } const 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'] ]; const 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++) { const 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--) { const digit = roman[i]; const 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); const format = analyseIntegerPicture(picture); return _formatInteger(value, format); } const formats = { DECIMAL: 'decimal', LETTERS: 'letters', ROMAN: 'roman', WORDS: 'words', SEQUENCE: 'sequence' }; const 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) { let formattedInteger; const 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 = Array.from(formattedInteger).map(code => { return String.fromCodePoint(code.codePointAt(0) + format.zeroCode - 0x30); }).join(''); } // insert the grouping-separator-signs, if any if (format.regular) { const n = Math.floor((formattedInteger.length - 1) / format.groupingSeparators.position); for (let ii = n; ii > 0; ii--) { const pos = formattedInteger.length - ii * format.groupingSeparators.position; formattedInteger = formattedInteger.substr(0, pos) + format.groupingSeparators.character + formattedInteger.substr(pos); } } else { format.groupingSeparators.reverse().forEach(separator => { const 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) ??? const 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) { const format = { type: 'integer', primary: formats.DECIMAL, case: tcase.LOWER, ordinal: false }; let primaryFormat, formatModifier; const 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) let zeroCode = null; let mandatoryDigits = 0; let optionalDigits = 0; let groupingSeparators = []; let separatorPosition = 0; const formatCodepoints = Array.from(primaryFormat, c => c.codePointAt(0)).reverse(); // reverse the array to determine positions of grouping-separator-signs formatCodepoints.forEach((codePoint) => { // step though each char in the picture to determine the digit group let digit = false; for (let ii = 0; ii < decimalGroups.length; ii++) { const 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'? const regularRepeat = function (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? const sepChar = separators[0].character; for (let ii = 1; ii < separators.length; ii++) { if (separators[ii].character !== sepChar) { return 0; } } // are they equally spaced? const indexes = separators.map(separator => separator.position); const gcd = function (a, b) { return b === 0 ? a : gcd(b, a % b); }; // find the greatest common divisor of all the positions const factor = indexes.reduce(gcd); // is every position separated by this divisor? If so, it's regular for (let index = 1; index <= indexes.length; index++) { if (indexes.indexOf(index * factor) === -1) { return 0; } } return factor; }; const 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; } const 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 = []; const format = { type: 'datetime', parts: spec }; const addLiteral = function (start, end) { if (end > start) { let 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' }; } let 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 const widthMod = marker.substring(comma + 1); const dash = widthMod.indexOf('-'); let min, max; const parseWidth = function (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); } const 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 (def.component === 'Y') { // §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; } const days = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; const millisInADay = 1000 * 60 * 60 * 24; const startOfFirstWeek = function (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) const 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; }; const yearMonth = function (year, month) { return { year: year, month: month, nextMonth: function () { return (month === 11) ? yearMonth(year + 1, 0) : yearMonth(year, month + 1); }, previousMonth: function () { return (month === 0) ? yearMonth(year - 1, 11) : yearMonth(year, month - 1); }, nextYear: function () { return yearMonth(year + 1, month); }, previousYear: function () { return yearMonth(year - 1, month); } }; }; const deltaWeeks = function (start, end) { return (end - start) / (millisInADay * 7) + 1; }; const getDateTimeFragment = (date, component) => { let 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) const today = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); // millis for given 1st Jan of that year (at 00:00 UTC) const 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 const thisYear = yearMonth(date.getUTCFullYear(), 0); const startOfWeek1 = startOfFirstWeek(thisYear); const today = Date.UTC(thisYear.year, date.getUTCMonth(), date.getUTCDate()); let week = deltaWeeks(startOfWeek1, today); if (week > 52) { // might be first week of the following year const startOfFollowingYear = startOfFirstWeek(thisYear.nextYear()); if (today >= startOfFollowingYear) { week = 1; } } else if (week < 1) { // must be end of the previous year const startOfPreviousYear = startOfFirstWeek(thisYear.previousYear()); week = deltaWeeks(startOfPreviousYear, today); } componentValue = Math.floor(week); break; } case 'w': { // week in month const thisMonth = yearMonth(date.getUTCFullYear(), date.getUTCMonth()); const startOfWeek1 = startOfFirstWeek(thisMonth); const today = Date.UTC(thisMonth.year, thisMonth.month, date.getUTCDate()); let week = deltaWeeks(startOfWeek1, today); if (week > 4) { // might be first week of the following month const startOfFollowingMonth = startOfFirstWeek(thisMonth.nextMonth()); if (today >= startOfFollowingMonth) { week = 1; } } else if (week < 1) { // must be end of the previous month const startOfPreviousMonth = startOfFirstWeek(thisMonth.previousMonth()); week = deltaWeeks(startOfPreviousMonth, today); } 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) const thisYear = yearMonth(date.getUTCFullYear(), 0); const startOfISOYear = startOfFirstWeek(thisYear); const endOfISOYear = startOfFirstWeek(thisYear.nextYear()); const 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) const thisMonth = yearMonth(date.getUTCFullYear(), date.getUTCMonth()); const startOfISOMonth = startOfFirstWeek(thisMonth); const nextMonth = thisMonth.nextMonth(); const endOfISOMonth = startOfFirstWeek(nextMonth); const 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; }; const iso8601Spec = analyseDateTimePicture('[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].[f001][Z01:01t]'); /** * 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 const offset = parseInt(timezone); offsetHours = Math.floor(offset / 100); offsetMinutes = offset % 100; } var formatComponent = function (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 const offset = offsetHours * 100 + offsetMinutes; if (markerSpec.integerFormat.regular) { componentValue = _formatInteger(offset, markerSpec.integerFormat); } else { const 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'; } } return componentValue; }; let formatSpec; if(typeof picture === 'undefined') { // default to ISO 8601 format formatSpec = iso8601Spec; } else { formatSpec = analyseDateTimePicture(picture); } const offsetMillis = (60 * offsetHours + offsetMinutes) * 60 * 1000; const dateTime = new Date(millis + offsetMillis); let 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.integerFormat) { 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'; const isUpper = formatSpec.case === tcase.UPPER; 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]+'; if (formatSpec.ordinal) { // ordinals matcher.regex += '(?:th|st|nd|rd)'; } matcher.parse = function (value) { let 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(sep => { digits = digits.split(sep.character).join(''); }); } if (formatSpec.zeroCode !== 0x30) { // apply offset digits = digits.split('').map(char => 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; } const formatSpec = analyseIntegerPicture(picture); const matchSpec = generateRegex(formatSpec); //const fullRegex = '^' + matchSpec.regex + '$'; //const matcher = new RegExp(fullRegex); // TODO validate input based on the matcher regex const 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) { const formatSpec = analyseDateTimePicture(picture); const matchSpec = generateRegex(formatSpec); const fullRegex = '^' + matchSpec.parts.map(part => '(' + part.regex + ')').join('') + '$'; const 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 const dmA = 161; // binary 10100001 const dmB = 130; // binary 10000010 const dmC = 84; // binary 01010100 const dmD = 72; // binary 01001000 // time mask PHhmsf const tmA = 23; // binary 010111 const tmB = 47; // binary 101111 const components = {}; for (let i = 1; i < info.length; i++) { const 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; } let mask = 0; const shift = bit => { mask <<= 1; mask += bit ? 1 : 0; }; const isType = type => { // shouldn't match any 0's, must match at least one 1 return !(~type & mask) && !!(type & mask); }; 'YXMxWwdD'.split('').forEach(part => shift(components[part])); const dateA = isType(dmA); const dateB = !dateA && isType(dmB); const dateC = isType(dmC); const dateD = !dateC && isType(dmD); mask = 0; 'PHhmsf'.split('').forEach(part => shift(components[part])); const timeA = isType(tmA); const timeB = !timeA && isType(tmB); // should only be zero or one date type and zero or one time type const dateComps = dateB ? 'YD' : dateC ? 'XxwF' : dateD? 'XWF' : 'YMD'; const timeComps = timeB ? 'Phmsf' : 'Hmsf'; const 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 const now = this.environment.timestamp; // must get the fixed timestamp from jsonata let startSpecified = false; let endSpecified = false; comps.split('').forEach(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) const firstJan = Date.UTC(components.Y, 0); const offsetMillis = (components.d - 1) * 1000 * 60 * 60 * 24; const 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); 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, parseInteger, fromMillis, toMillis }; })(); module.exports = dateTime; },{}],2:[function(require,module,exports){ (function (global){ /** * © 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'); const functions = (() => { '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 getFunctionArity = utils.getFunctionArity; var deepEquals = utils.isDeepEqual; /** * 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, prettify = 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 = Array.from(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 Array.from(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(matcher, str) { var result = matcher.apply(this, [str]); // eslint-disable-line no-useless-call if(isIterable(result)) { result = yield * result; } if(result && !(typeof result.start === 'number' || result.end === 'number' || Array.isArray(result.groups) || isFunction(result.next))) { // the matcher function didn't return the correct structure throw { code: "T1010", stack: (new Error()).stack, }; } return result; } /** * 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* contains(str, token) { // undefined inputs always return undefined if (typeof str === 'undefined') { return undefined; } var result; if (typeof token === 'string') { result = (str.indexOf(token) !== -1); } else { var matches = yield* evaluateMatcher(token, str); result = (typeof matches !== 'undefined'); } return result; } /** * 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* match(str, regex, limit) { // undefined inputs always return undefined if (typeof str === 'undefined') { return undefined; } // limit, if specified, must be a non-negative number if (limit < 0) { throw { stack: (new Error()).stack, value: limit, code: 'D3040', index: 3 }; } var result = createSequence(); if (typeof limit === 'undefined' || limit > 0) { var count = 0; var matches = yield* evaluateMatcher(regex, str); if (typeof matches !== 'undefined') { while (typeof matches !== 'undefined' && (typeof limit === 'undefined' || count < limit)) { result.push({ match: matches.match, index: matches.start, groups: matches.groups }); matches = yield* evaluateMatcher(matches.next); count++; } } } return result; } /** * 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* replace(str, pattern, replacement, limit) { // undefined inputs always return undefined if (typeof str === 'undefined') { return undefined; } var self = this; // pattern cannot be an empty string if (pattern === '') { throw { code: "D3010", stack: (new Error()).stack, value: pattern, index: 2 }; } // limit, if specified, must be a non-negative number if (limit < 0) { throw { code: "D3011", stack: (new Error()).stack, value: limit, index: 4 }; } var replacer; if (typeof replacement === 'string') { replacer = function (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; } var result = ''; var position = 0; if (typeof limit === 'undefined' || limit > 0) { var count = 0; if (typeof pattern === 'string') { var 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); } else { var matches = yield* evaluateMatcher(pattern, str); if (typeof matches !== 'undefined') { while (typeof matches !== 'undefined' && (typeof limit === 'undefined' || count < limit)) { result += str.substring(position, matches.start); var replacedWith = replacer.apply(self, [matches]); if (isIterable(replacedWith)) { replacedWith = yield* replacedWith; } // check replacedWith is a string if (typeof replacedWith === 'string') { result += replacedWith; } else { // not a string - throw error throw { code: "D3012", stack: (new Error()).stack, value: replacedWith }; } position = matches.start + matches.match.length; count++; matches = yield* evaluateMatcher(matches.next); } result += str.substring(position); } else { result = str; } } } else { result = str; } return result; } /** * Base64 encode a string * @param {String} str - string * @returns {String} Base 64 encoding of the binary data */ 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(str, 'base64').toString('binary'); }; 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(str, separator, limit) { // undefined inputs always return undefined if (typeof str === 'undefined') { return undefined; } // limit, if specified, must be a non-negative number if (limit < 0) { throw { code: "D3020", stack: (new Error()).stack, value: limit, index: 3 }; } var result = []; if (typeof limit === 'undefined' || limit > 0) { if (typeof separator === 'string') { result = str.split(separator, limit); } else { var count = 0; var matches = yield* evaluateMatcher(separator, str); if (typeof matches !== 'undefined') { var start = 0; while (typeof matches !== 'undefined' && (typeof limit === 'undefined' || count < limit)) { result.push(str.substring(start, matches.start)); start = matches.end; matches = yield* evaluateMatcher(matches.next); count++; } if (typeof limit === 'undefined' || count < limit) { result.push(str.substring(start)); } } else { result.push(str); } } } return result; } /** * 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 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 (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 (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 (char) { return activeChars.indexOf(char) === -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 (char) { return decimalDigitFamily.indexOf(char) > -1; }).length > 0) { error = 'D3090'; } optionalDigitPos = parts.fractionalPart.lastIndexOf(properties.digit); if (optionalDigitPos !== -1 && parts.fractionalPart.substring(optionalDigitPos).split('').filter(function (char) { return decimalDigitFamily.indexOf(char) > -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 (char) { return decimalDigitFamily.indexOf(char) === -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 (parts) { var getGroupingPositions = function (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 (char) { return decimalDigitFamily.indexOf(char) !== -1 || char === 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 (indexes) { // are the grouping positions regular? i.e. same interval between each of them if (indexes.length === 0) { return 0; } var gcd = function (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 (char) { return decimalDigitFamily.indexOf(char) !== -1; }).length; var scalingFactor = minimumIntegerPartSize; var fractionalPartArray = parts.fractionalPart.split(''); var minimumFactionalPartSize = fractionalPartArray.filter(function (char) { return decimalDigitFamily.indexOf(char) !== -1; }).length; var maximumFactionalPartSize = fractionalPartArray.filter(function (char) { return decimalDigitFamily.indexOf(char) !== -1 || char === 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 (char) { return decimalDigitFamily.indexOf(char) !== -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 (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 (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) { 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(arr, func) { // undefined inputs always return undefined if (typeof arr === 'undefined') { return undefined; } var result = createSequence(); // do the map - iterate over the arrays, and invoke func for (var i = 0; i < arr.length; i++) { var func_args = hofFuncArgs(func, arr[i], i, arr); // invoke func var res = yield* func.apply(this, func_args); if (typeof res !== 'undefined') { result.push(res); } } return result; } /** * Create a map from an array of arguments * @param {Array} [arr] - array to filter * @param {Function} func - predicate function * @returns {Array} Map array */ function* filter(arr, func) { // eslint-disable-line require-yield // undefined inputs always return undefined if (typeof arr === 'undefined') { return undefined; } var result = createSequence(); for (var i = 0; i < arr.length; i++) { var entry = arr[i]; var func_args = hofFuncArgs(func, entry, i, arr); // invoke func var res = yield* func.apply(this, func_args); if (boolean(res)) { result.push(entry); } } return result; } /** * 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* single(arr, func) { // eslint-disable-line require-yield // undefined inputs always return undefined if (typeof arr === 'undefined') { return undefined; } var hasFoundMatch = false; var result; for (var i = 0; i < arr.length; i++) { var entry = arr[i]; var positiveResult = true; if (typeof func !== 'undefined') { var func_args = hofFuncArgs(func, entry, i, arr); // invoke func var res = yield* func.apply(this, func_args); positiveResult = boolean(res); } if (positiveResult) { if(!hasFoundMatch) { result = entry; hasFoundMatch = true; } else { throw { stack: (new Error()).stack, code: "D3138", index: i }; } } } if(!hasFoundMatch) { throw { stack: (new Error()).stack, code: "D3139" }; } return result; } /** * Convolves (zips) each value from a set of arrays * @param {Array} [args] - arrays to zip * @returns {Array} Zipped array */ 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((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(sequence, func, init) { // undefined inputs always return undefined if (typeof sequence === 'undefined') { return undefined; } var result; var arity = getFunctionArity(func); if (arity < 2) { throw { stack: (new Error()).stack, code: "D3050", index: 1 }; } var index; if (typeof init === 'undefined' && sequence.length > 0) { result = sequence[0]; index = 1; } else { result = init; index = 0; } while (index < sequence.length) { var args = [result, sequence[index]]; if (arity >= 3) { args.push(index); } if (arity >= 4) { args.push(sequence); } result = yield* func.apply(this, args); index++; } return result; } /** * Return keys for an object * @param {Object} arg - Object * @returns {Array} Array of keys */ 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' && !(isLambda(arg))) { Object.keys(arg).forEach(key => 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)) { result.push(...res); } else { result.push(res); } } } } else if (input !== null && typeof input === 'object') { 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(obj, func) { var result = createSequence(); for (var key in obj) { var func_args = hofFuncArgs(func, obj[key], key, obj); // invoke func var val = yield* func.apply(this, func_args); if(typeof val !== 'undefined') { result.push(val); } } return result; } /** * * @param {string} [message] - the message to attach to the error * @throws custom error with code 'D3137' */ 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(arr, comparator) { // undefined inputs always return undefined if (typeof arr === 'undefined') { return undefined; } if (arr.length <= 1) { return arr; } var comp; if (typeof comparator === 'undefined') { // inject a default comparator - only works for numeric or string arrays if (!isArrayOfNumbers(arr) && !isArrayOfStrings(arr)) { throw { stack: (new Error()).stack, code: "D3070", index: 1 }; } comp = function* (a, b) { // eslint-disable-line require-yield return a > b; }; } else { // for internal usage of functionSort (i.e. order-by syntax) comp = comparator; } var merge = function* (l, r) { var merge_iter = function* (result, left, right) { if (left.length === 0) { Array.prototype.push.apply(result, right); } else if (right.length === 0) { Array.prototype.push.apply(result, left); } else if (yield* comp(left[0], right[0])) { // invoke the comparator function // if it returns true - swap left and right result.push(right[0]); yield* merge_iter(result, left, right.slice(1)); } else { // otherwise keep the same order result.push(left[0]); yield* merge_iter(result, left.slice(1), right); } }; var merged = []; yield* merge_iter(merged, l, r); return merged; }; var msort = function* (array) { if (!Array.isArray(array) || array.length <= 1) { return array; } else { var middle = Math.floor(array.length / 2); var left = array.slice(0, middle); var right = array.slice(middle); left = yield* msort(left); right = yield* msort(right); return yield* merge(left, right); } }; var result = yield* msort(arr); return result; } /** * Randomly shuffles the contents of an array * @param {Array} arr - the input array * @returns {Array} the shuffled array */ 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(arg, func) { var result = {}; for (var item in arg) { var entry = arg[item]; var func_args = hofFuncArgs(func, entry, item, arg); // invoke func var res = yield* func.apply(this, func_args); if (boolean(res)) { result[item] = entry; } } // empty objects should be changed to undefined if (Object.keys(result).length === 0) { result = undefined; } return result; } return { sum, count, max, min, average, string, substring, substringBefore, substringAfter, lowercase, uppercase, length, trim, pad, match, contains, replace, split, join, formatNumber, formatBase, number, floor, ceil, round, abs, sqrt, power, random, boolean, not, map, zip, filter, single, foldLeft, sift, keys, lookup, append, exists, spread, merge, reverse, each, error, assert, type, sort, shuffle, distinct, base64encode, base64decode, encodeUrlComponent, encodeUrl, decodeUrlComponent, decodeUrl }; })(); module.exports = functions; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./utils":6}],3:[function(require,module,exports){ /** * © 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 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* evaluate(expr, input, environment) { var result; var entryCallback = environment.lookup('__evaluate_entry'); if(entryCallback) { entryCallback(expr, input, environment); } switch (expr.type) { case 'path': result = yield * evaluatePath(expr, input, environment); break; case 'binary': result = yield * evaluateBinary(expr, input, environment); break; case 'unary': result = yield * evaluateUnary(expr, input, environment); break; case 'name': result = evaluateName(expr, input, environment); break; case 'string': case 'number': case 'value': result = evaluateLiteral(expr, input, environment); break; case 'wildcard': result = evaluateWildcard(expr, input, environment); break; case 'descendant': result = evaluateDescendants(expr, input, environment); break; case 'parent': result = environment.lookup(expr.slot.label); break; case 'condition': result = yield * evaluateCondition(expr, input, environment); break; case 'block': result = yield * evaluateBlock(expr, input, environment); break; case 'bind': result = yield * evaluateBindExpression(expr, input, environment); break; case 'regex': result = evaluateRegex(expr, input, environment); break; case 'function': result = yield * evaluateFunction(expr, input, environment); break; case 'variable': result = evaluateVariable(expr, input, environment); break; case 'lambda': result = evaluateLambda(expr, input, environment); break; case 'partial': result = yield * evaluatePartialApplication(expr, input, environment); break; case 'apply': result = yield * evaluateApplyExpression(expr, input, environment); break; case 'transform': result = evaluateTransformExpression(expr, input, environment); break; } if(environment.async && (typeof result === 'undefined' || result === null || typeof result.then !== 'function')) { result = Promise.resolve(result); } if(environment.async && typeof result.then === 'function' && expr.nextFunction && typeof result[expr.nextFunction] === 'function') { // although this is a 'thenable', it is chaining a different function // so don't yield since yielding will trigger the .then() } else { result = yield result; } if (Object.prototype.hasOwnProperty.call(expr, 'predicate')) { for(var ii = 0; ii < expr.predicate.length; ii++) { result = yield * evaluateFilter(expr.predicate[ii].expr, result, environment); } } if (expr.type !== 'path' && Object.prototype.hasOwnProperty.call(expr, 'group')) { result = yield * evaluateGroupExpression(expr.group, result, environment); } var exitCallback = environment.lookup('__evaluate_exit'); if(exitCallback) { exitCallback(expr, input, environment, result); } 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 result; } /** * 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* evaluatePath(expr, input, environment) { var inputSequence; // 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); } var resultSequence; var isTupleStream = false; var tupleBindings = undefined; // evaluate each step in turn for(var ii = 0; ii < expr.steps.length; ii++) { var 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) { resultSequence = yield * evaluate(step, inputSequence, environment); } else { if(isTupleStream) { tupleBindings = yield * evaluateTupleStep(step, inputSequence, tupleBindings, environment); } else { resultSequence = yield * evaluateStep(step, inputSequence, environment, ii === expr.steps.length - 1); } } if (!isTupleStream && (typeof resultSequence === 'undefined' || resultSequence.length === 0)) { break; } if(typeof step.focus === 'undefined') { inputSequence = resultSequence; } } 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(!isSequence(resultSequence)) { resultSequence = createSequence(resultSequence); } resultSequence.keepSingleton = true; } if (expr.hasOwnProperty('group')) { resultSequence = yield* evaluateGroupExpression(expr.group, isTupleStream ? tupleBindings : resultSequence, environment) } return resultSequence; } function createFrameFromTuple(environment, tuple) { var frame = createFrame(environment); for(const 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(expr, input, environment, lastStep) { var result; if(expr.type === 'sort') { result = yield* evaluateSortExpression(expr, input, environment); if(expr.stages) { result = yield* evaluateStages(expr.stages, result, environment); } return result; } result = createSequence(); for(var ii = 0; ii < input.length; ii++) { var res = yield * evaluate(expr, input[ii], environment); if(expr.stages) { for(var ss = 0; ss < expr.stages.length; ss++) { res = yield* evaluateFilter(expr.stages[ss].expr, res, environment); } } if(typeof res !== 'undefined') { result.push(res); } } var 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 Array.prototype.push.apply(resultSequence, res); } }); } return resultSequence; } function* evaluateStages(stages, input, environment) { var result = input; for(var ss = 0; ss < stages.length; ss++) { var stage = stages[ss]; switch(stage.type) { case 'filter': result = yield * evaluateFilter(stage.expr, result, environment); break; case 'index': for(var ee = 0; ee < result.length; ee++) { var tuple = result[ee]; tuple[stage.value] = ee; } break; } } return result; } /** * 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* evaluateTupleStep(expr, input, tupleBindings, environment) { var result; if(expr.type === 'sort') { if(tupleBindings) { result = yield* evaluateSortExpression(expr, tupleBindings, environment); } else { var sorted = yield* evaluateSortExpression(expr, input, environment); result = createSequence(); result.tupleStream = true; for(var ss = 0; ss < sorted.length; ss++) { var tuple = {'@': sorted[ss]}; tuple[expr.index] = ss; result.push(tuple); } } if(expr.stages) { result = yield* evaluateStages(expr.stages, result, environment); } return result; } result = createSequence(); result.tupleStream = true; var stepEnv = environment; if(tupleBindings === undefined) { tupleBindings = input.map(item => { return {'@': item} }); } for(var ee = 0; ee < tupleBindings.length; ee++) { stepEnv = createFrameFromTuple(environment, tupleBindings[ee]); var res = yield* evaluate(expr, tupleBindings[ee]['@'], stepEnv); // res is the binding sequence for the output tuple stream if(typeof res !== 'undefined') { if (!Array.isArray(res)) { res = [res]; } for (var 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); } } } if(expr.stages) { result = yield * evaluateStages(expr.stages, result, environment); } return result; } /** * 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* evaluateFilter(predicate, input, environment) { var results = createSequence(); if( input && input.tupleStream) { results.tupleStream = true; } if (!Array.isArray(input)) { input = createSequence(input); } if (predicate.type === 'number') { var index = Math.floor(predicate.value); // round it down if (index < 0) { // count in from end of array index = input.length + index; } var item = input[index]; if(typeof item !== 'undefined') { if(Array.isArray(item)) { results = item; } else { results.push(item); } } } else { for (index = 0; index < input.length; index++) { var item = input[index]; var context = item; var env = environment; if(input.tupleStream) { context = item['@']; env = createFrameFromTuple(environment, item); } var res = yield* evaluate(predicate, context, env); 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); } } } return results; } /** * 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 * evaluateBinary(expr, input, environment) { var result; var lhs = yield * evaluate(expr.lhs, input, environment); var rhs = yield * evaluate(expr.rhs, input, environment); var op = expr.value; try { switch (op) { case '+': case '-': case '*': case '/': case '%': result = evaluateNumericExpression(lhs, rhs, op); break; case '=': case '!=': result = evaluateEqualityExpression(lhs, rhs, op); break; case '<': case '<=': case '>': case '>=': result = evaluateComparisonExpression(lhs, rhs, op); break; case '&': result = evaluateStringConcat(lhs, rhs); break; case 'and': case 'or': result = evaluateBooleanExpression(lhs, rhs, op); break; case '..': result = evaluateRangeExpression(lhs, rhs); break; case 'in': result = evaluateIncludesExpression(lhs, rhs); break; } } catch(err) { err.position = expr.position; err.token = op; throw err; } return result; } /** * 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* evaluateUnary(expr, input, environment) { var result; switch (expr.value) { case '-': result = yield * evaluate(expr.expression, input, environment); if(typeof result === 'undefined') { result = undefined; } else if (isNumeric(result)) { result = -result; } else { throw { code: "D1002", stack: (new Error()).stack, position: expr.position, token: expr.value, value: result }; } break; case '[': // array constructor - evaluate each item result = []; for(var ii = 0; ii < expr.expressions.length; ii++) { var item = expr.expressions[ii]; var value = yield * evaluate(item, input, environment); if (typeof value !== 'undefined') { if(item.value === '[') { result.push(value); } else { result = fn.append(result, value); } } } if(expr.consarray) { Object.defineProperty(result, 'cons', { enumerable: false, configurable: false, value: true }); } break; case '{': // object constructor - apply grouping result = yield * evaluateGroupExpression(expr, input, environment); break; } return result; } /** * 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 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 (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 {Object} rhs - RHS value * @param {Object} op - opcode * @returns {*} Result */ function evaluateBooleanExpression(lhs, rhs, op) { var result; var lBool = fn.boolean(lhs); var rBool = fn.boolean(rhs); if (typeof lBool === 'undefined') { lBool = false; } if (typeof rBool === 'undefined') { rBool = false; } switch (op) { case 'and': result = lBool && rBool; break; case 'or': result = lBool || rBool; break; } return result; } /** * 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(expr, input, environment) { var result = {}; var groups = {}; var reduce = input && input.tupleStream ? true : false; // group the input sequence by 'key' expression if (!Array.isArray(input)) { input = createSequence(input); } for(var itemIndex = 0; itemIndex < input.length; itemIndex++) { var item = input[itemIndex]; var env = reduce ? createFrameFromTuple(environment, item) : environment; for(var pairIndex = 0; pairIndex < expr.lhs.length; pairIndex++) { var pair = expr.lhs[pairIndex]; var key = yield * evaluate(pair[0], reduce ? item['@'] : item, env); // key has to be a string if (typeof key !== 'string') { throw { code: "T1003", stack: (new Error()).stack, position: expr.position, value: key }; } var entry = {data: item, exprIndex: pairIndex}; if (groups.hasOwnProperty(key)) { // a value already exists in this slot if(groups[key].exprIndex !== pairIndex) { // this key has been generated by another expression in this group // when multiple key expressions evaluate to the same key, then error D1009 must be thrown throw { code: "D1009", stack: (new Error()).stack, position: expr.position, value: key }; } // append it as an array groups[key].data = fn.append(groups[key].data, item); } else { groups[key] = entry; } } } // iterate over the groups to evaluate the 'value' expression for (key in groups) { entry = groups[key]; var context = entry.data; var env = environment; if (reduce) { var tuple = reduceTupleStream(entry.data); context = tuple['@']; delete tuple['@']; env = createFrameFromTuple(environment, tuple); } var value = yield * evaluate(expr.lhs[entry.exprIndex][1], context, env); if(typeof value !== 'undefined') { result[key] = value; } } return result; } 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(const 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(expr, input, environment) { // The RHS is the expression to evaluate // The LHS is the name of the variable to bind to - should be a VARIABLE token (enforced by parser) var value = yield * evaluate(expr.rhs, input, environment); environment.bind(expr.lhs.value, value); return value; } /** * 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* evaluateCondition(expr, input, environment) { var result; var condition = yield * evaluate(expr.condition, input, environment); if (fn.boolean(condition)) { result = yield * evaluate(expr.then, input, environment); } else if (typeof expr.else !== 'undefined') { result = yield * evaluate(expr.else, input, environment); } return result; } /** * 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* evaluateBlock(expr, input, environment) { var result; // 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 var frame = createFrame(environment); // invoke each expression in turn // only return the result of the last one for(var ii = 0; ii < expr.expressions.length; ii++) { result = yield * evaluate(expr.expressions[ii], input, frame); } return result; } /** * Prepare a regex * @param {Object} expr - expression containing regex * @returns {Function} Higher order function representing prepared regex */ function evaluateRegex(expr) { var re = new RegExp(expr.value); var closure = function(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(expr, input, environment) { var result; // evaluate the lhs, then sort the results in order according to rhs expression //var lhs = yield * evaluate(expr.lhs, input, environment); var lhs = input; var isTupleSort = input.tupleStream ? true : false; // sort the lhs array // use comparator function var comparator = function*(a, b) { // eslint-disable-line require-yield // expr.terms is an array of order-by in priority order var comp = 0; for(var index = 0; comp === 0 && index < expr.terms.length; index++) { var term = expr.terms[index]; //evaluate the sort term in the context of a var context = a; var env = environment; if(isTupleSort) { context = a['@']; env = createFrameFromTuple(environment, a); } var aa = yield * evaluate(term.expression, context, env); //evaluate the sort term in the context of b context = b; env = environment; if(isTupleSort) { context = b['@']; env = createFrameFromTuple(environment, b); } var bb = yield * evaluate(term.expression, context, env); // type checks var atype = typeof aa; var btype = typeof bb; // undefined should be last in sort order if(atype === 'undefined') { // swap them, unless btype is also undefined comp = (btype === 'undefined') ? 0 : 1; continue; } if(btype === 'undefined') { comp = -1; continue; } // if aa or bb are not string or numeric values, then throw an error if(!(atype === 'string' || atype === 'number') || !(btype === 'string' || btype === 'number')) { throw { code: "T2008", stack: (new Error()).stack, position: expr.position, value: !(atype === 'string' || atype === 'number') ? aa : bb }; } //if aa and bb are not of the same type if(atype !== btype) { throw { code: "T2007", stack: (new Error()).stack, position: expr.position, value: aa, value2: bb }; } if(aa === bb) { // both the same - move on to next term continue; } else if (aa < bb) { comp = -1; } else { comp = 1; } if(term.descending === true) { comp = -comp; } } // only swap a & b if comp equals 1 return comp === 1; }; var focus = { environment: environment, input: input }; // the `focus` is passed in as the `this` for the invoked function result = yield * fn.sort.apply(focus, [lhs, comparator]); return result; } /** * 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 evaluateTransformExpression(expr, input, environment) { // create a function to implement the transform definition var transformer = function*(obj) { // signature <(oa):o> // undefined inputs always return undefined if(typeof obj === 'undefined') { return undefined; } // this function returns a copy of obj with changes specified by the pattern/operation var cloneFunction = environment.lookup('clone'); if(!isFunction(cloneFunction)) { // throw type error throw { code: "T2013", stack: (new Error()).stack, position: expr.position }; } var result = yield * apply(cloneFunction, [obj], null, environment); var matches = yield * evaluate(expr.pattern, result, environment); if(typeof matches !== 'undefined') { if(!Array.isArray(matches)) { matches = [matches]; } for(var ii = 0; ii < matches.length; ii++) { var match = matches[ii]; // evaluate the update value for each match var update = yield * evaluate(expr.update, match, environment); // update must be an object var updateType = typeof update; if(updateType !== 'undefined') { if(updateType !== 'object' || update === null || Array.isArray(update)) { // throw type error throw { code: "T2011", stack: (new Error()).stack, position: expr.update.position, value: update }; } // merge the update for(var prop in update) { match[prop] = update[prop]; } } // delete, if specified, must be an array of strings (or single string) if(typeof expr.delete !== 'undefined') { var deletions = yield * evaluate(expr.delete, match, environment); if(typeof deletions !== 'undefined') { var val = deletions; if (!Array.isArray(deletions)) { deletions = [deletions]; } if (!isArrayOfStrings(deletions)) { // throw type error throw { code: "T2012", stack: (new Error()).stack, position: expr.delete.position, value: val }; } for (var jj = 0; jj < deletions.length; jj++) { if(typeof match === 'object' && match !== null) { delete match[deletions[jj]]; } } } } } } return result; }; 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(expr, input, environment) { var result; var lhs = yield * evaluate(expr.lhs, input, environment); if(expr.rhs.type === 'function') { // this is a function _invocation_; invoke it with lhs expression as the first argument result = yield * evaluateFunction(expr.rhs, input, environment, { context: lhs }); } else { var func = yield * evaluate(expr.rhs, input, environment); if(!isFunction(func)) { throw { code: "T2006", stack: (new Error()).stack, position: expr.position, value: func }; } if(isFunction(lhs)) { // this is function chaining (func1 ~> func2) // λ($f, $g) { λ($x){ $g($f($x)) } } var chain = yield * evaluate(chainAST, null, environment); result = yield * apply(chain, [lhs, func], null, environment); } else { result = yield * apply(func, [lhs], null, environment); } } return result; } /** * 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* evaluateFunction(expr, input, environment, applyto) { var result; // create the procedure // can't assume that expr.procedure is a lambda type directly // could be an expression that evaluates to a function (e.g. variable reference, parens expr etc. // evaluate it generically first, then check that it is a function. Throw error if not. var proc = yield * evaluate(expr.procedure, input, environment); if (typeof proc === 'undefined' && expr.procedure.type === 'path' && environment.lookup(expr.procedure.steps[0].value)) { // help the user out here if they simply forgot the leading $ throw { code: "T1005", stack: (new Error()).stack, position: expr.position, token: expr.procedure.steps[0].value }; } var evaluatedArgs = []; if(typeof applyto !== 'undefined') { evaluatedArgs.push(applyto.context); } // eager evaluation - evaluate the arguments for (var jj = 0; jj < expr.arguments.length; jj++) { const arg = yield* evaluate(expr.arguments[jj], input, environment); if(isFunction(arg)) { // wrap this in a closure const closure = function* (...params) { // invoke func return yield * apply(arg, params, null, environment); }; closure.arity = getFunctionArity(arg); evaluatedArgs.push(closure); } else { evaluatedArgs.push(arg); } } // apply the procedure var procName = expr.procedure.type === 'path' ? expr.procedure.steps[0].value : expr.procedure.value; try { if(typeof proc === 'object') { proc.token = procName; proc.position = expr.position; } result = yield * apply(proc, evaluatedArgs, input, environment); } catch (err) { if(!err.position) { // add the position field to the error err.position = expr.position; } if (!err.token) { // and the function identifier err.token = procName; } throw err; } return result; } /** * 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(proc, args, input, environment) { var result; result = yield * applyInner(proc, args, input, environment); while(isLambda(result) && result.thunk === true) { // trampoline loop - this gets invoked as a result of tail-call optimization // the function returned a tail-call thunk // unpack it, evaluate its arguments, and apply the tail call var next = yield * evaluate(result.body.procedure, result.input, result.environment); if(result.body.procedure.type === 'variable') { next.token = result.body.procedure.value; } next.position = result.body.procedure.position; var evaluatedArgs = []; for(var ii = 0; ii < result.body.arguments.length; ii++) { evaluatedArgs.push(yield * evaluate(result.body.arguments[ii], result.input, result.environment)); } result = yield * applyInner(next, evaluatedArgs, input, environment); } return result; } /** * 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* applyInner(proc, args, input, environment) { var result; try { var validatedArgs = args; if (proc) { validatedArgs = validateArguments(proc.signature, args, input); } if (isLambda(proc)) { result = yield* applyProcedure(proc, validatedArgs); } else if (proc && proc._jsonata_function === true) { var 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 = yield* result; } } else if (typeof proc === 'function') { // 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. $func().next().next() result = proc.apply(input, validatedArgs); /* istanbul ignore next */ if (isIterable(result)) { result = yield* result; } } else { throw { code: "T1006", stack: (new Error()).stack }; } } catch(err) { if(proc) { if (typeof err.token == 'undefined' && typeof proc.token !== 'undefined') { err.token = proc.token; } err.position = proc.position; } throw err; } return result; } /** * 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 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 = function*(self, args) { return yield * apply(procedure, args, input, self.environment); }; 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(expr, input, environment) { // partially apply a function var result; // evaluate the arguments var evaluatedArgs = []; for(var ii = 0; ii < expr.arguments.length; ii++) { var arg = expr.arguments[ii]; if (arg.type === 'operator' && arg.value === '?') { evaluatedArgs.push(arg); } else { evaluatedArgs.push(yield * evaluate(arg, input, environment)); } } // lookup the procedure var proc = yield * evaluate(expr.procedure, input, environment); if (typeof proc === 'undefined' && expr.procedure.type === 'path' && environment.lookup(expr.procedure.steps[0].value)) { // help the user out here if they simply forgot the leading $ throw { code: "T1007", stack: (new Error()).stack, position: expr.position, token: expr.procedure.steps[0].value }; } if (isLambda(proc)) { result = partialApplyProcedure(proc, evaluatedArgs); } else if (proc && proc._jsonata_function === true) { result = partialApplyNativeFunction(proc.implementation, evaluatedArgs); } else if (typeof proc === 'function') { result = partialApplyNativeFunction(proc, evaluatedArgs); } else { throw { code: "T1008", stack: (new Error()).stack, position: expr.position, token: expr.procedure.type === 'path' ? expr.procedure.steps[0].value : expr.procedure.value }; } return result; } /** * 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 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(proc, args) { var result; var env = createFrame(proc.environment); proc.arguments.forEach(function (param, index) { env.bind(param.value, args[index]); }); if (typeof proc.body === 'function') { // this is a lambda that wraps a native function - generated by partially evaluating a native result = yield * applyNativeFunction(proc.body, env); } else { result = yield * evaluate(proc.body, proc.input, env); } return result; } /** * 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 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(proc, env) { var sigArgs = getNativeFunctionArguments(proc); // generate the array of arguments for invoking the function - look them up in the environment var args = sigArgs.map(function (sigArg) { return env.lookup(sigArg.trim()); }); var focus = { environment: env }; var result = proc.apply(focus, args); if(isIterable(result)) { result = yield * result; } return result; } /** * Get native function arguments * @param {Function} func - Function * @returns {*|Array} Native function 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(expr, focus) { // undefined inputs always return undefined if(typeof expr === 'undefined') { return undefined; } var input = this.input; if(typeof focus !== 'undefined') { input = focus; } try { var ast = parser(expr, false); } catch(err) { // error parsing the expression passed to $eval populateMessage(err); throw { stack: (new Error()).stack, code: "D3120", value: err.message, error: err }; } try { var result = yield* evaluate(ast, input, this.environment); } catch(err) { // error evaluating the expression passed to $eval populateMessage(err); throw { stack: (new Error()).stack, code: "D3121", value:err.message, error: err }; } return result; } /** * Clones an object * @param {Object} arg - object to clone (deep copy) * @returns {*} - the cloned object */ 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 (name, value) { bindings[name] = value; }, lookup: function (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, global: enclosingEnvironment ? enclosingEnvironment.global : { ancestry: [ null ] } }; } // Function registration staticFrame.bind('sum', defineFunction(fn.sum, ':n>')); staticFrame.bind('count', defineFunction(fn.count, '')); staticFrame.bind('max', defineFunction(fn.max, ':n>')); staticFrame.bind('min', defineFunction(fn.min, ':n>')); staticFrame.bind('average', defineFunction(fn.average, ':n>')); staticFrame.bind('string', defineFunction(fn.string, '')); staticFrame.bind('substring', defineFunction(fn.substring, '')); staticFrame.bind('substringBefore', defineFunction(fn.substringBefore, '')); staticFrame.bind('substringAfter', defineFunction(fn.substringAfter, '')); staticFrame.bind('lowercase', defineFunction(fn.lowercase, '')); staticFrame.bind('uppercase', defineFunction(fn.uppercase, '')); staticFrame.bind('length', defineFunction(fn.length, '')); staticFrame.bind('trim', defineFunction(fn.trim, '')); staticFrame.bind('pad', defineFunction(fn.pad, '')); staticFrame.bind('match', defineFunction(fn.match, 'n?:a>')); staticFrame.bind('contains', defineFunction(fn.contains, '')); // TODO ):b> staticFrame.bind('replace', defineFunction(fn.replace, '')); // TODO )(sf)n?:s> staticFrame.bind('split', defineFunction(fn.split, '>')); // TODO )n?:a> staticFrame.bind('join', defineFunction(fn.join, 's?:s>')); staticFrame.bind('formatNumber', defineFunction(fn.formatNumber, '')); staticFrame.bind('formatBase', defineFunction(fn.formatBase, '')); staticFrame.bind('formatInteger', defineFunction(datetime.formatInteger, '')); staticFrame.bind('parseInteger', defineFunction(datetime.parseInteger, '')); staticFrame.bind('number', defineFunction(fn.number, '<(nsb)-:n>')); staticFrame.bind('floor', defineFunction(fn.floor, '')); staticFrame.bind('ceil', defineFunction(fn.ceil, '')); staticFrame.bind('round', defineFunction(fn.round, '')); staticFrame.bind('abs', defineFunction(fn.abs, '')); staticFrame.bind('sqrt', defineFunction(fn.sqrt, '')); staticFrame.bind('power', defineFunction(fn.power, '')); staticFrame.bind('random', defineFunction(fn.random, '<:n>')); staticFrame.bind('boolean', defineFunction(fn.boolean, '')); staticFrame.bind('not', defineFunction(fn.not, '')); staticFrame.bind('map', defineFunction(fn.map, '')); staticFrame.bind('zip', defineFunction(fn.zip, '')); staticFrame.bind('filter', defineFunction(fn.filter, '')); staticFrame.bind('single', defineFunction(fn.single, '')); staticFrame.bind('reduce', defineFunction(fn.foldLeft, '')); // TODO aj?:j> staticFrame.bind('sift', defineFunction(fn.sift, '')); staticFrame.bind('keys', defineFunction(fn.keys, '>')); staticFrame.bind('lookup', defineFunction(fn.lookup, '')); staticFrame.bind('append', defineFunction(fn.append, '')); staticFrame.bind('exists', defineFunction(fn.exists, '')); staticFrame.bind('spread', defineFunction(fn.spread, '>')); staticFrame.bind('merge', defineFunction(fn.merge, ':o>')); staticFrame.bind('reverse', defineFunction(fn.reverse, '')); staticFrame.bind('each', defineFunction(fn.each, '')); staticFrame.bind('error', defineFunction(fn.error, '')); staticFrame.bind('assert', defineFunction(fn.assert, '')); staticFrame.bind('type', defineFunction(fn.type, '')); staticFrame.bind('sort', defineFunction(fn.sort, '')); staticFrame.bind('shuffle', defineFunction(fn.shuffle, '')); staticFrame.bind('distinct', defineFunction(fn.distinct, '')); staticFrame.bind('base64encode', defineFunction(fn.base64encode, '')); staticFrame.bind('base64decode', defineFunction(fn.base64decode, '')); staticFrame.bind('encodeUrlComponent', defineFunction(fn.encodeUrlComponent, '')); staticFrame.bind('encodeUrl', defineFunction(fn.encodeUrl, '')); staticFrame.bind('decodeUrlComponent', defineFunction(fn.decodeUrlComponent, '')); staticFrame.bind('decodeUrl', defineFunction(fn.decodeUrl, '')); staticFrame.bind('eval', defineFunction(functionEval, '')); staticFrame.bind('toMillis', defineFunction(datetime.toMillis, '')); staticFrame.bind('fromMillis', defineFunction(datetime.fromMillis, '')); 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}}", "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 {boolean} options - recover: attempt to recover on parse error * @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); }, '')); environment.bind('millis', defineFunction(function() { return timestamp.getTime(); }, '<:n>')); return { evaluate: function (input, bindings, callback) { // throw if the expression compiled with syntax errors if(typeof errors !== 'undefined') { var err = { code: 'S0500', position: 0 }; populateMessage(err); // possible side-effects on `err` throw err; } if (typeof bindings !== 'undefined') { var exec_env; // the variable bindings have been passed in - create a frame to hold these exec_env = createFrame(environment); for (var 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; } var result, it; // if a callback function is supplied, then drive the generator in a promise chain if(typeof callback === 'function') { exec_env.async = true; var catchHandler = function (err) { populateMessage(err); // possible side-effects on `err` callback(err, null); }; var thenHandler = function (response) { result = it.next(response); if (result.done) { callback(null, result.value); } else { result.value.then(thenHandler).catch(catchHandler); } }; it = evaluate(ast, input, exec_env); result = it.next(); result.value.then(thenHandler).catch(catchHandler); } else { // no callback function - drive the generator to completion synchronously try { it = evaluate(ast, input, exec_env); result = it.next(); while (!result.done) { result = it.next(result.value); } return result.value; } catch (err) { // insert error message into structure populateMessage(err); // possible side-effects on `err` throw err; } } }, assign: function (name, value) { environment.bind(name, value); }, registerFunction: function(name, implementation, signature) { var func = defineFunction(implementation, signature); environment.bind(name, func); }, ast: function() { return ast; }, errors: function() { 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){ /** * © 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'); const parser = (() => { '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 (path) { var position = 0; var length = path.length; var create = function (type, value) { var obj = {type: type, value: value, position: position}; return obj; }; var scanRegex = function () { // 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; while (position < length) { var currentChar = path.charAt(position); if (currentChar === '/' && path.charAt(position - 1) !== '\\' && depth === 0) { // 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 (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 (source, recover) { var node; var lexer; var symbol_table = {}; var errors = []; var remainingTokens = function () { 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 () { // 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 (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 (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 (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 (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 (id) { var s = symbol(id, 0); s.nud = function () { return this; }; }; // match infix operators // // left associative var infix = function (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 // // right associative var infixr = function (id, bp, led) { var s = symbol(id, bp); s.led = led; return s; }; // match prefix operators // var prefix = function (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 (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 (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 (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(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(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 (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(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){ /** * © 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'); const signature = (() => { '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 * @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 () { params.push(param); prevParam = param; param = {}; }; var findClosingBracket = function (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 (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 (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 (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){ /** * © Copyright IBM Corp. 2016, 2018 All Rights Reserved * Project name: JSONata * This project is licensed under the MIT License, see LICENSE */ const utils = (() => { '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 $Symbol = typeof Symbol === "function" ? Symbol : {}; // istanbul ignore next var iteratorSymbol = $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; } return { isNumeric, isArrayOfStrings, isArrayOfNumbers, createSequence, isSequence, isFunction, isLambda, isIterable, getFunctionArity, isDeepEqual }; })(); module.exports = utils; },{}]},{},[3])(3) }); /***/ }), /***/ 375: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const {PassThrough: PassThroughStream} = __webpack_require__(413); module.exports = options => { options = {...options}; const {array} = options; let {encoding} = options; const isBuffer = encoding === 'buffer'; let objectMode = false; if (array) { objectMode = !(encoding || isBuffer); } else { encoding = encoding || 'utf8'; } if (isBuffer) { encoding = null; } const stream = new PassThroughStream({objectMode}); if (encoding) { stream.setEncoding(encoding); } let length = 0; const chunks = []; stream.on('data', chunk => { chunks.push(chunk); if (objectMode) { length = chunks.length; } else { length += chunk.length; } }); stream.getBufferedValue = () => { if (array) { return chunks; } return isBuffer ? Buffer.concat(chunks, length) : chunks.join(''); }; stream.getBufferedLength = () => length; return stream; }; /***/ }), /***/ 390: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const EventEmitter = __webpack_require__(614); const urlLib = __webpack_require__(835); const normalizeUrl = __webpack_require__(53); const getStream = __webpack_require__(997); const CachePolicy = __webpack_require__(154); const Response = __webpack_require__(93); const lowercaseKeys = __webpack_require__(474); const cloneResponse = __webpack_require__(325); const Keyv = __webpack_require__(303); class CacheableRequest { constructor(request, cacheAdapter) { if (typeof request !== 'function') { throw new TypeError('Parameter `request` must be a function'); } this.cache = new Keyv({ uri: typeof cacheAdapter === 'string' && cacheAdapter, store: typeof cacheAdapter !== 'string' && cacheAdapter, namespace: 'cacheable-request' }); return this.createCacheableRequest(request); } createCacheableRequest(request) { return (opts, cb) => { let url; if (typeof opts === 'string') { url = normalizeUrlObject(urlLib.parse(opts)); opts = {}; } else if (opts instanceof urlLib.URL) { url = normalizeUrlObject(urlLib.parse(opts.toString())); opts = {}; } else { const [pathname, ...searchParts] = (opts.path || '').split('?'); const search = searchParts.length > 0 ? `?${searchParts.join('?')}` : ''; url = normalizeUrlObject({ ...opts, pathname, search }); } opts = { headers: {}, method: 'GET', cache: true, strictTtl: false, automaticFailover: false, ...opts, ...urlObjectToRequestOptions(url) }; opts.headers = lowercaseKeys(opts.headers); const ee = new EventEmitter(); const normalizedUrlString = normalizeUrl( urlLib.format(url), { stripWWW: false, removeTrailingSlash: false, stripAuthentication: false } ); const key = `${opts.method}:${normalizedUrlString}`; let revalidate = false; let madeRequest = false; const makeRequest = opts => { madeRequest = true; let requestErrored = false; let requestErrorCallback; const requestErrorPromise = new Promise(resolve => { requestErrorCallback = () => { if (!requestErrored) { requestErrored = true; resolve(); } }; }); const handler = response => { if (revalidate && !opts.forceRefresh) { response.status = response.statusCode; const revalidatedPolicy = CachePolicy.fromObject(revalidate.cachePolicy).revalidatedPolicy(opts, response); if (!revalidatedPolicy.modified) { const headers = revalidatedPolicy.policy.responseHeaders(); response = new Response(revalidate.statusCode, headers, revalidate.body, revalidate.url); response.cachePolicy = revalidatedPolicy.policy; response.fromCache = true; } } if (!response.fromCache) { response.cachePolicy = new CachePolicy(opts, response, opts); response.fromCache = false; } let clonedResponse; if (opts.cache && response.cachePolicy.storable()) { clonedResponse = cloneResponse(response); (async () => { try { const bodyPromise = getStream.buffer(response); await Promise.race([ requestErrorPromise, new Promise(resolve => response.once('end', resolve)) ]); if (requestErrored) { return; } const body = await bodyPromise; const value = { cachePolicy: response.cachePolicy.toObject(), url: response.url, statusCode: response.fromCache ? revalidate.statusCode : response.statusCode, body }; let ttl = opts.strictTtl ? response.cachePolicy.timeToLive() : undefined; if (opts.maxTtl) { ttl = ttl ? Math.min(ttl, opts.maxTtl) : opts.maxTtl; } await this.cache.set(key, value, ttl); } catch (error) { ee.emit('error', new CacheableRequest.CacheError(error)); } })(); } else if (opts.cache && revalidate) { (async () => { try { await this.cache.delete(key); } catch (error) { ee.emit('error', new CacheableRequest.CacheError(error)); } })(); } ee.emit('response', clonedResponse || response); if (typeof cb === 'function') { cb(clonedResponse || response); } }; try { const req = request(opts, handler); req.once('error', requestErrorCallback); req.once('abort', requestErrorCallback); ee.emit('request', req); } catch (error) { ee.emit('error', new CacheableRequest.RequestError(error)); } }; (async () => { const get = async opts => { await Promise.resolve(); const cacheEntry = opts.cache ? await this.cache.get(key) : undefined; if (typeof cacheEntry === 'undefined') { return makeRequest(opts); } const policy = CachePolicy.fromObject(cacheEntry.cachePolicy); if (policy.satisfiesWithoutRevalidation(opts) && !opts.forceRefresh) { const headers = policy.responseHeaders(); const response = new Response(cacheEntry.statusCode, headers, cacheEntry.body, cacheEntry.url); response.cachePolicy = policy; response.fromCache = true; ee.emit('response', response); if (typeof cb === 'function') { cb(response); } } else { revalidate = cacheEntry; opts.headers = policy.revalidationHeaders(opts); makeRequest(opts); } }; const errorHandler = error => ee.emit('error', new CacheableRequest.CacheError(error)); this.cache.once('error', errorHandler); ee.on('response', () => this.cache.removeListener('error', errorHandler)); try { await get(opts); } catch (error) { if (opts.automaticFailover && !madeRequest) { makeRequest(opts); } ee.emit('error', new CacheableRequest.CacheError(error)); } })(); return ee; }; } } function urlObjectToRequestOptions(url) { const options = { ...url }; options.path = `${url.pathname || '/'}${url.search || ''}`; delete options.pathname; delete options.search; return options; } function normalizeUrlObject(url) { // If url was parsed by url.parse or new URL: // - hostname will be set // - host will be hostname[:port] // - port will be set if it was explicit in the parsed string // Otherwise, url was from request options: // - hostname or host may be set // - host shall not have port encoded return { protocol: url.protocol, auth: url.auth, hostname: url.hostname || url.host || 'localhost', port: url.port, pathname: url.pathname, search: url.search }; } CacheableRequest.RequestError = class extends Error { constructor(error) { super(error.message); this.name = 'RequestError'; Object.assign(this, error); } }; CacheableRequest.CacheError = class extends Error { constructor(error) { super(error.message); this.name = 'CacheError'; Object.assign(this, error); } }; module.exports = CacheableRequest; /***/ }), /***/ 413: /***/ (function(module) { module.exports = require("stream"); /***/ }), /***/ 431: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const os = __importStar(__webpack_require__(87)); /** * Commands * * Command Format: * ::name key=value,key=value::message * * Examples: * ::warning::This is the message * ::set-env name=MY_VAR::some value */ function issueCommand(command, properties, message) { const cmd = new Command(command, properties, message); process.stdout.write(cmd.toString() + os.EOL); } exports.issueCommand = issueCommand; function issue(name, message = '') { issueCommand(name, {}, message); } exports.issue = issue; const CMD_STRING = '::'; class Command { constructor(command, properties, message) { if (!command) { command = 'missing.command'; } this.command = command; this.properties = properties; this.message = message; } toString() { let cmdStr = CMD_STRING + this.command; if (this.properties && Object.keys(this.properties).length > 0) { cmdStr += ' '; let first = true; for (const key in this.properties) { if (this.properties.hasOwnProperty(key)) { const val = this.properties[key]; if (val) { if (first) { first = false; } else { cmdStr += ','; } cmdStr += `${key}=${escapeProperty(val)}`; } } } } cmdStr += `${CMD_STRING}${escapeData(this.message)}`; return cmdStr; } } function escapeData(s) { return (s || '') .replace(/%/g, '%25') .replace(/\r/g, '%0D') .replace(/\n/g, '%0A'); } function escapeProperty(s) { return (s || '') .replace(/%/g, '%25') .replace(/\r/g, '%0D') .replace(/\n/g, '%0A') .replace(/:/g, '%3A') .replace(/,/g, '%2C'); } //# sourceMappingURL=command.js.map /***/ }), /***/ 452: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // TODO: Update https://github.com/sindresorhus/get-stream const getBuffer = async (stream) => { const chunks = []; let length = 0; for await (const chunk of stream) { chunks.push(chunk); length += Buffer.byteLength(chunk); } if (Buffer.isBuffer(chunks[0])) { return Buffer.concat(chunks, length); } return Buffer.from(chunks.join('')); }; exports.default = getBuffer; /***/ }), /***/ 453: /***/ (function(module, __unusedexports, __webpack_require__) { var once = __webpack_require__(49) var eos = __webpack_require__(9) var fs = __webpack_require__(747) // we only need fs to get the ReadStream and WriteStream prototypes var noop = function () {} var ancient = /^v?\.0/.test(process.version) var isFn = function (fn) { return typeof fn === 'function' } var isFS = function (stream) { if (!ancient) return false // newer node version do not need to care about fs is a special way if (!fs) return false // browser return (stream instanceof (fs.ReadStream || noop) || stream instanceof (fs.WriteStream || noop)) && isFn(stream.close) } var isRequest = function (stream) { return stream.setHeader && isFn(stream.abort) } var destroyer = function (stream, reading, writing, callback) { callback = once(callback) var closed = false stream.on('close', function () { closed = true }) eos(stream, {readable: reading, writable: writing}, function (err) { if (err) return callback(err) closed = true callback() }) var destroyed = false return function (err) { if (closed) return if (destroyed) return destroyed = true if (isFS(stream)) return stream.close(noop) // use close for fs streams to avoid fd leaks if (isRequest(stream)) return stream.abort() // request.destroy just do .end - .abort is what we want if (isFn(stream.destroy)) return stream.destroy() callback(err || new Error('stream was destroyed')) } } var call = function (fn) { fn() } var pipe = function (from, to) { return from.pipe(to) } var pump = function () { var streams = Array.prototype.slice.call(arguments) var callback = isFn(streams[streams.length - 1] || noop) && streams.pop() || noop if (Array.isArray(streams[0])) streams = streams[0] if (streams.length < 2) throw new Error('pump requires two streams per minimum') var error var destroys = streams.map(function (stream, i) { var reading = i < streams.length - 1 var writing = i > 0 return destroyer(stream, reading, writing, function (err) { if (!error) error = err if (err) destroys.forEach(call) if (reading) return destroys.forEach(call) callback(error) }) }) return streams.reduce(pipe) } module.exports = pump /***/ }), /***/ 460: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const is_1 = __webpack_require__(534); exports.default = (body) => is_1.default.nodeStream(body) && is_1.default.function_(body.getBoundary); /***/ }), /***/ 461: /***/ (function(module, __unusedexports, __webpack_require__) { const jsonata = __webpack_require__(350); /** * @typedef {Object} SecretRequest * @property {string} path * @property {string} selector */ /** * @template {SecretRequest} TRequest * @typedef {Object} SecretResponse * @property {TRequest} request * @property {string} value * @property {boolean} cachedResponse */ /** * @template TRequest * @param {Array} secretRequests * @param {import('got').Got} client * @return {Promise[]>} */ async function getSecrets(secretRequests, client) { const responseCache = new Map(); const results = []; for (const secretRequest of secretRequests) { const { path, selector } = secretRequest; const requestPath = `v1${path}`; let body; let cachedResponse = false; if (responseCache.has(requestPath)) { body = responseCache.get(requestPath); cachedResponse = true; } else { const result = await client.get(requestPath); body = result.body; responseCache.set(requestPath, body); } const value = selectData(JSON.parse(body), selector); results.push({ request: secretRequest, value, cachedResponse }); } return results; } /** * Uses a Jsonata selector retrieve a bit of data from the result * @param {object} data * @param {string} selector */ function selectData(data, selector) { const ata = jsonata(selector); let result = JSON.stringify(ata.evaluate(data)); // Compat for custom engines if (!result && ata.ast().type === "path" && ata.ast()['steps'].length === 1 && selector !== 'data' && 'data' in data) { result = JSON.stringify(jsonata(`data.${selector}`).evaluate(data)); } else if (!result) { throw Error(`Unable to retrieve result for ${selector}. No match data was found. Double check your Key or Selector.`); } if (result.startsWith(`"`)) { result = result.substring(1, result.length - 1); } return result; } module.exports = { getSecrets, selectData } /***/ }), /***/ 468: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseBody = exports.knownBodyTypes = void 0; const is_1 = __webpack_require__(534); const types_1 = __webpack_require__(36); const core_1 = __webpack_require__(946); if (!core_1.knownHookEvents.includes('beforeRetry')) { core_1.knownHookEvents.push('beforeRetry', 'afterResponse'); } exports.knownBodyTypes = ['json', 'buffer', 'text']; exports.parseBody = (response, responseType, parseJson, encoding) => { const { rawBody } = response; try { if (responseType === 'text') { return rawBody.toString(encoding); } if (responseType === 'json') { return rawBody.length === 0 ? '' : parseJson(rawBody.toString()); } if (responseType === 'buffer') { return Buffer.from(rawBody); } throw new types_1.ParseError({ message: `Unknown body type '${responseType}'`, name: 'Error' }, response); } catch (error) { throw new types_1.ParseError(error, response); } }; class PromisableRequest extends core_1.default { static normalizeArguments(url, nonNormalizedOptions, defaults) { const options = super.normalizeArguments(url, nonNormalizedOptions, defaults); if (is_1.default.null_(options.encoding)) { throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead'); } is_1.assert.any([is_1.default.string, is_1.default.undefined], options.encoding); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.resolveBodyOnly); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.methodRewriting); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.isStream); is_1.assert.any([is_1.default.string, is_1.default.undefined], options.responseType); // `options.responseType` if (options.responseType === undefined) { options.responseType = 'text'; } // `options.retry` const { retry } = options; if (defaults) { options.retry = { ...defaults.retry }; } else { options.retry = { calculateDelay: retryObject => retryObject.computedValue, limit: 0, methods: [], statusCodes: [], errorCodes: [], maxRetryAfter: undefined }; } if (is_1.default.object(retry)) { options.retry = { ...options.retry, ...retry }; options.retry.methods = [...new Set(options.retry.methods.map(method => method.toUpperCase()))]; options.retry.statusCodes = [...new Set(options.retry.statusCodes)]; options.retry.errorCodes = [...new Set(options.retry.errorCodes)]; } else if (is_1.default.number(retry)) { options.retry.limit = retry; } if (is_1.default.undefined(options.retry.maxRetryAfter)) { options.retry.maxRetryAfter = Math.min( // TypeScript is not smart enough to handle `.filter(x => is.number(x))`. // eslint-disable-next-line unicorn/no-fn-reference-in-iterator ...[options.timeout.request, options.timeout.connect].filter(is_1.default.number)); } // `options.pagination` if (is_1.default.object(options.pagination)) { if (defaults) { options.pagination = { ...defaults.pagination, ...options.pagination }; } const { pagination } = options; if (!is_1.default.function_(pagination.transform)) { throw new Error('`options.pagination.transform` must be implemented'); } if (!is_1.default.function_(pagination.shouldContinue)) { throw new Error('`options.pagination.shouldContinue` must be implemented'); } if (!is_1.default.function_(pagination.filter)) { throw new TypeError('`options.pagination.filter` must be implemented'); } if (!is_1.default.function_(pagination.paginate)) { throw new Error('`options.pagination.paginate` must be implemented'); } } // JSON mode if (options.responseType === 'json' && options.headers.accept === undefined) { options.headers.accept = 'application/json'; } return options; } static mergeOptions(...sources) { let mergedOptions; for (const source of sources) { mergedOptions = PromisableRequest.normalizeArguments(undefined, source, mergedOptions); } return mergedOptions; } _beforeError(error) { if (this.destroyed) { return; } if (!(error instanceof core_1.RequestError)) { error = new core_1.RequestError(error.message, error, this); } // Let the promise decide whether to abort or not // It is also responsible for the `beforeError` hook this.emit('error', error); } } exports.default = PromisableRequest; /***/ }), /***/ 470: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const command_1 = __webpack_require__(431); const os = __importStar(__webpack_require__(87)); const path = __importStar(__webpack_require__(622)); /** * The code to exit an action */ var ExitCode; (function (ExitCode) { /** * A code indicating that the action was successful */ ExitCode[ExitCode["Success"] = 0] = "Success"; /** * A code indicating that the action was a failure */ ExitCode[ExitCode["Failure"] = 1] = "Failure"; })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); //----------------------------------------------------------------------- // Variables //----------------------------------------------------------------------- /** * Sets env variable for this action and future actions in the job * @param name the name of the variable to set * @param val the value of the variable */ function exportVariable(name, val) { process.env[name] = val; command_1.issueCommand('set-env', { name }, val); } exports.exportVariable = exportVariable; /** * Registers a secret which will get masked from logs * @param secret value of the secret */ function setSecret(secret) { command_1.issueCommand('add-mask', {}, secret); } exports.setSecret = setSecret; /** * Prepends inputPath to the PATH (for this action and future actions) * @param inputPath */ function addPath(inputPath) { command_1.issueCommand('add-path', {}, inputPath); process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; } exports.addPath = addPath; /** * Gets the value of an input. The value is also trimmed. * * @param name name of the input to get * @param options optional. See InputOptions. * @returns string */ function getInput(name, options) { const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; if (options && options.required && !val) { throw new Error(`Input required and not supplied: ${name}`); } return val.trim(); } exports.getInput = getInput; /** * Sets the value of an output. * * @param name name of the output to set * @param value value to store */ function setOutput(name, value) { command_1.issueCommand('set-output', { name }, value); } exports.setOutput = setOutput; //----------------------------------------------------------------------- // Results //----------------------------------------------------------------------- /** * Sets the action status to failed. * When the action exits it will be with an exit code of 1 * @param message add error issue message */ function setFailed(message) { process.exitCode = ExitCode.Failure; error(message); } exports.setFailed = setFailed; //----------------------------------------------------------------------- // Logging Commands //----------------------------------------------------------------------- /** * Gets whether Actions Step Debug is on or not */ function isDebug() { return process.env['RUNNER_DEBUG'] === '1'; } exports.isDebug = isDebug; /** * Writes debug message to user log * @param message debug message */ function debug(message) { command_1.issueCommand('debug', {}, message); } exports.debug = debug; /** * Adds an error issue * @param message error issue message */ function error(message) { command_1.issue('error', message); } exports.error = error; /** * Adds an warning issue * @param message warning issue message */ function warning(message) { command_1.issue('warning', message); } exports.warning = warning; /** * Writes info to log with console.log. * @param message info message */ function info(message) { process.stdout.write(message + os.EOL); } exports.info = info; /** * Begin an output group. * * Output until the next `groupEnd` will be foldable in this group * * @param name The name of the output group */ function startGroup(name) { command_1.issue('group', name); } exports.startGroup = startGroup; /** * End an output group. */ function endGroup() { command_1.issue('endgroup'); } exports.endGroup = endGroup; /** * Wrap an asynchronous function call in a group. * * Returns the same type as the function itself. * * @param name The name of the group * @param fn The function to wrap in the group */ function group(name, fn) { return __awaiter(this, void 0, void 0, function* () { startGroup(name); let result; try { result = yield fn(); } finally { endGroup(); } return result; }); } exports.group = group; //----------------------------------------------------------------------- // Wrapper action state //----------------------------------------------------------------------- /** * Saves state for current action, the state can only be retrieved by this action's post job execution. * * @param name name of the state to store * @param value value to store */ function saveState(name, value) { command_1.issueCommand('save-state', { name }, value); } exports.saveState = saveState; /** * Gets the value of an state set by this action's main execution. * * @param name name of the state to get * @returns string */ function getState(name) { return process.env[`STATE_${name}`] || ''; } exports.getState = getState; //# sourceMappingURL=core.js.map /***/ }), /***/ 474: /***/ (function(module) { "use strict"; module.exports = object => { const result = {}; for (const [key, value] of Object.entries(object)) { result[key.toLowerCase()] = value; } return result; }; /***/ }), /***/ 490: /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const defer_to_connect_1 = __webpack_require__(790); const nodejsMajorVersion = Number(process.versions.node.split('.')[0]); const timer = (request) => { const timings = { start: Date.now(), socket: undefined, lookup: undefined, connect: undefined, secureConnect: undefined, upload: undefined, response: undefined, end: undefined, error: undefined, abort: undefined, phases: { wait: undefined, dns: undefined, tcp: undefined, tls: undefined, request: undefined, firstByte: undefined, download: undefined, total: undefined } }; request.timings = timings; const handleError = (origin) => { const emit = origin.emit.bind(origin); origin.emit = (event, ...args) => { // Catches the `error` event if (event === 'error') { timings.error = Date.now(); timings.phases.total = timings.error - timings.start; origin.emit = emit; } // Saves the original behavior return emit(event, ...args); }; }; handleError(request); request.prependOnceListener('abort', () => { timings.abort = Date.now(); // Let the `end` response event be responsible for setting the total phase, // unless the Node.js major version is >= 13. if (!timings.response || nodejsMajorVersion >= 13) { timings.phases.total = Date.now() - timings.start; } }); const onSocket = (socket) => { timings.socket = Date.now(); timings.phases.wait = timings.socket - timings.start; const lookupListener = () => { timings.lookup = Date.now(); timings.phases.dns = timings.lookup - timings.socket; }; socket.prependOnceListener('lookup', lookupListener); defer_to_connect_1.default(socket, { connect: () => { timings.connect = Date.now(); if (timings.lookup === undefined) { socket.removeListener('lookup', lookupListener); timings.lookup = timings.connect; timings.phases.dns = timings.lookup - timings.socket; } timings.phases.tcp = timings.connect - timings.lookup; // This callback is called before flushing any data, // so we don't need to set `timings.phases.request` here. }, secureConnect: () => { timings.secureConnect = Date.now(); timings.phases.tls = timings.secureConnect - timings.connect; } }); }; if (request.socket) { onSocket(request.socket); } else { request.prependOnceListener('socket', onSocket); } const onUpload = () => { var _a; timings.upload = Date.now(); timings.phases.request = timings.upload - (_a = timings.secureConnect, (_a !== null && _a !== void 0 ? _a : timings.connect)); }; const writableFinished = () => { if (typeof request.writableFinished === 'boolean') { return request.writableFinished; } // Node.js doesn't have `request.writableFinished` property return request.finished && request.outputSize === 0 && (!request.socket || request.socket.writableLength === 0); }; if (writableFinished()) { onUpload(); } else { request.prependOnceListener('finish', onUpload); } request.prependOnceListener('response', (response) => { timings.response = Date.now(); timings.phases.firstByte = timings.response - timings.upload; response.timings = timings; handleError(response); response.prependOnceListener('end', () => { timings.end = Date.now(); timings.phases.download = timings.end - timings.response; timings.phases.total = timings.end - timings.start; }); }); return timings; }; exports.default = timer; // For CommonJS default export support module.exports = timer; module.exports.default = timer; /***/ }), /***/ 492: /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { const core = __webpack_require__(470); const { exportSecrets } = __webpack_require__(928); (async () => { try { await core.group('Test Get Vault Secrets', exportSecrets); } catch (error) { core.setFailed(error.message); } })(); /***/ }), /***/ 507: /***/ (function(module) { "use strict"; /* istanbul ignore file: https://github.com/nodejs/node/blob/a91293d4d9ab403046ab5eb022332e4e3d249bd3/lib/internal/url.js#L1257 */ module.exports = url => { const options = { protocol: url.protocol, hostname: typeof url.hostname === 'string' && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, host: url.host, hash: url.hash, search: url.search, pathname: url.pathname, href: url.href, path: `${url.pathname || ''}${url.search || ''}` }; if (typeof url.port === 'string' && url.port.length !== 0) { options.port = Number(url.port); } if (url.username || url.password) { options.auth = `${url.username || ''}:${url.password || ''}`; } return options; }; /***/ }), /***/ 524: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const tls = __webpack_require__(16); module.exports = (options = {}) => new Promise((resolve, reject) => { const socket = tls.connect(options, () => { if (options.resolveSocket) { socket.off('error', reject); resolve({alpnProtocol: socket.alpnProtocol, socket}); } else { socket.destroy(); resolve({alpnProtocol: socket.alpnProtocol}); } }); socket.on('error', reject); }); /***/ }), /***/ 534: /***/ (function(module, exports) { "use strict"; /// /// /// Object.defineProperty(exports, "__esModule", { value: true }); const typedArrayTypeNames = [ 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array' ]; function isTypedArrayName(name) { return typedArrayTypeNames.includes(name); } const objectTypeNames = [ 'Function', 'Generator', 'AsyncGenerator', 'GeneratorFunction', 'AsyncGeneratorFunction', 'AsyncFunction', 'Observable', 'Array', 'Buffer', 'Object', 'RegExp', 'Date', 'Error', 'Map', 'Set', 'WeakMap', 'WeakSet', 'ArrayBuffer', 'SharedArrayBuffer', 'DataView', 'Promise', 'URL', 'HTMLElement', ...typedArrayTypeNames ]; function isObjectTypeName(name) { return objectTypeNames.includes(name); } const primitiveTypeNames = [ 'null', 'undefined', 'string', 'number', 'bigint', 'boolean', 'symbol' ]; function isPrimitiveTypeName(name) { return primitiveTypeNames.includes(name); } // eslint-disable-next-line @typescript-eslint/ban-types function isOfType(type) { return (value) => typeof value === type; } const { toString } = Object.prototype; const getObjectType = (value) => { const objectTypeName = toString.call(value).slice(8, -1); if (/HTML\w+Element/.test(objectTypeName) && is.domElement(value)) { return 'HTMLElement'; } if (isObjectTypeName(objectTypeName)) { return objectTypeName; } return undefined; }; const isObjectOfType = (type) => (value) => getObjectType(value) === type; function is(value) { if (value === null) { return 'null'; } switch (typeof value) { case 'undefined': return 'undefined'; case 'string': return 'string'; case 'number': return 'number'; case 'boolean': return 'boolean'; case 'function': return 'Function'; case 'bigint': return 'bigint'; case 'symbol': return 'symbol'; default: } if (is.observable(value)) { return 'Observable'; } if (is.array(value)) { return 'Array'; } if (is.buffer(value)) { return 'Buffer'; } const tagType = getObjectType(value); if (tagType) { return tagType; } if (value instanceof String || value instanceof Boolean || value instanceof Number) { throw new TypeError('Please don\'t use object wrappers for primitive types'); } return 'Object'; } is.undefined = isOfType('undefined'); is.string = isOfType('string'); const isNumberType = isOfType('number'); is.number = (value) => isNumberType(value) && !is.nan(value); is.bigint = isOfType('bigint'); // eslint-disable-next-line @typescript-eslint/ban-types is.function_ = isOfType('function'); is.null_ = (value) => value === null; is.class_ = (value) => is.function_(value) && value.toString().startsWith('class '); is.boolean = (value) => value === true || value === false; is.symbol = isOfType('symbol'); is.numericString = (value) => is.string(value) && !is.emptyStringOrWhitespace(value) && !Number.isNaN(Number(value)); is.array = (value, assertion) => { if (!Array.isArray(value)) { return false; } if (!assertion) { return true; } return value.every(assertion); }; is.buffer = (value) => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = value) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.isBuffer) === null || _c === void 0 ? void 0 : _c.call(_b, value)) !== null && _d !== void 0 ? _d : false; }; is.nullOrUndefined = (value) => is.null_(value) || is.undefined(value); is.object = (value) => !is.null_(value) && (typeof value === 'object' || is.function_(value)); is.iterable = (value) => { var _a; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a[Symbol.iterator]); }; is.asyncIterable = (value) => { var _a; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a[Symbol.asyncIterator]); }; is.generator = (value) => is.iterable(value) && is.function_(value.next) && is.function_(value.throw); is.asyncGenerator = (value) => is.asyncIterable(value) && is.function_(value.next) && is.function_(value.throw); is.nativePromise = (value) => isObjectOfType('Promise')(value); const hasPromiseAPI = (value) => { var _a, _b; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a.then) && is.function_((_b = value) === null || _b === void 0 ? void 0 : _b.catch); }; is.promise = (value) => is.nativePromise(value) || hasPromiseAPI(value); is.generatorFunction = isObjectOfType('GeneratorFunction'); is.asyncGeneratorFunction = (value) => getObjectType(value) === 'AsyncGeneratorFunction'; is.asyncFunction = (value) => getObjectType(value) === 'AsyncFunction'; // eslint-disable-next-line no-prototype-builtins, @typescript-eslint/ban-types is.boundFunction = (value) => is.function_(value) && !value.hasOwnProperty('prototype'); is.regExp = isObjectOfType('RegExp'); is.date = isObjectOfType('Date'); is.error = isObjectOfType('Error'); is.map = (value) => isObjectOfType('Map')(value); is.set = (value) => isObjectOfType('Set')(value); is.weakMap = (value) => isObjectOfType('WeakMap')(value); is.weakSet = (value) => isObjectOfType('WeakSet')(value); is.int8Array = isObjectOfType('Int8Array'); is.uint8Array = isObjectOfType('Uint8Array'); is.uint8ClampedArray = isObjectOfType('Uint8ClampedArray'); is.int16Array = isObjectOfType('Int16Array'); is.uint16Array = isObjectOfType('Uint16Array'); is.int32Array = isObjectOfType('Int32Array'); is.uint32Array = isObjectOfType('Uint32Array'); is.float32Array = isObjectOfType('Float32Array'); is.float64Array = isObjectOfType('Float64Array'); is.bigInt64Array = isObjectOfType('BigInt64Array'); is.bigUint64Array = isObjectOfType('BigUint64Array'); is.arrayBuffer = isObjectOfType('ArrayBuffer'); is.sharedArrayBuffer = isObjectOfType('SharedArrayBuffer'); is.dataView = isObjectOfType('DataView'); is.directInstanceOf = (instance, class_) => Object.getPrototypeOf(instance) === class_.prototype; is.urlInstance = (value) => isObjectOfType('URL')(value); is.urlString = (value) => { if (!is.string(value)) { return false; } try { new URL(value); // eslint-disable-line no-new return true; } catch (_a) { return false; } }; // TODO: Use the `not` operator with a type guard here when it's available. // Example: `is.truthy = (value: unknown): value is (not false | not 0 | not '' | not undefined | not null) => Boolean(value);` is.truthy = (value) => Boolean(value); // Example: `is.falsy = (value: unknown): value is (not true | 0 | '' | undefined | null) => Boolean(value);` is.falsy = (value) => !value; is.nan = (value) => Number.isNaN(value); is.primitive = (value) => is.null_(value) || isPrimitiveTypeName(typeof value); is.integer = (value) => Number.isInteger(value); is.safeInteger = (value) => Number.isSafeInteger(value); is.plainObject = (value) => { // From: https://github.com/sindresorhus/is-plain-obj/blob/master/index.js if (toString.call(value) !== '[object Object]') { return false; } const prototype = Object.getPrototypeOf(value); return prototype === null || prototype === Object.getPrototypeOf({}); }; is.typedArray = (value) => isTypedArrayName(getObjectType(value)); const isValidLength = (value) => is.safeInteger(value) && value >= 0; is.arrayLike = (value) => !is.nullOrUndefined(value) && !is.function_(value) && isValidLength(value.length); is.inRange = (value, range) => { if (is.number(range)) { return value >= Math.min(0, range) && value <= Math.max(range, 0); } if (is.array(range) && range.length === 2) { return value >= Math.min(...range) && value <= Math.max(...range); } throw new TypeError(`Invalid range: ${JSON.stringify(range)}`); }; const NODE_TYPE_ELEMENT = 1; const DOM_PROPERTIES_TO_CHECK = [ 'innerHTML', 'ownerDocument', 'style', 'attributes', 'nodeValue' ]; is.domElement = (value) => { return is.object(value) && value.nodeType === NODE_TYPE_ELEMENT && is.string(value.nodeName) && !is.plainObject(value) && DOM_PROPERTIES_TO_CHECK.every(property => property in value); }; is.observable = (value) => { var _a, _b, _c, _d; if (!value) { return false; } // eslint-disable-next-line no-use-extend-native/no-use-extend-native if (value === ((_b = (_a = value)[Symbol.observable]) === null || _b === void 0 ? void 0 : _b.call(_a))) { return true; } if (value === ((_d = (_c = value)['@@observable']) === null || _d === void 0 ? void 0 : _d.call(_c))) { return true; } return false; }; is.nodeStream = (value) => is.object(value) && is.function_(value.pipe) && !is.observable(value); is.infinite = (value) => value === Infinity || value === -Infinity; const isAbsoluteMod2 = (remainder) => (value) => is.integer(value) && Math.abs(value % 2) === remainder; is.evenInteger = isAbsoluteMod2(0); is.oddInteger = isAbsoluteMod2(1); is.emptyArray = (value) => is.array(value) && value.length === 0; is.nonEmptyArray = (value) => is.array(value) && value.length > 0; is.emptyString = (value) => is.string(value) && value.length === 0; // TODO: Use `not ''` when the `not` operator is available. is.nonEmptyString = (value) => is.string(value) && value.length > 0; const isWhiteSpaceString = (value) => is.string(value) && !/\S/.test(value); is.emptyStringOrWhitespace = (value) => is.emptyString(value) || isWhiteSpaceString(value); is.emptyObject = (value) => is.object(value) && !is.map(value) && !is.set(value) && Object.keys(value).length === 0; // TODO: Use `not` operator here to remove `Map` and `Set` from type guard: // - https://github.com/Microsoft/TypeScript/pull/29317 is.nonEmptyObject = (value) => is.object(value) && !is.map(value) && !is.set(value) && Object.keys(value).length > 0; is.emptySet = (value) => is.set(value) && value.size === 0; is.nonEmptySet = (value) => is.set(value) && value.size > 0; is.emptyMap = (value) => is.map(value) && value.size === 0; is.nonEmptyMap = (value) => is.map(value) && value.size > 0; const predicateOnArray = (method, predicate, values) => { if (!is.function_(predicate)) { throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); } if (values.length === 0) { throw new TypeError('Invalid number of values'); } return method.call(values, predicate); }; is.any = (predicate, ...values) => { const predicates = is.array(predicate) ? predicate : [predicate]; return predicates.some(singlePredicate => predicateOnArray(Array.prototype.some, singlePredicate, values)); }; is.all = (predicate, ...values) => predicateOnArray(Array.prototype.every, predicate, values); const assertType = (condition, description, value) => { if (!condition) { throw new TypeError(`Expected value which is \`${description}\`, received value of type \`${is(value)}\`.`); } }; exports.assert = { // Unknowns. undefined: (value) => assertType(is.undefined(value), 'undefined', value), string: (value) => assertType(is.string(value), 'string', value), number: (value) => assertType(is.number(value), 'number', value), bigint: (value) => assertType(is.bigint(value), 'bigint', value), // eslint-disable-next-line @typescript-eslint/ban-types function_: (value) => assertType(is.function_(value), 'Function', value), null_: (value) => assertType(is.null_(value), 'null', value), class_: (value) => assertType(is.class_(value), "Class" /* class_ */, value), boolean: (value) => assertType(is.boolean(value), 'boolean', value), symbol: (value) => assertType(is.symbol(value), 'symbol', value), numericString: (value) => assertType(is.numericString(value), "string with a number" /* numericString */, value), array: (value, assertion) => { const assert = assertType; assert(is.array(value), 'Array', value); if (assertion) { value.forEach(assertion); } }, buffer: (value) => assertType(is.buffer(value), 'Buffer', value), nullOrUndefined: (value) => assertType(is.nullOrUndefined(value), "null or undefined" /* nullOrUndefined */, value), object: (value) => assertType(is.object(value), 'Object', value), iterable: (value) => assertType(is.iterable(value), "Iterable" /* iterable */, value), asyncIterable: (value) => assertType(is.asyncIterable(value), "AsyncIterable" /* asyncIterable */, value), generator: (value) => assertType(is.generator(value), 'Generator', value), asyncGenerator: (value) => assertType(is.asyncGenerator(value), 'AsyncGenerator', value), nativePromise: (value) => assertType(is.nativePromise(value), "native Promise" /* nativePromise */, value), promise: (value) => assertType(is.promise(value), 'Promise', value), generatorFunction: (value) => assertType(is.generatorFunction(value), 'GeneratorFunction', value), asyncGeneratorFunction: (value) => assertType(is.asyncGeneratorFunction(value), 'AsyncGeneratorFunction', value), // eslint-disable-next-line @typescript-eslint/ban-types asyncFunction: (value) => assertType(is.asyncFunction(value), 'AsyncFunction', value), // eslint-disable-next-line @typescript-eslint/ban-types boundFunction: (value) => assertType(is.boundFunction(value), 'Function', value), regExp: (value) => assertType(is.regExp(value), 'RegExp', value), date: (value) => assertType(is.date(value), 'Date', value), error: (value) => assertType(is.error(value), 'Error', value), map: (value) => assertType(is.map(value), 'Map', value), set: (value) => assertType(is.set(value), 'Set', value), weakMap: (value) => assertType(is.weakMap(value), 'WeakMap', value), weakSet: (value) => assertType(is.weakSet(value), 'WeakSet', value), int8Array: (value) => assertType(is.int8Array(value), 'Int8Array', value), uint8Array: (value) => assertType(is.uint8Array(value), 'Uint8Array', value), uint8ClampedArray: (value) => assertType(is.uint8ClampedArray(value), 'Uint8ClampedArray', value), int16Array: (value) => assertType(is.int16Array(value), 'Int16Array', value), uint16Array: (value) => assertType(is.uint16Array(value), 'Uint16Array', value), int32Array: (value) => assertType(is.int32Array(value), 'Int32Array', value), uint32Array: (value) => assertType(is.uint32Array(value), 'Uint32Array', value), float32Array: (value) => assertType(is.float32Array(value), 'Float32Array', value), float64Array: (value) => assertType(is.float64Array(value), 'Float64Array', value), bigInt64Array: (value) => assertType(is.bigInt64Array(value), 'BigInt64Array', value), bigUint64Array: (value) => assertType(is.bigUint64Array(value), 'BigUint64Array', value), arrayBuffer: (value) => assertType(is.arrayBuffer(value), 'ArrayBuffer', value), sharedArrayBuffer: (value) => assertType(is.sharedArrayBuffer(value), 'SharedArrayBuffer', value), dataView: (value) => assertType(is.dataView(value), 'DataView', value), urlInstance: (value) => assertType(is.urlInstance(value), 'URL', value), urlString: (value) => assertType(is.urlString(value), "string with a URL" /* urlString */, value), truthy: (value) => assertType(is.truthy(value), "truthy" /* truthy */, value), falsy: (value) => assertType(is.falsy(value), "falsy" /* falsy */, value), nan: (value) => assertType(is.nan(value), "NaN" /* nan */, value), primitive: (value) => assertType(is.primitive(value), "primitive" /* primitive */, value), integer: (value) => assertType(is.integer(value), "integer" /* integer */, value), safeInteger: (value) => assertType(is.safeInteger(value), "integer" /* safeInteger */, value), plainObject: (value) => assertType(is.plainObject(value), "plain object" /* plainObject */, value), typedArray: (value) => assertType(is.typedArray(value), "TypedArray" /* typedArray */, value), arrayLike: (value) => assertType(is.arrayLike(value), "array-like" /* arrayLike */, value), domElement: (value) => assertType(is.domElement(value), "HTMLElement" /* domElement */, value), observable: (value) => assertType(is.observable(value), 'Observable', value), nodeStream: (value) => assertType(is.nodeStream(value), "Node.js Stream" /* nodeStream */, value), infinite: (value) => assertType(is.infinite(value), "infinite number" /* infinite */, value), emptyArray: (value) => assertType(is.emptyArray(value), "empty array" /* emptyArray */, value), nonEmptyArray: (value) => assertType(is.nonEmptyArray(value), "non-empty array" /* nonEmptyArray */, value), emptyString: (value) => assertType(is.emptyString(value), "empty string" /* emptyString */, value), nonEmptyString: (value) => assertType(is.nonEmptyString(value), "non-empty string" /* nonEmptyString */, value), emptyStringOrWhitespace: (value) => assertType(is.emptyStringOrWhitespace(value), "empty string or whitespace" /* emptyStringOrWhitespace */, value), emptyObject: (value) => assertType(is.emptyObject(value), "empty object" /* emptyObject */, value), nonEmptyObject: (value) => assertType(is.nonEmptyObject(value), "non-empty object" /* nonEmptyObject */, value), emptySet: (value) => assertType(is.emptySet(value), "empty set" /* emptySet */, value), nonEmptySet: (value) => assertType(is.nonEmptySet(value), "non-empty set" /* nonEmptySet */, value), emptyMap: (value) => assertType(is.emptyMap(value), "empty map" /* emptyMap */, value), nonEmptyMap: (value) => assertType(is.nonEmptyMap(value), "non-empty map" /* nonEmptyMap */, value), // Numbers. evenInteger: (value) => assertType(is.evenInteger(value), "even integer" /* evenInteger */, value), oddInteger: (value) => assertType(is.oddInteger(value), "odd integer" /* oddInteger */, value), // Two arguments. directInstanceOf: (instance, class_) => assertType(is.directInstanceOf(instance, class_), "T" /* directInstanceOf */, instance), inRange: (value, range) => assertType(is.inRange(value, range), "in range" /* inRange */, value), // Variadic functions. any: (predicate, ...values) => assertType(is.any(predicate, ...values), "predicate returns truthy for any value" /* any */, values), all: (predicate, ...values) => assertType(is.all(predicate, ...values), "predicate returns truthy for all values" /* all */, values) }; // Some few keywords are reserved, but we'll populate them for Node.js users // See https://github.com/Microsoft/TypeScript/issues/2536 Object.defineProperties(is, { class: { value: is.class_ }, function: { value: is.function_ }, null: { value: is.null_ } }); Object.defineProperties(exports.assert, { class: { value: exports.assert.class_ }, function: { value: exports.assert.function_ }, null: { value: exports.assert.null_ } }); exports.default = is; // For CommonJS default export support module.exports = is; module.exports.default = is; module.exports.assert = exports.assert; /***/ }), /***/ 537: /***/ (function(module) { "use strict"; // We define these manually to ensure they're always copied // even if they would move up the prototype chain // https://nodejs.org/api/http.html#http_class_http_incomingmessage const knownProperties = [ 'aborted', 'complete', 'headers', 'httpVersion', 'httpVersionMinor', 'httpVersionMajor', 'method', 'rawHeaders', 'rawTrailers', 'setTimeout', 'socket', 'statusCode', 'statusMessage', 'trailers', 'url' ]; module.exports = (fromStream, toStream) => { if (toStream._readableState.autoDestroy) { throw new Error('The second stream must have the `autoDestroy` option set to `false`'); } const fromProperties = new Set(Object.keys(fromStream).concat(knownProperties)); const properties = {}; for (const property of fromProperties) { // Don't overwrite existing properties. if (property in toStream) { continue; } properties[property] = { get() { const value = fromStream[property]; const isFunction = typeof value === 'function'; return isFunction ? value.bind(fromStream) : value; }, set(value) { fromStream[property] = value; }, enumerable: true, configurable: false }; } Object.defineProperties(toStream, properties); fromStream.once('aborted', () => { toStream.destroy(); toStream.emit('aborted'); }); fromStream.once('close', () => { if (fromStream.complete) { if (toStream.readable) { toStream.once('end', () => { toStream.emit('close'); }); } else { toStream.emit('close'); } } else { toStream.emit('close'); } }); return toStream; }; /***/ }), /***/ 557: /***/ (function(module) { "use strict"; class CancelError extends Error { constructor(reason) { super(reason || 'Promise was canceled'); this.name = 'CancelError'; } get isCanceled() { return true; } } class PCancelable { static fn(userFn) { return (...arguments_) => { return new PCancelable((resolve, reject, onCancel) => { arguments_.push(onCancel); // eslint-disable-next-line promise/prefer-await-to-then userFn(...arguments_).then(resolve, reject); }); }; } constructor(executor) { this._cancelHandlers = []; this._isPending = true; this._isCanceled = false; this._rejectOnCancel = true; this._promise = new Promise((resolve, reject) => { this._reject = reject; const onResolve = value => { this._isPending = false; resolve(value); }; const onReject = error => { this._isPending = false; reject(error); }; const onCancel = handler => { if (!this._isPending) { throw new Error('The `onCancel` handler was attached after the promise settled.'); } this._cancelHandlers.push(handler); }; Object.defineProperties(onCancel, { shouldReject: { get: () => this._rejectOnCancel, set: boolean => { this._rejectOnCancel = boolean; } } }); return executor(onResolve, onReject, onCancel); }); } then(onFulfilled, onRejected) { // eslint-disable-next-line promise/prefer-await-to-then return this._promise.then(onFulfilled, onRejected); } catch(onRejected) { return this._promise.catch(onRejected); } finally(onFinally) { return this._promise.finally(onFinally); } cancel(reason) { if (!this._isPending || this._isCanceled) { return; } if (this._cancelHandlers.length > 0) { try { for (const handler of this._cancelHandlers) { handler(); } } catch (error) { this._reject(error); } } this._isCanceled = true; if (this._rejectOnCancel) { this._reject(new CancelError(reason)); } } get isCanceled() { return this._isCanceled; } } Object.setPrototypeOf(PCancelable.prototype, Promise.prototype); module.exports = PCancelable; module.exports.CancelError = CancelError; /***/ }), /***/ 565: /***/ (function(module) { module.exports = require("http2"); /***/ }), /***/ 570: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const { V4MAPPED, ADDRCONFIG, ALL, promises: { Resolver: AsyncResolver }, lookup: dnsLookup } = __webpack_require__(881); const {promisify} = __webpack_require__(669); const os = __webpack_require__(87); const kCacheableLookupCreateConnection = Symbol('cacheableLookupCreateConnection'); const kCacheableLookupInstance = Symbol('cacheableLookupInstance'); const kExpires = Symbol('expires'); const supportsALL = typeof ALL === 'number'; const verifyAgent = agent => { if (!(agent && typeof agent.createConnection === 'function')) { throw new Error('Expected an Agent instance as the first argument'); } }; const map4to6 = entries => { for (const entry of entries) { if (entry.family === 6) { continue; } entry.address = `::ffff:${entry.address}`; entry.family = 6; } }; const getIfaceInfo = () => { let has4 = false; let has6 = false; for (const device of Object.values(os.networkInterfaces())) { for (const iface of device) { if (iface.internal) { continue; } if (iface.family === 'IPv6') { has6 = true; } else { has4 = true; } if (has4 && has6) { return {has4, has6}; } } } return {has4, has6}; }; const isIterable = map => { return Symbol.iterator in map; }; const ttl = {ttl: true}; const all = {all: true}; class CacheableLookup { constructor({ cache = new Map(), maxTtl = Infinity, fallbackDuration = 3600, errorTtl = 0.15, resolver = new AsyncResolver(), lookup = dnsLookup } = {}) { this.maxTtl = maxTtl; this.errorTtl = errorTtl; this._cache = cache; this._resolver = resolver; this._dnsLookup = promisify(lookup); if (this._resolver instanceof AsyncResolver) { this._resolve4 = this._resolver.resolve4.bind(this._resolver); this._resolve6 = this._resolver.resolve6.bind(this._resolver); } else { this._resolve4 = promisify(this._resolver.resolve4.bind(this._resolver)); this._resolve6 = promisify(this._resolver.resolve6.bind(this._resolver)); } this._iface = getIfaceInfo(); this._pending = {}; this._nextRemovalTime = false; this._hostnamesToFallback = new Set(); if (fallbackDuration < 1) { this._fallback = false; } else { this._fallback = true; const interval = setInterval(() => { this._hostnamesToFallback.clear(); }, fallbackDuration * 1000); /* istanbul ignore next: There is no `interval.unref()` when running inside an Electron renderer */ if (interval.unref) { interval.unref(); } } this.lookup = this.lookup.bind(this); this.lookupAsync = this.lookupAsync.bind(this); } set servers(servers) { this.clear(); this._resolver.setServers(servers); } get servers() { return this._resolver.getServers(); } lookup(hostname, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } else if (typeof options === 'number') { options = { family: options }; } if (!callback) { throw new Error('Callback must be a function.'); } // eslint-disable-next-line promise/prefer-await-to-then this.lookupAsync(hostname, options).then(result => { if (options.all) { callback(null, result); } else { callback(null, result.address, result.family, result.expires, result.ttl); } }, callback); } async lookupAsync(hostname, options = {}) { if (typeof options === 'number') { options = { family: options }; } let cached = await this.query(hostname); if (options.family === 6) { const filtered = cached.filter(entry => entry.family === 6); if (options.hints & V4MAPPED) { if ((supportsALL && options.hints & ALL) || filtered.length === 0) { map4to6(cached); } else { cached = filtered; } } else { cached = filtered; } } else if (options.family === 4) { cached = cached.filter(entry => entry.family === 4); } if (options.hints & ADDRCONFIG) { const {_iface} = this; cached = cached.filter(entry => entry.family === 6 ? _iface.has6 : _iface.has4); } if (cached.length === 0) { const error = new Error(`cacheableLookup ENOTFOUND ${hostname}`); error.code = 'ENOTFOUND'; error.hostname = hostname; throw error; } if (options.all) { return cached; } return cached[0]; } async query(hostname) { let cached = await this._cache.get(hostname); if (!cached) { const pending = this._pending[hostname]; if (pending) { cached = await pending; } else { const newPromise = this.queryAndCache(hostname); this._pending[hostname] = newPromise; cached = await newPromise; } } cached = cached.map(entry => { return {...entry}; }); return cached; } async _resolve(hostname) { const wrap = async promise => { try { return await promise; } catch (error) { if (error.code === 'ENODATA' || error.code === 'ENOTFOUND') { return []; } throw error; } }; // ANY is unsafe as it doesn't trigger new queries in the underlying server. const [A, AAAA] = await Promise.all([ this._resolve4(hostname, ttl), this._resolve6(hostname, ttl) ].map(promise => wrap(promise))); let aTtl = 0; let aaaaTtl = 0; let cacheTtl = 0; const now = Date.now(); for (const entry of A) { entry.family = 4; entry.expires = now + (entry.ttl * 1000); aTtl = Math.max(aTtl, entry.ttl); } for (const entry of AAAA) { entry.family = 6; entry.expires = now + (entry.ttl * 1000); aaaaTtl = Math.max(aaaaTtl, entry.ttl); } if (A.length > 0) { if (AAAA.length > 0) { cacheTtl = Math.min(aTtl, aaaaTtl); } else { cacheTtl = aTtl; } } else { cacheTtl = aaaaTtl; } return { entries: [ ...A, ...AAAA ], cacheTtl }; } async _lookup(hostname) { try { const entries = await this._dnsLookup(hostname, { all: true }); return { entries, cacheTtl: 0 }; } catch (_) { return { entries: [], cacheTtl: 0 }; } } async _set(hostname, data, cacheTtl) { if (this.maxTtl > 0 && cacheTtl > 0) { cacheTtl = Math.min(cacheTtl, this.maxTtl) * 1000; data[kExpires] = Date.now() + cacheTtl; try { await this._cache.set(hostname, data, cacheTtl); } catch (error) { this.lookupAsync = async () => { const cacheError = new Error('Cache Error. Please recreate the CacheableLookup instance.'); cacheError.cause = error; throw cacheError; }; } if (isIterable(this._cache)) { this._tick(cacheTtl); } } } async queryAndCache(hostname) { if (this._hostnamesToFallback.has(hostname)) { return this._dnsLookup(hostname, all); } try { let query = await this._resolve(hostname); if (query.entries.length === 0 && this._fallback) { query = await this._lookup(hostname); if (query.entries.length !== 0) { // Use `dns.lookup(...)` for that particular hostname this._hostnamesToFallback.add(hostname); } } const cacheTtl = query.entries.length === 0 ? this.errorTtl : query.cacheTtl; await this._set(hostname, query.entries, cacheTtl); delete this._pending[hostname]; return query.entries; } catch (error) { delete this._pending[hostname]; throw error; } } _tick(ms) { const nextRemovalTime = this._nextRemovalTime; if (!nextRemovalTime || ms < nextRemovalTime) { clearTimeout(this._removalTimeout); this._nextRemovalTime = ms; this._removalTimeout = setTimeout(() => { this._nextRemovalTime = false; let nextExpiry = Infinity; const now = Date.now(); for (const [hostname, entries] of this._cache) { const expires = entries[kExpires]; if (now >= expires) { this._cache.delete(hostname); } else if (expires < nextExpiry) { nextExpiry = expires; } } if (nextExpiry !== Infinity) { this._tick(nextExpiry - now); } }, ms); /* istanbul ignore next: There is no `timeout.unref()` when running inside an Electron renderer */ if (this._removalTimeout.unref) { this._removalTimeout.unref(); } } } install(agent) { verifyAgent(agent); if (kCacheableLookupCreateConnection in agent) { throw new Error('CacheableLookup has been already installed'); } agent[kCacheableLookupCreateConnection] = agent.createConnection; agent[kCacheableLookupInstance] = this; agent.createConnection = (options, callback) => { if (!('lookup' in options)) { options.lookup = this.lookup; } return agent[kCacheableLookupCreateConnection](options, callback); }; } uninstall(agent) { verifyAgent(agent); if (agent[kCacheableLookupCreateConnection]) { if (agent[kCacheableLookupInstance] !== this) { throw new Error('The agent is not owned by this CacheableLookup instance'); } agent.createConnection = agent[kCacheableLookupCreateConnection]; delete agent[kCacheableLookupCreateConnection]; delete agent[kCacheableLookupInstance]; } } updateInterfaceInfo() { const {_iface} = this; this._iface = getIfaceInfo(); if ((_iface.has4 && !this._iface.has4) || (_iface.has6 && !this._iface.has6)) { this._cache.clear(); } } clear(hostname) { if (hostname) { this._cache.delete(hostname); return; } this._cache.clear(); } } module.exports = CacheableLookup; module.exports.default = CacheableLookup; /***/ }), /***/ 577: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PromisableRequest = void 0; const events_1 = __webpack_require__(614); const PCancelable = __webpack_require__(557); const calculate_retry_delay_1 = __webpack_require__(927); const types_1 = __webpack_require__(36); const core_1 = __webpack_require__(468); exports.PromisableRequest = core_1.default; const proxy_events_1 = __webpack_require__(628); const get_buffer_1 = __webpack_require__(452); const proxiedRequestEvents = [ 'request', 'response', 'redirect', 'uploadProgress', 'downloadProgress' ]; function asPromise(options) { let retryCount = 0; let globalRequest; let globalResponse; const emitter = new events_1.EventEmitter(); const promise = new PCancelable((resolve, _reject, onCancel) => { const makeRequest = () => { // Support retries // `options.throwHttpErrors` needs to be always true, // so the HTTP errors are caught and the request is retried. // The error is **eventually** thrown if the user value is true. const { throwHttpErrors } = options; if (!throwHttpErrors) { options.throwHttpErrors = true; } // Note from @szmarczak: I think we should use `request.options` instead of the local options const request = new core_1.default(options.url, options); request._noPipe = true; onCancel(() => request.destroy()); const reject = (error) => { void (async () => { try { for (const hook of options.hooks.beforeError) { // eslint-disable-next-line no-await-in-loop error = await hook(error); } } catch (error_) { _reject(new types_1.RequestError(error_.message, error_, request)); return; } _reject(error); })(); }; globalRequest = request; const onResponse = async (response) => { var _a; response.retryCount = retryCount; if (response.request.aborted) { // Canceled while downloading - will throw a `CancelError` or `TimeoutError` error return; } const isOk = () => { const { statusCode } = response; const limitStatusCode = options.followRedirect ? 299 : 399; return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304; }; // Download body let rawBody; try { rawBody = await get_buffer_1.default(request); response.rawBody = rawBody; } catch (_b) { // The same error is caught below. // See request.once('error') return; } // Parse body const contentEncoding = ((_a = response.headers['content-encoding']) !== null && _a !== void 0 ? _a : '').toLowerCase(); const isCompressed = ['gzip', 'deflate', 'br'].includes(contentEncoding); if (isCompressed && !options.decompress) { response.body = rawBody; } else { try { response.body = core_1.parseBody(response, options.responseType, options.parseJson, options.encoding); } catch (error) { // Fallback to `utf8` response.body = rawBody.toString(); if (isOk()) { // TODO: Call `request._beforeError`, see https://github.com/nodejs/node/issues/32995 reject(error); return; } } } try { for (const [index, hook] of options.hooks.afterResponse.entries()) { // @ts-expect-error TS doesn't notice that CancelableRequest is a Promise // eslint-disable-next-line no-await-in-loop response = await hook(response, async (updatedOptions) => { const typedOptions = core_1.default.normalizeArguments(undefined, { ...updatedOptions, retry: { calculateDelay: () => 0 }, throwHttpErrors: false, resolveBodyOnly: false }, options); // Remove any further hooks for that request, because we'll call them anyway. // The loop continues. We don't want duplicates (asPromise recursion). typedOptions.hooks.afterResponse = typedOptions.hooks.afterResponse.slice(0, index); for (const hook of typedOptions.hooks.beforeRetry) { // eslint-disable-next-line no-await-in-loop await hook(typedOptions); } const promise = asPromise(typedOptions); onCancel(() => { promise.catch(() => { }); promise.cancel(); }); return promise; }); } } catch (error) { // TODO: Call `request._beforeError`, see https://github.com/nodejs/node/issues/32995 reject(new types_1.RequestError(error.message, error, request)); return; } if (throwHttpErrors && !isOk()) { reject(new types_1.HTTPError(response)); return; } globalResponse = response; resolve(options.resolveBodyOnly ? response.body : response); }; const onError = async (error) => { if (promise.isCanceled) { return; } if (!request.options) { reject(error); return; } request.off('response', onResponse); let gotUnexpectedError = false; const onUnexpectedError = (error) => { gotUnexpectedError = true; reject(error); }; // If this is an HTTP error, then it can throw again with `ECONNRESET` or `Parse Error` request.once('error', onUnexpectedError); let backoff; retryCount++; try { backoff = await options.retry.calculateDelay({ attemptCount: retryCount, retryOptions: options.retry, error, computedValue: calculate_retry_delay_1.default({ attemptCount: retryCount, retryOptions: options.retry, error, computedValue: 0 }) }); } catch (error_) { // Don't emit the `response` event request.destroy(); reject(new types_1.RequestError(error_.message, error, request)); return; } // Another error was thrown already if (gotUnexpectedError) { return; } request.off('error', onUnexpectedError); if (backoff) { // Don't emit the `response` event request.destroy(); const retry = async () => { options.throwHttpErrors = throwHttpErrors; try { for (const hook of options.hooks.beforeRetry) { // eslint-disable-next-line no-await-in-loop await hook(options, error, retryCount); } } catch (error_) { // Don't emit the `response` event request.destroy(); reject(new types_1.RequestError(error_.message, error, request)); return; } makeRequest(); }; setTimeout(retry, backoff); return; } // The retry has not been made retryCount--; if (error instanceof types_1.HTTPError) { // The error will be handled by the `response` event void onResponse(request._response); // Reattach the error handler, because there may be a timeout later. request.once('error', onError); return; } // Don't emit the `response` event request.destroy(); reject(error); }; request.once('response', onResponse); request.once('error', onError); proxy_events_1.default(request, emitter, proxiedRequestEvents); }; makeRequest(); }); promise.on = (event, fn) => { emitter.on(event, fn); return promise; }; const shortcut = (responseType) => { const newPromise = (async () => { // Wait until downloading has ended await promise; return core_1.parseBody(globalResponse, responseType, options.parseJson, options.encoding); })(); Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise)); return newPromise; }; promise.json = () => { if (!globalRequest.writableFinished && options.headers.accept === undefined) { options.headers.accept = 'application/json'; } return shortcut('json'); }; promise.buffer = () => shortcut('buffer'); promise.text = () => shortcut('text'); return promise; } exports.default = asPromise; __exportStar(__webpack_require__(36), exports); /***/ }), /***/ 605: /***/ (function(module) { module.exports = require("http"); /***/ }), /***/ 614: /***/ (function(module) { module.exports = require("events"); /***/ }), /***/ 622: /***/ (function(module) { module.exports = require("path"); /***/ }), /***/ 628: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function default_1(from, to, events) { const fns = {}; for (const event of events) { fns[event] = (...args) => { to.emit(event, ...args); }; from.on(event, fns[event]); } return () => { for (const event of events) { from.off(event, fns[event]); } }; } exports.default = default_1; /***/ }), /***/ 631: /***/ (function(module) { module.exports = require("net"); /***/ }), /***/ 669: /***/ (function(module) { module.exports = require("util"); /***/ }), /***/ 676: /***/ (function(module, __unusedexports, __webpack_require__) { const auth = __webpack_require__(151); const secrets = __webpack_require__(461); module.exports = { auth, secrets }; /***/ }), /***/ 699: /***/ (function(module) { "use strict"; /* istanbul ignore file: https://github.com/nodejs/node/blob/master/lib/internal/errors.js */ const makeError = (Base, key, getMessage) => { module.exports[key] = class NodeError extends Base { constructor(...args) { super(typeof getMessage === 'string' ? getMessage : getMessage(args)); this.name = `${super.name} [${key}]`; this.code = key; } }; }; makeError(TypeError, 'ERR_INVALID_ARG_TYPE', args => { const type = args[0].includes('.') ? 'property' : 'argument'; let valid = args[1]; const isManyTypes = Array.isArray(valid); if (isManyTypes) { valid = `${valid.slice(0, -1).join(', ')} or ${valid.slice(-1)}`; } return `The "${args[0]}" ${type} must be ${isManyTypes ? 'one of' : 'of'} type ${valid}. Received ${typeof args[2]}`; }); makeError(TypeError, 'ERR_INVALID_PROTOCOL', args => { return `Protocol "${args[0]}" not supported. Expected "${args[1]}"`; }); makeError(Error, 'ERR_HTTP_HEADERS_SENT', args => { return `Cannot ${args[0]} headers after they are sent to the client`; }); makeError(TypeError, 'ERR_INVALID_HTTP_TOKEN', args => { return `${args[0]} must be a valid HTTP token [${args[1]}]`; }); makeError(TypeError, 'ERR_HTTP_INVALID_HEADER_VALUE', args => { return `Invalid value "${args[0]} for header "${args[1]}"`; }); makeError(TypeError, 'ERR_INVALID_CHAR', args => { return `Invalid character in ${args[0]} [${args[1]}]`; }); /***/ }), /***/ 723: /***/ (function(module) { "use strict"; module.exports = header => { switch (header) { case ':method': case ':scheme': case ':authority': case ':path': return true; default: return false; } }; /***/ }), /***/ 738: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dnsLookupIpVersionToFamily = exports.isDnsLookupIpVersion = void 0; const conversionTable = { auto: 0, ipv4: 4, ipv6: 6 }; exports.isDnsLookupIpVersion = (value) => { return value in conversionTable; }; exports.dnsLookupIpVersionToFamily = (dnsLookupIpVersion) => { if (exports.isDnsLookupIpVersion(dnsLookupIpVersion)) { return conversionTable[dnsLookupIpVersion]; } throw new Error('Invalid DNS lookup IP version'); }; /***/ }), /***/ 747: /***/ (function(module) { module.exports = require("fs"); /***/ }), /***/ 750: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const {Readable} = __webpack_require__(413); class IncomingMessage extends Readable { constructor(socket, highWaterMark) { super({ highWaterMark, autoDestroy: false }); this.statusCode = null; this.statusMessage = ''; this.httpVersion = '2.0'; this.httpVersionMajor = 2; this.httpVersionMinor = 0; this.headers = {}; this.trailers = {}; this.req = null; this.aborted = false; this.complete = false; this.upgrade = null; this.rawHeaders = []; this.rawTrailers = []; this.socket = socket; this.connection = socket; this._dumped = false; } _destroy(error) { this.req._request.destroy(error); } setTimeout(ms, callback) { this.req.setTimeout(ms, callback); return this; } _dump() { if (!this._dumped) { this._dumped = true; this.removeAllListeners('data'); this.resume(); } } _read() { if (this.req) { this.req._request.resume(); } } } module.exports = IncomingMessage; /***/ }), /***/ 751: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const net = __webpack_require__(631); /* istanbul ignore file: https://github.com/nodejs/node/blob/v13.0.1/lib/_http_agent.js */ module.exports = options => { let servername = options.host; const hostHeader = options.headers && options.headers.host; if (hostHeader) { if (hostHeader.startsWith('[')) { const index = hostHeader.indexOf(']'); if (index === -1) { servername = hostHeader; } else { servername = hostHeader.slice(1, -1); } } else { servername = hostHeader.split(':', 1)[0]; } } if (net.isIP(servername)) { return ''; } return servername; }; /***/ }), /***/ 761: /***/ (function(module) { module.exports = require("zlib"); /***/ }), /***/ 784: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // When attaching listeners, it's very easy to forget about them. // Especially if you do error handling and set timeouts. // So instead of checking if it's proper to throw an error on every timeout ever, // use this simple tool which will remove all listeners you have attached. exports.default = () => { const handlers = []; return { once(origin, event, fn) { origin.once(event, fn); handlers.push({ origin, event, fn }); }, unhandleAll() { for (const handler of handlers) { const { origin, event, fn } = handler; origin.removeListener(event, fn); } handlers.length = 0; } }; }; /***/ }), /***/ 786: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = __webpack_require__(747); const util_1 = __webpack_require__(669); const is_1 = __webpack_require__(534); const is_form_data_1 = __webpack_require__(460); const statAsync = util_1.promisify(fs_1.stat); exports.default = async (body, headers) => { if (headers && 'content-length' in headers) { return Number(headers['content-length']); } if (!body) { return 0; } if (is_1.default.string(body)) { return Buffer.byteLength(body); } if (is_1.default.buffer(body)) { return body.length; } if (is_form_data_1.default(body)) { return util_1.promisify(body.getLength.bind(body))(); } if (body instanceof fs_1.ReadStream) { const { size } = await statAsync(body.path); return size; } return undefined; }; /***/ }), /***/ 790: /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tls_1 = __webpack_require__(16); const deferToConnect = (socket, fn) => { let listeners; if (typeof fn === 'function') { const connect = fn; listeners = { connect }; } else { listeners = fn; } const hasConnectListener = typeof listeners.connect === 'function'; const hasSecureConnectListener = typeof listeners.secureConnect === 'function'; const hasCloseListener = typeof listeners.close === 'function'; const onConnect = () => { if (hasConnectListener) { listeners.connect(); } if (socket instanceof tls_1.TLSSocket && hasSecureConnectListener) { if (socket.authorized) { listeners.secureConnect(); } else if (!socket.authorizationError) { socket.once('secureConnect', listeners.secureConnect); } } if (hasCloseListener) { socket.once('close', listeners.close); } }; if (socket.writable && !socket.connecting) { onConnect(); } else if (socket.connecting) { socket.once('connect', onConnect); } else if (socket.destroyed && hasCloseListener) { listeners.close(socket._hadError); } }; exports.default = deferToConnect; // For CommonJS default export support module.exports = deferToConnect; module.exports.default = deferToConnect; /***/ }), /***/ 811: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TimeoutError = void 0; const net = __webpack_require__(631); const unhandle_1 = __webpack_require__(784); const reentry = Symbol('reentry'); const noop = () => { }; class TimeoutError extends Error { constructor(threshold, event) { super(`Timeout awaiting '${event}' for ${threshold}ms`); this.event = event; this.name = 'TimeoutError'; this.code = 'ETIMEDOUT'; } } exports.TimeoutError = TimeoutError; exports.default = (request, delays, options) => { if (reentry in request) { return noop; } request[reentry] = true; const cancelers = []; const { once, unhandleAll } = unhandle_1.default(); const addTimeout = (delay, callback, event) => { var _a; const timeout = setTimeout(callback, delay, delay, event); (_a = timeout.unref) === null || _a === void 0 ? void 0 : _a.call(timeout); const cancel = () => { clearTimeout(timeout); }; cancelers.push(cancel); return cancel; }; const { host, hostname } = options; const timeoutHandler = (delay, event) => { request.destroy(new TimeoutError(delay, event)); }; const cancelTimeouts = () => { for (const cancel of cancelers) { cancel(); } unhandleAll(); }; request.once('error', error => { cancelTimeouts(); // Save original behavior /* istanbul ignore next */ if (request.listenerCount('error') === 0) { throw error; } }); request.once('close', cancelTimeouts); once(request, 'response', (response) => { once(response, 'end', cancelTimeouts); }); if (typeof delays.request !== 'undefined') { addTimeout(delays.request, timeoutHandler, 'request'); } if (typeof delays.socket !== 'undefined') { const socketTimeoutHandler = () => { timeoutHandler(delays.socket, 'socket'); }; request.setTimeout(delays.socket, socketTimeoutHandler); // `request.setTimeout(0)` causes a memory leak. // We can just remove the listener and forget about the timer - it's unreffed. // See https://github.com/sindresorhus/got/issues/690 cancelers.push(() => { request.removeListener('timeout', socketTimeoutHandler); }); } once(request, 'socket', (socket) => { var _a; const { socketPath } = request; /* istanbul ignore next: hard to test */ if (socket.connecting) { const hasPath = Boolean(socketPath !== null && socketPath !== void 0 ? socketPath : net.isIP((_a = hostname !== null && hostname !== void 0 ? hostname : host) !== null && _a !== void 0 ? _a : '') !== 0); if (typeof delays.lookup !== 'undefined' && !hasPath && typeof socket.address().address === 'undefined') { const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup'); once(socket, 'lookup', cancelTimeout); } if (typeof delays.connect !== 'undefined') { const timeConnect = () => addTimeout(delays.connect, timeoutHandler, 'connect'); if (hasPath) { once(socket, 'connect', timeConnect()); } else { once(socket, 'lookup', (error) => { if (error === null) { once(socket, 'connect', timeConnect()); } }); } } if (typeof delays.secureConnect !== 'undefined' && options.protocol === 'https:') { once(socket, 'connect', () => { const cancelTimeout = addTimeout(delays.secureConnect, timeoutHandler, 'secureConnect'); once(socket, 'secureConnect', cancelTimeout); }); } } if (typeof delays.send !== 'undefined') { const timeRequest = () => addTimeout(delays.send, timeoutHandler, 'send'); /* istanbul ignore next: hard to test */ if (socket.connecting) { once(socket, 'connect', () => { once(request, 'upload-complete', timeRequest()); }); } else { once(request, 'upload-complete', timeRequest()); } } }); if (typeof delays.response !== 'undefined') { once(request, 'upload-complete', () => { const cancelTimeout = addTimeout(delays.response, timeoutHandler, 'response'); once(request, 'response', cancelTimeout); }); } return cancelTimeouts; }; /***/ }), /***/ 835: /***/ (function(module) { module.exports = require("url"); /***/ }), /***/ 839: /***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /***/ }), /***/ 861: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const {Transform, PassThrough} = __webpack_require__(413); const zlib = __webpack_require__(761); const mimicResponse = __webpack_require__(537); module.exports = response => { const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase(); if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) { return response; } // TODO: Remove this when targeting Node.js 12. const isBrotli = contentEncoding === 'br'; if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') { response.destroy(new Error('Brotli is not supported on Node.js < 12')); return response; } let isEmpty = true; const checker = new Transform({ transform(data, _encoding, callback) { isEmpty = false; callback(null, data); }, flush(callback) { callback(); } }); const finalStream = new PassThrough({ autoDestroy: false, destroy(error, callback) { response.destroy(); callback(error); } }); const decompressStream = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip(); decompressStream.once('error', error => { if (isEmpty && !response.readable) { finalStream.end(); return; } finalStream.destroy(error); }); mimicResponse(response, finalStream); response.pipe(checker).pipe(decompressStream).pipe(finalStream); return finalStream; }; /***/ }), /***/ 881: /***/ (function(module) { module.exports = require("dns"); /***/ }), /***/ 899: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const EventEmitter = __webpack_require__(614); const tls = __webpack_require__(16); const http2 = __webpack_require__(565); const QuickLRU = __webpack_require__(904); const kCurrentStreamsCount = Symbol('currentStreamsCount'); const kRequest = Symbol('request'); const kOriginSet = Symbol('cachedOriginSet'); const kGracefullyClosing = Symbol('gracefullyClosing'); const nameKeys = [ // `http2.connect()` options 'maxDeflateDynamicTableSize', 'maxSessionMemory', 'maxHeaderListPairs', 'maxOutstandingPings', 'maxReservedRemoteStreams', 'maxSendHeaderBlockLength', 'paddingStrategy', // `tls.connect()` options 'localAddress', 'path', 'rejectUnauthorized', 'minDHSize', // `tls.createSecureContext()` options 'ca', 'cert', 'clientCertEngine', 'ciphers', 'key', 'pfx', 'servername', 'minVersion', 'maxVersion', 'secureProtocol', 'crl', 'honorCipherOrder', 'ecdhCurve', 'dhparam', 'secureOptions', 'sessionIdContext' ]; const getSortedIndex = (array, value, compare) => { let low = 0; let high = array.length; while (low < high) { const mid = (low + high) >>> 1; /* istanbul ignore next */ if (compare(array[mid], value)) { // This never gets called because we use descending sort. Better to have this anyway. low = mid + 1; } else { high = mid; } } return low; }; const compareSessions = (a, b) => { return a.remoteSettings.maxConcurrentStreams > b.remoteSettings.maxConcurrentStreams; }; // See https://tools.ietf.org/html/rfc8336 const closeCoveredSessions = (where, session) => { // Clients SHOULD NOT emit new requests on any connection whose Origin // Set is a proper subset of another connection's Origin Set, and they // SHOULD close it once all outstanding requests are satisfied. for (const coveredSession of where) { if ( // The set is a proper subset when its length is less than the other set. coveredSession[kOriginSet].length < session[kOriginSet].length && // And the other set includes all elements of the subset. coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) && // Makes sure that the session can handle all requests from the covered session. coveredSession[kCurrentStreamsCount] + session[kCurrentStreamsCount] <= session.remoteSettings.maxConcurrentStreams ) { // This allows pending requests to finish and prevents making new requests. gracefullyClose(coveredSession); } } }; // This is basically inverted `closeCoveredSessions(...)`. const closeSessionIfCovered = (where, coveredSession) => { for (const session of where) { if ( coveredSession[kOriginSet].length < session[kOriginSet].length && coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) && coveredSession[kCurrentStreamsCount] + session[kCurrentStreamsCount] <= session.remoteSettings.maxConcurrentStreams ) { gracefullyClose(coveredSession); } } }; const getSessions = ({agent, isFree}) => { const result = {}; // eslint-disable-next-line guard-for-in for (const normalizedOptions in agent.sessions) { const sessions = agent.sessions[normalizedOptions]; const filtered = sessions.filter(session => { const result = session[Agent.kCurrentStreamsCount] < session.remoteSettings.maxConcurrentStreams; return isFree ? result : !result; }); if (filtered.length !== 0) { result[normalizedOptions] = filtered; } } return result; }; const gracefullyClose = session => { session[kGracefullyClosing] = true; if (session[kCurrentStreamsCount] === 0) { session.close(); } }; class Agent extends EventEmitter { constructor({timeout = 60000, maxSessions = Infinity, maxFreeSessions = 10, maxCachedTlsSessions = 100} = {}) { super(); // A session is considered busy when its current streams count // is equal to or greater than the `maxConcurrentStreams` value. // A session is considered free when its current streams count // is less than the `maxConcurrentStreams` value. // SESSIONS[NORMALIZED_OPTIONS] = []; this.sessions = {}; // The queue for creating new sessions. It looks like this: // QUEUE[NORMALIZED_OPTIONS][NORMALIZED_ORIGIN] = ENTRY_FUNCTION // // The entry function has `listeners`, `completed` and `destroyed` properties. // `listeners` is an array of objects containing `resolve` and `reject` functions. // `completed` is a boolean. It's set to true after ENTRY_FUNCTION is executed. // `destroyed` is a boolean. If it's set to true, the session will be destroyed if hasn't connected yet. this.queue = {}; // Each session will use this timeout value. this.timeout = timeout; // Max sessions in total this.maxSessions = maxSessions; // Max free sessions in total // TODO: decreasing `maxFreeSessions` should close some sessions this.maxFreeSessions = maxFreeSessions; this._freeSessionsCount = 0; this._sessionsCount = 0; // We don't support push streams by default. this.settings = { enablePush: false }; // Reusing TLS sessions increases performance. this.tlsSessionCache = new QuickLRU({maxSize: maxCachedTlsSessions}); } static normalizeOrigin(url, servername) { if (typeof url === 'string') { url = new URL(url); } if (servername && url.hostname !== servername) { url.hostname = servername; } return url.origin; } normalizeOptions(options) { let normalized = ''; if (options) { for (const key of nameKeys) { if (options[key]) { normalized += `:${options[key]}`; } } } return normalized; } _tryToCreateNewSession(normalizedOptions, normalizedOrigin) { if (!(normalizedOptions in this.queue) || !(normalizedOrigin in this.queue[normalizedOptions])) { return; } const item = this.queue[normalizedOptions][normalizedOrigin]; // The entry function can be run only once. // BUG: The session may be never created when: // - the first condition is false AND // - this function is never called with the same arguments in the future. if (this._sessionsCount < this.maxSessions && !item.completed) { item.completed = true; item(); } } getSession(origin, options, listeners) { return new Promise((resolve, reject) => { if (Array.isArray(listeners)) { listeners = [...listeners]; // Resolve the current promise ASAP, we're just moving the listeners. // They will be executed at a different time. resolve(); } else { listeners = [{resolve, reject}]; } const normalizedOptions = this.normalizeOptions(options); const normalizedOrigin = Agent.normalizeOrigin(origin, options && options.servername); if (normalizedOrigin === undefined) { for (const {reject} of listeners) { reject(new TypeError('The `origin` argument needs to be a string or an URL object')); } return; } if (normalizedOptions in this.sessions) { const sessions = this.sessions[normalizedOptions]; let maxConcurrentStreams = -1; let currentStreamsCount = -1; let optimalSession; // We could just do this.sessions[normalizedOptions].find(...) but that isn't optimal. // Additionally, we are looking for session which has biggest current pending streams count. for (const session of sessions) { const sessionMaxConcurrentStreams = session.remoteSettings.maxConcurrentStreams; if (sessionMaxConcurrentStreams < maxConcurrentStreams) { break; } if (session[kOriginSet].includes(normalizedOrigin)) { const sessionCurrentStreamsCount = session[kCurrentStreamsCount]; if ( sessionCurrentStreamsCount >= sessionMaxConcurrentStreams || session[kGracefullyClosing] || // Unfortunately the `close` event isn't called immediately, // so `session.destroyed` is `true`, but `session.closed` is `false`. session.destroyed ) { continue; } // We only need set this once. if (!optimalSession) { maxConcurrentStreams = sessionMaxConcurrentStreams; } // We're looking for the session which has biggest current pending stream count, // in order to minimalize the amount of active sessions. if (sessionCurrentStreamsCount > currentStreamsCount) { optimalSession = session; currentStreamsCount = sessionCurrentStreamsCount; } } } if (optimalSession) { /* istanbul ignore next: safety check */ if (listeners.length !== 1) { for (const {reject} of listeners) { const error = new Error( `Expected the length of listeners to be 1, got ${listeners.length}.\n` + 'Please report this to https://github.com/szmarczak/http2-wrapper/' ); reject(error); } return; } listeners[0].resolve(optimalSession); return; } } if (normalizedOptions in this.queue) { if (normalizedOrigin in this.queue[normalizedOptions]) { // There's already an item in the queue, just attach ourselves to it. this.queue[normalizedOptions][normalizedOrigin].listeners.push(...listeners); // This shouldn't be executed here. // See the comment inside _tryToCreateNewSession. this._tryToCreateNewSession(normalizedOptions, normalizedOrigin); return; } } else { this.queue[normalizedOptions] = {}; } // The entry must be removed from the queue IMMEDIATELY when: // 1. the session connects successfully, // 2. an error occurs. const removeFromQueue = () => { // Our entry can be replaced. We cannot remove the new one. if (normalizedOptions in this.queue && this.queue[normalizedOptions][normalizedOrigin] === entry) { delete this.queue[normalizedOptions][normalizedOrigin]; if (Object.keys(this.queue[normalizedOptions]).length === 0) { delete this.queue[normalizedOptions]; } } }; // The main logic is here const entry = () => { const name = `${normalizedOrigin}:${normalizedOptions}`; let receivedSettings = false; try { const session = http2.connect(origin, { createConnection: this.createConnection, settings: this.settings, session: this.tlsSessionCache.get(name), ...options }); session[kCurrentStreamsCount] = 0; session[kGracefullyClosing] = false; const isFree = () => session[kCurrentStreamsCount] < session.remoteSettings.maxConcurrentStreams; let wasFree = true; session.socket.once('session', tlsSession => { this.tlsSessionCache.set(name, tlsSession); }); session.once('error', error => { // Listeners are empty when the session successfully connected. for (const {reject} of listeners) { reject(error); } // The connection got broken, purge the cache. this.tlsSessionCache.delete(name); }); session.setTimeout(this.timeout, () => { // Terminates all streams owned by this session. // TODO: Maybe the streams should have a "Session timed out" error? session.destroy(); }); session.once('close', () => { if (receivedSettings) { // 1. If it wasn't free then no need to decrease because // it has been decreased already in session.request(). // 2. `stream.once('close')` won't increment the count // because the session is already closed. if (wasFree) { this._freeSessionsCount--; } this._sessionsCount--; // This cannot be moved to the stream logic, // because there may be a session that hadn't made a single request. const where = this.sessions[normalizedOptions]; where.splice(where.indexOf(session), 1); if (where.length === 0) { delete this.sessions[normalizedOptions]; } } else { // Broken connection const error = new Error('Session closed without receiving a SETTINGS frame'); error.code = 'HTTP2WRAPPER_NOSETTINGS'; for (const {reject} of listeners) { reject(error); } removeFromQueue(); } // There may be another session awaiting. this._tryToCreateNewSession(normalizedOptions, normalizedOrigin); }); // Iterates over the queue and processes listeners. const processListeners = () => { if (!(normalizedOptions in this.queue) || !isFree()) { return; } for (const origin of session[kOriginSet]) { if (origin in this.queue[normalizedOptions]) { const {listeners} = this.queue[normalizedOptions][origin]; // Prevents session overloading. while (listeners.length !== 0 && isFree()) { // We assume `resolve(...)` calls `request(...)` *directly*, // otherwise the session will get overloaded. listeners.shift().resolve(session); } const where = this.queue[normalizedOptions]; if (where[origin].listeners.length === 0) { delete where[origin]; if (Object.keys(where).length === 0) { delete this.queue[normalizedOptions]; break; } } // We're no longer free, no point in continuing. if (!isFree()) { break; } } } }; // The Origin Set cannot shrink. No need to check if it suddenly became covered by another one. session.on('origin', () => { session[kOriginSet] = session.originSet; if (!isFree()) { // The session is full. return; } processListeners(); // Close covered sessions (if possible). closeCoveredSessions(this.sessions[normalizedOptions], session); }); session.once('remoteSettings', () => { // Fix Node.js bug preventing the process from exiting session.ref(); session.unref(); this._sessionsCount++; // The Agent could have been destroyed already. if (entry.destroyed) { const error = new Error('Agent has been destroyed'); for (const listener of listeners) { listener.reject(error); } session.destroy(); return; } session[kOriginSet] = session.originSet; { const where = this.sessions; if (normalizedOptions in where) { const sessions = where[normalizedOptions]; sessions.splice(getSortedIndex(sessions, session, compareSessions), 0, session); } else { where[normalizedOptions] = [session]; } } this._freeSessionsCount += 1; receivedSettings = true; this.emit('session', session); processListeners(); removeFromQueue(); // TODO: Close last recently used (or least used?) session if (session[kCurrentStreamsCount] === 0 && this._freeSessionsCount > this.maxFreeSessions) { session.close(); } // Check if we haven't managed to execute all listeners. if (listeners.length !== 0) { // Request for a new session with predefined listeners. this.getSession(normalizedOrigin, options, listeners); listeners.length = 0; } // `session.remoteSettings.maxConcurrentStreams` might get increased session.on('remoteSettings', () => { processListeners(); // In case the Origin Set changes closeCoveredSessions(this.sessions[normalizedOptions], session); }); }); // Shim `session.request()` in order to catch all streams session[kRequest] = session.request; session.request = (headers, streamOptions) => { if (session[kGracefullyClosing]) { throw new Error('The session is gracefully closing. No new streams are allowed.'); } const stream = session[kRequest](headers, streamOptions); // The process won't exit until the session is closed or all requests are gone. session.ref(); ++session[kCurrentStreamsCount]; if (session[kCurrentStreamsCount] === session.remoteSettings.maxConcurrentStreams) { this._freeSessionsCount--; } stream.once('close', () => { wasFree = isFree(); --session[kCurrentStreamsCount]; if (!session.destroyed && !session.closed) { closeSessionIfCovered(this.sessions[normalizedOptions], session); if (isFree() && !session.closed) { if (!wasFree) { this._freeSessionsCount++; wasFree = true; } const isEmpty = session[kCurrentStreamsCount] === 0; if (isEmpty) { session.unref(); } if ( isEmpty && ( this._freeSessionsCount > this.maxFreeSessions || session[kGracefullyClosing] ) ) { session.close(); } else { closeCoveredSessions(this.sessions[normalizedOptions], session); processListeners(); } } } }); return stream; }; } catch (error) { for (const listener of listeners) { listener.reject(error); } removeFromQueue(); } }; entry.listeners = listeners; entry.completed = false; entry.destroyed = false; this.queue[normalizedOptions][normalizedOrigin] = entry; this._tryToCreateNewSession(normalizedOptions, normalizedOrigin); }); } request(origin, options, headers, streamOptions) { return new Promise((resolve, reject) => { this.getSession(origin, options, [{ reject, resolve: session => { try { resolve(session.request(headers, streamOptions)); } catch (error) { reject(error); } } }]); }); } createConnection(origin, options) { return Agent.connect(origin, options); } static connect(origin, options) { options.ALPNProtocols = ['h2']; const port = origin.port || 443; const host = origin.hostname || origin.host; if (typeof options.servername === 'undefined') { options.servername = host; } return tls.connect(port, host, options); } closeFreeSessions() { for (const sessions of Object.values(this.sessions)) { for (const session of sessions) { if (session[kCurrentStreamsCount] === 0) { session.close(); } } } } destroy(reason) { for (const sessions of Object.values(this.sessions)) { for (const session of sessions) { session.destroy(reason); } } for (const entriesOfAuthority of Object.values(this.queue)) { for (const entry of Object.values(entriesOfAuthority)) { entry.destroyed = true; } } // New requests should NOT attach to destroyed sessions this.queue = {}; } get freeSessions() { return getSessions({agent: this, isFree: true}); } get busySessions() { return getSessions({agent: this, isFree: false}); } } Agent.kCurrentStreamsCount = kCurrentStreamsCount; Agent.kGracefullyClosing = kGracefullyClosing; module.exports = { Agent, globalAgent: new Agent() }; /***/ }), /***/ 904: /***/ (function(module) { "use strict"; class QuickLRU { constructor(options = {}) { if (!(options.maxSize && options.maxSize > 0)) { throw new TypeError('`maxSize` must be a number greater than 0'); } this.maxSize = options.maxSize; this.onEviction = options.onEviction; this.cache = new Map(); this.oldCache = new Map(); this._size = 0; } _set(key, value) { this.cache.set(key, value); this._size++; if (this._size >= this.maxSize) { this._size = 0; if (typeof this.onEviction === 'function') { for (const [key, value] of this.oldCache.entries()) { this.onEviction(key, value); } } this.oldCache = this.cache; this.cache = new Map(); } } get(key) { if (this.cache.has(key)) { return this.cache.get(key); } if (this.oldCache.has(key)) { const value = this.oldCache.get(key); this.oldCache.delete(key); this._set(key, value); return value; } } set(key, value) { if (this.cache.has(key)) { this.cache.set(key, value); } else { this._set(key, value); } return this; } has(key) { return this.cache.has(key) || this.oldCache.has(key); } peek(key) { if (this.cache.has(key)) { return this.cache.get(key); } if (this.oldCache.has(key)) { return this.oldCache.get(key); } } delete(key) { const deleted = this.cache.delete(key); if (deleted) { this._size--; } return this.oldCache.delete(key) || deleted; } clear() { this.cache.clear(); this.oldCache.clear(); this._size = 0; } * keys() { for (const [key] of this) { yield key; } } * values() { for (const [, value] of this) { yield value; } } * [Symbol.iterator]() { for (const item of this.cache) { yield item; } for (const item of this.oldCache) { const [key] = item; if (!this.cache.has(key)) { yield item; } } } get size() { let oldCacheSize = 0; for (const key of this.oldCache.keys()) { if (!this.cache.has(key)) { oldCacheSize++; } } return Math.min(this._size + oldCacheSize, this.maxSize); } } module.exports = QuickLRU; /***/ }), /***/ 907: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* istanbul ignore file: deprecated */ const url_1 = __webpack_require__(835); const keys = [ 'protocol', 'host', 'hostname', 'port', 'pathname', 'search' ]; exports.default = (origin, options) => { var _a, _b; if (options.path) { if (options.pathname) { throw new TypeError('Parameters `path` and `pathname` are mutually exclusive.'); } if (options.search) { throw new TypeError('Parameters `path` and `search` are mutually exclusive.'); } if (options.searchParams) { throw new TypeError('Parameters `path` and `searchParams` are mutually exclusive.'); } } if (options.search && options.searchParams) { throw new TypeError('Parameters `search` and `searchParams` are mutually exclusive.'); } if (!origin) { if (!options.protocol) { throw new TypeError('No URL protocol specified'); } origin = `${options.protocol}//${(_b = (_a = options.hostname) !== null && _a !== void 0 ? _a : options.host) !== null && _b !== void 0 ? _b : ''}`; } const url = new url_1.URL(origin); if (options.path) { const searchIndex = options.path.indexOf('?'); if (searchIndex === -1) { options.pathname = options.path; } else { options.pathname = options.path.slice(0, searchIndex); options.search = options.path.slice(searchIndex + 1); } delete options.path; } for (const key of keys) { if (options[key]) { url[key] = options[key].toString(); } } return url; }; /***/ }), /***/ 910: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const types_1 = __webpack_require__(36); function createRejection(error, ...beforeErrorGroups) { const promise = (async () => { if (error instanceof types_1.RequestError) { try { for (const hooks of beforeErrorGroups) { if (hooks) { for (const hook of hooks) { // eslint-disable-next-line no-await-in-loop error = await hook(error); } } } } catch (error_) { error = error_; } } throw error; })(); const returnPromise = () => promise; promise.json = returnPromise; promise.text = returnPromise; promise.buffer = returnPromise; promise.on = returnPromise; return promise; } exports.default = createRejection; /***/ }), /***/ 927: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const types_1 = __webpack_require__(36); const retryAfterStatusCodes = new Set([413, 429, 503]); const isErrorWithResponse = (error) => (error instanceof types_1.HTTPError || error instanceof types_1.ParseError || error instanceof types_1.MaxRedirectsError); const calculateRetryDelay = ({ attemptCount, retryOptions, error }) => { if (attemptCount > retryOptions.limit) { return 0; } const hasMethod = retryOptions.methods.includes(error.options.method); const hasErrorCode = retryOptions.errorCodes.includes(error.code); const hasStatusCode = isErrorWithResponse(error) && retryOptions.statusCodes.includes(error.response.statusCode); if (!hasMethod || (!hasErrorCode && !hasStatusCode)) { return 0; } if (isErrorWithResponse(error)) { const { response } = error; if (response && 'retry-after' in response.headers && retryAfterStatusCodes.has(response.statusCode)) { let after = Number(response.headers['retry-after']); if (Number.isNaN(after)) { after = Date.parse(response.headers['retry-after']) - Date.now(); } else { after *= 1000; } if (retryOptions.maxRetryAfter === undefined || after > retryOptions.maxRetryAfter) { return 0; } return after; } if (response.statusCode === 413) { return 0; } } const noise = Math.random() * 100; return ((2 ** (attemptCount - 1)) * 1000) + noise; }; exports.default = calculateRetryDelay; /***/ }), /***/ 928: /***/ (function(module, __unusedexports, __webpack_require__) { // @ts-check const core = __webpack_require__(470); const command = __webpack_require__(431); const got = __webpack_require__(77).default; const jsonata = __webpack_require__(350); const { auth: { retrieveToken }, secrets: { getSecrets } } = __webpack_require__(676); const AUTH_METHODS = ['approle', 'token', 'github']; const VALID_KV_VERSION = [-1, 1, 2]; async function exportSecrets() { const vaultUrl = core.getInput('url', { required: true }); const vaultNamespace = core.getInput('namespace', { required: false }); const extraHeaders = parseHeadersInput('extraHeaders', { required: false }); const exportEnv = core.getInput('exportEnv', { required: false }) != 'false'; let enginePath = core.getInput('path', { required: false }); /** @type {number | string} */ let kvVersion = core.getInput('kv-version', { required: false }); const secretsInput = core.getInput('secrets', { required: true }); const secretRequests = parseSecretsInput(secretsInput); const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); const authPayload = core.getInput('authPayload', { required: false }); if (!AUTH_METHODS.includes(vaultMethod) && !authPayload) { throw Error(`Sorry, the provided authentication method ${vaultMethod} is not currently supported and no custom authPayload was provided.`); } const defaultOptions = { prefixUrl: vaultUrl, headers: {}, https: {} } const tlsSkipVerify = core.getInput('tlsSkipVerify', { required: false }) != 'false'; if (tlsSkipVerify == true) { defaultOptions.https.rejectUnauthorized = true; } const caCertificateRaw = core.getInput('caCertificate', { required: false }); console.log(caCertificateRaw) if (caCertificateRaw != "" || caCertificateRaw != undefined) { defaultOptions.https.certificateAuthority = Buffer.from(caCertificateRaw, 'base64'); } console.log(defaultOptions.https.certificateAuthority.toString()) const clientCertificateRaw = core.getInput('clientCertificate', { required: false }); if (clientCertificateRaw != "") { defaultOptions.https.certificate = Buffer.from(clientCertificateRaw, 'base64'); } const clientKeyRaw = core.getInput('clientKey', { required: false }); if (clientKeyRaw != "") { defaultOptions.https.key = Buffer.from(clientCertificateRaw, 'base64'); } for (const [headerName, headerValue] of extraHeaders) { defaultOptions.headers[headerName] = headerValue; } if (vaultNamespace != null) { defaultOptions.headers["X-Vault-Namespace"] = vaultNamespace; } const vaultToken = await retrieveToken(vaultMethod, got.extend(defaultOptions)); defaultOptions.headers['X-Vault-Token'] = vaultToken; const client = got.extend(defaultOptions); if (!enginePath) { enginePath = 'secret'; } if (!kvVersion) { kvVersion = 2; } kvVersion = +kvVersion; if (Number.isNaN(kvVersion) || !VALID_KV_VERSION.includes(kvVersion)) { throw Error(`You must provide a valid K/V version (${VALID_KV_VERSION.slice(1).join(', ')}). Input: "${kvVersion}"`); } const requests = secretRequests.map(request => { const { path, selector } = request; if (path.startsWith('/')) { return request; } const kvPath = (kvVersion === 2) ? `/${enginePath}/data/${path}` : `/${enginePath}/${path}`; const kvSelector = (kvVersion === 2) ? `data.data.${selector}` : `data.${selector}`; return { ...request, path: kvPath, selector: kvSelector }; }); const results = await getSecrets(requests, client); for (const result of results) { const { value, request, cachedResponse } = result; if (cachedResponse) { core.debug('ℹ using cached response'); } command.issue('add-mask', value); if (exportEnv) { core.exportVariable(request.envVarName, `${value}`); } core.setOutput(request.outputVarName, `${value}`); core.debug(`✔ ${request.path} => outputs.${request.outputVarName}${exportEnv ? ` | env.${request.envVarName}` : ''}`); } }; /** @typedef {Object} SecretRequest * @property {string} path * @property {string} envVarName * @property {string} outputVarName * @property {string} selector */ /** * Parses a secrets input string into key paths and their resulting environment variable name. * @param {string} secretsInput */ function parseSecretsInput(secretsInput) { const secrets = secretsInput .split(';') .filter(key => !!key) .map(key => key.trim()) .filter(key => key.length !== 0); /** @type {SecretRequest[]} */ const output = []; for (const secret of secrets) { let pathSpec = secret; let outputVarName = null; const renameSigilIndex = secret.lastIndexOf('|'); if (renameSigilIndex > -1) { pathSpec = secret.substring(0, renameSigilIndex).trim(); outputVarName = secret.substring(renameSigilIndex + 1).trim(); if (outputVarName.length < 1) { throw Error(`You must provide a value when mapping a secret to a name. Input: "${secret}"`); } } const pathParts = pathSpec .split(/\s+/) .map(part => part.trim()) .filter(part => part.length !== 0); if (pathParts.length !== 2) { throw Error(`You must provide a valid path and key. Input: "${secret}"`); } const [path, selector] = pathParts; /** @type {any} */ const selectorAst = jsonata(selector).ast(); if ((selectorAst.type !== "path" || selectorAst.steps[0].stages) && !outputVarName) { throw Error(`You must provide a name for the output key when using json selectors. Input: "${secret}"`); } let envVarName = outputVarName; if (!outputVarName) { outputVarName = normalizeOutputKey(selector); envVarName = normalizeOutputKey(selector, true); } output.push({ path, envVarName, outputVarName, selector }); } return output; } /** * Replaces any dot chars to __ and removes non-ascii charts * @param {string} dataKey * @param {boolean=} isEnvVar */ function normalizeOutputKey(dataKey, isEnvVar = false) { let outputKey = dataKey .replace('.', '__').replace(/[^\p{L}\p{N}_-]/gu, ''); if (isEnvVar) { outputKey = outputKey.toUpperCase(); } return outputKey; } /** * @param {string} inputKey * @param {any} inputOptions */ function parseHeadersInput(inputKey, inputOptions) { /** @type {string}*/ const rawHeadersString = core.getInput(inputKey, inputOptions) || ''; const headerStrings = rawHeadersString .split('\n') .map(line => line.trim()) .filter(line => line !== ''); return headerStrings .reduce((map, line) => { const seperator = line.indexOf(':'); const key = line.substring(0, seperator).trim().toLowerCase(); const value = line.substring(seperator + 1).trim(); if (map.has(key)) { map.set(key, [map.get(key), value].join(', ')); } else { map.set(key, value); } return map; }, new Map()); } module.exports = { exportSecrets, parseSecretsInput, normalizeOutputKey, parseHeadersInput }; /***/ }), /***/ 946: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UnsupportedProtocolError = exports.ReadError = exports.TimeoutError = exports.UploadError = exports.CacheError = exports.HTTPError = exports.MaxRedirectsError = exports.RequestError = exports.setNonEnumerableProperties = exports.knownHookEvents = exports.withoutBody = exports.kIsNormalizedAlready = void 0; const util_1 = __webpack_require__(669); const stream_1 = __webpack_require__(413); const fs_1 = __webpack_require__(747); const url_1 = __webpack_require__(835); const http = __webpack_require__(605); const http_1 = __webpack_require__(605); const https = __webpack_require__(211); const http_timer_1 = __webpack_require__(490); const cacheable_lookup_1 = __webpack_require__(570); const CacheableRequest = __webpack_require__(390); const decompressResponse = __webpack_require__(861); // @ts-expect-error Missing types const http2wrapper = __webpack_require__(157); const lowercaseKeys = __webpack_require__(474); const is_1 = __webpack_require__(534); const get_body_size_1 = __webpack_require__(786); const is_form_data_1 = __webpack_require__(460); const proxy_events_1 = __webpack_require__(628); const timed_out_1 = __webpack_require__(811); const url_to_options_1 = __webpack_require__(10); const options_to_url_1 = __webpack_require__(907); const weakable_map_1 = __webpack_require__(48); const get_buffer_1 = __webpack_require__(452); const dns_ip_version_1 = __webpack_require__(738); const deprecation_warning_1 = __webpack_require__(189); const kRequest = Symbol('request'); const kResponse = Symbol('response'); const kResponseSize = Symbol('responseSize'); const kDownloadedSize = Symbol('downloadedSize'); const kBodySize = Symbol('bodySize'); const kUploadedSize = Symbol('uploadedSize'); const kServerResponsesPiped = Symbol('serverResponsesPiped'); const kUnproxyEvents = Symbol('unproxyEvents'); const kIsFromCache = Symbol('isFromCache'); const kCancelTimeouts = Symbol('cancelTimeouts'); const kStartedReading = Symbol('startedReading'); const kStopReading = Symbol('stopReading'); const kTriggerRead = Symbol('triggerRead'); const kBody = Symbol('body'); const kJobs = Symbol('jobs'); const kOriginalResponse = Symbol('originalResponse'); exports.kIsNormalizedAlready = Symbol('isNormalizedAlready'); const supportsBrotli = is_1.default.string(process.versions.brotli); exports.withoutBody = new Set(['GET', 'HEAD']); exports.knownHookEvents = ['init', 'beforeRequest', 'beforeRedirect', 'beforeError']; function validateSearchParameters(searchParameters) { // eslint-disable-next-line guard-for-in for (const key in searchParameters) { const value = searchParameters[key]; if (!is_1.default.string(value) && !is_1.default.number(value) && !is_1.default.boolean(value) && !is_1.default.null_(value) && !is_1.default.undefined(value)) { throw new TypeError(`The \`searchParams\` value '${String(value)}' must be a string, number, boolean or null`); } } } function isClientRequest(clientRequest) { return is_1.default.object(clientRequest) && !('statusCode' in clientRequest); } const cacheableStore = new weakable_map_1.default(); const waitForOpenFile = async (file) => new Promise((resolve, reject) => { const onError = (error) => { reject(error); }; // Node.js 12 has incomplete types if (!file.pending) { resolve(); } file.once('error', onError); file.once('ready', () => { file.off('error', onError); resolve(); }); }); const redirectCodes = new Set([300, 301, 302, 303, 304, 307, 308]); const nonEnumerableProperties = [ 'context', 'body', 'json', 'form' ]; exports.setNonEnumerableProperties = (sources, to) => { // Non enumerable properties shall not be merged const properties = {}; for (const source of sources) { if (!source) { continue; } for (const name of nonEnumerableProperties) { if (!(name in source)) { continue; } properties[name] = { writable: true, configurable: true, enumerable: false, // @ts-expect-error TS doesn't see the check above value: source[name] }; } } Object.defineProperties(to, properties); }; class RequestError extends Error { constructor(message, error, self) { var _a; super(message); Error.captureStackTrace(this, this.constructor); this.name = 'RequestError'; this.code = error.code; if (self instanceof Request) { Object.defineProperty(this, 'request', { enumerable: false, value: self }); Object.defineProperty(this, 'response', { enumerable: false, value: self[kResponse] }); Object.defineProperty(this, 'options', { // This fails because of TS 3.7.2 useDefineForClassFields // Ref: https://github.com/microsoft/TypeScript/issues/34972 enumerable: false, value: self.options }); } else { Object.defineProperty(this, 'options', { // This fails because of TS 3.7.2 useDefineForClassFields // Ref: https://github.com/microsoft/TypeScript/issues/34972 enumerable: false, value: self }); } this.timings = (_a = this.request) === null || _a === void 0 ? void 0 : _a.timings; // Recover the original stacktrace if (!is_1.default.undefined(error.stack)) { const indexOfMessage = this.stack.indexOf(this.message) + this.message.length; const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse(); const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse(); // Remove duplicated traces while (errorStackTrace.length !== 0 && errorStackTrace[0] === thisStackTrace[0]) { thisStackTrace.shift(); } this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`; } } } exports.RequestError = RequestError; class MaxRedirectsError extends RequestError { constructor(request) { super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request); this.name = 'MaxRedirectsError'; } } exports.MaxRedirectsError = MaxRedirectsError; class HTTPError extends RequestError { constructor(response) { super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, response.request); this.name = 'HTTPError'; } } exports.HTTPError = HTTPError; class CacheError extends RequestError { constructor(error, request) { super(error.message, error, request); this.name = 'CacheError'; } } exports.CacheError = CacheError; class UploadError extends RequestError { constructor(error, request) { super(error.message, error, request); this.name = 'UploadError'; } } exports.UploadError = UploadError; class TimeoutError extends RequestError { constructor(error, timings, request) { super(error.message, error, request); this.name = 'TimeoutError'; this.event = error.event; this.timings = timings; } } exports.TimeoutError = TimeoutError; class ReadError extends RequestError { constructor(error, request) { super(error.message, error, request); this.name = 'ReadError'; } } exports.ReadError = ReadError; class UnsupportedProtocolError extends RequestError { constructor(options) { super(`Unsupported protocol "${options.url.protocol}"`, {}, options); this.name = 'UnsupportedProtocolError'; } } exports.UnsupportedProtocolError = UnsupportedProtocolError; const proxiedRequestEvents = [ 'socket', 'connect', 'continue', 'information', 'upgrade', 'timeout' ]; class Request extends stream_1.Duplex { constructor(url, options = {}, defaults) { super({ // It needs to be zero because we're just proxying the data to another stream highWaterMark: 0 }); this[kDownloadedSize] = 0; this[kUploadedSize] = 0; this.requestInitialized = false; this[kServerResponsesPiped] = new Set(); this.redirects = []; this[kStopReading] = false; this[kTriggerRead] = false; this[kJobs] = []; // TODO: Remove this when targeting Node.js >= 12 this._progressCallbacks = []; const unlockWrite = () => this._unlockWrite(); const lockWrite = () => this._lockWrite(); this.on('pipe', (source) => { source.prependListener('data', unlockWrite); source.on('data', lockWrite); source.prependListener('end', unlockWrite); source.on('end', lockWrite); }); this.on('unpipe', (source) => { source.off('data', unlockWrite); source.off('data', lockWrite); source.off('end', unlockWrite); source.off('end', lockWrite); }); this.on('pipe', source => { if (source instanceof http_1.IncomingMessage) { this.options.headers = { ...source.headers, ...this.options.headers }; } }); const { json, body, form } = options; if (json || body || form) { this._lockWrite(); } (async (nonNormalizedOptions) => { var _a; try { if (nonNormalizedOptions.body instanceof fs_1.ReadStream) { await waitForOpenFile(nonNormalizedOptions.body); } if (exports.kIsNormalizedAlready in nonNormalizedOptions) { this.options = nonNormalizedOptions; } else { // @ts-expect-error Common TypeScript bug saying that `this.constructor` is not accessible this.options = this.constructor.normalizeArguments(url, nonNormalizedOptions, defaults); } const { url: normalizedURL } = this.options; if (!normalizedURL) { throw new TypeError('Missing `url` property'); } this.requestUrl = normalizedURL.toString(); decodeURI(this.requestUrl); await this._finalizeBody(); await this._makeRequest(); if (this.destroyed) { (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroy(); return; } // Queued writes etc. for (const job of this[kJobs]) { job(); } this.requestInitialized = true; } catch (error) { if (error instanceof RequestError) { this._beforeError(error); return; } // This is a workaround for https://github.com/nodejs/node/issues/33335 if (!this.destroyed) { this.destroy(error); } } })(options); } static normalizeArguments(url, options, defaults) { var _a, _b, _c, _d; const rawOptions = options; if (is_1.default.object(url) && !is_1.default.urlInstance(url)) { options = { ...defaults, ...url, ...options }; } else { if (url && options && options.url !== undefined) { throw new TypeError('The `url` option is mutually exclusive with the `input` argument'); } options = { ...defaults, ...options }; if (url !== undefined) { options.url = url; } if (is_1.default.urlInstance(options.url)) { options.url = new url_1.URL(options.url.toString()); } } // TODO: Deprecate URL options in Got 12. // Support extend-specific options if (options.cache === false) { options.cache = undefined; } if (options.dnsCache === false) { options.dnsCache = undefined; } // Nice type assertions is_1.assert.any([is_1.default.string, is_1.default.undefined], options.method); is_1.assert.any([is_1.default.object, is_1.default.undefined], options.headers); is_1.assert.any([is_1.default.string, is_1.default.urlInstance, is_1.default.undefined], options.prefixUrl); is_1.assert.any([is_1.default.object, is_1.default.undefined], options.cookieJar); is_1.assert.any([is_1.default.object, is_1.default.string, is_1.default.undefined], options.searchParams); is_1.assert.any([is_1.default.object, is_1.default.string, is_1.default.undefined], options.cache); is_1.assert.any([is_1.default.object, is_1.default.number, is_1.default.undefined], options.timeout); is_1.assert.any([is_1.default.object, is_1.default.undefined], options.context); is_1.assert.any([is_1.default.object, is_1.default.undefined], options.hooks); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.decompress); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.ignoreInvalidCookies); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.followRedirect); is_1.assert.any([is_1.default.number, is_1.default.undefined], options.maxRedirects); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.throwHttpErrors); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.http2); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.allowGetBody); is_1.assert.any([is_1.default.string, is_1.default.undefined], options.localAddress); is_1.assert.any([dns_ip_version_1.isDnsLookupIpVersion, is_1.default.undefined], options.dnsLookupIpVersion); is_1.assert.any([is_1.default.object, is_1.default.undefined], options.https); is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.rejectUnauthorized); if (options.https) { is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.https.rejectUnauthorized); is_1.assert.any([is_1.default.function_, is_1.default.undefined], options.https.checkServerIdentity); is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificateAuthority); is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.key); is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificate); is_1.assert.any([is_1.default.string, is_1.default.undefined], options.https.passphrase); } // `options.method` if (is_1.default.string(options.method)) { options.method = options.method.toUpperCase(); } else { options.method = 'GET'; } // `options.headers` if (options.headers === (defaults === null || defaults === void 0 ? void 0 : defaults.headers)) { options.headers = { ...options.headers }; } else { options.headers = lowercaseKeys({ ...(defaults === null || defaults === void 0 ? void 0 : defaults.headers), ...options.headers }); } // Disallow legacy `url.Url` if ('slashes' in options) { throw new TypeError('The legacy `url.Url` has been deprecated. Use `URL` instead.'); } // `options.auth` if ('auth' in options) { throw new TypeError('Parameter `auth` is deprecated. Use `username` / `password` instead.'); } // `options.searchParams` if ('searchParams' in options) { if (options.searchParams && options.searchParams !== (defaults === null || defaults === void 0 ? void 0 : defaults.searchParams)) { let searchParameters; if (is_1.default.string(options.searchParams) || (options.searchParams instanceof url_1.URLSearchParams)) { searchParameters = new url_1.URLSearchParams(options.searchParams); } else { validateSearchParameters(options.searchParams); searchParameters = new url_1.URLSearchParams(); // eslint-disable-next-line guard-for-in for (const key in options.searchParams) { const value = options.searchParams[key]; if (value === null) { searchParameters.append(key, ''); } else if (value !== undefined) { searchParameters.append(key, value); } } } // `normalizeArguments()` is also used to merge options (_a = defaults === null || defaults === void 0 ? void 0 : defaults.searchParams) === null || _a === void 0 ? void 0 : _a.forEach((value, key) => { // Only use default if one isn't already defined if (!searchParameters.has(key)) { searchParameters.append(key, value); } }); options.searchParams = searchParameters; } } // `options.username` & `options.password` options.username = (_b = options.username) !== null && _b !== void 0 ? _b : ''; options.password = (_c = options.password) !== null && _c !== void 0 ? _c : ''; // `options.prefixUrl` & `options.url` if (options.prefixUrl) { options.prefixUrl = options.prefixUrl.toString(); if (options.prefixUrl !== '' && !options.prefixUrl.endsWith('/')) { options.prefixUrl += '/'; } } else { options.prefixUrl = ''; } if (is_1.default.string(options.url)) { if (options.url.startsWith('/')) { throw new Error('`input` must not start with a slash when using `prefixUrl`'); } options.url = options_to_url_1.default(options.prefixUrl + options.url, options); } else if ((is_1.default.undefined(options.url) && options.prefixUrl !== '') || options.protocol) { options.url = options_to_url_1.default(options.prefixUrl, options); } if (options.url) { // Make it possible to change `options.prefixUrl` let { prefixUrl } = options; Object.defineProperty(options, 'prefixUrl', { set: (value) => { const url = options.url; if (!url.href.startsWith(value)) { throw new Error(`Cannot change \`prefixUrl\` from ${prefixUrl} to ${value}: ${url.href}`); } options.url = new url_1.URL(value + url.href.slice(prefixUrl.length)); prefixUrl = value; }, get: () => prefixUrl }); // Support UNIX sockets let { protocol } = options.url; if (protocol === 'unix:') { protocol = 'http:'; options.url = new url_1.URL(`http://unix${options.url.pathname}${options.url.search}`); } // Set search params if (options.searchParams) { // eslint-disable-next-line @typescript-eslint/no-base-to-string options.url.search = options.searchParams.toString(); } // Protocol check if (protocol !== 'http:' && protocol !== 'https:') { throw new UnsupportedProtocolError(options); } // Update `username` if (options.username === '') { options.username = options.url.username; } else { options.url.username = options.username; } // Update `password` if (options.password === '') { options.password = options.url.password; } else { options.url.password = options.password; } } // `options.cookieJar` const { cookieJar } = options; if (cookieJar) { let { setCookie, getCookieString } = cookieJar; is_1.assert.function_(setCookie); is_1.assert.function_(getCookieString); /* istanbul ignore next: Horrible `tough-cookie` v3 check */ if (setCookie.length === 4 && getCookieString.length === 0) { setCookie = util_1.promisify(setCookie.bind(options.cookieJar)); getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar)); options.cookieJar = { setCookie, // TODO: Fix this when upgrading to TypeScript 4. // @ts-expect-error TypeScript thinks that promisifying callback(error, string) will result in Promise getCookieString }; } } // `options.cache` const { cache } = options; if (cache) { if (!cacheableStore.has(cache)) { cacheableStore.set(cache, new CacheableRequest(((requestOptions, handler) => { const result = requestOptions[kRequest](requestOptions, handler); // TODO: remove this when `cacheable-request` supports async request functions. if (is_1.default.promise(result)) { // @ts-expect-error // We only need to implement the error handler in order to support HTTP2 caching. // The result will be a promise anyway. result.once = (event, handler) => { if (event === 'error') { result.catch(handler); } else if (event === 'abort') { // The empty catch is needed here in case when // it rejects before it's `await`ed in `_makeRequest`. (async () => { try { const request = (await result); request.once('abort', handler); } catch (_a) { } })(); } else { /* istanbul ignore next: safety check */ throw new Error(`Unknown HTTP2 promise event: ${event}`); } return result; }; } return result; }), cache)); } } // `options.dnsCache` if (options.dnsCache === true) { options.dnsCache = new cacheable_lookup_1.default(); } else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) { throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${is_1.default(options.dnsCache)}`); } // `options.timeout` if (is_1.default.number(options.timeout)) { options.timeout = { request: options.timeout }; } else if (defaults && options.timeout !== defaults.timeout) { options.timeout = { ...defaults.timeout, ...options.timeout }; } else { options.timeout = { ...options.timeout }; } // `options.context` if (!options.context) { options.context = {}; } // `options.hooks` const areHooksDefault = options.hooks === (defaults === null || defaults === void 0 ? void 0 : defaults.hooks); options.hooks = { ...options.hooks }; for (const event of exports.knownHookEvents) { if (event in options.hooks) { if (is_1.default.array(options.hooks[event])) { // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044 options.hooks[event] = [...options.hooks[event]]; } else { throw new TypeError(`Parameter \`${event}\` must be an Array, got ${is_1.default(options.hooks[event])}`); } } else { options.hooks[event] = []; } } if (defaults && !areHooksDefault) { for (const event of exports.knownHookEvents) { const defaultHooks = defaults.hooks[event]; if (defaultHooks.length !== 0) { // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044 options.hooks[event] = [ ...defaults.hooks[event], ...options.hooks[event] ]; } } } // DNS options if ('family' in options) { deprecation_warning_1.default('"options.family" was never documented, please use "options.dnsLookupIpVersion"'); } // HTTPS options if (defaults === null || defaults === void 0 ? void 0 : defaults.https) { options.https = { ...defaults.https, ...options.https }; } if ('rejectUnauthorized' in options) { deprecation_warning_1.default('"options.rejectUnauthorized" is now deprecated, please use "options.https.rejectUnauthorized"'); } if ('checkServerIdentity' in options) { deprecation_warning_1.default('"options.checkServerIdentity" was never documented, please use "options.https.checkServerIdentity"'); } if ('ca' in options) { deprecation_warning_1.default('"options.ca" was never documented, please use "options.https.certificateAuthority"'); } if ('key' in options) { deprecation_warning_1.default('"options.key" was never documented, please use "options.https.key"'); } if ('cert' in options) { deprecation_warning_1.default('"options.cert" was never documented, please use "options.https.certificate"'); } if ('passphrase' in options) { deprecation_warning_1.default('"options.passphrase" was never documented, please use "options.https.passphrase"'); } // Other options if ('followRedirects' in options) { throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.'); } if (options.agent) { for (const key in options.agent) { if (key !== 'http' && key !== 'https' && key !== 'http2') { throw new TypeError(`Expected the \`options.agent\` properties to be \`http\`, \`https\` or \`http2\`, got \`${key}\``); } } } options.maxRedirects = (_d = options.maxRedirects) !== null && _d !== void 0 ? _d : 0; // Set non-enumerable properties exports.setNonEnumerableProperties([defaults, rawOptions], options); return options; } _lockWrite() { const onLockedWrite = () => { throw new TypeError('The payload has been already provided'); }; this.write = onLockedWrite; this.end = onLockedWrite; } _unlockWrite() { this.write = super.write; this.end = super.end; } async _finalizeBody() { const { options } = this; const { headers } = options; const isForm = !is_1.default.undefined(options.form); const isJSON = !is_1.default.undefined(options.json); const isBody = !is_1.default.undefined(options.body); const hasPayload = isForm || isJSON || isBody; const cannotHaveBody = exports.withoutBody.has(options.method) && !(options.method === 'GET' && options.allowGetBody); this._cannotHaveBody = cannotHaveBody; if (hasPayload) { if (cannotHaveBody) { throw new TypeError(`The \`${options.method}\` method cannot be used with a body`); } if ([isBody, isForm, isJSON].filter(isTrue => isTrue).length > 1) { throw new TypeError('The `body`, `json` and `form` options are mutually exclusive'); } if (isBody && !(options.body instanceof stream_1.Readable) && !is_1.default.string(options.body) && !is_1.default.buffer(options.body) && !is_form_data_1.default(options.body)) { throw new TypeError('The `body` option must be a stream.Readable, string or Buffer'); } if (isForm && !is_1.default.object(options.form)) { throw new TypeError('The `form` option must be an Object'); } { // Serialize body const noContentType = !is_1.default.string(headers['content-type']); if (isBody) { // Special case for https://github.com/form-data/form-data if (is_form_data_1.default(options.body) && noContentType) { headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`; } this[kBody] = options.body; } else if (isForm) { if (noContentType) { headers['content-type'] = 'application/x-www-form-urlencoded'; } this[kBody] = (new url_1.URLSearchParams(options.form)).toString(); } else { if (noContentType) { headers['content-type'] = 'application/json'; } this[kBody] = options.stringifyJson(options.json); } const uploadBodySize = await get_body_size_1.default(this[kBody], options.headers); // See https://tools.ietf.org/html/rfc7230#section-3.3.2 // A user agent SHOULD send a Content-Length in a request message when // no Transfer-Encoding is sent and the request method defines a meaning // for an enclosed payload body. For example, a Content-Length header // field is normally sent in a POST request even when the value is 0 // (indicating an empty payload body). A user agent SHOULD NOT send a // Content-Length header field when the request message does not contain // a payload body and the method semantics do not anticipate such a // body. if (is_1.default.undefined(headers['content-length']) && is_1.default.undefined(headers['transfer-encoding'])) { if (!cannotHaveBody && !is_1.default.undefined(uploadBodySize)) { headers['content-length'] = String(uploadBodySize); } } } } else if (cannotHaveBody) { this._lockWrite(); } else { this._unlockWrite(); } this[kBodySize] = Number(headers['content-length']) || undefined; } async _onResponseBase(response) { const { options } = this; const { url } = options; this[kOriginalResponse] = response; if (options.decompress) { response = decompressResponse(response); } const statusCode = response.statusCode; const typedResponse = response; typedResponse.statusMessage = typedResponse.statusMessage ? typedResponse.statusMessage : http.STATUS_CODES[statusCode]; typedResponse.url = options.url.toString(); typedResponse.requestUrl = this.requestUrl; typedResponse.redirectUrls = this.redirects; typedResponse.request = this; typedResponse.isFromCache = response.fromCache || false; typedResponse.ip = this.ip; this[kIsFromCache] = typedResponse.isFromCache; this[kResponseSize] = Number(response.headers['content-length']) || undefined; this[kResponse] = response; response.once('end', () => { this[kResponseSize] = this[kDownloadedSize]; this.emit('downloadProgress', this.downloadProgress); }); response.once('error', (error) => { // Force clean-up, because some packages don't do this. // TODO: Fix decompress-response response.destroy(); this._beforeError(new ReadError(error, this)); }); response.once('aborted', () => { this._beforeError(new ReadError({ name: 'Error', message: 'The server aborted pending request', code: 'ECONNRESET' }, this)); }); this.emit('downloadProgress', this.downloadProgress); const rawCookies = response.headers['set-cookie']; if (is_1.default.object(options.cookieJar) && rawCookies) { let promises = rawCookies.map(async (rawCookie) => options.cookieJar.setCookie(rawCookie, url.toString())); if (options.ignoreInvalidCookies) { promises = promises.map(async (p) => p.catch(() => { })); } try { await Promise.all(promises); } catch (error) { this._beforeError(error); return; } } if (options.followRedirect && response.headers.location && redirectCodes.has(statusCode)) { // We're being redirected, we don't care about the response. // It'd be besto to abort the request, but we can't because // we would have to sacrifice the TCP connection. We don't want that. response.resume(); if (this[kRequest]) { this[kCancelTimeouts](); // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete this[kRequest]; this[kUnproxyEvents](); } const shouldBeGet = statusCode === 303 && options.method !== 'GET' && options.method !== 'HEAD'; if (shouldBeGet || !options.methodRewriting) { // Server responded with "see other", indicating that the resource exists at another location, // and the client should request it from that location via GET or HEAD. options.method = 'GET'; if ('body' in options) { delete options.body; } if ('json' in options) { delete options.json; } if ('form' in options) { delete options.form; } } if (this.redirects.length >= options.maxRedirects) { this._beforeError(new MaxRedirectsError(this)); return; } try { // Do not remove. See https://github.com/sindresorhus/got/pull/214 const redirectBuffer = Buffer.from(response.headers.location, 'binary').toString(); // Handles invalid URLs. See https://github.com/sindresorhus/got/issues/604 const redirectUrl = new url_1.URL(redirectBuffer, url); const redirectString = redirectUrl.toString(); decodeURI(redirectString); // Redirecting to a different site, clear sensitive data. if (redirectUrl.hostname !== url.hostname) { if ('host' in options.headers) { delete options.headers.host; } if ('cookie' in options.headers) { delete options.headers.cookie; } if ('authorization' in options.headers) { delete options.headers.authorization; } if (options.username || options.password) { delete options.username; delete options.password; } } this.redirects.push(redirectString); options.url = redirectUrl; for (const hook of options.hooks.beforeRedirect) { // eslint-disable-next-line no-await-in-loop await hook(options, typedResponse); } this.emit('redirect', typedResponse, options); await this._makeRequest(); } catch (error) { this._beforeError(error); return; } return; } const limitStatusCode = options.followRedirect ? 299 : 399; const isOk = (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304; if (options.throwHttpErrors && !isOk) { // Normally we would have to use `void [await] this._beforeError(error)` everywhere, // but since there's `void (async () => { ... })()` inside of it, we don't have to. this._beforeError(new HTTPError(typedResponse)); // This is equivalent to this.destroyed if (this[kStopReading]) { return; } } response.on('readable', () => { if (this[kTriggerRead]) { this._read(); } }); this.on('resume', () => { response.resume(); }); this.on('pause', () => { response.pause(); }); response.once('end', () => { this.push(null); }); this.emit('response', response); for (const destination of this[kServerResponsesPiped]) { if (destination.headersSent) { continue; } // eslint-disable-next-line guard-for-in for (const key in response.headers) { const isAllowed = options.decompress ? key !== 'content-encoding' : true; const value = response.headers[key]; if (isAllowed) { destination.setHeader(key, value); } } destination.statusCode = statusCode; } } async _onResponse(response) { try { await this._onResponseBase(response); } catch (error) { this._beforeError(error); } } _onRequest(request) { const { options } = this; const { timeout, url } = options; http_timer_1.default(request); this[kCancelTimeouts] = timed_out_1.default(request, timeout, url); const responseEventName = options.cache ? 'cacheableResponse' : 'response'; request.once(responseEventName, (response) => { void this._onResponse(response); }); request.once('error', (error) => { var _a; // Force clean-up, because some packages (e.g. nock) don't do this. request.destroy(); // Node.js <= 12.18.2 mistakenly emits the response `end` first. (_a = request.res) === null || _a === void 0 ? void 0 : _a.removeAllListeners('end'); if (error instanceof timed_out_1.TimeoutError) { error = new TimeoutError(error, this.timings, this); } else { error = new RequestError(error.message, error, this); } this._beforeError(error); }); this[kUnproxyEvents] = proxy_events_1.default(request, this, proxiedRequestEvents); this[kRequest] = request; this.emit('uploadProgress', this.uploadProgress); // Send body const body = this[kBody]; const currentRequest = this.redirects.length === 0 ? this : request; if (is_1.default.nodeStream(body)) { body.pipe(currentRequest); body.once('error', (error) => { this._beforeError(new UploadError(error, this)); }); body.once('end', () => { delete options.body; }); } else { this._unlockWrite(); if (!is_1.default.undefined(body)) { this._writeRequest(body, undefined, () => { }); currentRequest.end(); this._lockWrite(); } else if (this._cannotHaveBody || this._noPipe) { currentRequest.end(); this._lockWrite(); } } this.emit('request', request); } async _createCacheableRequest(url, options) { return new Promise((resolve, reject) => { // TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed Object.assign(options, url_to_options_1.default(url)); // `http-cache-semantics` checks this delete options.url; let request; // This is ugly const cacheRequest = cacheableStore.get(options.cache)(options, async (response) => { // TODO: Fix `cacheable-response` response._readableState.autoDestroy = false; if (request) { (await request).emit('cacheableResponse', response); } resolve(response); }); // Restore options options.url = url; cacheRequest.once('error', reject); cacheRequest.once('request', async (requestOrPromise) => { request = requestOrPromise; resolve(request); }); }); } async _makeRequest() { var _a; const { options } = this; const { headers } = options; for (const key in headers) { if (is_1.default.undefined(headers[key])) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete headers[key]; } else if (is_1.default.null_(headers[key])) { throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`); } } if (options.decompress && is_1.default.undefined(headers['accept-encoding'])) { headers['accept-encoding'] = supportsBrotli ? 'gzip, deflate, br' : 'gzip, deflate'; } // Set cookies if (options.cookieJar) { const cookieString = await options.cookieJar.getCookieString(options.url.toString()); if (is_1.default.nonEmptyString(cookieString)) { options.headers.cookie = cookieString; } } for (const hook of options.hooks.beforeRequest) { // eslint-disable-next-line no-await-in-loop const result = await hook(options); if (!is_1.default.undefined(result)) { // @ts-expect-error Skip the type mismatch to support abstract responses options.request = () => result; break; } } const { agent, request, timeout, url } = options; if (options.dnsCache && !('lookup' in options)) { options.lookup = options.dnsCache.lookup; } // UNIX sockets if (url.hostname === 'unix') { const matches = /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`); if (matches === null || matches === void 0 ? void 0 : matches.groups) { const { socketPath, path } = matches.groups; Object.assign(options, { socketPath, path, host: '' }); } } const isHttps = url.protocol === 'https:'; // Fallback function let fallbackFn; if (options.http2) { fallbackFn = http2wrapper.auto; } else { fallbackFn = isHttps ? https.request : http.request; } const realFn = (_a = options.request) !== null && _a !== void 0 ? _a : fallbackFn; // Cache support const fn = options.cache ? this._createCacheableRequest : realFn; // Pass an agent directly when HTTP2 is disabled if (agent && !options.http2) { options.agent = agent[isHttps ? 'https' : 'http']; } // Prepare plain HTTP request options options[kRequest] = realFn; delete options.request; delete options.timeout; const requestOptions = options; // If `dnsLookupIpVersion` is not present do not override `family` if (options.dnsLookupIpVersion !== undefined) { try { requestOptions.family = dns_ip_version_1.dnsLookupIpVersionToFamily(options.dnsLookupIpVersion); } catch (_b) { throw new Error('Invalid `dnsLookupIpVersion` option value'); } } // HTTPS options remapping if (options.https) { if ('rejectUnauthorized' in options.https) { requestOptions.rejectUnauthorized = options.https.rejectUnauthorized; } if (options.https.checkServerIdentity) { requestOptions.checkServerIdentity = options.https.checkServerIdentity; } if (options.https.certificateAuthority) { requestOptions.ca = options.https.certificateAuthority; } if (options.https.certificate) { requestOptions.cert = options.https.certificate; } if (options.https.key) { requestOptions.key = options.https.key; } if (options.https.passphrase) { requestOptions.passphrase = options.https.passphrase; } } try { let requestOrResponse = await fn(url, requestOptions); if (is_1.default.undefined(requestOrResponse)) { requestOrResponse = fallbackFn(url, requestOptions); } // Restore options options.request = request; options.timeout = timeout; options.agent = agent; if (isClientRequest(requestOrResponse)) { this._onRequest(requestOrResponse); // Emit the response after the stream has been ended } else if (this.writable) { this.once('finish', () => { void this._onResponse(requestOrResponse); }); this._unlockWrite(); this.end(); this._lockWrite(); } else { void this._onResponse(requestOrResponse); } } catch (error) { if (error instanceof CacheableRequest.CacheError) { throw new CacheError(error, this); } throw new RequestError(error.message, error, this); } } _beforeError(error) { if (this.destroyed) { return; } this[kStopReading] = true; if (!(error instanceof RequestError)) { error = new RequestError(error.message, error, this); } void (async () => { try { const { response } = error; if (response) { response.setEncoding(this._readableState.encoding); response.rawBody = await get_buffer_1.default(response); response.body = response.rawBody.toString(); } } catch (_a) { } try { for (const hook of this.options.hooks.beforeError) { // eslint-disable-next-line no-await-in-loop error = await hook(error); } } catch (error_) { error = new RequestError(error_.message, error_, this); } this.destroy(error); })(); } _read() { this[kTriggerRead] = true; const response = this[kResponse]; if (response && !this[kStopReading]) { // We cannot put this in the `if` above // because `.read()` also triggers the `end` event if (response.readableLength) { this[kTriggerRead] = false; } let data; while ((data = response.read()) !== null) { this[kDownloadedSize] += data.length; this[kStartedReading] = true; const progress = this.downloadProgress; if (progress.percent < 1) { this.emit('downloadProgress', progress); } this.push(data); } } } // Node.js 12 has incorrect types, so the encoding must be a string _write(chunk, encoding, callback) { const write = () => { this._writeRequest(chunk, encoding, callback); }; if (this.requestInitialized) { write(); } else { this[kJobs].push(write); } } _writeRequest(chunk, encoding, callback) { this._progressCallbacks.push(() => { this[kUploadedSize] += Buffer.byteLength(chunk, encoding); const progress = this.uploadProgress; if (progress.percent < 1) { this.emit('uploadProgress', progress); } }); // TODO: What happens if it's from cache? Then this[kRequest] won't be defined. this[kRequest].write(chunk, encoding, (error) => { if (!error && this._progressCallbacks.length !== 0) { this._progressCallbacks.shift()(); } callback(error); }); } _final(callback) { const endRequest = () => { // FIX: Node.js 10 calls the write callback AFTER the end callback! while (this._progressCallbacks.length !== 0) { this._progressCallbacks.shift()(); } // We need to check if `this[kRequest]` is present, // because it isn't when we use cache. if (!(kRequest in this)) { callback(); return; } if (this[kRequest].destroyed) { callback(); return; } this[kRequest].end((error) => { if (!error) { this[kBodySize] = this[kUploadedSize]; this.emit('uploadProgress', this.uploadProgress); this[kRequest].emit('upload-complete'); } callback(error); }); }; if (this.requestInitialized) { endRequest(); } else { this[kJobs].push(endRequest); } } _destroy(error, callback) { var _a; this[kStopReading] = true; if (kRequest in this) { this[kCancelTimeouts](); // TODO: Remove the next `if` when these get fixed: // - https://github.com/nodejs/node/issues/32851 if (!((_a = this[kResponse]) === null || _a === void 0 ? void 0 : _a.complete)) { this[kRequest].destroy(); } } if (error !== null && !is_1.default.undefined(error) && !(error instanceof RequestError)) { error = new RequestError(error.message, error, this); } callback(error); } get ip() { var _a; return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket.remoteAddress; } get aborted() { var _a, _b, _c; return ((_b = (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroyed) !== null && _b !== void 0 ? _b : this.destroyed) && !((_c = this[kOriginalResponse]) === null || _c === void 0 ? void 0 : _c.complete); } get socket() { var _a; return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket; } get downloadProgress() { let percent; if (this[kResponseSize]) { percent = this[kDownloadedSize] / this[kResponseSize]; } else if (this[kResponseSize] === this[kDownloadedSize]) { percent = 1; } else { percent = 0; } return { percent, transferred: this[kDownloadedSize], total: this[kResponseSize] }; } get uploadProgress() { let percent; if (this[kBodySize]) { percent = this[kUploadedSize] / this[kBodySize]; } else if (this[kBodySize] === this[kUploadedSize]) { percent = 1; } else { percent = 0; } return { percent, transferred: this[kUploadedSize], total: this[kBodySize] }; } get timings() { var _a; return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.timings; } get isFromCache() { return this[kIsFromCache]; } get _response() { return this[kResponse]; } pipe(destination, options) { if (this[kStartedReading]) { throw new Error('Failed to pipe. The response has been emitted already.'); } if (destination instanceof http_1.ServerResponse) { this[kServerResponsesPiped].add(destination); } return super.pipe(destination, options); } unpipe(destination) { if (destination instanceof http_1.ServerResponse) { this[kServerResponsesPiped].delete(destination); } super.unpipe(destination); return this; } } exports.default = Request; /***/ }), /***/ 988: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const http = __webpack_require__(605); const https = __webpack_require__(211); const resolveALPN = __webpack_require__(524); const QuickLRU = __webpack_require__(904); const Http2ClientRequest = __webpack_require__(181); const calculateServerName = __webpack_require__(751); const urlToOptions = __webpack_require__(507); const cache = new QuickLRU({maxSize: 100}); const queue = new Map(); const installSocket = (agent, socket, options) => { socket._httpMessage = {shouldKeepAlive: true}; const onFree = () => { agent.emit('free', socket, options); }; socket.on('free', onFree); const onClose = () => { agent.removeSocket(socket, options); }; socket.on('close', onClose); const onRemove = () => { agent.removeSocket(socket, options); socket.off('close', onClose); socket.off('free', onFree); socket.off('agentRemove', onRemove); }; socket.on('agentRemove', onRemove); agent.emit('free', socket, options); }; const resolveProtocol = async options => { const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`; if (!cache.has(name)) { if (queue.has(name)) { const result = await queue.get(name); return result.alpnProtocol; } const {path, agent} = options; options.path = options.socketPath; const resultPromise = resolveALPN(options); queue.set(name, resultPromise); try { const {socket, alpnProtocol} = await resultPromise; cache.set(name, alpnProtocol); options.path = path; if (alpnProtocol === 'h2') { // https://github.com/nodejs/node/issues/33343 socket.destroy(); } else { const {globalAgent} = https; const defaultCreateConnection = https.Agent.prototype.createConnection; if (agent) { if (agent.createConnection === defaultCreateConnection) { installSocket(agent, socket, options); } else { socket.destroy(); } } else if (globalAgent.createConnection === defaultCreateConnection) { installSocket(globalAgent, socket, options); } else { socket.destroy(); } } queue.delete(name); return alpnProtocol; } catch (error) { queue.delete(name); throw error; } } return cache.get(name); }; module.exports = async (input, options, callback) => { if (typeof input === 'string' || input instanceof URL) { input = urlToOptions(new URL(input)); } if (typeof options === 'function') { callback = options; options = undefined; } options = { ALPNProtocols: ['h2', 'http/1.1'], ...input, ...options, resolveSocket: true }; if (!Array.isArray(options.ALPNProtocols) || options.ALPNProtocols.length === 0) { throw new Error('The `ALPNProtocols` option must be an Array with at least one entry'); } options.protocol = options.protocol || 'https:'; const isHttps = options.protocol === 'https:'; options.host = options.hostname || options.host || 'localhost'; options.session = options.tlsSession; options.servername = options.servername || calculateServerName(options); options.port = options.port || (isHttps ? 443 : 80); options._defaultAgent = isHttps ? https.globalAgent : http.globalAgent; const agents = options.agent; if (agents) { if (agents.addRequest) { throw new Error('The `options.agent` object can contain only `http`, `https` or `http2` properties'); } options.agent = agents[isHttps ? 'https' : 'http']; } if (isHttps) { const protocol = await resolveProtocol(options); if (protocol === 'h2') { if (agents) { options.agent = agents.http2; } return new Http2ClientRequest(options, callback); } } return http.request(options, callback); }; module.exports.protocolCache = cache; /***/ }), /***/ 997: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; const pump = __webpack_require__(453); const bufferStream = __webpack_require__(375); class MaxBufferError extends Error { constructor() { super('maxBuffer exceeded'); this.name = 'MaxBufferError'; } } async function getStream(inputStream, options) { if (!inputStream) { return Promise.reject(new Error('Expected a stream')); } options = { maxBuffer: Infinity, ...options }; const {maxBuffer} = options; let stream; await new Promise((resolve, reject) => { const rejectPromise = error => { if (error) { // A null check error.bufferedData = stream.getBufferedValue(); } reject(error); }; stream = pump(inputStream, bufferStream(options), error => { if (error) { rejectPromise(error); return; } resolve(); }); stream.on('data', () => { if (stream.getBufferedLength() > maxBuffer) { rejectPromise(new MaxBufferError()); } }); }); return stream.getBufferedValue(); } module.exports = getStream; // TODO: Remove this for the next major release module.exports.default = getStream; module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'}); module.exports.array = (stream, options) => getStream(stream, {...options, array: true}); module.exports.MaxBufferError = MaxBufferError; /***/ }) /******/ });