diff --git a/README.md b/README.md index 4a0cabc..2e556dc 100644 --- a/README.md +++ b/README.md @@ -126,9 +126,28 @@ Hook | Description `prepare` | Called when the release is about to be prepared. This is before updating files such as package.json, CHANGELOG.md and pushing a commit. It provides a reference to the **next version** number via the environment variable **NLM_NEXT_VERSION**. +```ts +interface NlmOptions { + acceptInvalidCommits?: boolean; + changelog: { + omit?: string[], + verbose?: boolean + }; + deprecated?: boolean; + emoji?: { + skip?: boolean + set?: {[type: string]: string} + }; + license?: { + files?: string[], + exclude?: string[] + } +} +``` -* `license.files`: List of files and/or directories to add license headers to. -* `license.exclude`: List of files to exclude that would otherwise be included. `nlm` will always exclude +* `license`: + * `files`: List of files and/or directories to add license headers to. + * `exclude`: List of files to exclude that would otherwise be included. `nlm` will always exclude anything in `node_modules`. * `acceptInvalidCommits`: Accept commit messages even if they can't be parsed. It's highly discouraged to use this option. @@ -136,10 +155,13 @@ anything in `node_modules`. * `deprecated`: String (may be empty) describing reason this package has been deprecated. To deprecate a package, set it to a descriptive reason. To "un-deprecate" a package, set it to an empty string (can then be later deleted). +* `changelog`: + * `omit`: Array of types, which will be omitted from the changelog. + * `verbose`: Display PR's commits. Default: `false` * `emoji`: Configure changelog emoji setting logic - * `emoji.skip`: deactivates emoji in changelog. Default: `null` - * `emoji.set`: Custom emojis map, which will overwrite the default one + * `skip`: deactivates emoji in changelog. Default: `null` + * `set`: Custom emojis map, which will overwrite the default one Example for ```json5 @@ -157,18 +179,20 @@ Example for The default emojis for the commit types are: ```json5 { - "feat": "✨", + + "breaking": "đŸ’Ĩ", + "feat": "🚀", "fix": "🐛", "perf": "⚡", "refactor": "đŸ“Ļī¸", - "chore": "â™ģī¸", - "build": "👷", "revert": "↩ī¸", "docs": "📝", - "style": "🎨", - "test": "✅", - "ci": "💚", - "breaking": "đŸ’Ĩ" // this emoji will be set before the "Breaking Change" section + "style": "💅", + + // internal types + "deps": "đŸ”ŧ", // will be set when dependencies are found in PR commit subject + "internal": "🏡", // will be set for types: "chore", "build", "test", "ci" or commits without type + } ``` diff --git a/lib/cli.js b/lib/cli.js index 3391402..5d49946 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -106,5 +106,7 @@ if (argv.version) { // eslint-disable-next-line import/no-dynamic-require const pkg = require(packageJsonFile); - command(cwd, pkg, { ...argv, ...pkg.nlm }).catch(prettyPrintErrorAndExit); + command(cwd, pkg, { ...argv, ...pkg.nlm, nlmOptions: { ...pkg.nlm } }).catch( + prettyPrintErrorAndExit + ); } diff --git a/lib/commands/verify.js b/lib/commands/verify.js index 48a1d09..ece915e 100644 --- a/lib/commands/verify.js +++ b/lib/commands/verify.js @@ -107,9 +107,9 @@ function verify(cwd, pkg, options) { const { releaseType } = options; const nextUpdate = releaseType !== 'none' - ? `${pkg.version} -> ${semver.inc(pkg.version, releaseType)}` + ? `(${pkg.version} -> ${semver.inc(pkg.version, releaseType)})` : ''; - console.log('[nlm] Changes are %j (%s)', releaseType, nextUpdate); + console.log('[nlm] Changes are %j %s', releaseType, nextUpdate); } const verifyTasks = [ diff --git a/lib/steps/changelog.js b/lib/steps/changelog.js index e0eb4d9..a3be9ac 100644 --- a/lib/steps/changelog.js +++ b/lib/steps/changelog.js @@ -32,32 +32,196 @@ 'use strict'; +/** + * @typedef PR + * @property {number} pullId + * @property {{name: string, href: string}} author + * @property {string} href + * @property {string} title + * @property {string[]} shas + * @property {Commit[]} commits + */ + +/** + * @typedef Commit + * @extends PR + * @property {string} type + * @property {string} header + * @property {string} subject + * @property {string} sha + * @property {{title: string, text:string}[]} notes + * @property {{prefix: string, issue: number, href: string}[]} references + */ + +/** + * @typedef RepoInfo + * @property {string} htmlBase + * @property {string} username + * @property {string} repository + */ + +/** + * @typedef NlmOptions + * @property {{skip?: boolean, set: {[type: string]: string}}} emoji + * @property {{verbose?: boolean, omit?: string[]}} changelog + */ + +const replaceAll = require('string.prototype.replaceall'); + const Github = require('../github/client'); const parseRepository = require('../github/parse-repository'); +const DEP_REGEXP = /(`)?([@\w\/-_.]+[@\s]v?\d+[0-9x.]+)(`)?/gim; + const emojiMaps = new Map([ [ 'default', { + // angular types: breaking: 'đŸ’Ĩ', - feat: '✨', - fix: '🐛', + feat: '🚀', perf: '⚡', refactor: 'đŸ“Ļī¸', - chore: 'â™ģī¸', - build: '👷', + fix: '🐛', revert: '↩ī¸', + style: '💅', docs: '📝', - style: '🎨', - test: '✅', - ci: '💚', + + // internal types: + deps: 'đŸ”ŧ', + internal: '🏡', }, ], ]); -function addPullRequestCommits(pkg, commits, pr) { - const github = Github.forRepository(pkg.repository); +/** + * @param {string} type + * @param {{nlmOptions?: NlmOptions}} options + * @return {string} + */ +function getTypeCategory(type, options) { + const { nlmOptions = {} } = options; + const { emoji: emojiOpts = {} } = nlmOptions; + + let descr; + const headlineLevel = '####'; + + switch (type) { + case 'breaking': + descr = 'Breaking Changes'; + break; + + case 'feat': + descr = 'New Features'; + break; + + case 'perf': + descr = 'Performance Improvements'; + break; + + case 'refactor': + descr = 'Code Refactoring'; + break; + + case 'fix': + descr = 'Bug Fixes'; + break; + + case 'dep': + descr = 'Dependencies'; + break; + + case 'revert': + descr = 'Reverts'; + break; + + case 'docs': + descr = 'Documentation'; + break; + + case 'style': + descr = 'Polish'; + break; + + default: + descr = 'Internal'; + } + + const emojiSet = { ...emojiMaps.get('default'), ...(emojiOpts.set || {}) }; + const emoji = !emojiOpts.skip ? emojiSet[type] || emojiSet['internal'] : ''; + + return (emoji ? [headlineLevel, emoji, descr] : [headlineLevel, descr]).join( + ' ' + ); +} + +/** + * @param {*[]} data + * @return {*[]} + */ +function sortByType(data) { + if (!data.length) { + return []; + } + + const sorted = []; + [ + 'breaking', + 'feat', + 'perf', + 'refactor', + 'fix', + 'dep', + 'revert', + 'style', + 'docs', + ].forEach(type => { + data = data.reduce((acc, entry) => { + if (entry[0] === type) { + sorted.push(entry); + } else { + acc.push(entry); + } + return acc; + }, []); + }); + + return sorted.concat(data); +} + +/** + * @param {string} title + * @return {string} + */ +function getType(title) { + const match = title.match(/^(\w+):/); + let type = match && match[1]; + if (findDependency(title)) { + type = 'dep'; + } + return type || 'internal'; +} + +/** + * @param {String} str + * @return {RegExpMatchArray|null} + */ +function findDependency(str) { + return str.match(DEP_REGEXP); +} + +/** + * + * @param {Object} github + * @param {Commit[]} commits + * @param {PR} pr + * @return {Promise} + */ +function addPullRequestCommits(github, commits, pr) { + pr.commits = null; + pr.shas = null; + return Promise.all([ github.pull.get(pr.pullId), github.pull.commits(pr.pullId), @@ -69,29 +233,40 @@ function addPullRequestCommits(pkg, commits, pr) { }; pr.href = info.html_url; pr.title = info.title || info.header; - const shas = (pr.shas = prCommits.map(c => c.sha)); - pr.commits = commits.filter(commit => shas.includes(commit.sha)); + pr.shas = prCommits.map(c => c.sha); + pr.commits = commits.filter(commit => pr.shas.includes(commit.sha)); }) .catch(err => { if (err.statusCode !== 404) throw err; // If the PR doesn't exist, handle it gracefully. - - pr.commits = pr.shas = null; }); } +/** + * @param {*[]} arrs + * @return {*[]} + */ function flatten(arrs) { return [].concat.apply([], arrs); } -function removePRCommits(commits, prs) { +/** + * @param {PR[]} prs + * @param {Commit[]} commits + * @return {*[]|Commit[]} + */ +function removePRCommits(prs, commits) { const prShas = flatten(prs.map(pr => pr.shas)); return commits.filter( commit => commit.type !== 'pr' && !prShas.includes(commit.sha) ); } +/** + * @param {Commit} commit + * @return {*[]|{commit: Commit, text: string}[]} + */ function extractBreakingChanges(commit) { - if (!commit.notes || !commit.notes.length) { + if (!(commit.notes && commit.notes.length)) { return []; } @@ -105,6 +280,9 @@ function extractBreakingChanges(commit) { }); } +/** + * @param {PR[]} prs + */ function removeInvalidPRs(prs) { // Warning: We're doing something evil here and mutate the input array. const filtered = prs.filter(pr => { @@ -114,101 +292,195 @@ function removeInvalidPRs(prs) { Object.assign(prs, filtered); } -async function generateChangeLog(cwd, pkg, options) { - const repoInfo = parseRepository(pkg.repository); - const { commits, emoji = {} } = options; - let emojiSet = {}; - if (!emoji.skip) { - emojiSet = { ...emojiMaps.get('default'), ...(emoji.set || {}) }; +/** + * @param {{prefix: string, issue: number, href: string}[]} refs + * @return {string} + */ +function formatReferences(refs) { + if (!refs || refs.length === 0) { + return ''; } - const prs = commits.filter(c => c.type === 'pr'); - function getCommitLink(commit) { - const abbr = commit.sha.substr(0, 7); - const href = [ - repoInfo.htmlBase, - repoInfo.username, - repoInfo.repository, - 'commit', - commit.sha, - ].join('/'); - return `[\`${abbr}\`](${href})`; - } + const references = refs.map(ref => { + return `[${ref.prefix}${ref.issue}](${ref.href})`; + }); + + return ` - see: ${references.join(', ')}`; +} - function formatBreakingChange(change) { - return `${change.text}\n\n*See: ${getCommitLink(change.commit)}*`; +/** + * @param {Commit} commit + * @param {RepoInfo} repoInfo + * @return {string} + */ +function getCommitLink(commit, repoInfo) { + const abbr = commit.sha.substr(0, 7); + const href = [ + repoInfo.htmlBase, + repoInfo.username, + repoInfo.repository, + 'commit', + commit.sha, + ].join('/'); + return `[\`${abbr}\`](${href})`; +} + +/** + * @param {{text: string, commit: Commit}} change + * @param {RepoInfo} repoInfo + * @return {string} + */ +function formatBreakingChange(change, repoInfo) { + return `${change.text}\n\n*See: ${getCommitLink(change.commit, repoInfo)}*`; +} + +/** + * @param {Commit[]} commits + * @param {{nlmOptions?: NlmOptions}} options}} options + * @param {RepoInfo} repoInfo + * @return {*[]|(string)[][]} + */ +function getBreakingChanges(commits, options, repoInfo) { + const breaking = flatten(commits.map(extractBreakingChanges)); + if (!breaking.length) { + return []; } - function prependBreakingChanges(changelog) { - const breaking = flatten(commits.map(extractBreakingChanges)); - if (!breaking.length) return changelog; - return `#### ${ - !emoji.skip ? `${emojiSet['breaking']} ` : '' - }Breaking Changes + const breakingChanges = breaking + .map(change => formatBreakingChange(change, repoInfo)) + .join('\n\n'); -${breaking.map(formatBreakingChange).join('\n\n')} + return [['breaking', breakingChanges]]; +} -#### Commits +/** + * @param {Commit} commit + * @param {RepoInfo} repoInfo + * @return {string} + */ +function formatCommit(commit, repoInfo) { + let subject; -${changelog}`; + if (commit.type) { + subject = `${commit.type}: ${commit.subject}`; + } else { + subject = commit.header; } - function formatReference(ref) { - return `[${ref.prefix}${ref.issue}](${ref.href})`; + if (findDependency(subject)) { + subject = replaceAll(subject, DEP_REGEXP, '`$2`'); } - function formatReferences(refs) { - if (!refs || refs.length === 0) return ''; - return ` - see: ${refs.map(formatReference).join(', ')}`; - } + return `${getCommitLink(commit, repoInfo)} ${subject}${formatReferences( + commit.references + )}`; +} + +/** + * @param {PR} pr + * @param {{nlmOptions?: NlmOptions}} options + * @param {RepoInfo} repoInfo + * @return {string} + */ +function formatPR(pr, options, repoInfo) { + const { nlmOptions = {} } = options; + const changes = + nlmOptions.changelog && nlmOptions.changelog.verbose + ? pr.commits.map(commit => { + return ` - ${formatCommit(commit, repoInfo)}`; + }) + : []; - function formatCommit(commit) { - let subject; + const titleLine = `[#${pr.pullId}](${pr.href}) ${pr.title} ([@${pr.author.name}](${pr.author.href})) `; - if (commit.type) { - subject = `${!emoji.skip ? `${emojiSet[commit.type]} ` : ''}**${ - commit.type - }:** ${commit.subject}`; - } else { - subject = commit.header; + return [titleLine].concat(changes).join('\n'); +} + +/** + * @param {PR[]} rawPRs + * @param {Commit[]} rawCommits + * @param {{nlmOptions?: NlmOptions}} options + * @param {RepoInfo} repoInfo + * @return {*[]|[string, string][]} + */ +function format(rawPRs, rawCommits, options, repoInfo) { + const orphansCommits = rawCommits.map(commit => [ + getType(`${commit.type}: ${commit.subject}`), + formatCommit(commit, repoInfo), + ]); + + return rawPRs + .map(pr => [getType(pr.title), formatPR(pr, options, repoInfo)]) + .concat(orphansCommits) + .map(([type, line]) => [type, `* ${line}`]); +} + +/** + * @param {[string, string][]|*[]} data + * @param {{nlmOptions?: NlmOptions}} options + * @return {string} + */ +function mergeChangelog(data, options) { + const { nlmOptions = {} } = options; + const changelog = new Map(); + const sorted = sortByType(data); + + for (const [type, entry] of sorted) { + const category = getTypeCategory(type, options); + + // filter out types + if (nlmOptions.changelog && nlmOptions.changelog.omit) { + if (nlmOptions.changelog.omit.includes(type)) continue; } - return `${getCommitLink(commit)} ${subject}${formatReferences( - commit.references - )}`; + if (!changelog.has(category)) { + changelog.set(category, [entry]); + } else { + changelog.set(category, changelog.get(category).concat(entry)); + } } - function formatPR(pr) { - const changes = pr.commits.map(formatCommit).map(line => { - return ` - ${line}`; - }); - const titleLine = `${pr.title} - **[@${pr.author.name}](${pr.author.href})** [#${pr.pullId}](${pr.href})`; - return [titleLine].concat(changes).join('\n'); - } - /* - * * {prTitle} - @{author} #{pullId} - * - {sha} {type}: {message} - * * {sha} {type}: {message} - */ - - function formatCommits(orphans) { - const changes = prs - .map(formatPR) - .concat(orphans.map(formatCommit)) - .map(line => { - return `* ${line}`; - }); - return changes.join('\n'); - } + return [...changelog] + .map(([headline, entries]) => `${headline}\n\n${entries.join('\n')}`) + .join('\n\n'); +} - for (const pr of prs) await addPullRequestCommits(pkg, commits, pr); +/** + * @param {*} cwd + * @param {{repository: string|{url: string}}} pkg + * @param {{commits: Commit[], nlmOptions?: NlmOptions, changelog?: string}} options + * @return {Promise} + */ +async function generateChangeLog(cwd, pkg, options) { + const { commits } = options; + const repoInfo = parseRepository(pkg.repository); + const github = Github.forRepository(pkg.repository); + /** @type {PR[]} */ + const prs = commits.filter(c => c.type === 'pr'); + + // step1: fetch PR commits data from GH & match with commits + for (const pr of prs) { + await addPullRequestCommits(github, commits, pr); + } + + // step2: remove PRs without commits removeInvalidPRs(prs); - let changelog = removePRCommits(commits, prs); - changelog = formatCommits(changelog); - changelog = prependBreakingChanges(changelog); - options.changelog = changelog; - return changelog; + + // step3: remove commits of type `pr` + const cleanedCommits = removePRCommits(prs, commits); + + // step4: generate PRs / commits changelog entries + const data = format(prs, cleanedCommits, options, repoInfo); + + // step5: scan commits for breaking changes + const breakingChanges = getBreakingChanges(commits, options, repoInfo); + + // step6: build changelog + options.changelog = mergeChangelog(breakingChanges.concat(data), options); + + return options.changelog; } +generateChangeLog.emojiMaps = emojiMaps; module.exports = generateChangeLog; diff --git a/lib/steps/version-commit.js b/lib/steps/version-commit.js index 85cca18..51f772a 100644 --- a/lib/steps/version-commit.js +++ b/lib/steps/version-commit.js @@ -103,15 +103,18 @@ function createVersionCommit(cwd, pkg, options) { changeLogContent = ''; } - changeLogContent = `### ${options.nextVersion} - ${getCurrentDate()}\n\n${ + changeLogContent = `### v${options.nextVersion} (${getCurrentDate()})\n\n${ options.changelog }${changeLogContent}`; fs.writeFileSync(changeLogFile, `${changeLogContent.trim()}\n`); + const packageJsonFile = path.join(cwd, 'package.json'); pkg.version = options.nextVersion; fs.writeFileSync(packageJsonFile, `${JSON.stringify(pkg, null, 2)}\n`); + const files = ['CHANGELOG.md', 'package.json']; updatePackageLockVersion(cwd, pkg.version, files); + return addFiles(cwd, files) .then(commit.bind(null, cwd, `v${pkg.version}`)) .then(getHEAD.bind(null, cwd)) diff --git a/package-lock.json b/package-lock.json index 9f8e9c4..a5712e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,16 +11,16 @@ "conventional-commits-parser": "^3.1.0", "debug": "^4.2.0", "glob": "^7.1.6", - "gofer": "^5.0.3", + "gofer": "^5.0.4", "minimist": "^1.2.5", "rc": "^1.2.8", - "semver": "^7.3.2" + "semver": "^7.3.2", + "string.prototype.replaceall": "^1.0.3" }, "bin": { "nlm": "bin/nlm.js" }, "devDependencies": { - "assertive": "^5.0.2", "eslint": "^7.12.1", "eslint-config-groupon": "^10.0.1", "eslint-plugin-import": "^2.22.1", @@ -84,12 +84,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.1.tgz", - "integrity": "sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", "dev": true, "dependencies": { - "@babel/types": "^7.12.1", + "@babel/types": "^7.12.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -124,12 +124,12 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.1.tgz", - "integrity": "sha512-ZeC1TlMSvikvJNy1v/wPIazCu3NdOwgYZLIkmIyAsGhqkNpiDoQQRmaCK8YP4Pq3GPTLPV9WXaPCJKvx06JxKA==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", "dev": true, "dependencies": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.12.5" } }, "node_modules/@babel/helper-module-transforms": { @@ -159,15 +159,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.1.tgz", - "integrity": "sha512-zJjTvtNJnCFsCXVi5rUInstLd/EIVNmIKA1Q9ynESmMBWPWd+7sdR+G4/wdu+Mppfep0XLyG2m7EBPvjCeFyrw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", "dev": true, "dependencies": { "@babel/helper-member-expression-to-functions": "^7.12.1", "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1" + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" } }, "node_modules/@babel/helper-simple-access": { @@ -194,14 +194,14 @@ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, "node_modules/@babel/helpers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.1.tgz", - "integrity": "sha512-9JoDSBGoWtmbay98efmT2+mySkwjzeFeAL9BuWNoVQpkPFQF8SIIFUfY5os9u8wVzglzoiPRSW7cuJmBDUt43g==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", "dev": true, "dependencies": { "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1" + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" } }, "node_modules/@babel/highlight": { @@ -279,9 +279,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.3.tgz", - "integrity": "sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -302,17 +302,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.1.tgz", - "integrity": "sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", + "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", + "@babel/generator": "^7.12.5", "@babel/helper-function-name": "^7.10.4", "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.1", - "@babel/types": "^7.12.1", + "@babel/parser": "^7.12.5", + "@babel/types": "^7.12.5", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -328,9 +328,9 @@ } }, "node_modules/@babel/types": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz", - "integrity": "sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.5.tgz", + "integrity": "sha512-gyTcvz7JFa4V45C0Zklv//GmFOAal5fL23OWpBLqc4nZ4Yrz67s4kCNwSK1Gu0MXGTU8mRY3zJYtacLdKXlzig==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.10.4", @@ -631,20 +631,6 @@ "node": ">=0.10.0" } }, - "node_modules/assertive": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/assertive/-/assertive-5.0.2.tgz", - "integrity": "sha512-zvQkb694hAx3YC8f+eDqDoRmvrm/NkIbfS7EVUFiAmi6tXuJzoE4n2k/Y1UmTiCY3D2ePi9KL7TxJUx935/eaA==", - "dev": true, - "dependencies": { - "lodash.isequal": "^4.5.0" - }, - "engines": { - "node": ">=10.3.0", - "npm": "^6.1.0", - "yarn": "0.0.0" - } - }, "node_modules/astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -710,6 +696,18 @@ "node": ">=8" } }, + "node_modules/call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -982,7 +980,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "dependencies": { "object-keys": "^1.0.12" }, @@ -1041,7 +1038,6 @@ "version": "1.17.7", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, "dependencies": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -1066,7 +1062,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -1695,9 +1690,9 @@ } }, "node_modules/fromentries": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.0.tgz", - "integrity": "sha512-+pKvlQHvpxxSTF+tWZ4DjxD0Sz4G26EjAP4z7D2k8VLJ19hrLbSgaQLx/u2mVQn7hiA2s/3DyutOyFwTuDsRgA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.1.tgz", + "integrity": "sha512-w4t/zm2J+uAcrpeKyW0VmYiIs3aqe/xKQ+2qwazVNZSCklQHhaVjk6XzKw5GtImq5thgL0IVRjGRAOastb08RQ==", "dev": true, "funding": [ { @@ -1745,9 +1740,9 @@ "dev": true }, "node_modules/gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1762,6 +1757,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -1818,9 +1826,9 @@ } }, "node_modules/gofer": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gofer/-/gofer-5.0.3.tgz", - "integrity": "sha512-pDq3OhpopYNJCynBKPm6DThwdeHS6bWU5Yrv3/FEUSRyTbqw5mxpEOi03X2Ik9iU04EqCu1dwAiJhXruanm8Eg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gofer/-/gofer-5.0.4.tgz", + "integrity": "sha512-0aPot92f+jjgxzgKFChWUEaofhES/QLq7JQV0BUbg016YMegPsr8nwWxuSstlY0Ske24b1b12NMwbeokM2nU/A==", "dependencies": { "debug": "^4.2.0", "lodash.isobjectlike": "^4.0.0", @@ -1879,7 +1887,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -1933,9 +1940,9 @@ } }, "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", "dev": true, "dependencies": { "parent-module": "^1.0.0", @@ -2005,7 +2012,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2028,7 +2034,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2070,7 +2075,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", - "dev": true, "engines": { "node": ">= 0.4" } @@ -2096,7 +2100,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.1" }, @@ -2132,7 +2135,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.1" }, @@ -2469,12 +2471,6 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, "node_modules/lodash.isobjectlike": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/lodash.isobjectlike/-/lodash.isobjectlike-4.0.0.tgz", @@ -2735,9 +2731,9 @@ } }, "node_modules/mocha": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", - "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", @@ -3048,7 +3044,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3057,19 +3052,17 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "dev": true, + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dependencies": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", "has-symbols": "^1.0.1", "object-keys": "^1.1.1" }, @@ -3080,32 +3073,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.assign/node_modules/es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", @@ -3971,11 +3938,25 @@ "node": ">=6" } }, + "node_modules/string.prototype.replaceall": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.replaceall/-/string.prototype.replaceall-1.0.3.tgz", + "integrity": "sha512-GF8JS9jtHSDkIsVMsYBPR4dItwaU6xOSPsMcRGTAbBr12ZDfyKMtgxdC2HDFbsMogGel29pmwxioJoXeu9ztIg==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-regex": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trimend": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", - "dev": true, "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.1" @@ -3988,7 +3969,6 @@ "version": "1.18.0-next.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, "dependencies": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -4014,7 +3994,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", - "dev": true, "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.1" @@ -4027,7 +4006,6 @@ "version": "1.18.0-next.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, "dependencies": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -4286,9 +4264,9 @@ } }, "node_modules/v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", "dev": true }, "node_modules/validate-npm-package-license": { @@ -4530,9 +4508,9 @@ } }, "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.1.0.tgz", - "integrity": "sha512-WCMml9ivU60+8rEJgELlFp1gxFcEGxwYleE3bziHEDeqsqAWGHdimB7beBFGjLzVNgPGyDsfgXLQEYMpmIFnVQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true, "engines": { "node": ">=10" @@ -4676,12 +4654,12 @@ } }, "@babel/generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.1.tgz", - "integrity": "sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", "dev": true, "requires": { - "@babel/types": "^7.12.1", + "@babel/types": "^7.12.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -4716,12 +4694,12 @@ } }, "@babel/helper-module-imports": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.1.tgz", - "integrity": "sha512-ZeC1TlMSvikvJNy1v/wPIazCu3NdOwgYZLIkmIyAsGhqkNpiDoQQRmaCK8YP4Pq3GPTLPV9WXaPCJKvx06JxKA==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.12.5" } }, "@babel/helper-module-transforms": { @@ -4751,15 +4729,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.1.tgz", - "integrity": "sha512-zJjTvtNJnCFsCXVi5rUInstLd/EIVNmIKA1Q9ynESmMBWPWd+7sdR+G4/wdu+Mppfep0XLyG2m7EBPvjCeFyrw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.12.1", "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1" + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" } }, "@babel/helper-simple-access": { @@ -4786,14 +4764,14 @@ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, "@babel/helpers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.1.tgz", - "integrity": "sha512-9JoDSBGoWtmbay98efmT2+mySkwjzeFeAL9BuWNoVQpkPFQF8SIIFUfY5os9u8wVzglzoiPRSW7cuJmBDUt43g==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", "dev": true, "requires": { "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1" + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" } }, "@babel/highlight": { @@ -4858,9 +4836,9 @@ } }, "@babel/parser": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.3.tgz", - "integrity": "sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", "dev": true }, "@babel/template": { @@ -4875,17 +4853,17 @@ } }, "@babel/traverse": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.1.tgz", - "integrity": "sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", + "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", + "@babel/generator": "^7.12.5", "@babel/helper-function-name": "^7.10.4", "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.1", - "@babel/types": "^7.12.1", + "@babel/parser": "^7.12.5", + "@babel/types": "^7.12.5", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -4900,9 +4878,9 @@ } }, "@babel/types": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz", - "integrity": "sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.5.tgz", + "integrity": "sha512-gyTcvz7JFa4V45C0Zklv//GmFOAal5fL23OWpBLqc4nZ4Yrz67s4kCNwSK1Gu0MXGTU8mRY3zJYtacLdKXlzig==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", @@ -5130,15 +5108,6 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, - "assertive": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/assertive/-/assertive-5.0.2.tgz", - "integrity": "sha512-zvQkb694hAx3YC8f+eDqDoRmvrm/NkIbfS7EVUFiAmi6tXuJzoE4n2k/Y1UmTiCY3D2ePi9KL7TxJUx935/eaA==", - "dev": true, - "requires": { - "lodash.isequal": "^4.5.0" - } - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -5192,6 +5161,15 @@ "write-file-atomic": "^3.0.0" } }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5397,7 +5375,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -5444,7 +5421,6 @@ "version": "1.17.7", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -5463,7 +5439,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -5942,9 +5917,9 @@ } }, "fromentries": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.0.tgz", - "integrity": "sha512-+pKvlQHvpxxSTF+tWZ4DjxD0Sz4G26EjAP4z7D2k8VLJ19hrLbSgaQLx/u2mVQn7hiA2s/3DyutOyFwTuDsRgA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.1.tgz", + "integrity": "sha512-w4t/zm2J+uAcrpeKyW0VmYiIs3aqe/xKQ+2qwazVNZSCklQHhaVjk6XzKw5GtImq5thgL0IVRjGRAOastb08RQ==", "dev": true }, "fs.realpath": { @@ -5971,9 +5946,9 @@ "dev": true }, "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, "get-caller-file": { @@ -5982,6 +5957,16 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -6020,9 +6005,9 @@ } }, "gofer": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gofer/-/gofer-5.0.3.tgz", - "integrity": "sha512-pDq3OhpopYNJCynBKPm6DThwdeHS6bWU5Yrv3/FEUSRyTbqw5mxpEOi03X2Ik9iU04EqCu1dwAiJhXruanm8Eg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gofer/-/gofer-5.0.4.tgz", + "integrity": "sha512-0aPot92f+jjgxzgKFChWUEaofhES/QLq7JQV0BUbg016YMegPsr8nwWxuSstlY0Ske24b1b12NMwbeokM2nU/A==", "requires": { "debug": "^4.2.0", "lodash.isobjectlike": "^4.0.0", @@ -6065,8 +6050,7 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "hasha": { "version": "5.2.2", @@ -6102,9 +6086,9 @@ "dev": true }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -6158,8 +6142,7 @@ "is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", - "dev": true + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" }, "is-core-module": { "version": "2.0.0", @@ -6172,8 +6155,7 @@ "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-extglob": { "version": "2.1.1", @@ -6199,8 +6181,7 @@ "is-negative-zero": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", - "dev": true + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" }, "is-number": { "version": "7.0.0", @@ -6217,7 +6198,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -6238,7 +6218,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -6496,12 +6475,6 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, "lodash.isobjectlike": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/lodash.isobjectlike/-/lodash.isobjectlike-4.0.0.tgz", @@ -6695,9 +6668,9 @@ } }, "mocha": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", - "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", @@ -6945,47 +6918,22 @@ "object-inspect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "dev": true, + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", "has-symbols": "^1.0.1", "object-keys": "^1.1.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "object.values": { @@ -7654,11 +7602,22 @@ } } }, + "string.prototype.replaceall": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.replaceall/-/string.prototype.replaceall-1.0.3.tgz", + "integrity": "sha512-GF8JS9jtHSDkIsVMsYBPR4dItwaU6xOSPsMcRGTAbBr12ZDfyKMtgxdC2HDFbsMogGel29pmwxioJoXeu9ztIg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-regex": "^1.0.4" + } + }, "string.prototype.trimend": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.1" @@ -7668,7 +7627,6 @@ "version": "1.18.0-next.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -7690,7 +7648,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.1" @@ -7700,7 +7657,6 @@ "version": "1.18.0-next.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -7903,9 +7859,9 @@ "dev": true }, "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", "dev": true }, "validate-npm-package-license": { @@ -8164,9 +8120,9 @@ }, "dependencies": { "camelcase": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.1.0.tgz", - "integrity": "sha512-WCMml9ivU60+8rEJgELlFp1gxFcEGxwYleE3bziHEDeqsqAWGHdimB7beBFGjLzVNgPGyDsfgXLQEYMpmIFnVQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true }, "decamelize": { diff --git a/package.json b/package.json index 57f2679..6424b4c 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,11 @@ "conventional-commits-parser": "^3.1.0", "debug": "^4.2.0", "glob": "^7.1.6", - "gofer": "^5.0.3", + "gofer": "^5.0.4", "minimist": "^1.2.5", "rc": "^1.2.8", - "semver": "^7.3.2" + "semver": "^7.3.2", + "string.prototype.replaceall": "^1.0.3" }, "devDependencies": { "eslint": "^7.12.1", diff --git a/test/steps/changelog.test.js b/test/steps/changelog.test.js index 4b361ef..0336f6c 100644 --- a/test/steps/changelog.test.js +++ b/test/steps/changelog.test.js @@ -46,7 +46,7 @@ function responseByUrl(url) { html_url: 'http://pr-1-user', }, html_url: 'http://pr-1', - title: 'PR #1 Title', + title: 'feat: PR #1 Title', }); break; @@ -120,10 +120,22 @@ function withFakeGithub() { return httpCalls; } +function assertEntries(changelog, expected) { + const lines = Array.isArray(changelog) ? changelog : changelog.split('\n'); + + return expected.map(entry => { + const index = lines.findIndex(i => i === entry); + assert.ok(index !== -1, expected); + return index; + }); +} + describe('generateChangeLog', () => { const defaultOptions = { - emoji: { - skip: true, + nlmOptions: { + emoji: { + skip: true, + }, }, }; @@ -188,19 +200,16 @@ describe('generateChangeLog', () => { const href1 = `https://github.com/usr/proj/commit/${commits[1].sha}`; const changelog = await generateChangeLog(null, pkg, options); + + const expectedEntries = [ + `* [\`1234567\`](${href0}) fix: Stop doing the wrong thing - see: [fo/ba#7](https://gitub.com/fo/ba/issues/7)`, + `* [\`2234567\`](${href1}) feat: Do more things - see: [THING-2010](https://example.com/browse/THING-7), [#44](https://github.com/usr/proj/issues/44)`, + ]; + const indices = assertEntries(changelog, expectedEntries); const lines = changelog.split('\n'); - assert.strictEqual( - lines[0], - `* [\`1234567\`](${href0}) **fix:** Stop doing the wrong thing - see: ` + - `[fo/ba#7](https://gitub.com/fo/ba/issues/7)` - ); - assert.strictEqual( - lines[1], - `* [\`2234567\`](${href1}) **feat:** Do more things - see: ` + - `[THING-2010](https://example.com/browse/THING-7), ` + - `[#44](https://github.com/usr/proj/issues/44)` - ); + assert.strictEqual(lines[indices[0] - 2], '#### Bug Fixes'); + assert.strictEqual(lines[indices[1] - 2], '#### New Features'); }); it('can create a changelog for two commits', async () => { @@ -228,13 +237,44 @@ describe('generateChangeLog', () => { const changelog = await generateChangeLog(null, pkg, options); - assert.strictEqual( - changelog, - [ - `* [\`1234567\`](${href0}) **fix:** Stop doing the wrong thing`, - `* [\`2234567\`](${href1}) **feat:** Do more things`, - ].join('\n') - ); + const expectedEntries = [ + `* [\`1234567\`](${href0}) fix: Stop doing the wrong thing`, + `* [\`2234567\`](${href1}) feat: Do more things`, + ]; + assertEntries(changelog, expectedEntries); + }); + + it('omits commit types from changelog when specificed in nlm changelog options', async () => { + const pkg = { + repository: 'usr/proj', + }; + const commits = [ + { + sha: '1234567890123456789012345678901234567890', + type: 'fix', + subject: 'Stop doing the wrong thing', + }, + { + sha: '2234567890123456789012345678901234567890', + type: 'feat', + subject: 'Do more things', + }, + ]; + const options = { + commits, + nlmOptions: { + changelog: { + omit: ['fix'], + }, + emoji: { + skip: true, + }, + }, + }; + + const changelog = await generateChangeLog(null, pkg, options); + + assert.ok(!changelog.includes('[`1234567`]')); }); it('puts breaking changes ahead of everything else', async () => { @@ -266,120 +306,85 @@ describe('generateChangeLog', () => { const href0 = `https://github.com/usr/proj/commit/${commits[0].sha}`; const href1 = `https://github.com/usr/proj/commit/${commits[1].sha}`; + const expected = [ + '#### Breaking Changes', + '', + 'The interface of this library changed in some way.', + '', + `*See: [\`2234567\`](${href1})*`, + '', + ].join('\n'); + + const expectedEntries = [ + `* [\`1234567\`](${href0}) fix: Stop doing the wrong thing`, + `* [\`2234567\`](${href1}) feat: Do more things`, + ]; + const changelog = await generateChangeLog(null, pkg, options); - assert.strictEqual( - changelog, - [ - '#### Breaking Changes', - '', - 'The interface of this library changed in some way.', - '', - `*See: [\`2234567\`](${href1})*`, - '', - '#### Commits', - '', - `* [\`1234567\`](${href0}) **fix:** Stop doing the wrong thing`, - `* [\`2234567\`](${href1}) **feat:** Do more things`, - ].join('\n') - ); + + assert.ok(changelog.startsWith(expected)); + assertEntries(changelog, expectedEntries); }); it('handles variants typings of BREAKING CHANGE', async () => { const pkg = { repository: 'usr/proj', }; - const commits = [ + const defaultCommit = { + sha: '2234567890123456789012345678901234567890', + type: 'feat', + subject: 'Do more things', + }; + const testCases = [ { - sha: '2234567890123456789012345678901234567890', - type: 'feat', - subject: 'Do more things', - notes: [ - { - title: 'BREAKING CHANGE', - text: 'without a colon', - }, - ], + title: 'BREAKING CHANGE', + text: 'without a colon', }, { - sha: '2234567890123456789012345678901234567891', - type: 'feat', - subject: 'Do more things', - notes: [ - { - title: 'BREAKING CHANGE:', - text: 'with a colon', - }, - ], + title: 'BREAKING CHANGE:', + text: 'with a colon', }, { - sha: '2234567890123456789012345678901234567892', - type: 'feat', - subject: 'Do more things', - notes: [ - { - title: 'BREAKING CHANGES', - text: 'plural', - }, - ], + title: 'BREAKING CHANGES', + text: 'plural', }, { - sha: '2234567890123456789012345678901234567893', - type: 'feat', - subject: 'Do more things', - notes: [ - { - title: 'BREAKING CHANGES:', - text: 'plural with colon', - }, - ], + title: 'BREAKING CHANGES:', + text: 'plural with colon', }, ]; - const options = { - ...defaultOptions, - commits, - }; - const href0 = `https://github.com/usr/proj/commit/${commits[0].sha}`; - const href1 = `https://github.com/usr/proj/commit/${commits[1].sha}`; - const href2 = `https://github.com/usr/proj/commit/${commits[2].sha}`; - const href3 = `https://github.com/usr/proj/commit/${commits[3].sha}`; - const changelog = await generateChangeLog(null, pkg, options); - assert.strictEqual( - changelog, - [ + for (const commitNote of testCases) { + const commit = { ...defaultCommit, notes: [commitNote] }; + const href0 = `https://github.com/usr/proj/commit/${commit.sha}`; + + const expected = [ '#### Breaking Changes', '', - 'without a colon', + commit.notes.map(note => note.text).join('\n'), '', `*See: [\`2234567\`](${href0})*`, '', - 'with a colon', - '', - `*See: [\`2234567\`](${href1})*`, - '', - 'plural', - '', - `*See: [\`2234567\`](${href2})*`, - '', - 'plural with colon', - '', - `*See: [\`2234567\`](${href3})*`, - '', - '#### Commits', - '', - `* [\`2234567\`](${href0}) **feat:** Do more things`, - `* [\`2234567\`](${href1}) **feat:** Do more things`, - `* [\`2234567\`](${href2}) **feat:** Do more things`, - `* [\`2234567\`](${href3}) **feat:** Do more things`, - ].join('\n') - ); + ].join('\n'); + + const changelog = await generateChangeLog(null, pkg, { + ...defaultOptions, + commits: [commit], + }); + + assert.ok(changelog.startsWith(expected)); + + assertEntries(changelog, [ + `* [\`2234567\`](${href0}) feat: Do more things`, + ]); + } }); describe('PRs', () => { - const pkg = { - repository: 'http://127.0.0.1:3000/usr/proj', - }; describe('pull request commits', () => { + const pkg = { + repository: 'http://127.0.0.1:3000/usr/proj', + }; const httpCalls = withFakeGithub(); const commits = [ { @@ -413,13 +418,49 @@ describe('generateChangeLog', () => { assert.strictEqual(httpCalls.length, 2); }); - it('groups commits by pull request', () => { - assert.ok(changelog.includes('* PR #1 Title')); - assert.ok(changelog.includes(' - [`1234567`]')); + it('omits commits by pull request by default', async () => { + changelog = await generateChangeLog(null, pkg, options); + + assert.ok(changelog.includes('[#1](http://pr-1) feat: PR #1 Title')); + assert.ok( + !changelog.includes(' - [`1234567`] fix: Stop doing the wrong thing') + ); + }); + + describe('with changelog.verbose flag', () => { + const verboseOpts = { + nlmOptions: { changelog: { verbose: true } }, + }; + it('groups commits by pull request with changelog.verbose flag', async () => { + changelog = await generateChangeLog(null, pkg, { + ...options, + ...verboseOpts, + }); + + assert.ok(changelog.includes('[#1](http://pr-1) feat: PR #1 Title')); + assert.ok(changelog.includes(' - [`1234567`]')); + }); + + it("doesn't add emojis to pull commits", async () => { + changelog = await generateChangeLog(null, pkg, { + ...options, + nlmOptions: { + changelog: { verbose: true }, + emoji: { + skip: false, + }, + }, + }); + + assert.ok(changelog.includes(') fix: Stop')); + }); }); }); - describe('with an invalid PR', () => { + describe('with a PR w/o associated commits)', () => { + const pkg = { + repository: 'http://127.0.0.1:3000/usr/proj', + }; const httpCalls = withFakeGithub(); const commits = [ { @@ -439,12 +480,15 @@ describe('generateChangeLog', () => { pullId: '2', }, ]; + + // sloppyCommits lack "type" property const sloppyCommits = commits.map(commit => { - if (commit.type === 'pr') return commit; - return { - sha: commit.sha, - header: commit.subject, - }; + return commit.type === 'pr' + ? commit + : { + sha: commit.sha, + header: commit.subject, + }; }); const options = { ...defaultOptions, @@ -468,8 +512,8 @@ describe('generateChangeLog', () => { assert.strictEqual(httpCalls.length, 4); }); - it('ignores the PR', () => { - assert.ok(!changelog.includes('* PR #2 Title')); + it('ignores the PR w/o associated commits', () => { + assert.ok(!changelog.includes('* [#2] PR #2 Title')); assert.ok(changelog.includes('* [`1234567`]')); }); @@ -477,9 +521,19 @@ describe('generateChangeLog', () => { assert.ok(sloppyChangelog.includes(') Stop doing the wrong thing\n')); assert.ok(sloppyChangelog.includes(') Do more things')); }); + + it('categorizes commits w/o angular prefix as "Internal"', () => { + assert.ok( + sloppyChangelog.startsWith('#### Internal'), + 'sets "Internal" category' + ); + }); }); - describe('with a missing PR', () => { + describe('with a PR missing in GH', () => { + const pkg = { + repository: 'http://127.0.0.1:3000/usr/proj', + }; const httpCalls = withFakeGithub(); const commits = [ { @@ -493,6 +547,7 @@ describe('generateChangeLog', () => { subject: 'Do more things', }, { + // this PR is missing - see missing mocks at the beginning of this file sha: '3234567890123456789012345678901234567890', type: 'pr', subject: 'Merge PR #3', @@ -514,65 +569,204 @@ describe('generateChangeLog', () => { }); it('ignores the PR', () => { - assert.ok(changelog.includes('* [`1234567`]')); + assert.ok(!changelog.includes('Merge PR #3')); + }); + }); + + describe('categorization', () => { + withFakeGithub(); + const pkg = { + repository: 'usr/proj', + }; + const defaultCommit = { + sha: '1234567890123456789012345678901234567890', + subject: 'Stop doing the wrong thing', + }; + const headlineLevel = '####'; + + const testCases = [ + { headline: 'New Features', prefixes: ['feat'] }, + { headline: 'Code Refactoring', prefixes: ['refactor'] }, + { headline: 'Bug Fixes', prefixes: ['fix'] }, + { headline: 'Performance Improvements', prefixes: ['perf'] }, + { headline: 'Dependencies', prefixes: ['dep'] }, + { headline: 'Documentation', prefixes: ['docs'] }, + { headline: 'Polish', prefixes: ['style'] }, + { headline: 'Reverts', prefixes: ['revert'] }, + { + headline: 'Internal', + prefixes: ['ci', 'test', 'build', 'chore'], + }, + ]; + + const href0 = `https://github.com/usr/proj/commit/${defaultCommit.sha}`; + + it('sorts commits into according categories', async () => { + for (const { headline, prefixes } of testCases) { + for (const prefix of prefixes) { + const options = { + nlmOptions: { + emoji: { + skip: true, + }, + }, + commits: [{ ...defaultCommit, type: prefix }], + }; + + const expectedEntries = [ + `* [\`1234567\`](${href0}) ${prefix}: Stop doing the wrong thing`, + ]; + + const changelog = await generateChangeLog(null, pkg, options); + const lines = changelog.split('\n'); + + const indices = assertEntries(changelog, expectedEntries); + assert.strictEqual( + lines[indices[0] - 2], + `${headlineLevel} ${headline}` + ); + } + } + }); + + it('identifies & highlights dependency updates in commit subject and groups them into "Dependencies" category', async () => { + function removeBackticks(str) { + return str.replace(/`/g, ''); + } + + const subjectCases = [ + '@scope/create@23.0', + '@scope/create@23.0.0', + ['@scope/create@23.0.x', '`create@23.0.x`', '`create@23x`'], // multiple packages in subject + '@scope/cr.eate@23.x', + 'create@23.x', + 'cre.ate@23', + 'cre.ate@v23', + 'cre.ate v23', + 'cre.ate 23', + '`cre.ate 23`', + ]; + + for (const subject of subjectCases) { + const commits = [ + { + sha: '1234567890123456789012345678901234567890', + type: 'fix', + subject: Array.isArray(subject) ? subject.join(' ') : subject, + }, + ]; + const options = { + ...defaultOptions, + commits, + }; + const href = `https://github.com/usr/proj/commit/${commits[0].sha}`; + const expectedEntries = [ + `* [\`1234567\`](${href}) fix: \`${ + Array.isArray(subject) + ? subject.map(removeBackticks).join('` `') + : removeBackticks(subject) + }\``, + ]; + + const changelog = await generateChangeLog( + null, + pkg, + options + ).then(res => res.split('\n')); + + const index = assertEntries(changelog, expectedEntries); + assert.strictEqual(changelog[index - 2], '#### Dependencies'); + } }); }); }); - describe('emoji', () => { + describe('Emojis', () => { + let changelog; const pkg = { repository: 'http://127.0.0.1:3000/usr/proj', }; const defaultCommit = { - sha: '2234567890123456789012345678901234567890', + sha: '1234567890123456789012345678901234567890', subject: 'something', }; const cases = [ - { type: 'feat', expected: '✨ **feat:**' }, - { type: 'fix', expected: '🐛 **fix:**' }, - { type: 'refactor', expected: 'đŸ“Ļī¸ **refactor:**' }, - { type: 'docs', expected: '📝 **docs:**' }, - { type: 'revert', expected: '↩ī¸ **revert:**' }, - { type: 'style', expected: '🎨 **style:**' }, - { type: 'build', expected: '👷 **build:**' }, - { type: 'ci', expected: '💚 **ci:**' }, - { type: 'test', expected: '✅ **test:**' }, - { type: 'perf', expected: '⚡ **perf:**' }, - { type: 'chore', expected: 'â™ģī¸ **chore:**' }, + { type: 'feat' }, + { type: 'fix' }, + { type: 'refactor' }, + { type: 'docs' }, + { type: 'revert' }, + { type: 'style' }, + { type: 'build' }, + { type: 'ci' }, + { type: 'test' }, + { type: 'perf' }, + { type: 'chore' }, ]; const commits = cases.map(({ type }) => ({ type, ...defaultCommit })); const options = { commits, + nlmOptions: { + changelog: { + verbose: true, + }, + }, }; - let changelog; - - it('sets emojis for all commit types', async () => { - changelog = await generateChangeLog(null, pkg, options); - cases.forEach(({ expected }) => { - assert.ok(changelog.includes(expected), `should include ${expected}`); - }); - }); - - it('allows custom emojis with emoji.set config', async () => { - changelog = await generateChangeLog(null, pkg, { - ...options, - emoji: { - set: { - feat: '🚀', - }, + it('adds category emojis to each category', async () => { + const testCases = [ + { headline: 'New Features', prefixes: ['feat'] }, + { headline: 'Code Refactoring', prefixes: ['refactor'] }, + { headline: 'Bug Fixes', prefixes: ['fix'] }, + { headline: 'Performance Improvements', prefixes: ['perf'] }, + { headline: 'Dependencies', prefixes: ['dep'] }, + { headline: 'Documentation', prefixes: ['docs'] }, + { headline: 'Polish', prefixes: ['style'] }, + { headline: 'Reverts', prefixes: ['revert'] }, + { + headline: 'Internal', + prefixes: ['ci', 'test', 'build', 'chore'], }, - }); - const expected = '🚀 **feat:**'; + ]; - assert.ok(changelog.includes(expected), `should include ${expected}`); + const headlineLevel = '####'; + const href0 = `https://github.com/usr/proj/commit/${defaultCommit.sha}`; + + const emojiMaps = generateChangeLog.emojiMaps.get('default'); + for (const { headline, prefixes } of testCases) { + for (const prefix of prefixes) { + const expectedEntries = [ + `* [\`1234567\`](${href0}) ${prefix}: something`, + ]; + + changelog = await generateChangeLog( + null, + { repository: 'usr/proj' }, + { + commits: [{ ...defaultCommit, type: prefix }], + } + ); + const lines = changelog.split('\n'); + + const indices = assertEntries(changelog, expectedEntries); + assert.strictEqual( + lines[indices[0] - 2], + `${headlineLevel} ${ + emojiMaps[prefix] || emojiMaps['internal'] + } ${headline}` + ); + } + } }); it('disables emojis with emoji.skip config', async () => { changelog = await generateChangeLog(null, pkg, { ...options, - emoji: { - skip: true, + nlmOptions: { + ...options.nlmOptions, + emoji: { + skip: true, + }, }, }); const notExpected = 'đŸ“Ļī¸'; diff --git a/test/steps/version-commit.test.js b/test/steps/version-commit.test.js index e4ac72d..398802c 100644 --- a/test/steps/version-commit.test.js +++ b/test/steps/version-commit.test.js @@ -66,9 +66,11 @@ describe('createVersionCommit', () => { before(resetVars); afterEach(resetVars); + describe('with no package-lock.json', () => { const dirname = withFixture('multiple-commits'); let currentDate; + before('commits with the original author', done => { execFile('git', ['show'], { cwd: dirname }, (err, stdout) => { if (err) return done(err); @@ -98,7 +100,7 @@ describe('createVersionCommit', () => { .readFileSync(`${dirname}/CHANGELOG.md`, 'utf8') .split('\n'); - assert.strictEqual(version, `### 1.0.0 - ${currentDate}`); + assert.strictEqual(version, `### v1.0.0 (${currentDate})`); assert.strictEqual(commit1, '* New stuff'); assert.strictEqual(commit2, '* Interesting features'); }); @@ -112,6 +114,7 @@ describe('createVersionCommit', () => { }); }); }); + describe('using package-lock.json', () => { const dirname = withFixture('with-plock'); @@ -136,6 +139,7 @@ describe('createVersionCommit', () => { describe('with unused package-lock.json', () => { const dirname = withFixture('with-bogus-plock'); + before('create version commit', () => createVersionCommit(dirname, pkg, options) );