diff --git a/dist/index.js b/dist/index.js index 086c9d0..48a23c5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -19,7 +19,13 @@ module.exports = /******/ }; /******/ /******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ var threw = true; +/******/ try { +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ threw = false; +/******/ } finally { +/******/ if(threw) delete installedModules[moduleId]; +/******/ } /******/ /******/ // Flag the module as loaded /******/ module.l = true; @@ -34,7 +40,7 @@ module.exports = /******/ // the startup function /******/ function startup() { /******/ // Load entry module and return exports -/******/ return __webpack_require__(492); +/******/ return __webpack_require__(130); /******/ }; /******/ /******/ // run startup @@ -43,14060 +49,15 @@ module.exports = /************************************************************************/ /******/ ({ -/***/ 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: +/***/ 94: /***/ (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 core = __webpack_require__(968); +const command = __webpack_require__(422); +const got = __webpack_require__(349).default; +const jsonata = __webpack_require__(128); +const { auth: { retrieveToken }, secrets: { getSecrets } } = __webpack_require__(897); const AUTH_METHODS = ['approle', 'token', 'github']; const VALID_KV_VERSION = [-1, 1, 2]; @@ -14126,27 +87,24 @@ async function exportSecrets() { https: {} } - const tlsSkipVerify = core.getInput('tlsSkipVerify', { required: false }) != 'false'; - if (tlsSkipVerify == true) { + const tlsSkipVerify = (core.getInput('tlsSkipVerify', { required: false }) || 'false').toLowerCase() != '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'); + if (caCertificateRaw != null) { + defaultOptions.https.certificateAuthority = Buffer.from(caCertificateRaw, 'base64').toString(); } - console.log(defaultOptions.https.certificateAuthority.toString()) - const clientCertificateRaw = core.getInput('clientCertificate', { required: false }); - if (clientCertificateRaw != "") { - defaultOptions.https.certificate = Buffer.from(clientCertificateRaw, 'base64'); + if (clientCertificateRaw != null) { + defaultOptions.https.certificate = Buffer.from(clientCertificateRaw, 'base64').toString(); } const clientKeyRaw = core.getInput('clientKey', { required: false }); - if (clientKeyRaw != "") { - defaultOptions.https.key = Buffer.from(clientCertificateRaw, 'base64'); + if (clientKeyRaw != null) { + defaultOptions.https.key = Buffer.from(clientKeyRaw, 'base64').toString(); } for (const [headerName, headerValue] of extraHeaders) { @@ -14322,1512 +280,234 @@ module.exports = { /***/ }), -/***/ 946: -/***/ (function(__unusedmodule, exports, __webpack_require__) { +/***/ 128: +/***/ (function(module) { -"use strict"; +module.exports = eval("require")("jsonata"); -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`); + +/***/ }), + +/***/ 130: +/***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { + +const core = __webpack_require__(968); +const { exportSecrets } = __webpack_require__(94); + +(async () => { + try { + await core.group('Get Vault Secrets', exportSecrets); + } catch (error) { + core.setFailed(error.message); + } +})(); + + +/***/ }), + +/***/ 238: +/***/ (function(module, __unusedexports, __webpack_require__) { + +// @ts-check +const core = __webpack_require__(968); + +/*** + * 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())); + } } } } -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); + +/*** + * 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, }; - // Node.js 12 has incomplete types - if (!file.pending) { - resolve(); + + 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.`); } - 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); +} + +/*** + * @typedef {Object} VaultLoginResponse + * @property {{ + * client_token: string; + * accessor: string; + * policies: string[]; + * metadata: unknown; + * lease_duration: number; + * renewable: boolean; + * }} auth + */ + +module.exports = { + retrieveToken, }; -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__) { +/***/ 349: +/***/ (function(module) { -"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; +module.exports = eval("require")("got"); /***/ }), -/***/ 997: +/***/ 422: +/***/ (function(module) { + +module.exports = eval("require")("@actions/core/lib/command"); + + +/***/ }), + +/***/ 520: /***/ (function(module, __unusedexports, __webpack_require__) { -"use strict"; +const jsonata = __webpack_require__(128); -const pump = __webpack_require__(453); -const bufferStream = __webpack_require__(375); -class MaxBufferError extends Error { - constructor() { - super('maxBuffer exceeded'); - this.name = 'MaxBufferError'; - } +/** + * @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; } -async function getStream(inputStream, options) { - if (!inputStream) { - return Promise.reject(new Error('Expected a stream')); - } +/** + * 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.`); + } - 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(); + if (result.startsWith(`"`)) { + result = result.substring(1, result.length - 1); + } + return result; } -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; +module.exports = { + getSecrets, + selectData +} + +/***/ }), + +/***/ 897: +/***/ (function(module, __unusedexports, __webpack_require__) { + +const auth = __webpack_require__(238); +const secrets = __webpack_require__(520); + +module.exports = { + auth, + secrets +}; + +/***/ }), + +/***/ 968: +/***/ (function(module) { + +module.exports = eval("require")("@actions/core"); /***/ })