diff --git a/dist/index.js b/dist/index.js index fbd86806..706ac6e6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1666,21 +1666,45 @@ async function deletePreviousReviewComments(postedReviewComments) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.uploadArtifact = uploadArtifact; exports.getTmpDir = getTmpDir; -const os_1 = __nccwpck_require__(70857); const fs_1 = __nccwpck_require__(79896); +const os_1 = __nccwpck_require__(70857); const artifact_1 = __nccwpck_require__(76846); +const artifact_v1_1 = __nccwpck_require__(20166); const canonical_path_1 = __nccwpck_require__(85982); +const config_1 = __nccwpck_require__(34151); const logger_1 = __nccwpck_require__(66113); const response_1 = __nccwpck_require__(93590); -const config_1 = __nccwpck_require__(34151); +const utils_1 = __nccwpck_require__(27180); async function uploadArtifact() { - const artifactClient = new artifact_1.DefaultArtifactClient(); + logger_1.logger.header('Uploading artifact'); const tmpdir = getTmpDir() + '/ticstmpdir'; // Example TICS_tics-github-action_2_qserver_ticstmpdir const name = sanitizeArtifactName(`${config_1.githubConfig.job}_${config_1.githubConfig.action}_${config_1.ticsConfig.mode}_ticstmpdir`); + logger_1.logger.info(`Logs taken from ${tmpdir}`); + if (isGhes()) { + await uploadGhes(name, tmpdir); + } + else { + await uploadGithub(name, tmpdir); + } +} +async function uploadGhes(name, tmpdir) { + const artifactClient = (0, artifact_v1_1.create)(); + try { + const response = await artifactClient.uploadArtifact(name, getFilesInFolder(tmpdir), tmpdir); + if (response.failedItems.length > 0) { + logger_1.logger.debug(`Failed to upload file(s): ${response.failedItems.join(', ')}`); + } + logger_1.logger.info(`Uploaded artifact "${name}" (size: ${createSize(response.size)})`); + } + catch (error) { + const message = (0, response_1.handleOctokitError)(error); + logger_1.logger.debug('Failed to upload artifact: ' + message); + } +} +async function uploadGithub(name, tmpdir) { + const artifactClient = new artifact_1.DefaultArtifactClient(); try { - logger_1.logger.header('Uploading artifact'); - logger_1.logger.info(`Logs gotten from ${tmpdir}`); const response = await artifactClient.uploadArtifact(name, getFilesInFolder(tmpdir), tmpdir); if (response.id && response.size) { logger_1.logger.info(`Uploaded artifact "${name}" with id "${response.id.toString()}" (size: ${createSize(response.size)})`); @@ -1738,6 +1762,18 @@ function getFilesInFolder(directory) { traverseDirectory(directory); return files; } +/** + * Copied from @actions/artifacts v6.2.0 + * https://github.com/actions/toolkit/blob/02afeb157764304bb3bfe1a6cfd37258ec3fcf7c/packages/artifact/src/internal/shared/config.ts + */ +function isGhes() { + const ghUrl = new URL((0, utils_1.emptyToNull)(process.env.GITHUB_SERVER_URL) ?? 'https://github.com'); + const hostname = ghUrl.hostname.trimEnd().toUpperCase(); + const isGitHubHost = hostname === 'GITHUB.COM'; + const isGheHost = hostname.endsWith('.GHE.COM'); + const isLocalHost = hostname.endsWith('.LOCALHOST'); + return !isGitHubHost && !isGheHost && !isLocalHost; +} /***/ }), @@ -2080,28 +2116,28 @@ async function getChangedFilesOfPullRequestQL() { }; let response; try { - response = await octokit_1.octokit.graphql.paginate(`query changedFiles($owner: String!, $repo: String!, $pull_number: Int!, $per_page: Int!, $cursor: String) { - rateLimit { - remaining - } - repository(owner: $owner, name: $repo) { - pullRequest(number: $pull_number) { - files(first: $per_page, after: $cursor) { - totalCount - nodes { - path - changeType - additions - deletions - viewerViewedState - } - pageInfo { - hasNextPage - endCursor - } - } - } - } + response = await octokit_1.octokit.graphql.paginate(`query changedFiles($owner: String!, $repo: String!, $pull_number: Int!, $per_page: Int!, $cursor: String) { + rateLimit { + remaining + } + repository(owner: $owner, name: $repo) { + pullRequest(number: $pull_number) { + files(first: $per_page, after: $cursor) { + totalCount + nodes { + path + changeType + additions + deletions + viewerViewedState + } + pageInfo { + hasNextPage + endCursor + } + } + } + } }`, params); logger_1.logger.debug(JSON.stringify(response)); } @@ -2567,6 +2603,7 @@ function joinUrl(url, ...paths) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isOneOf = isOneOf; +exports.emptyToNull = emptyToNull; /** * Checks if the first value is one of the following ones. * Replaces value === arg1 || value === arg2 || ... @@ -2577,6 +2614,9 @@ exports.isOneOf = isOneOf; function isOneOf(value, ...args) { return args.includes(value); } +function emptyToNull(value) { + return value !== undefined && value !== null && value !== '' ? value : null; +} /***/ }), @@ -3207,6 +3247,2254 @@ class ViewerVersion { exports.viewerVersion = new ViewerVersion(); +/***/ }), + +/***/ 20166: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.create = void 0; +const artifact_client_1 = __nccwpck_require__(91262); +/** + * Constructs an ArtifactClient + */ +function create() { + return artifact_client_1.DefaultArtifactClient.create(); +} +exports.create = create; +//# sourceMappingURL=artifact-client.js.map + +/***/ }), + +/***/ 91262: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.DefaultArtifactClient = void 0; +const core = __importStar(__nccwpck_require__(37484)); +const upload_specification_1 = __nccwpck_require__(71583); +const upload_http_client_1 = __nccwpck_require__(87566); +const utils_1 = __nccwpck_require__(24149); +const path_and_artifact_name_validation_1 = __nccwpck_require__(53520); +const download_http_client_1 = __nccwpck_require__(79063); +const download_specification_1 = __nccwpck_require__(23718); +const config_variables_1 = __nccwpck_require__(49388); +const path_1 = __nccwpck_require__(16928); +class DefaultArtifactClient { + /** + * Constructs a DefaultArtifactClient + */ + static create() { + return new DefaultArtifactClient(); + } + /** + * Uploads an artifact + */ + uploadArtifact(name, files, rootDirectory, options) { + return __awaiter(this, void 0, void 0, function* () { + core.info(`Starting artifact upload +For more detailed logs during the artifact upload process, enable step-debugging: https://docs.github.com/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging#enabling-step-debug-logging`); + (0, path_and_artifact_name_validation_1.checkArtifactName)(name); + // Get specification for the files being uploaded + const uploadSpecification = (0, upload_specification_1.getUploadSpecification)(name, rootDirectory, files); + const uploadResponse = { + artifactName: name, + artifactItems: [], + size: 0, + failedItems: [] + }; + const uploadHttpClient = new upload_http_client_1.UploadHttpClient(); + if (uploadSpecification.length === 0) { + core.warning(`No files found that can be uploaded`); + } + else { + // Create an entry for the artifact in the file container + const response = yield uploadHttpClient.createArtifactInFileContainer(name, options); + if (!response.fileContainerResourceUrl) { + core.debug(response.toString()); + throw new Error('No URL provided by the Artifact Service to upload an artifact to'); + } + core.debug(`Upload Resource URL: ${response.fileContainerResourceUrl}`); + core.info(`Container for artifact "${name}" successfully created. Starting upload of file(s)`); + // Upload each of the files that were found concurrently + const uploadResult = yield uploadHttpClient.uploadArtifactToFileContainer(response.fileContainerResourceUrl, uploadSpecification, options); + // Update the size of the artifact to indicate we are done uploading + // The uncompressed size is used for display when downloading a zip of the artifact from the UI + core.info(`File upload process has finished. Finalizing the artifact upload`); + yield uploadHttpClient.patchArtifactSize(uploadResult.totalSize, name); + if (uploadResult.failedItems.length > 0) { + core.info(`Upload finished. There were ${uploadResult.failedItems.length} items that failed to upload`); + } + else { + core.info(`Artifact has been finalized. All files have been successfully uploaded!`); + } + core.info(` +The raw size of all the files that were specified for upload is ${uploadResult.totalSize} bytes +The size of all the files that were uploaded is ${uploadResult.uploadSize} bytes. This takes into account any gzip compression used to reduce the upload size, time and storage + +Note: The size of downloaded zips can differ significantly from the reported size. For more information see: https://github.com/actions/upload-artifact#zipped-artifact-downloads \r\n`); + uploadResponse.artifactItems = uploadSpecification.map(item => item.absoluteFilePath); + uploadResponse.size = uploadResult.uploadSize; + uploadResponse.failedItems = uploadResult.failedItems; + } + return uploadResponse; + }); + } + downloadArtifact(name, path, options) { + return __awaiter(this, void 0, void 0, function* () { + const downloadHttpClient = new download_http_client_1.DownloadHttpClient(); + const artifacts = yield downloadHttpClient.listArtifacts(); + if (artifacts.count === 0) { + throw new Error(`Unable to find any artifacts for the associated workflow`); + } + const artifactToDownload = artifacts.value.find(artifact => { + return artifact.name === name; + }); + if (!artifactToDownload) { + throw new Error(`Unable to find an artifact with the name: ${name}`); + } + const items = yield downloadHttpClient.getContainerItems(artifactToDownload.name, artifactToDownload.fileContainerResourceUrl); + if (!path) { + path = (0, config_variables_1.getWorkSpaceDirectory)(); + } + path = (0, path_1.normalize)(path); + path = (0, path_1.resolve)(path); + // During upload, empty directories are rejected by the remote server so there should be no artifacts that consist of only empty directories + const downloadSpecification = (0, download_specification_1.getDownloadSpecification)(name, items.value, path, (options === null || options === void 0 ? void 0 : options.createArtifactFolder) || false); + if (downloadSpecification.filesToDownload.length === 0) { + core.info(`No downloadable files were found for the artifact: ${artifactToDownload.name}`); + } + else { + // Create all necessary directories recursively before starting any download + yield (0, utils_1.createDirectoriesForArtifact)(downloadSpecification.directoryStructure); + core.info('Directory structure has been set up for the artifact'); + yield (0, utils_1.createEmptyFilesForArtifact)(downloadSpecification.emptyFilesToCreate); + yield downloadHttpClient.downloadSingleArtifact(downloadSpecification.filesToDownload); + } + return { + artifactName: name, + downloadPath: downloadSpecification.rootDownloadLocation + }; + }); + } + downloadAllArtifacts(path) { + return __awaiter(this, void 0, void 0, function* () { + const downloadHttpClient = new download_http_client_1.DownloadHttpClient(); + const response = []; + const artifacts = yield downloadHttpClient.listArtifacts(); + if (artifacts.count === 0) { + core.info('Unable to find any artifacts for the associated workflow'); + return response; + } + if (!path) { + path = (0, config_variables_1.getWorkSpaceDirectory)(); + } + path = (0, path_1.normalize)(path); + path = (0, path_1.resolve)(path); + let downloadedArtifacts = 0; + while (downloadedArtifacts < artifacts.count) { + const currentArtifactToDownload = artifacts.value[downloadedArtifacts]; + downloadedArtifacts += 1; + core.info(`starting download of artifact ${currentArtifactToDownload.name} : ${downloadedArtifacts}/${artifacts.count}`); + // Get container entries for the specific artifact + const items = yield downloadHttpClient.getContainerItems(currentArtifactToDownload.name, currentArtifactToDownload.fileContainerResourceUrl); + const downloadSpecification = (0, download_specification_1.getDownloadSpecification)(currentArtifactToDownload.name, items.value, path, true); + if (downloadSpecification.filesToDownload.length === 0) { + core.info(`No downloadable files were found for any artifact ${currentArtifactToDownload.name}`); + } + else { + yield (0, utils_1.createDirectoriesForArtifact)(downloadSpecification.directoryStructure); + yield (0, utils_1.createEmptyFilesForArtifact)(downloadSpecification.emptyFilesToCreate); + yield downloadHttpClient.downloadSingleArtifact(downloadSpecification.filesToDownload); + } + response.push({ + artifactName: currentArtifactToDownload.name, + downloadPath: downloadSpecification.rootDownloadLocation + }); + } + return response; + }); + } +} +exports.DefaultArtifactClient = DefaultArtifactClient; +//# sourceMappingURL=artifact-client.js.map + +/***/ }), + +/***/ 49388: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isGhes = exports.getRetentionDays = exports.getWorkSpaceDirectory = exports.getWorkFlowRunId = exports.getRuntimeUrl = exports.getRuntimeToken = exports.getDownloadFileConcurrency = exports.getInitialRetryIntervalInMilliseconds = exports.getRetryMultiplier = exports.getRetryLimit = exports.getUploadChunkSize = exports.getUploadFileConcurrency = void 0; +// The number of concurrent uploads that happens at the same time +function getUploadFileConcurrency() { + return 2; +} +exports.getUploadFileConcurrency = getUploadFileConcurrency; +// When uploading large files that can't be uploaded with a single http call, this controls +// the chunk size that is used during upload +function getUploadChunkSize() { + return 8 * 1024 * 1024; // 8 MB Chunks +} +exports.getUploadChunkSize = getUploadChunkSize; +// The maximum number of retries that can be attempted before an upload or download fails +function getRetryLimit() { + return 5; +} +exports.getRetryLimit = getRetryLimit; +// With exponential backoff, the larger the retry count, the larger the wait time before another attempt +// The retry multiplier controls by how much the backOff time increases depending on the number of retries +function getRetryMultiplier() { + return 1.5; +} +exports.getRetryMultiplier = getRetryMultiplier; +// The initial wait time if an upload or download fails and a retry is being attempted for the first time +function getInitialRetryIntervalInMilliseconds() { + return 3000; +} +exports.getInitialRetryIntervalInMilliseconds = getInitialRetryIntervalInMilliseconds; +// The number of concurrent downloads that happens at the same time +function getDownloadFileConcurrency() { + return 2; +} +exports.getDownloadFileConcurrency = getDownloadFileConcurrency; +function getRuntimeToken() { + const token = process.env['ACTIONS_RUNTIME_TOKEN']; + if (!token) { + throw new Error('Unable to get ACTIONS_RUNTIME_TOKEN env variable'); + } + return token; +} +exports.getRuntimeToken = getRuntimeToken; +function getRuntimeUrl() { + const runtimeUrl = process.env['ACTIONS_RUNTIME_URL']; + if (!runtimeUrl) { + throw new Error('Unable to get ACTIONS_RUNTIME_URL env variable'); + } + return runtimeUrl; +} +exports.getRuntimeUrl = getRuntimeUrl; +function getWorkFlowRunId() { + const workFlowRunId = process.env['GITHUB_RUN_ID']; + if (!workFlowRunId) { + throw new Error('Unable to get GITHUB_RUN_ID env variable'); + } + return workFlowRunId; +} +exports.getWorkFlowRunId = getWorkFlowRunId; +function getWorkSpaceDirectory() { + const workspaceDirectory = process.env['GITHUB_WORKSPACE']; + if (!workspaceDirectory) { + throw new Error('Unable to get GITHUB_WORKSPACE env variable'); + } + return workspaceDirectory; +} +exports.getWorkSpaceDirectory = getWorkSpaceDirectory; +function getRetentionDays() { + return process.env['GITHUB_RETENTION_DAYS']; +} +exports.getRetentionDays = getRetentionDays; +function isGhes() { + const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); + return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; +} +exports.isGhes = isGhes; +//# sourceMappingURL=config-variables.js.map + +/***/ }), + +/***/ 1116: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +/** + * CRC64: cyclic redundancy check, 64-bits + * + * In order to validate that artifacts are not being corrupted over the wire, this redundancy check allows us to + * validate that there was no corruption during transmission. The implementation here is based on Go's hash/crc64 pkg, + * but without the slicing-by-8 optimization: https://cs.opensource.google/go/go/+/master:src/hash/crc64/crc64.go + * + * This implementation uses a pregenerated table based on 0x9A6C9329AC4BC9B5 as the polynomial, the same polynomial that + * is used for Azure Storage: https://github.com/Azure/azure-storage-net/blob/cbe605f9faa01bfc3003d75fc5a16b2eaccfe102/Lib/Common/Core/Util/Crc64.cs#L27 + */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +// when transpile target is >= ES2020 (after dropping node 12) these can be changed to bigint literals - ts(2737) +const PREGEN_POLY_TABLE = [ + BigInt('0x0000000000000000'), + BigInt('0x7F6EF0C830358979'), + BigInt('0xFEDDE190606B12F2'), + BigInt('0x81B31158505E9B8B'), + BigInt('0xC962E5739841B68F'), + BigInt('0xB60C15BBA8743FF6'), + BigInt('0x37BF04E3F82AA47D'), + BigInt('0x48D1F42BC81F2D04'), + BigInt('0xA61CECB46814FE75'), + BigInt('0xD9721C7C5821770C'), + BigInt('0x58C10D24087FEC87'), + BigInt('0x27AFFDEC384A65FE'), + BigInt('0x6F7E09C7F05548FA'), + BigInt('0x1010F90FC060C183'), + BigInt('0x91A3E857903E5A08'), + BigInt('0xEECD189FA00BD371'), + BigInt('0x78E0FF3B88BE6F81'), + BigInt('0x078E0FF3B88BE6F8'), + BigInt('0x863D1EABE8D57D73'), + BigInt('0xF953EE63D8E0F40A'), + BigInt('0xB1821A4810FFD90E'), + BigInt('0xCEECEA8020CA5077'), + BigInt('0x4F5FFBD87094CBFC'), + BigInt('0x30310B1040A14285'), + BigInt('0xDEFC138FE0AA91F4'), + BigInt('0xA192E347D09F188D'), + BigInt('0x2021F21F80C18306'), + BigInt('0x5F4F02D7B0F40A7F'), + BigInt('0x179EF6FC78EB277B'), + BigInt('0x68F0063448DEAE02'), + BigInt('0xE943176C18803589'), + BigInt('0x962DE7A428B5BCF0'), + BigInt('0xF1C1FE77117CDF02'), + BigInt('0x8EAF0EBF2149567B'), + BigInt('0x0F1C1FE77117CDF0'), + BigInt('0x7072EF2F41224489'), + BigInt('0x38A31B04893D698D'), + BigInt('0x47CDEBCCB908E0F4'), + BigInt('0xC67EFA94E9567B7F'), + BigInt('0xB9100A5CD963F206'), + BigInt('0x57DD12C379682177'), + BigInt('0x28B3E20B495DA80E'), + BigInt('0xA900F35319033385'), + BigInt('0xD66E039B2936BAFC'), + BigInt('0x9EBFF7B0E12997F8'), + BigInt('0xE1D10778D11C1E81'), + BigInt('0x606216208142850A'), + BigInt('0x1F0CE6E8B1770C73'), + BigInt('0x8921014C99C2B083'), + BigInt('0xF64FF184A9F739FA'), + BigInt('0x77FCE0DCF9A9A271'), + BigInt('0x08921014C99C2B08'), + BigInt('0x4043E43F0183060C'), + BigInt('0x3F2D14F731B68F75'), + BigInt('0xBE9E05AF61E814FE'), + BigInt('0xC1F0F56751DD9D87'), + BigInt('0x2F3DEDF8F1D64EF6'), + BigInt('0x50531D30C1E3C78F'), + BigInt('0xD1E00C6891BD5C04'), + BigInt('0xAE8EFCA0A188D57D'), + BigInt('0xE65F088B6997F879'), + BigInt('0x9931F84359A27100'), + BigInt('0x1882E91B09FCEA8B'), + BigInt('0x67EC19D339C963F2'), + BigInt('0xD75ADABD7A6E2D6F'), + BigInt('0xA8342A754A5BA416'), + BigInt('0x29873B2D1A053F9D'), + BigInt('0x56E9CBE52A30B6E4'), + BigInt('0x1E383FCEE22F9BE0'), + BigInt('0x6156CF06D21A1299'), + BigInt('0xE0E5DE5E82448912'), + BigInt('0x9F8B2E96B271006B'), + BigInt('0x71463609127AD31A'), + BigInt('0x0E28C6C1224F5A63'), + BigInt('0x8F9BD7997211C1E8'), + BigInt('0xF0F5275142244891'), + BigInt('0xB824D37A8A3B6595'), + BigInt('0xC74A23B2BA0EECEC'), + BigInt('0x46F932EAEA507767'), + BigInt('0x3997C222DA65FE1E'), + BigInt('0xAFBA2586F2D042EE'), + BigInt('0xD0D4D54EC2E5CB97'), + BigInt('0x5167C41692BB501C'), + BigInt('0x2E0934DEA28ED965'), + BigInt('0x66D8C0F56A91F461'), + BigInt('0x19B6303D5AA47D18'), + BigInt('0x980521650AFAE693'), + BigInt('0xE76BD1AD3ACF6FEA'), + BigInt('0x09A6C9329AC4BC9B'), + BigInt('0x76C839FAAAF135E2'), + BigInt('0xF77B28A2FAAFAE69'), + BigInt('0x8815D86ACA9A2710'), + BigInt('0xC0C42C4102850A14'), + BigInt('0xBFAADC8932B0836D'), + BigInt('0x3E19CDD162EE18E6'), + BigInt('0x41773D1952DB919F'), + BigInt('0x269B24CA6B12F26D'), + BigInt('0x59F5D4025B277B14'), + BigInt('0xD846C55A0B79E09F'), + BigInt('0xA72835923B4C69E6'), + BigInt('0xEFF9C1B9F35344E2'), + BigInt('0x90973171C366CD9B'), + BigInt('0x1124202993385610'), + BigInt('0x6E4AD0E1A30DDF69'), + BigInt('0x8087C87E03060C18'), + BigInt('0xFFE938B633338561'), + BigInt('0x7E5A29EE636D1EEA'), + BigInt('0x0134D92653589793'), + BigInt('0x49E52D0D9B47BA97'), + BigInt('0x368BDDC5AB7233EE'), + BigInt('0xB738CC9DFB2CA865'), + BigInt('0xC8563C55CB19211C'), + BigInt('0x5E7BDBF1E3AC9DEC'), + BigInt('0x21152B39D3991495'), + BigInt('0xA0A63A6183C78F1E'), + BigInt('0xDFC8CAA9B3F20667'), + BigInt('0x97193E827BED2B63'), + BigInt('0xE877CE4A4BD8A21A'), + BigInt('0x69C4DF121B863991'), + BigInt('0x16AA2FDA2BB3B0E8'), + BigInt('0xF86737458BB86399'), + BigInt('0x8709C78DBB8DEAE0'), + BigInt('0x06BAD6D5EBD3716B'), + BigInt('0x79D4261DDBE6F812'), + BigInt('0x3105D23613F9D516'), + BigInt('0x4E6B22FE23CC5C6F'), + BigInt('0xCFD833A67392C7E4'), + BigInt('0xB0B6C36E43A74E9D'), + BigInt('0x9A6C9329AC4BC9B5'), + BigInt('0xE50263E19C7E40CC'), + BigInt('0x64B172B9CC20DB47'), + BigInt('0x1BDF8271FC15523E'), + BigInt('0x530E765A340A7F3A'), + BigInt('0x2C608692043FF643'), + BigInt('0xADD397CA54616DC8'), + BigInt('0xD2BD67026454E4B1'), + BigInt('0x3C707F9DC45F37C0'), + BigInt('0x431E8F55F46ABEB9'), + BigInt('0xC2AD9E0DA4342532'), + BigInt('0xBDC36EC59401AC4B'), + BigInt('0xF5129AEE5C1E814F'), + BigInt('0x8A7C6A266C2B0836'), + BigInt('0x0BCF7B7E3C7593BD'), + BigInt('0x74A18BB60C401AC4'), + BigInt('0xE28C6C1224F5A634'), + BigInt('0x9DE29CDA14C02F4D'), + BigInt('0x1C518D82449EB4C6'), + BigInt('0x633F7D4A74AB3DBF'), + BigInt('0x2BEE8961BCB410BB'), + BigInt('0x548079A98C8199C2'), + BigInt('0xD53368F1DCDF0249'), + BigInt('0xAA5D9839ECEA8B30'), + BigInt('0x449080A64CE15841'), + BigInt('0x3BFE706E7CD4D138'), + BigInt('0xBA4D61362C8A4AB3'), + BigInt('0xC52391FE1CBFC3CA'), + BigInt('0x8DF265D5D4A0EECE'), + BigInt('0xF29C951DE49567B7'), + BigInt('0x732F8445B4CBFC3C'), + BigInt('0x0C41748D84FE7545'), + BigInt('0x6BAD6D5EBD3716B7'), + BigInt('0x14C39D968D029FCE'), + BigInt('0x95708CCEDD5C0445'), + BigInt('0xEA1E7C06ED698D3C'), + BigInt('0xA2CF882D2576A038'), + BigInt('0xDDA178E515432941'), + BigInt('0x5C1269BD451DB2CA'), + BigInt('0x237C997575283BB3'), + BigInt('0xCDB181EAD523E8C2'), + BigInt('0xB2DF7122E51661BB'), + BigInt('0x336C607AB548FA30'), + BigInt('0x4C0290B2857D7349'), + BigInt('0x04D364994D625E4D'), + BigInt('0x7BBD94517D57D734'), + BigInt('0xFA0E85092D094CBF'), + BigInt('0x856075C11D3CC5C6'), + BigInt('0x134D926535897936'), + BigInt('0x6C2362AD05BCF04F'), + BigInt('0xED9073F555E26BC4'), + BigInt('0x92FE833D65D7E2BD'), + BigInt('0xDA2F7716ADC8CFB9'), + BigInt('0xA54187DE9DFD46C0'), + BigInt('0x24F29686CDA3DD4B'), + BigInt('0x5B9C664EFD965432'), + BigInt('0xB5517ED15D9D8743'), + BigInt('0xCA3F8E196DA80E3A'), + BigInt('0x4B8C9F413DF695B1'), + BigInt('0x34E26F890DC31CC8'), + BigInt('0x7C339BA2C5DC31CC'), + BigInt('0x035D6B6AF5E9B8B5'), + BigInt('0x82EE7A32A5B7233E'), + BigInt('0xFD808AFA9582AA47'), + BigInt('0x4D364994D625E4DA'), + BigInt('0x3258B95CE6106DA3'), + BigInt('0xB3EBA804B64EF628'), + BigInt('0xCC8558CC867B7F51'), + BigInt('0x8454ACE74E645255'), + BigInt('0xFB3A5C2F7E51DB2C'), + BigInt('0x7A894D772E0F40A7'), + BigInt('0x05E7BDBF1E3AC9DE'), + BigInt('0xEB2AA520BE311AAF'), + BigInt('0x944455E88E0493D6'), + BigInt('0x15F744B0DE5A085D'), + BigInt('0x6A99B478EE6F8124'), + BigInt('0x224840532670AC20'), + BigInt('0x5D26B09B16452559'), + BigInt('0xDC95A1C3461BBED2'), + BigInt('0xA3FB510B762E37AB'), + BigInt('0x35D6B6AF5E9B8B5B'), + BigInt('0x4AB846676EAE0222'), + BigInt('0xCB0B573F3EF099A9'), + BigInt('0xB465A7F70EC510D0'), + BigInt('0xFCB453DCC6DA3DD4'), + BigInt('0x83DAA314F6EFB4AD'), + BigInt('0x0269B24CA6B12F26'), + BigInt('0x7D0742849684A65F'), + BigInt('0x93CA5A1B368F752E'), + BigInt('0xECA4AAD306BAFC57'), + BigInt('0x6D17BB8B56E467DC'), + BigInt('0x12794B4366D1EEA5'), + BigInt('0x5AA8BF68AECEC3A1'), + BigInt('0x25C64FA09EFB4AD8'), + BigInt('0xA4755EF8CEA5D153'), + BigInt('0xDB1BAE30FE90582A'), + BigInt('0xBCF7B7E3C7593BD8'), + BigInt('0xC399472BF76CB2A1'), + BigInt('0x422A5673A732292A'), + BigInt('0x3D44A6BB9707A053'), + BigInt('0x759552905F188D57'), + BigInt('0x0AFBA2586F2D042E'), + BigInt('0x8B48B3003F739FA5'), + BigInt('0xF42643C80F4616DC'), + BigInt('0x1AEB5B57AF4DC5AD'), + BigInt('0x6585AB9F9F784CD4'), + BigInt('0xE436BAC7CF26D75F'), + BigInt('0x9B584A0FFF135E26'), + BigInt('0xD389BE24370C7322'), + BigInt('0xACE74EEC0739FA5B'), + BigInt('0x2D545FB4576761D0'), + BigInt('0x523AAF7C6752E8A9'), + BigInt('0xC41748D84FE75459'), + BigInt('0xBB79B8107FD2DD20'), + BigInt('0x3ACAA9482F8C46AB'), + BigInt('0x45A459801FB9CFD2'), + BigInt('0x0D75ADABD7A6E2D6'), + BigInt('0x721B5D63E7936BAF'), + BigInt('0xF3A84C3BB7CDF024'), + BigInt('0x8CC6BCF387F8795D'), + BigInt('0x620BA46C27F3AA2C'), + BigInt('0x1D6554A417C62355'), + BigInt('0x9CD645FC4798B8DE'), + BigInt('0xE3B8B53477AD31A7'), + BigInt('0xAB69411FBFB21CA3'), + BigInt('0xD407B1D78F8795DA'), + BigInt('0x55B4A08FDFD90E51'), + BigInt('0x2ADA5047EFEC8728') +]; +class CRC64 { + constructor() { + this._crc = BigInt(0); + } + update(data) { + const buffer = typeof data === 'string' ? Buffer.from(data) : data; + let crc = CRC64.flip64Bits(this._crc); + for (const dataByte of buffer) { + const crcByte = Number(crc & BigInt(0xff)); + crc = PREGEN_POLY_TABLE[crcByte ^ dataByte] ^ (crc >> BigInt(8)); + } + this._crc = CRC64.flip64Bits(crc); + } + digest(encoding) { + switch (encoding) { + case 'hex': + return this._crc.toString(16).toUpperCase(); + case 'base64': + return this.toBuffer().toString('base64'); + default: + return this.toBuffer(); + } + } + toBuffer() { + return Buffer.from([0, 8, 16, 24, 32, 40, 48, 56].map(s => Number((this._crc >> BigInt(s)) & BigInt(0xff)))); + } + static flip64Bits(n) { + return (BigInt(1) << BigInt(64)) - BigInt(1) - n; + } +} +exports["default"] = CRC64; +//# sourceMappingURL=crc64.js.map + +/***/ }), + +/***/ 79063: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.DownloadHttpClient = void 0; +const fs = __importStar(__nccwpck_require__(79896)); +const core = __importStar(__nccwpck_require__(37484)); +const zlib = __importStar(__nccwpck_require__(43106)); +const utils_1 = __nccwpck_require__(24149); +const url_1 = __nccwpck_require__(87016); +const status_reporter_1 = __nccwpck_require__(85572); +const perf_hooks_1 = __nccwpck_require__(82987); +const http_manager_1 = __nccwpck_require__(72448); +const config_variables_1 = __nccwpck_require__(49388); +const requestUtils_1 = __nccwpck_require__(93912); +class DownloadHttpClient { + constructor() { + this.downloadHttpManager = new http_manager_1.HttpManager((0, config_variables_1.getDownloadFileConcurrency)(), '@actions/artifact-download'); + // downloads are usually significantly faster than uploads so display status information every second + this.statusReporter = new status_reporter_1.StatusReporter(1000); + } + /** + * Gets a list of all artifacts that are in a specific container + */ + listArtifacts() { + return __awaiter(this, void 0, void 0, function* () { + const artifactUrl = (0, utils_1.getArtifactUrl)(); + // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately + const client = this.downloadHttpManager.getClient(0); + const headers = (0, utils_1.getDownloadHeaders)('application/json'); + const response = yield (0, requestUtils_1.retryHttpClientRequest)('List Artifacts', () => __awaiter(this, void 0, void 0, function* () { return client.get(artifactUrl, headers); })); + const body = yield response.readBody(); + return JSON.parse(body); + }); + } + /** + * Fetches a set of container items that describe the contents of an artifact + * @param artifactName the name of the artifact + * @param containerUrl the artifact container URL for the run + */ + getContainerItems(artifactName, containerUrl) { + return __awaiter(this, void 0, void 0, function* () { + // the itemPath search parameter controls which containers will be returned + const resourceUrl = new url_1.URL(containerUrl); + resourceUrl.searchParams.append('itemPath', artifactName); + // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately + const client = this.downloadHttpManager.getClient(0); + const headers = (0, utils_1.getDownloadHeaders)('application/json'); + const response = yield (0, requestUtils_1.retryHttpClientRequest)('Get Container Items', () => __awaiter(this, void 0, void 0, function* () { return client.get(resourceUrl.toString(), headers); })); + const body = yield response.readBody(); + return JSON.parse(body); + }); + } + /** + * Concurrently downloads all the files that are part of an artifact + * @param downloadItems information about what items to download and where to save them + */ + downloadSingleArtifact(downloadItems) { + return __awaiter(this, void 0, void 0, function* () { + const DOWNLOAD_CONCURRENCY = (0, config_variables_1.getDownloadFileConcurrency)(); + // limit the number of files downloaded at a single time + core.debug(`Download file concurrency is set to ${DOWNLOAD_CONCURRENCY}`); + const parallelDownloads = [...new Array(DOWNLOAD_CONCURRENCY).keys()]; + let currentFile = 0; + let downloadedFiles = 0; + core.info(`Total number of files that will be downloaded: ${downloadItems.length}`); + this.statusReporter.setTotalNumberOfFilesToProcess(downloadItems.length); + this.statusReporter.start(); + yield Promise.all(parallelDownloads.map((index) => __awaiter(this, void 0, void 0, function* () { + while (currentFile < downloadItems.length) { + const currentFileToDownload = downloadItems[currentFile]; + currentFile += 1; + const startTime = perf_hooks_1.performance.now(); + yield this.downloadIndividualFile(index, currentFileToDownload.sourceLocation, currentFileToDownload.targetPath); + if (core.isDebug()) { + core.debug(`File: ${++downloadedFiles}/${downloadItems.length}. ${currentFileToDownload.targetPath} took ${(perf_hooks_1.performance.now() - startTime).toFixed(3)} milliseconds to finish downloading`); + } + this.statusReporter.incrementProcessedCount(); + } + }))) + .catch(error => { + throw new Error(`Unable to download the artifact: ${error}`); + }) + .finally(() => { + this.statusReporter.stop(); + // safety dispose all connections + this.downloadHttpManager.disposeAndReplaceAllClients(); + }); + }); + } + /** + * Downloads an individual file + * @param httpClientIndex the index of the http client that is used to make all of the calls + * @param artifactLocation origin location where a file will be downloaded from + * @param downloadPath destination location for the file being downloaded + */ + downloadIndividualFile(httpClientIndex, artifactLocation, downloadPath) { + return __awaiter(this, void 0, void 0, function* () { + let retryCount = 0; + const retryLimit = (0, config_variables_1.getRetryLimit)(); + let destinationStream = fs.createWriteStream(downloadPath); + const headers = (0, utils_1.getDownloadHeaders)('application/json', true, true); + // a single GET request is used to download a file + const makeDownloadRequest = () => __awaiter(this, void 0, void 0, function* () { + const client = this.downloadHttpManager.getClient(httpClientIndex); + return yield client.get(artifactLocation, headers); + }); + // check the response headers to determine if the file was compressed using gzip + const isGzip = (incomingHeaders) => { + return ('content-encoding' in incomingHeaders && + incomingHeaders['content-encoding'] === 'gzip'); + }; + // Increments the current retry count and then checks if the retry limit has been reached + // If there have been too many retries, fail so the download stops. If there is a retryAfterValue value provided, + // it will be used + const backOff = (retryAfterValue) => __awaiter(this, void 0, void 0, function* () { + retryCount++; + if (retryCount > retryLimit) { + return Promise.reject(new Error(`Retry limit has been reached. Unable to download ${artifactLocation}`)); + } + else { + this.downloadHttpManager.disposeAndReplaceClient(httpClientIndex); + if (retryAfterValue) { + // Back off by waiting the specified time denoted by the retry-after header + core.info(`Backoff due to too many requests, retry #${retryCount}. Waiting for ${retryAfterValue} milliseconds before continuing the download`); + yield (0, utils_1.sleep)(retryAfterValue); + } + else { + // Back off using an exponential value that depends on the retry count + const backoffTime = (0, utils_1.getExponentialRetryTimeInMilliseconds)(retryCount); + core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the download`); + yield (0, utils_1.sleep)(backoffTime); + } + core.info(`Finished backoff for retry #${retryCount}, continuing with download`); + } + }); + const isAllBytesReceived = (expected, received) => { + // be lenient, if any input is missing, assume success, i.e. not truncated + if (!expected || + !received || + process.env['ACTIONS_ARTIFACT_SKIP_DOWNLOAD_VALIDATION']) { + core.info('Skipping download validation.'); + return true; + } + return parseInt(expected) === received; + }; + const resetDestinationStream = (fileDownloadPath) => __awaiter(this, void 0, void 0, function* () { + destinationStream.close(); + // await until file is created at downloadpath; node15 and up fs.createWriteStream had not created a file yet + yield new Promise(resolve => { + destinationStream.on('close', resolve); + if (destinationStream.writableFinished) { + resolve(); + } + }); + yield (0, utils_1.rmFile)(fileDownloadPath); + destinationStream = fs.createWriteStream(fileDownloadPath); + }); + // keep trying to download a file until a retry limit has been reached + while (retryCount <= retryLimit) { + let response; + try { + response = yield makeDownloadRequest(); + } + catch (error) { + // if an error is caught, it is usually indicative of a timeout so retry the download + core.info('An error occurred while attempting to download a file'); + // eslint-disable-next-line no-console + console.log(error); + // increment the retryCount and use exponential backoff to wait before making the next request + yield backOff(); + continue; + } + let forceRetry = false; + if ((0, utils_1.isSuccessStatusCode)(response.message.statusCode)) { + // The body contains the contents of the file however calling response.readBody() causes all the content to be converted to a string + // which can cause some gzip encoded data to be lost + // Instead of using response.readBody(), response.message is a readableStream that can be directly used to get the raw body contents + try { + const isGzipped = isGzip(response.message.headers); + yield this.pipeResponseToFile(response, destinationStream, isGzipped); + if (isGzipped || + isAllBytesReceived(response.message.headers['content-length'], yield (0, utils_1.getFileSize)(downloadPath))) { + return; + } + else { + forceRetry = true; + } + } + catch (error) { + // retry on error, most likely streams were corrupted + forceRetry = true; + } + } + if (forceRetry || (0, utils_1.isRetryableStatusCode)(response.message.statusCode)) { + core.info(`A ${response.message.statusCode} response code has been received while attempting to download an artifact`); + resetDestinationStream(downloadPath); + // if a throttled status code is received, try to get the retryAfter header value, else differ to standard exponential backoff + (0, utils_1.isThrottledStatusCode)(response.message.statusCode) + ? yield backOff((0, utils_1.tryGetRetryAfterValueTimeInMilliseconds)(response.message.headers)) + : yield backOff(); + } + else { + // Some unexpected response code, fail immediately and stop the download + (0, utils_1.displayHttpDiagnostics)(response); + return Promise.reject(new Error(`Unexpected http ${response.message.statusCode} during download for ${artifactLocation}`)); + } + } + }); + } + /** + * Pipes the response from downloading an individual file to the appropriate destination stream while decoding gzip content if necessary + * @param response the http response received when downloading a file + * @param destinationStream the stream where the file should be written to + * @param isGzip a boolean denoting if the content is compressed using gzip and if we need to decode it + */ + pipeResponseToFile(response, destinationStream, isGzip) { + return __awaiter(this, void 0, void 0, function* () { + yield new Promise((resolve, reject) => { + if (isGzip) { + const gunzip = zlib.createGunzip(); + response.message + .on('error', error => { + core.info(`An error occurred while attempting to read the response stream`); + gunzip.close(); + destinationStream.close(); + reject(error); + }) + .pipe(gunzip) + .on('error', error => { + core.info(`An error occurred while attempting to decompress the response stream`); + destinationStream.close(); + reject(error); + }) + .pipe(destinationStream) + .on('close', () => { + resolve(); + }) + .on('error', error => { + core.info(`An error occurred while writing a downloaded file to ${destinationStream.path}`); + reject(error); + }); + } + else { + response.message + .on('error', error => { + core.info(`An error occurred while attempting to read the response stream`); + destinationStream.close(); + reject(error); + }) + .pipe(destinationStream) + .on('close', () => { + resolve(); + }) + .on('error', error => { + core.info(`An error occurred while writing a downloaded file to ${destinationStream.path}`); + reject(error); + }); + } + }); + return; + }); + } +} +exports.DownloadHttpClient = DownloadHttpClient; +//# sourceMappingURL=download-http-client.js.map + +/***/ }), + +/***/ 23718: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getDownloadSpecification = void 0; +const path = __importStar(__nccwpck_require__(16928)); +/** + * Creates a specification for a set of files that will be downloaded + * @param artifactName the name of the artifact + * @param artifactEntries a set of container entries that describe that files that make up an artifact + * @param downloadPath the path where the artifact will be downloaded to + * @param includeRootDirectory specifies if there should be an extra directory (denoted by the artifact name) where the artifact files should be downloaded to + */ +function getDownloadSpecification(artifactName, artifactEntries, downloadPath, includeRootDirectory) { + // use a set for the directory paths so that there are no duplicates + const directories = new Set(); + const specifications = { + rootDownloadLocation: includeRootDirectory + ? path.join(downloadPath, artifactName) + : downloadPath, + directoryStructure: [], + emptyFilesToCreate: [], + filesToDownload: [] + }; + for (const entry of artifactEntries) { + // Ignore artifacts in the container that don't begin with the same name + if (entry.path.startsWith(`${artifactName}/`) || + entry.path.startsWith(`${artifactName}\\`)) { + // normalize all separators to the local OS + const normalizedPathEntry = path.normalize(entry.path); + // entry.path always starts with the artifact name, if includeRootDirectory is false, remove the name from the beginning of the path + const filePath = path.join(downloadPath, includeRootDirectory + ? normalizedPathEntry + : normalizedPathEntry.replace(artifactName, '')); + // Case insensitive folder structure maintained in the backend, not every folder is created so the 'folder' + // itemType cannot be relied upon. The file must be used to determine the directory structure + if (entry.itemType === 'file') { + // Get the directories that we need to create from the filePath for each individual file + directories.add(path.dirname(filePath)); + if (entry.fileLength === 0) { + // An empty file was uploaded, create the empty files locally so that no extra http calls are made + specifications.emptyFilesToCreate.push(filePath); + } + else { + specifications.filesToDownload.push({ + sourceLocation: entry.contentLocation, + targetPath: filePath + }); + } + } + } + } + specifications.directoryStructure = Array.from(directories); + return specifications; +} +exports.getDownloadSpecification = getDownloadSpecification; +//# sourceMappingURL=download-specification.js.map + +/***/ }), + +/***/ 72448: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.HttpManager = void 0; +const utils_1 = __nccwpck_require__(24149); +/** + * Used for managing http clients during either upload or download + */ +class HttpManager { + constructor(clientCount, userAgent) { + if (clientCount < 1) { + throw new Error('There must be at least one client'); + } + this.userAgent = userAgent; + this.clients = new Array(clientCount).fill((0, utils_1.createHttpClient)(userAgent)); + } + getClient(index) { + return this.clients[index]; + } + // client disposal is necessary if a keep-alive connection is used to properly close the connection + // for more information see: https://github.com/actions/http-client/blob/04e5ad73cd3fd1f5610a32116b0759eddf6570d2/index.ts#L292 + disposeAndReplaceClient(index) { + this.clients[index].dispose(); + this.clients[index] = (0, utils_1.createHttpClient)(this.userAgent); + } + disposeAndReplaceAllClients() { + for (const [index] of this.clients.entries()) { + this.disposeAndReplaceClient(index); + } + } +} +exports.HttpManager = HttpManager; +//# sourceMappingURL=http-manager.js.map + +/***/ }), + +/***/ 53520: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.checkArtifactFilePath = exports.checkArtifactName = void 0; +const core_1 = __nccwpck_require__(37484); +/** + * Invalid characters that cannot be in the artifact name or an uploaded file. Will be rejected + * from the server if attempted to be sent over. These characters are not allowed due to limitations with certain + * file systems such as NTFS. To maintain platform-agnostic behavior, all characters that are not supported by an + * individual filesystem/platform will not be supported on all fileSystems/platforms + * + * FilePaths can include characters such as \ and / which are not permitted in the artifact name alone + */ +const invalidArtifactFilePathCharacters = new Map([ + ['"', ' Double quote "'], + [':', ' Colon :'], + ['<', ' Less than <'], + ['>', ' Greater than >'], + ['|', ' Vertical bar |'], + ['*', ' Asterisk *'], + ['?', ' Question mark ?'], + ['\r', ' Carriage return \\r'], + ['\n', ' Line feed \\n'] +]); +const invalidArtifactNameCharacters = new Map([ + ...invalidArtifactFilePathCharacters, + ['\\', ' Backslash \\'], + ['/', ' Forward slash /'] +]); +/** + * Scans the name of the artifact to make sure there are no illegal characters + */ +function checkArtifactName(name) { + if (!name) { + throw new Error(`Artifact name: ${name}, is incorrectly provided`); + } + for (const [invalidCharacterKey, errorMessageForCharacter] of invalidArtifactNameCharacters) { + if (name.includes(invalidCharacterKey)) { + throw new Error(`Artifact name is not valid: ${name}. Contains the following character: ${errorMessageForCharacter} + +Invalid characters include: ${Array.from(invalidArtifactNameCharacters.values()).toString()} + +These characters are not allowed in the artifact name due to limitations with certain file systems such as NTFS. To maintain file system agnostic behavior, these characters are intentionally not allowed to prevent potential problems with downloads on different file systems.`); + } + } + (0, core_1.info)(`Artifact name is valid!`); +} +exports.checkArtifactName = checkArtifactName; +/** + * Scans the name of the filePath used to make sure there are no illegal characters + */ +function checkArtifactFilePath(path) { + if (!path) { + throw new Error(`Artifact path: ${path}, is incorrectly provided`); + } + for (const [invalidCharacterKey, errorMessageForCharacter] of invalidArtifactFilePathCharacters) { + if (path.includes(invalidCharacterKey)) { + throw new Error(`Artifact path is not valid: ${path}. Contains the following character: ${errorMessageForCharacter} + +Invalid characters include: ${Array.from(invalidArtifactFilePathCharacters.values()).toString()} + +The following characters are not allowed in files that are uploaded due to limitations with certain file systems such as NTFS. To maintain file system agnostic behavior, these characters are intentionally not allowed to prevent potential problems with downloads on different file systems. + `); + } + } +} +exports.checkArtifactFilePath = checkArtifactFilePath; +//# sourceMappingURL=path-and-artifact-name-validation.js.map + +/***/ }), + +/***/ 93912: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.retryHttpClientRequest = exports.retry = void 0; +const utils_1 = __nccwpck_require__(24149); +const core = __importStar(__nccwpck_require__(37484)); +const config_variables_1 = __nccwpck_require__(49388); +function retry(name, operation, customErrorMessages, maxAttempts) { + return __awaiter(this, void 0, void 0, function* () { + let response = undefined; + let statusCode = undefined; + let isRetryable = false; + let errorMessage = ''; + let customErrorInformation = undefined; + let attempt = 1; + while (attempt <= maxAttempts) { + try { + response = yield operation(); + statusCode = response.message.statusCode; + if ((0, utils_1.isSuccessStatusCode)(statusCode)) { + return response; + } + // Extra error information that we want to display if a particular response code is hit + if (statusCode) { + customErrorInformation = customErrorMessages.get(statusCode); + } + isRetryable = (0, utils_1.isRetryableStatusCode)(statusCode); + errorMessage = `Artifact service responded with ${statusCode}`; + } + catch (error) { + isRetryable = true; + errorMessage = error.message; + } + if (!isRetryable) { + core.info(`${name} - Error is not retryable`); + if (response) { + (0, utils_1.displayHttpDiagnostics)(response); + } + break; + } + core.info(`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`); + yield (0, utils_1.sleep)((0, utils_1.getExponentialRetryTimeInMilliseconds)(attempt)); + attempt++; + } + if (response) { + (0, utils_1.displayHttpDiagnostics)(response); + } + if (customErrorInformation) { + throw Error(`${name} failed: ${customErrorInformation}`); + } + throw Error(`${name} failed: ${errorMessage}`); + }); +} +exports.retry = retry; +function retryHttpClientRequest(name, method, customErrorMessages = new Map(), maxAttempts = (0, config_variables_1.getRetryLimit)()) { + return __awaiter(this, void 0, void 0, function* () { + return yield retry(name, method, customErrorMessages, maxAttempts); + }); +} +exports.retryHttpClientRequest = retryHttpClientRequest; +//# sourceMappingURL=requestUtils.js.map + +/***/ }), + +/***/ 85572: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.StatusReporter = void 0; +const core_1 = __nccwpck_require__(37484); +/** + * Status Reporter that displays information about the progress/status of an artifact that is being uploaded or downloaded + * + * Variable display time that can be adjusted using the displayFrequencyInMilliseconds variable + * The total status of the upload/download gets displayed according to this value + * If there is a large file that is being uploaded, extra information about the individual status can also be displayed using the updateLargeFileStatus function + */ +class StatusReporter { + constructor(displayFrequencyInMilliseconds) { + this.totalNumberOfFilesToProcess = 0; + this.processedCount = 0; + this.largeFiles = new Map(); + this.totalFileStatus = undefined; + this.displayFrequencyInMilliseconds = displayFrequencyInMilliseconds; + } + setTotalNumberOfFilesToProcess(fileTotal) { + this.totalNumberOfFilesToProcess = fileTotal; + this.processedCount = 0; + } + start() { + // displays information about the total upload/download status + this.totalFileStatus = setInterval(() => { + // display 1 decimal place without any rounding + const percentage = this.formatPercentage(this.processedCount, this.totalNumberOfFilesToProcess); + (0, core_1.info)(`Total file count: ${this.totalNumberOfFilesToProcess} ---- Processed file #${this.processedCount} (${percentage.slice(0, percentage.indexOf('.') + 2)}%)`); + }, this.displayFrequencyInMilliseconds); + } + // if there is a large file that is being uploaded in chunks, this is used to display extra information about the status of the upload + updateLargeFileStatus(fileName, chunkStartIndex, chunkEndIndex, totalUploadFileSize) { + // display 1 decimal place without any rounding + const percentage = this.formatPercentage(chunkEndIndex, totalUploadFileSize); + (0, core_1.info)(`Uploaded ${fileName} (${percentage.slice(0, percentage.indexOf('.') + 2)}%) bytes ${chunkStartIndex}:${chunkEndIndex}`); + } + stop() { + if (this.totalFileStatus) { + clearInterval(this.totalFileStatus); + } + } + incrementProcessedCount() { + this.processedCount++; + } + formatPercentage(numerator, denominator) { + // toFixed() rounds, so use extra precision to display accurate information even though 4 decimal places are not displayed + return ((numerator / denominator) * 100).toFixed(4).toString(); + } +} +exports.StatusReporter = StatusReporter; +//# sourceMappingURL=status-reporter.js.map + +/***/ }), + +/***/ 86084: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __asyncValues = (this && this.__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); } +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.createGZipFileInBuffer = exports.createGZipFileOnDisk = void 0; +const fs = __importStar(__nccwpck_require__(79896)); +const zlib = __importStar(__nccwpck_require__(43106)); +const util_1 = __nccwpck_require__(39023); +const stat = (0, util_1.promisify)(fs.stat); +/** + * GZipping certain files that are already compressed will likely not yield further size reductions. Creating large temporary gzip + * files then will just waste a lot of time before ultimately being discarded (especially for very large files). + * If any of these types of files are encountered then on-disk gzip creation will be skipped and the original file will be uploaded as-is + */ +const gzipExemptFileExtensions = [ + '.gz', + '.gzip', + '.tgz', + '.taz', + '.Z', + '.taZ', + '.bz2', + '.tbz', + '.tbz2', + '.tz2', + '.lz', + '.lzma', + '.tlz', + '.lzo', + '.xz', + '.txz', + '.zst', + '.zstd', + '.tzst', + '.zip', + '.7z' // 7ZIP +]; +/** + * Creates a Gzip compressed file of an original file at the provided temporary filepath location + * @param {string} originalFilePath filepath of whatever will be compressed. The original file will be unmodified + * @param {string} tempFilePath the location of where the Gzip file will be created + * @returns the size of gzip file that gets created + */ +function createGZipFileOnDisk(originalFilePath, tempFilePath) { + return __awaiter(this, void 0, void 0, function* () { + for (const gzipExemptExtension of gzipExemptFileExtensions) { + if (originalFilePath.endsWith(gzipExemptExtension)) { + // return a really large number so that the original file gets uploaded + return Number.MAX_SAFE_INTEGER; + } + } + return new Promise((resolve, reject) => { + const inputStream = fs.createReadStream(originalFilePath); + const gzip = zlib.createGzip(); + const outputStream = fs.createWriteStream(tempFilePath); + inputStream.pipe(gzip).pipe(outputStream); + outputStream.on('finish', () => __awaiter(this, void 0, void 0, function* () { + // wait for stream to finish before calculating the size which is needed as part of the Content-Length header when starting an upload + const size = (yield stat(tempFilePath)).size; + resolve(size); + })); + outputStream.on('error', error => { + // eslint-disable-next-line no-console + console.log(error); + reject(error); + }); + }); + }); +} +exports.createGZipFileOnDisk = createGZipFileOnDisk; +/** + * Creates a GZip file in memory using a buffer. Should be used for smaller files to reduce disk I/O + * @param originalFilePath the path to the original file that is being GZipped + * @returns a buffer with the GZip file + */ +function createGZipFileInBuffer(originalFilePath) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { + var _a, e_1, _b, _c; + const inputStream = fs.createReadStream(originalFilePath); + const gzip = zlib.createGzip(); + inputStream.pipe(gzip); + // read stream into buffer, using experimental async iterators see https://github.com/nodejs/readable-stream/issues/403#issuecomment-479069043 + const chunks = []; + try { + for (var _d = true, gzip_1 = __asyncValues(gzip), gzip_1_1; gzip_1_1 = yield gzip_1.next(), _a = gzip_1_1.done, !_a;) { + _c = gzip_1_1.value; + _d = false; + try { + const chunk = _c; + chunks.push(chunk); + } + finally { + _d = true; + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (!_d && !_a && (_b = gzip_1.return)) yield _b.call(gzip_1); + } + finally { if (e_1) throw e_1.error; } + } + resolve(Buffer.concat(chunks)); + })); + }); +} +exports.createGZipFileInBuffer = createGZipFileInBuffer; +//# sourceMappingURL=upload-gzip.js.map + +/***/ }), + +/***/ 87566: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.UploadHttpClient = void 0; +const fs = __importStar(__nccwpck_require__(79896)); +const core = __importStar(__nccwpck_require__(37484)); +const tmp = __importStar(__nccwpck_require__(69601)); +const stream = __importStar(__nccwpck_require__(2203)); +const utils_1 = __nccwpck_require__(24149); +const config_variables_1 = __nccwpck_require__(49388); +const util_1 = __nccwpck_require__(39023); +const url_1 = __nccwpck_require__(87016); +const perf_hooks_1 = __nccwpck_require__(82987); +const status_reporter_1 = __nccwpck_require__(85572); +const http_client_1 = __nccwpck_require__(54844); +const http_manager_1 = __nccwpck_require__(72448); +const upload_gzip_1 = __nccwpck_require__(86084); +const requestUtils_1 = __nccwpck_require__(93912); +const stat = (0, util_1.promisify)(fs.stat); +class UploadHttpClient { + constructor() { + this.uploadHttpManager = new http_manager_1.HttpManager((0, config_variables_1.getUploadFileConcurrency)(), '@actions/artifact-upload'); + this.statusReporter = new status_reporter_1.StatusReporter(10000); + } + /** + * Creates a file container for the new artifact in the remote blob storage/file service + * @param {string} artifactName Name of the artifact being created + * @returns The response from the Artifact Service if the file container was successfully created + */ + createArtifactInFileContainer(artifactName, options) { + return __awaiter(this, void 0, void 0, function* () { + const parameters = { + Type: 'actions_storage', + Name: artifactName + }; + // calculate retention period + if (options && options.retentionDays) { + const maxRetentionStr = (0, config_variables_1.getRetentionDays)(); + parameters.RetentionDays = (0, utils_1.getProperRetention)(options.retentionDays, maxRetentionStr); + } + const data = JSON.stringify(parameters, null, 2); + const artifactUrl = (0, utils_1.getArtifactUrl)(); + // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately + const client = this.uploadHttpManager.getClient(0); + const headers = (0, utils_1.getUploadHeaders)('application/json', false); + // Extra information to display when a particular HTTP code is returned + // If a 403 is returned when trying to create a file container, the customer has exceeded + // their storage quota so no new artifact containers can be created + const customErrorMessages = new Map([ + [ + http_client_1.HttpCodes.Forbidden, + (0, config_variables_1.isGhes)() + ? 'Please reference [Enabling GitHub Actions for GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.8/admin/github-actions/enabling-github-actions-for-github-enterprise-server) to ensure Actions storage is configured correctly.' + : 'Artifact storage quota has been hit. Unable to upload any new artifacts' + ], + [ + http_client_1.HttpCodes.BadRequest, + `The artifact name ${artifactName} is not valid. Request URL ${artifactUrl}` + ] + ]); + const response = yield (0, requestUtils_1.retryHttpClientRequest)('Create Artifact Container', () => __awaiter(this, void 0, void 0, function* () { return client.post(artifactUrl, data, headers); }), customErrorMessages); + const body = yield response.readBody(); + return JSON.parse(body); + }); + } + /** + * Concurrently upload all of the files in chunks + * @param {string} uploadUrl Base Url for the artifact that was created + * @param {SearchResult[]} filesToUpload A list of information about the files being uploaded + * @returns The size of all the files uploaded in bytes + */ + uploadArtifactToFileContainer(uploadUrl, filesToUpload, options) { + return __awaiter(this, void 0, void 0, function* () { + const FILE_CONCURRENCY = (0, config_variables_1.getUploadFileConcurrency)(); + const MAX_CHUNK_SIZE = (0, config_variables_1.getUploadChunkSize)(); + core.debug(`File Concurrency: ${FILE_CONCURRENCY}, and Chunk Size: ${MAX_CHUNK_SIZE}`); + const parameters = []; + // by default, file uploads will continue if there is an error unless specified differently in the options + let continueOnError = true; + if (options) { + if (options.continueOnError === false) { + continueOnError = false; + } + } + // prepare the necessary parameters to upload all the files + for (const file of filesToUpload) { + const resourceUrl = new url_1.URL(uploadUrl); + resourceUrl.searchParams.append('itemPath', file.uploadFilePath); + parameters.push({ + file: file.absoluteFilePath, + resourceUrl: resourceUrl.toString(), + maxChunkSize: MAX_CHUNK_SIZE, + continueOnError + }); + } + const parallelUploads = [...new Array(FILE_CONCURRENCY).keys()]; + const failedItemsToReport = []; + let currentFile = 0; + let completedFiles = 0; + let uploadFileSize = 0; + let totalFileSize = 0; + let abortPendingFileUploads = false; + this.statusReporter.setTotalNumberOfFilesToProcess(filesToUpload.length); + this.statusReporter.start(); + // only allow a certain amount of files to be uploaded at once, this is done to reduce potential errors + yield Promise.all(parallelUploads.map((index) => __awaiter(this, void 0, void 0, function* () { + while (currentFile < filesToUpload.length) { + const currentFileParameters = parameters[currentFile]; + currentFile += 1; + if (abortPendingFileUploads) { + failedItemsToReport.push(currentFileParameters.file); + continue; + } + const startTime = perf_hooks_1.performance.now(); + const uploadFileResult = yield this.uploadFileAsync(index, currentFileParameters); + if (core.isDebug()) { + core.debug(`File: ${++completedFiles}/${filesToUpload.length}. ${currentFileParameters.file} took ${(perf_hooks_1.performance.now() - startTime).toFixed(3)} milliseconds to finish upload`); + } + uploadFileSize += uploadFileResult.successfulUploadSize; + totalFileSize += uploadFileResult.totalSize; + if (uploadFileResult.isSuccess === false) { + failedItemsToReport.push(currentFileParameters.file); + if (!continueOnError) { + // fail fast + core.error(`aborting artifact upload`); + abortPendingFileUploads = true; + } + } + this.statusReporter.incrementProcessedCount(); + } + }))); + this.statusReporter.stop(); + // done uploading, safety dispose all connections + this.uploadHttpManager.disposeAndReplaceAllClients(); + core.info(`Total size of all the files uploaded is ${uploadFileSize} bytes`); + return { + uploadSize: uploadFileSize, + totalSize: totalFileSize, + failedItems: failedItemsToReport + }; + }); + } + /** + * Asynchronously uploads a file. The file is compressed and uploaded using GZip if it is determined to save space. + * If the upload file is bigger than the max chunk size it will be uploaded via multiple calls + * @param {number} httpClientIndex The index of the httpClient that is being used to make all of the calls + * @param {UploadFileParameters} parameters Information about the file that needs to be uploaded + * @returns The size of the file that was uploaded in bytes along with any failed uploads + */ + uploadFileAsync(httpClientIndex, parameters) { + return __awaiter(this, void 0, void 0, function* () { + const fileStat = yield stat(parameters.file); + const totalFileSize = fileStat.size; + const isFIFO = fileStat.isFIFO(); + let offset = 0; + let isUploadSuccessful = true; + let failedChunkSizes = 0; + let uploadFileSize = 0; + let isGzip = true; + // the file that is being uploaded is less than 64k in size to increase throughput and to minimize disk I/O + // for creating a new GZip file, an in-memory buffer is used for compression + // with named pipes the file size is reported as zero in that case don't read the file in memory + if (!isFIFO && totalFileSize < 65536) { + core.debug(`${parameters.file} is less than 64k in size. Creating a gzip file in-memory to potentially reduce the upload size`); + const buffer = yield (0, upload_gzip_1.createGZipFileInBuffer)(parameters.file); + // An open stream is needed in the event of a failure and we need to retry. If a NodeJS.ReadableStream is directly passed in, + // it will not properly get reset to the start of the stream if a chunk upload needs to be retried + let openUploadStream; + if (totalFileSize < buffer.byteLength) { + // compression did not help with reducing the size, use a readable stream from the original file for upload + core.debug(`The gzip file created for ${parameters.file} did not help with reducing the size of the file. The original file will be uploaded as-is`); + openUploadStream = () => fs.createReadStream(parameters.file); + isGzip = false; + uploadFileSize = totalFileSize; + } + else { + // create a readable stream using a PassThrough stream that is both readable and writable + core.debug(`A gzip file created for ${parameters.file} helped with reducing the size of the original file. The file will be uploaded using gzip.`); + openUploadStream = () => { + const passThrough = new stream.PassThrough(); + passThrough.end(buffer); + return passThrough; + }; + uploadFileSize = buffer.byteLength; + } + const result = yield this.uploadChunk(httpClientIndex, parameters.resourceUrl, openUploadStream, 0, uploadFileSize - 1, uploadFileSize, isGzip, totalFileSize); + if (!result) { + // chunk failed to upload + isUploadSuccessful = false; + failedChunkSizes += uploadFileSize; + core.warning(`Aborting upload for ${parameters.file} due to failure`); + } + return { + isSuccess: isUploadSuccessful, + successfulUploadSize: uploadFileSize - failedChunkSizes, + totalSize: totalFileSize + }; + } + else { + // the file that is being uploaded is greater than 64k in size, a temporary file gets created on disk using the + // npm tmp-promise package and this file gets used to create a GZipped file + const tempFile = yield tmp.file(); + core.debug(`${parameters.file} is greater than 64k in size. Creating a gzip file on-disk ${tempFile.path} to potentially reduce the upload size`); + // create a GZip file of the original file being uploaded, the original file should not be modified in any way + uploadFileSize = yield (0, upload_gzip_1.createGZipFileOnDisk)(parameters.file, tempFile.path); + let uploadFilePath = tempFile.path; + // compression did not help with size reduction, use the original file for upload and delete the temp GZip file + // for named pipes totalFileSize is zero, this assumes compression did help + if (!isFIFO && totalFileSize < uploadFileSize) { + core.debug(`The gzip file created for ${parameters.file} did not help with reducing the size of the file. The original file will be uploaded as-is`); + uploadFileSize = totalFileSize; + uploadFilePath = parameters.file; + isGzip = false; + } + else { + core.debug(`The gzip file created for ${parameters.file} is smaller than the original file. The file will be uploaded using gzip.`); + } + let abortFileUpload = false; + // upload only a single chunk at a time + while (offset < uploadFileSize) { + const chunkSize = Math.min(uploadFileSize - offset, parameters.maxChunkSize); + const startChunkIndex = offset; + const endChunkIndex = offset + chunkSize - 1; + offset += parameters.maxChunkSize; + if (abortFileUpload) { + // if we don't want to continue in the event of an error, any pending upload chunks will be marked as failed + failedChunkSizes += chunkSize; + continue; + } + const result = yield this.uploadChunk(httpClientIndex, parameters.resourceUrl, () => fs.createReadStream(uploadFilePath, { + start: startChunkIndex, + end: endChunkIndex, + autoClose: false + }), startChunkIndex, endChunkIndex, uploadFileSize, isGzip, totalFileSize); + if (!result) { + // Chunk failed to upload, report as failed and do not continue uploading any more chunks for the file. It is possible that part of a chunk was + // successfully uploaded so the server may report a different size for what was uploaded + isUploadSuccessful = false; + failedChunkSizes += chunkSize; + core.warning(`Aborting upload for ${parameters.file} due to failure`); + abortFileUpload = true; + } + else { + // if an individual file is greater than 8MB (1024*1024*8) in size, display extra information about the upload status + if (uploadFileSize > 8388608) { + this.statusReporter.updateLargeFileStatus(parameters.file, startChunkIndex, endChunkIndex, uploadFileSize); + } + } + } + // Delete the temporary file that was created as part of the upload. If the temp file does not get manually deleted by + // calling cleanup, it gets removed when the node process exits. For more info see: https://www.npmjs.com/package/tmp-promise#about + core.debug(`deleting temporary gzip file ${tempFile.path}`); + yield tempFile.cleanup(); + return { + isSuccess: isUploadSuccessful, + successfulUploadSize: uploadFileSize - failedChunkSizes, + totalSize: totalFileSize + }; + } + }); + } + /** + * Uploads a chunk of an individual file to the specified resourceUrl. If the upload fails and the status code + * indicates a retryable status, we try to upload the chunk as well + * @param {number} httpClientIndex The index of the httpClient being used to make all the necessary calls + * @param {string} resourceUrl Url of the resource that the chunk will be uploaded to + * @param {NodeJS.ReadableStream} openStream Stream of the file that will be uploaded + * @param {number} start Starting byte index of file that the chunk belongs to + * @param {number} end Ending byte index of file that the chunk belongs to + * @param {number} uploadFileSize Total size of the file in bytes that is being uploaded + * @param {boolean} isGzip Denotes if we are uploading a Gzip compressed stream + * @param {number} totalFileSize Original total size of the file that is being uploaded + * @returns if the chunk was successfully uploaded + */ + uploadChunk(httpClientIndex, resourceUrl, openStream, start, end, uploadFileSize, isGzip, totalFileSize) { + return __awaiter(this, void 0, void 0, function* () { + // open a new stream and read it to compute the digest + const digest = yield (0, utils_1.digestForStream)(openStream()); + // prepare all the necessary headers before making any http call + const headers = (0, utils_1.getUploadHeaders)('application/octet-stream', true, isGzip, totalFileSize, end - start + 1, (0, utils_1.getContentRange)(start, end, uploadFileSize), digest); + const uploadChunkRequest = () => __awaiter(this, void 0, void 0, function* () { + const client = this.uploadHttpManager.getClient(httpClientIndex); + return yield client.sendStream('PUT', resourceUrl, openStream(), headers); + }); + let retryCount = 0; + const retryLimit = (0, config_variables_1.getRetryLimit)(); + // Increments the current retry count and then checks if the retry limit has been reached + // If there have been too many retries, fail so the download stops + const incrementAndCheckRetryLimit = (response) => { + retryCount++; + if (retryCount > retryLimit) { + if (response) { + (0, utils_1.displayHttpDiagnostics)(response); + } + core.info(`Retry limit has been reached for chunk at offset ${start} to ${resourceUrl}`); + return true; + } + return false; + }; + const backOff = (retryAfterValue) => __awaiter(this, void 0, void 0, function* () { + this.uploadHttpManager.disposeAndReplaceClient(httpClientIndex); + if (retryAfterValue) { + core.info(`Backoff due to too many requests, retry #${retryCount}. Waiting for ${retryAfterValue} milliseconds before continuing the upload`); + yield (0, utils_1.sleep)(retryAfterValue); + } + else { + const backoffTime = (0, utils_1.getExponentialRetryTimeInMilliseconds)(retryCount); + core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the upload at offset ${start}`); + yield (0, utils_1.sleep)(backoffTime); + } + core.info(`Finished backoff for retry #${retryCount}, continuing with upload`); + return; + }); + // allow for failed chunks to be retried multiple times + while (retryCount <= retryLimit) { + let response; + try { + response = yield uploadChunkRequest(); + } + catch (error) { + // if an error is caught, it is usually indicative of a timeout so retry the upload + core.info(`An error has been caught http-client index ${httpClientIndex}, retrying the upload`); + // eslint-disable-next-line no-console + console.log(error); + if (incrementAndCheckRetryLimit()) { + return false; + } + yield backOff(); + continue; + } + // Always read the body of the response. There is potential for a resource leak if the body is not read which will + // result in the connection remaining open along with unintended consequences when trying to dispose of the client + yield response.readBody(); + if ((0, utils_1.isSuccessStatusCode)(response.message.statusCode)) { + return true; + } + else if ((0, utils_1.isRetryableStatusCode)(response.message.statusCode)) { + core.info(`A ${response.message.statusCode} status code has been received, will attempt to retry the upload`); + if (incrementAndCheckRetryLimit(response)) { + return false; + } + (0, utils_1.isThrottledStatusCode)(response.message.statusCode) + ? yield backOff((0, utils_1.tryGetRetryAfterValueTimeInMilliseconds)(response.message.headers)) + : yield backOff(); + } + else { + core.error(`Unexpected response. Unable to upload chunk to ${resourceUrl}`); + (0, utils_1.displayHttpDiagnostics)(response); + return false; + } + } + return false; + }); + } + /** + * Updates the size of the artifact from -1 which was initially set when the container was first created for the artifact. + * Updating the size indicates that we are done uploading all the contents of the artifact + */ + patchArtifactSize(size, artifactName) { + return __awaiter(this, void 0, void 0, function* () { + const resourceUrl = new url_1.URL((0, utils_1.getArtifactUrl)()); + resourceUrl.searchParams.append('artifactName', artifactName); + const parameters = { Size: size }; + const data = JSON.stringify(parameters, null, 2); + core.debug(`URL is ${resourceUrl.toString()}`); + // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately + const client = this.uploadHttpManager.getClient(0); + const headers = (0, utils_1.getUploadHeaders)('application/json', false); + // Extra information to display when a particular HTTP code is returned + const customErrorMessages = new Map([ + [ + http_client_1.HttpCodes.NotFound, + `An Artifact with the name ${artifactName} was not found` + ] + ]); + // TODO retry for all possible response codes, the artifact upload is pretty much complete so it at all costs we should try to finish this + const response = yield (0, requestUtils_1.retryHttpClientRequest)('Finalize artifact upload', () => __awaiter(this, void 0, void 0, function* () { return client.patch(resourceUrl.toString(), data, headers); }), customErrorMessages); + yield response.readBody(); + core.debug(`Artifact ${artifactName} has been successfully uploaded, total size in bytes: ${size}`); + }); + } +} +exports.UploadHttpClient = UploadHttpClient; +//# sourceMappingURL=upload-http-client.js.map + +/***/ }), + +/***/ 71583: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__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]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__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; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getUploadSpecification = void 0; +const fs = __importStar(__nccwpck_require__(79896)); +const core_1 = __nccwpck_require__(37484); +const path_1 = __nccwpck_require__(16928); +const path_and_artifact_name_validation_1 = __nccwpck_require__(53520); +/** + * Creates a specification that describes how each file that is part of the artifact will be uploaded + * @param artifactName the name of the artifact being uploaded. Used during upload to denote where the artifact is stored on the server + * @param rootDirectory an absolute file path that denotes the path that should be removed from the beginning of each artifact file + * @param artifactFiles a list of absolute file paths that denote what should be uploaded as part of the artifact + */ +function getUploadSpecification(artifactName, rootDirectory, artifactFiles) { + // artifact name was checked earlier on, no need to check again + const specifications = []; + if (!fs.existsSync(rootDirectory)) { + throw new Error(`Provided rootDirectory ${rootDirectory} does not exist`); + } + if (!fs.statSync(rootDirectory).isDirectory()) { + throw new Error(`Provided rootDirectory ${rootDirectory} is not a valid directory`); + } + // Normalize and resolve, this allows for either absolute or relative paths to be used + rootDirectory = (0, path_1.normalize)(rootDirectory); + rootDirectory = (0, path_1.resolve)(rootDirectory); + /* + Example to demonstrate behavior + + Input: + artifactName: my-artifact + rootDirectory: '/home/user/files/plz-upload' + artifactFiles: [ + '/home/user/files/plz-upload/file1.txt', + '/home/user/files/plz-upload/file2.txt', + '/home/user/files/plz-upload/dir/file3.txt' + ] + + Output: + specifications: [ + ['/home/user/files/plz-upload/file1.txt', 'my-artifact/file1.txt'], + ['/home/user/files/plz-upload/file1.txt', 'my-artifact/file2.txt'], + ['/home/user/files/plz-upload/file1.txt', 'my-artifact/dir/file3.txt'] + ] + */ + for (let file of artifactFiles) { + if (!fs.existsSync(file)) { + throw new Error(`File ${file} does not exist`); + } + if (!fs.statSync(file).isDirectory()) { + // Normalize and resolve, this allows for either absolute or relative paths to be used + file = (0, path_1.normalize)(file); + file = (0, path_1.resolve)(file); + if (!file.startsWith(rootDirectory)) { + throw new Error(`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`); + } + // Check for forbidden characters in file paths that will be rejected during upload + const uploadPath = file.replace(rootDirectory, ''); + (0, path_and_artifact_name_validation_1.checkArtifactFilePath)(uploadPath); + /* + uploadFilePath denotes where the file will be uploaded in the file container on the server. During a run, if multiple artifacts are uploaded, they will all + be saved in the same container. The artifact name is used as the root directory in the container to separate and distinguish uploaded artifacts + + path.join handles all the following cases and would return 'artifact-name/file-to-upload.txt + join('artifact-name/', 'file-to-upload.txt') + join('artifact-name/', '/file-to-upload.txt') + join('artifact-name', 'file-to-upload.txt') + join('artifact-name', '/file-to-upload.txt') + */ + specifications.push({ + absoluteFilePath: file, + uploadFilePath: (0, path_1.join)(artifactName, uploadPath) + }); + } + else { + // Directories are rejected by the server during upload + (0, core_1.debug)(`Removing ${file} from rawSearchResults because it is a directory`); + } + } + return specifications; +} +exports.getUploadSpecification = getUploadSpecification; +//# sourceMappingURL=upload-specification.js.map + +/***/ }), + +/***/ 24149: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.digestForStream = exports.sleep = exports.getProperRetention = exports.rmFile = exports.getFileSize = exports.createEmptyFilesForArtifact = exports.createDirectoriesForArtifact = exports.displayHttpDiagnostics = exports.getArtifactUrl = exports.createHttpClient = exports.getUploadHeaders = exports.getDownloadHeaders = exports.getContentRange = exports.tryGetRetryAfterValueTimeInMilliseconds = exports.isThrottledStatusCode = exports.isRetryableStatusCode = exports.isForbiddenStatusCode = exports.isSuccessStatusCode = exports.getApiVersion = exports.parseEnvNumber = exports.getExponentialRetryTimeInMilliseconds = void 0; +const crypto_1 = __importDefault(__nccwpck_require__(76982)); +const fs_1 = __nccwpck_require__(79896); +const core_1 = __nccwpck_require__(37484); +const http_client_1 = __nccwpck_require__(54844); +const auth_1 = __nccwpck_require__(44552); +const config_variables_1 = __nccwpck_require__(49388); +const crc64_1 = __importDefault(__nccwpck_require__(1116)); +/** + * Returns a retry time in milliseconds that exponentially gets larger + * depending on the amount of retries that have been attempted + */ +function getExponentialRetryTimeInMilliseconds(retryCount) { + if (retryCount < 0) { + throw new Error('RetryCount should not be negative'); + } + else if (retryCount === 0) { + return (0, config_variables_1.getInitialRetryIntervalInMilliseconds)(); + } + const minTime = (0, config_variables_1.getInitialRetryIntervalInMilliseconds)() * (0, config_variables_1.getRetryMultiplier)() * retryCount; + const maxTime = minTime * (0, config_variables_1.getRetryMultiplier)(); + // returns a random number between the minTime (inclusive) and the maxTime (exclusive) + return Math.trunc(Math.random() * (maxTime - minTime) + minTime); +} +exports.getExponentialRetryTimeInMilliseconds = getExponentialRetryTimeInMilliseconds; +/** + * Parses a env variable that is a number + */ +function parseEnvNumber(key) { + const value = Number(process.env[key]); + if (Number.isNaN(value) || value < 0) { + return undefined; + } + return value; +} +exports.parseEnvNumber = parseEnvNumber; +/** + * Various utility functions to help with the necessary API calls + */ +function getApiVersion() { + return '6.0-preview'; +} +exports.getApiVersion = getApiVersion; +function isSuccessStatusCode(statusCode) { + if (!statusCode) { + return false; + } + return statusCode >= 200 && statusCode < 300; +} +exports.isSuccessStatusCode = isSuccessStatusCode; +function isForbiddenStatusCode(statusCode) { + if (!statusCode) { + return false; + } + return statusCode === http_client_1.HttpCodes.Forbidden; +} +exports.isForbiddenStatusCode = isForbiddenStatusCode; +function isRetryableStatusCode(statusCode) { + if (!statusCode) { + return false; + } + const retryableStatusCodes = [ + http_client_1.HttpCodes.BadGateway, + http_client_1.HttpCodes.GatewayTimeout, + http_client_1.HttpCodes.InternalServerError, + http_client_1.HttpCodes.ServiceUnavailable, + http_client_1.HttpCodes.TooManyRequests, + 413 // Payload Too Large + ]; + return retryableStatusCodes.includes(statusCode); +} +exports.isRetryableStatusCode = isRetryableStatusCode; +function isThrottledStatusCode(statusCode) { + if (!statusCode) { + return false; + } + return statusCode === http_client_1.HttpCodes.TooManyRequests; +} +exports.isThrottledStatusCode = isThrottledStatusCode; +/** + * Attempts to get the retry-after value from a set of http headers. The retry time + * is originally denoted in seconds, so if present, it is converted to milliseconds + * @param headers all the headers received when making an http call + */ +function tryGetRetryAfterValueTimeInMilliseconds(headers) { + if (headers['retry-after']) { + const retryTime = Number(headers['retry-after']); + if (!isNaN(retryTime)) { + (0, core_1.info)(`Retry-After header is present with a value of ${retryTime}`); + return retryTime * 1000; + } + (0, core_1.info)(`Returned retry-after header value: ${retryTime} is non-numeric and cannot be used`); + return undefined; + } + (0, core_1.info)(`No retry-after header was found. Dumping all headers for diagnostic purposes`); + // eslint-disable-next-line no-console + console.log(headers); + return undefined; +} +exports.tryGetRetryAfterValueTimeInMilliseconds = tryGetRetryAfterValueTimeInMilliseconds; +function getContentRange(start, end, total) { + // Format: `bytes start-end/fileSize + // start and end are inclusive + // For a 200 byte chunk starting at byte 0: + // Content-Range: bytes 0-199/200 + return `bytes ${start}-${end}/${total}`; +} +exports.getContentRange = getContentRange; +/** + * Sets all the necessary headers when downloading an artifact + * @param {string} contentType the type of content being uploaded + * @param {boolean} isKeepAlive is the same connection being used to make multiple calls + * @param {boolean} acceptGzip can we accept a gzip encoded response + * @param {string} acceptType the type of content that we can accept + * @returns appropriate headers to make a specific http call during artifact download + */ +function getDownloadHeaders(contentType, isKeepAlive, acceptGzip) { + const requestOptions = {}; + if (contentType) { + requestOptions['Content-Type'] = contentType; + } + if (isKeepAlive) { + requestOptions['Connection'] = 'Keep-Alive'; + // keep alive for at least 10 seconds before closing the connection + requestOptions['Keep-Alive'] = '10'; + } + if (acceptGzip) { + // if we are expecting a response with gzip encoding, it should be using an octet-stream in the accept header + requestOptions['Accept-Encoding'] = 'gzip'; + requestOptions['Accept'] = `application/octet-stream;api-version=${getApiVersion()}`; + } + else { + // default to application/json if we are not working with gzip content + requestOptions['Accept'] = `application/json;api-version=${getApiVersion()}`; + } + return requestOptions; +} +exports.getDownloadHeaders = getDownloadHeaders; +/** + * Sets all the necessary headers when uploading an artifact + * @param {string} contentType the type of content being uploaded + * @param {boolean} isKeepAlive is the same connection being used to make multiple calls + * @param {boolean} isGzip is the connection being used to upload GZip compressed content + * @param {number} uncompressedLength the original size of the content if something is being uploaded that has been compressed + * @param {number} contentLength the length of the content that is being uploaded + * @param {string} contentRange the range of the content that is being uploaded + * @returns appropriate headers to make a specific http call during artifact upload + */ +function getUploadHeaders(contentType, isKeepAlive, isGzip, uncompressedLength, contentLength, contentRange, digest) { + const requestOptions = {}; + requestOptions['Accept'] = `application/json;api-version=${getApiVersion()}`; + if (contentType) { + requestOptions['Content-Type'] = contentType; + } + if (isKeepAlive) { + requestOptions['Connection'] = 'Keep-Alive'; + // keep alive for at least 10 seconds before closing the connection + requestOptions['Keep-Alive'] = '10'; + } + if (isGzip) { + requestOptions['Content-Encoding'] = 'gzip'; + requestOptions['x-tfs-filelength'] = uncompressedLength; + } + if (contentLength) { + requestOptions['Content-Length'] = contentLength; + } + if (contentRange) { + requestOptions['Content-Range'] = contentRange; + } + if (digest) { + requestOptions['x-actions-results-crc64'] = digest.crc64; + requestOptions['x-actions-results-md5'] = digest.md5; + } + return requestOptions; +} +exports.getUploadHeaders = getUploadHeaders; +function createHttpClient(userAgent) { + return new http_client_1.HttpClient(userAgent, [ + new auth_1.BearerCredentialHandler((0, config_variables_1.getRuntimeToken)()) + ]); +} +exports.createHttpClient = createHttpClient; +function getArtifactUrl() { + const artifactUrl = `${(0, config_variables_1.getRuntimeUrl)()}_apis/pipelines/workflows/${(0, config_variables_1.getWorkFlowRunId)()}/artifacts?api-version=${getApiVersion()}`; + (0, core_1.debug)(`Artifact Url: ${artifactUrl}`); + return artifactUrl; +} +exports.getArtifactUrl = getArtifactUrl; +/** + * Uh oh! Something might have gone wrong during either upload or download. The IHtttpClientResponse object contains information + * about the http call that was made by the actions http client. This information might be useful to display for diagnostic purposes, but + * this entire object is really big and most of the information is not really useful. This function takes the response object and displays only + * the information that we want. + * + * Certain information such as the TLSSocket and the Readable state are not really useful for diagnostic purposes so they can be avoided. + * Other information such as the headers, the response code and message might be useful, so this is displayed. + */ +function displayHttpDiagnostics(response) { + (0, core_1.info)(`##### Begin Diagnostic HTTP information ##### +Status Code: ${response.message.statusCode} +Status Message: ${response.message.statusMessage} +Header Information: ${JSON.stringify(response.message.headers, undefined, 2)} +###### End Diagnostic HTTP information ######`); +} +exports.displayHttpDiagnostics = displayHttpDiagnostics; +function createDirectoriesForArtifact(directories) { + return __awaiter(this, void 0, void 0, function* () { + for (const directory of directories) { + yield fs_1.promises.mkdir(directory, { + recursive: true + }); + } + }); +} +exports.createDirectoriesForArtifact = createDirectoriesForArtifact; +function createEmptyFilesForArtifact(emptyFilesToCreate) { + return __awaiter(this, void 0, void 0, function* () { + for (const filePath of emptyFilesToCreate) { + yield (yield fs_1.promises.open(filePath, 'w')).close(); + } + }); +} +exports.createEmptyFilesForArtifact = createEmptyFilesForArtifact; +function getFileSize(filePath) { + return __awaiter(this, void 0, void 0, function* () { + const stats = yield fs_1.promises.stat(filePath); + (0, core_1.debug)(`${filePath} size:(${stats.size}) blksize:(${stats.blksize}) blocks:(${stats.blocks})`); + return stats.size; + }); +} +exports.getFileSize = getFileSize; +function rmFile(filePath) { + return __awaiter(this, void 0, void 0, function* () { + yield fs_1.promises.unlink(filePath); + }); +} +exports.rmFile = rmFile; +function getProperRetention(retentionInput, retentionSetting) { + if (retentionInput < 0) { + throw new Error('Invalid retention, minimum value is 1.'); + } + let retention = retentionInput; + if (retentionSetting) { + const maxRetention = parseInt(retentionSetting); + if (!isNaN(maxRetention) && maxRetention < retention) { + (0, core_1.warning)(`Retention days is greater than the max value allowed by the repository setting, reduce retention to ${maxRetention} days`); + retention = maxRetention; + } + } + return retention; +} +exports.getProperRetention = getProperRetention; +function sleep(milliseconds) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(resolve => setTimeout(resolve, milliseconds)); + }); +} +exports.sleep = sleep; +function digestForStream(stream) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + const crc64 = new crc64_1.default(); + const md5 = crypto_1.default.createHash('md5'); + stream + .on('data', data => { + crc64.update(data); + md5.update(data); + }) + .on('end', () => resolve({ + crc64: crc64.digest('base64'), + md5: md5.digest('base64') + })) + .on('error', reject); + }); + }); +} +exports.digestForStream = digestForStream; +//# sourceMappingURL=utils.js.map + /***/ }), /***/ 76846: @@ -62790,6 +65078,9 @@ const fsStat = (0, util_1.promisify)(fs_1.stat); const fsOpen = (0, util_1.promisify)(fs_1.open); const fsClose = (0, util_1.promisify)(fs_1.close); const fsUnlink = (0, util_1.promisify)(fs_1.unlink); +const defaultClientOptions = { + allowSeparateTransferHost: true +}; const LIST_COMMANDS_DEFAULT = () => ["LIST -a", "LIST"]; const LIST_COMMANDS_MLSD = () => ["MLSD", "LIST -a", "LIST"]; /** @@ -62801,10 +65092,13 @@ class Client { * * @param timeout Timeout in milliseconds, use 0 for no timeout. Optional, default is 30 seconds. */ - constructor(timeout = 30000) { + constructor(timeout = 30000, options = defaultClientOptions) { this.availableListCommands = LIST_COMMANDS_DEFAULT(); this.ftp = new FtpContext_1.FTPContext(timeout); - this.prepareTransfer = this._enterFirstCompatibleMode([transfer_1.enterPassiveModeIPv6, transfer_1.enterPassiveModeIPv4]); + this.prepareTransfer = this._enterFirstCompatibleMode([ + transfer_1.enterPassiveModeIPv6, + options.allowSeparateTransferHost ? transfer_1.enterPassiveModeIPv4 : transfer_1.enterPassiveModeIPv4_forceControlHostIP + ]); this.parseList = parseList_1.parseList; this._progressTracker = new ProgressTracker_1.ProgressTracker(); } @@ -63387,6 +65681,12 @@ class Client { async _downloadFromWorkingDir(localDirPath) { await ensureLocalDirectory(localDirPath); for (const file of await this.list()) { + const hasInvalidName = !file.name || (0, path_1.basename)(file.name) !== file.name; + if (hasInvalidName) { + const safeName = JSON.stringify(file.name); + this.ftp.log(`Invalid filename from server listing, will skip file. (${safeName})`); + continue; + } const localPath = (0, path_1.join)(localDirPath, file.name); if (file.isDirectory) { await this.cd(file.name); @@ -63467,7 +65767,7 @@ class Client { try { const res = await strategy(ftp); ftp.log("Optimal transfer strategy found."); - this.prepareTransfer = strategy; // eslint-disable-line require-atomic-updates + this.prepareTransfer = strategy; return res; } catch (err) { @@ -63525,7 +65825,7 @@ async function ensureLocalDirectory(path) { try { await fsStat(path); } - catch (err) { + catch (_a) { await fsMkDir(path, { recursive: true }); } } @@ -63533,7 +65833,7 @@ async function ignoreError(func) { try { return await func(); } - catch (err) { + catch (_a) { // Ignore return undefined; } @@ -64178,7 +66478,10 @@ Object.defineProperty(exports, "enterPassiveModeIPv6", ({ enumerable: true, get: "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.ipIsPrivateV4Address = exports.upgradeSocket = exports.describeAddress = exports.describeTLS = void 0; +exports.describeTLS = describeTLS; +exports.describeAddress = describeAddress; +exports.upgradeSocket = upgradeSocket; +exports.ipIsPrivateV4Address = ipIsPrivateV4Address; const tls_1 = __nccwpck_require__(64756); /** * Returns a string describing the encryption on a given socket instance. @@ -64190,7 +66493,6 @@ function describeTLS(socket) { } return "No encryption"; } -exports.describeTLS = describeTLS; /** * Returns a string describing the remote address of a socket. */ @@ -64200,7 +66502,6 @@ function describeAddress(socket) { } return `${socket.remoteAddress}:${socket.remotePort}`; } -exports.describeAddress = describeAddress; /** * Upgrade a socket connection with TLS. */ @@ -64224,7 +66525,6 @@ function upgradeSocket(socket, options) { }); }); } -exports.upgradeSocket = upgradeSocket; /** * Returns true if an IP is a private address according to https://tools.ietf.org/html/rfc1918#section-3. * This will handle IPv4-mapped IPv6 addresses correctly but return false for all other IPv6 addresses. @@ -64242,7 +66542,6 @@ function ipIsPrivateV4Address(ip = "") { || (octets[0] === 192 && octets[1] === 168) // 192.168.0.0 - 192.168.255.255 || ip === "127.0.0.1"; } -exports.ipIsPrivateV4Address = ipIsPrivateV4Address; /***/ }), @@ -64253,7 +66552,11 @@ exports.ipIsPrivateV4Address = ipIsPrivateV4Address; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.positiveIntermediate = exports.positiveCompletion = exports.isMultiline = exports.isSingleLine = exports.parseControlResponse = void 0; +exports.parseControlResponse = parseControlResponse; +exports.isSingleLine = isSingleLine; +exports.isMultiline = isMultiline; +exports.positiveCompletion = positiveCompletion; +exports.positiveIntermediate = positiveIntermediate; const LF = "\n"; /** * Parse an FTP control response as a collection of messages. A message is a complete @@ -64292,29 +66595,24 @@ function parseControlResponse(text) { const rest = tokenRegex ? lines.slice(startAt).join(LF) + LF : ""; return { messages, rest }; } -exports.parseControlResponse = parseControlResponse; function isSingleLine(line) { return /^\d\d\d(?:$| )/.test(line); } -exports.isSingleLine = isSingleLine; function isMultiline(line) { return /^\d\d\d-/.test(line); } -exports.isMultiline = isMultiline; /** * Return true if an FTP return code describes a positive completion. */ function positiveCompletion(code) { return code >= 200 && code < 300; } -exports.positiveCompletion = positiveCompletion; /** * Return true if an FTP return code describes a positive intermediate response. */ function positiveIntermediate(code) { return code >= 300 && code < 400; } -exports.positiveIntermediate = positiveIntermediate; function isNotBlank(str) { return str.trim() !== ""; } @@ -64343,15 +66641,25 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? ( }) : function(o, v) { o["default"] = v; }); -var __importStar = (this && this.__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; -}; +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.parseList = void 0; +exports.parseList = parseList; const dosParser = __importStar(__nccwpck_require__(4439)); const unixParser = __importStar(__nccwpck_require__(98003)); const mlsdParser = __importStar(__nccwpck_require__(75287)); @@ -64395,7 +66703,6 @@ function parseList(rawList) { .filter((info) => info !== undefined); return parser.transformList(files); } -exports.parseList = parseList; /***/ }), @@ -64406,7 +66713,9 @@ exports.parseList = parseList; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.transformList = exports.parseLine = exports.testLine = void 0; +exports.testLine = testLine; +exports.parseLine = parseLine; +exports.transformList = transformList; const FileInfo_1 = __nccwpck_require__(37666); /** * This parser is based on the FTP client library source code in Apache Commons Net provided @@ -64426,7 +66735,6 @@ const RE_LINE = new RegExp("(\\S+)\\s+(\\S+)\\s+" // MM-dd-yy whitespace hh:mma| function testLine(line) { return /^\d{2}/.test(line) && RE_LINE.test(line); } -exports.testLine = testLine; /** * Parse a single line of a DOS-style directory listing. */ @@ -64452,11 +66760,9 @@ function parseLine(line) { file.rawModifiedAt = groups[1] + " " + groups[2]; return file; } -exports.parseLine = parseLine; function transformList(files) { return files; } -exports.transformList = transformList; /***/ }), @@ -64467,7 +66773,10 @@ exports.transformList = transformList; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.parseMLSxDate = exports.transformList = exports.parseLine = exports.testLine = void 0; +exports.testLine = testLine; +exports.parseLine = parseLine; +exports.transformList = transformList; +exports.parseMLSxDate = parseMLSxDate; const FileInfo_1 = __nccwpck_require__(37666); function parseSize(value, info) { info.size = parseInt(value, 10); @@ -64580,7 +66889,6 @@ function splitStringOnce(str, delimiter) { function testLine(line) { return /^\S+=\S+;/.test(line) || line.startsWith(" "); } -exports.testLine = testLine; /** * Parse single line as MLSD listing, see specification at https://tools.ietf.org/html/rfc3659#section-7. */ @@ -64607,7 +66915,6 @@ function parseLine(line) { } return info; } -exports.parseLine = parseLine; function transformList(files) { // Create a map of all files that are not symbolic links by their unique ID const nonLinksByID = new Map(); @@ -64635,7 +66942,6 @@ function transformList(files) { } return resolvedFiles; } -exports.transformList = transformList; /** * Parse date as specified in https://tools.ietf.org/html/rfc3659#section-2.3. * @@ -64652,7 +66958,6 @@ function parseMLSxDate(fact) { +fact.slice(15, 18) // Milliseconds )); } -exports.parseMLSxDate = parseMLSxDate; /***/ }), @@ -64663,7 +66968,9 @@ exports.parseMLSxDate = parseMLSxDate; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.transformList = exports.parseLine = exports.testLine = void 0; +exports.testLine = testLine; +exports.parseLine = parseLine; +exports.transformList = transformList; const FileInfo_1 = __nccwpck_require__(37666); const JA_MONTH = "\u6708"; const JA_DAY = "\u65e5"; @@ -64740,7 +67047,6 @@ const RE_LINE = new RegExp("([bcdelfmpSs-])" // file type function testLine(line) { return RE_LINE.test(line); } -exports.testLine = testLine; /** * Parse a single line of a Unix-style directory listing. */ @@ -64798,11 +67104,9 @@ function parseLine(line) { } return file; } -exports.parseLine = parseLine; function transformList(files) { return files; } -exports.transformList = transformList; function parseMode(r, w, x) { let value = 0; if (r !== "-") { @@ -64827,7 +67131,14 @@ function parseMode(r, w, x) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.downloadTo = exports.uploadFrom = exports.connectForPassiveTransfer = exports.parsePasvResponse = exports.enterPassiveModeIPv4 = exports.parseEpsvResponse = exports.enterPassiveModeIPv6 = void 0; +exports.enterPassiveModeIPv6 = enterPassiveModeIPv6; +exports.parseEpsvResponse = parseEpsvResponse; +exports.enterPassiveModeIPv4 = enterPassiveModeIPv4; +exports.enterPassiveModeIPv4_forceControlHostIP = enterPassiveModeIPv4_forceControlHostIP; +exports.parsePasvResponse = parsePasvResponse; +exports.connectForPassiveTransfer = connectForPassiveTransfer; +exports.uploadFrom = uploadFrom; +exports.downloadTo = downloadTo; const netUtils_1 = __nccwpck_require__(76156); const stream_1 = __nccwpck_require__(2203); const tls_1 = __nccwpck_require__(64756); @@ -64848,7 +67159,6 @@ async function enterPassiveModeIPv6(ftp) { await connectForPassiveTransfer(controlHost, port, ftp); return res; } -exports.enterPassiveModeIPv6 = enterPassiveModeIPv6; /** * Parse an EPSV response. Returns only the port as in EPSV the host of the control connection is used. */ @@ -64865,7 +67175,6 @@ function parseEpsvResponse(message) { } return port; } -exports.parseEpsvResponse = parseEpsvResponse; /** * Prepare a data socket using passive mode over IPv4. */ @@ -64886,7 +67195,24 @@ async function enterPassiveModeIPv4(ftp) { await connectForPassiveTransfer(target.host, target.port, ftp); return res; } -exports.enterPassiveModeIPv4 = enterPassiveModeIPv4; +/** + * Prepare a data socket using passive mode over IPv4. Ignore the IP provided by the PASV response, + * and use the control host IP. This is the same behaviour as with the more modern variant EPSV. Use + * this to fix issues around NAT or provide more security by preventing FTP bounce attacks. + */ +async function enterPassiveModeIPv4_forceControlHostIP(ftp) { + const res = await ftp.request("PASV"); + const target = parsePasvResponse(res.message); + if (!target) { + throw new Error("Can't parse PASV response: " + res.message); + } + const controlHost = ftp.socket.remoteAddress; + if (controlHost === undefined) { + throw new Error("Control socket is disconnected, can't get remote address."); + } + await connectForPassiveTransfer(controlHost, target.port, ftp); + return res; +} /** * Parse a PASV response. */ @@ -64901,7 +67227,6 @@ function parsePasvResponse(message) { port: (parseInt(groups[2], 10) & 255) * 256 + (parseInt(groups[3], 10) & 255) }; } -exports.parsePasvResponse = parsePasvResponse; function connectForPassiveTransfer(host, port, ftp) { return new Promise((resolve, reject) => { let socket = ftp._newSocket(); @@ -64943,7 +67268,6 @@ function connectForPassiveTransfer(host, port, ftp) { }); }); } -exports.connectForPassiveTransfer = connectForPassiveTransfer; /** * Helps resolving/rejecting transfers. * @@ -65068,7 +67392,6 @@ function uploadFrom(source, config) { // Ignore all other positive preliminary response codes (< 200) }); } -exports.uploadFrom = uploadFrom; function downloadTo(destination, config) { if (!config.ftp.dataSocket) { throw new Error("Download will be initiated but no data connection is available."); @@ -65107,7 +67430,6 @@ function downloadTo(destination, config) { // Ignore all other positive preliminary response codes (< 200) }); } -exports.downloadTo = downloadTo; /** * Calls a function immediately if a condition is met or subscribes to an event and calls * it once the event is emitted. @@ -122328,6 +124650,8 @@ class Minimatch { if (!options) options = {} this.options = options + this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined + ? options.maxGlobstarRecursion : 200 this.set = [] this.pattern = pattern this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || @@ -122415,114 +124739,172 @@ class Minimatch { // out of pattern, then that's fine, as long as all // the parts match. matchOne (file, pattern, partial) { - var options = this.options + if (pattern.indexOf(GLOBSTAR) !== -1) { + return this._matchGlobstar(file, pattern, partial, 0, 0) + } + return this._matchOne(file, pattern, partial, 0, 0) + } - this.debug('matchOne', - { 'this': this, file: file, pattern: pattern }) + _matchGlobstar (file, pattern, partial, fileIndex, patternIndex) { + // find first globstar from patternIndex + let firstgs = -1 + for (let i = patternIndex; i < pattern.length; i++) { + if (pattern[i] === GLOBSTAR) { firstgs = i; break } + } - this.debug('matchOne', file.length, pattern.length) + // find last globstar + let lastgs = -1 + for (let i = pattern.length - 1; i >= 0; i--) { + if (pattern[i] === GLOBSTAR) { lastgs = i; break } + } - for (var fi = 0, - pi = 0, - fl = file.length, - pl = pattern.length - ; (fi < fl) && (pi < pl) - ; fi++, pi++) { - this.debug('matchOne loop') - var p = pattern[pi] - var f = file[fi] + const head = pattern.slice(patternIndex, firstgs) + const body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs) + const tail = partial ? [] : pattern.slice(lastgs + 1) - this.debug(pattern, p, f) + // check the head + if (head.length) { + const fileHead = file.slice(fileIndex, fileIndex + head.length) + if (!this._matchOne(fileHead, head, partial, 0, 0)) { + return false + } + fileIndex += head.length + } - // should be impossible. - // some invalid regexp stuff in the set. - /* istanbul ignore if */ - if (p === false) return false - - if (p === GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]) - - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi - var pr = pi + 1 - if (pr === pl) { - this.debug('** at the end') - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for (; fi < fl; fi++) { - if (file[fi] === '.' || file[fi] === '..' || - (!options.dot && file[fi].charAt(0) === '.')) return false - } - return true + // check the tail + let fileTailMatch = 0 + if (tail.length) { + if (tail.length + fileIndex > file.length) return false + + const tailStart = file.length - tail.length + if (this._matchOne(file, tail, partial, tailStart, 0)) { + fileTailMatch = tail.length + } else { + // affordance for stuff like a/**/* matching a/b/ + if (file[file.length - 1] !== '' || + fileIndex + tail.length === file.length) { + return false } + if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) { + return false + } + fileTailMatch = tail.length + 1 + } + } + + // if body is empty (single ** between head and tail) + if (!body.length) { + let sawSome = !!fileTailMatch + for (let i = fileIndex; i < file.length - fileTailMatch; i++) { + const f = String(file[i]) + sawSome = true + if (f === '.' || f === '..' || + (!this.options.dot && f.charAt(0) === '.')) { + return false + } + } + return partial || sawSome + } - // ok, let's see if we can swallow whatever we can. - while (fr < fl) { - var swallowee = file[fr] + // split body into segments at each GLOBSTAR + const bodySegments = [[[], 0]] + let currentBody = bodySegments[0] + let nonGsParts = 0 + const nonGsPartsSums = [0] + for (const b of body) { + if (b === GLOBSTAR) { + nonGsPartsSums.push(nonGsParts) + currentBody = [[], 0] + bodySegments.push(currentBody) + } else { + currentBody[0].push(b) + nonGsParts++ + } + } - this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) + let idx = bodySegments.length - 1 + const fileLength = file.length - fileTailMatch + for (const b of bodySegments) { + b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length) + } - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee) - // found a match. - return true - } else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === '.' || swallowee === '..' || - (!options.dot && swallowee.charAt(0) === '.')) { - this.debug('dot detected!', file, fr, pattern, pr) - break - } + return !!this._matchGlobStarBodySections( + file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch + ) + } - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue') - fr++ - } + // return false for "nope, not matching" + // return null for "not matching, cannot keep trying" + _matchGlobStarBodySections ( + file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail + ) { + const bs = bodySegments[bodyIndex] + if (!bs) { + // just make sure there are no bad dots + for (let i = fileIndex; i < file.length; i++) { + sawTail = true + const f = file[i] + if (f === '.' || f === '..' || + (!this.options.dot && f.charAt(0) === '.')) { + return false } + } + return sawTail + } - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then - /* istanbul ignore if */ - if (partial) { - // ran out of file - this.debug('\n>>> no match, partial?', file, fr, pattern, pr) - if (fr === fl) return true + const [body, after] = bs + while (fileIndex <= after) { + const m = this._matchOne( + file.slice(0, fileIndex + body.length), + body, + partial, + fileIndex, + 0 + ) + // if limit exceeded, no match. intentional false negative, + // acceptable break in correctness for security. + if (m && globStarDepth < this.maxGlobstarRecursion) { + const sub = this._matchGlobStarBodySections( + file, bodySegments, + fileIndex + body.length, bodyIndex + 1, + partial, globStarDepth + 1, sawTail + ) + if (sub !== false) { + return sub } + } + const f = file[fileIndex] + if (f === '.' || f === '..' || + (!this.options.dot && f.charAt(0) === '.')) { return false } + fileIndex++ + } + return partial || null + } + + _matchOne (file, pattern, partial, fileIndex, patternIndex) { + let fi, pi, fl, pl + for ( + fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi++, pi++ + ) { + this.debug('matchOne loop') + const p = pattern[pi] + const f = file[fi] + + this.debug(pattern, p, f) + + // should be impossible. + // some invalid regexp stuff in the set. + /* istanbul ignore if */ + if (p === false || p === GLOBSTAR) return false // something other than ** // non-magic patterns just have to match exactly // patterns with magic have been turned into regexps. - var hit + let hit if (typeof p === 'string') { hit = f === p this.debug('string match', p, f, hit) @@ -122534,17 +124916,6 @@ class Minimatch { if (!hit) return false } - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - // now either we fell off the end of the pattern, or we're done. if (fi === fl && pi === pl) { // ran out of pattern and filename at the same time. @@ -122693,6 +125064,9 @@ class Minimatch { continue } + // coalesce consecutive non-globstar * characters + if (c === '*' && stateChar === '*') continue + // if we already have a stateChar, then it means // that there was something like ** or +? in there. // Handle the stateChar, then proceed with this one. @@ -134723,6 +137097,913 @@ module.exports = class UTF8Decoder { } +/***/ }), + +/***/ 69601: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + + +const { promisify } = __nccwpck_require__(39023); +const tmp = __nccwpck_require__(51288); + +// file +module.exports.fileSync = tmp.fileSync; +const fileWithOptions = promisify((options, cb) => + tmp.file(options, (err, path, fd, cleanup) => + err ? cb(err) : cb(undefined, { path, fd, cleanup: promisify(cleanup) }) + ) +); +module.exports.file = async (options) => fileWithOptions(options); + +module.exports.withFile = async function withFile(fn, options) { + const { path, fd, cleanup } = await module.exports.file(options); + try { + return await fn({ path, fd }); + } finally { + await cleanup(); + } +}; + + +// directory +module.exports.dirSync = tmp.dirSync; +const dirWithOptions = promisify((options, cb) => + tmp.dir(options, (err, path, cleanup) => + err ? cb(err) : cb(undefined, { path, cleanup: promisify(cleanup) }) + ) +); +module.exports.dir = async (options) => dirWithOptions(options); + +module.exports.withDir = async function withDir(fn, options) { + const { path, cleanup } = await module.exports.dir(options); + try { + return await fn({ path }); + } finally { + await cleanup(); + } +}; + + +// name generation +module.exports.tmpNameSync = tmp.tmpNameSync; +module.exports.tmpName = promisify(tmp.tmpName); + +module.exports.tmpdir = tmp.tmpdir; + +module.exports.setGracefulCleanup = tmp.setGracefulCleanup; + + +/***/ }), + +/***/ 51288: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +/*! + * Tmp + * + * Copyright (c) 2011-2017 KARASZI Istvan + * + * MIT Licensed + */ + +/* + * Module dependencies. + */ +const fs = __nccwpck_require__(79896); +const os = __nccwpck_require__(70857); +const path = __nccwpck_require__(16928); +const crypto = __nccwpck_require__(76982); +const _c = { fs: fs.constants, os: os.constants }; + +/* + * The working inner variables. + */ +const // the random characters to choose from + RANDOM_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', + TEMPLATE_PATTERN = /XXXXXX/, + DEFAULT_TRIES = 3, + CREATE_FLAGS = (_c.O_CREAT || _c.fs.O_CREAT) | (_c.O_EXCL || _c.fs.O_EXCL) | (_c.O_RDWR || _c.fs.O_RDWR), + // constants are off on the windows platform and will not match the actual errno codes + IS_WIN32 = os.platform() === 'win32', + EBADF = _c.EBADF || _c.os.errno.EBADF, + ENOENT = _c.ENOENT || _c.os.errno.ENOENT, + DIR_MODE = 0o700 /* 448 */, + FILE_MODE = 0o600 /* 384 */, + EXIT = 'exit', + // this will hold the objects need to be removed on exit + _removeObjects = [], + // API change in fs.rmdirSync leads to error when passing in a second parameter, e.g. the callback + FN_RMDIR_SYNC = fs.rmdirSync.bind(fs); + +let _gracefulCleanup = false; + +/** + * Recursively remove a directory and its contents. + * + * @param {string} dirPath path of directory to remove + * @param {Function} callback + * @private + */ +function rimraf(dirPath, callback) { + return fs.rm(dirPath, { recursive: true }, callback); +} + +/** + * Recursively remove a directory and its contents, synchronously. + * + * @param {string} dirPath path of directory to remove + * @private + */ +function FN_RIMRAF_SYNC(dirPath) { + return fs.rmSync(dirPath, { recursive: true }); +} + +/** + * Gets a temporary file name. + * + * @param {(Options|tmpNameCallback)} options options or callback + * @param {?tmpNameCallback} callback the callback function + */ +function tmpName(options, callback) { + const args = _parseArguments(options, callback), + opts = args[0], + cb = args[1]; + + _assertAndSanitizeOptions(opts, function (err, sanitizedOptions) { + if (err) return cb(err); + + let tries = sanitizedOptions.tries; + (function _getUniqueName() { + try { + const name = _generateTmpName(sanitizedOptions); + + // check whether the path exists then retry if needed + fs.stat(name, function (err) { + /* istanbul ignore else */ + if (!err) { + /* istanbul ignore else */ + if (tries-- > 0) return _getUniqueName(); + + return cb(new Error('Could not get a unique tmp filename, max tries reached ' + name)); + } + + cb(null, name); + }); + } catch (err) { + cb(err); + } + })(); + }); +} + +/** + * Synchronous version of tmpName. + * + * @param {Object} options + * @returns {string} the generated random name + * @throws {Error} if the options are invalid or could not generate a filename + */ +function tmpNameSync(options) { + const args = _parseArguments(options), + opts = args[0]; + + const sanitizedOptions = _assertAndSanitizeOptionsSync(opts); + + let tries = sanitizedOptions.tries; + do { + const name = _generateTmpName(sanitizedOptions); + try { + fs.statSync(name); + } catch (e) { + return name; + } + } while (tries-- > 0); + + throw new Error('Could not get a unique tmp filename, max tries reached'); +} + +/** + * Creates and opens a temporary file. + * + * @param {(Options|null|undefined|fileCallback)} options the config options or the callback function or null or undefined + * @param {?fileCallback} callback + */ +function file(options, callback) { + const args = _parseArguments(options, callback), + opts = args[0], + cb = args[1]; + + // gets a temporary filename + tmpName(opts, function _tmpNameCreated(err, name) { + /* istanbul ignore else */ + if (err) return cb(err); + + // create and open the file + fs.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err, fd) { + /* istanbu ignore else */ + if (err) return cb(err); + + if (opts.discardDescriptor) { + return fs.close(fd, function _discardCallback(possibleErr) { + // the chance of getting an error on close here is rather low and might occur in the most edgiest cases only + return cb(possibleErr, name, undefined, _prepareTmpFileRemoveCallback(name, -1, opts, false)); + }); + } else { + // detachDescriptor passes the descriptor whereas discardDescriptor closes it, either way, we no longer care + // about the descriptor + const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor; + cb(null, name, fd, _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, false)); + } + }); + }); +} + +/** + * Synchronous version of file. + * + * @param {Options} options + * @returns {FileSyncObject} object consists of name, fd and removeCallback + * @throws {Error} if cannot create a file + */ +function fileSync(options) { + const args = _parseArguments(options), + opts = args[0]; + + const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor; + const name = tmpNameSync(opts); + let fd = fs.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE); + /* istanbul ignore else */ + if (opts.discardDescriptor) { + fs.closeSync(fd); + fd = undefined; + } + + return { + name: name, + fd: fd, + removeCallback: _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, true) + }; +} + +/** + * Creates a temporary directory. + * + * @param {(Options|dirCallback)} options the options or the callback function + * @param {?dirCallback} callback + */ +function dir(options, callback) { + const args = _parseArguments(options, callback), + opts = args[0], + cb = args[1]; + + // gets a temporary filename + tmpName(opts, function _tmpNameCreated(err, name) { + /* istanbul ignore else */ + if (err) return cb(err); + + // create the directory + fs.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err) { + /* istanbul ignore else */ + if (err) return cb(err); + + cb(null, name, _prepareTmpDirRemoveCallback(name, opts, false)); + }); + }); +} + +/** + * Synchronous version of dir. + * + * @param {Options} options + * @returns {DirSyncObject} object consists of name and removeCallback + * @throws {Error} if it cannot create a directory + */ +function dirSync(options) { + const args = _parseArguments(options), + opts = args[0]; + + const name = tmpNameSync(opts); + fs.mkdirSync(name, opts.mode || DIR_MODE); + + return { + name: name, + removeCallback: _prepareTmpDirRemoveCallback(name, opts, true) + }; +} + +/** + * Removes files asynchronously. + * + * @param {Object} fdPath + * @param {Function} next + * @private + */ +function _removeFileAsync(fdPath, next) { + const _handler = function (err) { + if (err && !_isENOENT(err)) { + // reraise any unanticipated error + return next(err); + } + next(); + }; + + if (0 <= fdPath[0]) + fs.close(fdPath[0], function () { + fs.unlink(fdPath[1], _handler); + }); + else fs.unlink(fdPath[1], _handler); +} + +/** + * Removes files synchronously. + * + * @param {Object} fdPath + * @private + */ +function _removeFileSync(fdPath) { + let rethrownException = null; + try { + if (0 <= fdPath[0]) fs.closeSync(fdPath[0]); + } catch (e) { + // reraise any unanticipated error + if (!_isEBADF(e) && !_isENOENT(e)) throw e; + } finally { + try { + fs.unlinkSync(fdPath[1]); + } catch (e) { + // reraise any unanticipated error + if (!_isENOENT(e)) rethrownException = e; + } + } + if (rethrownException !== null) { + throw rethrownException; + } +} + +/** + * Prepares the callback for removal of the temporary file. + * + * Returns either a sync callback or a async callback depending on whether + * fileSync or file was called, which is expressed by the sync parameter. + * + * @param {string} name the path of the file + * @param {number} fd file descriptor + * @param {Object} opts + * @param {boolean} sync + * @returns {fileCallback | fileCallbackSync} + * @private + */ +function _prepareTmpFileRemoveCallback(name, fd, opts, sync) { + const removeCallbackSync = _prepareRemoveCallback(_removeFileSync, [fd, name], sync); + const removeCallback = _prepareRemoveCallback(_removeFileAsync, [fd, name], sync, removeCallbackSync); + + if (!opts.keep) _removeObjects.unshift(removeCallbackSync); + + return sync ? removeCallbackSync : removeCallback; +} + +/** + * Prepares the callback for removal of the temporary directory. + * + * Returns either a sync callback or a async callback depending on whether + * tmpFileSync or tmpFile was called, which is expressed by the sync parameter. + * + * @param {string} name + * @param {Object} opts + * @param {boolean} sync + * @returns {Function} the callback + * @private + */ +function _prepareTmpDirRemoveCallback(name, opts, sync) { + const removeFunction = opts.unsafeCleanup ? rimraf : fs.rmdir.bind(fs); + const removeFunctionSync = opts.unsafeCleanup ? FN_RIMRAF_SYNC : FN_RMDIR_SYNC; + const removeCallbackSync = _prepareRemoveCallback(removeFunctionSync, name, sync); + const removeCallback = _prepareRemoveCallback(removeFunction, name, sync, removeCallbackSync); + if (!opts.keep) _removeObjects.unshift(removeCallbackSync); + + return sync ? removeCallbackSync : removeCallback; +} + +/** + * Creates a guarded function wrapping the removeFunction call. + * + * The cleanup callback is save to be called multiple times. + * Subsequent invocations will be ignored. + * + * @param {Function} removeFunction + * @param {string} fileOrDirName + * @param {boolean} sync + * @param {cleanupCallbackSync?} cleanupCallbackSync + * @returns {cleanupCallback | cleanupCallbackSync} + * @private + */ +function _prepareRemoveCallback(removeFunction, fileOrDirName, sync, cleanupCallbackSync) { + let called = false; + + // if sync is true, the next parameter will be ignored + return function _cleanupCallback(next) { + /* istanbul ignore else */ + if (!called) { + // remove cleanupCallback from cache + const toRemove = cleanupCallbackSync || _cleanupCallback; + const index = _removeObjects.indexOf(toRemove); + /* istanbul ignore else */ + if (index >= 0) _removeObjects.splice(index, 1); + + called = true; + if (sync || removeFunction === FN_RMDIR_SYNC || removeFunction === FN_RIMRAF_SYNC) { + return removeFunction(fileOrDirName); + } else { + return removeFunction(fileOrDirName, next || function () {}); + } + } + }; +} + +/** + * The garbage collector. + * + * @private + */ +function _garbageCollector() { + /* istanbul ignore else */ + if (!_gracefulCleanup) return; + + // the function being called removes itself from _removeObjects, + // loop until _removeObjects is empty + while (_removeObjects.length) { + try { + _removeObjects[0](); + } catch (e) { + // already removed? + } + } +} + +/** + * Random name generator based on crypto. + * Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript + * + * @param {number} howMany + * @returns {string} the generated random name + * @private + */ +function _randomChars(howMany) { + let value = [], + rnd = null; + + // make sure that we do not fail because we ran out of entropy + try { + rnd = crypto.randomBytes(howMany); + } catch (e) { + rnd = crypto.pseudoRandomBytes(howMany); + } + + for (let i = 0; i < howMany; i++) { + value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]); + } + + return value.join(''); +} + +/** + * Checks whether the `obj` parameter is defined or not. + * + * @param {Object} obj + * @returns {boolean} true if the object is undefined + * @private + */ +function _isUndefined(obj) { + return typeof obj === 'undefined'; +} + +/** + * Parses the function arguments. + * + * This function helps to have optional arguments. + * + * @param {(Options|null|undefined|Function)} options + * @param {?Function} callback + * @returns {Array} parsed arguments + * @private + */ +function _parseArguments(options, callback) { + /* istanbul ignore else */ + if (typeof options === 'function') { + return [{}, options]; + } + + /* istanbul ignore else */ + if (_isUndefined(options)) { + return [{}, callback]; + } + + // copy options so we do not leak the changes we make internally + const actualOptions = {}; + for (const key of Object.getOwnPropertyNames(options)) { + actualOptions[key] = options[key]; + } + + return [actualOptions, callback]; +} + +/** + * Resolve the specified path name in respect to tmpDir. + * + * The specified name might include relative path components, e.g. ../ + * so we need to resolve in order to be sure that is is located inside tmpDir + * + * @private + */ +function _resolvePath(name, tmpDir, cb) { + const pathToResolve = path.isAbsolute(name) ? name : path.join(tmpDir, name); + + fs.stat(pathToResolve, function (err) { + if (err) { + fs.realpath(path.dirname(pathToResolve), function (err, parentDir) { + if (err) return cb(err); + + cb(null, path.join(parentDir, path.basename(pathToResolve))); + }); + } else { + fs.realpath(pathToResolve, cb); + } + }); +} + +/** + * Resolve the specified path name in respect to tmpDir. + * + * The specified name might include relative path components, e.g. ../ + * so we need to resolve in order to be sure that is is located inside tmpDir + * + * @private + */ +function _resolvePathSync(name, tmpDir) { + const pathToResolve = path.isAbsolute(name) ? name : path.join(tmpDir, name); + + try { + fs.statSync(pathToResolve); + return fs.realpathSync(pathToResolve); + } catch (_err) { + const parentDir = fs.realpathSync(path.dirname(pathToResolve)); + + return path.join(parentDir, path.basename(pathToResolve)); + } +} + +/** + * Generates a new temporary name. + * + * @param {Object} opts + * @returns {string} the new random name according to opts + * @private + */ +function _generateTmpName(opts) { + const tmpDir = opts.tmpdir; + + /* istanbul ignore else */ + if (!_isUndefined(opts.name)) { + return path.join(tmpDir, opts.dir, opts.name); + } + + /* istanbul ignore else */ + if (!_isUndefined(opts.template)) { + return path.join(tmpDir, opts.dir, opts.template).replace(TEMPLATE_PATTERN, _randomChars(6)); + } + + // prefix and postfix + const name = [ + opts.prefix ? opts.prefix : 'tmp', + '-', + process.pid, + '-', + _randomChars(12), + opts.postfix ? '-' + opts.postfix : '' + ].join(''); + + return path.join(tmpDir, opts.dir, name); +} + +/** + * Asserts and sanitizes the basic options. + * + * @private + */ +function _assertOptionsBase(options) { + if (!_isUndefined(options.name)) { + const name = options.name; + + // assert that name is not absolute and does not contain a path + if (path.isAbsolute(name)) throw new Error(`name option must not contain an absolute path, found "${name}".`); + + // must not fail on valid . or .. or similar such constructs + const basename = path.basename(name); + if (basename === '..' || basename === '.' || basename !== name) + throw new Error(`name option must not contain a path, found "${name}".`); + } + + /* istanbul ignore else */ + if (!_isUndefined(options.template) && !options.template.match(TEMPLATE_PATTERN)) { + throw new Error(`Invalid template, found "${options.template}".`); + } + + /* istanbul ignore else */ + if ((!_isUndefined(options.tries) && isNaN(options.tries)) || options.tries < 0) { + throw new Error(`Invalid tries, found "${options.tries}".`); + } + + // if a name was specified we will try once + options.tries = _isUndefined(options.name) ? options.tries || DEFAULT_TRIES : 1; + options.keep = !!options.keep; + options.detachDescriptor = !!options.detachDescriptor; + options.discardDescriptor = !!options.discardDescriptor; + options.unsafeCleanup = !!options.unsafeCleanup; + + // for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to + options.prefix = _isUndefined(options.prefix) ? '' : options.prefix; + options.postfix = _isUndefined(options.postfix) ? '' : options.postfix; +} + +/** + * Gets the relative directory to tmpDir. + * + * @private + */ +function _getRelativePath(option, name, tmpDir, cb) { + if (_isUndefined(name)) return cb(null); + + _resolvePath(name, tmpDir, function (err, resolvedPath) { + if (err) return cb(err); + + const relativePath = path.relative(tmpDir, resolvedPath); + + if (!resolvedPath.startsWith(tmpDir)) { + return cb(new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`)); + } + + cb(null, relativePath); + }); +} + +/** + * Gets the relative path to tmpDir. + * + * @private + */ +function _getRelativePathSync(option, name, tmpDir) { + if (_isUndefined(name)) return; + + const resolvedPath = _resolvePathSync(name, tmpDir); + const relativePath = path.relative(tmpDir, resolvedPath); + + if (!resolvedPath.startsWith(tmpDir)) { + throw new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`); + } + + return relativePath; +} + +/** + * Asserts whether the specified options are valid, also sanitizes options and provides sane defaults for missing + * options. + * + * @private + */ +function _assertAndSanitizeOptions(options, cb) { + _getTmpDir(options, function (err, tmpDir) { + if (err) return cb(err); + + options.tmpdir = tmpDir; + + try { + _assertOptionsBase(options, tmpDir); + } catch (err) { + return cb(err); + } + + // sanitize dir, also keep (multiple) blanks if the user, purportedly sane, requests us to + _getRelativePath('dir', options.dir, tmpDir, function (err, dir) { + if (err) return cb(err); + + options.dir = _isUndefined(dir) ? '' : dir; + + // sanitize further if template is relative to options.dir + _getRelativePath('template', options.template, tmpDir, function (err, template) { + if (err) return cb(err); + + options.template = template; + + cb(null, options); + }); + }); + }); +} + +/** + * Asserts whether the specified options are valid, also sanitizes options and provides sane defaults for missing + * options. + * + * @private + */ +function _assertAndSanitizeOptionsSync(options) { + const tmpDir = (options.tmpdir = _getTmpDirSync(options)); + + _assertOptionsBase(options, tmpDir); + + const dir = _getRelativePathSync('dir', options.dir, tmpDir); + options.dir = _isUndefined(dir) ? '' : dir; + + options.template = _getRelativePathSync('template', options.template, tmpDir); + + return options; +} + +/** + * Helper for testing against EBADF to compensate changes made to Node 7.x under Windows. + * + * @private + */ +function _isEBADF(error) { + return _isExpectedError(error, -EBADF, 'EBADF'); +} + +/** + * Helper for testing against ENOENT to compensate changes made to Node 7.x under Windows. + * + * @private + */ +function _isENOENT(error) { + return _isExpectedError(error, -ENOENT, 'ENOENT'); +} + +/** + * Helper to determine whether the expected error code matches the actual code and errno, + * which will differ between the supported node versions. + * + * - Node >= 7.0: + * error.code {string} + * error.errno {number} any numerical value will be negated + * + * CAVEAT + * + * On windows, the errno for EBADF is -4083 but os.constants.errno.EBADF is different and we must assume that ENOENT + * is no different here. + * + * @param {SystemError} error + * @param {number} errno + * @param {string} code + * @private + */ +function _isExpectedError(error, errno, code) { + return IS_WIN32 ? error.code === code : error.code === code && error.errno === errno; +} + +/** + * Sets the graceful cleanup. + * + * If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the + * temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary + * object removals. + */ +function setGracefulCleanup() { + _gracefulCleanup = true; +} + +/** + * Returns the currently configured tmp dir from os.tmpdir(). + * + * @private + */ +function _getTmpDir(options, cb) { + return fs.realpath((options && options.tmpdir) || os.tmpdir(), cb); +} + +/** + * Returns the currently configured tmp dir from os.tmpdir(). + * + * @private + */ +function _getTmpDirSync(options) { + return fs.realpathSync((options && options.tmpdir) || os.tmpdir()); +} + +// Install process exit listener +process.addListener(EXIT, _garbageCollector); + +/** + * Configuration options. + * + * @typedef {Object} Options + * @property {?boolean} keep the temporary object (file or dir) will not be garbage collected + * @property {?number} tries the number of tries before give up the name generation + * @property (?int) mode the access mode, defaults are 0o700 for directories and 0o600 for files + * @property {?string} template the "mkstemp" like filename template + * @property {?string} name fixed name relative to tmpdir or the specified dir option + * @property {?string} dir tmp directory relative to the root tmp directory in use + * @property {?string} prefix prefix for the generated name + * @property {?string} postfix postfix for the generated name + * @property {?string} tmpdir the root tmp directory which overrides the os tmpdir + * @property {?boolean} unsafeCleanup recursively removes the created temporary directory, even when it's not empty + * @property {?boolean} detachDescriptor detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection + * @property {?boolean} discardDescriptor discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection + */ + +/** + * @typedef {Object} FileSyncObject + * @property {string} name the name of the file + * @property {string} fd the file descriptor or -1 if the fd has been discarded + * @property {fileCallback} removeCallback the callback function to remove the file + */ + +/** + * @typedef {Object} DirSyncObject + * @property {string} name the name of the directory + * @property {fileCallback} removeCallback the callback function to remove the directory + */ + +/** + * @callback tmpNameCallback + * @param {?Error} err the error object if anything goes wrong + * @param {string} name the temporary file name + */ + +/** + * @callback fileCallback + * @param {?Error} err the error object if anything goes wrong + * @param {string} name the temporary file name + * @param {number} fd the file descriptor or -1 if the fd had been discarded + * @param {cleanupCallback} fn the cleanup callback function + */ + +/** + * @callback fileCallbackSync + * @param {?Error} err the error object if anything goes wrong + * @param {string} name the temporary file name + * @param {number} fd the file descriptor or -1 if the fd had been discarded + * @param {cleanupCallbackSync} fn the cleanup callback function + */ + +/** + * @callback dirCallback + * @param {?Error} err the error object if anything goes wrong + * @param {string} name the temporary file name + * @param {cleanupCallback} fn the cleanup callback function + */ + +/** + * @callback dirCallbackSync + * @param {?Error} err the error object if anything goes wrong + * @param {string} name the temporary file name + * @param {cleanupCallbackSync} fn the cleanup callback function + */ + +/** + * Removes the temporary created file or directory. + * + * @callback cleanupCallback + * @param {simpleCallback} [next] function to call whenever the tmp object needs to be removed + */ + +/** + * Removes the temporary created file or directory. + * + * @callback cleanupCallbackSync + */ + +/** + * Callback function for function composition. + * @see {@link https://github.com/raszi/node-tmp/issues/57|raszi/node-tmp#57} + * + * @callback simpleCallback + */ + +// exporting all the needed methods + +// evaluate _getTmpDir() lazily, mainly for simplifying testing but it also will +// allow users to reconfigure the temporary directory +Object.defineProperty(module.exports, "tmpdir", ({ + enumerable: true, + configurable: false, + get: function () { + return _getTmpDirSync(); + } +})); + +module.exports.dir = dir; +module.exports.dirSync = dirSync; + +module.exports.file = file; +module.exports.fileSync = fileSync; + +module.exports.tmpName = tmpName; +module.exports.tmpNameSync = tmpNameSync; + +module.exports.setGracefulCleanup = setGracefulCleanup; + + /***/ }), /***/ 1552: @@ -174728,12 +178009,39 @@ exports.assertValidPattern = assertValidPattern; "use strict"; // parse a single path portion +var _a; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AST = void 0; const brace_expressions_js_1 = __nccwpck_require__(90570); const unescape_js_1 = __nccwpck_require__(28075); const types = new Set(['!', '?', '+', '*', '@']); const isExtglobType = (c) => types.has(c); +const isExtglobAST = (c) => isExtglobType(c.type); +const adoptionMap = new Map([ + ['!', ['@']], + ['?', ['?', '@']], + ['@', ['@']], + ['*', ['*', '+', '?', '@']], + ['+', ['+', '@']], +]); +const adoptionWithSpaceMap = new Map([ + ['!', ['?']], + ['@', ['?']], + ['+', ['?', '*']], +]); +const adoptionAnyMap = new Map([ + ['!', ['?', '@']], + ['?', ['?', '@']], + ['@', ['?', '@']], + ['*', ['*', '+', '?', '@']], + ['+', ['+', '@', '?', '*']], +]); +const usurpMap = new Map([ + ['!', new Map([['!', '@']])], + ['?', new Map([['*', '*'], ['+', '*']])], + ['@', new Map([['!', '!'], ['?', '?'], ['@', '@'], ['*', '*'], ['+', '+']])], + ['+', new Map([['?', '*'], ['*', '*']])], +]); // Patterns that get prepended to bind to the start of either the // entire string, or just a single path portion, to prevent dots // and/or traversal patterns, when needed. @@ -174850,7 +178158,7 @@ class AST { if (p === '') continue; /* c8 ignore start */ - if (typeof p !== 'string' && !(p instanceof AST && p.#parent === this)) { + if (typeof p !== 'string' && !(p instanceof _a && p.#parent === this)) { throw new Error('invalid part: ' + p); } /* c8 ignore stop */ @@ -174882,7 +178190,7 @@ class AST { const p = this.#parent; for (let i = 0; i < this.#parentIndex; i++) { const pp = p.#parts[i]; - if (!(pp instanceof AST && pp.type === '!')) { + if (!(pp instanceof _a && pp.type === '!')) { return false; } } @@ -174910,13 +178218,14 @@ class AST { this.push(part.clone(this)); } clone(parent) { - const c = new AST(this.type, parent); + const c = new _a(this.type, parent); for (const p of this.#parts) { c.copyIn(p); } return c; } - static #parseAST(str, ast, pos, opt) { + static #parseAST(str, ast, pos, opt, extDepth) { + const maxDepth = opt.maxExtglobRecursion ?? 2; let escaping = false; let inBrace = false; let braceStart = -1; @@ -174953,11 +178262,15 @@ class AST { acc += c; continue; } - if (!opt.noext && isExtglobType(c) && str.charAt(i) === '(') { + const doRecurse = !opt.noext && + isExtglobType(c) && + str.charAt(i) === '(' && + extDepth <= maxDepth; + if (doRecurse) { ast.push(acc); acc = ''; - const ext = new AST(c, ast); - i = AST.#parseAST(str, ext, i, opt); + const ext = new _a(c, ast); + i = _a.#parseAST(str, ext, i, opt, extDepth + 1); ast.push(ext); continue; } @@ -174969,7 +178282,7 @@ class AST { // some kind of extglob, pos is at the ( // find the next | or ) let i = pos + 1; - let part = new AST(null, ast); + let part = new _a(null, ast); const parts = []; let acc = ''; while (i < str.length) { @@ -175000,19 +178313,25 @@ class AST { acc += c; continue; } - if (isExtglobType(c) && str.charAt(i) === '(') { + const doRecurse = isExtglobType(c) && + str.charAt(i) === '(' && + /* c8 ignore start - the maxDepth is sufficient here */ + (extDepth <= maxDepth || (ast && ast.#canAdoptType(c))); + /* c8 ignore stop */ + if (doRecurse) { + const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1; part.push(acc); acc = ''; - const ext = new AST(c, part); + const ext = new _a(c, part); part.push(ext); - i = AST.#parseAST(str, ext, i, opt); + i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd); continue; } if (c === '|') { part.push(acc); acc = ''; parts.push(part); - part = new AST(null, ast); + part = new _a(null, ast); continue; } if (c === ')') { @@ -175034,9 +178353,115 @@ class AST { ast.#parts = [str.substring(pos - 1)]; return i; } + #canAdoptWithSpace(child) { + return this.#canAdopt(child, adoptionWithSpaceMap); + } + #canAdopt(child, map = adoptionMap) { + if (!child || + typeof child !== 'object' || + child.type !== null || + child.#parts.length !== 1 || + this.type === null) { + return false; + } + const gc = child.#parts[0]; + if (!gc || typeof gc !== 'object' || gc.type === null) { + return false; + } + return this.#canAdoptType(gc.type, map); + } + #canAdoptType(c, map = adoptionAnyMap) { + return !!map.get(this.type)?.includes(c); + } + #adoptWithSpace(child, index) { + const gc = child.#parts[0]; + const blank = new _a(null, gc, this.options); + blank.#parts.push(''); + gc.push(blank); + this.#adopt(child, index); + } + #adopt(child, index) { + const gc = child.#parts[0]; + this.#parts.splice(index, 1, ...gc.#parts); + for (const p of gc.#parts) { + if (typeof p === 'object') + p.#parent = this; + } + this.#toString = undefined; + } + #canUsurpType(c) { + const m = usurpMap.get(this.type); + return !!(m?.has(c)); + } + #canUsurp(child) { + if (!child || + typeof child !== 'object' || + child.type !== null || + child.#parts.length !== 1 || + this.type === null || + this.#parts.length !== 1) { + return false; + } + const gc = child.#parts[0]; + if (!gc || typeof gc !== 'object' || gc.type === null) { + return false; + } + return this.#canUsurpType(gc.type); + } + #usurp(child) { + const m = usurpMap.get(this.type); + const gc = child.#parts[0]; + const nt = m?.get(gc.type); + /* c8 ignore start - impossible */ + if (!nt) + return false; + /* c8 ignore stop */ + this.#parts = gc.#parts; + for (const p of this.#parts) { + if (typeof p === 'object') + p.#parent = this; + } + this.type = nt; + this.#toString = undefined; + this.#emptyExt = false; + } + #flatten() { + if (!isExtglobAST(this)) { + for (const p of this.#parts) { + if (typeof p === 'object') + p.#flatten(); + } + } + else { + let iterations = 0; + let done = false; + do { + done = true; + for (let i = 0; i < this.#parts.length; i++) { + const c = this.#parts[i]; + if (typeof c === 'object') { + c.#flatten(); + if (this.#canAdopt(c)) { + done = false; + this.#adopt(c, i); + } + else if (this.#canAdoptWithSpace(c)) { + done = false; + this.#adoptWithSpace(c, i); + } + else if (this.#canUsurp(c)) { + done = false; + this.#usurp(c); + } + } + } + } while (!done && ++iterations < 10); + } + this.#toString = undefined; + } static fromGlob(pattern, options = {}) { - const ast = new AST(null, undefined, options); - AST.#parseAST(pattern, ast, 0, options); + const ast = new _a(null, undefined, options); + _a.#parseAST(pattern, ast, 0, options, 0); return ast; } // returns the regular expression if there's magic, or the unescaped @@ -175140,14 +178565,16 @@ class AST { // or start or whatever) and prepend ^ or / at the Regexp construction. toRegExpSource(allowDot) { const dot = allowDot ?? !!this.#options.dot; - if (this.#root === this) + if (this.#root === this) { + this.#flatten(); this.#fillNegs(); - if (!this.type) { + } + if (!isExtglobAST(this)) { const noEmpty = this.isStart() && this.isEnd(); const src = this.#parts .map(p => { const [re, _, hasMagic, uflag] = typeof p === 'string' - ? AST.#parseGlob(p, this.#hasMagic, noEmpty) + ? _a.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot); this.#hasMagic = this.#hasMagic || hasMagic; this.#uflag = this.#uflag || uflag; @@ -175206,9 +178633,10 @@ class AST { // invalid extglob, has to at least be *something* present, if it's // the entire path portion. const s = this.toString(); - this.#parts = [s]; - this.type = null; - this.#hasMagic = undefined; + const me = this; + me.#parts = [s]; + me.type = null; + me.#hasMagic = undefined; return [s, (0, unescape_js_1.unescape)(this.toString()), false, false]; } // XXX abstract out this map method @@ -175272,11 +178700,14 @@ class AST { let escaping = false; let re = ''; let uflag = false; + // multiple stars that aren't globstars coalesce into one * + let inStar = false; for (let i = 0; i < glob.length; i++) { const c = glob.charAt(i); if (escaping) { escaping = false; re += (reSpecials.has(c) ? '\\' : '') + c; + inStar = false; continue; } if (c === '\\') { @@ -175295,17 +178726,21 @@ class AST { uflag = uflag || needUflag; i += consumed - 1; hasMagic = hasMagic || magic; + inStar = false; continue; } } if (c === '*') { - if (noEmpty && glob === '*') - re += starNoEmpty; - else - re += star; + if (inStar) + continue; + inStar = true; + re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star; hasMagic = true; continue; } + else { + inStar = false; + } if (c === '?') { re += qmark; hasMagic = true; @@ -175317,6 +178752,7 @@ class AST { } } exports.AST = AST; +_a = AST; //# sourceMappingURL=ast.js.map /***/ }), @@ -175720,11 +179156,13 @@ class Minimatch { isWindows; platform; windowsNoMagicRoot; + maxGlobstarRecursion; regexp; constructor(pattern, options = {}) { (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); options = options || {}; this.options = options; + this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200; this.pattern = pattern; this.platform = options.platform || defaultPlatform; this.isWindows = this.platform === 'win32'; @@ -176124,7 +179562,8 @@ class Minimatch { // out of pattern, then that's fine, as long as all // the parts match. matchOne(file, pattern, partial = false) { - const options = this.options; + let fileStartIndex = 0; + let patternStartIndex = 0; // UNC paths like //?/X:/... can match X:/... and vice versa // Drive letters in absolute drive or unc paths are always compared // case-insensitively. @@ -176145,15 +179584,14 @@ class Minimatch { const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined; const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined; if (typeof fdi === 'number' && typeof pdi === 'number') { - const [fd, pd] = [file[fdi], pattern[pdi]]; + const [fd, pd] = [ + file[fdi], + pattern[pdi], + ]; if (fd.toLowerCase() === pd.toLowerCase()) { pattern[pdi] = fd; - if (pdi > fdi) { - pattern = pattern.slice(pdi); - } - else if (fdi > pdi) { - file = file.slice(fdi); - } + patternStartIndex = pdi; + fileStartIndex = fdi; } } } @@ -176163,102 +179601,127 @@ class Minimatch { if (optimizationLevel >= 2) { file = this.levelTwoFileOptimize(file); } - this.debug('matchOne', this, { file, pattern }); - this.debug('matchOne', file.length, pattern.length); - for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { - this.debug('matchOne loop'); - var p = pattern[pi]; - var f = file[fi]; - this.debug(pattern, p, f); - // should be impossible. - // some invalid regexp stuff in the set. - /* c8 ignore start */ - if (p === false) { + if (pattern.includes(exports.GLOBSTAR)) { + return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex); + } + return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex); + } + #matchGlobstar(file, pattern, partial, fileIndex, patternIndex) { + const firstgs = pattern.indexOf(exports.GLOBSTAR, patternIndex); + const lastgs = pattern.lastIndexOf(exports.GLOBSTAR); + const [head, body, tail] = partial ? [ + pattern.slice(patternIndex, firstgs), + pattern.slice(firstgs + 1), + [], + ] : [ + pattern.slice(patternIndex, firstgs), + pattern.slice(firstgs + 1, lastgs), + pattern.slice(lastgs + 1), + ]; + if (head.length) { + const fileHead = file.slice(fileIndex, fileIndex + head.length); + if (!this.#matchOne(fileHead, head, partial, 0, 0)) + return false; + fileIndex += head.length; + } + let fileTailMatch = 0; + if (tail.length) { + if (tail.length + fileIndex > file.length) return false; + let tailStart = file.length - tail.length; + if (this.#matchOne(file, tail, partial, tailStart, 0)) { + fileTailMatch = tail.length; } - /* c8 ignore stop */ - if (p === exports.GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]); - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi; - var pr = pi + 1; - if (pr === pl) { - this.debug('** at the end'); - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for (; fi < fl; fi++) { - if (file[fi] === '.' || - file[fi] === '..' || - (!options.dot && file[fi].charAt(0) === '.')) - return false; - } - return true; + else { + if (file[file.length - 1] !== '' || + fileIndex + tail.length === file.length) { + return false; } - // ok, let's see if we can swallow whatever we can. - while (fr < fl) { - var swallowee = file[fr]; - this.debug('\nglobstar while', file, fr, pattern, pr, swallowee); - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee); - // found a match. - return true; - } - else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === '.' || - swallowee === '..' || - (!options.dot && swallowee.charAt(0) === '.')) { - this.debug('dot detected!', file, fr, pattern, pr); - break; - } - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue'); - fr++; - } + tailStart--; + if (!this.#matchOne(file, tail, partial, tailStart, 0)) + return false; + fileTailMatch = tail.length + 1; + } + } + if (!body.length) { + let sawSome = !!fileTailMatch; + for (let i = fileIndex; i < file.length - fileTailMatch; i++) { + const f = String(file[i]); + sawSome = true; + if (f === '.' || f === '..' || + (!this.options.dot && f.startsWith('.'))) { + return false; } - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - /* c8 ignore start */ - if (partial) { - // ran out of file - this.debug('\n>>> no match, partial?', file, fr, pattern, pr); - if (fr === fl) { - return true; - } + } + return partial || sawSome; + } + const bodySegments = [[[], 0]]; + let currentBody = bodySegments[0]; + let nonGsParts = 0; + const nonGsPartsSums = [0]; + for (const b of body) { + if (b === exports.GLOBSTAR) { + nonGsPartsSums.push(nonGsParts); + currentBody = [[], 0]; + bodySegments.push(currentBody); + } + else { + currentBody[0].push(b); + nonGsParts++; + } + } + let i = bodySegments.length - 1; + const fileLength = file.length - fileTailMatch; + for (const b of bodySegments) { + b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length); + } + return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch); + } + #matchGlobStarBodySections(file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) { + const bs = bodySegments[bodyIndex]; + if (!bs) { + for (let i = fileIndex; i < file.length; i++) { + sawTail = true; + const f = file[i]; + if (f === '.' || f === '..' || + (!this.options.dot && f.startsWith('.'))) { + return false; } - /* c8 ignore stop */ + } + return sawTail; + } + const [body, after] = bs; + while (fileIndex <= after) { + const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0); + if (m && globStarDepth < this.maxGlobstarRecursion) { + const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail); + if (sub !== false) + return sub; + } + const f = file[fileIndex]; + if (f === '.' || f === '..' || + (!this.options.dot && f.startsWith('.'))) { return false; } - // something other than ** - // non-magic patterns just have to match exactly - // patterns with magic have been turned into regexps. + fileIndex++; + } + return partial || null; + } + #matchOne(file, pattern, partial, fileIndex, patternIndex) { + let fi; + let pi; + let pl; + let fl; + for (fi = fileIndex, pi = patternIndex, + fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { + this.debug('matchOne loop'); + let p = pattern[pi]; + let f = file[fi]; + this.debug(pattern, p, f); + /* c8 ignore start */ + if (p === false || p === exports.GLOBSTAR) + return false; + /* c8 ignore stop */ let hit; if (typeof p === 'string') { hit = f === p; @@ -176271,38 +179734,17 @@ class Minimatch { if (!hit) return false; } - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - // now either we fell off the end of the pattern, or we're done. if (fi === fl && pi === pl) { - // ran out of pattern and filename at the same time. - // an exact hit! return true; } else if (fi === fl) { - // ran out of file, but still had pattern left. - // this is ok if we're doing the match as part of - // a glob fs traversal. return partial; } else if (pi === pl) { - // ran out of pattern, still have file left. - // this is only acceptable if we're on the very last - // empty segment of a file with a trailing slash. - // a/* should match a/b/ return fi === fl - 1 && file[fi] === ''; /* c8 ignore start */ } else { - // should be unreachable. throw new Error('wtf?'); } /* c8 ignore stop */ @@ -198577,6 +202019,378 @@ function cleanEscapedString(input) { } +/***/ }), + +/***/ 27633: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +exports.parseISO = parseISO; +var _index = __nccwpck_require__(46104); + +var _index2 = __nccwpck_require__(25848); +var _index3 = __nccwpck_require__(44826); + +/** + * 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; +} + + +/***/ }), + +/***/ 26380: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +exports.parseJSON = parseJSON; +var _index = __nccwpck_require__(44826); + +/** + * 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, + ); +} + + /***/ }), /***/ 29861: @@ -201109,378 +204923,6 @@ function isLeapYearIndex(year) { } -/***/ }), - -/***/ 27633: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -exports.parseISO = parseISO; -var _index = __nccwpck_require__(46104); - -var _index2 = __nccwpck_require__(25848); -var _index3 = __nccwpck_require__(44826); - -/** - * 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; -} - - -/***/ }), - -/***/ 26380: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -exports.parseJSON = parseJSON; -var _index = __nccwpck_require__(44826); - -/** - * 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, - ); -} - - /***/ }), /***/ 80144: @@ -204551,7 +207993,7 @@ function yearsToQuarters(years) { /***/ 50591: /***/ ((module) => { -(()=>{"use strict";var t={d:(e,n)=>{for(var i in n)t.o(n,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:n[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{XMLBuilder:()=>dt,XMLParser:()=>it,XMLValidator:()=>gt});const n=":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",i=new RegExp("^["+n+"]["+n+"\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$");function s(t,e){const n=[];let i=e.exec(t);for(;i;){const s=[];s.startIndex=e.lastIndex-i[0].length;const r=i.length;for(let t=0;t"!==t[o]&&" "!==t[o]&&"\t"!==t[o]&&"\n"!==t[o]&&"\r"!==t[o];o++)p+=t[o];if(p=p.trim(),"/"===p[p.length-1]&&(p=p.substring(0,p.length-1),o--),!r(p)){let e;return e=0===p.trim().length?"Invalid space after '<'.":"Tag '"+p+"' is an invalid name.",m("InvalidTag",e,b(t,o))}const c=f(t,o);if(!1===c)return m("InvalidAttr","Attributes for '"+p+"' have open quote.",b(t,o));let E=c.value;if(o=c.index,"/"===E[E.length-1]){const n=o-E.length;E=E.substring(0,E.length-1);const s=g(E,e);if(!0!==s)return m(s.err.code,s.err.msg,b(t,n+s.err.line));i=!0}else if(d){if(!c.tagClosed)return m("InvalidTag","Closing tag '"+p+"' doesn't have proper closing.",b(t,o));if(E.trim().length>0)return m("InvalidTag","Closing tag '"+p+"' can't have attributes or invalid starting.",b(t,a));if(0===n.length)return m("InvalidTag","Closing tag '"+p+"' has not been opened.",b(t,a));{const e=n.pop();if(p!==e.tagName){let n=b(t,e.tagStartPos);return m("InvalidTag","Expected closing tag '"+e.tagName+"' (opened in line "+n.line+", col "+n.col+") instead of closing tag '"+p+"'.",b(t,a))}0==n.length&&(s=!0)}}else{const r=g(E,e);if(!0!==r)return m(r.err.code,r.err.msg,b(t,o-E.length+r.err.line));if(!0===s)return m("InvalidXml","Multiple possible root nodes found.",b(t,o));-1!==e.unpairedTags.indexOf(p)||n.push({tagName:p,tagStartPos:a}),i=!0}for(o++;o0)||m("InvalidXml","Invalid '"+JSON.stringify(n.map((t=>t.tagName)),null,4).replace(/\r?\n/g,"")+"' found.",{line:1,col:1}):m("InvalidXml","Start tag expected.",1)}function l(t){return" "===t||"\t"===t||"\n"===t||"\r"===t}function u(t,e){const n=e;for(;e5&&"xml"===i)return m("InvalidXml","XML declaration allowed only at the start of the document.",b(t,e));if("?"==t[e]&&">"==t[e+1]){e++;break}}return e}function h(t,e){if(t.length>e+5&&"-"===t[e+1]&&"-"===t[e+2]){for(e+=3;e"===t[e+2]){e+=2;break}}else if(t.length>e+8&&"D"===t[e+1]&&"O"===t[e+2]&&"C"===t[e+3]&&"T"===t[e+4]&&"Y"===t[e+5]&&"P"===t[e+6]&&"E"===t[e+7]){let n=1;for(e+=8;e"===t[e]&&(n--,0===n))break}else if(t.length>e+9&&"["===t[e+1]&&"C"===t[e+2]&&"D"===t[e+3]&&"A"===t[e+4]&&"T"===t[e+5]&&"A"===t[e+6]&&"["===t[e+7])for(e+=8;e"===t[e+2]){e+=2;break}return e}const d='"',p="'";function f(t,e){let n="",i="",s=!1;for(;e"===t[e]&&""===i){s=!0;break}n+=t[e]}return""===i&&{value:n,index:e,tagClosed:s}}const c=new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?","g");function g(t,e){const n=s(t,c),i={};for(let t=0;t!1,commentPropName:!1,unpairedTags:[],processEntities:!0,htmlEntities:!1,ignoreDeclaration:!1,ignorePiTags:!1,transformTagName:!1,transformAttributeName:!1,updateTag:function(t,e,n){return t},captureMetaData:!1};function T(t){return"boolean"==typeof t?{enabled:t,maxEntitySize:1e4,maxExpansionDepth:10,maxTotalExpansions:1e3,maxExpandedLength:1e5,allowedTags:null,tagFilter:null}:"object"==typeof t&&null!==t?{enabled:!1!==t.enabled,maxEntitySize:t.maxEntitySize??1e4,maxExpansionDepth:t.maxExpansionDepth??10,maxTotalExpansions:t.maxTotalExpansions??1e3,maxExpandedLength:t.maxExpandedLength??1e5,allowedTags:t.allowedTags??null,tagFilter:t.tagFilter??null}:T(!0)}const w=function(t){const e=Object.assign({},y,t);return e.processEntities=T(e.processEntities),e};let v;v="function"!=typeof Symbol?"@@xmlMetadata":Symbol("XML Node Metadata");class I{constructor(t){this.tagname=t,this.child=[],this[":@"]={}}add(t,e){"__proto__"===t&&(t="#__proto__"),this.child.push({[t]:e})}addChild(t,e){"__proto__"===t.tagname&&(t.tagname="#__proto__"),t[":@"]&&Object.keys(t[":@"]).length>0?this.child.push({[t.tagname]:t.child,":@":t[":@"]}):this.child.push({[t.tagname]:t.child}),void 0!==e&&(this.child[this.child.length-1][v]={startIndex:e})}static getMetaDataSymbol(){return v}}class O{constructor(t){this.suppressValidationErr=!t,this.options=t}readDocType(t,e){const n={};if("O"!==t[e+3]||"C"!==t[e+4]||"T"!==t[e+5]||"Y"!==t[e+6]||"P"!==t[e+7]||"E"!==t[e+8])throw new Error("Invalid Tag instead of DOCTYPE");{e+=9;let i=1,s=!1,r=!1,o="";for(;e"===t[e]){if(r?"-"===t[e-1]&&"-"===t[e-2]&&(r=!1,i--):i--,0===i)break}else"["===t[e]?s=!0:o+=t[e];else{if(s&&A(t,"!ENTITY",e)){let i,s;if(e+=7,[i,s,e]=this.readEntityExp(t,e+1,this.suppressValidationErr),-1===s.indexOf("&")){const t=i.replace(/[.\-+*:]/g,"\\.");n[i]={regx:RegExp(`&${t};`,"g"),val:s}}}else if(s&&A(t,"!ELEMENT",e)){e+=8;const{index:n}=this.readElementExp(t,e+1);e=n}else if(s&&A(t,"!ATTLIST",e))e+=8;else if(s&&A(t,"!NOTATION",e)){e+=9;const{index:n}=this.readNotationExp(t,e+1,this.suppressValidationErr);e=n}else{if(!A(t,"!--",e))throw new Error("Invalid DOCTYPE");r=!0}i++,o=""}if(0!==i)throw new Error("Unclosed DOCTYPE")}return{entities:n,i:e}}readEntityExp(t,e){e=P(t,e);let n="";for(;ethis.options.maxEntitySize)throw new Error(`Entity "${n}" size (${i.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`);return[n,i,--e]}readNotationExp(t,e){e=P(t,e);let n="";for(;e{for(;e{for(const n of t){if("string"==typeof n&&e===n)return!0;if(n instanceof RegExp&&n.test(e))return!0}}:()=>!1}class F{constructor(t){if(this.options=t,this.currentNode=null,this.tagsNodeStack=[],this.docTypeEntities={},this.lastEntities={apos:{regex:/&(apos|#39|#x27);/g,val:"'"},gt:{regex:/&(gt|#62|#x3E);/g,val:">"},lt:{regex:/&(lt|#60|#x3C);/g,val:"<"},quot:{regex:/&(quot|#34|#x22);/g,val:'"'}},this.ampEntity={regex:/&(amp|#38|#x26);/g,val:"&"},this.htmlEntities={space:{regex:/&(nbsp|#160);/g,val:" "},cent:{regex:/&(cent|#162);/g,val:"¢"},pound:{regex:/&(pound|#163);/g,val:"£"},yen:{regex:/&(yen|#165);/g,val:"¥"},euro:{regex:/&(euro|#8364);/g,val:"€"},copyright:{regex:/&(copy|#169);/g,val:"©"},reg:{regex:/&(reg|#174);/g,val:"®"},inr:{regex:/&(inr|#8377);/g,val:"₹"},num_dec:{regex:/&#([0-9]{1,7});/g,val:(t,e)=>K(e,10,"&#")},num_hex:{regex:/&#x([0-9a-fA-F]{1,6});/g,val:(t,e)=>K(e,16,"&#x")}},this.addExternalEntities=j,this.parseXml=B,this.parseTextData=M,this.resolveNameSpace=_,this.buildAttributesMap=U,this.isItStopNode=X,this.replaceEntitiesValue=Y,this.readStopNodeData=q,this.saveTextToParentTag=G,this.addChild=R,this.ignoreAttributesFn=L(this.options.ignoreAttributes),this.entityExpansionCount=0,this.currentExpandedLength=0,this.options.stopNodes&&this.options.stopNodes.length>0){this.stopNodesExact=new Set,this.stopNodesWildcard=new Set;for(let t=0;t0)){o||(t=this.replaceEntitiesValue(t,e,n));const i=this.options.tagValueProcessor(e,t,n,s,r);return null==i?t:typeof i!=typeof t||i!==t?i:this.options.trimValues||t.trim()===t?Z(t,this.options.parseTagValue,this.options.numberParseOptions):t}}function _(t){if(this.options.removeNSPrefix){const e=t.split(":"),n="/"===t.charAt(0)?"/":"";if("xmlns"===e[0])return"";2===e.length&&(t=n+e[1])}return t}const k=new RegExp("([^\\s=]+)\\s*(=\\s*(['\"])([\\s\\S]*?)\\3)?","gm");function U(t,e,n){if(!0!==this.options.ignoreAttributes&&"string"==typeof t){const i=s(t,k),r=i.length,o={};for(let t=0;t",o,"Closing Tag is not closed.");let r=t.substring(o+2,e).trim();if(this.options.removeNSPrefix){const t=r.indexOf(":");-1!==t&&(r=r.substr(t+1))}this.options.transformTagName&&(r=this.options.transformTagName(r)),n&&(i=this.saveTextToParentTag(i,n,s));const a=s.substring(s.lastIndexOf(".")+1);if(r&&-1!==this.options.unpairedTags.indexOf(r))throw new Error(`Unpaired tag can not be used as closing tag: `);let l=0;a&&-1!==this.options.unpairedTags.indexOf(a)?(l=s.lastIndexOf(".",s.lastIndexOf(".")-1),this.tagsNodeStack.pop()):l=s.lastIndexOf("."),s=s.substring(0,l),n=this.tagsNodeStack.pop(),i="",o=e}else if("?"===t[o+1]){let e=W(t,o,!1,"?>");if(!e)throw new Error("Pi Tag is not closed.");if(i=this.saveTextToParentTag(i,n,s),this.options.ignoreDeclaration&&"?xml"===e.tagName||this.options.ignorePiTags);else{const t=new I(e.tagName);t.add(this.options.textNodeName,""),e.tagName!==e.tagExp&&e.attrExpPresent&&(t[":@"]=this.buildAttributesMap(e.tagExp,s,e.tagName)),this.addChild(n,t,s,o)}o=e.closeIndex+1}else if("!--"===t.substr(o+1,3)){const e=z(t,"--\x3e",o+4,"Comment is not closed.");if(this.options.commentPropName){const r=t.substring(o+4,e-2);i=this.saveTextToParentTag(i,n,s),n.add(this.options.commentPropName,[{[this.options.textNodeName]:r}])}o=e}else if("!D"===t.substr(o+1,2)){const e=r.readDocType(t,o);this.docTypeEntities=e.entities,o=e.i}else if("!["===t.substr(o+1,2)){const e=z(t,"]]>",o,"CDATA is not closed.")-2,r=t.substring(o+9,e);i=this.saveTextToParentTag(i,n,s);let a=this.parseTextData(r,n.tagname,s,!0,!1,!0,!0);null==a&&(a=""),this.options.cdataPropName?n.add(this.options.cdataPropName,[{[this.options.textNodeName]:r}]):n.add(this.options.textNodeName,a),o=e+2}else{let r=W(t,o,this.options.removeNSPrefix),a=r.tagName;const l=r.rawTagName;let u=r.tagExp,h=r.attrExpPresent,d=r.closeIndex;if(this.options.transformTagName){const t=this.options.transformTagName(a);u===a&&(u=t),a=t}n&&i&&"!xml"!==n.tagname&&(i=this.saveTextToParentTag(i,n,s,!1));const p=n;p&&-1!==this.options.unpairedTags.indexOf(p.tagname)&&(n=this.tagsNodeStack.pop(),s=s.substring(0,s.lastIndexOf("."))),a!==e.tagname&&(s+=s?"."+a:a);const f=o;if(this.isItStopNode(this.stopNodesExact,this.stopNodesWildcard,s,a)){let e="";if(u.length>0&&u.lastIndexOf("/")===u.length-1)"/"===a[a.length-1]?(a=a.substr(0,a.length-1),s=s.substr(0,s.length-1),u=a):u=u.substr(0,u.length-1),o=r.closeIndex;else if(-1!==this.options.unpairedTags.indexOf(a))o=r.closeIndex;else{const n=this.readStopNodeData(t,l,d+1);if(!n)throw new Error(`Unexpected end of ${l}`);o=n.i,e=n.tagContent}const i=new I(a);a!==u&&h&&(i[":@"]=this.buildAttributesMap(u,s,a)),e&&(e=this.parseTextData(e,a,s,!0,h,!0,!0)),s=s.substr(0,s.lastIndexOf(".")),i.add(this.options.textNodeName,e),this.addChild(n,i,s,f)}else{if(u.length>0&&u.lastIndexOf("/")===u.length-1){if("/"===a[a.length-1]?(a=a.substr(0,a.length-1),s=s.substr(0,s.length-1),u=a):u=u.substr(0,u.length-1),this.options.transformTagName){const t=this.options.transformTagName(a);u===a&&(u=t),a=t}const t=new I(a);a!==u&&h&&(t[":@"]=this.buildAttributesMap(u,s,a)),this.addChild(n,t,s,f),s=s.substr(0,s.lastIndexOf("."))}else{const t=new I(a);this.tagsNodeStack.push(n),a!==u&&h&&(t[":@"]=this.buildAttributesMap(u,s,a)),this.addChild(n,t,s,f),n=t}i="",o=d}}else i+=t[o];return e.child};function R(t,e,n,i){this.options.captureMetaData||(i=void 0);const s=this.options.updateTag(e.tagname,n,e[":@"]);!1===s||("string"==typeof s?(e.tagname=s,t.addChild(e,i)):t.addChild(e,i))}const Y=function(t,e,n){if(-1===t.indexOf("&"))return t;const i=this.options.processEntities;if(!i.enabled)return t;if(i.allowedTags&&!i.allowedTags.includes(e))return t;if(i.tagFilter&&!i.tagFilter(e,n))return t;for(let e in this.docTypeEntities){const n=this.docTypeEntities[e],s=t.match(n.regx);if(s){if(this.entityExpansionCount+=s.length,i.maxTotalExpansions&&this.entityExpansionCount>i.maxTotalExpansions)throw new Error(`Entity expansion limit exceeded: ${this.entityExpansionCount} > ${i.maxTotalExpansions}`);const e=t.length;if(t=t.replace(n.regx,n.val),i.maxExpandedLength&&(this.currentExpandedLength+=t.length-e,this.currentExpandedLength>i.maxExpandedLength))throw new Error(`Total expanded content size exceeded: ${this.currentExpandedLength} > ${i.maxExpandedLength}`)}}if(-1===t.indexOf("&"))return t;for(let e in this.lastEntities){const n=this.lastEntities[e];t=t.replace(n.regex,n.val)}if(-1===t.indexOf("&"))return t;if(this.options.htmlEntities)for(let e in this.htmlEntities){const n=this.htmlEntities[e];t=t.replace(n.regex,n.val)}return t.replace(this.ampEntity.regex,this.ampEntity.val)};function G(t,e,n,i){return t&&(void 0===i&&(i=0===e.child.length),void 0!==(t=this.parseTextData(t,e.tagname,n,!1,!!e[":@"]&&0!==Object.keys(e[":@"]).length,i))&&""!==t&&e.add(this.options.textNodeName,t),t=""),t}function X(t,e,n,i){return!(!e||!e.has(i))||!(!t||!t.has(n))}function z(t,e,n,i){const s=t.indexOf(e,n);if(-1===s)throw new Error(i);return s+e.length-1}function W(t,e,n,i=">"){const s=function(t,e,n=">"){let i,s="";for(let r=e;r",n,`${e} is not closed`);if(t.substring(n+2,r).trim()===e&&(s--,0===s))return{tagContent:t.substring(i,n),i:r};n=r}else if("?"===t[n+1])n=z(t,"?>",n+1,"StopNode is not closed.");else if("!--"===t.substr(n+1,3))n=z(t,"--\x3e",n+3,"StopNode is not closed.");else if("!["===t.substr(n+1,2))n=z(t,"]]>",n,"StopNode is not closed.")-2;else{const i=W(t,n,">");i&&((i&&i.tagName)===e&&"/"!==i.tagExp[i.tagExp.length-1]&&s++,n=i.closeIndex)}}function Z(t,e,n){if(e&&"string"==typeof t){const e=t.trim();return"true"===e||"false"!==e&&function(t,e={}){if(e=Object.assign({},V,e),!t||"string"!=typeof t)return t;let n=t.trim();if(void 0!==e.skipLike&&e.skipLike.test(n))return t;if("0"===t)return 0;if(e.hex&&C.test(n))return function(t){if(parseInt)return parseInt(t,16);if(Number.parseInt)return Number.parseInt(t,16);if(window&&window.parseInt)return window.parseInt(t,16);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}(n);if(-1!==n.search(/.+[eE].+/))return function(t,e,n){if(!n.eNotation)return t;const i=e.match(D);if(i){let s=i[1]||"";const r=-1===i[3].indexOf("e")?"E":"e",o=i[2],a=s?t[o.length+1]===r:t[o.length]===r;return o.length>1&&a?t:1!==o.length||!i[3].startsWith(`.${r}`)&&i[3][0]!==r?n.leadingZeros&&!a?(e=(i[1]||"")+i[3],Number(e)):t:Number(e)}return t}(t,n,e);{const s=$.exec(n);if(s){const r=s[1]||"",o=s[2];let a=(i=s[3])&&-1!==i.indexOf(".")?("."===(i=i.replace(/0+$/,""))?i="0":"."===i[0]?i="0"+i:"."===i[i.length-1]&&(i=i.substring(0,i.length-1)),i):i;const l=r?"."===t[o.length+1]:"."===t[o.length];if(!e.leadingZeros&&(o.length>1||1===o.length&&!l))return t;{const i=Number(n),s=String(i);if(0===i||-0===i)return i;if(-1!==s.search(/[eE]/))return e.eNotation?i:t;if(-1!==n.indexOf("."))return"0"===s||s===a||s===`${r}${a}`?i:t;let l=o?a:n;return o?l===s||r+l===s?i:t:l===s||l===r+s?i:t}}return t}var i}(t,n)}return void 0!==t?t:""}function K(t,e,n){const i=Number.parseInt(t,e);return i>=0&&i<=1114111?String.fromCodePoint(i):n+t+";"}const Q=I.getMetaDataSymbol();function J(t,e){return H(t,e)}function H(t,e,n){let i;const s={};for(let r=0;r0&&(s[e.textNodeName]=i):void 0!==i&&(s[e.textNodeName]=i),s}function tt(t){const e=Object.keys(t);for(let t=0;t0&&(n="\n"),rt(t,e,"",n)}function rt(t,e,n,i){let s="",r=!1;for(let o=0;o`,r=!1;continue}if(l===e.commentPropName){s+=i+`\x3c!--${a[l][0][e.textNodeName]}--\x3e`,r=!0;continue}if("?"===l[0]){const t=at(a[":@"],e),n="?xml"===l?"":i;let o=a[l][0][e.textNodeName];o=0!==o.length?" "+o:"",s+=n+`<${l}${o}${t}?>`,r=!0;continue}let h=i;""!==h&&(h+=e.indentBy);const d=i+`<${l}${at(a[":@"],e)}`,p=rt(a[l],e,u,h);-1!==e.unpairedTags.indexOf(l)?e.suppressUnpairedNode?s+=d+">":s+=d+"/>":p&&0!==p.length||!e.suppressEmptyNode?p&&p.endsWith(">")?s+=d+`>${p}${i}`:(s+=d+">",p&&""!==i&&(p.includes("/>")||p.includes("`):s+=d+"/>",r=!0}return s}function ot(t){const e=Object.keys(t);for(let n=0;n0&&e.processEntities)for(let n=0;n","g"),val:">"},{regex:new RegExp("<","g"),val:"<"},{regex:new RegExp("'","g"),val:"'"},{regex:new RegExp('"',"g"),val:"""}],processEntities:!0,stopNodes:[],oneListGroup:!1};function dt(t){this.options=Object.assign({},ht,t),!0===this.options.ignoreAttributes||this.options.attributesGroupName?this.isAttribute=function(){return!1}:(this.ignoreAttributesFn=L(this.options.ignoreAttributes),this.attrPrefixLen=this.options.attributeNamePrefix.length,this.isAttribute=ct),this.processTextOrObjNode=pt,this.options.format?(this.indentate=ft,this.tagEndChar=">\n",this.newLine="\n"):(this.indentate=function(){return""},this.tagEndChar=">",this.newLine="")}function pt(t,e,n,i){const s=this.j2x(t,n+1,i.concat(e));return void 0!==t[this.options.textNodeName]&&1===Object.keys(t).length?this.buildTextValNode(t[this.options.textNodeName],e,s.attrStr,n):this.buildObjectNode(s.val,e,s.attrStr,n)}function ft(t){return this.options.indentBy.repeat(t)}function ct(t){return!(!t.startsWith(this.options.attributeNamePrefix)||t===this.options.textNodeName)&&t.substr(this.attrPrefixLen)}dt.prototype.build=function(t){return this.options.preserveOrder?st(t,this.options):(Array.isArray(t)&&this.options.arrayNodeName&&this.options.arrayNodeName.length>1&&(t={[this.options.arrayNodeName]:t}),this.j2x(t,0,[]).val)},dt.prototype.j2x=function(t,e,n){let i="",s="";const r=n.join(".");for(let o in t)if(Object.prototype.hasOwnProperty.call(t,o))if(void 0===t[o])this.isAttribute(o)&&(s+="");else if(null===t[o])this.isAttribute(o)||o===this.options.cdataPropName?s+="":"?"===o[0]?s+=this.indentate(e)+"<"+o+"?"+this.tagEndChar:s+=this.indentate(e)+"<"+o+"/"+this.tagEndChar;else if(t[o]instanceof Date)s+=this.buildTextValNode(t[o],o,"",e);else if("object"!=typeof t[o]){const n=this.isAttribute(o);if(n&&!this.ignoreAttributesFn(n,r))i+=this.buildAttrPairStr(n,""+t[o]);else if(!n)if(o===this.options.textNodeName){let e=this.options.tagValueProcessor(o,""+t[o]);s+=this.replaceEntitiesValue(e)}else s+=this.buildTextValNode(t[o],o,"",e)}else if(Array.isArray(t[o])){const i=t[o].length;let r="",a="";for(let l=0;l"+t+s}},dt.prototype.closeTag=function(t){let e="";return-1!==this.options.unpairedTags.indexOf(t)?this.options.suppressUnpairedNode||(e="/"):e=this.options.suppressEmptyNode?"/":`>`+this.newLine;if(!1!==this.options.commentPropName&&e===this.options.commentPropName)return this.indentate(i)+`\x3c!--${t}--\x3e`+this.newLine;if("?"===e[0])return this.indentate(i)+"<"+e+n+"?"+this.tagEndChar;{let s=this.options.tagValueProcessor(e,t);return s=this.replaceEntitiesValue(s),""===s?this.indentate(i)+"<"+e+n+this.closeTag(e)+this.tagEndChar:this.indentate(i)+"<"+e+n+">"+s+"0&&this.options.processEntities)for(let e=0;e{"use strict";var t={d:(e,n)=>{for(var i in n)t.o(n,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:n[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{XMLBuilder:()=>gt,XMLParser:()=>it,XMLValidator:()=>xt});const n=":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",i=new RegExp("^["+n+"]["+n+"\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$");function s(t,e){const n=[];let i=e.exec(t);for(;i;){const s=[];s.startIndex=e.lastIndex-i[0].length;const r=i.length;for(let t=0;t"!==t[r]&&" "!==t[r]&&"\t"!==t[r]&&"\n"!==t[r]&&"\r"!==t[r];r++)h+=t[r];if(h=h.trim(),"/"===h[h.length-1]&&(h=h.substring(0,h.length-1),r--),!b(h)){let e;return e=0===h.trim().length?"Invalid space after '<'.":"Tag '"+h+"' is an invalid name.",m("InvalidTag",e,N(t,r))}const p=c(t,r);if(!1===p)return m("InvalidAttr","Attributes for '"+h+"' have open quote.",N(t,r));let f=p.value;if(r=p.index,"/"===f[f.length-1]){const n=r-f.length;f=f.substring(0,f.length-1);const s=g(f,e);if(!0!==s)return m(s.err.code,s.err.msg,N(t,n+s.err.line));i=!0}else if(a){if(!p.tagClosed)return m("InvalidTag","Closing tag '"+h+"' doesn't have proper closing.",N(t,r));if(f.trim().length>0)return m("InvalidTag","Closing tag '"+h+"' can't have attributes or invalid starting.",N(t,o));if(0===n.length)return m("InvalidTag","Closing tag '"+h+"' has not been opened.",N(t,o));{const e=n.pop();if(h!==e.tagName){let n=N(t,e.tagStartPos);return m("InvalidTag","Expected closing tag '"+e.tagName+"' (opened in line "+n.line+", col "+n.col+") instead of closing tag '"+h+"'.",N(t,o))}0==n.length&&(s=!0)}}else{const a=g(f,e);if(!0!==a)return m(a.err.code,a.err.msg,N(t,r-f.length+a.err.line));if(!0===s)return m("InvalidXml","Multiple possible root nodes found.",N(t,r));-1!==e.unpairedTags.indexOf(h)||n.push({tagName:h,tagStartPos:o}),i=!0}for(r++;r0)||m("InvalidXml","Invalid '"+JSON.stringify(n.map(t=>t.tagName),null,4).replace(/\r?\n/g,"")+"' found.",{line:1,col:1}):m("InvalidXml","Start tag expected.",1)}function l(t){return" "===t||"\t"===t||"\n"===t||"\r"===t}function u(t,e){const n=e;for(;e5&&"xml"===i)return m("InvalidXml","XML declaration allowed only at the start of the document.",N(t,e));if("?"==t[e]&&">"==t[e+1]){e++;break}continue}return e}function d(t,e){if(t.length>e+5&&"-"===t[e+1]&&"-"===t[e+2]){for(e+=3;e"===t[e+2]){e+=2;break}}else if(t.length>e+8&&"D"===t[e+1]&&"O"===t[e+2]&&"C"===t[e+3]&&"T"===t[e+4]&&"Y"===t[e+5]&&"P"===t[e+6]&&"E"===t[e+7]){let n=1;for(e+=8;e"===t[e]&&(n--,0===n))break}else if(t.length>e+9&&"["===t[e+1]&&"C"===t[e+2]&&"D"===t[e+3]&&"A"===t[e+4]&&"T"===t[e+5]&&"A"===t[e+6]&&"["===t[e+7])for(e+=8;e"===t[e+2]){e+=2;break}return e}const h='"',p="'";function c(t,e){let n="",i="",s=!1;for(;e"===t[e]&&""===i){s=!0;break}n+=t[e]}return""===i&&{value:n,index:e,tagClosed:s}}const f=new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?","g");function g(t,e){const n=s(t,f),i={};for(let t=0;t!1,commentPropName:!1,unpairedTags:[],processEntities:!0,htmlEntities:!1,ignoreDeclaration:!1,ignorePiTags:!1,transformTagName:!1,transformAttributeName:!1,updateTag:function(t,e,n){return t},captureMetaData:!1,maxNestedTags:100,strictReservedNames:!0};function w(t){return"boolean"==typeof t?{enabled:t,maxEntitySize:1e4,maxExpansionDepth:10,maxTotalExpansions:1e3,maxExpandedLength:1e5,maxEntityCount:100,allowedTags:null,tagFilter:null}:"object"==typeof t&&null!==t?{enabled:!1!==t.enabled,maxEntitySize:t.maxEntitySize??1e4,maxExpansionDepth:t.maxExpansionDepth??10,maxTotalExpansions:t.maxTotalExpansions??1e3,maxExpandedLength:t.maxExpandedLength??1e5,maxEntityCount:t.maxEntityCount??100,allowedTags:t.allowedTags??null,tagFilter:t.tagFilter??null}:w(!0)}const v=function(t){const e=Object.assign({},T,t);return e.processEntities=w(e.processEntities),e};let O;O="function"!=typeof Symbol?"@@xmlMetadata":Symbol("XML Node Metadata");class I{constructor(t){this.tagname=t,this.child=[],this[":@"]=Object.create(null)}add(t,e){"__proto__"===t&&(t="#__proto__"),this.child.push({[t]:e})}addChild(t,e){"__proto__"===t.tagname&&(t.tagname="#__proto__"),t[":@"]&&Object.keys(t[":@"]).length>0?this.child.push({[t.tagname]:t.child,":@":t[":@"]}):this.child.push({[t.tagname]:t.child}),void 0!==e&&(this.child[this.child.length-1][O]={startIndex:e})}static getMetaDataSymbol(){return O}}class P{constructor(t){this.suppressValidationErr=!t,this.options=t}readDocType(t,e){const n=Object.create(null);let i=0;if("O"!==t[e+3]||"C"!==t[e+4]||"T"!==t[e+5]||"Y"!==t[e+6]||"P"!==t[e+7]||"E"!==t[e+8])throw new Error("Invalid Tag instead of DOCTYPE");{e+=9;let s=1,r=!1,o=!1,a="";for(;e"===t[e]){if(o?"-"===t[e-1]&&"-"===t[e-2]&&(o=!1,s--):s--,0===s)break}else"["===t[e]?r=!0:a+=t[e];else{if(r&&S(t,"!ENTITY",e)){let s,r;if(e+=7,[s,r,e]=this.readEntityExp(t,e+1,this.suppressValidationErr),-1===r.indexOf("&")){if(!1!==this.options.enabled&&this.options.maxEntityCount&&i>=this.options.maxEntityCount)throw new Error(`Entity count (${i+1}) exceeds maximum allowed (${this.options.maxEntityCount})`);const t=s.replace(/[.\-+*:]/g,"\\.");n[s]={regx:RegExp(`&${t};`,"g"),val:r},i++}}else if(r&&S(t,"!ELEMENT",e)){e+=8;const{index:n}=this.readElementExp(t,e+1);e=n}else if(r&&S(t,"!ATTLIST",e))e+=8;else if(r&&S(t,"!NOTATION",e)){e+=9;const{index:n}=this.readNotationExp(t,e+1,this.suppressValidationErr);e=n}else{if(!S(t,"!--",e))throw new Error("Invalid DOCTYPE");o=!0}s++,a=""}if(0!==s)throw new Error("Unclosed DOCTYPE")}return{entities:n,i:e}}readEntityExp(t,e){e=A(t,e);let n="";for(;ethis.options.maxEntitySize)throw new Error(`Entity "${n}" size (${i.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`);return[n,i,--e]}readNotationExp(t,e){e=A(t,e);let n="";for(;e{for(;e"},lt:{regex:/&(lt|#60|#x3C);/g,val:"<"},quot:{regex:/&(quot|#34|#x22);/g,val:'"'}},this.ampEntity={regex:/&(amp|#38|#x26);/g,val:"&"},this.htmlEntities={space:{regex:/&(nbsp|#160);/g,val:" "},cent:{regex:/&(cent|#162);/g,val:"¢"},pound:{regex:/&(pound|#163);/g,val:"£"},yen:{regex:/&(yen|#165);/g,val:"¥"},euro:{regex:/&(euro|#8364);/g,val:"€"},copyright:{regex:/&(copy|#169);/g,val:"©"},reg:{regex:/&(reg|#174);/g,val:"®"},inr:{regex:/&(inr|#8377);/g,val:"₹"},num_dec:{regex:/&#([0-9]{1,7});/g,val:(t,e)=>K(e,10,"&#")},num_hex:{regex:/&#x([0-9a-fA-F]{1,6});/g,val:(t,e)=>K(e,16,"&#x")}},this.addExternalEntities=F,this.parseXml=R,this.parseTextData=M,this.resolveNameSpace=k,this.buildAttributesMap=U,this.isItStopNode=X,this.replaceEntitiesValue=Y,this.readStopNodeData=q,this.saveTextToParentTag=G,this.addChild=B,this.ignoreAttributesFn="function"==typeof(e=this.options.ignoreAttributes)?e:Array.isArray(e)?t=>{for(const n of e){if("string"==typeof n&&t===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}}:()=>!1,this.entityExpansionCount=0,this.currentExpandedLength=0,this.options.stopNodes&&this.options.stopNodes.length>0){this.stopNodesExact=new Set,this.stopNodesWildcard=new Set;for(let t=0;t0)){o||(t=this.replaceEntitiesValue(t,e,n));const i=this.options.tagValueProcessor(e,t,n,s,r);return null==i?t:typeof i!=typeof t||i!==t?i:this.options.trimValues||t.trim()===t?Z(t,this.options.parseTagValue,this.options.numberParseOptions):t}}function k(t){if(this.options.removeNSPrefix){const e=t.split(":"),n="/"===t.charAt(0)?"/":"";if("xmlns"===e[0])return"";2===e.length&&(t=n+e[1])}return t}const _=new RegExp("([^\\s=]+)\\s*(=\\s*(['\"])([\\s\\S]*?)\\3)?","gm");function U(t,e,n){if(!0!==this.options.ignoreAttributes&&"string"==typeof t){const i=s(t,_),r=i.length,o={};for(let t=0;t",o,"Closing Tag is not closed.");let r=t.substring(o+2,e).trim();if(this.options.removeNSPrefix){const t=r.indexOf(":");-1!==t&&(r=r.substr(t+1))}this.options.transformTagName&&(r=this.options.transformTagName(r)),n&&(i=this.saveTextToParentTag(i,n,s));const a=s.substring(s.lastIndexOf(".")+1);if(r&&-1!==this.options.unpairedTags.indexOf(r))throw new Error(`Unpaired tag can not be used as closing tag: `);let l=0;a&&-1!==this.options.unpairedTags.indexOf(a)?(l=s.lastIndexOf(".",s.lastIndexOf(".")-1),this.tagsNodeStack.pop()):l=s.lastIndexOf("."),s=s.substring(0,l),n=this.tagsNodeStack.pop(),i="",o=e}else if("?"===t[o+1]){let e=W(t,o,!1,"?>");if(!e)throw new Error("Pi Tag is not closed.");if(i=this.saveTextToParentTag(i,n,s),this.options.ignoreDeclaration&&"?xml"===e.tagName||this.options.ignorePiTags);else{const t=new I(e.tagName);t.add(this.options.textNodeName,""),e.tagName!==e.tagExp&&e.attrExpPresent&&(t[":@"]=this.buildAttributesMap(e.tagExp,s,e.tagName)),this.addChild(n,t,s,o)}o=e.closeIndex+1}else if("!--"===t.substr(o+1,3)){const e=z(t,"--\x3e",o+4,"Comment is not closed.");if(this.options.commentPropName){const r=t.substring(o+4,e-2);i=this.saveTextToParentTag(i,n,s),n.add(this.options.commentPropName,[{[this.options.textNodeName]:r}])}o=e}else if("!D"===t.substr(o+1,2)){const e=r.readDocType(t,o);this.docTypeEntities=e.entities,o=e.i}else if("!["===t.substr(o+1,2)){const e=z(t,"]]>",o,"CDATA is not closed.")-2,r=t.substring(o+9,e);i=this.saveTextToParentTag(i,n,s);let a=this.parseTextData(r,n.tagname,s,!0,!1,!0,!0);null==a&&(a=""),this.options.cdataPropName?n.add(this.options.cdataPropName,[{[this.options.textNodeName]:r}]):n.add(this.options.textNodeName,a),o=e+2}else{let r=W(t,o,this.options.removeNSPrefix),a=r.tagName;const l=r.rawTagName;let u=r.tagExp,d=r.attrExpPresent,h=r.closeIndex;if(this.options.transformTagName){const t=this.options.transformTagName(a);u===a&&(u=t),a=t}if(this.options.strictReservedNames&&(a===this.options.commentPropName||a===this.options.cdataPropName))throw new Error(`Invalid tag name: ${a}`);n&&i&&"!xml"!==n.tagname&&(i=this.saveTextToParentTag(i,n,s,!1));const p=n;p&&-1!==this.options.unpairedTags.indexOf(p.tagname)&&(n=this.tagsNodeStack.pop(),s=s.substring(0,s.lastIndexOf("."))),a!==e.tagname&&(s+=s?"."+a:a);const c=o;if(this.isItStopNode(this.stopNodesExact,this.stopNodesWildcard,s,a)){let e="";if(u.length>0&&u.lastIndexOf("/")===u.length-1)"/"===a[a.length-1]?(a=a.substr(0,a.length-1),s=s.substr(0,s.length-1),u=a):u=u.substr(0,u.length-1),o=r.closeIndex;else if(-1!==this.options.unpairedTags.indexOf(a))o=r.closeIndex;else{const n=this.readStopNodeData(t,l,h+1);if(!n)throw new Error(`Unexpected end of ${l}`);o=n.i,e=n.tagContent}const i=new I(a);a!==u&&d&&(i[":@"]=this.buildAttributesMap(u,s,a)),e&&(e=this.parseTextData(e,a,s,!0,d,!0,!0)),s=s.substr(0,s.lastIndexOf(".")),i.add(this.options.textNodeName,e),this.addChild(n,i,s,c)}else{if(u.length>0&&u.lastIndexOf("/")===u.length-1){if("/"===a[a.length-1]?(a=a.substr(0,a.length-1),s=s.substr(0,s.length-1),u=a):u=u.substr(0,u.length-1),this.options.transformTagName){const t=this.options.transformTagName(a);u===a&&(u=t),a=t}const t=new I(a);a!==u&&d&&(t[":@"]=this.buildAttributesMap(u,s,a)),this.addChild(n,t,s,c),s=s.substr(0,s.lastIndexOf("."))}else{if(-1!==this.options.unpairedTags.indexOf(a)){const t=new I(a);a!==u&&d&&(t[":@"]=this.buildAttributesMap(u,s)),this.addChild(n,t,s,c),s=s.substr(0,s.lastIndexOf(".")),o=r.closeIndex;continue}{const t=new I(a);if(this.tagsNodeStack.length>this.options.maxNestedTags)throw new Error("Maximum nested tags exceeded");this.tagsNodeStack.push(n),a!==u&&d&&(t[":@"]=this.buildAttributesMap(u,s,a)),this.addChild(n,t,s,c),n=t}}i="",o=h}}else i+=t[o];return e.child};function B(t,e,n,i){this.options.captureMetaData||(i=void 0);const s=this.options.updateTag(e.tagname,n,e[":@"]);!1===s||("string"==typeof s?(e.tagname=s,t.addChild(e,i)):t.addChild(e,i))}const Y=function(t,e,n){if(-1===t.indexOf("&"))return t;const i=this.options.processEntities;if(!i.enabled)return t;if(i.allowedTags&&!i.allowedTags.includes(e))return t;if(i.tagFilter&&!i.tagFilter(e,n))return t;for(let e in this.docTypeEntities){const n=this.docTypeEntities[e],s=t.match(n.regx);if(s){if(this.entityExpansionCount+=s.length,i.maxTotalExpansions&&this.entityExpansionCount>i.maxTotalExpansions)throw new Error(`Entity expansion limit exceeded: ${this.entityExpansionCount} > ${i.maxTotalExpansions}`);const e=t.length;if(t=t.replace(n.regx,n.val),i.maxExpandedLength&&(this.currentExpandedLength+=t.length-e,this.currentExpandedLength>i.maxExpandedLength))throw new Error(`Total expanded content size exceeded: ${this.currentExpandedLength} > ${i.maxExpandedLength}`)}}if(-1===t.indexOf("&"))return t;for(let e in this.lastEntities){const n=this.lastEntities[e];t=t.replace(n.regex,n.val)}if(-1===t.indexOf("&"))return t;if(this.options.htmlEntities)for(let e in this.htmlEntities){const n=this.htmlEntities[e];t=t.replace(n.regex,n.val)}return t.replace(this.ampEntity.regex,this.ampEntity.val)};function G(t,e,n,i){return t&&(void 0===i&&(i=0===e.child.length),void 0!==(t=this.parseTextData(t,e.tagname,n,!1,!!e[":@"]&&0!==Object.keys(e[":@"]).length,i))&&""!==t&&e.add(this.options.textNodeName,t),t=""),t}function X(t,e,n,i){return!(!e||!e.has(i))||!(!t||!t.has(n))}function z(t,e,n,i){const s=t.indexOf(e,n);if(-1===s)throw new Error(i);return s+e.length-1}function W(t,e,n,i=">"){const s=function(t,e,n=">"){let i,s="";for(let r=e;r",n,`${e} is not closed`);if(t.substring(n+2,r).trim()===e&&(s--,0===s))return{tagContent:t.substring(i,n),i:r};n=r}else if("?"===t[n+1])n=z(t,"?>",n+1,"StopNode is not closed.");else if("!--"===t.substr(n+1,3))n=z(t,"--\x3e",n+3,"StopNode is not closed.");else if("!["===t.substr(n+1,2))n=z(t,"]]>",n,"StopNode is not closed.")-2;else{const i=W(t,n,">");i&&((i&&i.tagName)===e&&"/"!==i.tagExp[i.tagExp.length-1]&&s++,n=i.closeIndex)}}function Z(t,e,n){if(e&&"string"==typeof t){const e=t.trim();return"true"===e||"false"!==e&&function(t,e={}){if(e=Object.assign({},D,e),!t||"string"!=typeof t)return t;let n=t.trim();if(void 0!==e.skipLike&&e.skipLike.test(n))return t;if("0"===t)return 0;if(e.hex&&$.test(n))return function(t){if(parseInt)return parseInt(t,16);if(Number.parseInt)return Number.parseInt(t,16);if(window&&window.parseInt)return window.parseInt(t,16);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}(n);if(n.includes("e")||n.includes("E"))return function(t,e,n){if(!n.eNotation)return t;const i=e.match(j);if(i){let s=i[1]||"";const r=-1===i[3].indexOf("e")?"E":"e",o=i[2],a=s?t[o.length+1]===r:t[o.length]===r;return o.length>1&&a?t:1!==o.length||!i[3].startsWith(`.${r}`)&&i[3][0]!==r?n.leadingZeros&&!a?(e=(i[1]||"")+i[3],Number(e)):t:Number(e)}return t}(t,n,e);{const s=V.exec(n);if(s){const r=s[1]||"",o=s[2];let a=(i=s[3])&&-1!==i.indexOf(".")?("."===(i=i.replace(/0+$/,""))?i="0":"."===i[0]?i="0"+i:"."===i[i.length-1]&&(i=i.substring(0,i.length-1)),i):i;const l=r?"."===t[o.length+1]:"."===t[o.length];if(!e.leadingZeros&&(o.length>1||1===o.length&&!l))return t;{const i=Number(n),s=String(i);if(0===i)return i;if(-1!==s.search(/[eE]/))return e.eNotation?i:t;if(-1!==n.indexOf("."))return"0"===s||s===a||s===`${r}${a}`?i:t;let l=o?a:n;return o?l===s||r+l===s?i:t:l===s||l===r+s?i:t}}return t}var i}(t,n)}return void 0!==t?t:""}function K(t,e,n){const i=Number.parseInt(t,e);return i>=0&&i<=1114111?String.fromCodePoint(i):n+t+";"}const Q=I.getMetaDataSymbol();function J(t,e){return H(t,e)}function H(t,e,n){let i;const s={};for(let r=0;r0&&(s[e.textNodeName]=i):void 0!==i&&(s[e.textNodeName]=i),s}function tt(t){const e=Object.keys(t);for(let t=0;t0&&(n="\n"),rt(t,e,"",n)}function rt(t,e,n,i){let s="",r=!1;if(!Array.isArray(t)){if(null!=t){let n=t.toString();return n=ut(n,e),n}return""}for(let o=0;o`,r=!1;continue}if(l===e.commentPropName){s+=i+`\x3c!--${a[l][0][e.textNodeName]}--\x3e`,r=!0;continue}if("?"===l[0]){const t=at(a[":@"],e),n="?xml"===l?"":i;let o=a[l][0][e.textNodeName];o=0!==o.length?" "+o:"",s+=n+`<${l}${o}${t}?>`,r=!0;continue}let d=i;""!==d&&(d+=e.indentBy);const h=i+`<${l}${at(a[":@"],e)}`,p=rt(a[l],e,u,d);-1!==e.unpairedTags.indexOf(l)?e.suppressUnpairedNode?s+=h+">":s+=h+"/>":p&&0!==p.length||!e.suppressEmptyNode?p&&p.endsWith(">")?s+=h+`>${p}${i}`:(s+=h+">",p&&""!==i&&(p.includes("/>")||p.includes("`):s+=h+"/>",r=!0}return s}function ot(t){const e=Object.keys(t);for(let n=0;n0&&e.processEntities)for(let n=0;n","g"),val:">"},{regex:new RegExp("<","g"),val:"<"},{regex:new RegExp("'","g"),val:"'"},{regex:new RegExp('"',"g"),val:"""}],processEntities:!0,stopNodes:[],oneListGroup:!1};function ht(t){var e;this.options=Object.assign({},dt,t),!0===this.options.ignoreAttributes||this.options.attributesGroupName?this.isAttribute=function(){return!1}:(this.ignoreAttributesFn="function"==typeof(e=this.options.ignoreAttributes)?e:Array.isArray(e)?t=>{for(const n of e){if("string"==typeof n&&t===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}}:()=>!1,this.attrPrefixLen=this.options.attributeNamePrefix.length,this.isAttribute=ft),this.processTextOrObjNode=pt,this.options.format?(this.indentate=ct,this.tagEndChar=">\n",this.newLine="\n"):(this.indentate=function(){return""},this.tagEndChar=">",this.newLine="")}function pt(t,e,n,i){const s=this.j2x(t,n+1,i.concat(e));return void 0!==t[this.options.textNodeName]&&1===Object.keys(t).length?this.buildTextValNode(t[this.options.textNodeName],e,s.attrStr,n):this.buildObjectNode(s.val,e,s.attrStr,n)}function ct(t){return this.options.indentBy.repeat(t)}function ft(t){return!(!t.startsWith(this.options.attributeNamePrefix)||t===this.options.textNodeName)&&t.substr(this.attrPrefixLen)}ht.prototype.build=function(t){return this.options.preserveOrder?st(t,this.options):(Array.isArray(t)&&this.options.arrayNodeName&&this.options.arrayNodeName.length>1&&(t={[this.options.arrayNodeName]:t}),this.j2x(t,0,[]).val)},ht.prototype.j2x=function(t,e,n){let i="",s="";const r=n.join(".");for(let o in t)if(Object.prototype.hasOwnProperty.call(t,o))if(void 0===t[o])this.isAttribute(o)&&(s+="");else if(null===t[o])this.isAttribute(o)||o===this.options.cdataPropName?s+="":"?"===o[0]?s+=this.indentate(e)+"<"+o+"?"+this.tagEndChar:s+=this.indentate(e)+"<"+o+"/"+this.tagEndChar;else if(t[o]instanceof Date)s+=this.buildTextValNode(t[o],o,"",e);else if("object"!=typeof t[o]){const n=this.isAttribute(o);if(n&&!this.ignoreAttributesFn(n,r))i+=this.buildAttrPairStr(n,""+t[o]);else if(!n)if(o===this.options.textNodeName){let e=this.options.tagValueProcessor(o,""+t[o]);s+=this.replaceEntitiesValue(e)}else s+=this.buildTextValNode(t[o],o,"",e)}else if(Array.isArray(t[o])){const i=t[o].length;let r="",a="";for(let l=0;l"+t+s}},ht.prototype.closeTag=function(t){let e="";return-1!==this.options.unpairedTags.indexOf(t)?this.options.suppressUnpairedNode||(e="/"):e=this.options.suppressEmptyNode?"/":`>`+this.newLine;if(!1!==this.options.commentPropName&&e===this.options.commentPropName)return this.indentate(i)+`\x3c!--${t}--\x3e`+this.newLine;if("?"===e[0])return this.indentate(i)+"<"+e+n+"?"+this.tagEndChar;{let s=this.options.tagValueProcessor(e,t);return s=this.replaceEntitiesValue(s),""===s?this.indentate(i)+"<"+e+n+this.closeTag(e)+this.tagEndChar:this.indentate(i)+"<"+e+n+">"+s+"0&&this.options.processEntities)for(let e=0;e=16 || 14 >=14.17" @@ -3822,13 +3836,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4246,9 +4260,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -4389,11 +4403,12 @@ } }, "node_modules/archiver-utils/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4926,9 +4941,9 @@ "dev": true }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -5968,10 +5983,22 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-xml-builder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.0.0.tgz", + "integrity": "sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/fast-xml-parser": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz", - "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.2.tgz", + "integrity": "sha512-pw/6pIl4k0CSpElPEJhDppLzaixDEuWui2CUQQBH/ECDf7+y6YwA4Gf7Tyb0Rfe4DIMuZipYj4AEL0nACKglvQ==", "funding": [ { "type": "github", @@ -5980,6 +6007,7 @@ ], "license": "MIT", "dependencies": { + "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { @@ -7666,13 +7694,13 @@ } }, "node_modules/jest-config/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9707,13 +9735,13 @@ } }, "node_modules/jest-runtime/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -10412,10 +10440,11 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -11052,9 +11081,10 @@ } }, "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -11488,6 +11518,24 @@ "b4a": "^1.6.4" } }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", diff --git a/package.json b/package.json index 9f0a3b90..d21aa670 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "homepage": "https://github.com/tiobe/tics-github-action#readme", "dependencies": { "@actions/artifact": "^4.0.0", + "@actions/artifact-v1": "npm:@actions/artifact@1.1.2", "@actions/core": "^1.11.1", "@actions/exec": "^1.1.1", "@actions/github": "^6.0.1", diff --git a/src/github/artifacts.ts b/src/github/artifacts.ts index 78c2dc57..019be8d8 100644 --- a/src/github/artifacts.ts +++ b/src/github/artifacts.ts @@ -1,22 +1,51 @@ -import { tmpdir } from 'os'; import { readdirSync } from 'fs'; +import { tmpdir } from 'os'; import { DefaultArtifactClient } from '@actions/artifact'; +import { create } from '@actions/artifact-v1'; import { join } from 'canonical-path'; +import { githubConfig, ticsCli, ticsConfig } from '../configuration/config'; import { logger } from '../helper/logger'; import { handleOctokitError } from '../helper/response'; -import { githubConfig, ticsCli, ticsConfig } from '../configuration/config'; +import { emptyToNull } from '../helper/utils'; export async function uploadArtifact(): Promise { - const artifactClient = new DefaultArtifactClient(); + logger.header('Uploading artifact'); + const tmpdir = getTmpDir() + '/ticstmpdir'; // Example TICS_tics-github-action_2_qserver_ticstmpdir const name = sanitizeArtifactName(`${githubConfig.job}_${githubConfig.action}_${ticsConfig.mode}_ticstmpdir`); + logger.info(`Logs taken from ${tmpdir}`); + + if (isGhes()) { + await uploadGhes(name, tmpdir); + } else { + await uploadGithub(name, tmpdir); + } +} + +async function uploadGhes(name: string, tmpdir: string): Promise { + const artifactClient = create(); + + try { + const response = await artifactClient.uploadArtifact(name, getFilesInFolder(tmpdir), tmpdir); + + if (response.failedItems.length > 0) { + logger.debug(`Failed to upload file(s): ${response.failedItems.join(', ')}`); + } + logger.info(`Uploaded artifact "${name}" (size: ${createSize(response.size)})`); + } catch (error: unknown) { + const message = handleOctokitError(error); + logger.debug('Failed to upload artifact: ' + message); + } +} + +async function uploadGithub(name: string, tmpdir: string): Promise { + const artifactClient = new DefaultArtifactClient(); + try { - logger.header('Uploading artifact'); - logger.info(`Logs gotten from ${tmpdir}`); const response = await artifactClient.uploadArtifact(name, getFilesInFolder(tmpdir), tmpdir); if (response.id && response.size) { @@ -78,3 +107,18 @@ function getFilesInFolder(directory: string): string[] { traverseDirectory(directory); return files; } + +/** + * Copied from @actions/artifacts v6.2.0 + * https://github.com/actions/toolkit/blob/02afeb157764304bb3bfe1a6cfd37258ec3fcf7c/packages/artifact/src/internal/shared/config.ts + */ +function isGhes(): boolean { + const ghUrl = new URL(emptyToNull(process.env.GITHUB_SERVER_URL) ?? 'https://github.com'); + + const hostname = ghUrl.hostname.trimEnd().toUpperCase(); + const isGitHubHost = hostname === 'GITHUB.COM'; + const isGheHost = hostname.endsWith('.GHE.COM'); + const isLocalHost = hostname.endsWith('.LOCALHOST'); + + return !isGitHubHost && !isGheHost && !isLocalHost; +} diff --git a/src/helper/utils.ts b/src/helper/utils.ts index 209ba3b4..6439a3ee 100644 --- a/src/helper/utils.ts +++ b/src/helper/utils.ts @@ -8,3 +8,7 @@ export function isOneOf(value: T, ...args: [T, ...T[]]): boolean { return args.includes(value); } + +export function emptyToNull(value: string | null | undefined): string | null { + return value !== undefined && value !== null && value !== '' ? value : null; +} diff --git a/test/.setup/mock.ts b/test/.setup/mock.ts index b21a83c0..ab55ccf2 100644 --- a/test/.setup/mock.ts +++ b/test/.setup/mock.ts @@ -209,6 +209,13 @@ jest.mock('@actions/artifact', () => { })) }; }); +jest.mock('@actions/artifact-v1', () => { + return { + create: jest.fn().mockImplementation(() => ({ + uploadArtifact: jest.fn() + })) + }; +}); jest.mock('fs', () => { return { writeFileSync: jest.fn(), diff --git a/test/unit/github/artifacts.test.ts b/test/unit/github/artifacts.test.ts index 407652d1..8563ae7b 100644 --- a/test/unit/github/artifacts.test.ts +++ b/test/unit/github/artifacts.test.ts @@ -1,8 +1,9 @@ import { describe, expect, it, jest } from '@jest/globals'; import * as artifact from '@actions/artifact'; +import * as artifactV1 from '@actions/artifact-v1'; import * as fs from 'fs'; import { getTmpDir, uploadArtifact } from '../../../src/github/artifacts'; -import { MockArtifactClient, MockDirent } from './objects/artifacts'; +import { MockArtifactClient, MockArtifactClientV1, MockDirent } from './objects/artifacts'; import { logger } from '../../../src/helper/logger'; import { githubConfigMock, ticsCliMock } from '../../.setup/mock'; @@ -28,8 +29,17 @@ describe('tempdir test', () => { }); }); -describe('artifacts test', () => { +describe('artifacts test (github.com)', () => { const mockArtifactClient = new MockArtifactClient(); + const githubServerUrl = process.env.GITHUB_SERVER_URL; + + beforeAll(() => { + process.env.GITHUB_SERVER_URL = 'https://github.com'; + }); + + afterAll(() => { + process.env.GITHUB_SERVER_URL = githubServerUrl; + }); it('should upload logfile to tmpdir', async () => { ticsCliMock.tmpdir = '/tmp'; @@ -69,6 +79,7 @@ describe('artifacts test', () => { it('should call debug logger on upload throwing an error', async () => { ticsCliMock.tmpdir = '/tmp'; + delete process.env.GITHUB_SERVER_URL; jest.spyOn(fs, 'readdirSync').mockReturnValueOnce([new MockDirent(true, 'file.log', '/tmp/123_TICS_tics-github-action/ticstmpdir/file.log')]); jest.spyOn(artifact, 'DefaultArtifactClient').mockReturnValue(mockArtifactClient); @@ -85,3 +96,120 @@ describe('artifacts test', () => { expect(loggerSpy).toHaveBeenCalledWith(`Failed to upload artifact: connection issues`); }); }); + +describe('artifacts test (ghes)', () => { + const mockArtifactClient = new MockArtifactClientV1(); + const githubServerUrl = process.env.GITHUB_SERVER_URL; + + beforeAll(() => { + process.env.GITHUB_SERVER_URL = 'https://github.ghes.com'; + }); + + afterAll(() => { + process.env.GITHUB_SERVER_URL = githubServerUrl; + }); + + it('should upload logfile to tmpdir', async () => { + ticsCliMock.tmpdir = '/tmp'; + + jest.spyOn(fs, 'readdirSync').mockReturnValueOnce([new MockDirent(true, 'file.log', '/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log')]); + jest.spyOn(artifactV1, 'create').mockReturnValue(mockArtifactClient); + const uploadSpy = jest.spyOn(mockArtifactClient, 'uploadArtifact'); + + await uploadArtifact(); + + expect(uploadSpy).toHaveBeenCalledWith( + 'TICS_tics-github-action_client_ticstmpdir', + ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'], + '/tmp/123_TICS_1_tics-github-action/ticstmpdir' + ); + }); + + it('should upload logdir to tmpdir', async () => { + ticsCliMock.tmpdir = '/tmp'; + + const direntOne = [new MockDirent(false, 'tics', '/tmp/123_TICS_1_tics-github-action/ticstmpdir/tics')]; + const direntTwo = [new MockDirent(true, 'file.log', '/tmp/123_TICS_1_tics-github-action/ticstmpdir/tics/file.log')]; + + jest.spyOn(fs, 'readdirSync').mockReturnValueOnce(direntOne); + jest.spyOn(fs, 'readdirSync').mockReturnValueOnce(direntTwo); + const uploadSpy = jest.spyOn(mockArtifactClient, 'uploadArtifact'); + + await uploadArtifact(); + + expect(uploadSpy).toHaveBeenCalledWith( + 'TICS_tics-github-action_client_ticstmpdir', + ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/tics/file.log'], + '/tmp/123_TICS_1_tics-github-action/ticstmpdir' + ); + }); + + it('should log files that failed to upload', async () => { + ticsCliMock.tmpdir = '/tmp'; + + jest.spyOn(fs, 'readdirSync').mockReturnValueOnce([new MockDirent(true, 'file.log', '/tmp/123_TICS_tics-github-action/ticstmpdir/file.log')]); + jest.spyOn(artifactV1, 'create').mockReturnValue(mockArtifactClient); + const uploadSpy = jest.spyOn(mockArtifactClient, 'uploadArtifact').mockResolvedValue({ + artifactName: 'TICS_tics-github-action_client_ticstmpdir', + artifactItems: [], + size: 2048 * 1024, + failedItems: ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'] + }); + const loggerSpy = jest.spyOn(logger, 'debug'); + + await uploadArtifact(); + + expect(uploadSpy).toHaveBeenCalledWith( + 'TICS_tics-github-action_client_ticstmpdir', + ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'], + '/tmp/123_TICS_1_tics-github-action/ticstmpdir' + ); + expect(loggerSpy).toHaveBeenCalledWith('Failed to upload file(s): /tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'); + }); + + it('should upload a file and log files that failed to upload', async () => { + ticsCliMock.tmpdir = '/tmp'; + + jest + .spyOn(fs, 'readdirSync') + .mockReturnValueOnce([ + new MockDirent(true, 'file.log', '/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'), + new MockDirent(true, 'file1.log', '/tmp/123_TICS_1_tics-github-action/ticstmpdir/file1.log') + ]); + jest.spyOn(artifactV1, 'create').mockReturnValue(mockArtifactClient); + const uploadSpy = jest.spyOn(mockArtifactClient, 'uploadArtifact').mockResolvedValue({ + artifactName: 'TICS_tics-github-action_client_ticstmpdir', + artifactItems: ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file1.log'], + size: 2048 * 1024 * 1024, + failedItems: ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'] + }); + const loggerSpy = jest.spyOn(logger, 'debug'); + + await uploadArtifact(); + + expect(uploadSpy).toHaveBeenCalledWith( + 'TICS_tics-github-action_client_ticstmpdir', + ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log', '/tmp/123_TICS_1_tics-github-action/ticstmpdir/file1.log'], + '/tmp/123_TICS_1_tics-github-action/ticstmpdir' + ); + expect(loggerSpy).toHaveBeenCalledWith('Failed to upload file(s): /tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'); + }); + + it('should call debug logger on upload throwing an error', async () => { + ticsCliMock.tmpdir = '/tmp'; + + jest.spyOn(fs, 'readdirSync').mockReturnValueOnce([new MockDirent(true, 'file.log', '/tmp/123_TICS_tics-github-action/ticstmpdir/file.log')]); + jest.spyOn(artifactV1, 'create').mockReturnValue(mockArtifactClient); + const uploadSpy = jest.spyOn(mockArtifactClient, 'uploadArtifact').mockRejectedValue(Error('connection issues')); + const loggerSpy = jest.spyOn(logger, 'debug'); + + await uploadArtifact(); + + expect(uploadSpy).toHaveBeenCalledWith( + 'TICS_tics-github-action_client_ticstmpdir', + ['/tmp/123_TICS_1_tics-github-action/ticstmpdir/file.log'], + '/tmp/123_TICS_1_tics-github-action/ticstmpdir' + ); + expect(loggerSpy).toHaveBeenCalledWith(`Failed to upload artifact: connection issues`); + }); +}); diff --git a/test/unit/github/objects/artifacts.ts b/test/unit/github/objects/artifacts.ts index dac92654..cef1a67f 100644 --- a/test/unit/github/objects/artifacts.ts +++ b/test/unit/github/objects/artifacts.ts @@ -10,6 +10,7 @@ import { UploadArtifactOptions, UploadArtifactResponse } from '@actions/artifact'; +import * as ArtifactV1 from '@actions/artifact-v1'; import { Dirent } from 'fs'; export class MockArtifactClient implements ArtifactClient { @@ -37,6 +38,26 @@ export class MockArtifactClient implements ArtifactClient { } } +export class MockArtifactClientV1 implements ArtifactV1.ArtifactClient { + uploadArtifact(name: string, files: string[], rootDirectory: string, options?: ArtifactV1.UploadOptions): Promise { + const response: ArtifactV1.UploadResponse = { + size: files.length, + artifactName: name, + artifactItems: files, + failedItems: [] + }; + return new Promise(resolve => { + resolve(response); + }); + } + downloadArtifact(name: string, path?: string, options?: ArtifactV1.DownloadOptions): Promise { + throw new Error('Method not implemented.'); + } + downloadAllArtifacts(path?: string): Promise { + throw new Error('Method not implemented.'); + } +} + export class MockDirent implements Dirent { file: boolean; name: string; diff --git a/test/unit/helper/utils.test.ts b/test/unit/helper/utils.test.ts index a6a0c02d..3cc6f124 100644 --- a/test/unit/helper/utils.test.ts +++ b/test/unit/helper/utils.test.ts @@ -1,5 +1,5 @@ import { describe, it } from '@jest/globals'; -import { isOneOf } from '../../../src/helper/utils'; +import { emptyToNull, isOneOf } from '../../../src/helper/utils'; describe('isOneOf', () => { it('should pass if value is one of the given options', () => { @@ -12,3 +12,25 @@ describe('isOneOf', () => { expect(true).toBeTruthy(); }); }); + +describe('emptyToNull', () => { + it('should return null if string is undefined', () => { + const result = emptyToNull(undefined); + expect(result).toStrictEqual(null); + }); + + it('should return null if string is null', () => { + const result = emptyToNull(null); + expect(result).toStrictEqual(null); + }); + + it('should return null if string is empty', () => { + const result = emptyToNull(''); + expect(result).toStrictEqual(null); + }); + + it('should return value if string is not empty', () => { + const result = emptyToNull('value'); + expect(result).toStrictEqual('value'); + }); +});