diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..dea54daf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,30 @@ +name: Release +"on": + push: + branches: + - master + - next + - beta + - "*.x" +permissions: + contents: read # for checkout +jobs: + release: + permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance + name: release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + cache: npm + node-version: lts/* + - run: npm ci + - run: npx semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_BOT_NPM_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..78b23c98 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,47 @@ +name: Test +"on": + push: + branches: + - master + - renovate/** + pull_request: + types: + - opened + - synchronize +jobs: + test_matrix: + strategy: + matrix: + node-version: + - 20.8.1 # minimum supported Node version + - 20 + - 21 + - 22 + os: + - ubuntu-latest + - macos-latest + - windows-latest + runs-on: "${{ matrix.os }}" + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: "Use Node.js ${{ matrix.node-version }}" + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "${{ matrix.node-version }}" + cache: npm + - run: npm ci + - name: Ensure dependencies are compatible with the version of node + run: npx ls-engines@v0.9.4 + - run: npm run test + test: + runs-on: ubuntu-latest + needs: test_matrix + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: "Use Node.js ${{ matrix.node-version }}" + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "${{ matrix.node-version }}" + cache: npm + - run: npm ci + - run: npm run lint diff --git a/.gitignore b/.gitignore index fa6f8ca3..577ee284 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,3 @@ $RECYCLE.BIN/ *.lnk # End of https://www.gitignore.io/api/macos,windows,linux,node - -package-lock.json -yarn.lock diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 43c97e71..00000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bab1186d..00000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -version: ~> 1.0 - -import: - - semantic-release/semantic-release:.travis/node.yml - - semantic-release/semantic-release:.travis/node-versions.yml - - semantic-release/semantic-release:.travis/semantic-release.yml - - semantic-release/semantic-release:.travis/greenkeeper.yml - - semantic-release/semantic-release:.travis/codecov.yml diff --git a/.yarnrc b/.yarnrc deleted file mode 100644 index acaaffdb..00000000 --- a/.yarnrc +++ /dev/null @@ -1 +0,0 @@ ---install.no-lockfile true diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..e458d549 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,41 @@ +# Agent Guidelines for @semantic-release/gitlab + +## Commands + +- **Test**: `npm test` or `npm run test` +- **Lint**: `npm run lint` +- **Fix linting**: `npm run lint:fix` +- **Coverage**: Tests include coverage reporting via c8 + +## Code Style + +- **Node.js Version**: 20.8.1+ +- **Module type**: ES modules (`"type": "module"`) +- **Formatting**: Prettier with 120 character line width and ES5 trailing commas +- **Testing**: AVA test framework +- **Coverage**: c8 for code coverage + +## Development Guidelines + +- **Perform minimal changes**: Focus on the specific issue and make the smallest possible changes +- **Focus on reviewers**: Write clear, understandable code that is easy to review +- **Use semantic commits**: Follow conventional commit format (e.g., `feat:`, `fix:`, `docs:`, `test:`) +- **Run tests and formatting before committing**: Always run `npm test` and `npm run lint` before making commits + +## Project Structure + +- `lib/` - Core library modules +- `test/` - Test files (using AVA) +- `index.js` - Main entry point +- Configuration files support semantic-release conventions + +## Testing Requirements + +- All changes must maintain or improve test coverage +- Tests use nock for HTTP mocking +- Integration tests verify GitLab API interactions +- Run `npm test` to execute the full test suite + +## Semantic Release Integration + +This is a semantic-release plugin, so changes should follow semantic versioning principles and conventional commit formats for automated releases. diff --git a/LICENSE b/LICENSE index 8e443427..ac4cb561 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Contributors +Copyright (c) 2017-2026 Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index cd7b71d6..c414679d 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,17 @@ # @semantic-release/gitlab [**semantic-release**](https://github.com/semantic-release/semantic-release) plugin to publish a -[GitLab release](https://docs.gitlab.com/ce/workflow/releases.html). +[GitLab release](https://docs.gitlab.com/user/project/releases/). -[![Travis](https://img.shields.io/travis/semantic-release/gitlab.svg)](https://travis-ci.org/semantic-release/gitlab) -[![Codecov](https://img.shields.io/codecov/c/github/semantic-release/gitlab.svg)](https://codecov.io/gh/semantic-release/gitlab) -[![Greenkeeper badge](https://badges.greenkeeper.io/semantic-release/gitlab.svg)](https://greenkeeper.io/) - -[![npm latest version](https://img.shields.io/npm/v/@semantic-release/gitlab/latest.svg)](https://www.npmjs.com/package/@semantic-release/gitlab) +[![Build Status](https://github.com/semantic-release/gitlab/workflows/Test/badge.svg)](https://github.com/semantic-release/gitlab/actions?query=workflow%3ATest+branch%3Amaster) [![npm latest version](https://img.shields.io/npm/v/@semantic-release/gitlab/latest.svg)](https://www.npmjs.com/package/@semantic-release/gitlab) [![npm next version](https://img.shields.io/npm/v/@semantic-release/gitlab/next.svg)](https://www.npmjs.com/package/@semantic-release/gitlab) -| Step | Description | -|--------------------|-----------------------------------------------------------------------------------------------------------------------| -| `verifyConditions` | Verify the presence and the validity of the authentication (set via [environment variables](#environment-variables)). | -| `publish` | Publish a [GitLab release](https://docs.gitlab.com/ce/workflow/releases.html). | +| Step | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `verifyConditions` | Verify the presence and the validity of the authentication (set via [environment variables](#environment-variables)). | +| `publish` | Publish a [GitLab release](https://docs.gitlab.com/user/project/releases/). | +| `success` | Add a comment to each GitLab Issue or Merge Request resolved by the release. | +| `fail` | Open or update a [GitLab Issue](https://docs.gitlab.com/user/project/issues/) with information about the errors that caused the release to fail. | ## Install @@ -27,21 +25,27 @@ The plugin can be configured in the [**semantic-release** configuration file](ht ```json { + "branches": ["main"], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", - ["@semantic-release/gitlab", { - "gitlabUrl": "https://custom.gitlab.com", - "assets": [ - {"path": "dist/asset.min.css", "label": "CSS distribution"}, - {"path": "dist/asset.min.js", "label": "JS distribution"} - ] - }], + [ + "@semantic-release/gitlab", + { + "gitlabUrl": "https://custom.gitlab.com", + "assets": [ + { "path": "dist/asset.min.css", "label": "CSS distribution" }, + { "path": "dist/asset.min.js", "label": "JS distribution", "target": "generic_package" }, + { "path": "dist/asset.min.js", "label": "v${nextRelease.version}.js" }, + { "url": "https://gitlab.com/gitlab-org/gitlab/-/blob/master/README.md", "label": "README.md" } + ] + } + ] ] } ``` -With this example [GitLab releases](https://docs.gitlab.com/ce/workflow/releases.html) will be published to the `https://custom.gitlab.com` instance. +With this example [GitLab releases](https://docs.gitlab.com/user/project/releases/) will be published to the `https://custom.gitlab.com` instance. ## Configuration @@ -50,33 +54,78 @@ With this example [GitLab releases](https://docs.gitlab.com/ce/workflow/releases The GitLab authentication configuration is **required** and can be set via [environment variables](#environment-variables). -Create a [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) with the `api` scope and make it available in your CI environment via the `GL_TOKEN` environment variable. If you are using `GL_TOKEN` as the [remote Git repository authentication](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#authentication) it must also have the `write_repository` scope. +Create a [project access token](https://docs.gitlab.com/user/project/settings/project_access_tokens/), [group access token](https://docs.gitlab.com/user/group/settings/group_access_tokens/), or [personal access token](https://docs.gitlab.com/user/profile/personal_access_tokens/) with role _Developer_ (or higher) and the `api` scope and make it available in your CI environment via the `GL_TOKEN` environment variable. If you are using `GL_TOKEN` as the [remote Git repository authentication](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#authentication) it must also have the `write_repository` scope. + +**Note**: When running with [`dryRun`](https://semantic-release.gitbook.io/semantic-release/usage/configuration#dryrun) only `read_repository` scope is required. + +#### Using a CI Job Token + +When running in a GitLab CI/CD environment, you can use the `CI_JOB_TOKEN` for authentication. To enable this, set the `useJobToken` option to `true` in your plugin configuration: + +```json +{ + "plugins": [["@semantic-release/gitlab", { "useJobToken": true }]] +} +``` + +> **Important**: When `useJobToken` is enabled, comments on issues and merge requests are automatically disabled. This is due to the limited permissions of the `CI_JOB_TOKEN` which do not allow for these actions. ### Environment variables -| Variable | Description | -|--------------------------------|-----------------------------------------------------------| -| `GL_TOKEN` or `GITLAB_TOKEN` | **Required.** The token used to authenticate with GitLab. | -| `GL_URL` or `GITLAB_URL` | The GitLab endpoint. | -| `GL_PREFIX` or `GITLAB_PREFIX` | The GitLab API prefix. | +| Variable | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------ | +| `GL_TOKEN` or `GITLAB_TOKEN` | **Required.** The token used to authenticate with GitLab. | +| `GL_URL` or `GITLAB_URL` | The GitLab endpoint. | +| `GL_PREFIX` or `GITLAB_PREFIX` | The GitLab API prefix. | +| `CI_JOB_TOKEN` | The GitLab CI/CD job token. Used if `useJobToken` is `true`. | +| `HTTP_PROXY` or `HTTPS_PROXY` | HTTP or HTTPS proxy to use. | +| `NO_PROXY` | Patterns for which the proxy should be ignored. See [details below](#proxy-configuration). | + +#### Proxy configuration + +The plugin supports passing requests through a proxy server. + +You can configure a proxy server via the `HTTPS_PROXY` environment variable: `HTTPS_PROXY=http://proxyurl.com:8080` + +If your proxy server requires authentication embed the username and password in the URL: `HTTPS_PROXY=http://user:pwd@proxyurl.com:8080` + +If your GitLab instance is exposed via plain HTTP (not recommended!) use `HTTP_PROXY` instead. + +If you need to bypass the proxy for some hosts, configure the `NO_PROXY` environment variable: `NO_PROXY=*.host.com, host.com` ### Options -| Option | Description | Default | -|-----------------------|--------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `gitlabUrl` | The GitLab endpoint. | `GL_URL` or `GITLAB_URL` environment variable or CI provided environment variables if running on [GitLab CI/CD](https://docs.gitlab.com/ee/ci) or `https://gitlab.com`. | -| `gitlabApiPathPrefix` | The GitLab API prefix. | `GL_PREFIX` or `GITLAB_PREFIX` environment variable or CI provided environment variables if running on [GitLab CI/CD](https://docs.gitlab.com/ee/ci) or `/api/v4`. | -| `assets` | An array of files to upload to the release. See [assets](#assets). | - | +| Option | Description | Default | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `gitlabUrl` | The GitLab endpoint. | `GL_URL` or `GITLAB_URL` environment variable or CI provided environment variables if running on [GitLab CI/CD](https://docs.gitlab.com/ci/) or `https://gitlab.com`. | +| `gitlabApiPathPrefix` | The GitLab API prefix. | `GL_PREFIX` or `GITLAB_PREFIX` environment variable or CI provided environment variables if running on [GitLab CI/CD](https://docs.gitlab.com/ci/) or `/api/v4`. | +| `useJobToken` | Set to `true` to use the `CI_JOB_TOKEN` for authentication within a GitLab CI/CD environment. | `false` | +| `assets` | An array of files to upload to the release. See [assets](#assets). | - | +| `milestones` | An array of milestone titles to associate to the release. See [GitLab Release API](https://docs.gitlab.com/api/releases/#create-a-release). | - | +| `successComment` | The comment to add to each Issue and Merge Request resolved by the release. See [successComment](#successComment). | :tada: This issue has been resolved in version ${nextRelease.version} :tada:\n\nThe release is available on [GitLab release](gitlab_release_url) | +| `successCommentCondition` | Use this as condition, when to comment on issues or merge requests. See [successCommentCondition](#successCommentCondition). | - | +| `failComment` | The content of the issue created when a release fails. See [failComment](#failcomment). | Friendly message with links to **semantic-release** documentation and support, with the list of errors that caused the release to fail. | +| `failTitle` | The title of the issue created when a release fails. | `The automated release is failing 🚨` | +| `failCommentCondition` | Use this as condition, when to comment on or create an issues in case of failures. See [failCommentCondition](#failCommentCondition). | - | +| `labels` | The [labels](https://docs.gitlab.com/user/project/labels/#labels) to add to the issue created when a release fails. Set to `false` to not add any label. Labels should be comma-separated as described in the [official docs](https://docs.gitlab.com/api/issues/#new-issue), e.g. `"semantic-release,bot"`. | `semantic-release` | +| `assignee` | The [assignee](https://docs.gitlab.com/user/project/issues/managing_issues/#assignees) to add to the issue created when a release fails. | - | +| `retryLimit` | The maximum number of retries for failing HTTP requests. | `3` | #### assets Can be a [glob](https://github.com/isaacs/node-glob#glob-primer) or and `Array` of [globs](https://github.com/isaacs/node-glob#glob-primer) and `Object`s with the following properties: -| Property | Description | Default | -| -------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------ | -| `path` | **Required.** A [glob](https://github.com/isaacs/node-glob#glob-primer) to identify the files to upload. | - | -| `label` | Short description of the file displayed on the GitLab release. | File name extracted from the `path`. | +| Property | Description | Default | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | +| `path` | **Required**, unless `url` is set. A [glob](https://github.com/isaacs/node-glob#glob-primer) to identify the files to upload. Supports [Lodash templating](https://lodash.com/docs#template). | - | +| `url` | Alternative to setting `path` this provides the ability to add links to releases, e.g. URLs to container images. Supports [Lodash templating](https://lodash.com/docs#template). | - | +| `label` | Short description of the file displayed on the GitLab release. Ignored if `path` matches more than one file. Supports [Lodash templating](https://lodash.com/docs#template). | File name extracted from the `path`. | +| `type` | Asset type displayed on the GitLab release. Can be `runbook`, `package`, `image` and `other` (see official documents on [link types](https://docs.gitlab.com/user/project/releases/release_fields/#link-types)). Supports [Lodash templating](https://lodash.com/docs#template). | `other` | +| `filepath` | A filepath for creating a permalink pointing to the asset (requires GitLab 12.9+, see official documents on [permanent links](https://docs.gitlab.com/user/project/releases/release_fields/#permanent-links-to-release-assets)). Ignored if `path` matches more than one file. Supports [Lodash templating](https://lodash.com/docs#template). | - | +| `target` | Controls where the file is uploaded to. Can be set to `project_upload` for storing the file as [project upload](https://docs.gitlab.com/api/project_markdown_uploads/#upload-a-file) or `generic_package` for storing the file as [generic package](https://docs.gitlab.com/user/packages/generic_packages/). | `project_upload` | +| `packageName` | This is only applied if `target` is set to `generic_package`. It defines the package name (`:package_name`) to upload asset file to. More information could be found at [Publish a package](https://docs.gitlab.com/user/packages/generic_packages/#publish-a-package) | `release` | +| `status` | This is only applied, if `target` is set to `generic_package`. The generic package status. Can be `default` and `hidden` (see official documents on [generic packages](https://docs.gitlab.com/user/packages/generic_packages/)). | `default` | Each entry in the `assets` `Array` is globbed individually. A [glob](https://github.com/isaacs/node-glob#glob-primer) can be a `String` (`"dist/**/*.js"` or `"dist/mylib.js"`) or an `Array` of `String`s that will be globbed together @@ -100,3 +149,91 @@ distribution` and `MyLibrary CSS distribution` in the GitLab release. `[['dist/**/*.{js,css}', '!**/*.min.*'], {path: 'build/MyLibrary.zip', label: 'MyLibrary'}]`: include all the `js` and `css` files in the `dist` directory and its sub-directories excluding the minified version, plus the `build/MyLibrary.zip` file and label it `MyLibrary` in the GitLab release. + +#### successComment + +The message for the issue comments is generated with [Lodash template](https://lodash.com/docs#template). The following variables are available: + +| Parameter | Description | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `branch` | `Object` with `name`, `type`, `channel`, `range` and `prerelease` properties of the branch from which the release is done. | +| `lastRelease` | `Object` with `version`, `channel`, `gitTag` and `gitHead` of the last release. | +| `nextRelease` | `Object` with `version`, `channel`, `gitTag`, `gitHead` and `notes` of the release being done. | +| `commits` | `Array` of commit `Object`s with `hash`, `subject`, `body` `message` and `author`. | +| `releases` | `Array` with a release `Object`s for each release published, with optional release data such as `name` and `url`. | +| `issue` | A [GitLab API Issue object](https://docs.gitlab.com/api/issues/#single-issue) the comment will be posted to, or `false` when commenting Merge Requests. | +| `mergeRequest` | A [GitLab API Merge Request object](https://docs.gitlab.com/api/merge_requests/#get-single-mr) the comment will be posted to, or `false` when commenting Issues. | + +#### successCommentCondition + +The success comment condition is generated with [Lodash template](https://lodash.com/docs#template). The following variables are available: + +| Parameter | Description | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `branch` | `Object` with `name`, `type`, `channel`, `range` and `prerelease` properties of the branch from which the release is done. | +| `lastRelease` | `Object` with `version`, `channel`, `gitTag` and `gitHead` of the last release. | +| `nextRelease` | `Object` with `version`, `channel`, `gitTag`, `gitHead` and `notes` of the release being done. | +| `commits` | `Array` of commit `Object`s with `hash`, `subject`, `body` `message` and `author`. | +| `releases` | `Array` with a release `Object`s for each release published, with optional release data such as `name` and `url`. | +| `issue` | A [GitLab API Issue object](https://docs.gitlab.com/api/issues/#single-issue) the comment will be posted to. | +| `mergeRequest` | A [GitLab API Merge Request object](https://docs.gitlab.com/api/merge_requests/#get-single-mr) the comment will be posted to. | + +##### successCommentCondition example + +- do not create any comments at all: set to `false` or templating: `"<% return false; %>"` +- to only comment on issues: `"<% return issue %>"` +- to only comment on merge requests: `"<% return mergeRequest %>"` +- you can use labels to filter issues: `"<% return issue.labels?.includes('semantic-release-relevant') %>"` + +> check the [GitLab API Merge Request object](https://docs.gitlab.com/api/merge_requests/#get-single-mr) or the [GitLab API Issue object](https://docs.gitlab.com/api/issues/#single-issue) for properties which can be used for the filter + +#### failComment + +The message for the issue content is generated with [Lodash template](https://lodash.com/docs#template). The following variables are available: + +| Parameter | Description | +| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `branch` | The branch from which the release had failed. | +| `errors` | An `Array` of [SemanticReleaseError](https://github.com/semantic-release/error). Each error has the `message`, `code`, `pluginName` and `details` properties.
`pluginName` contains the package name of the plugin that threw the error.
`details` contains a information about the error formatted in markdown. | + +##### failComment example + +The `failComment` `This release from branch ${branch.name} had failed due to the following errors:\n- ${errors.map(err => err.message).join('\\n- ')}` will generate the comment: + +> This release from branch master had failed due to the following errors: +> +> - Error message 1 +> - Error message 2 + +#### failCommentCondition + +The fail comment condition is generated with [Lodash template](https://lodash.com/docs#template). The following variables are available: + +| Parameter | Description | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| `branch` | `Object` with `name`, `type`, `channel`, `range` and `prerelease` properties of the branch from which the release is done. | +| `lastRelease` | `Object` with `version`, `channel`, `gitTag` and `gitHead` of the last release. | +| `nextRelease` | `Object` with `version`, `channel`, `gitTag`, `gitHead` and `notes` of the release being done. | +| `commits` | `Array` of commit `Object`s with `hash`, `subject`, `body` `message` and `author`. | +| `releases` | `Array` with a release `Object`s for each release published, with optional release data such as `name` and `url`. | +| `issue` | A [GitLab API Issue object](https://docs.gitlab.com/api/issues/#single-issue) the comment will be posted to - only available if an open issue exists. | + +##### failCommentCondition example + +- do not create any comments at all: set to `false` or templating: `"<% return false; %>"` +- to only comment on main branch: `"<% return branch.name === 'main' %>"` +- you can use labels to filter issues, i.e. to not comment if the issue is labeled with `wip`: `"<% return !issue.labels?.includes('wip') %>"` + +> check the [GitLab API Issue object](https://docs.gitlab.com/api/issues/#single-issue) for properties which can be used for the filter + +## Compatibility + +The latest version of this plugin is compatible with all currently-supported versions of GitLab, [which is the current major version and previous two major versions](https://about.gitlab.com/support/statement-of-support.html#version-support). This plugin is not guaranteed to work with unsupported versions of GitLab. + +### Breaking changes in 14.0 + +If you are using GitLab.com or have upgraded your self-hosted GitLab instance to 14.0, please use version `>=6.0.7` of this plugin. + +#### Why? + +In GitLab 14.0, creating a release using the [Tags API](https://docs.gitlab.com/api/tags/) has been removed (see [#290311](https://gitlab.com/gitlab-org/gitlab/-/issues/290311)). This plugin was updated to use the [Releases API](https://docs.gitlab.com/api/releases/#create-a-release) instead in https://github.com/semantic-release/gitlab/pull/184, which is available in version `6.0.7` and beyond. diff --git a/index.js b/index.js index 0ab1255b..2210e453 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,18 @@ /* eslint require-atomic-updates: off */ -const verifyGitLab = require('./lib/verify'); -const publishGitLab = require('./lib/publish'); +import verifyGitLab from "./lib/verify.js"; +import publishGitLab from "./lib/publish.js"; +import successGitLab from "./lib/success.js"; +import failGitLab from "./lib/fail.js"; let verified; -async function verifyConditions(pluginConfig, context) { +export async function verifyConditions(pluginConfig, context) { await verifyGitLab(pluginConfig, context); verified = true; } -async function publish(pluginConfig, context) { +export async function publish(pluginConfig, context) { if (!verified) { await verifyGitLab(pluginConfig, context); verified = true; @@ -19,4 +21,20 @@ async function publish(pluginConfig, context) { return publishGitLab(pluginConfig, context); } -module.exports = {verifyConditions, publish}; +export async function success(pluginConfig, context) { + if (!verified) { + await verifyGitLab(pluginConfig, context); + verified = true; + } + + return successGitLab(pluginConfig, context); +} + +export async function fail(pluginConfig, context) { + if (!verified) { + await verifyGitLab(pluginConfig, context); + verified = true; + } + + return failGitLab(pluginConfig, context); +} diff --git a/lib/definitions/constants.js b/lib/definitions/constants.js new file mode 100644 index 00000000..18f1ecd3 --- /dev/null +++ b/lib/definitions/constants.js @@ -0,0 +1,3 @@ +export const HOME_URL = 'https://github.com/semantic-release/semantic-release'; + +export const RELEASE_NAME = 'GitLab release'; diff --git a/lib/definitions/errors.js b/lib/definitions/errors.js index 0316f682..51508538 100644 --- a/lib/definitions/errors.js +++ b/lib/definitions/errors.js @@ -1,11 +1,13 @@ -const {inspect} = require('util'); -const pkg = require('../../package.json'); +import {inspect} from 'util'; +import { createRequire } from "node:module"; +const require = createRequire(import.meta.url); +const pkg = require("../../package.json"); const [homepage] = pkg.homepage.split('#'); -const linkify = file => `${homepage}/blob/master/${file}`; -const stringify = obj => inspect(obj, {breakLength: Infinity, depth: 2, maxArrayLength: 5}); +const linkify = (file) => `${homepage}/blob/master/${file}`; +const stringify = (object) => inspect(object, {breakLength: Number.POSITIVE_INFINITY, depth: 2, maxArrayLength: 5}); -module.exports = { +export default { EINVALIDASSETS: ({assets}) => ({ message: 'Invalid `assets` option.', details: `The [assets option](${linkify( @@ -13,22 +15,46 @@ module.exports = { )}) must be an \`Array\` of \`Strings\` or \`Objects\` with a \`path\` property. Your configuration for the \`assets\` option is \`${stringify(assets)}\`.`, }), + EINVALIDFAILTITLE: ({failTitle}) => ({ + message: 'Invalid `failTitle` option.', + details: `The [failTitle option](${linkify('README.md#failtitle')}) if defined, must be a non empty \`String\`. + +Your configuration for the \`failTitle\` option is \`${stringify(failTitle)}\`.`, + }), + EINVALIDFAILCOMMENT: ({failComment}) => ({ + message: 'Invalid `failComment` option.', + details: `The [failComment option](${linkify('README.md#failcomment')}) if defined, must be a non empty \`String\`. + +Your configuration for the \`failComment\` option is \`${stringify(failComment)}\`.`, + }), + EINVALIDLABELS: ({labels}) => ({ + message: 'Invalid `labels` option.', + details: `The [labels option](${linkify('README.md#labels')}) if defined, must be a non empty \`String\`. + +Your configuration for the \`labels\` option is \`${stringify(labels)}\`.`, + }), + EINVALIDASSIGNEE: ({assignee}) => ({ + message: 'Invalid `assignee` option.', + details: `The [assignee option](${linkify('README.md#assignee')}) if defined, must be a non empty \`String\`. + + Your configuration for the \`assignee\` option is \`${stringify(assignee)}\`.`, + }), EINVALIDGITLABURL: () => ({ message: 'The git repository URL is not a valid GitLab URL.', - details: `The **semantic-release** \`repositoryUrl\` option must a valid GitLab URL with the format \`/.git\`. + details: `The **semantic-release** \`repositoryUrl\` option must a valid GitLab URL with the format \`/.git\`. By default the \`repositoryUrl\` option is retrieved from the \`repository\` property of your \`package.json\` or the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) of the repository cloned by your CI environment.`, }), - EINVALIDGLTOKEN: ({repoId}) => ({ + EINVALIDGLTOKEN: ({projectPath}) => ({ message: 'Invalid GitLab token.', details: `The [GitLab token](${linkify( 'README.md#gitlab-authentication' - )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must be a valid [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) allowing to push to the repository ${repoId}. + )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must be a valid [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) allowing to push to the repository ${projectPath}. Please make sure to set the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable in your CI with the exact value of the GitLab personal token.`, }), - EMISSINGREPO: ({repoId}) => ({ - message: `The repository ${repoId} doesn't exist.`, + EMISSINGREPO: ({projectPath}) => ({ + message: `The repository ${projectPath} doesn't exist.`, details: `The **semantic-release** \`repositoryUrl\` option must refer to your GitLab repository. The repository must be accessible with the [GitLab API](https://docs.gitlab.com/ce/api/README.html). By default the \`repositoryUrl\` option is retrieved from the \`repository\` property of your \`package.json\` or the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) of the repository cloned by your CI environment. @@ -37,20 +63,28 @@ If you are using [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee) 'README.md#options' )}).`, }), - EGLNOPERMISSION: ({repoId}) => ({ - message: `The GitLab token doesn't allow to push on the repository ${repoId}.`, + EGLNOPUSHPERMISSION: ({projectPath}) => ({ + message: `The GitLab token doesn't allow to push on the repository ${projectPath}.`, + details: `The user associated with the [GitLab token](${linkify( + 'README.md#gitlab-authentication' + )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allows to push to the repository ${projectPath}. + +Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${projectPath}.`, + }), + EGLNOPULLPERMISSION: ({projectPath}) => ({ + message: `The GitLab token doesn't allow to pull from the repository ${projectPath}.`, details: `The user associated with the [GitLab token](${linkify( 'README.md#gitlab-authentication' - )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allows to push to the repository ${repoId}. + )}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allow pull from the repository ${projectPath}. -Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${repoId}.`, +Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${projectPath}.`, }), ENOGLTOKEN: ({repositoryUrl}) => ({ message: 'No GitLab token specified.', - details: `A [GitLab personnal access token](${linkify( + details: `A [GitLab personal access token](${linkify( 'README.md#gitlab-authentication' )}) must be created and set in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable on your CI environment. -Please make sure to create a [GitLab personnal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) and to set it in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable on your CI environment. The token must allow to push to the repository ${repositoryUrl}.`, +Please make sure to create a [GitLab personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) and to set it in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable on your CI environment. The token must allow to push to the repository ${repositoryUrl}.`, }), }; diff --git a/lib/fail.js b/lib/fail.js new file mode 100644 index 00000000..3ce29c1e --- /dev/null +++ b/lib/fail.js @@ -0,0 +1,96 @@ +import { template } from "lodash-es"; +import urlJoin from "url-join"; +import got from "got"; +import _debug from "debug"; +const debug = _debug("semantic-release:gitlab"); +import resolveConfig from "./resolve-config.js"; +import getFailComment from "./get-fail-comment.js"; +import getProjectContext from "./get-project-context.js"; + +export default async (pluginConfig, context) => { + const { + options: { repositoryUrl }, + branch, + errors, + logger, + } = context; + const { + gitlabToken, + tokenHeader, + gitlabUrl, + gitlabApiUrl, + failComment, + failTitle, + failCommentCondition, + labels, + assignee, + retryLimit, + retryStatusCodes, + useJobToken, + } = resolveConfig(pluginConfig, context); + const { encodedProjectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); + + const apiOptions = { + headers: { [tokenHeader]: gitlabToken }, + retry: { + limit: retryLimit, + statusCodes: retryStatusCodes, + }, + }; + + if (failComment === false || failTitle === false) { + logger.log("Skip issue creation."); + logger.error(`Failure reporting should be disabled via 'failCommentCondition'. +Using 'false' for 'failComment' or 'failTitle' is deprecated and will be removed in a future major version.`); + } else if (failCommentCondition === false) { + logger.log( + "Skip issue creation." + useJobToken + ? " Setting 'failComment' or 'failTitle' has no effect when 'useJobToken' is set." + : "" + ); + } else { + const encodedFailTitle = encodeURIComponent(failTitle); + const description = failComment ? template(failComment)({ branch, errors }) : getFailComment(branch, errors); + + const issuesEndpoint = urlJoin(projectApiUrl, `issues`); + const openFailTitleIssueEndpoint = urlJoin(issuesEndpoint, `?state=opened&search=${encodedFailTitle}`); + + const openFailTitleIssues = await got(openFailTitleIssueEndpoint, { ...apiOptions }).json(); + const existingIssue = openFailTitleIssues.find((openFailTitleIssue) => openFailTitleIssue.title === failTitle); + + const canCommentOnOrCreateIssue = failCommentCondition + ? template(failCommentCondition)({ ...context, issue: existingIssue }) + : true; + if (canCommentOnOrCreateIssue) { + if (existingIssue) { + debug("comment on issue: %O", existingIssue); + + const issueNotesEndpoint = urlJoin( + gitlabApiUrl, + `/projects/${existingIssue.project_id}/issues/${existingIssue.iid}/notes` + ); + await got.post(issueNotesEndpoint, { + ...apiOptions, + json: { body: description }, + }); + + const { id, web_url } = existingIssue; + logger.log("Commented on issue #%d: %s.", id, web_url); + } else { + const newIssue = { id: encodedProjectPath, description, labels, title: failTitle, assignee_id: assignee }; + debug("create issue: %O", newIssue); + + /* eslint camelcase: off */ + const { id, web_url } = await got + .post(issuesEndpoint, { + ...apiOptions, + json: newIssue, + }) + .json(); + logger.log("Created issue #%d: %s.", id, web_url); + } + } else { + logger.log("Skip commenting on or creating an issue."); + } + } +}; diff --git a/lib/get-error.js b/lib/get-error.js index 56a09c0d..f797fd36 100644 --- a/lib/get-error.js +++ b/lib/get-error.js @@ -1,7 +1,7 @@ -const SemanticReleaseError = require('@semantic-release/error'); -const ERROR_DEFINITIONS = require('./definitions/errors'); +import SemanticReleaseError from "@semantic-release/error"; +import ERROR_DEFINITIONS from "./definitions/errors.js"; -module.exports = (code, ctx = {}) => { - const {message, details} = ERROR_DEFINITIONS[code](ctx); +export default (code, ctx = {}) => { + const { message, details } = ERROR_DEFINITIONS[code](ctx); return new SemanticReleaseError(message, code, details); }; diff --git a/lib/get-fail-comment.js b/lib/get-fail-comment.js new file mode 100644 index 00000000..922f6f2b --- /dev/null +++ b/lib/get-fail-comment.js @@ -0,0 +1,48 @@ +import { HOME_URL } from "./definitions/constants.js"; + +const FAQ_URL = `${HOME_URL}/blob/master/docs/support/FAQ.md`; +const GET_HELP_URL = `${HOME_URL}#get-help`; +const USAGE_DOC_URL = `${HOME_URL}/blob/master/docs/usage/README.md`; +const NEW_ISSUE_URL = `${HOME_URL}/issues/new`; + +const formatError = (error) => `### ${error.message} + +${ + error.details || + `Unfortunately this error doesn't have any additional information.${ + error.pluginName + ? ` Feel free to kindly ask the author of the \`${error.pluginName}\` plugin to add more helpful information.` + : "" + }` +}`; + +export default (branch, errors) => `## :rotating_light: The automated release from the \`${ + branch.name +}\` branch failed. :rotating_light: + +I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again. + +You can find below the list of errors reported by **semantic-release**. Each one of them has to be resolved in order to automatically publish your package. I'm sure you can fix this 💪. + +Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it. + +Once all the errors are resolved, **semantic-release** will release your package the next time you push a commit to the \`${ + branch.name +}\` branch. You can also manually restart the failed CI job that runs **semantic-release**. + +If you are not sure how to resolve this, here are some links that can help you: +- [Usage documentation](${USAGE_DOC_URL}) +- [Frequently Asked Questions](${FAQ_URL}) +- [Support channels](${GET_HELP_URL}) + +If those don't help, or if this issue is reporting something you think isn't right, you can always ask the humans behind **[semantic-release](${NEW_ISSUE_URL})**. + +--- + +${errors.map((error) => formatError(error)).join("\n\n---\n\n")} + +--- + +Good luck with your project ✨ + +Your **[semantic-release](${HOME_URL})** bot :package: :rocket:`; diff --git a/lib/get-project-context.js b/lib/get-project-context.js new file mode 100644 index 00000000..ad7bd049 --- /dev/null +++ b/lib/get-project-context.js @@ -0,0 +1,27 @@ +import escapeStringRegexp from "escape-string-regexp"; +import parseUrl from "parse-url"; +import urlJoin from "url-join"; + +export default ( + { envCi: { service } = {}, env: { CI_PROJECT_ID, CI_PROJECT_PATH } }, + gitlabUrl, + gitlabApiUrl, + repositoryUrl +) => { + const projectId = service === "gitlab" && CI_PROJECT_ID ? CI_PROJECT_ID : null; + const projectPath = + service === "gitlab" && CI_PROJECT_PATH + ? CI_PROJECT_PATH + : parseUrl(repositoryUrl) + .pathname.replace(new RegExp(`^${escapeStringRegexp(parseUrl(gitlabUrl).pathname)}`), "") + .replace(/^\//, "") + .replace(/\/$/, "") + .replace(/\.git$/, ""); + const encodedProjectPath = encodeURIComponent(projectPath); + const projectApiUrl = urlJoin(gitlabApiUrl, `/projects/${projectId ?? encodedProjectPath}`); + return { + projectPath, + encodedProjectPath, + projectApiUrl, + }; +}; diff --git a/lib/get-repo-id.js b/lib/get-repo-id.js deleted file mode 100644 index 27f77e3e..00000000 --- a/lib/get-repo-id.js +++ /dev/null @@ -1,11 +0,0 @@ -const parsePath = require('parse-path'); -const escapeStringRegexp = require('escape-string-regexp'); - -module.exports = ({envCi: {service} = {}, env: {CI_PROJECT_PATH}}, gitlabUrl, repositoryUrl) => - service === 'gitlab' && CI_PROJECT_PATH - ? CI_PROJECT_PATH - : parsePath(repositoryUrl) - .pathname.replace(new RegExp(`^${escapeStringRegexp(parsePath(gitlabUrl).pathname)}`), '') - .replace(/^\//, '') - .replace(/\/$/, '') - .replace(/\.git$/, ''); diff --git a/lib/get-success-comment.js b/lib/get-success-comment.js new file mode 100644 index 00000000..09bf8163 --- /dev/null +++ b/lib/get-success-comment.js @@ -0,0 +1,18 @@ +import { HOME_URL } from "./definitions/constants.js"; + +const linkify = (releaseInfo) => + `${releaseInfo.url ? `[${releaseInfo.name}](${releaseInfo.url})` : `\`${releaseInfo.name}\``}`; + +export default (issueOrMergeRequest, releaseInfos, nextRelease) => + `:tada: This ${issueOrMergeRequest.isMergeRequest ? "MR is included" : "issue has been resolved"} in version ${ + nextRelease.version + } :tada:${ + releaseInfos.length > 0 + ? `\n\nThe release is available on${ + releaseInfos.length === 1 + ? ` ${linkify(releaseInfos[0])}.` + : `:\n${releaseInfos.map((releaseInfo) => `- ${linkify(releaseInfo)}`).join("\n")}` + }` + : "" + } +\nYour **[semantic-release](${HOME_URL})** bot :package: :rocket:`; diff --git a/lib/glob-assets.js b/lib/glob-assets.js index a308eb14..6941bfb1 100644 --- a/lib/glob-assets.js +++ b/lib/glob-assets.js @@ -1,25 +1,26 @@ -const path = require('path'); -const {basename} = require('path'); -const {isPlainObject, castArray, uniqWith, uniq} = require('lodash'); -const dirGlob = require('dir-glob'); -const globby = require('globby'); -const debug = require('debug')('semantic-release:github'); +import path from "path"; +import { isPlainObject, castArray, uniqWith, uniq } from "lodash-es"; +import dirGlob from "dir-glob"; +import { globby } from "globby"; +import _debug from "debug"; +const debug = _debug("semantic-release:gitlab"); -module.exports = async ({cwd}, assets) => +export default async ({ cwd }, assets) => uniqWith( [] + // eslint-disable-next-line unicorn/prefer-spread .concat( ...(await Promise.all( - assets.map(async asset => { + assets.map(async (asset) => { // Wrap single glob definition in Array let glob = castArray(isPlainObject(asset) ? asset.path : asset); // TODO Temporary workaround for https://github.com/mrmlnc/fast-glob/issues/47 - glob = uniq([...(await dirGlob(glob, {cwd})), ...glob]); + glob = uniq([...(await dirGlob(glob, { cwd })), ...glob]); // Skip solo negated pattern (avoid to include every non js file with `!**/*.js`) - if (glob.length <= 1 && glob[0].startsWith('!')) { + if (glob.length <= 1 && glob[0].startsWith("!")) { debug( - 'skipping the negated glob %o as its alone in its group and would retrieve a large amount of files', + "skipping the negated glob %o as its alone in its group and would retrieve a large amount of files", glob[0] ); return []; @@ -38,15 +39,17 @@ module.exports = async ({cwd}, assets) => // If asset is an Object with a glob the `path` property that resolve to multiple files, // Output an Object definition for each file matched and set each one with: // - `path` of the matched file - // - `name` based on the actual file name (to avoid assets with duplicate `name`) + // - `label` based on the actual file name (to avoid assets with duplicate `label`s) + // - `filepath` ignored (also to avoid duplicates) // - other properties of the original asset definition - return globbed.map(file => ({...asset, path: file, name: basename(file)})); + const { filepath, ...others } = asset; + return globbed.map((file) => ({ ...others, path: file, label: path.basename(file) })); } // If asset is an Object, output an Object definition with: // - `path` of the matched file if there is one, or the original `path` definition (will be considered as a missing file) // - other properties of the original asset definition - return {...asset, path: globbed[0] || asset.path}; + return { ...asset, path: globbed[0] || asset.path }; } if (globbed.length > 0) { @@ -60,7 +63,7 @@ module.exports = async ({cwd}, assets) => // Sort with Object first, to prioritize Object definition over Strings in dedup )) ) - .sort(asset => (isPlainObject(asset) ? -1 : 1)), + .sort((asset) => (isPlainObject(asset) ? -1 : 1)), // Compare `path` property if Object definition, value itself if String (a, b) => path.resolve(cwd, isPlainObject(a) ? a.path : a) === path.resolve(cwd, isPlainObject(b) ? b.path : b) ); diff --git a/lib/publish.js b/lib/publish.js index 358a96a4..a86c4ac9 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -1,91 +1,229 @@ -const {createReadStream} = require('fs'); -const {resolve} = require('path'); -const {stat} = require('fs-extra'); -const {isPlainObject} = require('lodash'); -const FormData = require('form-data'); -const urlJoin = require('url-join'); -const got = require('got'); -const debug = require('debug')('semantic-release:gitlab'); -const resolveConfig = require('./resolve-config'); -const getRepoId = require('./get-repo-id'); -const getAssets = require('./glob-assets'); - -module.exports = async (pluginConfig, context) => { +import { readFileSync } from "fs"; +import pathlib from "path"; +import fs from "fs-extra"; +import { isPlainObject, template } from "lodash-es"; +import { FormData } from "formdata-node"; +import { fileFromPath } from "formdata-node/file-from-path"; +import urlJoin from "url-join"; +import got from "got"; +import _debug from "debug"; +const debug = _debug("semantic-release:gitlab"); +import resolveConfig from "./resolve-config.js"; +import getAssets from "./glob-assets.js"; +import { RELEASE_NAME } from "./definitions/constants.js"; +import getProjectContext from "./get-project-context.js"; + +const isUrlScheme = (value) => /^(https|http|ftp):\/\//.test(value); + +export default async (pluginConfig, context) => { const { cwd, - options: {repositoryUrl}, - nextRelease: {gitTag, gitHead, notes}, + options: { repositoryUrl }, + nextRelease: { gitTag, gitHead, notes, version }, logger, } = context; - const {gitlabToken, gitlabUrl, gitlabApiUrl, assets} = resolveConfig(pluginConfig, context); + const { gitlabToken, tokenHeader, gitlabUrl, gitlabApiUrl, assets, milestones, proxy, retryLimit, retryStatusCodes } = + resolveConfig(pluginConfig, context); const assetsList = []; - const repoId = getRepoId(context, gitlabUrl, repositoryUrl); - const encodedRepoId = encodeURIComponent(repoId); + const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); + const encodedGitTag = encodeURIComponent(gitTag); - const apiOptions = {headers: {'PRIVATE-TOKEN': gitlabToken}}; + const apiOptions = { + headers: { + [tokenHeader]: gitlabToken, + }, + hooks: { + beforeError: [ + (error) => { + const { response } = error; + if (response?.body && response.headers["content-type"] === "application/json") { + const parsedBody = JSON.parse(response.body); + if (parsedBody.message) { + error.message = `Response code ${response.statusCode} (${parsedBody.message})`; + } + } + return error; + }, + ], + }, + retry: { limit: retryLimit, statusCodes: retryStatusCodes }, + }; - debug('repoId: %o', repoId); - debug('release name: %o', gitTag); - debug('release ref: %o', gitHead); + debug("projectPath: %o", projectPath); + debug("release name: %o", gitTag); + debug("release ref: %o", gitHead); + debug("milestones: %o", milestones); if (assets && assets.length > 0) { - const globbedAssets = await getAssets(context, assets); - debug('globbed assets: %o', globbedAssets); + const templatedAssets = assets.map((asset) => { + if (isPlainObject(asset)) { + const templatedAsset = { ...asset }; + if (asset.path) { + templatedAsset.path = Array.isArray(asset.path) + ? asset.path.map((pattern) => template(pattern)(context)) + : template(asset.path)(context); + } + templatedAsset.url = asset.url ? template(asset.url)(context) : asset.url; + templatedAsset.label = asset.label ? template(asset.label)(context) : asset.label; + templatedAsset.type = asset.type ? template(asset.type)(context) : asset.type; + templatedAsset.filepath = asset.filepath ? template(asset.filepath)(context) : asset.filepath; + templatedAsset.target = asset.target ? template(asset.target)(context) : asset.target; + templatedAsset.status = asset.status ? template(asset.status)(context) : asset.status; + templatedAsset.packageName = asset.packageName ? template(asset.packageName)(context) : asset.packageName; + return templatedAsset; + } else if (Array.isArray(asset)) { + // Handle array of glob patterns + return asset.map((pattern) => template(pattern)(context)); + } else { + // String asset path + return template(asset)(context); + } + }); + + // Skip glob if url is provided + const urlAssets = templatedAssets.filter((asset) => asset.url); + debug("url assets: %o", urlAssets); + const globbedAssets = await getAssets( + context, + templatedAssets.filter((asset) => !asset.url) + ); + debug("globbed assets: %o", globbedAssets); + const allAssets = [...urlAssets, ...globbedAssets]; + debug("all assets: %o", allAssets); await Promise.all( - globbedAssets.map(async asset => { - const {path, label} = isPlainObject(asset) ? asset : {path: asset}; - const file = resolve(cwd, path); - let fileStat; - - try { - fileStat = await stat(file); - } catch (_) { - logger.error('The asset %s cannot be read, and will be ignored.', path); - return; - } + allAssets.map(async (asset) => { + const path = isPlainObject(asset) ? asset.path : asset; - if (!fileStat || !fileStat.isFile()) { - logger.error('The asset %s is not a file, and will be ignored.', path); - return; - } + if (asset.url) { + assetsList.push({ label: asset.label, rawUrl: asset.url, type: asset.type, filepath: asset.filepath }); + debug("use link from release setting: %s", asset.url); + } else { + const file = pathlib.resolve(cwd, path); + + let fileStat; + + try { + fileStat = await fs.stat(file); + } catch { + logger.error("The asset %s cannot be read, and will be ignored.", path); + return; + } + + if (!fileStat || !fileStat.isFile()) { + logger.error("The asset %s is not a file, and will be ignored.", path); + return; + } + + debug("file path: %o", path); + debug("file label: %o", asset.label); + debug("file type: %o", asset.type); + debug("file filepath: %o", asset.filepath); + debug("file target: %o", asset.target); + debug("file status: %o", asset.status); + debug("package name: %o", asset.packageName); + + let uploadEndpoint; + let response; + + if (asset.target === "generic_package") { + const finalLabel = asset.label ?? pathlib.basename(file); + const packageName = asset.packageName ?? "release"; + // Upload generic packages + const encodedVersion = encodeURIComponent(version); + const encodedPackageName = encodeURIComponent(packageName); + const encodedLabel = encodeURIComponent(finalLabel); + // https://docs.gitlab.com/ee/user/packages/generic_packages/#publish-a-package-file + uploadEndpoint = urlJoin( + projectApiUrl, + `packages/generic/${encodedPackageName}/${encodedVersion}/${encodedLabel}?${ + asset.status ? `status=${asset.status}&` : "" + }select=package_file` + ); - debug('file path: %o', path); - debug('file label: %o', label); + debug("PUT-ing the file %s to %s", file, uploadEndpoint); - // Uploaded assets to the project - const form = new FormData(); - form.append('file', createReadStream(file)); - const {url, alt} = await got - .post(urlJoin(gitlabApiUrl, `/projects/${encodedRepoId}/uploads`), {...apiOptions, body: form}) - .json(); + try { + response = await got.put(uploadEndpoint, { ...apiOptions, ...proxy, body: readFileSync(file) }).json(); + } catch (error) { + logger.error("An error occurred while uploading %s to the GitLab generics package API:\n%O", file, error); + throw error; + } - assetsList.push({label, alt, url}); + // https://docs.gitlab.com/ee/user/packages/generic_packages/#download-package-file + const url = urlJoin( + projectApiUrl, + `packages/generic/${encodedPackageName}/${encodedVersion}/${encodedLabel}` + ); - logger.log('Uploaded file: %s', url); + assetsList.push({ label: finalLabel, alt: packageName, url, type: "package", filepath: asset.filepath }); + + logger.log("Uploaded file: %s (%s)", url, response.file.url); + } else { + // Handle normal assets + uploadEndpoint = urlJoin(projectApiUrl, "uploads"); + + debug("POST-ing the file %s to %s", file, uploadEndpoint); + + try { + const form = new FormData(); + form.append("file", await fileFromPath(file)); + response = await got.post(uploadEndpoint, { ...apiOptions, ...proxy, body: form }).json(); + } catch (error) { + logger.error("An error occurred while uploading %s to the GitLab project uploads API:\n%O", file, error); + throw error; + } + + const { alt, full_path } = response; + const url = urlJoin(gitlabUrl, full_path); + + assetsList.push({ label: asset.label, alt, url, type: asset.type, filepath: asset.filepath }); + + logger.log("Uploaded file: %s", url); + } + } }) ); } - debug('Update git tag %o with commit %o and release description', gitTag, gitHead); - await got.post(urlJoin(gitlabApiUrl, `/projects/${encodedRepoId}/repository/tags/${encodedGitTag}/release`), { - ...apiOptions, - json: {tag_name: gitTag, description: notes}, // eslint-disable-line camelcase - }); + debug("Create a release for git tag %o with commit %o", gitTag, gitHead); - if (assetsList.length > 0) { - await Promise.all( - assetsList.map(({label, alt, url}) => { - debug('Add link to asset %o', label || alt); - return got.post(urlJoin(gitlabApiUrl, `/projects/${encodedRepoId}/releases/${encodedGitTag}/assets/links`), { - ...apiOptions, - json: {name: label || alt, url: urlJoin(gitlabUrl, repoId, url)}, - }); - }) - ); + const createReleaseEndpoint = urlJoin(projectApiUrl, "releases"); + + const json = { + /* eslint-disable camelcase */ + tag_name: gitTag, + description: notes && notes.trim() ? notes : gitTag, + milestones, + assets: { + links: assetsList.map(({ label, alt, url, type, filepath, rawUrl }) => { + return { + name: label || alt, + url: rawUrl || (isUrlScheme(url) ? url : urlJoin(gitlabUrl, projectPath, url)), + link_type: type, + filepath, + }; + }), + }, + /* eslint-enable camelcase */ + }; + + debug("POST-ing the following JSON to %s:\n%s", createReleaseEndpoint, JSON.stringify(json, null, 2)); + + try { + await got.post(createReleaseEndpoint, { + ...apiOptions, + ...proxy, + json, + }); + } catch (error) { + logger.error("An error occurred while making a request to the GitLab release API:\n%O", error); + throw error; } - logger.log('Published GitLab release: %s', gitTag); + logger.log("Published GitLab release: %s", gitTag); + + const releaseUrl = urlJoin(gitlabUrl, projectPath, `/-/releases/${encodedGitTag}`); - return {url: urlJoin(gitlabUrl, encodedRepoId, `/tags/${encodedGitTag}`), name: 'GitLab release'}; + return { name: RELEASE_NAME, url: releaseUrl }; }; diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 6555af98..3bb87627 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -1,23 +1,46 @@ -const {castArray, isNil} = require('lodash'); -const urlJoin = require('url-join'); +import { castArray, isNil } from "lodash-es"; +import urlJoin from "url-join"; +import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"; -module.exports = ( - {gitlabUrl, gitlabApiPathPrefix, assets}, +export default ( { - envCi: {service} = {}, + gitlabUrl, + gitlabApiPathPrefix, + assets, + milestones, + successComment, + successCommentCondition, + failTitle, + failComment, + failCommentCondition, + labels, + assignee, + retryLimit, + useJobToken, + }, + { + envCi: { service } = {}, env: { CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL, + CI_JOB_TOKEN, GL_TOKEN, GITLAB_TOKEN, GL_URL, GITLAB_URL, GL_PREFIX, GITLAB_PREFIX, + HTTP_PROXY, + HTTPS_PROXY, + NO_PROXY, }, } ) => { + const DEFAULT_RETRY_LIMIT = 3; + // Added 422 to fix #839 + // https://github.com/sindresorhus/got/blob/a359bd385129d2adbc765b52dfbbadac5f54a825/documentation/7-retry.md#retry + const DEFAULT_RETRY_STATUS_CODES = [408, 413, 422, 429, 500, 502, 503, 504, 521, 522, 524]; const userGitlabApiPathPrefix = isNil(gitlabApiPathPrefix) ? isNil(GL_PREFIX) ? GITLAB_PREFIX @@ -26,19 +49,129 @@ module.exports = ( const userGitlabUrl = gitlabUrl || GL_URL || GITLAB_URL; const defaultedGitlabUrl = userGitlabUrl || - (service === 'gitlab' && CI_PROJECT_URL && CI_PROJECT_PATH - ? CI_PROJECT_URL.replace(new RegExp(`/${CI_PROJECT_PATH}$`), '') - : 'https://gitlab.com'); - + (service === "gitlab" && CI_PROJECT_URL && CI_PROJECT_PATH + ? CI_PROJECT_URL.replace(new RegExp(`/${CI_PROJECT_PATH}$`), "") + : "https://gitlab.com"); return { - gitlabToken: GL_TOKEN || GITLAB_TOKEN, + gitlabToken: useJobToken ? CI_JOB_TOKEN : GL_TOKEN || GITLAB_TOKEN, + tokenHeader: useJobToken ? "JOB-TOKEN" : "PRIVATE-TOKEN", + useJobToken, gitlabUrl: defaultedGitlabUrl, gitlabApiUrl: userGitlabUrl && userGitlabApiPathPrefix ? urlJoin(userGitlabUrl, userGitlabApiPathPrefix) - : service === 'gitlab' && CI_API_V4_URL - ? CI_API_V4_URL - : urlJoin(defaultedGitlabUrl, isNil(userGitlabApiPathPrefix) ? '/api/v4' : userGitlabApiPathPrefix), + : service === "gitlab" && CI_API_V4_URL + ? CI_API_V4_URL + : urlJoin(defaultedGitlabUrl, isNil(userGitlabApiPathPrefix) ? "/api/v4" : userGitlabApiPathPrefix), assets: assets ? castArray(assets) : assets, + milestones: milestones ? castArray(milestones) : milestones, + successComment, + successCommentCondition: useJobToken ? false : successCommentCondition, + proxy: getProxyConfiguration(defaultedGitlabUrl, HTTP_PROXY, HTTPS_PROXY, NO_PROXY), + failTitle: isNil(failTitle) ? "The automated release is failing 🚨" : failTitle, + failComment, + failCommentCondition: useJobToken ? false : failCommentCondition, + labels: isNil(labels) ? "semantic-release" : labels === false ? false : labels, + assignee, + retryLimit: retryLimit ?? DEFAULT_RETRY_LIMIT, + retryStatusCodes: DEFAULT_RETRY_STATUS_CODES, }; }; + +// Copied from Rob Wu's great proxy-from-env library: https://github.com/Rob--W/proxy-from-env/blob/96d01f8fcfdccfb776735751132930bbf79c4a3a/index.js#L62 +function shouldProxy(gitlabUrl, NO_PROXY) { + const DEFAULT_PORTS = { + ftp: 21, + gopher: 70, + http: 80, + https: 443, + ws: 80, + wss: 443, + }; + const parsedUrl = + typeof gitlabUrl === "string" && (gitlabUrl.startsWith("https://") || gitlabUrl.startsWith("https://")) + ? new URL(gitlabUrl) + : gitlabUrl || {}; + let proto = parsedUrl.protocol; + let hostname = parsedUrl.host; + let { port } = parsedUrl; + if (typeof hostname !== "string" || !hostname || typeof proto !== "string") { + return ""; // Don't proxy URLs without a valid scheme or host. + } + + proto = proto.split(":", 1)[0]; + // Stripping ports in this way instead of using parsedUrl.hostname to make + // sure that the brackets around IPv6 addresses are kept. + hostname = hostname.replace(/:\d*$/, ""); + port = Number.parseInt(port, 10) || DEFAULT_PORTS[proto] || 0; + + if (!NO_PROXY) { + return true; // Always proxy if NO_PROXY is not set. + } + + if (NO_PROXY === "*") { + return false; // Never proxy if wildcard is set. + } + + return NO_PROXY.split(/[,\s]/).every((proxy) => { + if (!proxy) { + return true; // Skip zero-length hosts. + } + + const parsedProxy = proxy.match(/^(.+):(\d+)$/); + let parsedProxyHostname = parsedProxy ? parsedProxy[1] : proxy; + const parsedProxyPort = parsedProxy ? Number.parseInt(parsedProxy[2], 10) : 0; + if (parsedProxyPort && parsedProxyPort !== port) { + return true; // Skip if ports don't match. + } + + if (!/^[.*]/.test(parsedProxyHostname)) { + // No wildcards, so stop proxying if there is an exact match. + return hostname !== parsedProxyHostname; + } + + if (parsedProxyHostname.charAt(0) === "*") { + // Remove leading wildcard. + parsedProxyHostname = parsedProxyHostname.slice(1); + } + + // Stop proxying if the hostname ends with the no_proxy host. + return !hostname.endsWith(parsedProxyHostname); + }); +} + +function getProxyConfiguration(gitlabUrl, HTTP_PROXY, HTTPS_PROXY, NO_PROXY) { + const sharedParameters = { + keepAlive: true, + keepAliveMsecs: 1000, + maxSockets: 256, + maxFreeSockets: 256, + scheduling: "lifo", + }; + + if (shouldProxy(gitlabUrl, NO_PROXY)) { + if (HTTP_PROXY && gitlabUrl.startsWith("https://")) { + return { + agent: { + http: new HttpProxyAgent({ + ...sharedParameters, + proxy: HTTP_PROXY, + }), + }, + }; + } + + if (HTTPS_PROXY && gitlabUrl.startsWith("https://")) { + return { + agent: { + https: new HttpsProxyAgent({ + ...sharedParameters, + proxy: HTTPS_PROXY, + }), + }, + }; + } + } + + return {}; +} diff --git a/lib/success.js b/lib/success.js new file mode 100644 index 00000000..1c3ed3bb --- /dev/null +++ b/lib/success.js @@ -0,0 +1,136 @@ +import { uniqWith, isEqual, template } from "lodash-es"; +import urlJoin from "url-join"; +import got from "got"; +import _debug from "debug"; +const debug = _debug("semantic-release:gitlab"); +import resolveConfig from "./resolve-config.js"; +import getProjectContext from "./get-project-context.js"; +import getSuccessComment from "./get-success-comment.js"; + +export default async (pluginConfig, context) => { + const { + options: { repositoryUrl }, + nextRelease, + logger, + commits, + releases, + } = context; + const { + gitlabToken, + tokenHeader, + gitlabUrl, + gitlabApiUrl, + successComment, + successCommentCondition, + proxy, + retryLimit, + retryStatusCodes, + useJobToken, + } = resolveConfig(pluginConfig, context); + const { projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); + const apiOptions = { + headers: { [tokenHeader]: gitlabToken }, + retry: { limit: retryLimit, statusCodes: retryStatusCodes }, + }; + + if (successComment === false) { + logger.log("Skip commenting on issues and pull requests."); + logger.error(`Issue and pull request comments should be disabled via 'successCommentCondition'. +Using 'false' for 'successComment' is deprecated and will be removed in a future major version.`); + } else if (successCommentCondition === false) { + logger.log( + "Skip commenting on issues and pull requests." + useJobToken + ? " Setting 'successComment' has no effect when 'useJobToken' is set." + : "" + ); + } else { + const releaseInfos = releases.filter((release) => Boolean(release.name)); + try { + const postCommentToIssue = (issue) => { + const canCommentOnIssue = successCommentCondition + ? template(successCommentCondition)({ ...context, issue, mergeRequest: false }) + : true; + if (canCommentOnIssue) { + const issueNotesEndpoint = urlJoin(gitlabApiUrl, `/projects/${issue.project_id}/issues/${issue.iid}/notes`); + debug("Posting issue note to %s", issueNotesEndpoint); + const body = successComment + ? template(successComment)({ ...context, issue, mergeRequest: false }) + : getSuccessComment(issue, releaseInfos, nextRelease); + return got.post(issueNotesEndpoint, { + ...apiOptions, + ...proxy, + json: { body }, + }); + } else { + logger.log("Skip commenting on issue #%d.", issue.id); + } + }; + + const postCommentToMergeRequest = (mergeRequest) => { + const canCommentOnMergeRequest = successCommentCondition + ? template(successCommentCondition)({ ...context, issue: false, mergeRequest }) + : true; + if (canCommentOnMergeRequest) { + const mergeRequestNotesEndpoint = urlJoin( + gitlabApiUrl, + `/projects/${mergeRequest.project_id}/merge_requests/${mergeRequest.iid}/notes` + ); + debug("Posting MR note to %s", mergeRequestNotesEndpoint); + const body = successComment + ? template(successComment)({ ...context, issue: false, mergeRequest }) + : getSuccessComment({ isMergeRequest: true, ...mergeRequest }, releaseInfos, nextRelease); + return got.post(mergeRequestNotesEndpoint, { + ...apiOptions, + ...proxy, + json: { body }, + }); + } else { + logger.log("Skip commenting on merge request #%d.", mergeRequest.iid); + } + }; + + const getRelatedMergeRequests = async (commitHash) => { + const relatedMergeRequestsEndpoint = urlJoin(projectApiUrl, `repository/commits/${commitHash}/merge_requests`); + debug("Getting MRs from %s", relatedMergeRequestsEndpoint); + const relatedMergeRequests = await got + .get(relatedMergeRequestsEndpoint, { + ...apiOptions, + ...proxy, + }) + .json(); + + return relatedMergeRequests.filter((x) => x.state === "merged"); + }; + + const getRelatedIssues = async (mergeRequest) => { + const relatedIssuesEndpoint = urlJoin( + gitlabApiUrl, + `/projects/${mergeRequest.project_id}/merge_requests/${mergeRequest.iid}/closes_issues` + ); + debug("Getting related issues from %s", relatedIssuesEndpoint); + const relatedIssues = await got + .get(relatedIssuesEndpoint, { + ...apiOptions, + ...proxy, + }) + .json(); + + return relatedIssues.filter((x) => x.state === "closed"); + }; + + const relatedMergeRequests = uniqWith( + (await Promise.all(commits.map((commit) => getRelatedMergeRequests(commit.hash)))).flat(), + isEqual + ); + const relatedIssues = uniqWith( + (await Promise.all(relatedMergeRequests.map((mergeRequest) => getRelatedIssues(mergeRequest)))).flat(), + isEqual + ); + await Promise.all(relatedIssues.map((issues) => postCommentToIssue(issues))); + await Promise.all(relatedMergeRequests.map((mergeRequest) => postCommentToMergeRequest(mergeRequest))); + } catch (error) { + logger.error("An error occurred while posting comments to related issues and merge requests:\n%O", error); + throw error; + } + } +}; diff --git a/lib/verify.js b/lib/verify.js index 3bfb0baf..bade808f 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -1,68 +1,97 @@ -const {isString, isPlainObject, isArray} = require('lodash'); -const urlJoin = require('url-join'); -const got = require('got'); -const debug = require('debug')('semantic-release:gitlab'); -const AggregateError = require('aggregate-error'); -const resolveConfig = require('./resolve-config'); -const getRepoId = require('./get-repo-id'); -const getError = require('./get-error'); +import { isString, isPlainObject, isNil, isArray } from "lodash-es"; +import got from "got"; +import _debug from "debug"; +const debug = _debug("semantic-release:gitlab"); +import AggregateError from "aggregate-error"; +import resolveConfig from "./resolve-config.js"; +import getProjectContext from "./get-project-context.js"; +import getError from "./get-error.js"; +import urlJoin from "url-join"; -const isNonEmptyString = value => isString(value) && value.trim(); -const isStringOrStringArray = value => isNonEmptyString(value) || (isArray(value) && value.every(isNonEmptyString)); -const isArrayOf = validator => array => isArray(array) && array.every(value => validator(value)); +const isNonEmptyString = (value) => isString(value) && value.trim(); +const isStringOrStringArray = (value) => + isNonEmptyString(value) || (isArray(value) && value.every((item) => isNonEmptyString(item))); +const isArrayOf = (validator) => (array) => isArray(array) && array.every((value) => validator(value)); +const canBeDisabled = (validator) => (value) => value === false || validator(value); const VALIDATORS = { assets: isArrayOf( - asset => isStringOrStringArray(asset) || (isPlainObject(asset) && isStringOrStringArray(asset.path)) + (asset) => + isStringOrStringArray(asset) || + (isPlainObject(asset) && (isNonEmptyString(asset.url) || isStringOrStringArray(asset.path))) ), + failTitle: canBeDisabled(isNonEmptyString), + failComment: canBeDisabled(isNonEmptyString), + labels: canBeDisabled(isNonEmptyString), + assignee: isNonEmptyString, }; -module.exports = async (pluginConfig, context) => { +export default async (pluginConfig, context) => { const { - options: {repositoryUrl}, + options: { repositoryUrl }, logger, } = context; - const errors = []; - const {gitlabToken, gitlabUrl, gitlabApiUrl, assets} = resolveConfig(pluginConfig, context); - const repoId = getRepoId(context, gitlabUrl, repositoryUrl); - debug('apiUrl: %o', gitlabApiUrl); - debug('repoId: %o', repoId); + const { gitlabToken, gitlabUrl, gitlabApiUrl, tokenHeader, useJobToken, proxy, ...options } = resolveConfig( + pluginConfig, + context + ); + const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); - if (!repoId) { - errors.push(getError('EINVALIDGITLABURL')); - } + debug("apiUrl: %o", gitlabApiUrl); + debug("projectPath: %o", projectPath); + + const isValid = (option, value) => { + const validator = VALIDATORS[option]; + return isNil(value) || isNil(validator) || VALIDATORS[option](value); + }; + + const errors = Object.entries({ ...options }) + .filter(([option, value]) => !isValid(option, value)) + .map(([option, value]) => getError(`EINVALID${option.toUpperCase()}`, { [option]: value })); - if (assets && !VALIDATORS.assets(assets)) { - errors.push(getError('EINVALIDASSETS')); + if (!projectPath) { + errors.push(getError("EINVALIDGITLABURL")); } if (!gitlabToken) { - errors.push(getError('ENOGLTOKEN', {repositoryUrl})); + errors.push(getError("ENOGLTOKEN", { repositoryUrl })); } - if (gitlabToken && repoId) { + if (gitlabToken && projectPath) { let projectAccess; let groupAccess; - logger.log('Verify GitLab authentication (%s)', gitlabApiUrl); + logger.log("Verify GitLab authentication (%s)", gitlabApiUrl); try { - ({ - permissions: {project_access: projectAccess, group_access: groupAccess}, - } = await got - .get(urlJoin(gitlabApiUrl, `/projects/${encodeURIComponent(repoId)}`), { - headers: {'PRIVATE-TOKEN': gitlabToken}, - }) - .json()); - - if (!((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30))) { - errors.push(getError('EGLNOPERMISSION', {repoId})); + if (useJobToken) { + logger.log("Using Job Token for authentication. Some functionality may be disabled."); + await got.get(urlJoin(projectApiUrl, "releases"), { headers: { [tokenHeader]: gitlabToken } }); + } else { + ({ + permissions: { project_access: projectAccess, group_access: groupAccess }, + } = await got + .get(projectApiUrl, { + headers: { [tokenHeader]: gitlabToken }, + ...proxy, + }) + .json()); + if ( + context.options.dryRun && + !((projectAccess && projectAccess.access_level >= 10) || (groupAccess && groupAccess.access_level >= 10)) + ) { + errors.push(getError("EGLNOPULLPERMISSION", { projectPath })); + } else if ( + !((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30)) + ) { + errors.push(getError("EGLNOPUSHPERMISSION", { projectPath })); + } } } catch (error) { - if (error.response.statusCode === 401) { - errors.push(getError('EINVALIDGLTOKEN', {repoId})); - } else if (error.response.statusCode === 404) { - errors.push(getError('EMISSINGREPO', {repoId})); + if (error.response && error.response.statusCode === 401) { + errors.push(getError("EINVALIDGLTOKEN", { projectPath })); + } else if (error.response && error.response.statusCode === 404) { + errors.push(getError("EMISSINGREPO", { projectPath })); } else { throw error; } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..0e6e1c75 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8619 @@ +{ + "name": "@semantic-release/gitlab", + "version": "0.0.0-development", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@semantic-release/gitlab", + "version": "0.0.0-development", + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "escape-string-regexp": "^5.0.0", + "formdata-node": "^6.0.3", + "fs-extra": "^11.0.0", + "globby": "^14.0.0", + "got": "^14.0.0", + "hpagent": "^1.0.0", + "lodash-es": "^4.17.21", + "parse-url": "^10.0.0", + "url-join": "^4.0.0" + }, + "devDependencies": { + "ava": "6.4.1", + "c8": "11.0.0", + "nock": "14.0.15", + "prettier": "3.8.4", + "semantic-release": "25.0.5", + "sinon": "22.0.0", + "tempy": "1.0.1" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@actions/core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/exec": "^3.0.0", + "@actions/http-client": "^4.0.0" + } + }, + "node_modules/@actions/exec": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-3.0.0.tgz", + "integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/io": "^3.0.2" + } + }, + "node_modules/@actions/http-client": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz", + "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^6.23.0" + } + }, + "node_modules/@actions/http-client/node_modules/undici": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", + "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@actions/io": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-3.0.2.tgz", + "integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "license": "MIT" + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz", + "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "consola": "^3.2.3", + "detect-libc": "^2.0.0", + "https-proxy-agent": "^7.0.5", + "node-fetch": "^2.6.7", + "nopt": "^8.0.0", + "semver": "^7.5.3", + "tar": "^7.4.0" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.41.9", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.9.tgz", + "integrity": "sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz", + "integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.1.0.tgz", + "integrity": "sha512-O1FZgXeiGb2sowEr/hYTr6YunGdSAFWnr2fyW39Ah85H8O33ELASQxcvOFF5LE6Tjekcyu2ms4qAzJVhSaJxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=7" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.3.tgz", + "integrity": "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": "^7.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.10.tgz", + "integrity": "sha512-KxNC2pTqqhszMNrf12ZRd4PonRgyJdsM4F/jySiddQK+DsRcfBtUvqn8t7UsyZhnRJHvX46OohDt5N3VqIWC2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.3", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "content-type": "^2.0.0", + "json-with-bigint": "^3.5.3", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.3.tgz", + "integrity": "sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.1.tgz", + "integrity": "sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/github": { + "version": "12.0.8", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-12.0.8.tgz", + "integrity": "sha512-tej5AAgK5X9wHRoDmYhecMXEHEkFeGOY1XsEblKxu8pIQwahzf1STYyr7iPU6Lpbg6C5I3N2w/ocXrBo+L7jhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.0", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-retry": "^8.0.0", + "@octokit/plugin-throttling": "^11.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "http-proxy-agent": "^9.0.0", + "https-proxy-agent": "^9.0.0", + "issue-parser": "^7.0.0", + "lodash-es": "^4.17.21", + "mime": "^4.0.0", + "p-filter": "^4.0.0", + "tinyglobby": "^0.2.14", + "undici": "^7.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + }, + "peerDependencies": { + "semantic-release": ">=24.1.0" + } + }, + "node_modules/@semantic-release/github/node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@semantic-release/github/node_modules/https-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", + "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@semantic-release/github/node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@semantic-release/npm": { + "version": "13.1.5", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-13.1.5.tgz", + "integrity": "sha512-Hq5UxzoatN3LHiq2rTsWS54nCdqJHlsssGERCo8WlvdfFA9LoN0vO+OuKVSjtNapIc/S8C2LBj206wKLHg62mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/core": "^3.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "env-ci": "^11.2.0", + "execa": "^9.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^9.0.0", + "npm": "^11.6.2", + "rc": "^1.2.8", + "read-pkg": "^10.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/normalize-url": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-9.0.1.tgz", + "integrity": "sha512-ARftfC5HdUNu9jJeL8pHj8debUIHA2b91FizCoMzY4lG6dDX13jdvTK0TBe24IBDRf2HvJSzzwEPvmbkQWHRSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/tempy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.2.0.tgz", + "integrity": "sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.1.1.tgz", + "integrity": "sha512-Pbd2e2XRMUD0OxehHpgd5/YghsE76cddkRHSoDvKLK+OCy4Ewxn49rWR631MEUU01lgwF/uyVXvbnVuu6+Z6VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "read-package-up": "^11.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", + "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-10.0.2.tgz", + "integrity": "sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/nft": { + "version": "0.29.4", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.29.4.tgz", + "integrity": "sha512-6lLqMNX3TuycBPABycx7A9F1bHQR7kiQln6abjFbPrf5C/05qHM9M5E4PeTE59c7z8g6vHnx1Ioihb2AQl7BTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^2.0.0", + "@rollup/pluginutils": "^5.1.3", + "acorn": "^8.6.0", + "acorn-import-attributes": "^1.9.5", + "async-sema": "^3.1.1", + "bindings": "^1.4.0", + "estree-walker": "2.0.2", + "glob": "^10.4.5", + "graceful-fs": "^4.2.9", + "node-gyp-build": "^4.2.2", + "picomatch": "^4.0.2", + "resolve-from": "^5.0.0" + }, + "bin": { + "nft": "out/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arrgv": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", + "integrity": "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/arrify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", + "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/ava": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/ava/-/ava-6.4.1.tgz", + "integrity": "sha512-vxmPbi1gZx9zhAjHBgw81w/iEDKcrokeRk/fqDTyA2DQygZ0o+dUGRHFOtX8RA5N0heGJTTsIk7+xYxitDb61Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vercel/nft": "^0.29.4", + "acorn": "^8.15.0", + "acorn-walk": "^8.3.4", + "ansi-styles": "^6.2.1", + "arrgv": "^1.0.2", + "arrify": "^3.0.0", + "callsites": "^4.2.0", + "cbor": "^10.0.9", + "chalk": "^5.4.1", + "chunkd": "^2.0.1", + "ci-info": "^4.3.0", + "ci-parallel-vars": "^1.0.1", + "cli-truncate": "^4.0.0", + "code-excerpt": "^4.0.0", + "common-path-prefix": "^3.0.0", + "concordance": "^5.0.4", + "currently-unhandled": "^0.4.1", + "debug": "^4.4.1", + "emittery": "^1.2.0", + "figures": "^6.1.0", + "globby": "^14.1.0", + "ignore-by-default": "^2.1.0", + "indent-string": "^5.0.0", + "is-plain-object": "^5.0.0", + "is-promise": "^4.0.0", + "matcher": "^5.0.0", + "memoize": "^10.1.0", + "ms": "^2.1.3", + "p-map": "^7.0.3", + "package-config": "^5.0.0", + "picomatch": "^4.0.2", + "plur": "^5.1.0", + "pretty-ms": "^9.2.0", + "resolve-cwd": "^3.0.0", + "stack-utils": "^2.0.6", + "strip-ansi": "^7.1.0", + "supertap": "^3.0.1", + "temp-dir": "^3.0.0", + "write-file-atomic": "^6.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "ava": "entrypoints/cli.mjs" + }, + "engines": { + "node": "^18.18 || ^20.8 || ^22 || ^23 || >=24" + }, + "peerDependencies": { + "@ava/typescript": "*" + }, + "peerDependenciesMeta": { + "@ava/typescript": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/blueimp-md5": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", + "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/byte-counter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/byte-counter/-/byte-counter-0.1.0.tgz", + "integrity": "sha512-jheRLVMeUKrDBjVw2O5+k4EvR4t9wtxHL+bo/LxfkxsVeuGMy3a5SEGgXdAFA4FSzTrU8rQXQIrsZ3oBq5a0pQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c8": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz", + "integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^8.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": "20 || >=22" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "13.0.19", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-13.0.19.tgz", + "integrity": "sha512-SVXGH037+Mo1aIMO5B2UcleR43FGjFdN+M8JObSyEoQ2Mn4CODRWx28gN5jiTF0n5ItsgtIZfyargMNs8GX4kg==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.2.0", + "get-stream": "^9.0.1", + "http-cache-semantics": "^4.2.0", + "keyv": "^5.6.0", + "mimic-response": "^4.0.0", + "normalize-url": "^8.1.1", + "responselike": "^4.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/callsites": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.2.0.tgz", + "integrity": "sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cbor": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.12.tgz", + "integrity": "sha512-exQDevYd7ZQLP4moMQcZkKCVZsXLAtUSflObr3xTh4xzFIv/xBCdvCd6L259kQOUP2kcTC0jvC6PpZIf/WmRXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "nofilter": "^3.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chunkd": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chunkd/-/chunkd-2.0.1.tgz", + "integrity": "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ci-parallel-vars": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.1.tgz", + "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/clean-stack": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.3.0.tgz", + "integrity": "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-highlight/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true, + "license": "ISC" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concordance": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", + "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "date-time": "^3.1.0", + "esutils": "^2.0.3", + "fast-diff": "^1.2.0", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.15", + "md5-hex": "^3.0.1", + "semver": "^7.3.2", + "well-known-symbols": "^2.0.0" + }, + "engines": { + "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz", + "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.4.0.tgz", + "integrity": "sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", + "conventional-commits-filter": "^5.0.0", + "handlebars": "^4.7.7", + "meow": "^13.0.0", + "semver": "^7.5.2" + }, + "bin": { + "conventional-changelog-writer": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-filter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", + "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-parser": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", + "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/date-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", + "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "time-zone": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz", + "integrity": "sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==", + "license": "MIT", + "dependencies": { + "mimic-response": "^4.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/del/node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/del/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/del/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emittery": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-1.2.1.tgz", + "integrity": "sha512-sFz64DCRjirhwHLxofFqxYQm6DCp6o0Ix7jwKQvuCHPn4GMRZNuBZyLPu9Ccmk/QSCAMZt6FOUqA8JZCQvA9fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/env-ci": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.2.0.tgz", + "integrity": "sha512-D5kWfzkmaOQDioPmiviWAVtKmpPT4/iJmMVQxWxMPJTFyTkdc5JQUfc5iXEeWxcOdsYTKSAiA/Age4NUOqKsRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/env-ci/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/env-ci/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", + "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data-encoder": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz", + "integrity": "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/formdata-node": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-6.0.3.tgz", + "integrity": "sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-timeout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", + "integrity": "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-log-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", + "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "0.6.8" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", + "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^7.0.1", + "byte-counter": "^0.1.0", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^13.0.12", + "decompress-response": "^10.0.0", + "form-data-encoder": "^4.0.2", + "http2-wrapper": "^2.2.1", + "keyv": "^5.5.3", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^4.0.1", + "responselike": "^4.0.2", + "type-fest": "^4.26.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/hook-std": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-4.0.0.tgz", + "integrity": "sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz", + "integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz", + "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10 <11 || >=12 <13 || >=14" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from-esm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-2.0.0.tgz", + "integrity": "sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": ">=18.20" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/irregular-plurals": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/issue-parser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.2.tgz", + "integrity": "sha512-7atWPjhGEIX3JEtMrOYd8TKzboYlq+5sNbdl9POiLYOI14G5HZiQbZP0Xj5EZdrufQVXfJlpTV0hys0CuxwxZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json-with-bigint": { + "version": "3.5.8", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.8.tgz", + "integrity": "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", + "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-asynchronous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/make-asynchronous/-/make-asynchronous-1.1.0.tgz", + "integrity": "sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-event": "^6.0.0", + "type-fest": "^4.6.0", + "web-worker": "^1.5.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/marked-terminal": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz", + "integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "ansi-regex": "^6.1.0", + "chalk": "^5.4.1", + "cli-highlight": "^2.1.11", + "cli-table3": "^0.6.5", + "node-emoji": "^2.2.0", + "supports-hyperlinks": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <16" + } + }, + "node_modules/matcher": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", + "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "dev": true, + "license": "MIT", + "dependencies": { + "blueimp-md5": "^2.10.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/memoize": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/memoize/-/memoize-10.2.0.tgz", + "integrity": "sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/memoize?sponsor=1" + } + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "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.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/nock": { + "version": "14.0.15", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.15.tgz", + "integrity": "sha512-S0a47C9pLvcYx/Ugf0H30BVBEcUgMMBDk9VJIDlJ8XGrfH2QDUD4Tgdp45qDIiHttokBG+IbsOtsvIjGR/j3bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mswjs/interceptors": "^0.41.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">=18.20.0 <20 || >=20.12.1" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-emoji/node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.19" + } + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/normalize-package-data": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", + "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^9.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm": { + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.17.0.tgz", + "integrity": "sha512-PurxiZexEHDTE4SSaLI3ZrnbAGiZfeyUcQcxcP5D+hfytNAze/D1IzDuInTn9XVLIbAQUnQuSPXJx02LHjLvQw==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/metavuln-calculator", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which" + ], + "dev": true, + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^9.8.0", + "@npmcli/config": "^10.11.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/map-workspaces": "^5.0.3", + "@npmcli/metavuln-calculator": "^9.0.3", + "@npmcli/package-json": "^7.0.5", + "@npmcli/promise-spawn": "^9.0.1", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.4", + "@sigstore/tuf": "^4.0.2", + "abbrev": "^4.0.0", + "archy": "~1.0.0", + "cacache": "^20.0.4", + "chalk": "^5.6.2", + "ci-info": "^4.4.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^9.0.3", + "ini": "^6.0.0", + "init-package-json": "^8.2.5", + "is-cidr": "^6.0.4", + "json-parse-even-better-errors": "^5.0.0", + "libnpmaccess": "^10.0.3", + "libnpmdiff": "^8.1.10", + "libnpmexec": "^10.3.0", + "libnpmfund": "^7.0.24", + "libnpmorg": "^8.0.1", + "libnpmpack": "^9.1.10", + "libnpmpublish": "^11.2.0", + "libnpmsearch": "^9.0.1", + "libnpmteam": "^8.0.2", + "libnpmversion": "^8.0.4", + "make-fetch-happen": "^15.0.6", + "minimatch": "^10.2.5", + "minipass": "^7.1.3", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^12.4.0", + "nopt": "^9.0.0", + "npm-audit-report": "^7.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.2", + "npm-pick-manifest": "^11.0.3", + "npm-profile": "^12.0.1", + "npm-registry-fetch": "^19.1.1", + "npm-user-validate": "^4.0.0", + "p-map": "^7.0.4", + "pacote": "^21.5.1", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.1.0", + "qrcode-terminal": "^0.12.0", + "read": "^5.0.1", + "semver": "^7.8.4", + "spdx-expression-parse": "^4.0.0", + "ssri": "^13.0.1", + "supports-color": "^10.2.2", + "tar": "^7.5.16", + "text-table": "~0.2.0", + "tiny-relative-date": "^2.0.2", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^7.0.2", + "which": "^6.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@gar/promise-retry": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "9.8.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/metavuln-calculator": "^9.0.2", + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/query": "^5.0.0", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.0", + "bin-links": "^6.0.0", + "cacache": "^20.0.1", + "common-ancestor-path": "^2.0.0", + "hosted-git-info": "^9.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^9.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.0", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "pacote": "^21.0.2", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.0.0", + "proggy": "^4.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "semver": "^7.3.7", + "ssri": "^13.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^4.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "10.11.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "ini": "^6.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "glob": "^13.0.0", + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^20.0.0", + "json-parse-even-better-errors": "^5.0.0", + "pacote": "^21.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "7.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "10.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/core": { + "version": "3.2.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.5.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@gar/promise-retry": "^1.0.2", + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.4", + "proc-log": "^6.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.1", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "4.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/bin-links": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "proc-log": "^6.0.0", + "read-cmd-shim": "^6.0.0", + "write-file-atomic": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "5.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "20.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.6.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.4.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "5.0.5", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.4.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/diff": { + "version": "8.0.4", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.3", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "13.0.6", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.7.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "8.2.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "npm-package-arg": "^13.0.0", + "promzard": "^3.0.1", + "read": "^5.0.1", + "semver": "^7.7.2", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/ip-address": { + "version": "10.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^5.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/isexe": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "10.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "8.1.10", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.8.0", + "@npmcli/installed-package-contents": "^4.0.0", + "binary-extensions": "^3.0.0", + "diff": "^8.0.2", + "minimatch": "^10.0.3", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "tar": "^7.5.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "10.3.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/arborist": "^9.8.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "proc-log": "^6.0.0", + "read": "^5.0.1", + "semver": "^7.3.7", + "signal-exit": "^4.1.0", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "7.0.24", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.8.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "9.1.10", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.8.0", + "@npmcli/run-script": "^10.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "11.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7", + "sigstore": "^4.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "9.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "8.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "11.5.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "15.0.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^4.0.0", + "@npmcli/redact": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "10.2.5", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.1.3", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "5.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.6", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^7.1.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "12.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "undici": "^6.25.0", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "13.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "10.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "11.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "12.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "19.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "7.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "21.5.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^5.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "7.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "6.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^3.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.8.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.1", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.1", + "@sigstore/tuf": "^4.0.2", + "@sigstore/verify": "^3.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.8.9", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.23", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "13.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "10.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "7.5.16", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.17", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/undici": { + "version": "6.26.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/which": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-cancelable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/p-each-series": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", + "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-event": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-filter": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-4.1.0.tgz", + "integrity": "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^7.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/package-config": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/package-config/-/package-config-5.0.0.tgz", + "integrity": "sha512-GYTTew2slBcYdvRHqjhwaaydVMvn/qrGC323+nKclYioNSLTDUM/lGgtGTgyHVtYcozb+XkE8CNhwcraOmZ9Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "load-json-file": "^7.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module/node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-10.0.3.tgz", + "integrity": "sha512-RvldzLvNE0DtOO1loukZsYcHCzHVUnHe7GNyrKIkavp7fNWs5ueX3kUzY/hXS8uRqDWwtaRKDcAmLEVouPIxIw==", + "license": "MIT", + "dependencies": { + "parse-path": "^7.1.0" + }, + "engines": { + "node": ">=14.13.0" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/plur": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", + "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "irregular-plurals": "^3.3.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "license": "MIT" + }, + "node_modules/proxy-agent-negotiate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", + "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "kerberos": "^2.0.0" + }, + "peerDependenciesMeta": { + "kerberos": { + "optional": true + } + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/read-package-up": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-12.0.0.tgz", + "integrity": "sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.1", + "read-pkg": "^10.0.0", + "type-fest": "^5.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-package-up/node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-10.1.0.tgz", + "integrity": "sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.4", + "normalize-package-data": "^8.0.0", + "parse-json": "^8.3.0", + "type-fest": "^5.4.4", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz", + "integrity": "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^3.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/responselike": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz", + "integrity": "sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/semantic-release": { + "version": "25.0.5", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-25.0.5.tgz", + "integrity": "sha512-mn61SUJwtM8ThrWn2WmgLVpwVJeG/hPSupua1psdMoufmwRIPyvRLkRkL0JDXkP67OntlLWUYnBnfVc8EDO3/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/commit-analyzer": "^13.0.1", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^12.0.0", + "@semantic-release/npm": "^13.1.1", + "@semantic-release/release-notes-generator": "^14.1.0", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^9.0.0", + "debug": "^4.0.0", + "env-ci": "^11.0.0", + "execa": "^9.0.0", + "figures": "^6.0.0", + "find-versions": "^6.0.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^4.0.0", + "hosted-git-info": "^9.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "marked": "^15.0.0", + "marked-terminal": "^7.3.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-package-up": "^12.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "signale": "^1.2.1", + "yargs": "^18.0.0" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + } + }, + "node_modules/semantic-release/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/semantic-release/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/semantic-release/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/signale/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/signale/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/signale/node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sinon": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-22.0.0.tgz", + "integrity": "sha512-sq/6DpdXOrLyfbKlXLg/Usc7xu8YXPeLkOFZRvA3bNUSA2lhbrZ06yuXbH1fkzBPCbz9O10+7hznzUsjaYNm0Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^15.4.0", + "@sinonjs/samsam": "^10.0.2", + "diff": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", + "dev": true, + "license": "ISC", + "dependencies": { + "through2": "~2.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/super-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.1.0.tgz", + "integrity": "sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-timeout": "^1.0.1", + "make-asynchronous": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supertap": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", + "integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^5.0.0", + "js-yaml": "^3.14.1", + "serialize-error": "^7.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/supertap/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/supertap/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tar": { + "version": "7.5.16", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", + "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", + "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^13.0.6", + "minimatch": "^10.2.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/traverse": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.2.tgz", + "integrity": "sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/web-worker": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", + "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/well-known-symbols": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", + "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=6" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-6.0.0.tgz", + "integrity": "sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index 30ce12f0..f9224fbd 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,10 @@ "description": "semantic-release plugin to publish a GitLab release", "version": "0.0.0-development", "author": "Pierre Vanduynslager (https://twitter.com/@pvdlg_)", + "type": "module", "ava": { "files": [ "test/**/*.test.js" - ], - "helpers": [ - "test/helpers/**/*" ] }, "bugs": { @@ -19,32 +17,31 @@ "Gregor Martynus (https://twitter.com/gr2m)" ], "dependencies": { - "@semantic-release/error": "^2.2.0", - "aggregate-error": "^3.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", - "escape-string-regexp": "^2.0.0", - "form-data": "^3.0.0", - "fs-extra": "^8.0.0", - "globby": "^10.0.0", - "got": "^10.0.1", - "lodash": "^4.17.11", - "parse-path": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "formdata-node": "^6.0.3", + "fs-extra": "^11.0.0", + "globby": "^14.0.0", + "got": "^14.0.0", + "hpagent": "^1.0.0", + "lodash-es": "^4.17.21", + "parse-url": "^10.0.0", "url-join": "^4.0.0" }, "devDependencies": { - "ava": "^2.0.0", - "clear-module": "^4.0.0", - "codecov": "^3.0.0", - "nock": "^11.0.0", - "nyc": "^15.0.0", - "semantic-release": "^16.0.0", - "sinon": "^8.0.0", - "tempy": "^0.3.0", - "xo": "^0.25.2" + "ava": "6.4.1", + "c8": "11.0.0", + "nock": "14.0.15", + "prettier": "3.8.4", + "semantic-release": "25.0.5", + "sinon": "22.0.0", + "tempy": "1.0.1" }, "engines": { - "node": ">=10.13" + "node": ">=20.8.1" }, "files": [ "lib", @@ -61,10 +58,11 @@ ], "license": "MIT", "main": "index.js", - "nyc": { + "c8": { "include": [ "lib/**/*.js", - "index.js" + "index.js", + "cli.js" ], "reporter": [ "json", @@ -73,30 +71,30 @@ ], "all": true }, - "peerDependencies": { - "semantic-release": ">=15.8.0 <17.0.0" - }, "prettier": { "printWidth": 120, "trailingComma": "es5" }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + }, "publishConfig": { "access": "public", - "tag": "next" + "provenance": true }, "repository": { "type": "git", "url": "https://github.com/semantic-release/gitlab.git" }, "scripts": { - "codecov": "codecov -f coverage/coverage-final.json", - "lint": "xo", - "pretest": "npm run lint", + "lint": "prettier --check \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"{bin,lib,test}/*.js\"", + "lint:fix": "prettier --write \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"{bin,lib,test}/*.js\"", "semantic-release": "semantic-release", - "test": "nyc ava -v" + "test": "c8 ava --verbose" }, - "xo": { - "prettier": true, - "space": true + "renovate": { + "extends": [ + "github>semantic-release/.github:renovate-config" + ] } } diff --git a/test/fail.test.js b/test/fail.test.js new file mode 100644 index 00000000..59de52cb --- /dev/null +++ b/test/fail.test.js @@ -0,0 +1,363 @@ +import test from "ava"; +import nock from "nock"; +import { stub } from "sinon"; +import fail from "../lib/fail.js"; +import authenticate from "./helpers/mock-gitlab.js"; + +/* eslint camelcase: ["error", {properties: "never"}] */ + +test.beforeEach((t) => { + // Mock logger + t.context.log = stub(); + t.context.error = stub(); + t.context.logger = { log: t.context.log, error: t.context.error }; +}); + +test.afterEach.always(() => { + // Clear nock + nock.cleanAll(); +}); + +test.serial("Post new issue if none exists yet", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedFailTitle = encodeURIComponent("The automated release is failing 🚨"); + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/issues?state=opened&&search=${encodedFailTitle}`) + .reply(200, [ + { + id: 2, + iid: 2, + project_id: 1, + web_url: "https://gitlab.com/test_user/test_repo/issues/2", + title: "API should implemented authentication", + }, + ]) + .post(`/projects/${encodedProjectPath}/issues`, { + id: "test_user%2Ftest_repo", + description: `## :rotating_light: The automated release from the \`main\` branch failed. :rotating_light: + +I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again. + +You can find below the list of errors reported by **semantic-release**. Each one of them has to be resolved in order to automatically publish your package. I'm sure you can fix this 💪. + +Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it. + +Once all the errors are resolved, **semantic-release** will release your package the next time you push a commit to the \`main\` branch. You can also manually restart the failed CI job that runs **semantic-release**. + +If you are not sure how to resolve this, here are some links that can help you: +- [Usage documentation](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/README.md) +- [Frequently Asked Questions](https://github.com/semantic-release/semantic-release/blob/master/docs/support/FAQ.md) +- [Support channels](https://github.com/semantic-release/semantic-release#get-help) + +If those don't help, or if this issue is reporting something you think isn't right, you can always ask the humans behind **[semantic-release](https://github.com/semantic-release/semantic-release/issues/new)**. + +--- + +### An error occured + +Unfortunately this error doesn't have any additional information. + +--- + +Good luck with your project ✨ + +Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:`, + labels: "semantic-release", + title: "The automated release is failing 🚨", + }) + .reply(200, { id: 3, web_url: "https://gitlab.com/test_user/test_repo/-/issues/3" }); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); + t.deepEqual(t.context.log.args[0], [ + "Created issue #%d: %s.", + 3, + "https://gitlab.com/test_user/test_repo/-/issues/3", + ]); +}); + +test.serial("Post comments to existing issue", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedFailTitle = encodeURIComponent("The automated release is failing 🚨"); + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/issues?state=opened&search=${encodedFailTitle}`) + .reply(200, [ + { + id: 1, + iid: 1, + project_id: 1, + web_url: "https://gitlab.com/test_user%2Ftest_repo/issues/1", + title: "The automated release is failing 🚨", + }, + { + id: 2, + iid: 2, + project_id: 1, + web_url: "https://gitlab.com/test_user%2Ftest_repo/issues/2", + title: "API should implemented authentication", + }, + ]) + .post(`/projects/1/issues/1/notes`, { + body: `## :rotating_light: The automated release from the \`main\` branch failed. :rotating_light: + +I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again. + +You can find below the list of errors reported by **semantic-release**. Each one of them has to be resolved in order to automatically publish your package. I'm sure you can fix this 💪. + +Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it. + +Once all the errors are resolved, **semantic-release** will release your package the next time you push a commit to the \`main\` branch. You can also manually restart the failed CI job that runs **semantic-release**. + +If you are not sure how to resolve this, here are some links that can help you: +- [Usage documentation](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/README.md) +- [Frequently Asked Questions](https://github.com/semantic-release/semantic-release/blob/master/docs/support/FAQ.md) +- [Support channels](https://github.com/semantic-release/semantic-release#get-help) + +If those don't help, or if this issue is reporting something you think isn't right, you can always ask the humans behind **[semantic-release](https://github.com/semantic-release/semantic-release/issues/new)**. + +--- + +### An error occured + +Unfortunately this error doesn't have any additional information. + +--- + +Good luck with your project ✨ + +Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:`, + }) + .reply(200); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Post comments to existing issue with custom template", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { + failComment: `Error: Release for branch \${branch.name} failed with error: \${errors.map(error => error.message).join(';')}`, + failTitle: "Semantic Release Failure", + }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedFailTitle = encodeURIComponent("Semantic Release Failure"); + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/issues?state=opened&search=${encodedFailTitle}`) + .reply(200, [ + { + id: 1, + iid: 1, + project_id: 1, + web_url: "https://gitlab.com/test_user%2Ftest_repo/issues/1", + title: "Semantic Release Failure", + }, + { + id: 2, + iid: 2, + project_id: 1, + web_url: "https://gitlab.com/test_user%2Ftest_repo/issues/2", + title: "API should implemented authentication", + }, + ]) + .post(`/projects/1/issues/1/notes`, { + body: `Error: Release for branch main failed with error: An error occured`, + }) + .reply(200); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments when failTitle and failComment are both set to false", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { + failComment: false, + failTitle: false, + }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const gitlab = authenticate(env); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments when failTitle is set to false", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { + failComment: `Error: Release for branch \${branch.name} failed with error: \${errors.map(error => error.message).join(';')}`, + failTitle: false, + }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const gitlab = authenticate(env); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments when failComment is set to false", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { + failComment: false, + failTitle: "Semantic Release Failure", + }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const gitlab = authenticate(env); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments when failCommentCondition disables it", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { failCommentCondition: "<% return false; %>" }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedFailTitle = encodeURIComponent("The automated release is failing 🚨"); + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/issues?state=opened&&search=${encodedFailTitle}`) + .reply(200, [ + { + id: 2, + iid: 2, + project_id: 1, + web_url: "https://gitlab.com/test_user/test_repo/issues/2", + title: "API should implemented authentication", + }, + ]); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments on existing issues when failCommentCondition disables this", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { failCommentCondition: "<% return !issue; %>" }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedFailTitle = encodeURIComponent("The automated release is failing 🚨"); + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/issues?state=opened&&search=${encodedFailTitle}`) + .reply(200, [ + { + id: 1, + iid: 1, + project_id: 1, + web_url: "https://gitlab.com/test_user%2Ftest_repo/issues/1", + title: "The automated release is failing 🚨", + }, + { + id: 2, + iid: 2, + project_id: 1, + web_url: "https://gitlab.com/test_user%2Ftest_repo/issues/2", + title: "API should implemented authentication", + }, + ]); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); + +test.serial("Post new issue if none exists yet with disabled comment on existing issues", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { + failComment: `Error: Release for branch \${branch.name} failed with error: \${errors.map(error => error.message).join(';')}`, + failCommentCondition: "<% return !issue; %>", + }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedFailTitle = encodeURIComponent("The automated release is failing 🚨"); + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/issues?state=opened&&search=${encodedFailTitle}`) + .reply(200, [ + { + id: 2, + iid: 2, + project_id: 1, + web_url: "https://gitlab.com/test_user/test_repo/issues/2", + title: "API should implemented authentication", + }, + ]) + .post(`/projects/${encodedProjectPath}/issues`, { + id: "test_user%2Ftest_repo", + description: `Error: Release for branch main failed with error: An error occured`, + labels: "semantic-release", + title: "The automated release is failing 🚨", + }) + .reply(200, { id: 3, web_url: "https://gitlab.com/test_user/test_repo/-/issues/3" }); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); + t.deepEqual(t.context.log.args[0], [ + "Created issue #%d: %s.", + 3, + "https://gitlab.com/test_user/test_repo/-/issues/3", + ]); +}); + +test.serial("Does not post comments when failCommentCondition is set to false", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { failCommentCondition: false }; + const branch = { name: "main" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const errors = [{ message: "An error occured" }]; + const gitlab = authenticate(env); + + await fail(pluginConfig, { env, options, branch, errors, logger: t.context.logger }); + + t.true(gitlab.isDone()); +}); diff --git a/test/fixtures/versioned/upload_v1.0.0.txt b/test/fixtures/versioned/upload_v1.0.0.txt new file mode 100644 index 00000000..ea123bef --- /dev/null +++ b/test/fixtures/versioned/upload_v1.0.0.txt @@ -0,0 +1 @@ +Test file content for release with version in filename. \ No newline at end of file diff --git a/test/get-project-context.test.js b/test/get-project-context.test.js new file mode 100644 index 00000000..2ef3dfb4 --- /dev/null +++ b/test/get-project-context.test.js @@ -0,0 +1,147 @@ +import test from "ava"; +import getProjectContext from "../lib/get-project-context.js"; + +test("Parse project path with https URL", (t) => { + t.is( + getProjectContext({ env: {} }, "https://gitlab.com", "https://api.gitlab.com", "https://gitlab.com/owner/repo.git") + .projectPath, + "owner/repo" + ); + t.is( + getProjectContext({ env: {} }, "https://gitlab.com", "https://api.gitlab.com", "https://gitlab.com/owner/repo") + .projectPath, + "owner/repo" + ); +}); + +test("Parse project path with git URL", (t) => { + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com", + "https://api.gitlab.com", + "git+ssh://git@gitlab.com/owner/repo.git" + ).projectPath, + "owner/repo" + ); + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com", + "https://api.gitlab.com", + "git+ssh://git@gitlab.com/owner/repo" + ).projectPath, + "owner/repo" + ); +}); + +test("Parse project path with context in repo URL", (t) => { + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com/context", + "https://api.gitlab.com", + "https://gitlab.com/context/owner/repo.git" + ).projectPath, + "owner/repo" + ); + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com/context", + "https://api.gitlab.com", + "git+ssh://git@gitlab.com/context/owner/repo.git" + ).projectPath, + "owner/repo" + ); +}); + +test("Parse project path with context not in repo URL", (t) => { + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com/context", + "https://api.gitlab.com", + "https://gitlab.com/owner/repo.git" + ).projectPath, + "owner/repo" + ); + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com/context", + "https://api.gitlab.com", + "git+ssh://git@gitlab.com/owner/repo.git" + ).projectPath, + "owner/repo" + ); +}); + +test("Parse project path with organization and subgroup", (t) => { + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com/context", + "https://api.gitlab.com", + "https://gitlab.com/orga/subgroup/owner/repo.git" + ).projectPath, + "orga/subgroup/owner/repo" + ); + t.is( + getProjectContext( + { env: {} }, + "https://gitlab.com/context", + "https://api.gitlab.com", + "git+ssh://git@gitlab.com/orga/subgroup/owner/repo.git" + ).projectPath, + "orga/subgroup/owner/repo" + ); +}); + +test("Get project path from GitLab CI", (t) => { + t.is( + getProjectContext( + { envCi: { service: "gitlab" }, env: { CI_PROJECT_PATH: "other-owner/other-repo" } }, + "https://gitlab.com", + "https://api.gitlab.com", + "https://gitlab.com/owner/repo.git" + ).projectPath, + "other-owner/other-repo" + ); +}); + +test("Ignore CI_PROJECT_PATH if not on GitLab CI", (t) => { + t.is( + getProjectContext( + { envCi: { service: "travis" }, env: { CI_PROJECT_PATH: "other-owner/other-repo" } }, + "https://gitlab.com", + "https://api.gitlab.com", + "https://gitlab.com/owner/repo.git" + ).projectPath, + "owner/repo" + ); +}); + +test("Uses project API URL with project path", (t) => { + t.is( + getProjectContext( + { envCi: { service: "gitlab" }, env: { CI_PROJECT_PATH: "other-owner/other-repo" } }, + "https://gitlab.com", + "https://api.gitlab.com", + "https://gitlab.com/owner/repo.git" + ).projectApiUrl, + "https://api.gitlab.com/projects/other-owner%2Fother-repo" + ); +}); + +test("Uses project API URL with project ID", (t) => { + t.is( + getProjectContext( + { envCi: { service: "gitlab" }, env: { CI_PROJECT_ID: "42" } }, + "https://gitlab.com", + "https://api.gitlab.com", + "https://gitlab.com/owner/repo.git" + ).projectApiUrl, + "https://api.gitlab.com/projects/42" + ); +}); diff --git a/test/get-repo-id.test.js b/test/get-repo-id.test.js deleted file mode 100644 index 6f443918..00000000 --- a/test/get-repo-id.test.js +++ /dev/null @@ -1,58 +0,0 @@ -import test from 'ava'; -import getRepoId from '../lib/get-repo-id'; - -test('Parse repo id with https URL', t => { - t.is(getRepoId({env: {}}, 'https://gitlbab.com', 'https://gitlab.com/owner/repo.git'), 'owner/repo'); - t.is(getRepoId({env: {}}, 'https://gitlbab.com', 'https://gitlab.com/owner/repo'), 'owner/repo'); -}); - -test('Parse repo id with git URL', t => { - t.is(getRepoId({env: {}}, 'https://gitlab.com', 'git+ssh://git@gitlab.com/owner/repo.git'), 'owner/repo'); - t.is(getRepoId({env: {}}, 'https://gitlab.com', 'git+ssh://git@gitlab.com/owner/repo'), 'owner/repo'); -}); - -test('Parse repo id with context in repo URL', t => { - t.is(getRepoId({env: {}}, 'https://gitlbab.com/context', 'https://gitlab.com/context/owner/repo.git'), 'owner/repo'); - t.is( - getRepoId({env: {}}, 'https://gitlab.com/context', 'git+ssh://git@gitlab.com/context/owner/repo.git'), - 'owner/repo' - ); -}); - -test('Parse repo id with context not in repo URL', t => { - t.is(getRepoId({env: {}}, 'https://gitlbab.com/context', 'https://gitlab.com/owner/repo.git'), 'owner/repo'); - t.is(getRepoId({env: {}}, 'https://gitlab.com/context', 'git+ssh://git@gitlab.com/owner/repo.git'), 'owner/repo'); -}); - -test('Parse repo id with organization and subgroup', t => { - t.is( - getRepoId({env: {}}, 'https://gitlbab.com/context', 'https://gitlab.com/orga/subgroup/owner/repo.git'), - 'orga/subgroup/owner/repo' - ); - t.is( - getRepoId({env: {}}, 'https://gitlab.com/context', 'git+ssh://git@gitlab.com/orga/subgroup/owner/repo.git'), - 'orga/subgroup/owner/repo' - ); -}); - -test('Get repo id from GitLab CI', t => { - t.is( - getRepoId( - {envCi: {service: 'gitlab'}, env: {CI_PROJECT_PATH: 'other-owner/other-repo'}}, - 'https://gitlbab.com', - 'https://gitlab.com/owner/repo.git' - ), - 'other-owner/other-repo' - ); -}); - -test('Ignore CI_PROJECT_PATH if not on GitLab CI', t => { - t.is( - getRepoId( - {envCi: {service: 'travis'}, env: {CI_PROJECT_PATH: 'other-owner/other-repo'}}, - 'https://gitlbab.com', - 'https://gitlab.com/owner/repo.git' - ), - 'owner/repo' - ); -}); diff --git a/test/glob-assets.test.js b/test/glob-assets.test.js index 3ac9a4f4..885ab27a 100644 --- a/test/glob-assets.test.js +++ b/test/glob-assets.test.js @@ -1,199 +1,213 @@ -import path from 'path'; -import test from 'ava'; -import {copy, ensureDir} from 'fs-extra'; -import {isPlainObject, sortBy} from 'lodash'; -import tempy from 'tempy'; -import globAssets from '../lib/glob-assets'; +import path from "path"; +import test from "ava"; +import { copy, ensureDir } from "fs-extra"; +import { isPlainObject, sortBy } from "lodash-es"; +import tempy from "tempy"; +import globAssets from "../lib/glob-assets.js"; -const sortAssets = assets => sortBy(assets, asset => (isPlainObject(asset) ? asset.path : asset)); +const sortAssets = (assets) => sortBy(assets, (asset) => (isPlainObject(asset) ? asset.path : asset)); -const fixtures = 'test/fixtures/files'; +const fixtures = "test/fixtures/files"; -test('Retrieve file from single path', async t => { +test("Retrieve file from single path", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['upload.txt']); + const globbedAssets = await globAssets({ cwd }, ["upload.txt"]); - t.deepEqual(globbedAssets, ['upload.txt']); + t.deepEqual(globbedAssets, ["upload.txt"]); }); -test('Retrieve multiple files from path', async t => { +test("Retrieve multiple files from path", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['upload.txt', 'upload_other.txt']); + const globbedAssets = await globAssets({ cwd }, ["upload.txt", "upload_other.txt"]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt'])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["upload_other.txt", "upload.txt"])); }); -test('Include missing files as defined, using Object definition', async t => { +test("Include missing files as defined, using Object definition", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['upload.txt', {path: 'miss*.txt', label: 'Missing'}]); + const globbedAssets = await globAssets({ cwd }, ["upload.txt", { path: "miss*.txt", label: "Missing" }]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload.txt', {path: 'miss*.txt', label: 'Missing'}])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["upload.txt", { path: "miss*.txt", label: "Missing" }])); }); -test('Retrieve multiple files from Object', async t => { +test("Retrieve multiple files from Object", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [ - {path: 'upload.txt', name: 'upload_name', label: 'Upload label'}, - 'upload_other.txt', + const globbedAssets = await globAssets({ cwd }, [ + { path: "upload.txt", name: "upload_name", label: "Upload label" }, + "upload_other.txt", ]); t.deepEqual( sortAssets(globbedAssets), - sortAssets([{path: 'upload.txt', name: 'upload_name', label: 'Upload label'}, 'upload_other.txt']) + sortAssets([{ path: "upload.txt", name: "upload_name", label: "Upload label" }, "upload_other.txt"]) ); }); -test('Retrieve multiple files without duplicates', async t => { +test("Retrieve multiple files without duplicates", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [ - 'upload_other.txt', - 'upload.txt', - 'upload_other.txt', - 'upload.txt', - 'upload.txt', - 'upload_other.txt', + const globbedAssets = await globAssets({ cwd }, [ + "upload_other.txt", + "upload.txt", + "upload_other.txt", + "upload.txt", + "upload.txt", + "upload_other.txt", ]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt'])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["upload_other.txt", "upload.txt"])); }); -test('Favor Object over String values when removing duplicates', async t => { +test("Favor Object over String values when removing duplicates", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [ - 'upload_other.txt', - 'upload.txt', - {path: 'upload.txt', name: 'upload_name'}, - 'upload.txt', - {path: 'upload_other.txt', name: 'upload_other_name'}, - 'upload.txt', - 'upload_other.txt', + const globbedAssets = await globAssets({ cwd }, [ + "upload_other.txt", + "upload.txt", + { path: "upload.txt", name: "upload_name" }, + "upload.txt", + { path: "upload_other.txt", name: "upload_other_name", filepath: "/path/to/other" }, + "upload.txt", + "upload_other.txt", ]); t.deepEqual( sortAssets(globbedAssets), sortAssets([ - {path: 'upload.txt', name: 'upload_name'}, - {path: 'upload_other.txt', name: 'upload_other_name'}, + { path: "upload.txt", name: "upload_name" }, + { path: "upload_other.txt", name: "upload_other_name", filepath: "/path/to/other" }, ]) ); }); -test('Retrieve file from single glob', async t => { +test("Retrieve file from single glob", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['upload.*']); + const globbedAssets = await globAssets({ cwd }, ["upload.*"]); - t.deepEqual(globbedAssets, ['upload.txt']); + t.deepEqual(globbedAssets, ["upload.txt"]); }); -test('Retrieve multiple files from single glob', async t => { +test("Retrieve multiple files from single glob", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['*.txt']); + const globbedAssets = await globAssets({ cwd }, ["*.txt"]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt'])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["upload_other.txt", "upload.txt"])); }); -test('Accept glob array with one value', async t => { +test("Accept glob array with one value", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [['*load.txt'], ['*_other.txt']]); + const globbedAssets = await globAssets({ cwd }, [["*load.txt"], ["*_other.txt"]]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt'])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["upload_other.txt", "upload.txt"])); }); -test('Include globs that resolve to no files as defined', async t => { +test("Include globs that resolve to no files as defined", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [['upload.txt', '!upload.txt']]); + const globbedAssets = await globAssets({ cwd }, [["upload.txt", "!upload.txt"]]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['!upload.txt', 'upload.txt'])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["!upload.txt", "upload.txt"])); }); -test('Accept glob array with one value for missing files', async t => { +test("Accept glob array with one value for missing files", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [['*missing.txt'], ['*_other.txt']]); + const globbedAssets = await globAssets({ cwd }, [["*missing.txt"], ["*_other.txt"]]); - t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', '*missing.txt'])); + t.deepEqual(sortAssets(globbedAssets), sortAssets(["upload_other.txt", "*missing.txt"])); }); -test('Replace name by filename for Object that match multiple files', async t => { +test("Replace name by filename for Object that match multiple files", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [{path: '*.txt', name: 'upload_name', label: 'Upload label'}]); + const globbedAssets = await globAssets({ cwd }, [{ path: "*.txt", label: "Upload label" }]); t.deepEqual( sortAssets(globbedAssets), sortAssets([ - {path: 'upload.txt', name: 'upload.txt', label: 'Upload label'}, - {path: 'upload_other.txt', name: 'upload_other.txt', label: 'Upload label'}, + { path: "upload.txt", label: "upload.txt" }, + { path: "upload_other.txt", label: "upload_other.txt" }, ]) ); }); -test('Include dotfiles', async t => { +test("Ignore filepath for Object that match multiple files", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['.dot*']); + const globbedAssets = await globAssets({ cwd }, [{ path: "*.txt", filepath: "/path/to/file" }]); - t.deepEqual(globbedAssets, ['.dotfile']); + t.deepEqual( + sortAssets(globbedAssets), + sortAssets([ + { path: "upload.txt", label: "upload.txt" }, + { path: "upload_other.txt", label: "upload_other.txt" }, + ]) + ); +}); + +test("Include dotfiles", async (t) => { + const cwd = tempy.directory(); + await copy(fixtures, cwd); + const globbedAssets = await globAssets({ cwd }, [".dot*"]); + + t.deepEqual(globbedAssets, [".dotfile"]); }); -test('Ingnore single negated glob', async t => { +test("Ingnore single negated glob", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['!*.txt']); + const globbedAssets = await globAssets({ cwd }, ["!*.txt"]); t.deepEqual(globbedAssets, []); }); -test('Ingnore single negated glob in Object', async t => { +test("Ingnore single negated glob in Object", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [{path: '!*.txt'}]); + const globbedAssets = await globAssets({ cwd }, [{ path: "!*.txt" }]); t.deepEqual(globbedAssets, []); }); -test('Accept negated globs', async t => { +test("Accept negated globs", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, [['*.txt', '!**/*_other.txt']]); + const globbedAssets = await globAssets({ cwd }, [["*.txt", "!**/*_other.txt"]]); - t.deepEqual(globbedAssets, ['upload.txt']); + t.deepEqual(globbedAssets, ["upload.txt"]); }); -test('Expand directories', async t => { +test("Expand directories", async (t) => { const cwd = tempy.directory(); - await copy(fixtures, path.resolve(cwd, 'dir')); - const globbedAssets = await globAssets({cwd}, [['dir']]); + await copy(fixtures, path.resolve(cwd, "dir")); + const globbedAssets = await globAssets({ cwd }, [["dir"]]); t.deepEqual( sortAssets(globbedAssets), - sortAssets(['dir', 'dir/upload_other.txt', 'dir/upload.txt', 'dir/.dotfile', 'dir/file.css']) + sortAssets(["dir", "dir/upload_other.txt", "dir/upload.txt", "dir/.dotfile", "dir/file.css"]) ); }); -test('Include empty directory as defined', async t => { +test("Include empty directory as defined", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - await ensureDir(path.resolve(cwd, 'empty')); - const globbedAssets = await globAssets({cwd}, [['empty']]); + await ensureDir(path.resolve(cwd, "empty")); + const globbedAssets = await globAssets({ cwd }, [["empty"]]); - t.deepEqual(globbedAssets, ['empty']); + t.deepEqual(globbedAssets, ["empty"]); }); -test('Deduplicate resulting files path', async t => { +test("Deduplicate resulting files path", async (t) => { const cwd = tempy.directory(); await copy(fixtures, cwd); - const globbedAssets = await globAssets({cwd}, ['./upload.txt', path.resolve(cwd, 'upload.txt'), 'upload.txt']); + const globbedAssets = await globAssets({ cwd }, ["./upload.txt", path.resolve(cwd, "upload.txt"), "upload.txt"]); t.is(globbedAssets.length, 1); }); diff --git a/test/helpers/mock-gitlab.js b/test/helpers/mock-gitlab.js index deda5008..fbf41327 100644 --- a/test/helpers/mock-gitlab.js +++ b/test/helpers/mock-gitlab.js @@ -10,9 +10,10 @@ import urlJoin from 'url-join'; * @param {String} [gitlabApiPathPrefix=env.GL_PREFIX || env.GITLAB_PREFIX || ''] The GitHub Enterprise API prefix. * @return {Object} A `nock` object ready to respond to a github authentication request. */ -export default function authenticate( +export default function ( env = {}, { + useJobToken = false, gitlabToken = env.GL_TOKEN || env.GITLAB_TOKEN || 'GL_TOKEN', gitlabUrl = env.GL_URL || env.GITLAB_URL || 'https://gitlab.com', gitlabApiPathPrefix = typeof env.GL_PREFIX === 'string' @@ -22,5 +23,8 @@ export default function authenticate( : null || '/api/v4', } = {} ) { - return nock(urlJoin(gitlabUrl, gitlabApiPathPrefix), {reqheaders: {'Private-Token': gitlabToken}}); + const tokenHeader = useJobToken ? "JOB-TOKEN" : "Private-Token"; + const token = useJobToken ? env.CI_JOB_TOKEN : gitlabToken; + + return nock(urlJoin(gitlabUrl, gitlabApiPathPrefix), { reqheaders: { [tokenHeader]: token } }); } diff --git a/test/integration.test.js b/test/integration.test.js index bfa554ef..4b8863f3 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1,19 +1,16 @@ -import test from 'ava'; -import nock from 'nock'; -import {stub} from 'sinon'; -import clearModule from 'clear-module'; -import authenticate from './helpers/mock-gitlab'; +import test from "ava"; +import nock from "nock"; +import { stub } from "sinon"; +import authenticate from "./helpers/mock-gitlab.js"; /* eslint camelcase: ["error", {properties: "never"}] */ -test.beforeEach(t => { - // Clear npm cache to refresh the module state - clearModule('..'); - t.context.m = require('..'); +test.beforeEach(async (t) => { + t.context.m = await import(`../index.js?update=${Date.now()}`); // Stub the logger t.context.log = stub(); t.context.error = stub(); - t.context.logger = {log: t.context.log, error: t.context.error}; + t.context.logger = { log: t.context.log, error: t.context.error }; }); test.afterEach.always(() => { @@ -21,86 +18,128 @@ test.afterEach.always(() => { nock.cleanAll(); }); -test.serial('Verify GitLab auth', async t => { - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const owner = 'test_user'; - const repo = 'test_repo'; - const options = {repositoryUrl: `git+https://othertesturl.com/${owner}/${repo}.git`}; +test.serial("Verify GitLab auth", async (t) => { + const env = { GITLAB_TOKEN: "gitlab_token" }; + const owner = "test_user"; + const repo = "test_repo"; + const options = { repositoryUrl: `git+https://othertesturl.com/${owner}/${repo}.git` }; const github = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 30}}}); + .reply(200, { permissions: { project_access: { access_level: 30 } } }); - await t.notThrowsAsync(t.context.m.verifyConditions({}, {env, options, logger: t.context.logger})); + await t.notThrowsAsync(t.context.m.verifyConditions({}, { env, options, logger: t.context.logger })); t.true(github.isDone()); }); -test.serial('Throw SemanticReleaseError if invalid config', async t => { +test.serial("Throw SemanticReleaseError if invalid config", async (t) => { const env = {}; const options = { - publish: [{path: '@semantic-release/npm'}, {path: '@semantic-release/gitlab'}], - repositoryUrl: 'git+ssh://git@gitlab.com/context.git', + publish: [{ path: "@semantic-release/npm" }, { path: "@semantic-release/gitlab" }], + repositoryUrl: "git+ssh://git@gitlab.com/context.git", }; const errors = [ - ...(await t.throwsAsync( - t.context.m.verifyConditions({gitlabUrl: 'https://gitlab.com/context'}, {env, options, logger: t.context.logger}) - )), + ...( + await t.throwsAsync( + t.context.m.verifyConditions( + { gitlabUrl: "https://gitlab.com/context" }, + { env, options, logger: t.context.logger } + ) + ) + ).errors, ]; - t.is(errors[0].name, 'SemanticReleaseError'); - t.is(errors[0].code, 'EINVALIDGITLABURL'); - t.is(errors[1].name, 'SemanticReleaseError'); - t.is(errors[1].code, 'ENOGLTOKEN'); + t.is(errors[0].name, "SemanticReleaseError"); + t.is(errors[0].code, "EINVALIDGITLABURL"); + t.is(errors[1].name, "SemanticReleaseError"); + t.is(errors[1].code, "ENOGLTOKEN"); }); -test.serial('Publish a release', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const nextRelease = {gitHead: '123', gitTag: 'v1.0.0', notes: 'Test release note body'}; - const options = {branch: 'master', repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}; - const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); +test.serial("Publish a release", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { branch: "master", repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); const gitlab = authenticate(env) - .get(`/projects/${encodedRepoId}`) - .reply(200, {permissions: {project_access: {access_level: 30}}}) - .post(`/projects/${encodedRepoId}/repository/tags/${nextRelease.gitTag}/release`, { + .get(`/projects/${encodedProjectPath}`) + .reply(200, { permissions: { project_access: { access_level: 30 } } }) + .post(`/projects/${encodedProjectPath}/releases`, { tag_name: nextRelease.gitTag, description: nextRelease.notes, + assets: { + links: [], + }, }) .reply(200); - const result = await t.context.m.publish({}, {env, nextRelease, options, logger: t.context.logger}); + const result = await t.context.m.publish({}, { env, nextRelease, options, logger: t.context.logger }); - t.is(result.url, `https://gitlab.com/${encodedRepoId}/tags/${nextRelease.gitTag}`); - t.deepEqual(t.context.log.args[0], ['Verify GitLab authentication (%s)', 'https://gitlab.com/api/v4']); - t.deepEqual(t.context.log.args[1], ['Published GitLab release: %s', nextRelease.gitTag]); + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${nextRelease.gitTag}`); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://gitlab.com/api/v4"]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); t.true(gitlab.isDone()); }); -test.serial('Verify Github auth and release', async t => { - const env = {GL_TOKEN: 'gitlab_token'}; - const owner = 'test_user'; - const repo = 'test_repo'; - const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`}; - const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); - const nextRelease = {gitHead: '123', gitTag: 'v1.0.0', notes: 'Test release note body'}; +test.serial("Verify Github auth and release", async (t) => { + const env = { GL_TOKEN: "gitlab_token" }; + const owner = "test_user"; + const repo = "test_repo"; + const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; const gitlab = authenticate(env) - .get(`/projects/${encodedRepoId}`) - .reply(200, {permissions: {project_access: {access_level: 30}}}) - .post(`/projects/${encodedRepoId}/repository/tags/${nextRelease.gitTag}/release`, { + .get(`/projects/${encodedProjectPath}`) + .reply(200, { permissions: { project_access: { access_level: 30 } } }) + .post(`/projects/${encodedProjectPath}/releases`, { tag_name: nextRelease.gitTag, description: nextRelease.notes, + assets: { + links: [], + }, }) .reply(200); - await t.notThrowsAsync(t.context.m.verifyConditions({}, {env, options, logger: t.context.logger})); - const result = await t.context.m.publish({}, {env, options, nextRelease, logger: t.context.logger}); + await t.notThrowsAsync(t.context.m.verifyConditions({}, { env, options, logger: t.context.logger })); + const result = await t.context.m.publish({}, { env, options, nextRelease, logger: t.context.logger }); - t.is(result.url, `https://gitlab.com/${encodedRepoId}/tags/${nextRelease.gitTag}`); - t.deepEqual(t.context.log.args[0], ['Verify GitLab authentication (%s)', 'https://gitlab.com/api/v4']); - t.deepEqual(t.context.log.args[1], ['Published GitLab release: %s', nextRelease.gitTag]); + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${nextRelease.gitTag}`); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://gitlab.com/api/v4"]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Verify GitLab auth and release with Job Token", async (t) => { + const env = { CI_JOB_TOKEN: "job_token" }; + const owner = "test_user"; + const repo = "test_repo"; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const pluginConfig = { useJobToken: true }; + + const gitlab = authenticate(env, { useJobToken: true }) + .get(`/projects/${encodedProjectPath}/releases`) + .reply(200) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + }) + .reply(200, {}); + + await t.notThrowsAsync(t.context.m.verifyConditions(pluginConfig, { env, options, logger: t.context.logger })); + const result = await t.context.m.publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${nextRelease.gitTag}`); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://gitlab.com/api/v4"]); + t.deepEqual(t.context.log.args[1], ["Using Job Token for authentication. Some functionality may be disabled."]); + t.deepEqual(t.context.log.args[2], ["Published GitLab release: %s", nextRelease.gitTag]); t.true(gitlab.isDone()); }); diff --git a/test/publish.test.js b/test/publish.test.js index 18d355fe..d12443a9 100644 --- a/test/publish.test.js +++ b/test/publish.test.js @@ -1,17 +1,17 @@ -import test from 'ava'; -import nock from 'nock'; -import tempy from 'tempy'; -import {stub} from 'sinon'; -import publish from '../lib/publish'; -import authenticate from './helpers/mock-gitlab'; +import test from "ava"; +import nock from "nock"; +import tempy from "tempy"; +import { stub } from "sinon"; +import publish from "../lib/publish.js"; +import authenticate from "./helpers/mock-gitlab.js"; /* eslint camelcase: ["error", {properties: "never"}] */ -test.beforeEach(t => { +test.beforeEach((t) => { // Mock logger t.context.log = stub(); t.context.error = stub(); - t.context.logger = {log: t.context.log, error: t.context.error}; + t.context.logger = { log: t.context.log, error: t.context.error }; }); test.afterEach.always(() => { @@ -19,124 +19,852 @@ test.afterEach.always(() => { nock.cleanAll(); }); -test.serial('Publish a release', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; +test.serial("Publish a release", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; const pluginConfig = {}; - const nextRelease = {gitHead: '123', gitTag: '@scope/v1.0.0', notes: 'Test release note body'}; - const options = {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}; - const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); const encodedGitTag = encodeURIComponent(nextRelease.gitTag); const gitlab = authenticate(env) - .post(`/projects/${encodedRepoId}/repository/tags/${encodedGitTag}/release`, { + .post(`/projects/${encodedProjectPath}/releases`, { tag_name: nextRelease.gitTag, description: nextRelease.notes, + assets: { + links: [], + }, }) .reply(200); - const result = await publish(pluginConfig, {env, options, nextRelease, logger: t.context.logger}); + const result = await publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger }); - t.is(result.url, `https://gitlab.com/${encodedRepoId}/tags/${encodedGitTag}`); - t.deepEqual(t.context.log.args[0], ['Published GitLab release: %s', nextRelease.gitTag]); + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Published GitLab release: %s", nextRelease.gitTag]); t.true(gitlab.isDone()); }); -test.serial('Publish a release with assets', async t => { - const cwd = 'test/fixtures/files'; - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const nextRelease = {gitHead: '123', gitTag: '@scope/v1.0.0', notes: 'Test release note body'}; - const options = {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}; - const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); +test.serial("Publish a release with templated path", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token", FIXTURE: "upload" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); const encodedGitTag = encodeURIComponent(nextRelease.gitTag); - const uploaded = {url: '/uploads/file.css', alt: 'file.css'}; - const assets = [['**', '!**/*.txt', '!.dotfile']]; + const generic = { path: "${env.FIXTURE}.txt", filepath: "/upload.txt" }; + const assets = [generic]; + const uploaded = { + url: "/https/github.com/uploads/upload.txt", + alt: "upload.txt", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/upload.txt", + }; const gitlab = authenticate(env) - .post(`/projects/${encodedRepoId}/repository/tags/${encodedGitTag}/release`, { + .post(`/projects/${encodedProjectPath}/releases`, { tag_name: nextRelease.gitTag, description: nextRelease.notes, + assets: { + links: [ + { + name: "upload.txt", + url: `https://gitlab.com${uploaded.full_path}`, + filepath: "/upload.txt", + }, + ], + }, }) .reply(200); const gitlabUpload = authenticate(env) - .post(`/projects/${encodedRepoId}/uploads`, /filename="file.css"/gm) + .post(`/projects/${encodedProjectPath}/uploads`, /Content-Disposition/g) .reply(200, uploaded); - const gitlabAssetLink = authenticate(env) - .post(`/projects/${encodedRepoId}/releases/${encodedGitTag}/assets/links`, { - url: `https://gitlab.com/${owner}/${repo}${uploaded.url}`, - name: uploaded.alt, + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with assets", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const uploaded = { + url: "/https/github.com/uploads/file.css", + alt: "file.css", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/file.css", + }; + const assets = [["**", "!**/*.txt", "!.dotfile"]]; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: uploaded.alt, + url: `https://gitlab.com${uploaded.full_path}`, + }, + ], + }, }) - .reply(200, {}); + .reply(200); + const gitlabUpload = authenticate(env) + .post(`/projects/${encodedProjectPath}/uploads`, /filename="file.css"/gm) + .reply(200, uploaded); - const result = await publish({assets}, {env, cwd, options, nextRelease, logger: t.context.logger}); + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); - t.is(result.url, `https://gitlab.com/${encodedRepoId}/tags/${encodedGitTag}`); - t.deepEqual(t.context.log.args[0], ['Uploaded file: %s', uploaded.url]); - t.deepEqual(t.context.log.args[1], ['Published GitLab release: %s', nextRelease.gitTag]); + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); t.true(gitlabUpload.isDone()); t.true(gitlab.isDone()); - t.true(gitlabAssetLink.isDone()); }); -test.serial('Publish a release with array of missing assets', async t => { - const cwd = 'test/fixtures/files'; - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const nextRelease = {gitHead: '123', gitTag: '@scope/v1.0.0', notes: 'Test release note body'}; - const options = {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}; - const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); +test.serial("Publish a release with generics", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); const encodedGitTag = encodeURIComponent(nextRelease.gitTag); - const emptyDirectory = tempy.directory(); - const assets = [emptyDirectory, {path: 'missing.txt', label: 'missing.txt'}]; + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "/https/github.com/uploads/file.css" } }; + const generic = { path: "file.css", label: "Style package", target: "generic_package", status: "hidden" }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.label); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "Style package", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with generics: with asset.packageName (fixed text)", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "/https/github.com/uploads/file.css" } }; + const generic = { + path: "file.css", + label: "Style package", + target: "generic_package", + status: "hidden", + packageName: "microk8s", + }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.label); + const encodedPackageName = encodeURIComponent(generic.packageName); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/${encodedPackageName}/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "Style package", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/${encodedPackageName}/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with generics: with asset.packageName (template)", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { + gitHead: "123", + gitTag: "v1.0.0-alpha.1", + notes: "Test release note body", + version: "1.0.0-alpha.1", + channel: "alpha", + }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "/https/github.com/uploads/file.css" } }; + const generic = { + path: "file.css", + label: "Style package", + target: "generic_package", + status: "hidden", + packageName: "${nextRelease.channel}", + }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.label); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/alpha/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "Style package", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/alpha/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with generics (without label - issue #823)", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "/https/github.com/uploads/file.css" } }; + const generic = { path: "file.css", target: "generic_package", status: "hidden" }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.path); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "file.css", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with generics and external storage provider (http)", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "http://aws.example.com/bucket/gitlab/file.css" } }; + const generic = { path: "file.css", label: "Style package", target: "generic_package", status: "hidden" }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.label); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "Style package", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with generics and external storage provider (https)", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "https://aws.example.com/bucket/gitlab/file.css" } }; + const generic = { path: "file.css", label: "Style package", target: "generic_package", status: "hidden" }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.label); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "Style package", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with generics and external storage provider (ftp)", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const encodedVersion = encodeURIComponent(nextRelease.version); + const uploaded = { file: { url: "ftp://drive.example.com/gitlab/file.css" } }; + const generic = { path: "file.css", label: "Style package", target: "generic_package", status: "hidden" }; + const assets = [generic]; + const encodedLabel = encodeURIComponent(generic.label); + const expectedUrl = `https://gitlab.com/api/v4/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}`; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "Style package", + url: expectedUrl, + link_type: "package", + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .put( + `/projects/${encodedProjectPath}/packages/generic/release/${encodedVersion}/${encodedLabel}?status=${generic.status}&select=package_file`, + /\.test\s\{\}/gm + ) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s (%s)", expectedUrl, uploaded.file.url]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with asset type and permalink", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const uploaded = { + url: "/https/github.com/uploads/file.css", + alt: "file.css", + link_type: "package", + filepath: "/dist/file.css", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/file.css", + }; + const assets = [ + { + path: ["**", "!**/*.txt", "!.dotfile"], + type: "package", + filepath: "/dist/file.css", + }, + ]; const gitlab = authenticate(env) - .post(`/projects/${encodedRepoId}/repository/tags/${encodedGitTag}/release`, { + .post(`/projects/${encodedProjectPath}/releases`, { tag_name: nextRelease.gitTag, description: nextRelease.notes, + assets: { + links: [ + { + name: uploaded.alt, + url: `https://gitlab.com${uploaded.full_path}`, + link_type: uploaded.link_type, + filepath: uploaded.filepath, + }, + ], + }, }) .reply(200); - const result = await publish({assets}, {env, cwd, options, nextRelease, logger: t.context.logger}); + const gitlabUpload = authenticate(env) + .post(`/projects/${encodedProjectPath}/uploads`, /filename="file.css"/gm) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); - t.is(result.url, `https://gitlab.com/${encodedRepoId}/tags/${encodedGitTag}`); - t.deepEqual(t.context.log.args[0], ['Published GitLab release: %s', nextRelease.gitTag]); + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); t.true(gitlab.isDone()); }); -test.serial('Publish a release with one asset and custom label', async t => { - const cwd = 'test/fixtures/files'; - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const nextRelease = {gitHead: '123', gitTag: '@scope/v1.0.0', notes: 'Test release note body'}; - const options = {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}; - const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); +test.serial("Publish a release with an asset with a template label", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); const encodedGitTag = encodeURIComponent(nextRelease.gitTag); - const uploaded = {url: '/uploads/upload.txt'}; - const assetLabel = 'Custom Label'; - const assets = [{path: 'upload.txt', label: assetLabel}]; + const uploaded = { + url: "/https/github.com/uploads/file.css", + alt: "file.css", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/file.css", + }; + const assets = [ + { + label: `file-v\${nextRelease.version}.css`, + path: "file.css", + type: "other", + filepath: "/dist/file.css", + }, + ]; const gitlab = authenticate(env) - .post(`/projects/${encodedRepoId}/repository/tags/${encodedGitTag}/release`, { + .post(`/projects/${encodedProjectPath}/releases`, { tag_name: nextRelease.gitTag, description: nextRelease.notes, + assets: { + links: [ + { + name: "file-v1.0.0.css", + url: `https://gitlab.com${uploaded.full_path}`, + link_type: "other", + filepath: "/dist/file.css", + }, + ], + }, }) .reply(200); const gitlabUpload = authenticate(env) - .post(`/projects/${encodedRepoId}/uploads`, /filename="upload.txt"/gm) + .post(`/projects/${encodedProjectPath}/uploads`, /filename="file.css"/gm) .reply(200, uploaded); - const gitlabAssetLink = authenticate(env) - .post(`/projects/${encodedRepoId}/releases/${encodedGitTag}/assets/links`, { - url: `https://gitlab.com/${owner}/${repo}${uploaded.url}`, - name: assetLabel, + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release (with an link) with variables", async (t) => { + process.env.TYPE = "other"; + process.env.FILEPATH = "/dist/file.css"; + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const uploaded = { + url: "/https/github.com/uploads/file.css", + alt: "file.css", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/file.css", + }; + const assets = [ + { + label: `README-v\${nextRelease.version}.md`, + type: `\${process.env.TYPE}`, + url: `https://gitlab.com/gitlab-org/gitlab/-/blob/master/README-v\${nextRelease.version}.md`, + }, + { + label: "file.css", + path: "file.css", + type: "other", + filepath: `\${process.env.FILEPATH}`, + }, + ]; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "README-v1.0.0.md", + url: "https://gitlab.com/gitlab-org/gitlab/-/blob/master/README-v1.0.0.md", + link_type: "other", + }, + { + name: "file.css", + url: `https://gitlab.com${uploaded.full_path}`, + link_type: "other", + filepath: "/dist/file.css", + }, + ], + }, }) - .reply(200, {}); + .reply(200); - const result = await publish({assets}, {env, cwd, options, nextRelease, logger: t.context.logger}); + const gitlabUpload = authenticate(env) + .post(`/projects/${encodedProjectPath}/uploads`, /filename="file.css"/gm) + .reply(200, uploaded); + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); - t.is(result.url, `https://gitlab.com/${encodedRepoId}/tags/${encodedGitTag}`); - t.deepEqual(t.context.log.args[0], ['Uploaded file: %s', uploaded.url]); - t.deepEqual(t.context.log.args[1], ['Published GitLab release: %s', nextRelease.gitTag]); + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); t.true(gitlabUpload.isDone()); t.true(gitlab.isDone()); - t.true(gitlabAssetLink.isDone()); + + delete process.env.TYPE; + delete process.env.FILEPATH; +}); + +test.serial("Publish a release with a milestone", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { milestones: ["1.2.3"] }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + milestones: ["1.2.3"], + }) + .reply(200); + + const result = await publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with array of missing assets", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const emptyDirectory = tempy.directory(); + const assets = [emptyDirectory, { path: "missing.txt", label: "missing.txt" }]; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + }) + .reply(200); + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with one asset and custom label", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const uploaded = { + url: "/https/github.com/uploads/upload.txt", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/upload.txt", + }; + const assetLabel = "Custom Label"; + const assets = [{ path: "upload.txt", label: assetLabel }]; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: assetLabel, + url: `https://gitlab.com${uploaded.full_path}`, + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .post(`/projects/${encodedProjectPath}/uploads`, /filename="upload.txt"/gm) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlabUpload.isDone()); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with missing release notes", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.gitTag, + assets: { + links: [], + }, + }) + .reply(200); + + const result = await publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with an asset link", async (t) => { + const cwd = "test/fixtures/files"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const link = { + label: "README.md", + type: "other", + url: "https://gitlab.com/gitlab-org/gitlab/-/blob/master/README.md", + }; + const assets = [link]; + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "README.md", + url: `https://gitlab.com/gitlab-org/gitlab/-/blob/master/README.md`, + link_type: "other", + }, + ], + }, + }) + .reply(200); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with error response", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + }) + .reply(499, { message: "Something went wrong" }); + + const error = await t.throwsAsync(publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger })); + t.is(error.message, `Response code 499 (Something went wrong)`); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release with templated wildcard path", async (t) => { + const cwd = "test/fixtures"; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body", version: "1.0.0" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const encodedGitTag = encodeURIComponent(nextRelease.gitTag); + + const assets = ["versioned/upload_v${nextRelease.version}.txt"]; + + const uploaded = { + url: "/https/github.com/uploads/upload_v1.0.0.txt", + alt: "upload_v1.0.0.txt", + full_path: "/-/project/4/66dbcd21ec5d24ed6ea225176098d52b/upload_v1.0.0.txt", + }; + + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [ + { + name: "upload_v1.0.0.txt", + url: `https://gitlab.com${uploaded.full_path}`, + }, + ], + }, + }) + .reply(200); + const gitlabUpload = authenticate(env) + .post(`/projects/${encodedProjectPath}/uploads`, /Content-Disposition.*upload_v1\.0\.0\.txt/g) + .reply(200, uploaded); + + const result = await publish({ assets }, { env, cwd, options, nextRelease, logger: t.context.logger }); + + t.is(result.url, `https://gitlab.com/${owner}/${repo}/-/releases/${encodedGitTag}`); + t.deepEqual(t.context.log.args[0], ["Uploaded file: %s", `https://gitlab.com${uploaded.full_path}`]); + t.deepEqual(t.context.log.args[1], ["Published GitLab release: %s", nextRelease.gitTag]); + t.true(gitlab.isDone()); + t.true(gitlabUpload.isDone()); }); diff --git a/test/resolve-config.test.js b/test/resolve-config.test.js index 4a3201af..931cf677 100644 --- a/test/resolve-config.test.js +++ b/test/resolve-config.test.js @@ -1,127 +1,442 @@ -import test from 'ava'; -import urlJoin from 'url-join'; -import resolveConfig from '../lib/resolve-config'; +import test from "ava"; +import urlJoin from "url-join"; +import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"; +import resolveConfig from "../lib/resolve-config.js"; -test('Returns user config', t => { - const gitlabToken = 'TOKEN'; - const gitlabUrl = 'https://host.com'; - const gitlabApiPathPrefix = '/api/prefix'; - const assets = ['file.js']; +const defaultOptions = { + gitlabToken: undefined, + gitlabUrl: "https://gitlab.com", + gitlabApiUrl: urlJoin("https://gitlab.com", "/api/v4"), + assets: undefined, + milestones: undefined, + successComment: undefined, + successCommentCondition: undefined, + failTitle: "The automated release is failing 🚨", + failComment: undefined, + failCommentCondition: undefined, + labels: "semantic-release", + assignee: undefined, + tokenHeader: "PRIVATE-TOKEN", + useJobToken: undefined, + proxy: {}, + retryLimit: 3, + retryStatusCodes: [408, 413, 422, 429, 500, 502, 503, 504, 521, 522, 524], +}; - t.deepEqual(resolveConfig({gitlabUrl, gitlabApiPathPrefix, assets}, {env: {GITLAB_TOKEN: gitlabToken}}), { - gitlabToken, - gitlabUrl, - gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), - assets, - }); +test("Returns user config", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + const postComments = true; + const proxy = {}; + const labels = false; + const retryLimit = 42; + + t.deepEqual( + resolveConfig( + { gitlabUrl, gitlabApiPathPrefix, assets, postComments, labels, retryLimit }, + { env: { GITLAB_TOKEN: gitlabToken } } + ), + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + assets, + labels: false, + retryLimit, + } + ); + + t.deepEqual( + resolveConfig({ gitlabUrl, gitlabApiPathPrefix, assets, proxy }, { env: { GITLAB_TOKEN: gitlabToken } }), + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + assets, + proxy, + } + ); }); -test('Returns user config via environment variables', t => { - const gitlabToken = 'TOKEN'; - const gitlabUrl = 'https://host.com'; - const gitlabApiPathPrefix = '/api/prefix'; - const assets = ['file.js']; +test("Returns user config via environment variables", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + const milestones = ["1.2.3"]; t.deepEqual( resolveConfig( - {assets}, - {env: {GITLAB_TOKEN: gitlabToken, GITLAB_URL: gitlabUrl, GITLAB_PREFIX: gitlabApiPathPrefix}} + { assets, milestones }, + { env: { GITLAB_TOKEN: gitlabToken, GITLAB_URL: gitlabUrl, GITLAB_PREFIX: gitlabApiPathPrefix } } ), - {gitlabToken, gitlabUrl, gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), assets} + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + assets, + milestones, + } + ); +}); + +test("Returns user config via alternative environment variables", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + + t.deepEqual( + resolveConfig({ assets }, { env: { GL_TOKEN: gitlabToken, GL_URL: gitlabUrl, GL_PREFIX: gitlabApiPathPrefix } }), + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + assets, + milestones: undefined, + successComment: undefined, + } ); }); -test('Returns user config via alternative environment variables', t => { - const gitlabToken = 'TOKEN'; - const gitlabUrl = 'https://host.com'; - const gitlabApiPathPrefix = '/api/prefix'; - const assets = ['file.js']; +test("Returns user config via alternative environment variables with https proxy and no proto scheme set", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol + const proxyUrl = "http://proxy.test:8443"; + + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTPS_PROXY: proxyUrl, + }, + } + ); + + t.deepEqual(result.proxy, {}); +}); + +test("Returns user config via alternative environment variables with http proxy and no proto scheme set", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol + const proxyUrl = "http://proxy.test:8080"; + + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTP_PROXY: proxyUrl, + }, + } + ); + + t.deepEqual(result.proxy, {}); +}); + +test("Returns user config via alternative environment variables with http proxy", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "http://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol + const proxyUrl = "http://proxy.test:8080"; + + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTP_PROXY: proxyUrl, + }, + } + ); + + t.assert(result.proxy.agent.http instanceof HttpProxyAgent); + t.assert(result.proxy.agent.http.proxy.origin === proxyUrl); +}); + +test("Returns user config via alternative environment variables with https proxy", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8443 port because HttpsProxyAgent ignores 443 port with https protocol + const proxyUrl = "http://proxy.test:8443"; + + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTPS_PROXY: proxyUrl, + }, + } + ); + + t.assert(result.proxy.agent.https instanceof HttpsProxyAgent); + t.assert(result.proxy.agent.https.proxy.origin === proxyUrl); +}); + +test("Returns user config via alternative environment variables with mismatching http/https values for proxy gitlab url", (t) => { + const gitlabToken = "TOKEN"; + const httpGitlabUrl = "http://host.com"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8443 port because HttpsProxyAgent ignores 443 port with https protocol + + // HTTP GitLab URL and HTTPS_PROXY set + t.deepEqual( + resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: httpGitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTPS_PROXY: "https://proxy.test:8443", + }, + } + ), + { + ...defaultOptions, + gitlabToken: "TOKEN", + gitlabUrl: "http://host.com", + gitlabApiUrl: "http://host.com/api/prefix", + assets: ["file.js"], + } + ); + // HTTPS GitLab URL and HTTP_PROXY set t.deepEqual( - resolveConfig({assets}, {env: {GL_TOKEN: gitlabToken, GL_URL: gitlabUrl, GL_PREFIX: gitlabApiPathPrefix}}), - {gitlabToken, gitlabUrl, gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), assets} + resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTP_PROXY: "http://proxy.test:8443", + }, + } + ), + { + ...defaultOptions, + gitlabToken: "TOKEN", + gitlabUrl: "https://host.com", + gitlabApiUrl: "https://host.com/api/prefix", + assets: ["file.js"], + } ); }); +test("Returns user config via environment variables with HTTP_PROXY and NO_PROXY set", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "http://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol + const proxyUrl = "http://proxy.test:8080"; -test('Returns default config', t => { - const gitlabToken = 'TOKEN'; - const gitlabApiPathPrefix = '/api/prefix'; - const gitlabUrl = 'https://gitlab.com'; + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTP_PROXY: proxyUrl, + NO_PROXY: "*.host.com, host.com", + }, + } + ); + + t.deepEqual(result.proxy, {}); +}); + +test("Returns user config via environment variables with HTTPS_PROXY and NO_PROXY set", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol + const proxyUrl = "http://proxy.test:8080"; + + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTPS_PROXY: proxyUrl, + NO_PROXY: "*.host.com, host.com", + }, + } + ); + t.deepEqual(result.proxy, {}); +}); + +test("Returns user config via environment variables with HTTPS_PROXY and non-matching NO_PROXY set", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8443 port because HttpsProxyAgent ignores 443 port with http protocol + const proxyUrl = "https://proxy.test:8443"; + process.env.HTTPS_PROXY = proxyUrl; + process.env.NO_PROXY = "*.differenthost.com, differenthost.com"; - t.deepEqual(resolveConfig({}, {env: {GL_TOKEN: gitlabToken}}), { + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTPS_PROXY: proxyUrl, + NO_PROXY: "*.differenthost.com, differenthost.com", + }, + } + ); + t.assert(result.proxy.agent.https instanceof HttpsProxyAgent); +}); + +test("Returns user config via environment variables with HTTP_PROXY and non-matching NO_PROXY set", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "http://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol + const proxyUrl = "http://proxy.test:8080"; + + const result = resolveConfig( + { assets }, + { + env: { + GL_TOKEN: gitlabToken, + GL_URL: gitlabUrl, + GL_PREFIX: gitlabApiPathPrefix, + HTTP_PROXY: proxyUrl, + NO_PROXY: "*.differenthost.com, differenthost.com", + }, + } + ); + t.assert(result.proxy.agent.http instanceof HttpProxyAgent); +}); + +test("Returns default config", (t) => { + const gitlabToken = "TOKEN"; + const gitlabApiPathPrefix = "/api/prefix"; + const gitlabUrl = "https://gitlab.com"; + + t.deepEqual(resolveConfig({}, { env: { GL_TOKEN: gitlabToken } }), { + ...defaultOptions, gitlabToken, - gitlabUrl: 'https://gitlab.com', - gitlabApiUrl: urlJoin('https://gitlab.com', '/api/v4'), - assets: undefined, }); - t.deepEqual(resolveConfig({gitlabApiPathPrefix}, {env: {GL_TOKEN: gitlabToken}}), { + t.deepEqual(resolveConfig({ gitlabApiPathPrefix }, { env: { GL_TOKEN: gitlabToken } }), { + ...defaultOptions, gitlabToken, - gitlabUrl: 'https://gitlab.com', - gitlabApiUrl: urlJoin('https://gitlab.com', gitlabApiPathPrefix), - assets: undefined, + gitlabApiUrl: urlJoin("https://gitlab.com", gitlabApiPathPrefix), }); - t.deepEqual(resolveConfig({gitlabUrl}, {env: {GL_TOKEN: gitlabToken}}), { + t.deepEqual(resolveConfig({ gitlabUrl }, { env: { GL_TOKEN: gitlabToken } }), { + ...defaultOptions, gitlabToken, - gitlabUrl: 'https://gitlab.com', - gitlabApiUrl: urlJoin(gitlabUrl, '/api/v4'), - assets: undefined, + gitlabUrl: "https://gitlab.com", + gitlabApiUrl: urlJoin(gitlabUrl, "/api/v4"), }); }); -test('Returns default config via GitLab CI/CD environment variables', t => { - const gitlabToken = 'TOKEN'; - const CI_PROJECT_URL = 'http://ci-host.com/ci-owner/ci-repo'; - const CI_PROJECT_PATH = 'ci-owner/ci-repo'; - const CI_API_V4_URL = 'http://ci-host-api.com/prefix'; +test("Returns default config via GitLab CI/CD environment variables", (t) => { + const gitlabToken = "TOKEN"; + const CI_PROJECT_URL = "http://ci-host.com/ci-owner/ci-repo"; + const CI_PROJECT_PATH = "ci-owner/ci-repo"; + const CI_API_V4_URL = "http://ci-host-api.com/prefix"; t.deepEqual( resolveConfig( {}, { - envCi: {service: 'gitlab'}, - env: {GL_TOKEN: gitlabToken, CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL}, + envCi: { service: "gitlab" }, + env: { GL_TOKEN: gitlabToken, CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL }, } ), - {gitlabToken, gitlabUrl: 'http://ci-host.com', gitlabApiUrl: CI_API_V4_URL, assets: undefined} + { + ...defaultOptions, + gitlabToken, + gitlabUrl: "http://ci-host.com", + gitlabApiUrl: CI_API_V4_URL, + } ); }); -test('Returns user config over GitLab CI/CD environment variables', t => { - const gitlabToken = 'TOKEN'; - const gitlabUrl = 'https://host.com'; - const gitlabApiPathPrefix = '/api/prefix'; - const assets = ['file.js']; - const CI_PROJECT_URL = 'http://ci-host.com/ci-owner/ci-repo'; - const CI_PROJECT_PATH = 'ci-owner/ci-repo'; - const CI_API_V4_URL = 'http://ci-host-api.com/prefix'; +test("Returns user config over GitLab CI/CD environment variables", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const assets = ["file.js"]; + const failTitle = "The automated release unfortunately failed!"; + const labels = "bot,release-failed"; + const CI_PROJECT_URL = "http://ci-host.com/ci-owner/ci-repo"; + const CI_PROJECT_PATH = "ci-owner/ci-repo"; + const CI_API_V4_URL = "http://ci-host-api.com/prefix"; t.deepEqual( resolveConfig( - {gitlabUrl, gitlabApiPathPrefix, assets}, + { gitlabUrl, gitlabApiPathPrefix, assets, failTitle, labels }, { - envCi: {service: 'gitlab'}, - env: {GL_TOKEN: gitlabToken, CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL}, + envCi: { service: "gitlab" }, + env: { GL_TOKEN: gitlabToken, CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL }, } ), - {gitlabToken, gitlabUrl, gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), assets} + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + assets, + failTitle: "The automated release unfortunately failed!", + labels: "bot,release-failed", + } ); }); -test('Returns user config via environment variables over GitLab CI/CD environment variables', t => { - const gitlabToken = 'TOKEN'; - const gitlabUrl = 'https://host.com'; - const gitlabApiPathPrefix = '/api/prefix'; - const CI_PROJECT_URL = 'http://ci-host.com/ci-owner/ci-repo'; - const CI_PROJECT_PATH = 'ci-owner/ci-repo'; - const CI_API_V4_URL = 'http://ci-host-api.com/prefix'; +test("Returns user config via environment variables over GitLab CI/CD environment variables", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const CI_PROJECT_URL = "http://ci-host.com/ci-owner/ci-repo"; + const CI_PROJECT_PATH = "ci-owner/ci-repo"; + const CI_API_V4_URL = "http://ci-host-api.com/prefix"; t.deepEqual( resolveConfig( {}, { - envCi: {service: 'gitlab'}, + envCi: { service: "gitlab" }, env: { GITLAB_TOKEN: gitlabToken, GITLAB_URL: gitlabUrl, @@ -132,23 +447,28 @@ test('Returns user config via environment variables over GitLab CI/CD environmen }, } ), - {gitlabToken, gitlabUrl, gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), assets: undefined} + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + } ); }); -test('Returns user config via alternative environment variables over GitLab CI/CD environment variables', t => { - const gitlabToken = 'TOKEN'; - const gitlabUrl = 'https://host.com'; - const gitlabApiPathPrefix = '/api/prefix'; - const CI_PROJECT_URL = 'http://ci-host.com/ci-owner/ci-repo'; - const CI_PROJECT_PATH = 'ci-owner/ci-repo'; - const CI_API_V4_URL = 'http://ci-host-api.com/prefix'; +test("Returns user config via alternative environment variables over GitLab CI/CD environment variables", (t) => { + const gitlabToken = "TOKEN"; + const gitlabUrl = "https://host.com"; + const gitlabApiPathPrefix = "/api/prefix"; + const CI_PROJECT_URL = "http://ci-host.com/ci-owner/ci-repo"; + const CI_PROJECT_PATH = "ci-owner/ci-repo"; + const CI_API_V4_URL = "http://ci-host-api.com/prefix"; t.deepEqual( resolveConfig( {}, { - envCi: {service: 'gitlab'}, + envCi: { service: "gitlab" }, env: { GL_TOKEN: gitlabToken, GL_URL: gitlabUrl, @@ -159,29 +479,56 @@ test('Returns user config via alternative environment variables over GitLab CI/C }, } ), - {gitlabToken, gitlabUrl, gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), assets: undefined} + { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + } ); }); -test('Ignore GitLab CI/CD environment variables if not running on GitLab CI/CD', t => { - const gitlabToken = 'TOKEN'; - const CI_PROJECT_URL = 'http://ci-host.com/owner/repo'; - const CI_PROJECT_PATH = 'ci-owner/ci-repo'; - const CI_API_V4_URL = 'http://ci-host-api.com/prefix'; +test("Ignore GitLab CI/CD environment variables if not running on GitLab CI/CD", (t) => { + const gitlabToken = "TOKEN"; + const CI_PROJECT_URL = "http://ci-host.com/owner/repo"; + const CI_PROJECT_PATH = "ci-owner/ci-repo"; + const CI_API_V4_URL = "http://ci-host-api.com/prefix"; t.deepEqual( resolveConfig( {}, { - envCi: {service: 'travis'}, - env: {GL_TOKEN: gitlabToken, CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL}, + envCi: { service: "travis" }, + env: { GL_TOKEN: gitlabToken, CI_PROJECT_URL, CI_PROJECT_PATH, CI_API_V4_URL }, } ), { + ...defaultOptions, gitlabToken, - gitlabUrl: 'https://gitlab.com', - gitlabApiUrl: urlJoin('https://gitlab.com', '/api/v4'), - assets: undefined, + gitlabUrl: "https://gitlab.com", + gitlabApiUrl: urlJoin("https://gitlab.com", "/api/v4"), + } + ); +}); + +test("Set token header to JOB-TOKEN when useJobToken is set to true", (t) => { + const jobToken = "TOKEN"; + + t.deepEqual( + resolveConfig( + { useJobToken: true }, + { + envCi: { service: "gitlab" }, + env: { CI_JOB_TOKEN: jobToken }, + } + ), + { + ...defaultOptions, + gitlabToken: jobToken, + useJobToken: true, + tokenHeader: "JOB-TOKEN", + successCommentCondition: false, + failCommentCondition: false, } ); }); diff --git a/test/success.test.js b/test/success.test.js new file mode 100644 index 00000000..5394b87a --- /dev/null +++ b/test/success.test.js @@ -0,0 +1,334 @@ +import test from "ava"; +import nock from "nock"; +import { stub } from "sinon"; +import success from "../lib/success.js"; +import authenticate from "./helpers/mock-gitlab.js"; +import { RELEASE_NAME } from "../lib/definitions/constants.js"; + +/* eslint camelcase: ["error", {properties: "never"}] */ + +test.beforeEach((t) => { + // Mock logger + t.context.log = stub(); + t.context.error = stub(); + t.context.logger = { log: t.context.log, error: t.context.error }; +}); + +test.afterEach.always(() => { + // Clear nock + nock.cleanAll(); +}); + +test.serial("Post comments to related issues and MRs", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [ + { project_id: 100, iid: 1, state: "merged" }, + { project_id: 200, iid: 2, state: "closed" }, + { project_id: 300, iid: 3, state: "merged" }, + ]) + .get(`/projects/${encodedProjectPath}/repository/commits/fedcba/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, [ + { project_id: 100, iid: 11, state: "closed" }, + { project_id: 100, iid: 12, state: "open" }, + { project_id: 100, iid: 13, state: "closed" }, + ]) + .get(`/projects/300/merge_requests/3/closes_issues`) + .reply(200, []) + .post(`/projects/100/merge_requests/1/notes`, { + body: ":tada: This MR is included in version 1.0.0 :tada:\n\nThe release is available on [GitLab release](https://gitlab.com/test_user/test_repo/-/releases/v1.0.0).\n\nYour **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:", + }) + .reply(200) + .post(`/projects/300/merge_requests/3/notes`) + .reply(200) + .post(`/projects/100/issues/11/notes`, { + body: ":tada: This issue has been resolved in version 1.0.0 :tada:\n\nThe release is available on [GitLab release](https://gitlab.com/test_user/test_repo/-/releases/v1.0.0).\n\nYour **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:", + }) + .reply(200) + .post(`/projects/100/issues/13/notes`) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Post comments with custom template", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { + successComment: `nextRelease: \${nextRelease.version} commits: \${commits.length} releases: \${releases.length} \${issue ? "issue" : "MR"} ID: \${issue ? issue.iid : mergeRequest.iid}`, + }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, [{ project_id: 100, iid: 11, state: "closed" }]) + .post(`/projects/100/merge_requests/1/notes`, { + body: "nextRelease: 1.0.0 commits: 1 releases: 1 MR ID: 1", + }) + .reply(200) + .post(`/projects/100/issues/11/notes`, { + body: "nextRelease: 1.0.0 commits: 1 releases: 1 issue ID: 11", + }) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Post comments for multiple releases", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const nextRelease = { version: "1.0.0" }; + const releases = [ + { name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }, + { name: "Other release" }, + ]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, []) + .post(`/projects/100/merge_requests/1/notes`, { + body: ":tada: This MR is included in version 1.0.0 :tada:\n\nThe release is available on:\n- [GitLab release](https://gitlab.com/test_user/test_repo/-/releases/v1.0.0)\n- `Other release`\n\nYour **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:", + }) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments when successComment is set to false", async (t) => { + const pluginConfig = { successComment: false }; + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments when successCommentCondition disables it", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { successCommentCondition: "<% return false; %>" }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [ + { project_id: 100, iid: 1, state: "merged" }, + { project_id: 200, iid: 2, state: "closed" }, + { project_id: 300, iid: 3, state: "merged" }, + ]) + .get(`/projects/${encodedProjectPath}/repository/commits/fedcba/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, [ + { project_id: 100, iid: 11, state: "closed" }, + { project_id: 100, iid: 12, state: "open" }, + { project_id: 100, iid: 13, state: "closed" }, + ]) + .get(`/projects/300/merge_requests/3/closes_issues`) + .reply(200, []); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Does not post comments on issues when successCommentCondition disables issue commenting", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { successCommentCondition: "<% return !issue; %>" }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [ + { project_id: 100, iid: 1, state: "merged" }, + { project_id: 200, iid: 2, state: "closed" }, + { project_id: 300, iid: 3, state: "merged" }, + ]) + .get(`/projects/${encodedProjectPath}/repository/commits/fedcba/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, [ + { project_id: 100, iid: 11, state: "closed" }, + { project_id: 100, iid: 12, state: "open" }, + { project_id: 100, iid: 13, state: "closed" }, + ]) + .get(`/projects/300/merge_requests/3/closes_issues`) + .reply(200, []) + .post(`/projects/100/merge_requests/1/notes`, { + body: ":tada: This MR is included in version 1.0.0 :tada:\n\nThe release is available on [GitLab release](https://gitlab.com/test_user/test_repo/-/releases/v1.0.0).\n\nYour **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:", + }) + .reply(200) + .post(`/projects/300/merge_requests/3/notes`) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Only posts comments on issues which are found using the successCommentCondition", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { successCommentCondition: "<% return issue.labels?.includes('semantic-release-relevant'); %>" }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [ + { project_id: 100, iid: 1, state: "merged" }, + { project_id: 200, iid: 2, state: "closed" }, + { project_id: 300, iid: 3, state: "merged" }, + ]) + .get(`/projects/${encodedProjectPath}/repository/commits/fedcba/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, [ + { project_id: 100, iid: 11, labels: "doing,bug", state: "closed" }, + { project_id: 100, iid: 12, labels: "todo,feature", state: "open" }, + { project_id: 100, iid: 13, labels: "testing,semantic-release-relevant,critical", state: "closed" }, + ]) + .get(`/projects/300/merge_requests/3/closes_issues`) + .reply(200, []) + .post(`/projects/100/issues/13/notes`, { + body: ":tada: This issue has been resolved in version 1.0.0 :tada:\n\nThe release is available on [GitLab release](https://gitlab.com/test_user/test_repo/-/releases/v1.0.0).\n\nYour **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:", + }) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial( + "Does not post comments on merge requets when successCommentCondition disables merge request commenting", + async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { successCommentCondition: "<% return !mergeRequest; %>" }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [ + { project_id: 100, iid: 1, state: "merged" }, + { project_id: 200, iid: 2, state: "closed" }, + { project_id: 300, iid: 3, state: "merged" }, + ]) + .get(`/projects/${encodedProjectPath}/repository/commits/fedcba/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, [ + { project_id: 100, iid: 11, state: "closed" }, + { project_id: 100, iid: 12, state: "open" }, + { project_id: 100, iid: 13, state: "closed" }, + ]) + .get(`/projects/300/merge_requests/3/closes_issues`) + .reply(200, []) + .post(`/projects/100/issues/11/notes`, { + body: ":tada: This issue has been resolved in version 1.0.0 :tada:\n\nThe release is available on [GitLab release](https://gitlab.com/test_user/test_repo/-/releases/v1.0.0).\n\nYour **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package: :rocket:", + }) + .reply(200) + .post(`/projects/100/issues/13/notes`) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); + } +); + +test.serial("Does not post comments when successCommentCondition is set to false", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { successCommentCondition: false }; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const commits = [{ hash: "abcdef" }, { hash: "fedcba" }]; + const gitlab = authenticate(env); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases }); + + t.true(gitlab.isDone()); +}); + +test.serial("Retries requests when rate limited", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const nextRelease = { version: "1.0.0" }; + const releases = [{ name: RELEASE_NAME, url: "https://gitlab.com/test_user/test_repo/-/releases/v1.0.0" }]; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const commits = [{ hash: "abcdef" }]; + const retryLimit = 3; + const gitlab = authenticate(env) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .times(retryLimit) + .reply(429) + .get(`/projects/${encodedProjectPath}/repository/commits/abcdef/merge_requests`) + .reply(200, [{ project_id: 100, iid: 1, state: "merged" }]) + .get(`/projects/100/merge_requests/1/closes_issues`) + .reply(200, []) + .post(`/projects/100/merge_requests/1/notes`) + .reply(200); + + await success(pluginConfig, { env, options, nextRelease, logger: t.context.logger, commits, releases, retryLimit }); + + t.true(gitlab.isDone()); +}); diff --git a/test/verify.test.js b/test/verify.test.js index 5b784905..b0b1f3b9 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -1,16 +1,16 @@ -import test from 'ava'; -import nock from 'nock'; -import {stub} from 'sinon'; -import verify from '../lib/verify'; -import authenticate from './helpers/mock-gitlab'; +import test from "ava"; +import nock from "nock"; +import { stub } from "sinon"; +import verify from "../lib/verify.js"; +import authenticate from "./helpers/mock-gitlab.js"; /* eslint camelcase: ["error", {properties: "never"}] */ -test.beforeEach(t => { +test.beforeEach((t) => { // Mock logger t.context.log = stub(); t.context.error = stub(); - t.context.logger = {log: t.context.log, error: t.context.error}; + t.context.logger = { log: t.context.log, error: t.context.error }; }); test.afterEach.always(() => { @@ -18,504 +18,1011 @@ test.afterEach.always(() => { nock.cleanAll(); }); -test.serial('Verify token and repository access (project_access 30)', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; +test.serial("Verify token and repository access (project_access 30)", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 30}}}); + .reply(200, { permissions: { project_access: { access_level: 30 } } }); await t.notThrowsAsync( - verify({}, {env, options: {repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git`}, logger: t.context.logger}) + verify( + {}, + { env, options: { repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.true(gitlab.isDone()); }); -test.serial('Verify token and repository access (project_access 40)', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; +test.serial("Verify token and repository access (project_access 40)", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( - verify({}, {env, options: {repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git`}, logger: t.context.logger}) + verify( + {}, + { env, options: { repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.true(gitlab.isDone()); }); -test.serial('Verify token and repository access (group_access 30)', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; +test.serial("Verify token and repository access (group_access 30)", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 10}, group_access: {access_level: 30}}}); + .reply(200, { permissions: { project_access: { access_level: 10 }, group_access: { access_level: 30 } } }); await t.notThrowsAsync( - verify({}, {env, options: {repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git`}, logger: t.context.logger}) + verify( + {}, + { env, options: { repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.true(gitlab.isDone()); }); -test.serial('Verify token and repository access (group_access 40)', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; +test.serial("Verify token and repository access (group_access 40)", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 10}, group_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 10 }, group_access: { access_level: 40 } } }); await t.notThrowsAsync( - verify({}, {env, options: {repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git`}, logger: t.context.logger}) + verify( + {}, + { env, options: { repositoryUrl: `git+https://gitalb.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.true(gitlab.isDone()); }); -test.serial('Verify token and repository access and custom URL with prefix', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const gitlabUrl = 'https://othertesturl.com:9090'; - const gitlabApiPathPrefix = 'prefix'; - const gitlab = authenticate(env, {gitlabUrl, gitlabApiPathPrefix}) +test.serial("Verify CI_JOB_TOKEN and repository access", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { CI_JOB_TOKEN: "job_token" }; + const gitlab = authenticate(env, { useJobToken: true }).get(`/projects/${owner}%2F${repo}/releases`).reply(200); + + await t.notThrowsAsync( + verify( + { useJobToken: true }, + { env, options: { repositoryUrl: `git+https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.true(gitlab.isDone()); + t.deepEqual(t.context.log.args[1], ["Using Job Token for authentication. Some functionality may be disabled."]); +}); + +test.serial("Throw SemanticReleaseError for invalid CI_JOB_TOKEN", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { CI_JOB_TOKEN: "job_token" }; + const gitlab = authenticate(env, { useJobToken: true }).get(`/projects/${owner}%2F${repo}/releases`).reply(401); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { useJobToken: true }, + { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDGLTOKEN"); + t.true(gitlab.isDone()); +}); + +test.serial("Verify token and repository access and custom URL with prefix", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlabUrl = "https://othertesturl.com:9090"; + const gitlabApiPathPrefix = "prefix"; + const gitlab = authenticate(env, { gitlabUrl, gitlabApiPathPrefix }) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {gitlabUrl, gitlabApiPathPrefix}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { gitlabUrl, gitlabApiPathPrefix }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); - t.deepEqual(t.context.log.args[0], ['Verify GitLab authentication (%s)', 'https://othertesturl.com:9090/prefix']); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://othertesturl.com:9090/prefix"]); }); -test.serial('Verify token and repository access and custom URL without prefix', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const gitlabUrl = 'https://othertesturl.com:9090'; - const gitlab = authenticate(env, {gitlabUrl}) +test.serial("Verify token and repository access and custom URL without prefix", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlabUrl = "https://othertesturl.com:9090"; + const gitlab = authenticate(env, { gitlabUrl }) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {gitlabUrl}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { gitlabUrl }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); - t.deepEqual(t.context.log.args[0], ['Verify GitLab authentication (%s)', 'https://othertesturl.com:9090/api/v4']); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://othertesturl.com:9090/api/v4"]); }); -test.serial('Verify token and repository access with subgroup git URL', async t => { - const repoUri = 'orga/subgroup/test_user/test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const gitlabUrl = 'https://customurl.com:9090/context'; - const gitlabApiPathPrefix = 'prefix'; - const gitlab = authenticate(env, {gitlabUrl, gitlabApiPathPrefix}) +test.serial("Verify token and repository access with subgroup git URL", async (t) => { + const repoUri = "orga/subgroup/test_user/test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlabUrl = "https://customurl.com:9090/context"; + const gitlabApiPathPrefix = "prefix"; + const gitlab = authenticate(env, { gitlabUrl, gitlabApiPathPrefix }) .get(`/projects/${encodeURIComponent(repoUri)}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {gitlabUrl, gitlabApiPathPrefix}, - {env, options: {repositoryUrl: `git@customurl.com:${repoUri}.git`}, logger: t.context.logger} + { gitlabUrl, gitlabApiPathPrefix }, + { env, options: { repositoryUrl: `git@customurl.com:${repoUri}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); t.deepEqual(t.context.log.args[0], [ - 'Verify GitLab authentication (%s)', - 'https://customurl.com:9090/context/prefix', + "Verify GitLab authentication (%s)", + "https://customurl.com:9090/context/prefix", ]); }); -test.serial('Verify token and repository access with subgroup http URL', async t => { - const repoUri = 'orga/subgroup/test_user/test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const gitlabUrl = 'https://customurl.com:9090/context'; - const gitlabApiPathPrefix = 'prefix'; - const gitlab = authenticate(env, {gitlabUrl, gitlabApiPathPrefix}) +test.serial("Verify token and repository access with subgroup http URL", async (t) => { + const repoUri = "orga/subgroup/test_user/test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlabUrl = "https://customurl.com:9090/context"; + const gitlabApiPathPrefix = "prefix"; + const gitlab = authenticate(env, { gitlabUrl, gitlabApiPathPrefix }) .get(`/projects/${encodeURIComponent(repoUri)}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {gitlabUrl, gitlabApiPathPrefix}, - {env, options: {repositoryUrl: `http://customurl.com/${repoUri}.git`}, logger: t.context.logger} + { gitlabUrl, gitlabApiPathPrefix }, + { env, options: { repositoryUrl: `http://customurl.com/${repoUri}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); t.deepEqual(t.context.log.args[0], [ - 'Verify GitLab authentication (%s)', - 'https://customurl.com:9090/context/prefix', + "Verify GitLab authentication (%s)", + "https://customurl.com:9090/context/prefix", ]); }); -test.serial('Verify token and repository access with empty gitlabApiPathPrefix', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const gitlabUrl = 'https://othertesturl.com:9090'; - const gitlabApiPathPrefix = ''; - const gitlab = authenticate(env, {gitlabUrl, gitlabApiPathPrefix}) +test.serial("Verify token and repository access with empty gitlabApiPathPrefix", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlabUrl = "https://othertesturl.com:9090"; + const gitlabApiPathPrefix = ""; + const gitlab = authenticate(env, { gitlabUrl, gitlabApiPathPrefix }) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {gitlabUrl, gitlabApiPathPrefix}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { gitlabUrl, gitlabApiPathPrefix }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); - t.deepEqual(t.context.log.args[0], ['Verify GitLab authentication (%s)', 'https://othertesturl.com:9090']); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://othertesturl.com:9090"]); }); -test.serial('Verify token and repository with environment variables', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_URL: 'https://othertesturl.com:443', GL_TOKEN: 'gitlab_token', GL_PREFIX: 'prefix'}; +test.serial("Verify token and repository with environment variables", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_URL: "https://othertesturl.com:443", GL_TOKEN: "gitlab_token", GL_PREFIX: "prefix" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( - verify({}, {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger}) + verify( + {}, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.true(gitlab.isDone()); - t.deepEqual(t.context.log.args[0], ['Verify GitLab authentication (%s)', 'https://othertesturl.com:443/prefix']); + t.deepEqual(t.context.log.args[0], ["Verify GitLab authentication (%s)", "https://othertesturl.com:443/prefix"]); }); -test.serial('Verify token and repository access with alternative environment varialbes', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_URL: 'https://othertesturl.com:443', GITLAB_TOKEN: 'gitlab_token', GITLAB_PREFIX: 'prefix'}; +test.serial("Verify token and repository access with alternative environment varialbes", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_URL: "https://othertesturl.com:443", GITLAB_TOKEN: "gitlab_token", GITLAB_PREFIX: "prefix" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( - verify({}, {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger}) + verify( + {}, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.true(gitlab.isDone()); }); -test.serial('Verify "assets" is a String', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_URL: 'https://othertesturl.com:443', GITLAB_TOKEN: 'gitlab_token', GITLAB_PREFIX: 'prefix'}; - const assets = 'file2.js'; +test.serial('Verify "assets" is a String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_URL: "https://othertesturl.com:443", GITLAB_TOKEN: "gitlab_token", GITLAB_PREFIX: "prefix" }; + const assets = "file2.js"; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); }); -test.serial('Verify "assets" is an Object with a path property', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_URL: 'https://othertesturl.com:443', GITLAB_TOKEN: 'gitlab_token', GITLAB_PREFIX: 'prefix'}; - const assets = {path: 'file2.js'}; +test.serial('Verify "assets" is an Object with a path property', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_URL: "https://othertesturl.com:443", GITLAB_TOKEN: "gitlab_token", GITLAB_PREFIX: "prefix" }; + const assets = { path: "file2.js" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); }); -test.serial('Verify "assets" is an Array of Object with a path property', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_URL: 'https://othertesturl.com:443', GITLAB_TOKEN: 'gitlab_token', GITLAB_PREFIX: 'prefix'}; - const assets = [{path: 'file1.js'}, {path: 'file2.js'}]; +test.serial('Verify "assets" is an Array of Object with a path property', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_URL: "https://othertesturl.com:443", GITLAB_TOKEN: "gitlab_token", GITLAB_PREFIX: "prefix" }; + const assets = [{ path: "file1.js" }, { path: "file2.js" }]; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); }); -test.serial('Verify "assets" is an Array of glob Arrays', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_URL: 'https://othertesturl.com:443', GITLAB_TOKEN: 'gitlab_token', GITLAB_PREFIX: 'prefix'}; - const assets = [['dist/**', '!**/*.js'], 'file2.js']; +test.serial('Verify "assets" is an Array of glob Arrays', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_URL: "https://othertesturl.com:443", GITLAB_TOKEN: "gitlab_token", GITLAB_PREFIX: "prefix" }; + const assets = [["dist/**", "!**/*.js"], "file2.js"]; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); }); -test.serial('Verify "assets" is an Array of Object with a glob Arrays in path property', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_URL: 'https://othertesturl.com:443', GITLAB_TOKEN: 'gitlab_token', GITLAB_PREFIX: 'prefix'}; - const assets = [{path: ['dist/**', '!**/*.js']}, {path: 'file2.js'}]; +test.serial('Verify "assets" is an Array of Object with a glob Arrays in path property', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_URL: "https://othertesturl.com:443", GITLAB_TOKEN: "gitlab_token", GITLAB_PREFIX: "prefix" }; + const assets = [{ path: ["dist/**", "!**/*.js"] }, { path: "file2.js" }]; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); await t.notThrowsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.true(gitlab.isDone()); }); -test.serial('Throw SemanticReleaseError if "assets" option is not a String or an Array of Objects', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; +test.serial('Throw SemanticReleaseError if "assets" option is not a String or an Array of Objects', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; const assets = 42; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const [error, ...errors] = await t.throwsAsync( + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDASSETS'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSETS"); t.true(gitlab.isDone()); }); -test.serial('Throw SemanticReleaseError if "assets" option is an Array with invalid elements', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const assets = ['file.js', 42]; +test.serial('Throw SemanticReleaseError if "assets" option is an Array with invalid elements', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assets = ["file.js", 42]; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const [error, ...errors] = await t.throwsAsync( + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDASSETS'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSETS"); t.true(gitlab.isDone()); }); -test.serial('Throw SemanticReleaseError if "assets" option is an Object missing the "path" property', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const assets = {name: 'file.js'}; +test.serial('Throw SemanticReleaseError if "assets" option is an Object missing the "path" property', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assets = { name: "file.js" }; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const [error, ...errors] = await t.throwsAsync( + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDASSETS'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSETS"); t.true(gitlab.isDone()); }); test.serial( 'Throw SemanticReleaseError if "assets" option is an Array with objects missing the "path" property', - async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const assets = [{path: 'lib/file.js'}, {name: 'file.js'}]; + async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assets = [{ path: "lib/file.js" }, { name: "file.js" }]; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 40}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const [error, ...errors] = await t.throwsAsync( + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( - {assets}, - {env, options: {repositoryUrl: `https://gitlab.com/${owner}/${repo}.git`}, logger: t.context.logger} + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDASSETS'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSETS"); t.true(gitlab.isDone()); } ); -test('Throw SemanticReleaseError for missing GitLab token', async t => { +test("Throw SemanticReleaseError for missing GitLab token", async (t) => { const env = {}; - const [error, ...errors] = await t.throwsAsync( + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( {}, - {env, options: {repositoryUrl: 'https://gitlab.com/semantic-release/gitlab.git'}, logger: t.context.logger} + { env, options: { repositoryUrl: "https://gitlab.com/semantic-release/gitlab.git" }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'ENOGLTOKEN'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "ENOGLTOKEN"); }); -test.serial('Throw SemanticReleaseError for invalid token', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GL_TOKEN: 'gitlab_token'}; - const gitlab = authenticate(env) - .get(`/projects/${owner}%2F${repo}`) - .reply(401); +test.serial("Throw SemanticReleaseError for invalid token", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlab = authenticate(env).get(`/projects/${owner}%2F${repo}`).reply(401); - const [error, ...errors] = await t.throwsAsync( - verify({}, {env, options: {repositoryUrl: `https://gitlab.com:${owner}/${repo}.git`}, logger: t.context.logger}) + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify({}, { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger }) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDGLTOKEN'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDGLTOKEN"); t.true(gitlab.isDone()); }); -test.serial('Throw SemanticReleaseError for invalid repositoryUrl', async t => { - const env = {GITLAB_TOKEN: 'gitlab_token'}; - const gitlabUrl = 'https://gitlab.com/context'; +test.serial("Throw SemanticReleaseError for invalid repositoryUrl", async (t) => { + const env = { GITLAB_TOKEN: "gitlab_token" }; + const gitlabUrl = "https://gitlab.com/context"; - const [error, ...errors] = await t.throwsAsync( + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( - {gitlabUrl}, - {env, options: {repositoryUrl: 'git+ssh://git@gitlab.com/context.git'}, logger: t.context.logger} + { gitlabUrl }, + { env, options: { repositoryUrl: "git+ssh://git@gitlab.com/context.git" }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDGITLABURL'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDGITLABURL"); }); -test.serial('Throw AggregateError if multiple verification fails', async t => { +test.serial("Throw AggregateError if multiple verification fails", async (t) => { const env = {}; - const gitlabUrl = 'https://gitlab.com/context'; + const gitlabUrl = "https://gitlab.com/context"; const assets = 42; + const { + errors: [invalidAssetsError, invalidUrlError, noTokenError, ...errors], + } = await t.throwsAsync( + verify( + { assets, gitlabUrl }, + { env, options: { repositoryUrl: "git+ssh://git@gitlab.com/context.git" }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(invalidAssetsError.name, "SemanticReleaseError"); + t.is(invalidAssetsError.code, "EINVALIDASSETS"); + t.is(invalidUrlError.name, "SemanticReleaseError"); + t.is(invalidUrlError.code, "EINVALIDGITLABURL"); + t.is(noTokenError.name, "SemanticReleaseError"); + t.is(noTokenError.code, "ENOGLTOKEN"); +}); + +test.serial("Throw SemanticReleaseError if token doesn't have the push permission on the repository", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 10 }, group_access: { access_level: 20 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify({}, { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger }) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EGLNOPUSHPERMISSION"); + t.true(gitlab.isDone()); +}); + +test.serial("Throw SemanticReleaseError if token doesn't have the pull permission on the repository", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 5 }, group_access: { access_level: 5 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + {}, + { + env, + options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git`, dryRun: true }, + logger: t.context.logger, + } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EGLNOPULLPERMISSION"); + t.true(gitlab.isDone()); +}); + +test.serial("Throw SemanticReleaseError if the repository doesn't exist", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const gitlab = authenticate(env).get(`/projects/${owner}%2F${repo}`).reply(404); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify({}, { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger }) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EMISSINGREPO"); + t.true(gitlab.isDone()); +}); + +test.serial("Throw error if GitLab API return any other errors", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const gitlab = authenticate(env).get(`/projects/${owner}%2F${repo}`).times(3).reply(500); + + const error = await t.throwsAsync( + verify({}, { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger }) + ); - const [invalidUrlError, invalidAssetsError, noTokenError, ...errors] = await t.throwsAsync( + t.is(error.response.statusCode, 500); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "failTitle" option is not a String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const failTitle = 42; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( verify( - {assets, gitlabUrl}, - {env, options: {repositoryUrl: 'git+ssh://git@gitlab.com/context.git'}, logger: t.context.logger} + { failTitle }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } ) ); t.is(errors.length, 0); - t.is(invalidUrlError.name, 'SemanticReleaseError'); - t.is(invalidUrlError.code, 'EINVALIDGITLABURL'); - t.is(invalidAssetsError.name, 'SemanticReleaseError'); - t.is(invalidAssetsError.code, 'EINVALIDASSETS'); - t.is(noTokenError.name, 'SemanticReleaseError'); - t.is(noTokenError.code, 'ENOGLTOKEN'); -}); - -test.serial("Throw SemanticReleaseError if token doesn't have the push permission on the repository", async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDFAILTITLE"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "failTitle" option is an empty String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const failTitle = ""; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(200, {permissions: {project_access: {access_level: 10}, group_access: {access_level: 20}}}); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const [error, ...errors] = await t.throwsAsync( - verify({}, {env, options: {repositoryUrl: `https://gitlab.com:${owner}/${repo}.git`}, logger: t.context.logger}) + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { failTitle }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EGLNOPERMISSION'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDFAILTITLE"); t.true(gitlab.isDone()); }); -test.serial("Throw SemanticReleaseError if the repository doesn't exist", async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; +test.serial('Throw SemanticReleaseError if "failTitle" option is a whitespace String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const failTitle = " \n \r "; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .reply(404); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const [error, ...errors] = await t.throwsAsync( - verify({}, {env, options: {repositoryUrl: `https://gitlab.com:${owner}/${repo}.git`}, logger: t.context.logger}) + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { failTitle }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); t.is(errors.length, 0); - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EMISSINGREPO'); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDFAILTITLE"); t.true(gitlab.isDone()); }); -test.serial('Throw error if GitLab API return any other errors', async t => { - const owner = 'test_user'; - const repo = 'test_repo'; - const env = {GITLAB_TOKEN: 'gitlab_token'}; +test.serial('Throw SemanticReleaseError if "failComment" option is not a String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const failComment = 42; const gitlab = authenticate(env) .get(`/projects/${owner}%2F${repo}`) - .times(3) - .reply(500); + .reply(200, { permissions: { project_access: { access_level: 40 } } }); - const error = await t.throwsAsync( - verify({}, {env, options: {repositoryUrl: `https://gitlab.com:${owner}/${repo}.git`}, logger: t.context.logger}) + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { failComment }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) ); - t.is(error.response.statusCode, 500); + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDFAILCOMMENT"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "failComment" option is an empty String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const failComment = ""; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { failComment }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDFAILCOMMENT"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "failComment" option is a whitespace String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const failComment = " \n \r "; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { failComment }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDFAILCOMMENT"); + t.true(gitlab.isDone()); +}); + +test.serial('Does not throw SemanticReleaseError if "labels" option is a valid String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const labels = "semantic-release"; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + await t.notThrowsAsync( + verify( + { labels }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.true(gitlab.isDone()); +}); + +test.serial('Does not throw SemanticReleaseError if "labels" option is "false"', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const labels = false; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + await t.notThrowsAsync( + verify( + { labels }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "labels" option is not a String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const labels = 42; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { labels }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDLABELS"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "labels" option is an empty String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const labels = ""; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { labels }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDLABELS"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "labels" option is a whitespace String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const labels = " \n \r "; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { labels }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDLABELS"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "assignee" option is not a String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assignee = 42; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { assignee }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSIGNEE"); + t.true(gitlab.isDone()); +}); + +test.serial('Throw SemanticReleaseError if "assignee" option is an empty String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assignee = ""; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { assignee }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSIGNEE"); t.true(gitlab.isDone()); }); + +test.serial('Throw SemanticReleaseError if "assignee" option is a whitespace String', async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assignee = " \n \r "; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error, ...errors], + } = await t.throwsAsync( + verify( + { assignee }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + + t.is(errors.length, 0); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSIGNEE"); + t.true(gitlab.isDone()); +}); + +test.serial("Does not throw an error for option without validator", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GL_TOKEN: "gitlab_token" }; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 30 } } }); + + await t.notThrowsAsync( + verify( + { + someOption: 42, + }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + t.true(gitlab.isDone()); +}); + +test.serial( + 'Won\'t throw SemanticReleaseError if "assets" option is an Array of objects with url field but missing the "path" property', + async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assets = [{ url: "https://gitlab.com/gitlab-org/gitlab/-/blob/master/README.md" }]; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + await t.notThrowsAsync( + verify( + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + t.true(gitlab.isDone()); + } +); + +test.serial( + 'Won\'t throw SemanticReleaseError if "assets" option is an Array of objects with path field but missing the "url" property', + async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assets = [{ path: "README.md" }]; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + await t.notThrowsAsync( + verify( + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + t.true(gitlab.isDone()); + } +); + +test.serial( + 'Throw SemanticReleaseError if "assets" option is an Array of objects without url nor path property', + async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const assets = [{ name: "README.md" }]; + const gitlab = authenticate(env) + .get(`/projects/${owner}%2F${repo}`) + .reply(200, { permissions: { project_access: { access_level: 40 } } }); + + const { + errors: [error], + } = await t.throwsAsync( + verify( + { assets }, + { env, options: { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }, logger: t.context.logger } + ) + ); + t.is(error.name, "SemanticReleaseError"); + t.is(error.code, "EINVALIDASSETS"); + t.true(gitlab.isDone()); + } +);