From 5cc6a43faf998684a18051e728b4f69f1385e26c Mon Sep 17 00:00:00 2001 From: Seth Silesky <5115498+silesky@users.noreply.github.com> Date: Tue, 26 Jul 2022 15:25:27 -0500 Subject: [PATCH] Generate github release notes from changelog + tags (#553) * add release script * add test for scripts * make changelogPath work with irregular changelog names * add title * return array of tags * fix comment --- .buildkite/pipeline.yml | 5 + .github/workflows/create-github-release.yml | 9 +- package.json | 3 + scripts/create-release-from-tags.sh | 9 - .../fixtures/first-release-example.md | 11 + .../__tests__/fixtures/reg-example.md | 17 ++ .../__tests__/index.test.ts | 40 ++++ scripts/create-release-from-tags/index.ts | 192 ++++++++++++++++++ scripts/create-release-from-tags/run.ts | 8 + scripts/jest.config.js | 10 + scripts/utils/exists.ts | 7 + typings/get-monorepo-packages.d.ts | 9 + typings/spawn.d.ts | 10 + yarn.lock | 134 +++++++++++- 14 files changed, 443 insertions(+), 21 deletions(-) delete mode 100644 scripts/create-release-from-tags.sh create mode 100644 scripts/create-release-from-tags/__tests__/fixtures/first-release-example.md create mode 100644 scripts/create-release-from-tags/__tests__/fixtures/reg-example.md create mode 100644 scripts/create-release-from-tags/__tests__/index.test.ts create mode 100755 scripts/create-release-from-tags/index.ts create mode 100644 scripts/create-release-from-tags/run.ts create mode 100644 scripts/jest.config.js create mode 100644 scripts/utils/exists.ts create mode 100644 typings/get-monorepo-packages.d.ts create mode 100644 typings/spawn.d.ts diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index f23786d17..66007fc31 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -7,7 +7,12 @@ steps: agents: queue: v1 commands: + - npm config set "//registry.npmjs.org/:_authToken" $${NPM_TOKEN} + - echo "--- Install dependencies" + - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 HUSKY=0 yarn install --immutable + - echo "+++ Run tests" - yarn constraints + - yarn run test:scripts - label: "[Browser] Lint + Test" key: build diff --git a/.github/workflows/create-github-release.yml b/.github/workflows/create-github-release.yml index e3c36a2c0..f6f6e8f92 100644 --- a/.github/workflows/create-github-release.yml +++ b/.github/workflows/create-github-release.yml @@ -13,10 +13,17 @@ jobs: steps: - name: Checkout Repo uses: actions/checkout@v3 + - name: Setup Node.js 12.x + uses: actions/setup-node@v3 + with: + node-version: 12.x + cache: "yarn" + - name: Install Dependencies + run: HUSKY=0 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 yarn install --immutable - name: Create Github Release From Tags env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git config --global user.name "Segment Github" git config --global user.email "github-actions@segment.com" - bash scripts/create-release-from-tags.sh + yarn ts-node-script --files scripts/create-release-from-tags/run.ts diff --git a/package.json b/package.json index 113a16ae1..5f038bf0d 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "scripts": { "test": "turbo run test", + "test:scripts": "jest --config scripts/jest.config.js", "lint": "yarn constraints && turbo run lint", "build": "turbo run build", "build:packages": "turbo run build --filter='./packages/*'", @@ -34,6 +35,7 @@ "devDependencies": { "@changesets/changelog-github": "^0.4.5", "@changesets/cli": "^2.23.2", + "@npmcli/promise-spawn": "^3.0.0", "@types/jest": "^28.1.1", "@typescript-eslint/eslint-plugin": "^5.21.0", "@typescript-eslint/parser": "^5.21.0", @@ -41,6 +43,7 @@ "eslint": "^8.14.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.0.0", + "get-monorepo-packages": "^1.2.0", "husky": "^8.0.0", "jest": "^28.1.0", "lint-staged": "^13.0.0", diff --git a/scripts/create-release-from-tags.sh b/scripts/create-release-from-tags.sh deleted file mode 100644 index 2d83bb25a..000000000 --- a/scripts/create-release-from-tags.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Create github release(s) for every tag of the current commit. Use the github cli. - -tags=$(git tag --points-at HEAD) - -for tag in "${tags[@]}"; do - gh release create "$tag" -done diff --git a/scripts/create-release-from-tags/__tests__/fixtures/first-release-example.md b/scripts/create-release-from-tags/__tests__/fixtures/first-release-example.md new file mode 100644 index 000000000..5043bbf91 --- /dev/null +++ b/scripts/create-release-from-tags/__tests__/fixtures/first-release-example.md @@ -0,0 +1,11 @@ + # @segment/analytics-core + + ## 1.99.0 + + ### Minor Changes + + * [#606](https://github.com/segmentio/analytics-next/pull/606) [\`b9c6356\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - foo!) + + ### Patch Changes + + * [#404](https://github.com/segmentio/analytics-next/pull/404) [\`b9abc6\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - bar!) \ No newline at end of file diff --git a/scripts/create-release-from-tags/__tests__/fixtures/reg-example.md b/scripts/create-release-from-tags/__tests__/fixtures/reg-example.md new file mode 100644 index 000000000..71c23dbfb --- /dev/null +++ b/scripts/create-release-from-tags/__tests__/fixtures/reg-example.md @@ -0,0 +1,17 @@ + # @segment/analytics-core + + ## 1.99.0 + + ### Minor Changes + + * [#606](https://github.com/segmentio/analytics-next/pull/606) [\`b9c6356\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - foo!) + + ### Patch Changes + + * [#404](https://github.com/segmentio/analytics-next/pull/404) [\`b9abc6\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - bar!) + + ## 1.39.2 + + ### Patch Changes + + * [#513](https://github.com/segmentio/analytics-next/pull/513) [\`1d36ca1\`](https://github.com/segmentio/analytics-next/commit/1d36ca1440fc5df9171d16278d8918b3e5a32128) Thanks [@silesky](https://github.com/silesky)! - test \ No newline at end of file diff --git a/scripts/create-release-from-tags/__tests__/index.test.ts b/scripts/create-release-from-tags/__tests__/index.test.ts new file mode 100644 index 000000000..9d0841f06 --- /dev/null +++ b/scripts/create-release-from-tags/__tests__/index.test.ts @@ -0,0 +1,40 @@ +import { parseReleaseNotes } from '..' +import fs from 'fs' +import path from 'path' + +const readFixture = (filename: string) => { + return fs.readFileSync(path.join(__dirname, 'fixtures', filename), { + encoding: 'utf8', + }) +} + +describe('parseReleaseNotes', () => { + test('should work with reg example', () => { + const fixture = readFixture('reg-example.md') + expect(parseReleaseNotes(fixture, '1.99.0')).toMatchInlineSnapshot(` + " + ### Minor Changes + + * [#606](https://github.com/segmentio/analytics-next/pull/606) [\\\\\`b9c6356\\\\\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - foo!) + + ### Patch Changes + + * [#404](https://github.com/segmentio/analytics-next/pull/404) [\\\\\`b9abc6\\\\\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - bar!) + " + `) + }) + + test('should work if first release', () => { + const fixture = readFixture('first-release-example.md') + expect(parseReleaseNotes(fixture, '1.99.0')).toMatchInlineSnapshot(` + " + ### Minor Changes + + * [#606](https://github.com/segmentio/analytics-next/pull/606) [\\\\\`b9c6356\\\\\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - foo!) + + ### Patch Changes + + * [#404](https://github.com/segmentio/analytics-next/pull/404) [\\\\\`b9abc6\\\\\`](https://github.com/segmentio/analytics-next/commit/b9c6356b7d35ee8acb6ecbd1eebc468d18d63958) Thanks [@silesky] - bar!)" + `) + }) +}) diff --git a/scripts/create-release-from-tags/index.ts b/scripts/create-release-from-tags/index.ts new file mode 100755 index 000000000..33dbfffd9 --- /dev/null +++ b/scripts/create-release-from-tags/index.ts @@ -0,0 +1,192 @@ +import spawn from '@npmcli/promise-spawn' +import getPackages from 'get-monorepo-packages' +import path from 'path' +import fs from 'fs' +import { exists } from '../utils/exists' + +export type Config = { + isDryRun: boolean + tags: Tag[] +} + +export type Tag = { + name: string + versionNumber: string + raw: string +} + +/** + * + * @returns list of tags + * @example ["@segment/analytics-core@1.0.0", "@segment/analytics-next@2.1.1"] + */ +export const getCurrentGitTags = async (): Promise => { + const { stdout, stderr, code } = await spawn('git', [ + 'tag', + '--points-at', + 'HEAD', + '--column', + ]) + if (code !== 0) { + throw new Error(stderr.toString()) + } + + return parseRawTags(stdout.toString()) +} + +export const getConfig = async ({ + DRY_RUN, + TAGS, +}: NodeJS.ProcessEnv): Promise => { + const isDryRun = Boolean(DRY_RUN) + const tags = TAGS ? parseRawTags(TAGS) : await getCurrentGitTags() + + if (!tags.length) { + throw new Error('No git tags found.') + } + return { + isDryRun, + tags, + } +} + +const getChangelogPath = (packageName: string): string | undefined => { + const result = getPackages('.').find((p) => + p.package.name.includes(packageName) + ) + if (!result) + throw new Error(`could not find package with name: ${packageName}.`) + + let changelogPath = undefined + for (const fileName of ['CHANGELOG.MD', 'CHANGELOG.md']) { + if (changelogPath) break + const myPath = path.join(result.location, fileName) + const pathExists = fs.existsSync(myPath) + if (pathExists) { + changelogPath = myPath + } + } + + if (changelogPath) { + return changelogPath + } else { + console.log(`could not find changelog path for ${result.location}`) + } +} + +/** + * + * @returns list of tags + * @example ["@segment/analytics-core@1.0.0", "@segment/analytics-next@2.1.1"] + */ +const createGithubRelease = async ( + tag: string, + releaseNotes?: string +): Promise => { + const { stderr, code } = await spawn('gh', [ + 'release', + 'create', + tag, + '--title', + tag, + '--notes', + releaseNotes || '', + ]) + if (code !== 0) { + throw new Error(stderr.toString()) + } +} + +/** + * + * @param rawTag - ex. "@segment/analytics-foo@1.99.0" + */ +const extractPartsFromTag = (rawTag: string): Tag | undefined => { + const [name, version] = rawTag.split(/@(\d.*)/) + if (!name || !version) return undefined + return { + name, + versionNumber: version?.replace('\n', '') as string, + raw: rawTag, + } +} + +/** + * + * @param rawTags - string delimited list of tags (e.g. `@segment/analytics-next@2.1.1 @segment/analytics-core@1.0.0`) + */ +export const parseRawTags = (rawTags: string): Tag[] => { + return rawTags.trim().split(' ').map(extractPartsFromTag).filter(exists) +} + +/** + * + * @returns the release notes that correspond to a given tag. + */ +export const parseReleaseNotes = ( + changelogText: string, + versionNumber: string +): string => { + const h2tag = /(##\s.*\d.*)/gi + let begin: number + let end: number + + changelogText.split('\n').forEach((line, idx) => { + if (begin && end) return + if (line.includes(versionNumber)) { + begin = idx + 1 + } else if (begin && h2tag.test(line)) { + end = idx - 1 + } + }) + + const result = changelogText.split('\n').filter((_, idx) => { + return idx >= begin && idx <= (end ?? Infinity) + }) + return result.join('\n') +} + +const getReleaseNotes = (tag: Tag): string | undefined => { + const { name, versionNumber } = tag + const changelogPath = getChangelogPath(name) + if (!changelogPath) { + console.log(`no changelog path for ${name}... skipping.`) + return + } + const changelogText = fs.readFileSync(changelogPath, { encoding: 'utf8' }) + const releaseNotes = parseReleaseNotes(changelogText, versionNumber) + if (!releaseNotes) { + console.log( + `Could not find release notes for tags ${tag.raw} in ${changelogPath}.` + ) + } + return releaseNotes +} + +const createGithubReleaseFromTag = async ( + tag: Tag, + { dryRun = false } = {} +): Promise => { + const notes = getReleaseNotes(tag) + if (notes) { + console.log( + `\n ---> Outputting release titled: ${tag.raw} with notes: \n ${notes}` + ) + } + + if (dryRun) { + console.log(`--> Dry run: ${tag.raw} not released.`) + return undefined + } + + await createGithubRelease(tag.raw, notes) + return undefined +} + +export const createReleaseFromTags = async (config: Config) => { + console.log('Processing tags:', config.tags, '\n') + + for (const tag of config.tags) { + await createGithubReleaseFromTag(tag, { dryRun: config.isDryRun }) + } +} diff --git a/scripts/create-release-from-tags/run.ts b/scripts/create-release-from-tags/run.ts new file mode 100644 index 000000000..4e6d8a284 --- /dev/null +++ b/scripts/create-release-from-tags/run.ts @@ -0,0 +1,8 @@ +import { createReleaseFromTags, getConfig } from '.' + +async function run() { + const config = await getConfig(process.env) + return createReleaseFromTags(config) +} + +void run() diff --git a/scripts/jest.config.js b/scripts/jest.config.js new file mode 100644 index 000000000..e0cd94274 --- /dev/null +++ b/scripts/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ["**/?(*.)+(test).[jt]s?(x)"], + globals: { + 'ts-jest': { + isolatedModules: true, + }, + }, +} diff --git a/scripts/utils/exists.ts b/scripts/utils/exists.ts new file mode 100644 index 000000000..b19ea37ae --- /dev/null +++ b/scripts/utils/exists.ts @@ -0,0 +1,7 @@ +/** + * This type guard can be passed into a function such as native filter + * in order to remove nullish values from a list in a type-safe way. + */ +export const exists = (value: T): value is NonNullable => { + return value != null && value !== undefined +} diff --git a/typings/get-monorepo-packages.d.ts b/typings/get-monorepo-packages.d.ts new file mode 100644 index 000000000..b42564777 --- /dev/null +++ b/typings/get-monorepo-packages.d.ts @@ -0,0 +1,9 @@ +declare module 'get-monorepo-packages' { + export default function getPackages(pathToRoot: string): { + location: string + package: { + name: string + version: string + } + }[] +} diff --git a/typings/spawn.d.ts b/typings/spawn.d.ts new file mode 100644 index 000000000..35d328edb --- /dev/null +++ b/typings/spawn.d.ts @@ -0,0 +1,10 @@ +declare module '@npmcli/promise-spawn' { + import { EventEmitter } from 'events' + import { SpawnOptions } from 'child_process' + + export default function spawn( + cmd: string, + args?: string[], + opts?: SpawnOptions + ): Promise<{ stdout: Buffer; code: number; stderr: Buffer }> & EventEmitter +} diff --git a/yarn.lock b/yarn.lock index 5985873af..9f6efe1a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1460,6 +1460,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/promise-spawn@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/promise-spawn@npm:3.0.0" + dependencies: + infer-owner: ^1.0.4 + checksum: 3454465a2731cea5875ba51f80873e2205e5bd878c31517286b0ede4ea931c7bf3de895382287e906d03710fff6f9e44186bd0eee068ce578901c5d3b58e7692 + languageName: node + linkType: hard + "@polka/url@npm:^1.0.0-next.9": version: 1.0.0-next.11 resolution: "@polka/url@npm:1.0.0-next.11" @@ -3918,6 +3927,7 @@ __metadata: dependencies: "@changesets/changelog-github": ^0.4.5 "@changesets/cli": ^2.23.2 + "@npmcli/promise-spawn": ^3.0.0 "@types/jest": ^28.1.1 "@typescript-eslint/eslint-plugin": ^5.21.0 "@typescript-eslint/parser": ^5.21.0 @@ -3925,6 +3935,7 @@ __metadata: eslint: ^8.14.0 eslint-config-prettier: ^8.5.0 eslint-plugin-prettier: ^4.0.0 + get-monorepo-packages: ^1.2.0 husky: ^8.0.0 jest: ^28.1.0 lint-staged: ^13.0.0 @@ -4106,6 +4117,15 @@ __metadata: languageName: node linkType: hard +"array-union@npm:^1.0.1": + version: 1.0.2 + resolution: "array-union@npm:1.0.2" + dependencies: + array-uniq: ^1.0.1 + checksum: 82cec6421b6e6766556c484835a6d476a873f1b71cace5ab2b4f1b15b1e3162dc4da0d16f7a2b04d4aec18146c6638fe8f661340b31ba8e469fd811a1b45dc8d + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -4113,6 +4133,13 @@ __metadata: languageName: node linkType: hard +"array-uniq@npm:^1.0.1": + version: 1.0.3 + resolution: "array-uniq@npm:1.0.3" + checksum: 1625f06b093d8bf279b81adfec6e72951c0857d65b5e3f65f053fffe9f9dd61c2fc52cff57e38a4700817e7e3f01a4faa433d505ea9e33cdae4514c334e0bf9e + languageName: node + linkType: hard + "array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.2.5": version: 1.3.0 resolution: "array.prototype.flat@npm:1.3.0" @@ -5443,6 +5470,15 @@ __metadata: languageName: node linkType: hard +"dir-glob@npm:^2.0.0": + version: 2.2.2 + resolution: "dir-glob@npm:2.2.2" + dependencies: + path-type: ^3.0.0 + checksum: 3aa48714a9f7845ffc30ab03a5c674fe760477cc55e67b0847333371549227d93953e6627ec160f75140c5bea5c5f88d13c01de79bd1997a588efbcf06980842 + languageName: node + linkType: hard + "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -6942,6 +6978,16 @@ __metadata: languageName: node linkType: hard +"get-monorepo-packages@npm:^1.2.0": + version: 1.2.0 + resolution: "get-monorepo-packages@npm:1.2.0" + dependencies: + globby: ^7.1.1 + load-json-file: ^4.0.0 + checksum: f9321c11b8e11f02138758db6589d8ab8b7e1b05e78cac92493b635faea10aa100c20fe40f2cf110c82ec100c118c6c131dff4c65d32a721c617dc2928f7b277 + languageName: node + linkType: hard + "get-package-type@npm:^0.1.0": version: 0.1.0 resolution: "get-package-type@npm:0.1.0" @@ -7014,31 +7060,31 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4": - version: 7.1.6 - resolution: "glob@npm:7.1.6" +"glob@npm:^7.1.2, glob@npm:^7.2.0": + version: 7.2.3 + resolution: "glob@npm:7.2.3" dependencies: fs.realpath: ^1.0.0 inflight: ^1.0.4 inherits: 2 - minimatch: ^3.0.4 + minimatch: ^3.1.1 once: ^1.3.0 path-is-absolute: ^1.0.0 - checksum: 351d549dd90553b87c2d3f90ce11aed9e1093c74130440e7ae0592e11bbcd2ce7f0ebb8ba6bfe63aaf9b62166a7f4c80cb84490ae5d78408bb2572bf7d4ee0a6 + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 languageName: node linkType: hard -"glob@npm:^7.2.0": - version: 7.2.3 - resolution: "glob@npm:7.2.3" +"glob@npm:^7.1.3, glob@npm:^7.1.4": + version: 7.1.6 + resolution: "glob@npm:7.1.6" dependencies: fs.realpath: ^1.0.0 inflight: ^1.0.4 inherits: 2 - minimatch: ^3.1.1 + minimatch: ^3.0.4 once: ^1.3.0 path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + checksum: 351d549dd90553b87c2d3f90ce11aed9e1093c74130440e7ae0592e11bbcd2ce7f0ebb8ba6bfe63aaf9b62166a7f4c80cb84490ae5d78408bb2572bf7d4ee0a6 languageName: node linkType: hard @@ -7121,6 +7167,20 @@ __metadata: languageName: node linkType: hard +"globby@npm:^7.1.1": + version: 7.1.1 + resolution: "globby@npm:7.1.1" + dependencies: + array-union: ^1.0.1 + dir-glob: ^2.0.0 + glob: ^7.1.2 + ignore: ^3.3.5 + pify: ^3.0.0 + slash: ^1.0.0 + checksum: f0eba08a08ae7c98149a4411661c0bf08c4717d81e6f355cf624fb01880b249737eb8e951bf86124cb3af8ea1c793c0a9d363ed5cdec99bb2c6b68f8a323025f + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4": version: 4.2.4 resolution: "graceful-fs@npm:4.2.4" @@ -7391,6 +7451,13 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^3.3.5": + version: 3.3.10 + resolution: "ignore@npm:3.3.10" + checksum: 23e8cc776e367b56615ab21b78decf973a35dfca5522b39d9b47643d8168473b0d1f18dd1321a1bab466a12ea11a2411903f3b21644f4d5461ee0711ec8678bd + languageName: node + linkType: hard + "ignore@npm:^5.1.4": version: 5.1.8 resolution: "ignore@npm:5.1.8" @@ -8604,7 +8671,7 @@ __metadata: languageName: node linkType: hard -"json-parse-better-errors@npm:^1.0.2": +"json-parse-better-errors@npm:^1.0.1, json-parse-better-errors@npm:^1.0.2": version: 1.0.2 resolution: "json-parse-better-errors@npm:1.0.2" checksum: ff2b5ba2a70e88fd97a3cb28c1840144c5ce8fae9cbeeddba15afa333a5c407cf0e42300cd0a2885dbb055227fe68d405070faad941beeffbfde9cf3b2c78c5d @@ -8875,6 +8942,18 @@ __metadata: languageName: node linkType: hard +"load-json-file@npm:^4.0.0": + version: 4.0.0 + resolution: "load-json-file@npm:4.0.0" + dependencies: + graceful-fs: ^4.1.2 + parse-json: ^4.0.0 + pify: ^3.0.0 + strip-bom: ^3.0.0 + checksum: 8f5d6d93ba64a9620445ee9bde4d98b1eac32cf6c8c2d20d44abfa41a6945e7969456ab5f1ca2fb06ee32e206c9769a20eec7002fe290de462e8c884b6b8b356 + languageName: node + linkType: hard + "load-yaml-file@npm:^0.2.0": version: 0.2.0 resolution: "load-yaml-file@npm:0.2.0" @@ -10011,6 +10090,16 @@ __metadata: languageName: node linkType: hard +"parse-json@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-json@npm:4.0.0" + dependencies: + error-ex: ^1.3.1 + json-parse-better-errors: ^1.0.1 + checksum: 0fe227d410a61090c247e34fa210552b834613c006c2c64d9a05cfe9e89cf8b4246d1246b1a99524b53b313e9ac024438d0680f67e33eaed7e6f38db64cfe7b5 + languageName: node + linkType: hard + "parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -10107,6 +10196,15 @@ __metadata: languageName: node linkType: hard +"path-type@npm:^3.0.0": + version: 3.0.0 + resolution: "path-type@npm:3.0.0" + dependencies: + pify: ^3.0.0 + checksum: 735b35e256bad181f38fa021033b1c33cfbe62ead42bb2222b56c210e42938eecb272ae1949f3b6db4ac39597a61b44edd8384623ec4d79bfdc9a9c0f12537a6 + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -10151,6 +10249,13 @@ __metadata: languageName: node linkType: hard +"pify@npm:^3.0.0": + version: 3.0.0 + resolution: "pify@npm:3.0.0" + checksum: 6cdcbc3567d5c412450c53261a3f10991665d660961e06605decf4544a61a97a54fefe70a68d5c37080ff9d6f4cf51444c90198d1ba9f9309a6c0d6e9f5c4fde + languageName: node + linkType: hard + "pify@npm:^4.0.1": version: 4.0.1 resolution: "pify@npm:4.0.1" @@ -11308,6 +11413,13 @@ __metadata: languageName: node linkType: hard +"slash@npm:^1.0.0": + version: 1.0.0 + resolution: "slash@npm:1.0.0" + checksum: 4b6e21b1fba6184a7e2efb1dd173f692d8a845584c1bbf9dc818ff86f5a52fc91b413008223d17cc684604ee8bb9263a420b1182027ad9762e35388434918860 + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0"