diff --git a/dist/index.js b/dist/index.js index 593d2f07..fb2f2b16 100644 --- a/dist/index.js +++ b/dist/index.js @@ -47,10 +47,10 @@ const annotations_1 = __nccwpck_require__(31058); async function decorateAction(analysisResult, analysis) { let summaryBody; if (analysisResult) { - summaryBody = (0, summary_1.createSummaryBody)(analysisResult); + summaryBody = await (0, summary_1.createSummaryBody)(analysisResult); } else { - summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); + summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); } if (config_1.githubConfig.event.isPullRequest) { await (0, pull_request_1.decoratePullRequest)(analysisResult?.passed ?? false, summaryBody); @@ -71,6 +71,8 @@ async function decorateAction(analysisResult, analysis) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.generateStatusMarkdown = generateStatusMarkdown; exports.generateExpandableAreaMarkdown = generateExpandableAreaMarkdown; +exports.generateItalic = generateItalic; +exports.generateComment = generateComment; const os_1 = __nccwpck_require__(22037); const enums_1 = __nccwpck_require__(31655); /** @@ -101,6 +103,20 @@ function generateStatusMarkdown(status, hasSuffix = false) { function generateExpandableAreaMarkdown(header, body) { return `
${header}${os_1.EOL}${body}
${os_1.EOL}${os_1.EOL}`; } +/** + * Generates italic text for markdown. + * @param text The text to make italic. + */ +function generateItalic(text, title) { + return `${text}`; +} +/** + * Generates a hidden comment for markdown. + * @param comment The text of the comment. + */ +function generateComment(comment) { + return ``; +} /***/ }), @@ -201,11 +217,11 @@ const logger_1 = __nccwpck_require__(26440); const url_1 = __nccwpck_require__(76259); const markdown_1 = __nccwpck_require__(60517); const config_1 = __nccwpck_require__(86444); +const runs_1 = __nccwpck_require__(50046); const capitalize = (s) => s && String(s[0]).toUpperCase() + String(s).slice(1); -function createSummaryBody(analysisResult) { +async function createSummaryBody(analysisResult) { logger_1.logger.header('Creating summary.'); - core_1.summary.addHeading('TICS Quality Gate'); - core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(getStatus(analysisResult.passed, analysisResult.passedWithWarning), true), 3); + setSummaryHeader(getStatus(analysisResult.passed, analysisResult.passedWithWarning)); analysisResult.projectResults.forEach(projectResult => { if (projectResult.qualityGate) { const failedOrWarnConditions = extractFailedOrWarningConditions(projectResult.qualityGate.gates); @@ -231,6 +247,7 @@ function createSummaryBody(analysisResult) { core_1.summary.addRaw(createFilesSummary(projectResult.analyzedFiles)); } }); + await setSummaryFooter(); logger_1.logger.info('Created summary.'); return core_1.summary.stringify(); } @@ -240,10 +257,9 @@ function createSummaryBody(analysisResult) { * @param warningList list containing all the warnings found in the TICS run. * @returns string containing the error summary. */ -function createErrorSummaryBody(errorList, warningList) { +async function createErrorSummaryBody(errorList, warningList) { logger_1.logger.header('Creating summary.'); - core_1.summary.addHeading('TICS Quality Gate'); - core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(enums_1.Status.FAILED, true), 3); + setSummaryHeader(enums_1.Status.FAILED); if (errorList.length > 0) { core_1.summary.addHeading('The following errors have occurred during analysis:', 2); for (const error of errorList) { @@ -257,6 +273,7 @@ function createErrorSummaryBody(errorList, warningList) { core_1.summary.addRaw(`:warning: ${warning}${os_1.EOL}${os_1.EOL}`); } } + await setSummaryFooter(); logger_1.logger.info('Created summary.'); return core_1.summary.stringify(); } @@ -265,14 +282,24 @@ function createErrorSummaryBody(errorList, warningList) { * @param message Message to display in the body of the comment. * @returns string containing the error summary. */ -function createNothingAnalyzedSummaryBody(message) { +async function createNothingAnalyzedSummaryBody(message) { logger_1.logger.header('Creating summary.'); - core_1.summary.addHeading('TICS Quality Gate'); - core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(enums_1.Status.PASSED, true), 3); + setSummaryHeader(enums_1.Status.PASSED); core_1.summary.addRaw(message); + await setSummaryFooter(); logger_1.logger.info('Created summary.'); return core_1.summary.stringify(); } +function setSummaryHeader(status) { + core_1.summary.addHeading('TICS Quality Gate'); + core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(status, true), 3); +} +async function setSummaryFooter() { + core_1.summary.addEOL(); + core_1.summary.addRaw('

'); + core_1.summary.addRaw((0, markdown_1.generateItalic)(await (0, runs_1.getCurrentStepPath)(), 'Workflow / Job / Step'), true); + core_1.summary.addRaw((0, markdown_1.generateComment)(config_1.githubConfig.getCommentIdentifier())); +} function getConditionHeading(failedOrWarnConditions) { const countFailedConditions = failedOrWarnConditions.filter(c => !c.passed).length; const countWarnConditions = failedOrWarnConditions.filter(c => c.passed && c.passedWithWarning).length; @@ -519,6 +546,7 @@ function findAnnotationInList(list, annotation) { * @param unpostableReviewComments Review comments that could not be posted. * @returns Summary of all the review comments that could not be posted. */ +// Exported for testing function createUnpostableAnnotationsDetails(unpostableReviewComments) { const label = 'Quality gate failures that cannot be annotated in Files Changed'; let body = ''; @@ -674,14 +702,14 @@ async function processIncompleteAnalysis(analysis) { let summaryBody; if (!analysis.completed) { failedMessage = 'Failed to complete TICS analysis.'; - summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); + summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); } else if (analysis.warningList.find(w => w.includes('[WARNING 5057]'))) { - summaryBody = (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.'); + summaryBody = await (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.'); } else { failedMessage = 'Explorer URL not returned from TICS analysis.'; - summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); + summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); } if (config_1.githubConfig.event.isPullRequest) { await (0, pull_request_1.postToConversation)(false, summaryBody); @@ -808,13 +836,13 @@ async function qServerAnalysis() { }; if (!verdict.passed) { verdict.message = 'Failed to complete TICSQServer analysis.'; - const summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); + const summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList); if (config_1.githubConfig.event.isPullRequest) { await (0, pull_request_1.postToConversation)(false, summaryBody); } } else if (analysis.warningList.find(w => w.includes('[WARNING 5057]'))) { - const summaryBody = (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.'); + const summaryBody = await (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.'); if (config_1.githubConfig.event.isPullRequest) { await (0, pull_request_1.postToConversation)(false, summaryBody); } @@ -1024,17 +1052,29 @@ class GithubConfig { event; job; action; - id; + workflow; + runId; + runNumber; + runAttempt; pullRequestNumber; debugger; + runnerName; + id; constructor() { this.apiUrl = github_1.context.apiUrl; this.owner = github_1.context.repo.owner; this.reponame = github_1.context.repo.repo; this.commitSha = github_1.context.sha; this.event = this.getGithubEvent(); - this.job = github_1.context.job; + this.job = github_1.context.job.replace(/[\s|_]+/g, '-'); this.action = github_1.context.action.replace('__tiobe_', ''); + this.workflow = github_1.context.workflow.replace(/[\s|_]+/g, '-'); + this.runId = github_1.context.runId; + this.runNumber = github_1.context.runNumber; + this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10); + this.pullRequestNumber = this.getPullRequestNumber(); + this.debugger = (0, core_1.isDebug)(); + this.runnerName = process.env.RUNNER_NAME ?? ''; /** * Construct the id to use for storing tmpdirs. The action name will * be appended with a number if there are multiple runs within a job. @@ -1045,10 +1085,7 @@ class GithubConfig { * include a suffix that consists of the sequence number preceded by an underscore. * https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables */ - const runAttempt = process.env.GITHUB_RUN_ATTEMPT ?? '0'; - this.id = `${github_1.context.runId.toString()}_${runAttempt}_${this.job}_${this.action}`; - this.pullRequestNumber = this.getPullRequestNumber(); - this.debugger = (0, core_1.isDebug)(); + this.id = `${this.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`; this.removeWarningListener(); } getPullRequestNumber() { @@ -1080,6 +1117,9 @@ class GithubConfig { return github_event_1.GithubEvent.PUSH; } } + getCommentIdentifier() { + return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_'); + } removeWarningListener() { process.removeAllListeners('warning'); process.on('warning', warning => { @@ -1627,7 +1667,7 @@ async function postComment(body) { async function deletePreviousComments(comments) { logger_1.logger.header('Deleting comments of previous runs.'); for (const comment of comments) { - if (commentIncludesTicsTitle(comment.body)) { + if (shouldCommentBeDeleted(comment.body)) { try { const params = { owner: config_1.githubConfig.owner, @@ -1644,16 +1684,47 @@ async function deletePreviousComments(comments) { } logger_1.logger.info('Deleted review comments of previous runs.'); } -function commentIncludesTicsTitle(body) { - const titles = ['

TICS Quality Gate

', '## TICS Quality Gate', '## TICS Analysis']; +function shouldCommentBeDeleted(body) { if (!body) return false; + const titles = ['

TICS Quality Gate

', '## TICS Quality Gate', '## TICS Analysis']; let includesTitle = false; - titles.forEach(title => { - if (body.startsWith(title)) + for (const title of titles) { + if (body.startsWith(title)) { includesTitle = true; - }); - return includesTitle; + } + } + if (includesTitle) { + return isWorkflowAndJobInAnotherRun(body); + } + return false; +} +function isWorkflowAndJobInAnotherRun(body) { + const regex = //g; + let identifier = ''; + // Get the last match of the tag. + let match = null; + while ((match = regex.exec(body))) { + if (match[1] !== '') { + identifier = match[1]; + } + } + // If no identifier is found, the comment is + // of the old format and should be replaced. + if (identifier === '') + return true; + const split = identifier.split('_'); + // If the identifier does not match the correct format, do not replace. + if (split.length !== 4) { + logger_1.logger.debug(`Identifier is not of the correct format: ${identifier}`); + return false; + } + // If the workflow or job are different, do not replace. + if (split[0] !== config_1.githubConfig.workflow || split[1] !== config_1.githubConfig.job) { + return false; + } + // Only replace if the run number or run attempt are different. + return parseInt(split[2], 10) !== config_1.githubConfig.runNumber || parseInt(split[3], 10) !== config_1.githubConfig.runAttempt; } @@ -1882,6 +1953,54 @@ async function postReview(body, event) { } +/***/ }), + +/***/ 50046: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getCurrentStepPath = getCurrentStepPath; +const logger_1 = __nccwpck_require__(26440); +const response_1 = __nccwpck_require__(81934); +const config_1 = __nccwpck_require__(86444); +const octokit_1 = __nccwpck_require__(10775); +/** + * Create review on the pull request from the analysis given. + * @param body Body containing the summary of the review + * @param event Either approve or request changes in the review. + */ +async function getCurrentStepPath() { + const params = { + owner: config_1.githubConfig.owner, + repo: config_1.githubConfig.reponame, + run_id: config_1.githubConfig.runId, + attempt_number: config_1.githubConfig.runAttempt + }; + const stepname = [config_1.githubConfig.workflow, config_1.githubConfig.job, config_1.githubConfig.action]; + try { + logger_1.logger.debug('Retrieving step name for current step...'); + const response = await octokit_1.octokit.rest.actions.listJobsForWorkflowRunAttempt(params); + logger_1.logger.debug(JSON.stringify(response.data)); + const jobs = response.data.jobs.filter(j => j.status === 'in_progress' && j.runner_name === config_1.githubConfig.runnerName); + if (jobs.length === 1) { + const job = jobs[0]; + stepname[1] = job.name; + const steps = job.steps?.filter(s => s.status === 'in_progress'); + if (steps?.length === 1) { + stepname[2] = steps[0].name; + } + } + } + catch (error) { + const message = (0, response_1.handleOctokitError)(error); + logger_1.logger.notice(`Retrieving the step name failed: ${message}`); + } + return stepname.join(' / '); +} + + /***/ }), /***/ 31655: @@ -62212,427 +62331,427 @@ module.exports.PROCESSING_OPTIONS = PROCESSING_OPTIONS; /***/ 4351: /***/ ((module) => { -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ -/* global global, define, Symbol, Reflect, Promise, SuppressedError */ -var __extends; -var __assign; -var __rest; -var __decorate; -var __param; -var __esDecorate; -var __runInitializers; -var __propKey; -var __setFunctionName; -var __metadata; -var __awaiter; -var __generator; -var __exportStar; -var __values; -var __read; -var __spread; -var __spreadArrays; -var __spreadArray; -var __await; -var __asyncGenerator; -var __asyncDelegator; -var __asyncValues; -var __makeTemplateObject; -var __importStar; -var __importDefault; -var __classPrivateFieldGet; -var __classPrivateFieldSet; -var __classPrivateFieldIn; -var __createBinding; -var __addDisposableResource; -var __disposeResources; -(function (factory) { - var root = typeof global === "object" ? global : typeof self === "object" ? self : typeof this === "object" ? this : {}; - if (typeof define === "function" && define.amd) { - define("tslib", ["exports"], function (exports) { factory(createExporter(root, createExporter(exports))); }); - } - else if ( true && typeof module.exports === "object") { - factory(createExporter(root, createExporter(module.exports))); - } - else { - factory(createExporter(root)); - } - function createExporter(exports, previous) { - if (exports !== root) { - if (typeof Object.create === "function") { - Object.defineProperty(exports, "__esModule", { value: true }); - } - else { - exports.__esModule = true; - } - } - return function (id, v) { return exports[id] = previous ? previous(id, v) : v; }; - } -}) -(function (exporter) { - var extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; - - __extends = function (d, b) { - if (typeof b !== "function" && b !== null) - throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; - - __assign = Object.assign || function (t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - }; - - __rest = function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; - }; - - __decorate = function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - }; - - __param = function (paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } - }; - - __esDecorate = function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { - function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } - var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; - var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; - var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); - var _, done = false; - for (var i = decorators.length - 1; i >= 0; i--) { - var context = {}; - for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; - for (var p in contextIn.access) context.access[p] = contextIn.access[p]; - context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; - var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); - if (kind === "accessor") { - if (result === void 0) continue; - if (result === null || typeof result !== "object") throw new TypeError("Object expected"); - if (_ = accept(result.get)) descriptor.get = _; - if (_ = accept(result.set)) descriptor.set = _; - if (_ = accept(result.init)) initializers.unshift(_); - } - else if (_ = accept(result)) { - if (kind === "field") initializers.unshift(_); - else descriptor[key] = _; - } - } - if (target) Object.defineProperty(target, contextIn.name, descriptor); - done = true; - }; - - __runInitializers = function (thisArg, initializers, value) { - var useValue = arguments.length > 2; - for (var i = 0; i < initializers.length; i++) { - value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); - } - return useValue ? value : void 0; - }; - - __propKey = function (x) { - return typeof x === "symbol" ? x : "".concat(x); - }; - - __setFunctionName = function (f, name, prefix) { - if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; - return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); - }; - - __metadata = function (metadataKey, metadataValue) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); - }; - - __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()); - }); - }; - - __generator = function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } - }; - - __exportStar = function(m, o) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); - }; - - __createBinding = Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); - }) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - }); - - __values = function (o) { - var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; - if (m) return m.call(o); - if (o && typeof o.length === "number") return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; - throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); - }; - - __read = function (o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; - }; - - /** @deprecated */ - __spread = function () { - for (var ar = [], i = 0; i < arguments.length; i++) - ar = ar.concat(__read(arguments[i])); - return ar; - }; - - /** @deprecated */ - __spreadArrays = function () { - for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; - for (var r = Array(s), k = 0, i = 0; i < il; i++) - for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) - r[k] = a[j]; - return r; - }; - - __spreadArray = function (to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); - }; - - __await = function (v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); - }; - - __asyncGenerator = function (thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; - function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } - function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } - function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } - function fulfill(value) { resume("next", value); } - function reject(value) { resume("throw", value); } - function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } - }; - - __asyncDelegator = function (o) { - var i, p; - return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } - }; - - __asyncValues = function (o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } - }; - - __makeTemplateObject = function (cooked, raw) { - if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } - return cooked; - }; - - var __setModuleDefault = Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - }) : function(o, v) { - o["default"] = v; - }; - - __importStar = function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; - }; - - __importDefault = function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; - }; - - __classPrivateFieldGet = function (receiver, state, kind, f) { - if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); - return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); - }; - - __classPrivateFieldSet = function (receiver, state, value, kind, f) { - if (kind === "m") throw new TypeError("Private method is not writable"); - if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); - return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; - }; - - __classPrivateFieldIn = function (state, receiver) { - if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); - return typeof state === "function" ? receiver === state : state.has(receiver); - }; - - __addDisposableResource = function (env, value, async) { - if (value !== null && value !== void 0) { - if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); - var dispose; - if (async) { - if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); - dispose = value[Symbol.asyncDispose]; - } - if (dispose === void 0) { - if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); - dispose = value[Symbol.dispose]; - } - if (typeof dispose !== "function") throw new TypeError("Object not disposable."); - env.stack.push({ value: value, dispose: dispose, async: async }); - } - else if (async) { - env.stack.push({ async: true }); - } - return value; - }; - - var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { - var e = new Error(message); - return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; - }; - - __disposeResources = function (env) { - function fail(e) { - env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; - env.hasError = true; - } - function next() { - while (env.stack.length) { - var rec = env.stack.pop(); - try { - var result = rec.dispose && rec.dispose.call(rec.value); - if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); - } - catch (e) { - fail(e); - } - } - if (env.hasError) throw env.error; - } - return next(); - }; - - exporter("__extends", __extends); - exporter("__assign", __assign); - exporter("__rest", __rest); - exporter("__decorate", __decorate); - exporter("__param", __param); - exporter("__esDecorate", __esDecorate); - exporter("__runInitializers", __runInitializers); - exporter("__propKey", __propKey); - exporter("__setFunctionName", __setFunctionName); - exporter("__metadata", __metadata); - exporter("__awaiter", __awaiter); - exporter("__generator", __generator); - exporter("__exportStar", __exportStar); - exporter("__createBinding", __createBinding); - exporter("__values", __values); - exporter("__read", __read); - exporter("__spread", __spread); - exporter("__spreadArrays", __spreadArrays); - exporter("__spreadArray", __spreadArray); - exporter("__await", __await); - exporter("__asyncGenerator", __asyncGenerator); - exporter("__asyncDelegator", __asyncDelegator); - exporter("__asyncValues", __asyncValues); - exporter("__makeTemplateObject", __makeTemplateObject); - exporter("__importStar", __importStar); - exporter("__importDefault", __importDefault); - exporter("__classPrivateFieldGet", __classPrivateFieldGet); - exporter("__classPrivateFieldSet", __classPrivateFieldSet); - exporter("__classPrivateFieldIn", __classPrivateFieldIn); - exporter("__addDisposableResource", __addDisposableResource); - exporter("__disposeResources", __disposeResources); -}); +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global global, define, Symbol, Reflect, Promise, SuppressedError */ +var __extends; +var __assign; +var __rest; +var __decorate; +var __param; +var __esDecorate; +var __runInitializers; +var __propKey; +var __setFunctionName; +var __metadata; +var __awaiter; +var __generator; +var __exportStar; +var __values; +var __read; +var __spread; +var __spreadArrays; +var __spreadArray; +var __await; +var __asyncGenerator; +var __asyncDelegator; +var __asyncValues; +var __makeTemplateObject; +var __importStar; +var __importDefault; +var __classPrivateFieldGet; +var __classPrivateFieldSet; +var __classPrivateFieldIn; +var __createBinding; +var __addDisposableResource; +var __disposeResources; +(function (factory) { + var root = typeof global === "object" ? global : typeof self === "object" ? self : typeof this === "object" ? this : {}; + if (typeof define === "function" && define.amd) { + define("tslib", ["exports"], function (exports) { factory(createExporter(root, createExporter(exports))); }); + } + else if ( true && typeof module.exports === "object") { + factory(createExporter(root, createExporter(module.exports))); + } + else { + factory(createExporter(root)); + } + function createExporter(exports, previous) { + if (exports !== root) { + if (typeof Object.create === "function") { + Object.defineProperty(exports, "__esModule", { value: true }); + } + else { + exports.__esModule = true; + } + } + return function (id, v) { return exports[id] = previous ? previous(id, v) : v; }; + } +}) +(function (exporter) { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + + __extends = function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; + + __assign = Object.assign || function (t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + + __rest = function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; + }; + + __decorate = function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + }; + + __param = function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } + }; + + __esDecorate = function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; + }; + + __runInitializers = function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; + }; + + __propKey = function (x) { + return typeof x === "symbol" ? x : "".concat(x); + }; + + __setFunctionName = function (f, name, prefix) { + if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; + return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); + }; + + __metadata = function (metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); + }; + + __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()); + }); + }; + + __generator = function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } + }; + + __exportStar = function(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); + }; + + __createBinding = Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); + }) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); + + __values = function (o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); + }; + + __read = function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; + }; + + /** @deprecated */ + __spread = function () { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; + }; + + /** @deprecated */ + __spreadArrays = function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; + }; + + __spreadArray = function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); + }; + + __await = function (v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); + }; + + __asyncGenerator = function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } + }; + + __asyncDelegator = function (o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } + }; + + __asyncValues = function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } + }; + + __makeTemplateObject = function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; + }; + + var __setModuleDefault = Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); + }) : function(o, v) { + o["default"] = v; + }; + + __importStar = function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; + + __importDefault = function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; + }; + + __classPrivateFieldGet = function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); + }; + + __classPrivateFieldSet = function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; + }; + + __classPrivateFieldIn = function (state, receiver) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); + }; + + __addDisposableResource = function (env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + env.stack.push({ value: value, dispose: dispose, async: async }); + } + else if (async) { + env.stack.push({ async: true }); + } + return value; + }; + + var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }; + + __disposeResources = function (env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + function next() { + while (env.stack.length) { + var rec = env.stack.pop(); + try { + var result = rec.dispose && rec.dispose.call(rec.value); + if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); + } + catch (e) { + fail(e); + } + } + if (env.hasError) throw env.error; + } + return next(); + }; + + exporter("__extends", __extends); + exporter("__assign", __assign); + exporter("__rest", __rest); + exporter("__decorate", __decorate); + exporter("__param", __param); + exporter("__esDecorate", __esDecorate); + exporter("__runInitializers", __runInitializers); + exporter("__propKey", __propKey); + exporter("__setFunctionName", __setFunctionName); + exporter("__metadata", __metadata); + exporter("__awaiter", __awaiter); + exporter("__generator", __generator); + exporter("__exportStar", __exportStar); + exporter("__createBinding", __createBinding); + exporter("__values", __values); + exporter("__read", __read); + exporter("__spread", __spread); + exporter("__spreadArrays", __spreadArrays); + exporter("__spreadArray", __spreadArray); + exporter("__await", __await); + exporter("__asyncGenerator", __asyncGenerator); + exporter("__asyncDelegator", __asyncDelegator); + exporter("__asyncValues", __asyncValues); + exporter("__makeTemplateObject", __makeTemplateObject); + exporter("__importStar", __importStar); + exporter("__importDefault", __importDefault); + exporter("__classPrivateFieldGet", __classPrivateFieldGet); + exporter("__classPrivateFieldSet", __classPrivateFieldSet); + exporter("__classPrivateFieldIn", __classPrivateFieldIn); + exporter("__addDisposableResource", __addDisposableResource); + exporter("__disposeResources", __disposeResources); +}); /***/ }), @@ -85768,1303 +85887,1303 @@ exports.parseURL = __nccwpck_require__(2158).parseURL; /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; - -const punycode = __nccwpck_require__(85477); -const tr46 = __nccwpck_require__(84256); - -const specialSchemes = { - ftp: 21, - file: null, - gopher: 70, - http: 80, - https: 443, - ws: 80, - wss: 443 -}; - -const failure = Symbol("failure"); - -function countSymbols(str) { - return punycode.ucs2.decode(str).length; -} - -function at(input, idx) { - const c = input[idx]; - return isNaN(c) ? undefined : String.fromCodePoint(c); -} - -function isASCIIDigit(c) { - return c >= 0x30 && c <= 0x39; -} - -function isASCIIAlpha(c) { - return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); -} - -function isASCIIAlphanumeric(c) { - return isASCIIAlpha(c) || isASCIIDigit(c); -} - -function isASCIIHex(c) { - return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); -} - -function isSingleDot(buffer) { - return buffer === "." || buffer.toLowerCase() === "%2e"; -} - -function isDoubleDot(buffer) { - buffer = buffer.toLowerCase(); - return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e"; -} - -function isWindowsDriveLetterCodePoints(cp1, cp2) { - return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124); -} - -function isWindowsDriveLetterString(string) { - return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|"); -} - -function isNormalizedWindowsDriveLetterString(string) { - return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":"; -} - -function containsForbiddenHostCodePoint(string) { - return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1; -} - -function containsForbiddenHostCodePointExcludingPercent(string) { - return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1; -} - -function isSpecialScheme(scheme) { - return specialSchemes[scheme] !== undefined; -} - -function isSpecial(url) { - return isSpecialScheme(url.scheme); -} - -function defaultPort(scheme) { - return specialSchemes[scheme]; -} - -function percentEncode(c) { - let hex = c.toString(16).toUpperCase(); - if (hex.length === 1) { - hex = "0" + hex; - } - - return "%" + hex; -} - -function utf8PercentEncode(c) { - const buf = new Buffer(c); - - let str = ""; - - for (let i = 0; i < buf.length; ++i) { - str += percentEncode(buf[i]); - } - - return str; -} - -function utf8PercentDecode(str) { - const input = new Buffer(str); - const output = []; - for (let i = 0; i < input.length; ++i) { - if (input[i] !== 37) { - output.push(input[i]); - } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) { - output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16)); - i += 2; - } else { - output.push(input[i]); - } - } - return new Buffer(output).toString(); -} - -function isC0ControlPercentEncode(c) { - return c <= 0x1F || c > 0x7E; -} - -const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]); -function isPathPercentEncode(c) { - return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c); -} - -const extraUserinfoPercentEncodeSet = - new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]); -function isUserinfoPercentEncode(c) { - return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c); -} - -function percentEncodeChar(c, encodeSetPredicate) { - const cStr = String.fromCodePoint(c); - - if (encodeSetPredicate(c)) { - return utf8PercentEncode(cStr); - } - - return cStr; -} - -function parseIPv4Number(input) { - let R = 10; - - if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") { - input = input.substring(2); - R = 16; - } else if (input.length >= 2 && input.charAt(0) === "0") { - input = input.substring(1); - R = 8; - } - - if (input === "") { - return 0; - } - - const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/); - if (regex.test(input)) { - return failure; - } - - return parseInt(input, R); -} - -function parseIPv4(input) { - const parts = input.split("."); - if (parts[parts.length - 1] === "") { - if (parts.length > 1) { - parts.pop(); - } - } - - if (parts.length > 4) { - return input; - } - - const numbers = []; - for (const part of parts) { - if (part === "") { - return input; - } - const n = parseIPv4Number(part); - if (n === failure) { - return input; - } - - numbers.push(n); - } - - for (let i = 0; i < numbers.length - 1; ++i) { - if (numbers[i] > 255) { - return failure; - } - } - if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) { - return failure; - } - - let ipv4 = numbers.pop(); - let counter = 0; - - for (const n of numbers) { - ipv4 += n * Math.pow(256, 3 - counter); - ++counter; - } - - return ipv4; -} - -function serializeIPv4(address) { - let output = ""; - let n = address; - - for (let i = 1; i <= 4; ++i) { - output = String(n % 256) + output; - if (i !== 4) { - output = "." + output; - } - n = Math.floor(n / 256); - } - - return output; -} - -function parseIPv6(input) { - const address = [0, 0, 0, 0, 0, 0, 0, 0]; - let pieceIndex = 0; - let compress = null; - let pointer = 0; - - input = punycode.ucs2.decode(input); - - if (input[pointer] === 58) { - if (input[pointer + 1] !== 58) { - return failure; - } - - pointer += 2; - ++pieceIndex; - compress = pieceIndex; - } - - while (pointer < input.length) { - if (pieceIndex === 8) { - return failure; - } - - if (input[pointer] === 58) { - if (compress !== null) { - return failure; - } - ++pointer; - ++pieceIndex; - compress = pieceIndex; - continue; - } - - let value = 0; - let length = 0; - - while (length < 4 && isASCIIHex(input[pointer])) { - value = value * 0x10 + parseInt(at(input, pointer), 16); - ++pointer; - ++length; - } - - if (input[pointer] === 46) { - if (length === 0) { - return failure; - } - - pointer -= length; - - if (pieceIndex > 6) { - return failure; - } - - let numbersSeen = 0; - - while (input[pointer] !== undefined) { - let ipv4Piece = null; - - if (numbersSeen > 0) { - if (input[pointer] === 46 && numbersSeen < 4) { - ++pointer; - } else { - return failure; - } - } - - if (!isASCIIDigit(input[pointer])) { - return failure; - } - - while (isASCIIDigit(input[pointer])) { - const number = parseInt(at(input, pointer)); - if (ipv4Piece === null) { - ipv4Piece = number; - } else if (ipv4Piece === 0) { - return failure; - } else { - ipv4Piece = ipv4Piece * 10 + number; - } - if (ipv4Piece > 255) { - return failure; - } - ++pointer; - } - - address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece; - - ++numbersSeen; - - if (numbersSeen === 2 || numbersSeen === 4) { - ++pieceIndex; - } - } - - if (numbersSeen !== 4) { - return failure; - } - - break; - } else if (input[pointer] === 58) { - ++pointer; - if (input[pointer] === undefined) { - return failure; - } - } else if (input[pointer] !== undefined) { - return failure; - } - - address[pieceIndex] = value; - ++pieceIndex; - } - - if (compress !== null) { - let swaps = pieceIndex - compress; - pieceIndex = 7; - while (pieceIndex !== 0 && swaps > 0) { - const temp = address[compress + swaps - 1]; - address[compress + swaps - 1] = address[pieceIndex]; - address[pieceIndex] = temp; - --pieceIndex; - --swaps; - } - } else if (compress === null && pieceIndex !== 8) { - return failure; - } - - return address; -} - -function serializeIPv6(address) { - let output = ""; - const seqResult = findLongestZeroSequence(address); - const compress = seqResult.idx; - let ignore0 = false; - - for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) { - if (ignore0 && address[pieceIndex] === 0) { - continue; - } else if (ignore0) { - ignore0 = false; - } - - if (compress === pieceIndex) { - const separator = pieceIndex === 0 ? "::" : ":"; - output += separator; - ignore0 = true; - continue; - } - - output += address[pieceIndex].toString(16); - - if (pieceIndex !== 7) { - output += ":"; - } - } - - return output; -} - -function parseHost(input, isSpecialArg) { - if (input[0] === "[") { - if (input[input.length - 1] !== "]") { - return failure; - } - - return parseIPv6(input.substring(1, input.length - 1)); - } - - if (!isSpecialArg) { - return parseOpaqueHost(input); - } - - const domain = utf8PercentDecode(input); - const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false); - if (asciiDomain === null) { - return failure; - } - - if (containsForbiddenHostCodePoint(asciiDomain)) { - return failure; - } - - const ipv4Host = parseIPv4(asciiDomain); - if (typeof ipv4Host === "number" || ipv4Host === failure) { - return ipv4Host; - } - - return asciiDomain; -} - -function parseOpaqueHost(input) { - if (containsForbiddenHostCodePointExcludingPercent(input)) { - return failure; - } - - let output = ""; - const decoded = punycode.ucs2.decode(input); - for (let i = 0; i < decoded.length; ++i) { - output += percentEncodeChar(decoded[i], isC0ControlPercentEncode); - } - return output; -} - -function findLongestZeroSequence(arr) { - let maxIdx = null; - let maxLen = 1; // only find elements > 1 - let currStart = null; - let currLen = 0; - - for (let i = 0; i < arr.length; ++i) { - if (arr[i] !== 0) { - if (currLen > maxLen) { - maxIdx = currStart; - maxLen = currLen; - } - - currStart = null; - currLen = 0; - } else { - if (currStart === null) { - currStart = i; - } - ++currLen; - } - } - - // if trailing zeros - if (currLen > maxLen) { - maxIdx = currStart; - maxLen = currLen; - } - - return { - idx: maxIdx, - len: maxLen - }; -} - -function serializeHost(host) { - if (typeof host === "number") { - return serializeIPv4(host); - } - - // IPv6 serializer - if (host instanceof Array) { - return "[" + serializeIPv6(host) + "]"; - } - - return host; -} - -function trimControlChars(url) { - return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, ""); -} - -function trimTabAndNewline(url) { - return url.replace(/\u0009|\u000A|\u000D/g, ""); -} - -function shortenPath(url) { - const path = url.path; - if (path.length === 0) { - return; - } - if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) { - return; - } - - path.pop(); -} - -function includesCredentials(url) { - return url.username !== "" || url.password !== ""; -} - -function cannotHaveAUsernamePasswordPort(url) { - return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file"; -} - -function isNormalizedWindowsDriveLetter(string) { - return /^[A-Za-z]:$/.test(string); -} - -function URLStateMachine(input, base, encodingOverride, url, stateOverride) { - this.pointer = 0; - this.input = input; - this.base = base || null; - this.encodingOverride = encodingOverride || "utf-8"; - this.stateOverride = stateOverride; - this.url = url; - this.failure = false; - this.parseError = false; - - if (!this.url) { - this.url = { - scheme: "", - username: "", - password: "", - host: null, - port: null, - path: [], - query: null, - fragment: null, - - cannotBeABaseURL: false - }; - - const res = trimControlChars(this.input); - if (res !== this.input) { - this.parseError = true; - } - this.input = res; - } - - const res = trimTabAndNewline(this.input); - if (res !== this.input) { - this.parseError = true; - } - this.input = res; - - this.state = stateOverride || "scheme start"; - - this.buffer = ""; - this.atFlag = false; - this.arrFlag = false; - this.passwordTokenSeenFlag = false; - - this.input = punycode.ucs2.decode(this.input); - - for (; this.pointer <= this.input.length; ++this.pointer) { - const c = this.input[this.pointer]; - const cStr = isNaN(c) ? undefined : String.fromCodePoint(c); - - // exec state machine - const ret = this["parse " + this.state](c, cStr); - if (!ret) { - break; // terminate algorithm - } else if (ret === failure) { - this.failure = true; - break; - } - } -} - -URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) { - if (isASCIIAlpha(c)) { - this.buffer += cStr.toLowerCase(); - this.state = "scheme"; - } else if (!this.stateOverride) { - this.state = "no scheme"; - --this.pointer; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) { - if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) { - this.buffer += cStr.toLowerCase(); - } else if (c === 58) { - if (this.stateOverride) { - if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { - return false; - } - - if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { - return false; - } - - if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") { - return false; - } - - if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) { - return false; - } - } - this.url.scheme = this.buffer; - this.buffer = ""; - if (this.stateOverride) { - return false; - } - if (this.url.scheme === "file") { - if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) { - this.parseError = true; - } - this.state = "file"; - } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) { - this.state = "special relative or authority"; - } else if (isSpecial(this.url)) { - this.state = "special authority slashes"; - } else if (this.input[this.pointer + 1] === 47) { - this.state = "path or authority"; - ++this.pointer; - } else { - this.url.cannotBeABaseURL = true; - this.url.path.push(""); - this.state = "cannot-be-a-base-URL path"; - } - } else if (!this.stateOverride) { - this.buffer = ""; - this.state = "no scheme"; - this.pointer = -1; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) { - if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) { - return failure; - } else if (this.base.cannotBeABaseURL && c === 35) { - this.url.scheme = this.base.scheme; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.url.cannotBeABaseURL = true; - this.state = "fragment"; - } else if (this.base.scheme === "file") { - this.state = "file"; - --this.pointer; - } else { - this.state = "relative"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) { - if (c === 47 && this.input[this.pointer + 1] === 47) { - this.state = "special authority ignore slashes"; - ++this.pointer; - } else { - this.parseError = true; - this.state = "relative"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) { - if (c === 47) { - this.state = "authority"; - } else { - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse relative"] = function parseRelative(c) { - this.url.scheme = this.base.scheme; - if (isNaN(c)) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - } else if (c === 47) { - this.state = "relative slash"; - } else if (c === 63) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.state = "fragment"; - } else if (isSpecial(this.url) && c === 92) { - this.parseError = true; - this.state = "relative slash"; - } else { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.url.path = this.base.path.slice(0, this.base.path.length - 1); - - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) { - if (isSpecial(this.url) && (c === 47 || c === 92)) { - if (c === 92) { - this.parseError = true; - } - this.state = "special authority ignore slashes"; - } else if (c === 47) { - this.state = "authority"; - } else { - this.url.username = this.base.username; - this.url.password = this.base.password; - this.url.host = this.base.host; - this.url.port = this.base.port; - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) { - if (c === 47 && this.input[this.pointer + 1] === 47) { - this.state = "special authority ignore slashes"; - ++this.pointer; - } else { - this.parseError = true; - this.state = "special authority ignore slashes"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) { - if (c !== 47 && c !== 92) { - this.state = "authority"; - --this.pointer; - } else { - this.parseError = true; - } - - return true; -}; - -URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) { - if (c === 64) { - this.parseError = true; - if (this.atFlag) { - this.buffer = "%40" + this.buffer; - } - this.atFlag = true; - - // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars - const len = countSymbols(this.buffer); - for (let pointer = 0; pointer < len; ++pointer) { - const codePoint = this.buffer.codePointAt(pointer); - - if (codePoint === 58 && !this.passwordTokenSeenFlag) { - this.passwordTokenSeenFlag = true; - continue; - } - const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode); - if (this.passwordTokenSeenFlag) { - this.url.password += encodedCodePoints; - } else { - this.url.username += encodedCodePoints; - } - } - this.buffer = ""; - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92)) { - if (this.atFlag && this.buffer === "") { - this.parseError = true; - return failure; - } - this.pointer -= countSymbols(this.buffer) + 1; - this.buffer = ""; - this.state = "host"; - } else { - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse hostname"] = -URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) { - if (this.stateOverride && this.url.scheme === "file") { - --this.pointer; - this.state = "file host"; - } else if (c === 58 && !this.arrFlag) { - if (this.buffer === "") { - this.parseError = true; - return failure; - } - - const host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - - this.url.host = host; - this.buffer = ""; - this.state = "port"; - if (this.stateOverride === "hostname") { - return false; - } - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92)) { - --this.pointer; - if (isSpecial(this.url) && this.buffer === "") { - this.parseError = true; - return failure; - } else if (this.stateOverride && this.buffer === "" && - (includesCredentials(this.url) || this.url.port !== null)) { - this.parseError = true; - return false; - } - - const host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - - this.url.host = host; - this.buffer = ""; - this.state = "path start"; - if (this.stateOverride) { - return false; - } - } else { - if (c === 91) { - this.arrFlag = true; - } else if (c === 93) { - this.arrFlag = false; - } - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) { - if (isASCIIDigit(c)) { - this.buffer += cStr; - } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || - (isSpecial(this.url) && c === 92) || - this.stateOverride) { - if (this.buffer !== "") { - const port = parseInt(this.buffer); - if (port > Math.pow(2, 16) - 1) { - this.parseError = true; - return failure; - } - this.url.port = port === defaultPort(this.url.scheme) ? null : port; - this.buffer = ""; - } - if (this.stateOverride) { - return false; - } - this.state = "path start"; - --this.pointer; - } else { - this.parseError = true; - return failure; - } - - return true; -}; - -const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]); - -URLStateMachine.prototype["parse file"] = function parseFile(c) { - this.url.scheme = "file"; - - if (c === 47 || c === 92) { - if (c === 92) { - this.parseError = true; - } - this.state = "file slash"; - } else if (this.base !== null && this.base.scheme === "file") { - if (isNaN(c)) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - } else if (c === 63) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - this.url.query = this.base.query; - this.url.fragment = ""; - this.state = "fragment"; - } else { - if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points - !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) || - (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points - !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) { - this.url.host = this.base.host; - this.url.path = this.base.path.slice(); - shortenPath(this.url); - } else { - this.parseError = true; - } - - this.state = "path"; - --this.pointer; - } - } else { - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) { - if (c === 47 || c === 92) { - if (c === 92) { - this.parseError = true; - } - this.state = "file host"; - } else { - if (this.base !== null && this.base.scheme === "file") { - if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { - this.url.path.push(this.base.path[0]); - } else { - this.url.host = this.base.host; - } - } - this.state = "path"; - --this.pointer; - } - - return true; -}; - -URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) { - if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) { - --this.pointer; - if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { - this.parseError = true; - this.state = "path"; - } else if (this.buffer === "") { - this.url.host = ""; - if (this.stateOverride) { - return false; - } - this.state = "path start"; - } else { - let host = parseHost(this.buffer, isSpecial(this.url)); - if (host === failure) { - return failure; - } - if (host === "localhost") { - host = ""; - } - this.url.host = host; - - if (this.stateOverride) { - return false; - } - - this.buffer = ""; - this.state = "path start"; - } - } else { - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse path start"] = function parsePathStart(c) { - if (isSpecial(this.url)) { - if (c === 92) { - this.parseError = true; - } - this.state = "path"; - - if (c !== 47 && c !== 92) { - --this.pointer; - } - } else if (!this.stateOverride && c === 63) { - this.url.query = ""; - this.state = "query"; - } else if (!this.stateOverride && c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } else if (c !== undefined) { - this.state = "path"; - if (c !== 47) { - --this.pointer; - } - } - - return true; -}; - -URLStateMachine.prototype["parse path"] = function parsePath(c) { - if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) || - (!this.stateOverride && (c === 63 || c === 35))) { - if (isSpecial(this.url) && c === 92) { - this.parseError = true; - } - - if (isDoubleDot(this.buffer)) { - shortenPath(this.url); - if (c !== 47 && !(isSpecial(this.url) && c === 92)) { - this.url.path.push(""); - } - } else if (isSingleDot(this.buffer) && c !== 47 && - !(isSpecial(this.url) && c === 92)) { - this.url.path.push(""); - } else if (!isSingleDot(this.buffer)) { - if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) { - if (this.url.host !== "" && this.url.host !== null) { - this.parseError = true; - this.url.host = ""; - } - this.buffer = this.buffer[0] + ":"; - } - this.url.path.push(this.buffer); - } - this.buffer = ""; - if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) { - while (this.url.path.length > 1 && this.url.path[0] === "") { - this.parseError = true; - this.url.path.shift(); - } - } - if (c === 63) { - this.url.query = ""; - this.state = "query"; - } - if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } - } else { - // TODO: If c is not a URL code point and not "%", parse error. - - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.buffer += percentEncodeChar(c, isPathPercentEncode); - } - - return true; -}; - -URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) { - if (c === 63) { - this.url.query = ""; - this.state = "query"; - } else if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } else { - // TODO: Add: not a URL code point - if (!isNaN(c) && c !== 37) { - this.parseError = true; - } - - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - if (!isNaN(c)) { - this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode); - } - } - - return true; -}; - -URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) { - if (isNaN(c) || (!this.stateOverride && c === 35)) { - if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") { - this.encodingOverride = "utf-8"; - } - - const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead - for (let i = 0; i < buffer.length; ++i) { - if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 || - buffer[i] === 0x3C || buffer[i] === 0x3E) { - this.url.query += percentEncode(buffer[i]); - } else { - this.url.query += String.fromCodePoint(buffer[i]); - } - } - - this.buffer = ""; - if (c === 35) { - this.url.fragment = ""; - this.state = "fragment"; - } - } else { - // TODO: If c is not a URL code point and not "%", parse error. - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.buffer += cStr; - } - - return true; -}; - -URLStateMachine.prototype["parse fragment"] = function parseFragment(c) { - if (isNaN(c)) { // do nothing - } else if (c === 0x0) { - this.parseError = true; - } else { - // TODO: If c is not a URL code point and not "%", parse error. - if (c === 37 && - (!isASCIIHex(this.input[this.pointer + 1]) || - !isASCIIHex(this.input[this.pointer + 2]))) { - this.parseError = true; - } - - this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode); - } - - return true; -}; - -function serializeURL(url, excludeFragment) { - let output = url.scheme + ":"; - if (url.host !== null) { - output += "//"; - - if (url.username !== "" || url.password !== "") { - output += url.username; - if (url.password !== "") { - output += ":" + url.password; - } - output += "@"; - } - - output += serializeHost(url.host); - - if (url.port !== null) { - output += ":" + url.port; - } - } else if (url.host === null && url.scheme === "file") { - output += "//"; - } - - if (url.cannotBeABaseURL) { - output += url.path[0]; - } else { - for (const string of url.path) { - output += "/" + string; - } - } - - if (url.query !== null) { - output += "?" + url.query; - } - - if (!excludeFragment && url.fragment !== null) { - output += "#" + url.fragment; - } - - return output; -} - -function serializeOrigin(tuple) { - let result = tuple.scheme + "://"; - result += serializeHost(tuple.host); - - if (tuple.port !== null) { - result += ":" + tuple.port; - } - - return result; -} - -module.exports.serializeURL = serializeURL; - -module.exports.serializeURLOrigin = function (url) { - // https://url.spec.whatwg.org/#concept-url-origin - switch (url.scheme) { - case "blob": - try { - return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0])); - } catch (e) { - // serializing an opaque origin returns "null" - return "null"; - } - case "ftp": - case "gopher": - case "http": - case "https": - case "ws": - case "wss": - return serializeOrigin({ - scheme: url.scheme, - host: url.host, - port: url.port - }); - case "file": - // spec says "exercise to the reader", chrome says "file://" - return "file://"; - default: - // serializing an opaque origin returns "null" - return "null"; - } -}; - -module.exports.basicURLParse = function (input, options) { - if (options === undefined) { - options = {}; - } - - const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride); - if (usm.failure) { - return "failure"; - } - - return usm.url; -}; - -module.exports.setTheUsername = function (url, username) { - url.username = ""; - const decoded = punycode.ucs2.decode(username); - for (let i = 0; i < decoded.length; ++i) { - url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode); - } -}; - -module.exports.setThePassword = function (url, password) { - url.password = ""; - const decoded = punycode.ucs2.decode(password); - for (let i = 0; i < decoded.length; ++i) { - url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode); - } -}; - -module.exports.serializeHost = serializeHost; - -module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; - -module.exports.serializeInteger = function (integer) { - return String(integer); -}; - -module.exports.parseURL = function (input, options) { - if (options === undefined) { - options = {}; - } - - // We don't handle blobs, so this just delegates: - return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride }); -}; + +const punycode = __nccwpck_require__(85477); +const tr46 = __nccwpck_require__(84256); + +const specialSchemes = { + ftp: 21, + file: null, + gopher: 70, + http: 80, + https: 443, + ws: 80, + wss: 443 +}; + +const failure = Symbol("failure"); + +function countSymbols(str) { + return punycode.ucs2.decode(str).length; +} + +function at(input, idx) { + const c = input[idx]; + return isNaN(c) ? undefined : String.fromCodePoint(c); +} + +function isASCIIDigit(c) { + return c >= 0x30 && c <= 0x39; +} + +function isASCIIAlpha(c) { + return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); +} + +function isASCIIAlphanumeric(c) { + return isASCIIAlpha(c) || isASCIIDigit(c); +} + +function isASCIIHex(c) { + return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); +} + +function isSingleDot(buffer) { + return buffer === "." || buffer.toLowerCase() === "%2e"; +} + +function isDoubleDot(buffer) { + buffer = buffer.toLowerCase(); + return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e"; +} + +function isWindowsDriveLetterCodePoints(cp1, cp2) { + return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124); +} + +function isWindowsDriveLetterString(string) { + return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|"); +} + +function isNormalizedWindowsDriveLetterString(string) { + return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":"; +} + +function containsForbiddenHostCodePoint(string) { + return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1; +} + +function containsForbiddenHostCodePointExcludingPercent(string) { + return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1; +} + +function isSpecialScheme(scheme) { + return specialSchemes[scheme] !== undefined; +} + +function isSpecial(url) { + return isSpecialScheme(url.scheme); +} + +function defaultPort(scheme) { + return specialSchemes[scheme]; +} + +function percentEncode(c) { + let hex = c.toString(16).toUpperCase(); + if (hex.length === 1) { + hex = "0" + hex; + } + + return "%" + hex; +} + +function utf8PercentEncode(c) { + const buf = new Buffer(c); + + let str = ""; + + for (let i = 0; i < buf.length; ++i) { + str += percentEncode(buf[i]); + } + + return str; +} + +function utf8PercentDecode(str) { + const input = new Buffer(str); + const output = []; + for (let i = 0; i < input.length; ++i) { + if (input[i] !== 37) { + output.push(input[i]); + } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) { + output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16)); + i += 2; + } else { + output.push(input[i]); + } + } + return new Buffer(output).toString(); +} + +function isC0ControlPercentEncode(c) { + return c <= 0x1F || c > 0x7E; +} + +const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]); +function isPathPercentEncode(c) { + return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c); +} + +const extraUserinfoPercentEncodeSet = + new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]); +function isUserinfoPercentEncode(c) { + return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c); +} + +function percentEncodeChar(c, encodeSetPredicate) { + const cStr = String.fromCodePoint(c); + + if (encodeSetPredicate(c)) { + return utf8PercentEncode(cStr); + } + + return cStr; +} + +function parseIPv4Number(input) { + let R = 10; + + if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") { + input = input.substring(2); + R = 16; + } else if (input.length >= 2 && input.charAt(0) === "0") { + input = input.substring(1); + R = 8; + } + + if (input === "") { + return 0; + } + + const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/); + if (regex.test(input)) { + return failure; + } + + return parseInt(input, R); +} + +function parseIPv4(input) { + const parts = input.split("."); + if (parts[parts.length - 1] === "") { + if (parts.length > 1) { + parts.pop(); + } + } + + if (parts.length > 4) { + return input; + } + + const numbers = []; + for (const part of parts) { + if (part === "") { + return input; + } + const n = parseIPv4Number(part); + if (n === failure) { + return input; + } + + numbers.push(n); + } + + for (let i = 0; i < numbers.length - 1; ++i) { + if (numbers[i] > 255) { + return failure; + } + } + if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) { + return failure; + } + + let ipv4 = numbers.pop(); + let counter = 0; + + for (const n of numbers) { + ipv4 += n * Math.pow(256, 3 - counter); + ++counter; + } + + return ipv4; +} + +function serializeIPv4(address) { + let output = ""; + let n = address; + + for (let i = 1; i <= 4; ++i) { + output = String(n % 256) + output; + if (i !== 4) { + output = "." + output; + } + n = Math.floor(n / 256); + } + + return output; +} + +function parseIPv6(input) { + const address = [0, 0, 0, 0, 0, 0, 0, 0]; + let pieceIndex = 0; + let compress = null; + let pointer = 0; + + input = punycode.ucs2.decode(input); + + if (input[pointer] === 58) { + if (input[pointer + 1] !== 58) { + return failure; + } + + pointer += 2; + ++pieceIndex; + compress = pieceIndex; + } + + while (pointer < input.length) { + if (pieceIndex === 8) { + return failure; + } + + if (input[pointer] === 58) { + if (compress !== null) { + return failure; + } + ++pointer; + ++pieceIndex; + compress = pieceIndex; + continue; + } + + let value = 0; + let length = 0; + + while (length < 4 && isASCIIHex(input[pointer])) { + value = value * 0x10 + parseInt(at(input, pointer), 16); + ++pointer; + ++length; + } + + if (input[pointer] === 46) { + if (length === 0) { + return failure; + } + + pointer -= length; + + if (pieceIndex > 6) { + return failure; + } + + let numbersSeen = 0; + + while (input[pointer] !== undefined) { + let ipv4Piece = null; + + if (numbersSeen > 0) { + if (input[pointer] === 46 && numbersSeen < 4) { + ++pointer; + } else { + return failure; + } + } + + if (!isASCIIDigit(input[pointer])) { + return failure; + } + + while (isASCIIDigit(input[pointer])) { + const number = parseInt(at(input, pointer)); + if (ipv4Piece === null) { + ipv4Piece = number; + } else if (ipv4Piece === 0) { + return failure; + } else { + ipv4Piece = ipv4Piece * 10 + number; + } + if (ipv4Piece > 255) { + return failure; + } + ++pointer; + } + + address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece; + + ++numbersSeen; + + if (numbersSeen === 2 || numbersSeen === 4) { + ++pieceIndex; + } + } + + if (numbersSeen !== 4) { + return failure; + } + + break; + } else if (input[pointer] === 58) { + ++pointer; + if (input[pointer] === undefined) { + return failure; + } + } else if (input[pointer] !== undefined) { + return failure; + } + + address[pieceIndex] = value; + ++pieceIndex; + } + + if (compress !== null) { + let swaps = pieceIndex - compress; + pieceIndex = 7; + while (pieceIndex !== 0 && swaps > 0) { + const temp = address[compress + swaps - 1]; + address[compress + swaps - 1] = address[pieceIndex]; + address[pieceIndex] = temp; + --pieceIndex; + --swaps; + } + } else if (compress === null && pieceIndex !== 8) { + return failure; + } + + return address; +} + +function serializeIPv6(address) { + let output = ""; + const seqResult = findLongestZeroSequence(address); + const compress = seqResult.idx; + let ignore0 = false; + + for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) { + if (ignore0 && address[pieceIndex] === 0) { + continue; + } else if (ignore0) { + ignore0 = false; + } + + if (compress === pieceIndex) { + const separator = pieceIndex === 0 ? "::" : ":"; + output += separator; + ignore0 = true; + continue; + } + + output += address[pieceIndex].toString(16); + + if (pieceIndex !== 7) { + output += ":"; + } + } + + return output; +} + +function parseHost(input, isSpecialArg) { + if (input[0] === "[") { + if (input[input.length - 1] !== "]") { + return failure; + } + + return parseIPv6(input.substring(1, input.length - 1)); + } + + if (!isSpecialArg) { + return parseOpaqueHost(input); + } + + const domain = utf8PercentDecode(input); + const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false); + if (asciiDomain === null) { + return failure; + } + + if (containsForbiddenHostCodePoint(asciiDomain)) { + return failure; + } + + const ipv4Host = parseIPv4(asciiDomain); + if (typeof ipv4Host === "number" || ipv4Host === failure) { + return ipv4Host; + } + + return asciiDomain; +} + +function parseOpaqueHost(input) { + if (containsForbiddenHostCodePointExcludingPercent(input)) { + return failure; + } + + let output = ""; + const decoded = punycode.ucs2.decode(input); + for (let i = 0; i < decoded.length; ++i) { + output += percentEncodeChar(decoded[i], isC0ControlPercentEncode); + } + return output; +} + +function findLongestZeroSequence(arr) { + let maxIdx = null; + let maxLen = 1; // only find elements > 1 + let currStart = null; + let currLen = 0; + + for (let i = 0; i < arr.length; ++i) { + if (arr[i] !== 0) { + if (currLen > maxLen) { + maxIdx = currStart; + maxLen = currLen; + } + + currStart = null; + currLen = 0; + } else { + if (currStart === null) { + currStart = i; + } + ++currLen; + } + } + + // if trailing zeros + if (currLen > maxLen) { + maxIdx = currStart; + maxLen = currLen; + } + + return { + idx: maxIdx, + len: maxLen + }; +} + +function serializeHost(host) { + if (typeof host === "number") { + return serializeIPv4(host); + } + + // IPv6 serializer + if (host instanceof Array) { + return "[" + serializeIPv6(host) + "]"; + } + + return host; +} + +function trimControlChars(url) { + return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, ""); +} + +function trimTabAndNewline(url) { + return url.replace(/\u0009|\u000A|\u000D/g, ""); +} + +function shortenPath(url) { + const path = url.path; + if (path.length === 0) { + return; + } + if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) { + return; + } + + path.pop(); +} + +function includesCredentials(url) { + return url.username !== "" || url.password !== ""; +} + +function cannotHaveAUsernamePasswordPort(url) { + return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file"; +} + +function isNormalizedWindowsDriveLetter(string) { + return /^[A-Za-z]:$/.test(string); +} + +function URLStateMachine(input, base, encodingOverride, url, stateOverride) { + this.pointer = 0; + this.input = input; + this.base = base || null; + this.encodingOverride = encodingOverride || "utf-8"; + this.stateOverride = stateOverride; + this.url = url; + this.failure = false; + this.parseError = false; + + if (!this.url) { + this.url = { + scheme: "", + username: "", + password: "", + host: null, + port: null, + path: [], + query: null, + fragment: null, + + cannotBeABaseURL: false + }; + + const res = trimControlChars(this.input); + if (res !== this.input) { + this.parseError = true; + } + this.input = res; + } + + const res = trimTabAndNewline(this.input); + if (res !== this.input) { + this.parseError = true; + } + this.input = res; + + this.state = stateOverride || "scheme start"; + + this.buffer = ""; + this.atFlag = false; + this.arrFlag = false; + this.passwordTokenSeenFlag = false; + + this.input = punycode.ucs2.decode(this.input); + + for (; this.pointer <= this.input.length; ++this.pointer) { + const c = this.input[this.pointer]; + const cStr = isNaN(c) ? undefined : String.fromCodePoint(c); + + // exec state machine + const ret = this["parse " + this.state](c, cStr); + if (!ret) { + break; // terminate algorithm + } else if (ret === failure) { + this.failure = true; + break; + } + } +} + +URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) { + if (isASCIIAlpha(c)) { + this.buffer += cStr.toLowerCase(); + this.state = "scheme"; + } else if (!this.stateOverride) { + this.state = "no scheme"; + --this.pointer; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) { + if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) { + this.buffer += cStr.toLowerCase(); + } else if (c === 58) { + if (this.stateOverride) { + if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) { + return false; + } + + if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) { + return false; + } + + if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") { + return false; + } + + if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) { + return false; + } + } + this.url.scheme = this.buffer; + this.buffer = ""; + if (this.stateOverride) { + return false; + } + if (this.url.scheme === "file") { + if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) { + this.parseError = true; + } + this.state = "file"; + } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) { + this.state = "special relative or authority"; + } else if (isSpecial(this.url)) { + this.state = "special authority slashes"; + } else if (this.input[this.pointer + 1] === 47) { + this.state = "path or authority"; + ++this.pointer; + } else { + this.url.cannotBeABaseURL = true; + this.url.path.push(""); + this.state = "cannot-be-a-base-URL path"; + } + } else if (!this.stateOverride) { + this.buffer = ""; + this.state = "no scheme"; + this.pointer = -1; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) { + if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) { + return failure; + } else if (this.base.cannotBeABaseURL && c === 35) { + this.url.scheme = this.base.scheme; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.url.cannotBeABaseURL = true; + this.state = "fragment"; + } else if (this.base.scheme === "file") { + this.state = "file"; + --this.pointer; + } else { + this.state = "relative"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) { + if (c === 47 && this.input[this.pointer + 1] === 47) { + this.state = "special authority ignore slashes"; + ++this.pointer; + } else { + this.parseError = true; + this.state = "relative"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) { + if (c === 47) { + this.state = "authority"; + } else { + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse relative"] = function parseRelative(c) { + this.url.scheme = this.base.scheme; + if (isNaN(c)) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + } else if (c === 47) { + this.state = "relative slash"; + } else if (c === 63) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.state = "fragment"; + } else if (isSpecial(this.url) && c === 92) { + this.parseError = true; + this.state = "relative slash"; + } else { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.url.path = this.base.path.slice(0, this.base.path.length - 1); + + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) { + if (isSpecial(this.url) && (c === 47 || c === 92)) { + if (c === 92) { + this.parseError = true; + } + this.state = "special authority ignore slashes"; + } else if (c === 47) { + this.state = "authority"; + } else { + this.url.username = this.base.username; + this.url.password = this.base.password; + this.url.host = this.base.host; + this.url.port = this.base.port; + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) { + if (c === 47 && this.input[this.pointer + 1] === 47) { + this.state = "special authority ignore slashes"; + ++this.pointer; + } else { + this.parseError = true; + this.state = "special authority ignore slashes"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) { + if (c !== 47 && c !== 92) { + this.state = "authority"; + --this.pointer; + } else { + this.parseError = true; + } + + return true; +}; + +URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) { + if (c === 64) { + this.parseError = true; + if (this.atFlag) { + this.buffer = "%40" + this.buffer; + } + this.atFlag = true; + + // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars + const len = countSymbols(this.buffer); + for (let pointer = 0; pointer < len; ++pointer) { + const codePoint = this.buffer.codePointAt(pointer); + + if (codePoint === 58 && !this.passwordTokenSeenFlag) { + this.passwordTokenSeenFlag = true; + continue; + } + const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode); + if (this.passwordTokenSeenFlag) { + this.url.password += encodedCodePoints; + } else { + this.url.username += encodedCodePoints; + } + } + this.buffer = ""; + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92)) { + if (this.atFlag && this.buffer === "") { + this.parseError = true; + return failure; + } + this.pointer -= countSymbols(this.buffer) + 1; + this.buffer = ""; + this.state = "host"; + } else { + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse hostname"] = +URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) { + if (this.stateOverride && this.url.scheme === "file") { + --this.pointer; + this.state = "file host"; + } else if (c === 58 && !this.arrFlag) { + if (this.buffer === "") { + this.parseError = true; + return failure; + } + + const host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + + this.url.host = host; + this.buffer = ""; + this.state = "port"; + if (this.stateOverride === "hostname") { + return false; + } + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92)) { + --this.pointer; + if (isSpecial(this.url) && this.buffer === "") { + this.parseError = true; + return failure; + } else if (this.stateOverride && this.buffer === "" && + (includesCredentials(this.url) || this.url.port !== null)) { + this.parseError = true; + return false; + } + + const host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + + this.url.host = host; + this.buffer = ""; + this.state = "path start"; + if (this.stateOverride) { + return false; + } + } else { + if (c === 91) { + this.arrFlag = true; + } else if (c === 93) { + this.arrFlag = false; + } + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) { + if (isASCIIDigit(c)) { + this.buffer += cStr; + } else if (isNaN(c) || c === 47 || c === 63 || c === 35 || + (isSpecial(this.url) && c === 92) || + this.stateOverride) { + if (this.buffer !== "") { + const port = parseInt(this.buffer); + if (port > Math.pow(2, 16) - 1) { + this.parseError = true; + return failure; + } + this.url.port = port === defaultPort(this.url.scheme) ? null : port; + this.buffer = ""; + } + if (this.stateOverride) { + return false; + } + this.state = "path start"; + --this.pointer; + } else { + this.parseError = true; + return failure; + } + + return true; +}; + +const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]); + +URLStateMachine.prototype["parse file"] = function parseFile(c) { + this.url.scheme = "file"; + + if (c === 47 || c === 92) { + if (c === 92) { + this.parseError = true; + } + this.state = "file slash"; + } else if (this.base !== null && this.base.scheme === "file") { + if (isNaN(c)) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + } else if (c === 63) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + this.url.query = this.base.query; + this.url.fragment = ""; + this.state = "fragment"; + } else { + if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points + !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) || + (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points + !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) { + this.url.host = this.base.host; + this.url.path = this.base.path.slice(); + shortenPath(this.url); + } else { + this.parseError = true; + } + + this.state = "path"; + --this.pointer; + } + } else { + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) { + if (c === 47 || c === 92) { + if (c === 92) { + this.parseError = true; + } + this.state = "file host"; + } else { + if (this.base !== null && this.base.scheme === "file") { + if (isNormalizedWindowsDriveLetterString(this.base.path[0])) { + this.url.path.push(this.base.path[0]); + } else { + this.url.host = this.base.host; + } + } + this.state = "path"; + --this.pointer; + } + + return true; +}; + +URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) { + if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) { + --this.pointer; + if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) { + this.parseError = true; + this.state = "path"; + } else if (this.buffer === "") { + this.url.host = ""; + if (this.stateOverride) { + return false; + } + this.state = "path start"; + } else { + let host = parseHost(this.buffer, isSpecial(this.url)); + if (host === failure) { + return failure; + } + if (host === "localhost") { + host = ""; + } + this.url.host = host; + + if (this.stateOverride) { + return false; + } + + this.buffer = ""; + this.state = "path start"; + } + } else { + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse path start"] = function parsePathStart(c) { + if (isSpecial(this.url)) { + if (c === 92) { + this.parseError = true; + } + this.state = "path"; + + if (c !== 47 && c !== 92) { + --this.pointer; + } + } else if (!this.stateOverride && c === 63) { + this.url.query = ""; + this.state = "query"; + } else if (!this.stateOverride && c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } else if (c !== undefined) { + this.state = "path"; + if (c !== 47) { + --this.pointer; + } + } + + return true; +}; + +URLStateMachine.prototype["parse path"] = function parsePath(c) { + if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) || + (!this.stateOverride && (c === 63 || c === 35))) { + if (isSpecial(this.url) && c === 92) { + this.parseError = true; + } + + if (isDoubleDot(this.buffer)) { + shortenPath(this.url); + if (c !== 47 && !(isSpecial(this.url) && c === 92)) { + this.url.path.push(""); + } + } else if (isSingleDot(this.buffer) && c !== 47 && + !(isSpecial(this.url) && c === 92)) { + this.url.path.push(""); + } else if (!isSingleDot(this.buffer)) { + if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) { + if (this.url.host !== "" && this.url.host !== null) { + this.parseError = true; + this.url.host = ""; + } + this.buffer = this.buffer[0] + ":"; + } + this.url.path.push(this.buffer); + } + this.buffer = ""; + if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) { + while (this.url.path.length > 1 && this.url.path[0] === "") { + this.parseError = true; + this.url.path.shift(); + } + } + if (c === 63) { + this.url.query = ""; + this.state = "query"; + } + if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } + } else { + // TODO: If c is not a URL code point and not "%", parse error. + + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.buffer += percentEncodeChar(c, isPathPercentEncode); + } + + return true; +}; + +URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) { + if (c === 63) { + this.url.query = ""; + this.state = "query"; + } else if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } else { + // TODO: Add: not a URL code point + if (!isNaN(c) && c !== 37) { + this.parseError = true; + } + + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + if (!isNaN(c)) { + this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode); + } + } + + return true; +}; + +URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) { + if (isNaN(c) || (!this.stateOverride && c === 35)) { + if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") { + this.encodingOverride = "utf-8"; + } + + const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead + for (let i = 0; i < buffer.length; ++i) { + if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 || + buffer[i] === 0x3C || buffer[i] === 0x3E) { + this.url.query += percentEncode(buffer[i]); + } else { + this.url.query += String.fromCodePoint(buffer[i]); + } + } + + this.buffer = ""; + if (c === 35) { + this.url.fragment = ""; + this.state = "fragment"; + } + } else { + // TODO: If c is not a URL code point and not "%", parse error. + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.buffer += cStr; + } + + return true; +}; + +URLStateMachine.prototype["parse fragment"] = function parseFragment(c) { + if (isNaN(c)) { // do nothing + } else if (c === 0x0) { + this.parseError = true; + } else { + // TODO: If c is not a URL code point and not "%", parse error. + if (c === 37 && + (!isASCIIHex(this.input[this.pointer + 1]) || + !isASCIIHex(this.input[this.pointer + 2]))) { + this.parseError = true; + } + + this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode); + } + + return true; +}; + +function serializeURL(url, excludeFragment) { + let output = url.scheme + ":"; + if (url.host !== null) { + output += "//"; + + if (url.username !== "" || url.password !== "") { + output += url.username; + if (url.password !== "") { + output += ":" + url.password; + } + output += "@"; + } + + output += serializeHost(url.host); + + if (url.port !== null) { + output += ":" + url.port; + } + } else if (url.host === null && url.scheme === "file") { + output += "//"; + } + + if (url.cannotBeABaseURL) { + output += url.path[0]; + } else { + for (const string of url.path) { + output += "/" + string; + } + } + + if (url.query !== null) { + output += "?" + url.query; + } + + if (!excludeFragment && url.fragment !== null) { + output += "#" + url.fragment; + } + + return output; +} + +function serializeOrigin(tuple) { + let result = tuple.scheme + "://"; + result += serializeHost(tuple.host); + + if (tuple.port !== null) { + result += ":" + tuple.port; + } + + return result; +} + +module.exports.serializeURL = serializeURL; + +module.exports.serializeURLOrigin = function (url) { + // https://url.spec.whatwg.org/#concept-url-origin + switch (url.scheme) { + case "blob": + try { + return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0])); + } catch (e) { + // serializing an opaque origin returns "null" + return "null"; + } + case "ftp": + case "gopher": + case "http": + case "https": + case "ws": + case "wss": + return serializeOrigin({ + scheme: url.scheme, + host: url.host, + port: url.port + }); + case "file": + // spec says "exercise to the reader", chrome says "file://" + return "file://"; + default: + // serializing an opaque origin returns "null" + return "null"; + } +}; + +module.exports.basicURLParse = function (input, options) { + if (options === undefined) { + options = {}; + } + + const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride); + if (usm.failure) { + return "failure"; + } + + return usm.url; +}; + +module.exports.setTheUsername = function (url, username) { + url.username = ""; + const decoded = punycode.ucs2.decode(username); + for (let i = 0; i < decoded.length; ++i) { + url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode); + } +}; + +module.exports.setThePassword = function (url, password) { + url.password = ""; + const decoded = punycode.ucs2.decode(password); + for (let i = 0; i < decoded.length; ++i) { + url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode); + } +}; + +module.exports.serializeHost = serializeHost; + +module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; + +module.exports.serializeInteger = function (integer) { + return String(integer); +}; + +module.exports.parseURL = function (input, options) { + if (options === undefined) { + options = {}; + } + + // We don't handle blobs, so this just delegates: + return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride }); +}; /***/ }), @@ -104507,6 +104626,378 @@ function cleanEscapedString(input) { } +/***/ }), + +/***/ 5975: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +exports.parseISO = parseISO; +var _index = __nccwpck_require__(64278); + +var _index2 = __nccwpck_require__(30926); +var _index3 = __nccwpck_require__(46439); + +/** + * The {@link parseISO} function options. + */ + +/** + * @name parseISO + * @category Common Helpers + * @summary Parse ISO string + * + * @description + * Parse the given string in ISO 8601 format and return an instance of Date. + * + * Function accepts complete ISO 8601 formats as well as partial implementations. + * ISO 8601: http://en.wikipedia.org/wiki/ISO_8601 + * + * If the argument isn't a string, the function cannot parse the string or + * the values are invalid, it returns Invalid Date. + * + * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc). + * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments. + * + * @param argument - The value to convert + * @param options - An object with options + * + * @returns The parsed date in the local time zone + * + * @example + * // Convert string '2014-02-11T11:30:30' to date: + * const result = parseISO('2014-02-11T11:30:30') + * //=> Tue Feb 11 2014 11:30:30 + * + * @example + * // Convert string '+02014101' to date, + * // if the additional number of digits in the extended year format is 1: + * const result = parseISO('+02014101', { additionalDigits: 1 }) + * //=> Fri Apr 11 2014 00:00:00 + */ +function parseISO(argument, options) { + const invalidDate = () => (0, _index2.constructFrom)(options?.in, NaN); + + const additionalDigits = options?.additionalDigits ?? 2; + const dateStrings = splitDateString(argument); + + let date; + if (dateStrings.date) { + const parseYearResult = parseYear(dateStrings.date, additionalDigits); + date = parseDate(parseYearResult.restDateString, parseYearResult.year); + } + + if (!date || isNaN(+date)) return invalidDate(); + + const timestamp = +date; + let time = 0; + let offset; + + if (dateStrings.time) { + time = parseTime(dateStrings.time); + if (isNaN(time)) return invalidDate(); + } + + if (dateStrings.timezone) { + offset = parseTimezone(dateStrings.timezone); + if (isNaN(offset)) return invalidDate(); + } else { + const tmpDate = new Date(timestamp + time); + const result = (0, _index3.toDate)(0, options?.in); + result.setFullYear( + tmpDate.getUTCFullYear(), + tmpDate.getUTCMonth(), + tmpDate.getUTCDate(), + ); + result.setHours( + tmpDate.getUTCHours(), + tmpDate.getUTCMinutes(), + tmpDate.getUTCSeconds(), + tmpDate.getUTCMilliseconds(), + ); + return result; + } + + return (0, _index3.toDate)(timestamp + time + offset, options?.in); +} + +const patterns = { + dateTimeDelimiter: /[T ]/, + timeZoneDelimiter: /[Z ]/i, + timezone: /([Z+-].*)$/, +}; + +const dateRegex = + /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/; +const timeRegex = + /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/; +const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/; + +function splitDateString(dateString) { + const dateStrings = {}; + const array = dateString.split(patterns.dateTimeDelimiter); + let timeString; + + // The regex match should only return at maximum two array elements. + // [date], [time], or [date, time]. + if (array.length > 2) { + return dateStrings; + } + + if (/:/.test(array[0])) { + timeString = array[0]; + } else { + dateStrings.date = array[0]; + timeString = array[1]; + if (patterns.timeZoneDelimiter.test(dateStrings.date)) { + dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0]; + timeString = dateString.substr( + dateStrings.date.length, + dateString.length, + ); + } + } + + if (timeString) { + const token = patterns.timezone.exec(timeString); + if (token) { + dateStrings.time = timeString.replace(token[1], ""); + dateStrings.timezone = token[1]; + } else { + dateStrings.time = timeString; + } + } + + return dateStrings; +} + +function parseYear(dateString, additionalDigits) { + const regex = new RegExp( + "^(?:(\\d{4}|[+-]\\d{" + + (4 + additionalDigits) + + "})|(\\d{2}|[+-]\\d{" + + (2 + additionalDigits) + + "})$)", + ); + + const captures = dateString.match(regex); + // Invalid ISO-formatted year + if (!captures) return { year: NaN, restDateString: "" }; + + const year = captures[1] ? parseInt(captures[1]) : null; + const century = captures[2] ? parseInt(captures[2]) : null; + + // either year or century is null, not both + return { + year: century === null ? year : century * 100, + restDateString: dateString.slice((captures[1] || captures[2]).length), + }; +} + +function parseDate(dateString, year) { + // Invalid ISO-formatted year + if (year === null) return new Date(NaN); + + const captures = dateString.match(dateRegex); + // Invalid ISO-formatted string + if (!captures) return new Date(NaN); + + const isWeekDate = !!captures[4]; + const dayOfYear = parseDateUnit(captures[1]); + const month = parseDateUnit(captures[2]) - 1; + const day = parseDateUnit(captures[3]); + const week = parseDateUnit(captures[4]); + const dayOfWeek = parseDateUnit(captures[5]) - 1; + + if (isWeekDate) { + if (!validateWeekDate(year, week, dayOfWeek)) { + return new Date(NaN); + } + return dayOfISOWeekYear(year, week, dayOfWeek); + } else { + const date = new Date(0); + if ( + !validateDate(year, month, day) || + !validateDayOfYearDate(year, dayOfYear) + ) { + return new Date(NaN); + } + date.setUTCFullYear(year, month, Math.max(dayOfYear, day)); + return date; + } +} + +function parseDateUnit(value) { + return value ? parseInt(value) : 1; +} + +function parseTime(timeString) { + const captures = timeString.match(timeRegex); + if (!captures) return NaN; // Invalid ISO-formatted time + + const hours = parseTimeUnit(captures[1]); + const minutes = parseTimeUnit(captures[2]); + const seconds = parseTimeUnit(captures[3]); + + if (!validateTime(hours, minutes, seconds)) { + return NaN; + } + + return ( + hours * _index.millisecondsInHour + + minutes * _index.millisecondsInMinute + + seconds * 1000 + ); +} + +function parseTimeUnit(value) { + return (value && parseFloat(value.replace(",", "."))) || 0; +} + +function parseTimezone(timezoneString) { + if (timezoneString === "Z") return 0; + + const captures = timezoneString.match(timezoneRegex); + if (!captures) return 0; + + const sign = captures[1] === "+" ? -1 : 1; + const hours = parseInt(captures[2]); + const minutes = (captures[3] && parseInt(captures[3])) || 0; + + if (!validateTimezone(hours, minutes)) { + return NaN; + } + + return ( + sign * + (hours * _index.millisecondsInHour + minutes * _index.millisecondsInMinute) + ); +} + +function dayOfISOWeekYear(isoWeekYear, week, day) { + const date = new Date(0); + date.setUTCFullYear(isoWeekYear, 0, 4); + const fourthOfJanuaryDay = date.getUTCDay() || 7; + const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay; + date.setUTCDate(date.getUTCDate() + diff); + return date; +} + +// Validation functions + +// February is null to handle the leap year (using ||) +const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + +function isLeapYearIndex(year) { + return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0); +} + +function validateDate(year, month, date) { + return ( + month >= 0 && + month <= 11 && + date >= 1 && + date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28)) + ); +} + +function validateDayOfYearDate(year, dayOfYear) { + return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365); +} + +function validateWeekDate(_year, week, day) { + return week >= 1 && week <= 53 && day >= 0 && day <= 6; +} + +function validateTime(hours, minutes, seconds) { + if (hours === 24) { + return minutes === 0 && seconds === 0; + } + + return ( + seconds >= 0 && + seconds < 60 && + minutes >= 0 && + minutes < 60 && + hours >= 0 && + hours < 25 + ); +} + +function validateTimezone(_hours, minutes) { + return minutes >= 0 && minutes <= 59; +} + + +/***/ }), + +/***/ 25531: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +exports.parseJSON = parseJSON; +var _index = __nccwpck_require__(46439); + +/** + * The {@link parseJSON} function options. + */ + +/** + * Converts a complete ISO date string in UTC time, the typical format for transmitting + * a date in JSON, to a JavaScript `Date` instance. + * + * This is a minimal implementation for converting dates retrieved from a JSON API to + * a `Date` instance which can be used with other functions in the `date-fns` library. + * The following formats are supported: + * + * - `2000-03-15T05:20:10.123Z`: The output of `.toISOString()` and `JSON.stringify(new Date())` + * - `2000-03-15T05:20:10Z`: Without milliseconds + * - `2000-03-15T05:20:10+00:00`: With a zero offset, the default JSON encoded format in some other languages + * - `2000-03-15T05:20:10+05:45`: With a positive or negative offset, the default JSON encoded format in some other languages + * - `2000-03-15T05:20:10+0000`: With a zero offset without a colon + * - `2000-03-15T05:20:10`: Without a trailing 'Z' symbol + * - `2000-03-15T05:20:10.1234567`: Up to 7 digits in milliseconds field. Only first 3 are taken into account since JS does not allow fractional milliseconds + * - `2000-03-15 05:20:10`: With a space instead of a 'T' separator for APIs returning a SQL date without reformatting + * + * For convenience and ease of use these other input types are also supported + * via [toDate](https://date-fns.org/docs/toDate): + * + * - A `Date` instance will be cloned + * - A `number` will be treated as a timestamp + * + * Any other input type or invalid date strings will return an `Invalid Date`. + * + * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments. + * + * @param dateStr - A fully formed ISO8601 date string to convert + * @param options - An object with options + * + * @returns The parsed date in the local time zone + */ +function parseJSON(dateStr, options) { + const parts = dateStr.match( + /(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?/, + ); + + if (!parts) return (0, _index.toDate)(NaN, options?.in); + + return (0, _index.toDate)( + Date.UTC( + +parts[1], + +parts[2] - 1, + +parts[3], + +parts[4] - (+parts[9] || 0) * (parts[8] == "-" ? -1 : 1), + +parts[5] - (+parts[10] || 0) * (parts[8] == "-" ? -1 : 1), + +parts[6], + +((parts[7] || "0") + "00").substring(0, 3), + ), + options?.in, + ); +} + + /***/ }), /***/ 24759: @@ -107039,378 +107530,6 @@ function isLeapYearIndex(year) { } -/***/ }), - -/***/ 5975: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -exports.parseISO = parseISO; -var _index = __nccwpck_require__(64278); - -var _index2 = __nccwpck_require__(30926); -var _index3 = __nccwpck_require__(46439); - -/** - * The {@link parseISO} function options. - */ - -/** - * @name parseISO - * @category Common Helpers - * @summary Parse ISO string - * - * @description - * Parse the given string in ISO 8601 format and return an instance of Date. - * - * Function accepts complete ISO 8601 formats as well as partial implementations. - * ISO 8601: http://en.wikipedia.org/wiki/ISO_8601 - * - * If the argument isn't a string, the function cannot parse the string or - * the values are invalid, it returns Invalid Date. - * - * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc). - * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments. - * - * @param argument - The value to convert - * @param options - An object with options - * - * @returns The parsed date in the local time zone - * - * @example - * // Convert string '2014-02-11T11:30:30' to date: - * const result = parseISO('2014-02-11T11:30:30') - * //=> Tue Feb 11 2014 11:30:30 - * - * @example - * // Convert string '+02014101' to date, - * // if the additional number of digits in the extended year format is 1: - * const result = parseISO('+02014101', { additionalDigits: 1 }) - * //=> Fri Apr 11 2014 00:00:00 - */ -function parseISO(argument, options) { - const invalidDate = () => (0, _index2.constructFrom)(options?.in, NaN); - - const additionalDigits = options?.additionalDigits ?? 2; - const dateStrings = splitDateString(argument); - - let date; - if (dateStrings.date) { - const parseYearResult = parseYear(dateStrings.date, additionalDigits); - date = parseDate(parseYearResult.restDateString, parseYearResult.year); - } - - if (!date || isNaN(+date)) return invalidDate(); - - const timestamp = +date; - let time = 0; - let offset; - - if (dateStrings.time) { - time = parseTime(dateStrings.time); - if (isNaN(time)) return invalidDate(); - } - - if (dateStrings.timezone) { - offset = parseTimezone(dateStrings.timezone); - if (isNaN(offset)) return invalidDate(); - } else { - const tmpDate = new Date(timestamp + time); - const result = (0, _index3.toDate)(0, options?.in); - result.setFullYear( - tmpDate.getUTCFullYear(), - tmpDate.getUTCMonth(), - tmpDate.getUTCDate(), - ); - result.setHours( - tmpDate.getUTCHours(), - tmpDate.getUTCMinutes(), - tmpDate.getUTCSeconds(), - tmpDate.getUTCMilliseconds(), - ); - return result; - } - - return (0, _index3.toDate)(timestamp + time + offset, options?.in); -} - -const patterns = { - dateTimeDelimiter: /[T ]/, - timeZoneDelimiter: /[Z ]/i, - timezone: /([Z+-].*)$/, -}; - -const dateRegex = - /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/; -const timeRegex = - /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/; -const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/; - -function splitDateString(dateString) { - const dateStrings = {}; - const array = dateString.split(patterns.dateTimeDelimiter); - let timeString; - - // The regex match should only return at maximum two array elements. - // [date], [time], or [date, time]. - if (array.length > 2) { - return dateStrings; - } - - if (/:/.test(array[0])) { - timeString = array[0]; - } else { - dateStrings.date = array[0]; - timeString = array[1]; - if (patterns.timeZoneDelimiter.test(dateStrings.date)) { - dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0]; - timeString = dateString.substr( - dateStrings.date.length, - dateString.length, - ); - } - } - - if (timeString) { - const token = patterns.timezone.exec(timeString); - if (token) { - dateStrings.time = timeString.replace(token[1], ""); - dateStrings.timezone = token[1]; - } else { - dateStrings.time = timeString; - } - } - - return dateStrings; -} - -function parseYear(dateString, additionalDigits) { - const regex = new RegExp( - "^(?:(\\d{4}|[+-]\\d{" + - (4 + additionalDigits) + - "})|(\\d{2}|[+-]\\d{" + - (2 + additionalDigits) + - "})$)", - ); - - const captures = dateString.match(regex); - // Invalid ISO-formatted year - if (!captures) return { year: NaN, restDateString: "" }; - - const year = captures[1] ? parseInt(captures[1]) : null; - const century = captures[2] ? parseInt(captures[2]) : null; - - // either year or century is null, not both - return { - year: century === null ? year : century * 100, - restDateString: dateString.slice((captures[1] || captures[2]).length), - }; -} - -function parseDate(dateString, year) { - // Invalid ISO-formatted year - if (year === null) return new Date(NaN); - - const captures = dateString.match(dateRegex); - // Invalid ISO-formatted string - if (!captures) return new Date(NaN); - - const isWeekDate = !!captures[4]; - const dayOfYear = parseDateUnit(captures[1]); - const month = parseDateUnit(captures[2]) - 1; - const day = parseDateUnit(captures[3]); - const week = parseDateUnit(captures[4]); - const dayOfWeek = parseDateUnit(captures[5]) - 1; - - if (isWeekDate) { - if (!validateWeekDate(year, week, dayOfWeek)) { - return new Date(NaN); - } - return dayOfISOWeekYear(year, week, dayOfWeek); - } else { - const date = new Date(0); - if ( - !validateDate(year, month, day) || - !validateDayOfYearDate(year, dayOfYear) - ) { - return new Date(NaN); - } - date.setUTCFullYear(year, month, Math.max(dayOfYear, day)); - return date; - } -} - -function parseDateUnit(value) { - return value ? parseInt(value) : 1; -} - -function parseTime(timeString) { - const captures = timeString.match(timeRegex); - if (!captures) return NaN; // Invalid ISO-formatted time - - const hours = parseTimeUnit(captures[1]); - const minutes = parseTimeUnit(captures[2]); - const seconds = parseTimeUnit(captures[3]); - - if (!validateTime(hours, minutes, seconds)) { - return NaN; - } - - return ( - hours * _index.millisecondsInHour + - minutes * _index.millisecondsInMinute + - seconds * 1000 - ); -} - -function parseTimeUnit(value) { - return (value && parseFloat(value.replace(",", "."))) || 0; -} - -function parseTimezone(timezoneString) { - if (timezoneString === "Z") return 0; - - const captures = timezoneString.match(timezoneRegex); - if (!captures) return 0; - - const sign = captures[1] === "+" ? -1 : 1; - const hours = parseInt(captures[2]); - const minutes = (captures[3] && parseInt(captures[3])) || 0; - - if (!validateTimezone(hours, minutes)) { - return NaN; - } - - return ( - sign * - (hours * _index.millisecondsInHour + minutes * _index.millisecondsInMinute) - ); -} - -function dayOfISOWeekYear(isoWeekYear, week, day) { - const date = new Date(0); - date.setUTCFullYear(isoWeekYear, 0, 4); - const fourthOfJanuaryDay = date.getUTCDay() || 7; - const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay; - date.setUTCDate(date.getUTCDate() + diff); - return date; -} - -// Validation functions - -// February is null to handle the leap year (using ||) -const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - -function isLeapYearIndex(year) { - return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0); -} - -function validateDate(year, month, date) { - return ( - month >= 0 && - month <= 11 && - date >= 1 && - date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28)) - ); -} - -function validateDayOfYearDate(year, dayOfYear) { - return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365); -} - -function validateWeekDate(_year, week, day) { - return week >= 1 && week <= 53 && day >= 0 && day <= 6; -} - -function validateTime(hours, minutes, seconds) { - if (hours === 24) { - return minutes === 0 && seconds === 0; - } - - return ( - seconds >= 0 && - seconds < 60 && - minutes >= 0 && - minutes < 60 && - hours >= 0 && - hours < 25 - ); -} - -function validateTimezone(_hours, minutes) { - return minutes >= 0 && minutes <= 59; -} - - -/***/ }), - -/***/ 25531: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -exports.parseJSON = parseJSON; -var _index = __nccwpck_require__(46439); - -/** - * The {@link parseJSON} function options. - */ - -/** - * Converts a complete ISO date string in UTC time, the typical format for transmitting - * a date in JSON, to a JavaScript `Date` instance. - * - * This is a minimal implementation for converting dates retrieved from a JSON API to - * a `Date` instance which can be used with other functions in the `date-fns` library. - * The following formats are supported: - * - * - `2000-03-15T05:20:10.123Z`: The output of `.toISOString()` and `JSON.stringify(new Date())` - * - `2000-03-15T05:20:10Z`: Without milliseconds - * - `2000-03-15T05:20:10+00:00`: With a zero offset, the default JSON encoded format in some other languages - * - `2000-03-15T05:20:10+05:45`: With a positive or negative offset, the default JSON encoded format in some other languages - * - `2000-03-15T05:20:10+0000`: With a zero offset without a colon - * - `2000-03-15T05:20:10`: Without a trailing 'Z' symbol - * - `2000-03-15T05:20:10.1234567`: Up to 7 digits in milliseconds field. Only first 3 are taken into account since JS does not allow fractional milliseconds - * - `2000-03-15 05:20:10`: With a space instead of a 'T' separator for APIs returning a SQL date without reformatting - * - * For convenience and ease of use these other input types are also supported - * via [toDate](https://date-fns.org/docs/toDate): - * - * - A `Date` instance will be cloned - * - A `number` will be treated as a timestamp - * - * Any other input type or invalid date strings will return an `Invalid Date`. - * - * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments. - * - * @param dateStr - A fully formed ISO8601 date string to convert - * @param options - An object with options - * - * @returns The parsed date in the local time zone - */ -function parseJSON(dateStr, options) { - const parts = dateStr.match( - /(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?/, - ); - - if (!parts) return (0, _index.toDate)(NaN, options?.in); - - return (0, _index.toDate)( - Date.UTC( - +parts[1], - +parts[2] - 1, - +parts[3], - +parts[4] - (+parts[9] || 0) * (parts[8] == "-" ? -1 : 1), - +parts[5] - (+parts[10] || 0) * (parts[8] == "-" ? -1 : 1), - +parts[6], - +((parts[7] || "0") + "00").substring(0, 3), - ), - options?.in, - ); -} - - /***/ }), /***/ 61930: diff --git a/src/action/decorate/action.ts b/src/action/decorate/action.ts index d39be771..8a09f8eb 100644 --- a/src/action/decorate/action.ts +++ b/src/action/decorate/action.ts @@ -12,9 +12,9 @@ import { Analysis, AnalysisResult } from '../../helper/interfaces'; export async function decorateAction(analysisResult: AnalysisResult | undefined, analysis: Analysis): Promise { let summaryBody; if (analysisResult) { - summaryBody = createSummaryBody(analysisResult); + summaryBody = await createSummaryBody(analysisResult); } else { - summaryBody = createErrorSummaryBody(analysis.errorList, analysis.warningList); + summaryBody = await createErrorSummaryBody(analysis.errorList, analysis.warningList); } if (githubConfig.event.isPullRequest) { diff --git a/src/action/decorate/markdown.ts b/src/action/decorate/markdown.ts index ac08af29..68c8a9e8 100644 --- a/src/action/decorate/markdown.ts +++ b/src/action/decorate/markdown.ts @@ -30,3 +30,19 @@ export function generateStatusMarkdown(status: Status, hasSuffix = false): strin export function generateExpandableAreaMarkdown(header: string, body: string): string { return `
${header}${EOL}${body}
${EOL}${EOL}`; } + +/** + * Generates italic text for markdown. + * @param text The text to make italic. + */ +export function generateItalic(text: string, title?: string): string { + return `${text}`; +} + +/** + * Generates a hidden comment for markdown. + * @param comment The text of the comment. + */ +export function generateComment(comment: string): string { + return ``; +} diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts index 1d62f523..b99d69b4 100644 --- a/src/action/decorate/summary.ts +++ b/src/action/decorate/summary.ts @@ -3,7 +3,6 @@ import { format } from 'date-fns'; import { range } from 'underscore'; import { summary } from '@actions/core'; import { SummaryTableRow } from '@actions/core/lib/summary'; - import { ChangedFile } from '../../github/interfaces'; import { Status } from '../../helper/enums'; import { logger } from '../../helper/logger'; @@ -17,15 +16,15 @@ import { TicsReviewComment, TicsReviewComments } from '../../helper/interfaces'; -import { generateExpandableAreaMarkdown, generateStatusMarkdown } from './markdown'; +import { generateComment, generateExpandableAreaMarkdown, generateItalic, generateStatusMarkdown } from './markdown'; import { githubConfig, ticsConfig } from '../../configuration/config'; +import { getCurrentStepPath } from '../../github/runs'; const capitalize = (s: string): string => s && String(s[0]).toUpperCase() + String(s).slice(1); -export function createSummaryBody(analysisResult: AnalysisResult): string { +export async function createSummaryBody(analysisResult: AnalysisResult): Promise { logger.header('Creating summary.'); - summary.addHeading('TICS Quality Gate'); - summary.addHeading(generateStatusMarkdown(getStatus(analysisResult.passed, analysisResult.passedWithWarning), true), 3); + setSummaryHeader(getStatus(analysisResult.passed, analysisResult.passedWithWarning)); analysisResult.projectResults.forEach(projectResult => { if (projectResult.qualityGate) { @@ -56,6 +55,7 @@ export function createSummaryBody(analysisResult: AnalysisResult): string { summary.addRaw(createFilesSummary(projectResult.analyzedFiles)); } }); + await setSummaryFooter(); logger.info('Created summary.'); @@ -68,11 +68,10 @@ export function createSummaryBody(analysisResult: AnalysisResult): string { * @param warningList list containing all the warnings found in the TICS run. * @returns string containing the error summary. */ -export function createErrorSummaryBody(errorList: string[], warningList: string[]): string { +export async function createErrorSummaryBody(errorList: string[], warningList: string[]): Promise { logger.header('Creating summary.'); - summary.addHeading('TICS Quality Gate'); - summary.addHeading(generateStatusMarkdown(Status.FAILED, true), 3); + setSummaryHeader(Status.FAILED); if (errorList.length > 0) { summary.addHeading('The following errors have occurred during analysis:', 2); @@ -90,6 +89,7 @@ export function createErrorSummaryBody(errorList: string[], warningList: string[ summary.addRaw(`:warning: ${warning}${EOL}${EOL}`); } } + await setSummaryFooter(); logger.info('Created summary.'); return summary.stringify(); @@ -100,18 +100,30 @@ export function createErrorSummaryBody(errorList: string[], warningList: string[ * @param message Message to display in the body of the comment. * @returns string containing the error summary. */ -export function createNothingAnalyzedSummaryBody(message: string): string { +export async function createNothingAnalyzedSummaryBody(message: string): Promise { logger.header('Creating summary.'); - summary.addHeading('TICS Quality Gate'); - summary.addHeading(generateStatusMarkdown(Status.PASSED, true), 3); + setSummaryHeader(Status.PASSED); summary.addRaw(message); + await setSummaryFooter(); logger.info('Created summary.'); return summary.stringify(); } +function setSummaryHeader(status: Status) { + summary.addHeading('TICS Quality Gate'); + summary.addHeading(generateStatusMarkdown(status, true), 3); +} + +async function setSummaryFooter() { + summary.addEOL(); + summary.addRaw('

'); + summary.addRaw(generateItalic(await getCurrentStepPath(), 'Workflow / Job / Step'), true); + summary.addRaw(generateComment(githubConfig.getCommentIdentifier())); +} + function getConditionHeading(failedOrWarnConditions: Condition[]): string { const countFailedConditions = failedOrWarnConditions.filter(c => !c.passed).length; const countWarnConditions = failedOrWarnConditions.filter(c => c.passed && c.passedWithWarning).length; @@ -378,6 +390,7 @@ function findAnnotationInList(list: ExtendedAnnotation[], annotation: ExtendedAn * @param unpostableReviewComments Review comments that could not be posted. * @returns Summary of all the review comments that could not be posted. */ +// Exported for testing export function createUnpostableAnnotationsDetails(unpostableReviewComments: ExtendedAnnotation[]): string { const label = 'Quality gate failures that cannot be annotated in Files Changed'; let body = ''; diff --git a/src/analysis/client/process-analysis.ts b/src/analysis/client/process-analysis.ts index 4e858572..ca340a25 100644 --- a/src/analysis/client/process-analysis.ts +++ b/src/analysis/client/process-analysis.ts @@ -19,12 +19,12 @@ export async function processIncompleteAnalysis(analysis: Analysis): Promise w.includes('[WARNING 5057]'))) { - summaryBody = createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.'); + summaryBody = await createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.'); } else { failedMessage = 'Explorer URL not returned from TICS analysis.'; - summaryBody = createErrorSummaryBody(analysis.errorList, analysis.warningList); + summaryBody = await createErrorSummaryBody(analysis.errorList, analysis.warningList); } if (githubConfig.event.isPullRequest) { diff --git a/src/analysis/qserver.ts b/src/analysis/qserver.ts index b1818745..c7d5e3f7 100644 --- a/src/analysis/qserver.ts +++ b/src/analysis/qserver.ts @@ -28,12 +28,12 @@ export async function qServerAnalysis(): Promise { if (!verdict.passed) { verdict.message = 'Failed to complete TICSQServer analysis.'; - const summaryBody = createErrorSummaryBody(analysis.errorList, analysis.warningList); + const summaryBody = await createErrorSummaryBody(analysis.errorList, analysis.warningList); if (githubConfig.event.isPullRequest) { await postToConversation(false, summaryBody); } } else if (analysis.warningList.find(w => w.includes('[WARNING 5057]'))) { - const summaryBody = createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.'); + const summaryBody = await createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.'); if (githubConfig.event.isPullRequest) { await postToConversation(false, summaryBody); } diff --git a/src/configuration/github.ts b/src/configuration/github.ts index 2c39449c..f303e858 100644 --- a/src/configuration/github.ts +++ b/src/configuration/github.ts @@ -11,9 +11,14 @@ export class GithubConfig { readonly event: GithubEvent; readonly job: string; readonly action: string; - readonly id: string; + readonly workflow: string; + readonly runId: number; + readonly runNumber: number; + readonly runAttempt: number; readonly pullRequestNumber: number | undefined; readonly debugger: boolean; + readonly runnerName: string; + readonly id: string; constructor() { this.apiUrl = context.apiUrl; @@ -21,8 +26,15 @@ export class GithubConfig { this.reponame = context.repo.repo; this.commitSha = context.sha; this.event = this.getGithubEvent(); - this.job = context.job; + this.job = context.job.replace(/[\s|_]+/g, '-'); this.action = context.action.replace('__tiobe_', ''); + this.workflow = context.workflow.replace(/[\s|_]+/g, '-'); + this.runId = context.runId; + this.runNumber = context.runNumber; + this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10); + this.pullRequestNumber = this.getPullRequestNumber(); + this.debugger = isDebug(); + this.runnerName = process.env.RUNNER_NAME ?? ''; /** * Construct the id to use for storing tmpdirs. The action name will @@ -34,10 +46,7 @@ export class GithubConfig { * include a suffix that consists of the sequence number preceded by an underscore. * https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables */ - const runAttempt = process.env.GITHUB_RUN_ATTEMPT ?? '0'; - this.id = `${context.runId.toString()}_${runAttempt}_${this.job}_${this.action}`; - this.pullRequestNumber = this.getPullRequestNumber(); - this.debugger = isDebug(); + this.id = `${this.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`; this.removeWarningListener(); } @@ -71,6 +80,10 @@ export class GithubConfig { } } + getCommentIdentifier(): string { + return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_'); + } + removeWarningListener(): void { process.removeAllListeners('warning'); process.on('warning', warning => { diff --git a/src/github/comments.ts b/src/github/comments.ts index 41320a27..c05a8c81 100644 --- a/src/github/comments.ts +++ b/src/github/comments.ts @@ -59,7 +59,7 @@ export async function postComment(body: string): Promise { export async function deletePreviousComments(comments: Comment[]): Promise { logger.header('Deleting comments of previous runs.'); for (const comment of comments) { - if (commentIncludesTicsTitle(comment.body)) { + if (shouldCommentBeDeleted(comment.body)) { try { const params = { owner: githubConfig.owner, @@ -76,16 +76,55 @@ export async function deletePreviousComments(comments: Comment[]): Promise logger.info('Deleted review comments of previous runs.'); } -function commentIncludesTicsTitle(body?: string): boolean { - const titles = ['

TICS Quality Gate

', '## TICS Quality Gate', '## TICS Analysis']; - +function shouldCommentBeDeleted(body?: string): boolean { if (!body) return false; + const titles = ['

TICS Quality Gate

', '## TICS Quality Gate', '## TICS Analysis']; + let includesTitle = false; - titles.forEach(title => { - if (body.startsWith(title)) includesTitle = true; - }); + for (const title of titles) { + if (body.startsWith(title)) { + includesTitle = true; + } + } + + if (includesTitle) { + return isWorkflowAndJobInAnotherRun(body); + } + + return false; +} + +function isWorkflowAndJobInAnotherRun(body: string): boolean { + const regex = //g; + + let identifier = ''; + // Get the last match of the tag. + let match: RegExpExecArray | null = null; + while ((match = regex.exec(body))) { + if (match[1] !== '') { + identifier = match[1]; + } + } + + // If no identifier is found, the comment is + // of the old format and should be replaced. + if (identifier === '') return true; + + const split = identifier.split('_'); + + // If the identifier does not match the correct format, do not replace. + if (split.length !== 4) { + logger.debug(`Identifier is not of the correct format: ${identifier}`); + return false; + } + + // If the workflow or job are different, do not replace. + if (split[0] !== githubConfig.workflow || split[1] !== githubConfig.job) { + return false; + } - return includesTitle; + // Only replace if the run number or run attempt are different. + return parseInt(split[2], 10) !== githubConfig.runNumber || parseInt(split[3], 10) !== githubConfig.runAttempt; } diff --git a/src/github/runs.ts b/src/github/runs.ts new file mode 100644 index 00000000..619b97b4 --- /dev/null +++ b/src/github/runs.ts @@ -0,0 +1,39 @@ +import { logger } from '../helper/logger'; +import { handleOctokitError } from '../helper/response'; +import { githubConfig } from '../configuration/config'; +import { octokit } from './octokit'; + +/** + * Create review on the pull request from the analysis given. + * @param body Body containing the summary of the review + * @param event Either approve or request changes in the review. + */ +export async function getCurrentStepPath(): Promise { + const params = { + owner: githubConfig.owner, + repo: githubConfig.reponame, + run_id: githubConfig.runId, + attempt_number: githubConfig.runAttempt + }; + + const stepname = [githubConfig.workflow, githubConfig.job, githubConfig.action]; + try { + logger.debug('Retrieving step name for current step...'); + const response = await octokit.rest.actions.listJobsForWorkflowRunAttempt(params); + logger.debug(JSON.stringify(response.data)); + const jobs = response.data.jobs.filter(j => j.status === 'in_progress' && j.runner_name === githubConfig.runnerName); + + if (jobs.length === 1) { + const job = jobs[0]; + stepname[1] = job.name; + const steps = job.steps?.filter(s => s.status === 'in_progress'); + if (steps?.length === 1) { + stepname[2] = steps[0].name; + } + } + } catch (error: unknown) { + const message = handleOctokitError(error); + logger.notice(`Retrieving the step name failed: ${message}`); + } + return stepname.join(' / '); +} diff --git a/test/.setup/mock.ts b/test/.setup/mock.ts index 482ea806..b6e99d0f 100644 --- a/test/.setup/mock.ts +++ b/test/.setup/mock.ts @@ -13,6 +13,11 @@ export const githubConfigMock: { id: string; pullRequestNumber: number | undefined; debugger: boolean; + workflow: string; + runNumber: number; + runAttempt: number; + runnerName: string; + getCommentIdentifier(): string; } = { apiUrl: 'github.com/api/v1/', owner: 'tester', @@ -23,7 +28,14 @@ export const githubConfigMock: { action: 'tics-github-action', id: '123_TICS_1_tics-github-action', pullRequestNumber: 1, - debugger: false + debugger: false, + workflow: 'tics-client', + runNumber: 1, + runAttempt: 2, + runnerName: 'Github Actions 1', + getCommentIdentifier(): string { + return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_'); + } }; export const ticsConfigMock = { @@ -102,6 +114,9 @@ jest.mock('../../src/github/octokit', () => { }, repos: { getCommit: jest.fn() + }, + actions: { + listJobsForWorkflowRunAttempt: jest.fn() } }, graphql: jest.fn() @@ -121,6 +136,7 @@ export const contextMock: { job: string; runId: number; runNumber: number; + workflow: string; payload: { pull_request: | { @@ -140,6 +156,7 @@ export const contextMock: { job: 'TICS', runId: 123, runNumber: 1, + workflow: 'tics_client', payload: { pull_request: { number: 1 diff --git a/test/integration/configuration.test.ts b/test/integration/configuration.test.ts index 07b21e51..7a62fc87 100644 --- a/test/integration/configuration.test.ts +++ b/test/integration/configuration.test.ts @@ -28,6 +28,8 @@ describe('pullRequestNumber', () => { eventName: 'pull_request', runId: 1, runNumber: 1, + job: 'TICS', + workflow: 'tics_client', repo: { owner: 'owner', repo: 'repo' @@ -53,6 +55,8 @@ describe('pullRequestNumber', () => { eventName: 'pull_request', runId: 1, runNumber: 1, + job: 'TICS', + workflow: 'tics_client', repo: { owner: 'owner', repo: 'repo' @@ -80,6 +84,8 @@ describe('pullRequestNumber', () => { eventName: 'pull_request', runId: 1, runNumber: 1, + job: 'TICS', + workflow: 'tics_client', repo: { owner: 'owner', repo: 'repo' diff --git a/test/integration/httpclient.test.ts b/test/integration/httpclient.test.ts index f329337a..96d7b733 100644 --- a/test/integration/httpclient.test.ts +++ b/test/integration/httpclient.test.ts @@ -10,6 +10,8 @@ process.env['http_proxy'] = proxyUrl; // set required inputs process.env.GITHUB_REPOSITORY = 'owner/repo'; process.env.GITHUB_ACTION = '_tics-github-action'; +process.env.GITHUB_JOB = 'tics_client'; +process.env.GITHUB_WORKFLOW = 'tics client'; process.env.INPUT_GITHUBTOKEN = 'token'; process.env.INPUT_MODE = 'client'; process.env.INPUT_PROJECTNAME = 'tics-github-action'; diff --git a/test/integration/octokit.test.ts b/test/integration/octokit.test.ts index 0f850a67..0b9b8a8f 100644 --- a/test/integration/octokit.test.ts +++ b/test/integration/octokit.test.ts @@ -13,6 +13,8 @@ process.env['http_proxy'] = proxyUrl; process.env.GITHUB_REPOSITORY = 'owner/repo'; process.env.GITHUB_API_URL = 'https://api.github.com'; process.env.GITHUB_ACTION = '_tics-github-action'; +process.env.GITHUB_JOB = 'tics_client'; +process.env.GITHUB_WORKFLOW = 'tics client'; process.env.INPUT_MODE = 'client'; process.env.INPUT_PROJECTNAME = 'tics-github-action'; process.env.INPUT_VIEWERURL = 'http://localhost/tiobeweb/TICS/api/cfg?name=default'; diff --git a/test/unit/action/decorate/action.test.ts b/test/unit/action/decorate/action.test.ts index e1e5deed..61d8d671 100644 --- a/test/unit/action/decorate/action.test.ts +++ b/test/unit/action/decorate/action.test.ts @@ -14,8 +14,8 @@ describe('decorateAction', () => { let spyPostAnnotations: jest.SpyInstance; beforeEach(() => { - spyCreateSummaryBody = jest.spyOn(summary, 'createSummaryBody').mockReturnValue('body'); - spyCreateErrorSummaryBody = jest.spyOn(summary, 'createErrorSummaryBody').mockReturnValue('body'); + spyCreateSummaryBody = jest.spyOn(summary, 'createSummaryBody').mockResolvedValue('body'); + spyCreateErrorSummaryBody = jest.spyOn(summary, 'createErrorSummaryBody').mockResolvedValue('body'); spyDecoratePullRequest = jest.spyOn(pullRequest, 'decoratePullRequest').mockImplementation(); spyPostAnnotations = jest.spyOn(annotations, 'postAnnotations').mockImplementation(); }); diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts index b94ebf08..db0ae2f7 100644 --- a/test/unit/action/decorate/summary.test.ts +++ b/test/unit/action/decorate/summary.test.ts @@ -26,8 +26,8 @@ describe('createSummaryBody', () => { ticsConfigMock.displayUrl = 'http://viewer.url/'; }); - test('Should contain blocking after if there are soaked violations', () => { - const string = createSummaryBody(analysisResultsSoaked); + test('Should contain blocking after if there are soaked violations', async () => { + const string = await createSummaryBody(analysisResultsSoaked); expect(string).toContain('

:x: Failed

'); expect(string).toContain('

1 Condition(s) failed

'); @@ -42,8 +42,8 @@ describe('createSummaryBody', () => { summary.clear(); }); - test('Should not contain blocking after if there are no soaked violations', () => { - const string = createSummaryBody(analysisResultsNotSoaked); + test('Should not contain blocking after if there are no soaked violations', async () => { + const string = await createSummaryBody(analysisResultsNotSoaked); expect(string).toContain('

:x: Failed

'); expect(string).toContain('

1 Condition(s) failed

'); @@ -56,8 +56,8 @@ describe('createSummaryBody', () => { summary.clear(); }); - test('Should contain blocking after if there are partly violations', () => { - const string = createSummaryBody(analysisResultsPartlySoakedPassed); + test('Should contain blocking after if there are partly violations', async () => { + const string = await createSummaryBody(analysisResultsPartlySoakedPassed); expect(string).toContain('

:warning: Passed with warnings

'); expect(string).toContain('

1 Condition(s) passed with warning

'); @@ -69,8 +69,8 @@ describe('createSummaryBody', () => { summary.clear(); }); - test('Should contain blocking after for one of the two conditions', () => { - const string = createSummaryBody(analysisResultsPartlySoakedFailed); + test('Should contain blocking after for one of the two conditions', async () => { + const string = await createSummaryBody(analysisResultsPartlySoakedFailed); expect(string).toContain('

:x: Failed

'); expect(string).toContain('

1 Condition(s) failed, 1 Condition(s) passed with warning

'); @@ -84,8 +84,8 @@ describe('createSummaryBody', () => { summary.clear(); }); - test('Should pass with no conditions that passed with warnings', () => { - const string = createSummaryBody(analysisResultsNoSoakedPassed); + test('Should pass with no conditions that passed with warnings', async () => { + const string = await createSummaryBody(analysisResultsNoSoakedPassed); expect(string).toContain('

:heavy_check_mark: Passed

'); expect(string).toContain('

All conditions passed

'); @@ -95,10 +95,10 @@ describe('createSummaryBody', () => { }); describe('createErrorSummary', () => { - test('Should return summary of two errors', () => { + test('Should return summary of two errors', async () => { githubConfigMock.debugger = false; - const body = createErrorSummaryBody(['Error', 'Error'], []); + const body = await createErrorSummaryBody(['Error', 'Error'], []); summary.clear(); expect(body).toContainTimes('

The following errors have occurred during analysis:

', 1); @@ -107,10 +107,10 @@ describe('createErrorSummary', () => { expect(body).toContainTimes(':warning: Warning', 0); }); - test('Should return summary of zero warnings on logLevel default', () => { + test('Should return summary of zero warnings on logLevel default', async () => { githubConfigMock.debugger = false; - const body = createErrorSummaryBody([], ['Warning', 'Warning']); + const body = await createErrorSummaryBody([], ['Warning', 'Warning']); summary.clear(); expect(body).toContainTimes('

The following errors have occurred during analysis:

', 0); @@ -119,35 +119,41 @@ describe('createErrorSummary', () => { expect(body).toContainTimes(':warning: Warning', 0); }); - test('Should return summary of two warnings on logLevel debug', () => { + test('Should return summary of two warnings on logLevel debug', async () => { githubConfigMock.debugger = true; - const body = createErrorSummaryBody([], ['Warning', 'Warning']); + const body = await createErrorSummaryBody([], ['Warning', 'Warning']); summary.clear(); expect(body).toContainTimes('

The following errors have occurred during analysis:

', 0); expect(body).toContainTimes('

The following warnings have occurred during analysis:

', 1); expect(body).toContainTimes(':x: Error', 0); expect(body).toContainTimes(':warning: Warning', 2); + expect(body).toContainTimes('\n

tics-client / TICS / tics-github-action', 1); + expect(body).toContain('\n'); }); - test('Should return summary of one error and two warnings', () => { + test('Should return summary of one error and two warnings', async () => { githubConfigMock.debugger = true; - const body = createErrorSummaryBody(['Error'], ['Warning', 'Warning']); + const body = await createErrorSummaryBody(['Error'], ['Warning', 'Warning']); summary.clear(); expect(body).toContainTimes('

The following errors have occurred during analysis:

', 1); expect(body).toContainTimes('

The following warnings have occurred during analysis:

', 1); expect(body).toContainTimes(':x: Error', 1); expect(body).toContainTimes(':warning: Warning', 2); + expect(body).toContainTimes('\n

tics-client / TICS / tics-github-action', 1); + expect(body).toContainTimes('\n', 1); }); }); describe('createNothingAnalyzedSummaryBody', () => { test('Should return summary with the message given', async () => { - const body = createNothingAnalyzedSummaryBody('message'); - expect(body).toEqual('

TICS Quality Gate

\n

:heavy_check_mark: Passed

\nmessage'); + const body = await createNothingAnalyzedSummaryBody('message'); + expect(body).toEqual( + '

TICS Quality Gate

\n

:heavy_check_mark: Passed

\nmessage\n

tics-client / TICS / tics-github-action\n' + ); }); }); diff --git a/test/unit/analysis/qserver.test.ts b/test/unit/analysis/qserver.test.ts index d33015c6..f011c223 100644 --- a/test/unit/analysis/qserver.test.ts +++ b/test/unit/analysis/qserver.test.ts @@ -33,7 +33,7 @@ describe('SetFailed checks (QServer)', () => { spyGetLastQServerRunDate = jest.spyOn(viewer, 'getLastQServerRunDate'); jest.spyOn(action, 'decorateAction'); - jest.spyOn(summary, 'createNothingAnalyzedSummaryBody').mockReturnValue('body'); + jest.spyOn(summary, 'createNothingAnalyzedSummaryBody').mockResolvedValue('body'); }); afterEach(() => { diff --git a/test/unit/configuration/github.test.ts b/test/unit/configuration/github.test.ts index b95e7895..6d4c7d8a 100644 --- a/test/unit/configuration/github.test.ts +++ b/test/unit/configuration/github.test.ts @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import { GithubConfig } from '../../../src/configuration/github'; import { contextMock } from '../../.setup/mock'; +import { GithubEvent } from '../../../src/configuration/github-event'; describe('GitHub Configuration', () => { let githubConfig: GithubConfig; @@ -92,4 +93,26 @@ describe('GitHub Configuration', () => { githubConfig = new GithubConfig(); githubConfig.removeWarningListener(); }); + + test('getCommentIdentifier', () => { + githubConfig = new GithubConfig(); + expect(githubConfig.getCommentIdentifier()).toEqual('tics-client_TICS_1_1'); + }); + + test('getGithubEvent', () => { + contextMock.eventName = 'undefined'; + expect(new GithubConfig().event).toEqual(GithubEvent.PUSH); + contextMock.eventName = GithubEvent.PUSH.name; + expect(new GithubConfig().event).toEqual(GithubEvent.PUSH); + contextMock.eventName = GithubEvent.PULL_REQUEST.name; + expect(new GithubConfig().event).toEqual(GithubEvent.PULL_REQUEST); + contextMock.eventName = GithubEvent.PULL_REQUEST_TARGET.name; + expect(new GithubConfig().event).toEqual(GithubEvent.PULL_REQUEST_TARGET); + contextMock.eventName = GithubEvent.WORKFLOW_CALL.name; + expect(new GithubConfig().event).toEqual(GithubEvent.WORKFLOW_CALL); + contextMock.eventName = GithubEvent.WORKFLOW_DISPATCH.name; + expect(new GithubConfig().event).toEqual(GithubEvent.WORKFLOW_DISPATCH); + contextMock.eventName = GithubEvent.WORKFLOW_RUN.name; + expect(new GithubConfig().event).toEqual(GithubEvent.WORKFLOW_RUN); + }); }); diff --git a/test/unit/github/comments.test.ts b/test/unit/github/comments.test.ts index 5c614d67..a0e25378 100644 --- a/test/unit/github/comments.test.ts +++ b/test/unit/github/comments.test.ts @@ -130,7 +130,7 @@ describe('deletePreviousComments', () => { }); test('Should call deleteComment with values', async () => { - deletePreviousComments([commentWithBody]); + await deletePreviousComments([commentWithBody]); const calledWith = { owner: githubConfig.owner, repo: githubConfig.reponame, @@ -139,11 +139,46 @@ describe('deletePreviousComments', () => { expect(deleteCommentSpy).toHaveBeenCalledWith(calledWith); }); - test('Should call deleteComment with values', async () => { + test('Should not call deleteComment if body is undefined', async () => { await deletePreviousComments([commentWithoutBody]); expect(deleteCommentSpy).toHaveBeenCalledTimes(0); }); + test('Should not call deleteComment if body is not TICS', async () => { + await deletePreviousComments([commentWithoutTics]); + expect(deleteCommentSpy).toHaveBeenCalledTimes(0); + }); + + test('Should call deleteComment if identifier workflow and job match', async () => { + await deletePreviousComments([commentWithIdentifierSameJob]); + const calledWith = { + owner: githubConfig.owner, + repo: githubConfig.reponame, + comment_id: 0 + }; + expect(deleteCommentSpy).toHaveBeenCalledWith(calledWith); + }); + + test('Should not call deleteComment if identifier workflow and job match, but they are in the same run', async () => { + await deletePreviousComments([commentWithIdentifierSameJobAndRun]); + expect(deleteCommentSpy).toHaveBeenCalledTimes(0); + }); + + test('Should not call deleteComment if identifier workflow and job do not match', async () => { + await deletePreviousComments([commentWithIdentifierOtherJob]); + expect(deleteCommentSpy).toHaveBeenCalledTimes(0); + }); + + test('Should not call deleteComment if identifier is of the wrong format', async () => { + const debugSpy = jest.spyOn(logger, 'debug'); + + await deletePreviousComments([commentWithIdentifierWrongFormat]); + + expect(deleteCommentSpy).toHaveBeenCalledTimes(0); + expect(debugSpy).toHaveBeenCalledTimes(1); + expect(debugSpy).toHaveBeenCalledWith('Identifier is not of the correct format: tics-client_OTHER_1'); + }); + test('Should post a notice when deleteComment throws', async () => { deleteCommentSpy.mockRejectedValue(Error()); const noticeSpy = jest.spyOn(logger, 'notice'); @@ -167,13 +202,31 @@ const commentWithBody: Comment = { }; const commentWithoutBody: Comment = { - url: '', - html_url: '', - issue_url: '', - id: 0, - node_id: '', - user: null, - created_at: '', - updated_at: '', + ...commentWithBody, body: undefined }; + +const commentWithoutTics: Comment = { + ...commentWithBody, + body: 'Other action content' +}; + +const commentWithIdentifierSameJob: Comment = { + ...commentWithBody, + body: '

TICS Quality Gate

Message Here' +}; + +const commentWithIdentifierSameJobAndRun: Comment = { + ...commentWithBody, + body: '

TICS Quality Gate

Message Here' +}; + +const commentWithIdentifierOtherJob: Comment = { + ...commentWithBody, + body: '

TICS Quality Gate

Message Here' +}; + +const commentWithIdentifierWrongFormat: Comment = { + ...commentWithBody, + body: '

TICS Quality Gate

Message Here' +}; diff --git a/test/unit/github/runs.test.ts b/test/unit/github/runs.test.ts new file mode 100644 index 00000000..8bbe7cdc --- /dev/null +++ b/test/unit/github/runs.test.ts @@ -0,0 +1,105 @@ +import { getCurrentStepPath } from '../../../src/github/runs'; +import { octokit } from '../../../src/github/octokit'; +import { githubConfigMock } from '../../.setup/mock'; + +describe('postReview', () => { + let listJobsSpy: jest.SpyInstance; + + beforeEach(() => { + listJobsSpy = jest.spyOn(octokit.rest.actions, 'listJobsForWorkflowRunAttempt'); + }); + + test('Should return name when only one step is in progress', async () => { + listJobsSpy.mockResolvedValue({ + data: { + jobs: [ + { + name: 'TICS Client', + runner_name: 'Github Actions 1', + status: 'in_progress', + steps: [ + { + name: 'Step 1', + status: 'completed' + }, + { + name: 'Step 2', + status: 'in_progress' + } + ] + }, + { + name: 'TICS Client', + runner_name: 'Github Actions 2', + status: 'completed', + steps: [ + { + name: 'Step 1', + status: 'in_progress' + }, + { + name: 'Step 2', + status: 'in_progress' + } + ] + } + ] + } + }); + + const name = await getCurrentStepPath(); + + expect(name).toStrictEqual('tics-client / TICS Client / Step 2'); + }); + + test('Should not return name when multiple steps are in progress', async () => { + listJobsSpy.mockResolvedValue({ + data: { + jobs: [ + { + name: 'TICS', + runner_name: 'Github Actions 1', + status: 'in_progress', + steps: [ + { + name: 'Step 1', + status: 'in_progress' + }, + { + name: 'Step 2', + status: 'in_progress' + } + ] + }, + { + name: 'TICS', + runner_name: 'Github Actions 1', + status: 'completed', + steps: [ + { + name: 'Step 1', + status: 'completed' + }, + { + name: 'Step 2', + status: 'completed' + } + ] + } + ] + } + }); + + const name = await getCurrentStepPath(); + + expect(name).toStrictEqual('tics-client / TICS / tics-github-action'); + }); + + test('Should post a notice on createReview', async () => { + listJobsSpy.mockRejectedValue(new Error()); + + const name = await getCurrentStepPath(); + + expect(name).toStrictEqual('tics-client / TICS / tics-github-action'); + }); +}); diff --git a/test/unit/helper/logger.test.ts b/test/unit/helper/logger.test.ts index 0b4124ac..e007b077 100644 --- a/test/unit/helper/logger.test.ts +++ b/test/unit/helper/logger.test.ts @@ -1,27 +1,46 @@ import * as core from '@actions/core'; import { logger } from '../../../src/helper/logger'; +let infoSpy: jest.SpyInstance; +let debugSpy: jest.SpyInstance; +let noticeSpy: jest.SpyInstance; +let errorSpy: jest.SpyInstance; +let warningSpy: jest.SpyInstance; +let setFailedSpy: jest.SpyInstance; + +beforeEach(() => { + infoSpy = jest.spyOn(core, 'info'); + debugSpy = jest.spyOn(core, 'debug'); + noticeSpy = jest.spyOn(core, 'notice'); + errorSpy = jest.spyOn(core, 'error'); + warningSpy = jest.spyOn(core, 'warning'); + setFailedSpy = jest.spyOn(core, 'setFailed'); +}); + +afterEach(() => { + jest.resetAllMocks(); +}); + describe('info', () => { test('Should call core.info on info', () => { - const info = jest.spyOn(core, 'info'); const addNewline = jest.spyOn(logger, 'addNewline'); logger.info('string'); - expect(info).toHaveBeenCalledTimes(1); - expect(info).toHaveBeenCalledWith('string'); + expect(infoSpy).toHaveBeenCalledTimes(1); + expect(infoSpy).toHaveBeenCalledWith('string'); expect(addNewline).toHaveBeenCalledTimes(0); expect(logger.called).toEqual('info'); }); test('Should call core.info on header', () => { - const info = jest.spyOn(core, 'info'); const addNewline = jest.spyOn(logger, 'addNewline'); + logger.info('error'); logger.header('string'); - expect(info).toHaveBeenCalledTimes(2); // once for header, once for newline - expect(info).toHaveBeenCalledWith(expect.stringContaining('string')); + expect(infoSpy).toHaveBeenCalledTimes(2); // once for header, once for newline + expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('string')); expect(addNewline).toHaveBeenCalledTimes(1); expect(addNewline).toHaveBeenCalledWith('header'); expect(logger.called).toEqual('header'); @@ -30,14 +49,13 @@ describe('info', () => { describe('debug', () => { test('Should call core.debug on debug', () => { - const debug = jest.spyOn(core, 'debug'); const addNewline = jest.spyOn(logger, 'addNewline'); logger.setSecretsFilter(['token']); logger.debug('string token secret'); - expect(debug).toHaveBeenCalledTimes(1); - expect(debug).toHaveBeenCalledWith('string token ***'); + expect(debugSpy).toHaveBeenCalledTimes(1); + expect(debugSpy).toHaveBeenCalledWith('string token ***'); expect(addNewline).toHaveBeenCalledTimes(0); expect(logger.called).toEqual('debug'); }); @@ -45,13 +63,12 @@ describe('debug', () => { describe('notice', () => { test('Should call core.notice on notice', () => { - const debug = jest.spyOn(core, 'notice'); const addNewline = jest.spyOn(logger, 'addNewline'); logger.notice('string'); - expect(debug).toHaveBeenCalledTimes(1); - expect(debug).toHaveBeenCalledWith('string', undefined); + expect(noticeSpy).toHaveBeenCalledTimes(1); + expect(noticeSpy).toHaveBeenCalledWith('string', undefined); expect(addNewline).toHaveBeenCalledTimes(0); expect(logger.called).toEqual('notice'); }); @@ -59,13 +76,12 @@ describe('notice', () => { describe('warning', () => { test('Should call core.warning on warning', () => { - const debug = jest.spyOn(core, 'warning'); const addNewline = jest.spyOn(logger, 'addNewline'); logger.warning('string'); - expect(debug).toHaveBeenCalledTimes(1); - expect(debug).toHaveBeenCalledWith('\u001b[33mstring', undefined); + expect(warningSpy).toHaveBeenCalledTimes(1); + expect(warningSpy).toHaveBeenCalledWith('\u001b[33mstring', undefined); expect(addNewline).toHaveBeenCalledTimes(0); expect(logger.called).toEqual('warning'); }); @@ -73,13 +89,12 @@ describe('warning', () => { describe('error', () => { test('Should call core.error on error', () => { - const error = jest.spyOn(core, 'error'); const addNewline = jest.spyOn(logger, 'addNewline'); logger.error('error'); - expect(error).toHaveBeenCalledTimes(1); - expect(error).toHaveBeenCalledWith(expect.stringContaining('error'), undefined); + expect(errorSpy).toHaveBeenCalledTimes(1); + expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('error'), undefined); expect(addNewline).toHaveBeenCalledTimes(1); expect(addNewline).toHaveBeenCalledWith('error'); expect(logger.called).toEqual('error'); @@ -88,15 +103,34 @@ describe('error', () => { describe('setFailed', () => { test('Should call core.setFailed on setFailed', () => { - const setFailed = jest.spyOn(core, 'setFailed'); const addNewline = jest.spyOn(logger, 'addNewline'); logger.setFailed('error'); - expect(setFailed).toHaveBeenCalledTimes(1); - expect(setFailed).toHaveBeenCalledWith(expect.stringContaining('error')); + expect(setFailedSpy).toHaveBeenCalledTimes(1); + expect(setFailedSpy).toHaveBeenCalledWith(expect.stringContaining('error')); expect(addNewline).toHaveBeenCalledTimes(1); expect(addNewline).toHaveBeenCalledWith('error'); expect(logger.called).toEqual('error'); }); }); + +describe('maskOutput', () => { + test('Should filter out JAVA options', () => { + const message = 'Picked up JAVA_OPTIONS testing once'; + + logger.info(message); + logger.notice(message); + logger.debug(message); + logger.warning(message); + logger.error(message); + logger.setFailed(message); + + expect(infoSpy).toHaveBeenCalledTimes(0); + expect(noticeSpy).toHaveBeenCalledTimes(0); + expect(debugSpy).toHaveBeenCalledTimes(0); + expect(warningSpy).toHaveBeenCalledTimes(0); + expect(errorSpy).toHaveBeenCalledTimes(0); + expect(setFailedSpy).toHaveBeenCalledTimes(0); + }); +});