diff --git a/.eslintrc.json b/.eslintrc.json index 619ab8f..ae2d5d0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,7 +15,7 @@ "SharedArrayBuffer": "readonly" }, "parserOptions": { - "ecmaVersion": 2020 + "ecmaVersion": 2022 }, "rules": { "no-console": "off" diff --git a/README.md b/README.md index f434ee1..cb39bd3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ Used internally by OneBlink to release repositories quickly and consistently - [Node.js](https://nodejs.org/) 20.0 or newer - NPM 10.0 or newer -- See recommendation from [package-diff-summary](https://github.com/jokeyrhyme/package-diff-summary.js#github_oauth_token) regarding [GitHub API Rate Limiting](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) ## Installation @@ -29,3 +28,86 @@ Run the following command for usage information ```sh oneblink-release --help ``` + +## Changelog Automation + +To avoid constant merge conflicts with the `CHANGELOG.md` file. The Release CLI can automate changelog entries by allow developers to create a single file for each change entry (or a as many entries as the developer would like to add in that single file). Start by creating a directory called: `changelog-entries` in the root of the repository and add a `.keep` file to the directory, like so: + +``` +|- changelog-entries/ + |- .keep +|- src/ + |- index.js +|- .gitignore +|- package.json +|- README.md +``` + +The `.keep` file will simply prevent the directory from being removed from source control after each release. + +Each time a developer wants to add an entry to the changelog as part of the current release, create a file in the `changelog-entries` directory. The file must adhere to the [keepachangelog](https://keepachangelog.com/) format. + +Files can have as many entries as desired, however it is recommended to keep entries small to avoid merge conflicts with other developers. + +**All of the entry files will be removed as part of the release.** + +### Example Changelog Entry Files + +The following two files: + +- `kitchen-sink.md` + + ````md + ### Changed + + - the supported NodeJS version + - the name of a function. See the change below to migrate to the new function: + ```diff + -thisIsTheOldFunction() + +thisIsTheNewFunction() + ``` + + ### Removed + + - something that was not being used anymore + + ### Added + + - a new feature + + ### Fixed + + - a bug + ```` + +- `my-additions.md` + + ```md + ### Added + + - a really simple feature + ``` + +Would result in the following change entry: + +### Changed + +- the supported NodeJS version +- the name of a function. See the change below to migrate to the new function: + ```diff + -thisIsTheOldFunction() + +thisIsTheNewFunction() + ``` + +### Removed + +- something that was not being used anymore + +### Added + +- a new feature +- a really simple feature + +### Fixed + +- a bug diff --git a/changelog-entries/.keep b/changelog-entries/.keep new file mode 100644 index 0000000..e69de29 diff --git a/changelog-entries/changelog-automation.md b/changelog-entries/changelog-automation.md new file mode 100644 index 0000000..d89229d --- /dev/null +++ b/changelog-entries/changelog-automation.md @@ -0,0 +1,4 @@ +### Added + +- changelog automation from a `changelog-entries` directory +- `oneblink-release changelog-preview` command diff --git a/jest.config.js b/jest.config.js index 04d14af..f5d1552 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,4 @@ -/** - * @type {import('jest').Config} - */ +/** @type {import('jest').Config} */ const config = { preset: 'ts-jest', testEnvironment: 'node', @@ -11,6 +9,8 @@ const config = { 'ts-jest', { useESM: true, + isolatedModules: true, + tsconfig: './test/tsconfig.json', }, ], }, diff --git a/package-lock.json b/package-lock.json index e3128d5..5af997a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,8 @@ "enquirer": "^2.4.1", "execa": "^8.0.1", "github-url-from-git": "^1.5.0", + "glob": "^11.0.1", + "keep-a-changelog": "^2.5.3", "meow": "^12.1.1", "ora": "^7.0.1", "patch-package": "^8.0.0", @@ -47,7 +49,7 @@ "eslint-plugin-prettier": "^5.0.1", "jest": "^29.7.0", "prettier-plugin-jsdoc": "^1.1.1", - "ts-jest": "^29.1.1", + "ts-jest": "^29.2.5", "typescript": "^5.2.2" }, "engines": { @@ -645,6 +647,22 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@deno/shim-deno": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@deno/shim-deno/-/shim-deno-0.16.1.tgz", + "integrity": "sha512-s9v0kzF5bm/o9TgdwvsraHx6QNllYrXXmKzgOG2lh4LFXnVMr2gpjK/c/ve6EflQn1MqImcWmVD8HAv5ahuuZQ==", + "license": "MIT", + "dependencies": { + "@deno/shim-deno-test": "^0.4.0", + "which": "^2.0.2" + } + }, + "node_modules/@deno/shim-deno-test": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@deno/shim-deno-test/-/shim-deno-test-0.4.0.tgz", + "integrity": "sha512-oYWcD7CpERZy/TXMTM9Tgh1HD/POHlbY9WpzmAk+5H8DohcxG415Qws8yLGlim3EaKBT2v3lJv01x4G0BosnaQ==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -734,6 +752,102 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "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==", + "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/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "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==", + "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/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/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==", + "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/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1158,6 +1272,28 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/@jest/reporters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2287,6 +2423,13 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -3433,6 +3576,22 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.348", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz", @@ -4013,6 +4172,39 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4076,6 +4268,34 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/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==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -4101,7 +4321,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -4166,19 +4387,23 @@ "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==" }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4196,6 +4421,30 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/global-dirs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", @@ -4406,7 +4655,9 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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.", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4746,6 +4997,116 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/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/jake/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/jake/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/jake/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/jake/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/jake/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/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -5203,6 +5564,28 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/jest-config/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5988,6 +6371,28 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/jest-runtime/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -6518,6 +6923,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/keep-a-changelog": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/keep-a-changelog/-/keep-a-changelog-2.5.3.tgz", + "integrity": "sha512-ChMOZLbqdvxhdUIlKkA/UqU1PclcyR57bifjwkV/9/diYFUeHQeTaFkF3GWbXL1WYG/aZ5bJWg5pDLmC2NTycw==", + "license": "MIT", + "dependencies": { + "@deno/shim-deno": "~0.16.1" + }, + "bin": { + "changelog": "esm/bin.js" + } + }, "node_modules/keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -6630,17 +7047,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -7203,6 +7609,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7458,6 +7873,12 @@ "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==", + "license": "BlueOak-1.0.0" + }, "node_modules/package-json/node_modules/@sindresorhus/is": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", @@ -7711,6 +8132,27 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/patch-package/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/patch-package/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7761,7 +8203,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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7780,6 +8223,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -8257,6 +8725,28 @@ "url": "https://github.com/sponsors/isaacs" } }, + "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": "Glob versions prior to v9 are no longer supported", + "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/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -8404,12 +8894,10 @@ ] }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -8592,6 +9080,21 @@ "node": ">=8" } }, + "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==", + "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/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8603,6 +9106,19 @@ "node": ">=8" } }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -8682,6 +9198,28 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -8751,28 +9289,31 @@ } }, "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", "dev": true, + "license": "MIT", "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", "jest-util": "^29.0.0", "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", "@jest/types": "^29.0.0", "babel-jest": "^29.0.0", "jest": "^29.0.0", @@ -8782,6 +9323,9 @@ "@babel/core": { "optional": true }, + "@jest/transform": { + "optional": true + }, "@jest/types": { "optional": true }, @@ -9101,6 +9645,57 @@ "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==", + "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-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "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/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==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "license": "MIT" + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9172,11 +9767,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yaml": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", @@ -9677,6 +10267,20 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@deno/shim-deno": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@deno/shim-deno/-/shim-deno-0.16.1.tgz", + "integrity": "sha512-s9v0kzF5bm/o9TgdwvsraHx6QNllYrXXmKzgOG2lh4LFXnVMr2gpjK/c/ve6EflQn1MqImcWmVD8HAv5ahuuZQ==", + "requires": { + "@deno/shim-deno-test": "^0.4.0", + "which": "^2.0.2" + } + }, + "@deno/shim-deno-test": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@deno/shim-deno-test/-/shim-deno-test-0.4.0.tgz", + "integrity": "sha512-oYWcD7CpERZy/TXMTM9Tgh1HD/POHlbY9WpzmAk+5H8DohcxG415Qws8yLGlim3EaKBT2v3lJv01x4G0BosnaQ==" + }, "@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -9738,6 +10342,64 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "requires": { + "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" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==" + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -10059,6 +10721,20 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -10926,6 +11602,12 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -11702,6 +12384,15 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "requires": { + "jake": "^10.8.5" + } + }, "electron-to-chromium": { "version": "1.4.348", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz", @@ -12111,6 +12802,35 @@ "flat-cache": "^3.0.4" } }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -12158,6 +12878,22 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" + } + } + }, "form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -12177,7 +12913,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.3", @@ -12220,16 +12956,34 @@ "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==" }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "glob-parent": { @@ -12376,7 +13130,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -12601,6 +13355,77 @@ "istanbul-lib-report": "^3.0.0" } }, + "jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "requires": { + "@isaacs/cliui": "^8.0.2" + } + }, + "jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -12916,6 +13741,20 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -13505,6 +14344,20 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -13904,6 +14757,14 @@ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==" }, + "keep-a-changelog": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/keep-a-changelog/-/keep-a-changelog-2.5.3.tgz", + "integrity": "sha512-ChMOZLbqdvxhdUIlKkA/UqU1PclcyR57bifjwkV/9/diYFUeHQeTaFkF3GWbXL1WYG/aZ5bJWg5pDLmC2NTycw==", + "requires": { + "@deno/shim-deno": "~0.16.1" + } + }, "keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -13991,14 +14852,6 @@ "is-unicode-supported": "^1.1.0" } }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -14318,6 +15171,11 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -14593,6 +15451,11 @@ } } }, + "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==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -14666,6 +15529,19 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "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" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -14703,7 +15579,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -14716,6 +15592,22 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "requires": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "dependencies": { + "lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==" + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -15030,6 +15922,22 @@ "dev": true, "requires": { "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + } } }, "run-applescript": { @@ -15117,12 +16025,9 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" }, "semver-diff": { "version": "4.0.0", @@ -15265,6 +16170,16 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -15273,6 +16188,14 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -15325,6 +16248,22 @@ "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + } } }, "text-table": { @@ -15375,19 +16314,20 @@ "requires": {} }, "ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", "dev": true, "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", "jest-util": "^29.0.0", "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" } }, "type-check": { @@ -15626,6 +16566,39 @@ } } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "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==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -15652,11 +16625,6 @@ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yaml": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", diff --git a/package.json b/package.json index 4795f1f..68bf1fc 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "enquirer": "^2.4.1", "execa": "^8.0.1", "github-url-from-git": "^1.5.0", + "glob": "^11.0.1", + "keep-a-changelog": "^2.5.3", "meow": "^12.1.1", "ora": "^7.0.1", "patch-package": "^8.0.0", @@ -44,7 +46,7 @@ "eslint-plugin-prettier": "^5.0.1", "jest": "^29.7.0", "prettier-plugin-jsdoc": "^1.1.1", - "ts-jest": "^29.1.1", + "ts-jest": "^29.2.5", "typescript": "^5.2.2" }, "directories": { @@ -84,4 +86,4 @@ "typescript": "tsc --noEmit" }, "type": "module" -} +} \ No newline at end of file diff --git a/src/bin.ts b/src/bin.ts index 0b4c2bc..448bdc5 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -6,14 +6,15 @@ import updateNotifier from 'update-notifier' import meow from 'meow' import chalk from 'chalk' -import startRepositoryRelease from './startRepositoryRelease.js' +import startRepositoryRelease from './commands/startRepositoryRelease.js' import semver from 'semver' -import promptForNextVersion from './promptForNextVersion.js' -import getPreRelease from './getPreRelease.js' -import startProductRelease from './startProductRelease.js' -import promptForReleaseName from './promptForReleaseName.js' +import promptForNextVersion from './terminal/promptForNextVersion.js' +import getPreRelease from './utils/getPreRelease.js' +import startProductRelease from './commands/startProductRelease.js' +import promptForReleaseName from './terminal/promptForReleaseName.js' import getRepositoryPlugin from './repositories-plugins/plugins-factory.js' -import startUpdateDependents from './startUpdateDependents.js' +import startUpdateDependents from './commands/startUpdateDependents.js' +import startChangelogPreview from './commands/startChangelogPreview.js' const cli = meow( ` @@ -24,8 +25,8 @@ ${chalk.grey( the information required to perform the release.`, )} - --name ......... Skip the question to enter a name for the release by passing - a release name as a flag. + --name ........... Skip the question to enter a name for the release by + passing a release name as a flag. ${chalk.bold('Examples')} @@ -67,16 +68,33 @@ ${chalk.bold('Examples')} oneblink-release repository 1.1.1 --cwd ../path/to/code oneblink-release repository 1.1.1-uat.1 --no-git +${chalk.bold.blue('oneblink-release update-dependents [--cwd path]')} + ${chalk.grey('Update all product code bases that depend on an NPM package.')} - --cwd .......... Directory of the repository that is the dependency relative - to the current working directory, defaults to the current - working directory. + --cwd ............ Directory of the repository that is the dependency relative + to the current working directory, defaults to the current + working directory. ${chalk.bold('Examples')} oneblink-release update-dependents oneblink-release update-dependents --cwd ../path/to/code + +${chalk.bold.blue('oneblink-release changelog-preview [--cwd path]')} + +${chalk.grey( + `Display the changelog entries for the current "Unreleased" version based on +dependency changes and files in the "changelog-entries" directory.`, +)} + + --cwd ............ Directory of the repository to preview, defaults to the + current working directory. + +${chalk.bold('Examples')} + + oneblink-release changelog-preview + oneblink-release changelog-preview --cwd ../path/to/code `, { importMeta: import.meta, @@ -145,6 +163,12 @@ async function run(): Promise { const cwd = path.resolve(process.cwd(), cli.flags.cwd) switch (command) { + case 'changelog-preview': { + await startChangelogPreview({ + cwd, + }) + break + } case 'update-dependents': { await startUpdateDependents({ cwd, diff --git a/src/changelog/addNextReleaseToChangelog.ts b/src/changelog/addNextReleaseToChangelog.ts new file mode 100644 index 0000000..614150a --- /dev/null +++ b/src/changelog/addNextReleaseToChangelog.ts @@ -0,0 +1,89 @@ +import fs from 'fs/promises' +import prettier from 'prettier' +import { SemVer } from 'semver' +import wrapWithLoading from '../terminal/wrapWithLoading.js' +import { RepositoryPlugin } from '../repositories-plugins/RepositoryPlugin.js' +import generateNextReleaseChangelogEntries, { + UNRELEASED_VERSION_INDEX, +} from './generateNextReleaseChangelogEntries.js' + +export default async function addNextReleaseToChangelog({ + nextSemverVersion, + releaseName, + repositoryPlugin, +}: { + nextSemverVersion: SemVer + releaseName: string | undefined + repositoryPlugin: RepositoryPlugin +}) { + const { + parsedChangelog, + changelogPath, + nextReleaseChangelogEntries, + changelogEntryFiles, + } = await generateNextReleaseChangelogEntries({ repositoryPlugin }) + + const nextReleaseTitle = `[${nextSemverVersion.version}] - ${new Date() + .toISOString() + .substring(0, 10)}` + const releaseNameSubtitle = releaseName + ? `##### Release Name: ${releaseName}` + : '' + + await wrapWithLoading( + { + startText: `Updating CHANGELOG.md with next release (${nextReleaseTitle})`, + failText: `Failed to update CHANGELOG.md with next release (${nextReleaseTitle})`, + }, + async (spinner) => { + const changelog = await prettier.format( + ` +# ${parsedChangelog.title} + +${parsedChangelog.description || ''} + +${parsedChangelog.versions + .map(({ title, body }, index) => { + if (index === UNRELEASED_VERSION_INDEX) { + return ` +## ${title} + +## ${nextReleaseTitle} + +${releaseNameSubtitle} + +${nextReleaseChangelogEntries} +` + } + + return ` +## ${title} + +${body} +` + }) + .join('')}`, + { + parser: 'markdown', + }, + ) + await fs.writeFile(changelogPath, changelog, 'utf-8') + spinner.succeed( + `Updated CHANGELOG.md with next release (${nextReleaseTitle})`, + ) + }, + ) + + for (const { filePath } of changelogEntryFiles) { + wrapWithLoading( + { + startText: `Deleting file: "${filePath}"`, + failText: `Failed to delete file: "${filePath}"`, + }, + async (spinner) => { + await fs.unlink(filePath) + spinner.succeed(`Deleted file: "${filePath}"`) + }, + ) + } +} diff --git a/src/changelog/generateCodeChangelogEntries.ts b/src/changelog/generateCodeChangelogEntries.ts new file mode 100644 index 0000000..bab6519 --- /dev/null +++ b/src/changelog/generateCodeChangelogEntries.ts @@ -0,0 +1,90 @@ +import { readFile } from 'fs/promises' +import { glob } from 'glob' +import { parser, Release } from 'keep-a-changelog' +import prettier from 'prettier' +import wrapWithLoading from '../terminal/wrapWithLoading.js' +export const CHANGELOG_ENTRIES_DIRECTORY_NAME = 'changelog-entries' + +export default async function generateCodeChangelogEntries({ + cwd, + entriesInChangelog, +}: { + cwd: string + entriesInChangelog: string | undefined +}) { + return await wrapWithLoading( + { + startText: `Generating changelog entries from the "${CHANGELOG_ENTRIES_DIRECTORY_NAME}" directory`, + failText: `Failed to generate changelog entries from the "${CHANGELOG_ENTRIES_DIRECTORY_NAME}" directory`, + }, + async (spinner) => { + const entryFilePaths = await glob( + `${CHANGELOG_ENTRIES_DIRECTORY_NAME}/**`, + { + absolute: true, + cwd, + nodir: true, + }, + ) + + const finalRelease = new Release() + + if (entriesInChangelog) { + appendEntryToRelease(entriesInChangelog, finalRelease) + } + + const entryFiles: Array<{ + filePath: string + markdown: string + }> = [] + for (const entryFilePath of entryFilePaths) { + const entry = await readFile(entryFilePath, 'utf-8') + entryFiles.push({ + filePath: entryFilePath, + markdown: entry, + }) + appendEntryToRelease(entry, finalRelease) + } + + const releaseChangelogEntries = finalRelease + .toString() + .replace('## Unreleased', '') + const formatted = await prettier.format(releaseChangelogEntries, { + parser: 'markdown', + }) + + if (!entryFiles.length) { + spinner.info( + `Skipping inserting changelog entries from the "${CHANGELOG_ENTRIES_DIRECTORY_NAME}" directory to the CHANGELOG.md as there were no markdown files in the directory`, + ) + return { + formatted, + entryFiles, + } + } + + spinner.succeed( + `Changelog entries from the "${CHANGELOG_ENTRIES_DIRECTORY_NAME}" directory will be added to CHANGELOG.md`, + ) + + return { + formatted, + entryFiles, + } + }, + ) +} +function appendEntryToRelease(entry: string, finalRelease: Release) { + const parsed = parser(`# Changelog + +## Unreleased + +${entry}`) + for (const release of parsed.releases) { + for (const [type, changes] of release.changes) { + for (const change of changes) { + finalRelease.addChange(type, change) + } + } + } +} diff --git a/src/changelog/generateDependenciesChangelogEntry.ts b/src/changelog/generateDependenciesChangelogEntry.ts new file mode 100644 index 0000000..fbeb302 --- /dev/null +++ b/src/changelog/generateDependenciesChangelogEntry.ts @@ -0,0 +1,83 @@ +import parseChangelog from 'changelog-parser' +import wrapWithLoading from '../terminal/wrapWithLoading.js' +import { RepositoryPlugin } from '../repositories-plugins/RepositoryPlugin.js' + +const UNRELEASED_VERSION_INDEX = 0 +const GIT_TAG_PREFIX = 'v' + +export default async function generateDependenciesChangelogEntry({ + parsedChangelog, + repositoryPlugin, +}: { + parsedChangelog: parseChangelog.Changelog + repositoryPlugin: RepositoryPlugin +}): Promise { + return await wrapWithLoading( + { + startText: + 'Checking if the "Dependencies" heading should be added to CHANGELOG.md', + failText: + 'Failed to check if the "Dependencies" heading should be added to CHANGELOG.md', + }, + async (spinner) => { + if (!repositoryPlugin.generateDependenciesChangelog) { + spinner.info( + `Evaluating "Dependencies" is not supported for ${repositoryPlugin.displayType} repositories.`, + ) + return '' + } + + const unreleasedVersion = + parsedChangelog.versions[UNRELEASED_VERSION_INDEX] + if ( + !unreleasedVersion || + !unreleasedVersion.title.toLowerCase().includes('unreleased') + ) { + throw new Error('"Unreleased" heading in CHANGELOG.md does not exist') + } + + const dependenciesChangelogHeading = '### Dependencies' + + if (unreleasedVersion.body.includes(dependenciesChangelogHeading)) { + spinner.warn( + 'Skipping inserting the "Dependencies" heading in CHANGELOG.md as it already exists under the "Unreleased" heading. It is recommended to allow this release process to insert instead of adding them as dependencies change.', + ) + return '' + } + + const lastVersion = parsedChangelog.versions[1] + if (!lastVersion) { + spinner.info( + 'Skipping inserting the "Dependencies" heading in CHANGELOG.md as this is the first release according to the CHANGELOG.md.', + ) + return '' + } + + const lastGitTag = `${GIT_TAG_PREFIX}${lastVersion.version}` + const dependenciesChangelog = + await repositoryPlugin.generateDependenciesChangelog({ + previousVersion: lastGitTag, + }) + + if (dependenciesChangelog.result === 'WARNING') { + spinner.warn(dependenciesChangelog.message) + return '' + } + + if (!dependenciesChangelog.entries?.trim()) { + spinner.info( + `Skipping inserting the "Dependencies" heading in CHANGELOG.md as there were no dependency changes since the last release (${lastVersion.version})`, + ) + return '' + } + + spinner.succeed('"Dependencies" heading will be added to CHANGELOG.md') + + return ` +${dependenciesChangelogHeading} + +${dependenciesChangelog.entries} +` + }, + ) +} diff --git a/src/changelog/generateNextReleaseChangelogEntries.ts b/src/changelog/generateNextReleaseChangelogEntries.ts new file mode 100644 index 0000000..6d4e942 --- /dev/null +++ b/src/changelog/generateNextReleaseChangelogEntries.ts @@ -0,0 +1,47 @@ +import prettier from 'prettier' +import { RepositoryPlugin } from '../repositories-plugins/RepositoryPlugin.js' +import generateCodeChangelogEntries from './generateCodeChangelogEntries.js' +import generateDependenciesChangelogEntry from './generateDependenciesChangelogEntry.js' +import parseChangelogWithLoading from './parseChangelogWithLoading.js' + +export const UNRELEASED_VERSION_INDEX = 0 + +export default async function generateNextReleaseChangelogEntries({ + repositoryPlugin, +}: { + repositoryPlugin: RepositoryPlugin +}) { + const { parsedChangelog, changelogPath } = await parseChangelogWithLoading( + repositoryPlugin.cwd, + ) + + const { formatted: codeChangelogEntries, entryFiles: changelogEntryFiles } = + await generateCodeChangelogEntries({ + cwd: repositoryPlugin.cwd, + entriesInChangelog: + parsedChangelog.versions[UNRELEASED_VERSION_INDEX]?.body, + }) + + const dependenciesChangelogEntry = await generateDependenciesChangelogEntry({ + parsedChangelog, + repositoryPlugin, + }) + + const nextReleaseChangelogEntries = await prettier.format( + ` +${codeChangelogEntries} + +${dependenciesChangelogEntry} +`, + { + parser: 'markdown', + }, + ) + + return { + changelogEntryFiles, + parsedChangelog, + changelogPath, + nextReleaseChangelogEntries, + } +} diff --git a/src/parseChangelogWithLoading.ts b/src/changelog/parseChangelogWithLoading.ts similarity index 90% rename from src/parseChangelogWithLoading.ts rename to src/changelog/parseChangelogWithLoading.ts index a9edc78..3aacedd 100644 --- a/src/parseChangelogWithLoading.ts +++ b/src/changelog/parseChangelogWithLoading.ts @@ -1,6 +1,6 @@ import path from 'path' import parseChangelog from 'changelog-parser' -import wrapWithLoading from './wrapWithLoading.js' +import wrapWithLoading from '../terminal/wrapWithLoading.js' export default async function parseChangelogWithLoading(cwd: string) { const changelogPath = path.join(cwd, 'CHANGELOG.md') diff --git a/src/commands/startChangelogPreview.ts b/src/commands/startChangelogPreview.ts new file mode 100644 index 0000000..7c1b298 --- /dev/null +++ b/src/commands/startChangelogPreview.ts @@ -0,0 +1,49 @@ +import boxen from 'boxen' +import chalk from 'chalk' +import { CHANGELOG_ENTRIES_DIRECTORY_NAME } from '../changelog/generateCodeChangelogEntries.js' +import generateNextReleaseChangelogEntries from '../changelog/generateNextReleaseChangelogEntries.js' +import getRepositoryPlugin from '../repositories-plugins/plugins-factory.js' + +export default async function startChangelogPreview({ cwd }: { cwd: string }) { + const repositoryPlugin = await getRepositoryPlugin({ + cwd, + }) + const { nextReleaseChangelogEntries, changelogEntryFiles } = + await generateNextReleaseChangelogEntries({ + repositoryPlugin, + }) + if (!nextReleaseChangelogEntries) { + console.log( + chalk.yellow( + `There are no changelog entry files in the "${CHANGELOG_ENTRIES_DIRECTORY_NAME}" directory and there were no dependency changes`, + ), + ) + process.exitCode = 1 + return + } + + console.log( + boxen( + changelogEntryFiles.map(({ filePath }) => filePath).join(` +`), + { + title: 'Unreleased Entry Files', + padding: 1, + margin: { + top: 1, + bottom: 1, + }, + }, + ), + ) + console.log( + boxen(chalk.blue(nextReleaseChangelogEntries), { + title: 'Unreleased Entries', + padding: 1, + margin: { + top: 1, + bottom: 1, + }, + }), + ) +} diff --git a/src/startProductRelease.ts b/src/commands/startProductRelease.ts similarity index 65% rename from src/startProductRelease.ts rename to src/commands/startProductRelease.ts index 640c719..87b9153 100644 --- a/src/startProductRelease.ts +++ b/src/commands/startProductRelease.ts @@ -1,12 +1,12 @@ import enquirer from 'enquirer' -import executeCommand from './executeCommand.js' -import parseChangelogWithLoading from './parseChangelogWithLoading.js' -import promptForNextVersion from './promptForNextVersion.js' +import executeCommand from '../terminal/executeCommand.js' +import promptForNextVersion from '../terminal/promptForNextVersion.js' import boxen from 'boxen' import chalk from 'chalk' import startRepositoryRelease from './startRepositoryRelease.js' -import getRepositoryPlugin from './repositories-plugins/plugins-factory.js' -import enumerateProductRepositories from './enumerateProductRepositories.js' +import getRepositoryPlugin from '../repositories-plugins/plugins-factory.js' +import enumerateProductRepositories from '../repositories/enumerateProductRepositories.js' +import generateNextReleaseChangelogEntries from '../changelog/generateNextReleaseChangelogEntries.js' export default async function startProductRelease({ releaseName, @@ -17,31 +17,27 @@ export default async function startProductRelease({ const deploymentRequiredUrls: string[] = [] await enumerateProductRepositories( - async ({ productRepository, cloneUrl, repositoryWorkingDirectory }) => { + async ({ productRepository, repositoryWorkingDirectory }) => { const { repositoryName } = productRepository - // Check if repository needs releasing - const { parsedChangelog } = await parseChangelogWithLoading( - repositoryWorkingDirectory, - ) - const unreleasedVersion = parsedChangelog.versions.find((version) => - version.title.toLowerCase().includes('unreleased'), - ) - if (!unreleasedVersion) { - await continuePromptWithWarning(`"${repositoryName}" CHANGELOG.md does not contain an "Unreleased" section - -You need to checkout "${cloneUrl}" to fix this before trying again.`) - return - } - const { stdout: lastCommitMessage } = await executeCommand( 'git', ['log', '-1', '--pretty=oneline'], repositoryWorkingDirectory, ) + + const repositoryPlugin = await getRepositoryPlugin({ + cwd: repositoryWorkingDirectory, + repositoryType: productRepository, + }) + + const { nextReleaseChangelogEntries } = + await generateNextReleaseChangelogEntries({ + repositoryPlugin, + }) const unreleasedChangelogEntries = - unreleasedVersion.body.trim() || - chalk.italic('There are no entries under the "Unreleased" heading.') + nextReleaseChangelogEntries.trim() || + chalk.italic('There will be no entries under the "Unreleased" heading.') console.log( boxen( chalk.blue(`${unreleasedChangelogEntries} @@ -79,11 +75,6 @@ Last Commit: ${lastCommitMessage}`), return } - const repositoryPlugin = await getRepositoryPlugin({ - cwd: repositoryWorkingDirectory, - repositoryType: productRepository, - }) - const { nextVersion } = await promptForNextVersion({ repositoryPlugin, noPreRelease: true, @@ -124,16 +115,3 @@ Last Commit: ${lastCommitMessage}`), ) } } - -async function continuePromptWithWarning(warning: string) { - console.log( - boxen(chalk.yellow(warning), { - padding: 1, - }), - ) - await enquirer.prompt({ - type: 'invisible', - name: 'continue', - message: 'Press ENTER to continue.', - }) -} diff --git a/src/commands/startRepositoryRelease.ts b/src/commands/startRepositoryRelease.ts new file mode 100644 index 0000000..f4bc513 --- /dev/null +++ b/src/commands/startRepositoryRelease.ts @@ -0,0 +1,70 @@ +import semver from 'semver' +import ora from 'ora' +import executeCommand from '../terminal/executeCommand.js' +import getPreRelease from '../utils/getPreRelease.js' +import { RepositoryPlugin } from '../repositories-plugins/RepositoryPlugin.js' +import addNextReleaseToChangelog from '../changelog/addNextReleaseToChangelog.js' + +const GIT_TAG_PREFIX = 'v' + +export default async function startRepositoryRelease({ + nextVersion, + git, + releaseName, + repositoryPlugin, +}: { + nextVersion: string + git: boolean + releaseName: string | undefined + repositoryPlugin: RepositoryPlugin +}): Promise { + const nextSemverVersion = semver.parse(nextVersion) + if (!nextSemverVersion) { + throw new Error('Next version is not valid semver') + } + + const preRelease = getPreRelease(nextVersion) + + if (preRelease) { + const text = `Skipping changelog updates for "${preRelease.tag}" release` + ora(text).start().info(text) + } else { + await addNextReleaseToChangelog({ + nextSemverVersion, + releaseName, + repositoryPlugin, + }) + } + + await repositoryPlugin.incrementVersion(nextSemverVersion) + + if (!git) { + const text = `Skipping committing release changes using git` + ora(text).start().info(text) + return + } + + const message = `[RELEASE] ${nextSemverVersion.version}${ + releaseName ? ` - ${releaseName}` : '' + }` + + await executeCommand('git', ['add', '-A'], repositoryPlugin.cwd) + await executeCommand( + 'git', + ['commit', '--message', message], + repositoryPlugin.cwd, + ) + await executeCommand('git', ['push'], repositoryPlugin.cwd) + await executeCommand( + 'git', + [ + 'tag', + '-a', + `${GIT_TAG_PREFIX}${nextSemverVersion.version}`, + '-m', + message, + ], + repositoryPlugin.cwd, + ) + await executeCommand('git', ['push', '--tags'], repositoryPlugin.cwd) +} diff --git a/src/startUpdateDependents.ts b/src/commands/startUpdateDependents.ts similarity index 95% rename from src/startUpdateDependents.ts rename to src/commands/startUpdateDependents.ts index 0618308..c25bba2 100644 --- a/src/startUpdateDependents.ts +++ b/src/commands/startUpdateDependents.ts @@ -1,8 +1,8 @@ import { readPackageUp } from 'read-package-up' -import enumerateProductRepositories from './enumerateProductRepositories.js' -import getRepositoryPlugin from './repositories-plugins/plugins-factory.js' +import enumerateProductRepositories from '../repositories/enumerateProductRepositories.js' +import getRepositoryPlugin from '../repositories-plugins/plugins-factory.js' import enquirer from 'enquirer' -import executeCommand from './executeCommand.js' +import executeCommand from '../terminal/executeCommand.js' import boxen from 'boxen' export default async function startUpdateDependents({ cwd }: { cwd: string }) { diff --git a/src/repositories-plugins/NpmPlugin.ts b/src/repositories-plugins/NpmPlugin.ts index bb54289..a0ebb8c 100644 --- a/src/repositories-plugins/NpmPlugin.ts +++ b/src/repositories-plugins/NpmPlugin.ts @@ -1,7 +1,7 @@ import { readPackageUp } from 'read-package-up' import { main as packageDiffSummary } from '../package-diff-summary/index.js' import { SemVer } from 'semver' -import executeCommand from '../executeCommand.js' +import executeCommand from '../terminal/executeCommand.js' import { RepositoryPlugin } from './RepositoryPlugin.js' export default class NpmPlugin implements RepositoryPlugin { diff --git a/src/repositories-plugins/NugetPlugin.ts b/src/repositories-plugins/NugetPlugin.ts index 0fd9777..5194c70 100644 --- a/src/repositories-plugins/NugetPlugin.ts +++ b/src/repositories-plugins/NugetPlugin.ts @@ -1,7 +1,7 @@ import { readFile, writeFile } from 'fs/promises' import path from 'path' import { SemVer } from 'semver' -import getPreRelease from '../getPreRelease.js' +import getPreRelease from '../utils/getPreRelease.js' import { RepositoryPlugin } from './RepositoryPlugin.js' export default class NugetPlugin implements RepositoryPlugin { diff --git a/src/enumerateProductRepositories.ts b/src/repositories/enumerateProductRepositories.ts similarity index 97% rename from src/enumerateProductRepositories.ts rename to src/repositories/enumerateProductRepositories.ts index 0523c2e..c18425b 100644 --- a/src/enumerateProductRepositories.ts +++ b/src/repositories/enumerateProductRepositories.ts @@ -1,6 +1,6 @@ import path from 'path' import prepareCloneRepository from './prepareCloneRepository.js' -import { RepositoryType } from './repositories-plugins/plugins-factory.js' +import { RepositoryType } from '../repositories-plugins/plugins-factory.js' type Repository = { label: string diff --git a/src/prepareCloneRepository.ts b/src/repositories/prepareCloneRepository.ts similarity index 92% rename from src/prepareCloneRepository.ts rename to src/repositories/prepareCloneRepository.ts index c42b9f9..ae61379 100644 --- a/src/prepareCloneRepository.ts +++ b/src/repositories/prepareCloneRepository.ts @@ -1,8 +1,8 @@ import { mkdtemp, rm } from 'fs/promises' import { join } from 'node:path' import { tmpdir } from 'node:os' -import executeCommand from './executeCommand.js' -import wrapWithLoading from './wrapWithLoading.js' +import executeCommand from '../terminal/executeCommand.js' +import wrapWithLoading from '../terminal/wrapWithLoading.js' export default async function prepareCloneRepository({ repositoryName, diff --git a/src/startRepositoryRelease.ts b/src/startRepositoryRelease.ts deleted file mode 100644 index 2723d18..0000000 --- a/src/startRepositoryRelease.ts +++ /dev/null @@ -1,214 +0,0 @@ -import fs from 'fs' -import util from 'util' - -import prettier from 'prettier' -import semver, { SemVer } from 'semver' -import ora from 'ora' -import wrapWithLoading from './wrapWithLoading.js' -import executeCommand from './executeCommand.js' -import parseChangelogWithLoading from './parseChangelogWithLoading.js' -import getPreRelease from './getPreRelease.js' -import { RepositoryPlugin } from './repositories-plugins/RepositoryPlugin.js' - -const writeFileAsync = util.promisify(fs.writeFile) - -const UNRELEASED_VERSION_INDEX = 0 -const GIT_TAG_PREFIX = 'v' - -async function updateChangelog({ - nextSemverVersion, - releaseName, - repositoryPlugin, -}: { - nextSemverVersion: SemVer - releaseName: string | undefined - repositoryPlugin: RepositoryPlugin -}) { - const { parsedChangelog, changelogPath } = await parseChangelogWithLoading( - repositoryPlugin.cwd, - ) - - const dependenciesChangelogEntry = await wrapWithLoading( - { - startText: - 'Checking if the "Dependencies" heading should be added to CHANGELOG.md', - failText: - 'Failed to check if the "Dependencies" heading should be added to CHANGELOG.md', - }, - async (spinner) => { - if (!repositoryPlugin.generateDependenciesChangelog) { - spinner.info( - `Evaluating "Dependencies" is not supported for ${repositoryPlugin.displayType} repositories.`, - ) - return '' - } - - const unreleasedVersion = - parsedChangelog.versions[UNRELEASED_VERSION_INDEX] - if ( - !unreleasedVersion || - !unreleasedVersion.title.toLowerCase().includes('unreleased') - ) { - throw new Error('"Unreleased" heading in CHANGELOG.md does not exist') - } - - const dependenciesChangelogHeading = '### Dependencies' - - if (unreleasedVersion.body.includes(dependenciesChangelogHeading)) { - spinner.warn( - 'Skipping inserting the "Dependencies" heading in CHANGELOG.md as it already exists under the "Unreleased" heading. It is recommended to allow this release process to insert instead of adding them as dependencies change.', - ) - return '' - } - - const lastVersion = parsedChangelog.versions[1] - if (!lastVersion) { - spinner.info( - 'Skipping inserting the "Dependencies" heading in CHANGELOG.md as this is the first release according to the CHANGELOG.md.', - ) - return '' - } - - const lastGitTag = `${GIT_TAG_PREFIX}${lastVersion.version}` - const dependenciesChangelog = - await repositoryPlugin.generateDependenciesChangelog({ - previousVersion: lastGitTag, - }) - - if (dependenciesChangelog.result === 'WARNING') { - spinner.warn(dependenciesChangelog.message) - return '' - } - - if (!dependenciesChangelog.entries?.trim()) { - spinner.info( - `Skipping inserting the "Dependencies" heading in CHANGELOG.md as there were no dependency changes since the last release (${lastVersion.version})`, - ) - return '' - } - - spinner.succeed('"Dependencies" heading will be added to CHANGELOG.md') - - return ` -${dependenciesChangelogHeading} - -${dependenciesChangelog.entries} -` - }, - ) - - const nextReleaseTitle = `[${nextSemverVersion.version}] - ${new Date() - .toISOString() - .substring(0, 10)}` - const releaseNameSubtitle = releaseName - ? ` - -##### Release Name: ${releaseName}` - : '' - - await wrapWithLoading( - { - startText: `Updating CHANGELOG.md with next release (${nextReleaseTitle})`, - failText: `Failed to update CHANGELOG.md with next release (${nextReleaseTitle})`, - }, - async (spinner) => { - const changelog = await prettier.format( - ` -# ${parsedChangelog.title} - -${parsedChangelog.description || ''} - -${parsedChangelog.versions - .map(({ title, body }, index) => { - if (index === UNRELEASED_VERSION_INDEX) { - return ` -## ${title} - -## ${nextReleaseTitle}${releaseNameSubtitle} - -${body} - -${dependenciesChangelogEntry} -` - } - - return ` -## ${title} - -${body} -` - }) - .join('')}`, - { - parser: 'markdown', - }, - ) - await writeFileAsync(changelogPath, changelog, 'utf-8') - spinner.succeed( - `Updated CHANGELOG.md with next release (${nextReleaseTitle})`, - ) - }, - ) -} - -export default async function startRepositoryRelease({ - nextVersion, - git, - releaseName, - repositoryPlugin, -}: { - nextVersion: string - git: boolean - releaseName: string | undefined - repositoryPlugin: RepositoryPlugin -}): Promise { - const nextSemverVersion = semver.parse(nextVersion) - if (!nextSemverVersion) { - throw new Error('Next version is not valid semver') - } - - const preRelease = getPreRelease(nextVersion) - - if (preRelease) { - const text = `Skipping changelog updates for "${preRelease.tag}" release` - ora(text).start().info(text) - } else { - await updateChangelog({ - nextSemverVersion, - releaseName, - repositoryPlugin, - }) - } - - await repositoryPlugin.incrementVersion(nextSemverVersion) - - if (!git) { - const text = `Skipping committing release changes using git` - ora(text).start().info(text) - return - } - - const message = `[RELEASE] ${nextSemverVersion.version}${ - releaseName ? ` - ${releaseName}` : '' - }` - - await executeCommand('git', ['add', '-A'], repositoryPlugin.cwd) - await executeCommand( - 'git', - ['commit', '--message', message], - repositoryPlugin.cwd, - ) - await executeCommand('git', ['push'], repositoryPlugin.cwd) - await executeCommand( - 'git', - [ - 'tag', - '-a', - `${GIT_TAG_PREFIX}${nextSemverVersion.version}`, - '-m', - message, - ], - repositoryPlugin.cwd, - ) - await executeCommand('git', ['push', '--tags'], repositoryPlugin.cwd) -} diff --git a/src/executeCommand.ts b/src/terminal/executeCommand.ts similarity index 100% rename from src/executeCommand.ts rename to src/terminal/executeCommand.ts diff --git a/src/promptForNextVersion.ts b/src/terminal/promptForNextVersion.ts similarity index 91% rename from src/promptForNextVersion.ts rename to src/terminal/promptForNextVersion.ts index c2155b9..eaf46c3 100644 --- a/src/promptForNextVersion.ts +++ b/src/terminal/promptForNextVersion.ts @@ -1,7 +1,7 @@ import enquirer from 'enquirer' import semver from 'semver' -import getPreRelease from './getPreRelease.js' -import { RepositoryPlugin } from './repositories-plugins/RepositoryPlugin.js' +import getPreRelease from '../utils/getPreRelease.js' +import { RepositoryPlugin } from '../repositories-plugins/RepositoryPlugin.js' export default async function promptForNextVersion({ repositoryPlugin, diff --git a/src/promptForReleaseName.ts b/src/terminal/promptForReleaseName.ts similarity index 100% rename from src/promptForReleaseName.ts rename to src/terminal/promptForReleaseName.ts diff --git a/src/wrapWithLoading.ts b/src/terminal/wrapWithLoading.ts similarity index 100% rename from src/wrapWithLoading.ts rename to src/terminal/wrapWithLoading.ts diff --git a/src/getPreRelease.ts b/src/utils/getPreRelease.ts similarity index 100% rename from src/getPreRelease.ts rename to src/utils/getPreRelease.ts diff --git a/test/.eslintrc.json b/test/.eslintrc.json index a80a425..56a92f6 100644 --- a/test/.eslintrc.json +++ b/test/.eslintrc.json @@ -5,5 +5,9 @@ }, "rules": { "@typescript-eslint/no-explicit-any": "off" + }, + "parserOptions": { + "ecmaVersion": 2022, + "project": "./test/tsconfig.json" } } diff --git a/test/fixtures/empty-changelog/changelog-entries/.keep b/test/fixtures/empty-changelog/changelog-entries/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/valid-changelog/changelog-entries/.keep b/test/fixtures/valid-changelog/changelog-entries/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/valid-changelog/changelog-entries/entry1.md b/test/fixtures/valid-changelog/changelog-entries/entry1.md new file mode 100644 index 0000000..b47c9bc --- /dev/null +++ b/test/fixtures/valid-changelog/changelog-entries/entry1.md @@ -0,0 +1,3 @@ +### Added + +- Feature 1 diff --git a/test/fixtures/valid-changelog/changelog-entries/entry2.md b/test/fixtures/valid-changelog/changelog-entries/entry2.md new file mode 100644 index 0000000..75e5dba --- /dev/null +++ b/test/fixtures/valid-changelog/changelog-entries/entry2.md @@ -0,0 +1,3 @@ +### Fixed + +- Bug 1 diff --git a/test/src/changelog/__snapshots__/generateCodeChangelogEntries.test.ts.snap b/test/src/changelog/__snapshots__/generateCodeChangelogEntries.test.ts.snap new file mode 100644 index 0000000..88cf5fb --- /dev/null +++ b/test/src/changelog/__snapshots__/generateCodeChangelogEntries.test.ts.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateCodeChangelogEntries should handle empty changelog directory 1`] = `""`; + +exports[`generateCodeChangelogEntries should process changelog entries and format them 1`] = ` +"### Added + +- Feature 1 + +### Fixed + +- Bug 1 +" +`; + +exports[`generateCodeChangelogEntries should process changelog entries with existing changelog and format them 1`] = ` +"### Added + +- some stuff +- Feature 1 + +### Removed + +- almost everything + +### Fixed + +- some other stuff +- Bug 1 +" +`; diff --git a/test/src/changelog/generateCodeChangelogEntries.test.ts b/test/src/changelog/generateCodeChangelogEntries.test.ts new file mode 100644 index 0000000..02233c5 --- /dev/null +++ b/test/src/changelog/generateCodeChangelogEntries.test.ts @@ -0,0 +1,54 @@ +import path from 'path' +import generateCodeChangelogEntries from '../../../src/changelog/generateCodeChangelogEntries.js' + +describe('generateCodeChangelogEntries', () => { + const fixturesPath = path.resolve(process.cwd(), 'test', 'fixtures') + + it('should process changelog entries and format them', async () => { + const cwd = path.join(fixturesPath, 'valid-changelog') + console.log('cwd', cwd) + + const result = await generateCodeChangelogEntries({ + cwd, + entriesInChangelog: undefined, + }) + + expect(result.entryFiles).toHaveLength(2) + expect(result.formatted).toMatchSnapshot() + }) + + it('should process changelog entries with existing changelog and format them', async () => { + const cwd = path.join(fixturesPath, 'valid-changelog') + console.log('cwd', cwd) + + const result = await generateCodeChangelogEntries({ + cwd, + entriesInChangelog: `### Added +- some stuff + +### Fixed + +- some other stuff + +### Removed + +- almost everything`, + }) + + expect(result.entryFiles).toHaveLength(2) + expect(result.formatted).toMatchSnapshot() + }) + + it('should handle empty changelog directory', async () => { + const cwd = path.join(fixturesPath, 'empty-changelog') + console.log('cwd', cwd) + + const result = await generateCodeChangelogEntries({ + cwd, + entriesInChangelog: undefined, + }) + + expect(result.entryFiles).toHaveLength(0) + expect(result.formatted).toMatchSnapshot() + }) +}) diff --git a/test/src/commands/startReleaseProcess.test.ts b/test/src/commands/startReleaseProcess.test.ts new file mode 100644 index 0000000..6584386 --- /dev/null +++ b/test/src/commands/startReleaseProcess.test.ts @@ -0,0 +1,5 @@ +import startRepositoryRelease from '../../../src/commands/startRepositoryRelease.js' + +test('startReleaseProcess should be a function', () => { + expect(typeof startRepositoryRelease).toBe('function') +}) diff --git a/test/startReleaseProcess.test.ts b/test/startReleaseProcess.test.ts deleted file mode 100644 index d40e7a6..0000000 --- a/test/startReleaseProcess.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import startReleaseProcess from '../src/startReleaseProcess.js' - -console.log('before test') -test('startReleaseProcess should be a function', () => { - console.log('test start') - // expect(typeof startReleaseProcess).toBe('function') - expect(1).toBe(1) - console.log('test end') -}) -console.log('after test') diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..247515b --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": ".." + }, + "include": ["."] +} diff --git a/tsconfig.json b/tsconfig.json index 8674f6b..1e22ef3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -70,5 +70,5 @@ "skipLibCheck": true /* Skip type checking of declaration files. */, "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ }, - "include": ["src", "types"] + "include": ["src"] } diff --git a/types/package-diff-summary.d.ts b/types/package-diff-summary.d.ts deleted file mode 100644 index aeb451e..0000000 --- a/types/package-diff-summary.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'package-diff-summary' { - export function main(options: { - previousVersion: string - cwd: string - }): string -}