Awesome
parse-commit-message
Extensible parser for git commit messages following Conventional Commits Specification
Please consider following this project's author, Charlike Mike Reagent, and :star: the project to show your :heart: and support.
<div id="thetop"></div>If you have any how-to kind of questions, please read the Contributing Guide and Code of Conduct documents.
For bugs reports and feature requests, please create an issue or ping
@tunnckoCore at Twitter.
Project is semantically & automatically published with new-release on CircleCI and released by New Release GitHub App.
<!-- Logo when needed: <p align="center"> <a href="https://github.com/tunnckoCoreLabs/parse-commit-message"> <img src="./media/logo.png" width="85%"> </a> </p> -->Highlights
- Understands and follows Conventional Commits Specification
- Closed cycle: utilities for parsing, stringifying and validation
- Infinitely extensible through plugins, two built-in
- Thoroughly tested with 100% coverage and 64+ tests
- Collecting mentions from commit message
- Detection of breaking changes in commit
Table of Contents
- Install
- Type definitions
- API
- See Also
- Contributing
- License
(TOC generated by verb using markdown-toc)
Install
This project requires Node.js ^8.10.0 || >=10.13.0. Install it using
yarn or npm.
We highly recommend to use Yarn when you think to contribute to this project.
$ yarn add parse-commit-message
Type definitions
For TypeScript support, please consider sending a PR here (adding src/index.d.ts
)
or inform us when you PR to the DefinitelyTyped.
For FlowType support, PR adding .js.flow
files in the src/
for every respective file.
Header
type Header = {
type: string;
scope?: string | null;
subject: string;
};
The scope
may exist or not. When exist it should be non-empty string.
Commit
type Commit = {
header: Header;
body?: string | null;
footer?: string | null;
increment?: string | boolean;
isBreaking?: boolean;
mentions?: Array<Mention>;
};
Note: It may also include properties set by the plugins - the isBreaking
, increment
and mentions
are such. They are there when you apply the increment
and mentions
plugins.
ProTip: The increment
may be a Boolean false
if the commit type, for example, is chore
.
See .applyPlugins and .plugins.
Mention
type Mention = {
handle: string;
mention: string;
index: number;
};
See collect-mentions for more.
API
<!-- docks-start -->Generated using docks.
src/commit.js
.parseCommit
Receives a full commit message string
and parses it into an Commit
object
and returns it.
Basically the same as .parse, except that
it only can accept single string.
The parse*
methods are not doing any checking and validation,
so you may want to pass the result to validateCommit
or checkCommit
,
or to validateCommit
with ret
option set to true
.
Params
commit
{string} a message like'fix(foo): bar baz\n\nSome awesome body!'
Returns
Commit
a standard object like{ header: Header, body?, footer? }
Examples
import { parseCommit } from 'parse-commit-message';
const commitObj = parseCommit('foo: bar qux\n\nokey dude');
console.log(commitObj);
// => {
// header: { type: 'foo', scope: null, subject: 'bar qux' },
// body: 'okey dude',
// footer: null,
// }
.stringifyCommit
Receives a Commit
object, validates it using validateCommit
,
builds a "commit" string and returns it. Method throws if problems found.
Basically the same as .stringify, except that
it only can accept single Commit
object.
Params
commit
{Commit} aCommit
object like{ header: Header, body?, footer? }
Returns
string
a commit nessage stirng like'fix(foo): bar baz'
Examples
import { stringifyCommit } from 'parse-commit-message';
const commitStr = stringifyCommit({
header: { type: 'foo', subject: 'bar qux' },
body: 'okey dude',
});
console.log(commitStr); // => 'foo: bar qux\n\nokey dude'
.validateCommit
Validates given Commit
object and returns boolean
.
You may want to set ret
to true
return an object instead of throwing.
Basically the same as .validate, except that
it only can accept single Commit
object.
Params
commit
{Commit} aCommit
like{ header: Header, body?, footer? }
[ret]
{boolean} to return result instead of throwing, defaultfalse
Returns
undefined
ifret
istrue
then returns{ value, error }
object, wherevalue
isCommit
anderror
a standardError
Examples
import { validateCommit } from 'parse-commit-message';
const commit = {
header: { type: 'foo', subject: 'bar qux' },
body: 'okey dude',
};
const commitIsValid = validateCommit(commit);
console.log(commitIsValid); // => true
const { value } = validateCommit(commit, true);
console.log(value);
// => {
// header: { type: 'foo', scope: null, subject: 'bar qux' },
// body: 'okey dude',
// footer: null,
// }
.checkCommit
Receives a Commit
and checks if it is valid. Method throws if problems found.
Basically the same as .check, except that
it only can accept single Commit
object.
Params
commit
{Commit} aCommit
like{ header: Header, body?, footer? }
Returns
Commit
returns the same as given if no problems, otherwise it will throw.
Examples
import { checkCommit } from 'parse-commit-message';
try {
checkCommit({ header: { type: 'fix' } });
} catch(err) {
console.log(err);
// => TypeError: header.subject should be non empty string
}
// throws because can accept only Commit objects
checkCommit('foo bar baz');
checkCommit(123);
checkCommit([{ header: { type: 'foo', subject: 'bar' } }]);
src/header.js
.parseHeader
Parses given header
string into an header object.
Basically the same as .parse, except that
it only can accept single string and returns a Header
object.
The parse*
methods are not doing any checking and validation,
so you may want to pass the result to validateHeader
or checkHeader
,
or to validateHeader
with ret
option set to true
.
Params
header
{string} a header stirng like'fix(foo): bar baz'
Returns
Header
aHeader
object like{ type, scope?, subject }
Examples
import { parseHeader } from 'parse-commit-message';
const longCommitMsg = `fix: bar qux
Awesome body!`;
const headerObj = parseCommit(longCommitMsg);
console.log(headerObj);
// => { type: 'fix', scope: null, subject: 'bar qux' }
.stringifyHeader
Receives a header
object, validates it using validateHeader
,
builds a "header" string and returns it. Method throws if problems found.
Basically the same as .stringify, except that
it only can accept single Header
object.
Params
header
{Header} aHeader
object like{ type, scope?, subject }
Returns
string
a header stirng like'fix(foo): bar baz'
Examples
import { stringifyHeader } from 'parse-commit-message';
const headerStr = stringifyCommit({ type: 'foo', subject: 'bar qux' });
console.log(headerStr); // => 'foo: bar qux'
.validateHeader
Validates given header
object and returns boolean
.
You may want to pass ret
to return an object instead of throwing.
Basically the same as .validate, except that
it only can accept single Header
object.
Params
header
{Header} aHeader
object like{ type, scope?, subject }
[ret]
{boolean} to return result instead of throwing, defaultfalse
Returns
undefined
ifret
istrue
then returns{ value, error }
object, wherevalue
isHeader
anderror
a standardError
Examples
import { validateHeader } from 'parse-commit-message';
const header = { type: 'foo', subject: 'bar qux' };
const headerIsValid = validateHeader(header);
console.log(headerIsValid); // => true
const { value } = validateHeader(header, true);
console.log(value);
// => {
// header: { type: 'foo', scope: null, subject: 'bar qux' },
// body: 'okey dude',
// footer: null,
// }
const { error } = validateHeader({
type: 'bar'
}, true);
console.log(error);
// => TypeError: header.subject should be non empty string
.checkHeader
Receives a Header
and checks if it is valid.
Basically the same as .check, except that
it only can accept single Header
object.
Params
header
{Header} aHeader
object like{ type, scope?, subject }
Returns
Header
returns the same as given if no problems, otherwise it will throw.
Examples
import { checkHeader } from 'parse-commit-message';
try {
checkHeader({ type: 'fix' });
} catch(err) {
console.log(err);
// => TypeError: header.subject should be non empty string
}
// throws because can accept only Header objects
checkHeader('foo bar baz');
checkHeader(123);
checkHeader([]);
checkHeader([{ type: 'foo', subject: 'bar' }]);
src/index.js
.applyPlugins
Apply a set of plugins
over all of the given commits
.
A plugin is a simple function passed with Commit
object,
which may be returned to modify and set additional properties
to the Commit
object.
The commits
should be coming from parse
, validate
(with ret
option)
or the check
methods. It does not do checking and validation.
Params
plugins
{Array<Function>} a simple function like(commit) => {}
commits
{string|object|array} a value which should already be gone throughparse
Returns
Array<Commit>
plus the modified or added properties from each function inplugins
Examples
import dedent from 'dedent';
import { applyPlugins, plugins, parse, check } from './src';
const commits = [
'fix: bar qux',
dedent`feat(foo): yea yea
Awesome body here with @some mentions
resolves #123
BREAKING CHANGE: ouch!`,
'chore(ci): updates for ci config',
{
header: { type: 'fix', subject: 'Barry White' },
body: 'okey dude',
foo: 'possible',
},
];
// Parses, normalizes, validates
// and applies plugins
const results = applyPlugins(plugins, check(parse(commits)));
console.log(results);
// => [ { body: null,
// footer: null,
// header: { scope: null, type: 'fix', subject: 'bar qux' },
// mentions: [],
// increment: 'patch',
// isBreaking: false },
// { body: 'Awesome body here with @some mentions\nresolves #123',
// footer: 'BREAKING CHANGE: ouch!',
// header: { scope: 'foo', type: 'feat', subject: 'yea yea' },
// mentions: [ [Object] ],
// increment: 'major',
// isBreaking: true },
// { body: null,
// footer: null,
// header:
// { scope: 'ci', type: 'chore', subject: 'updates for ci config' },
// mentions: [],
// increment: false,
// isBreaking: false },
// { body: 'okey dude',
// footer: null,
// header: { scope: null, type: 'fix', subject: 'Barry White' },
// foo: 'possible',
// mentions: [],
// increment: 'patch',
// isBreaking: false } ]
.plugins
An array which includes mentions
and increment
built-in plugins.
The mentions
is an array of objects. Basically what's returned from
the collect-mentions package.
Examples
import { plugins, applyPlugins, parse } from 'parse-commit-message';
console.log(plugins); // => [mentions, increment]
console.log(plugins[0]); // => [Function mentions]
console.log(plugins[0]); // => [Function increment]
const cmts = parse([
'fix: foo @bar @qux haha',
'feat(cli): awesome @tunnckoCore feature\n\nSuper duper baz!'
'fix: ooh\n\nBREAKING CHANGE: some awful api change'
]);
const commits = applyPlugins(plugins, cmts);
console.log(commits);
// => [
// {
// header: { type: 'fix', scope: '', subject: 'foo bar baz' },
// body: '',
// footer: '',
// increment: 'patch',
// isBreaking: false,
// mentions: [
// { handle: '@bar', mention: 'bar', index: 8 },
// { handle: '@qux', mention: 'qux', index: 13 },
// ]
// },
// {
// header: { type: 'feat', scope: 'cli', subject: 'awesome feature' },
// body: 'Super duper baz!',
// footer: '',
// increment: 'minor',
// isBreaking: false,
// mentions: [
// { handle: '@tunnckoCore', mention: 'tunnckoCore', index: 18 },
// ]
// },
// {
// header: { type: 'fix', scope: '', subject: 'ooh' },
// body: 'BREAKING CHANGE: some awful api change',
// footer: '',
// increment: 'major',
// isBreaking: true,
// mentions: [],
// },
// ]
.mappers
An object (named set) which includes mentions
and increment
built-in plugins.
Examples
import { mappers, applyPlugins, parse } from 'parse-commit-message';
console.log(mappers); // => { mentions, increment }
console.log(mappers.mentions); // => [Function mentions]
console.log(mappers.increment); // => [Function increment]
const flat = true;
const parsed = parse('fix: bar', flat);
console.log(parsed);
// => {
// header: { type: 'feat', scope: 'cli', subject: 'awesome feature' },
// body: 'Super duper baz!',
// footer: '',
// }
const commit = applyPlugins([mappers.increment], parsed);
console.log(commit)
// => [{
// header: { type: 'feat', scope: 'cli', subject: 'awesome feature' },
// body: 'Super duper baz!',
// footer: '',
// increment: 'patch',
// }]
src/main.js
.parse
Receives and parses a single or multiple commit message(s) in form of string, object, array of strings, array of objects or mixed.
Params
commits
{string|object|array} a value to be parsed into an object likeCommit
type[flat]
{boolean} if the returned result length is 1, then returns the first item
Returns
Array<Commit>
ifflat: true
, returns aCommit
Examples
import { parse } from 'parse-commit-message';
const commits = [
'fix(ci): tweaks for @circleci config',
'chore: bar qux'
];
const result = parse(commits);
console.log(result);
// => [{
// header: { type: 'fix', scope: 'ci', subject: 'tweaks for @circleci config' },
// body: null,
// footer: null,
// }, {
// header: { type: 'chore', scope: null, subject: 'bar qux' },
// body: null,
// footer: null,
// }]
// Or pass `flat = true` to return a single object
// when results contain only one item.
const commitMessage = `feat: awesome yeah
Awesome body!
resolves #123
Signed-off-by: And Footer <abc@exam.pl>`;
const res = parse(commitMessage, true);
console.log(res);
// => {
// header: { type: 'feat', scope: null, subject: 'awesome yeah' },
// body: 'Awesome body!\nresolves #123',
// footer: 'Signed-off-by: And Footer <abc@exam.pl>',
// }
.stringify
Receives a Commit
object, validates it using validate
,
builds a "commit" message string and returns it.
This method does checking and validation too, so if you pass a string, it will be parsed and validated, and after that turned again to string.
Params
commits
{string|object|array} aCommit
object, or anything that can be passed tocheck
[flat]
{boolean} if the returned result length is 1, then returns the first item
Returns
Array<string>
an array of commit strings like'fix(foo): bar baz'
, ifflat: true
, returns astring
Examples
import { parse, stringify } from 'parse-commit-message';
const commitMessage = `feat: awesome yeah
Awesome body!
resolves #123
Signed-off-by: And Footer <abc@exam.pl>`;
const flat = true;
const res = parse(commitMessage, flat);
const str = stringify(res, flat);
console.log(str);
console.log(str === commitMessage);
.validate
Validates a single or multiple commit message(s) in form of string,
object, array of strings, array of objects or mixed.
You may want to pass ret
to return an object instead of throwing.
Params
commits
{string|object|array} a value to be parsed & validated into an object likeCommit
type[ret]
{boolean} to return result instead of throwing, defaultfalse
Returns
undefined
ifret
istrue
then returns{ value, error }
object, wherevalue
isCommit|Array<Commit>
anderror
a standardError
Examples
import { validate } from 'parse-commit-message';
console.log(validate('foo bar qux')); // false
console.log(validate('foo: bar qux')); // true
console.log(validate('fix(ci): bar qux')); // true
console.log(validate(['a bc cqux', 'foo bar qux'])); // false
console.log(validate({ qux: 1 })); // false
console.log(validate({ header: { type: 'fix' } })); // false
console.log(validate({ header: { type: 'fix', subject: 'ok' } })); // true
const commitObject = {
header: { type: 'test', subject: 'updating tests' },
foo: 'bar',
isBreaking: false,
body: 'oh ah',
};
console.log(validate(commitObject)); // true
const result = validate('foo bar qux', true);
console.log(result.error);
// => Error: expect \`commit\` to follow:
// <type>[optional scope]: <description>
//
// [optional body]
//
// [optional footer]
const res = validate('fix(ci): okey barry', true);
console.log(result.value);
// => [{
// header: { type: 'fix', scope: 'ci', subject: 'okey barry' },
// body: null,
// footer: null,
// }]
const commit = { header: { type: 'fix' } };
const { error } = validate(commit, true);
console.log(error);
// => TypeError: header.subject should be non empty string
const commit = { header: { type: 'fix', scope: 123, subject: 'okk' } };
const { error } = validate(commit, true);
console.log(error);
// => TypeError: header.scope should be non empty string when given
.check
Receives a single or multiple commit message(s) in form of string, object, array of strings, array of objects or mixed.
Basically the return result is the same as if you run .validate()
with
the ret
option, but instead it throws if find problems.
Params
commits
{string|object|array} a value to be parsed & validated into an object likeCommit
type[flat]
{boolean} if the returned result length is 1, then returns the first item
Returns
Array<Commit>
returns the same as given if no problems, otherwise it will throw; ifflat: true
, returns aCommit
Examples
import { check } from 'parse-commit-message';
try {
check({ header: { type: 'fix' } });
} catch(err) {
console.log(err);
// => TypeError: header.subject should be non empty string
}
// Can also validate/check a strings, array of strings,
// or even mixed - array of strings and objects
try {
check('fix(): invalid scope, it cannot be empty')
} catch(err) {
console.log(err);
// => TypeError: header.scope should be non empty string when given
}
src/plugins/increment.js
increment
A plugin that adds increment
and isBreaking
properties
to the commit
. It is already included in the plugins
named export,
and in mappers
named export.
See the .plugins and .mappers examples.
Params
commit
{Commit} a standardCommit
object
Returns
Commit
plus{ increment: string, isBreaking: boolean }
src/plugins/mentions.js
mentions
A plugin that adds mentions
array property to the commit
.
It is already included in the plugins
named export,
and in mappers
named export.
Basically each entry in that array is an object,
directly returned from the collect-mentions.
See the .plugins and .mappers examples.
Params
commit
{Commit} a standardCommit
object
Returns
Commit
plus{ mentions: Array<Mention> }
See Also
Some of these projects are used here or were inspiration for this one, others are just related. So, thanks for your existance!
- @tunnckocore/config: All the configs for all the tools, in one place | homepage
- @tunnckocore/create-project: Create and scaffold a new project, its GitHub repository and contents | homepage
- @tunnckocore/execa: Thin layer on top of execa that allows executing multiple commands… more | homepage
- @tunnckocore/scripts: Universal and minimalist scripts & tasks runner. | homepage
- @tunnckocore/update: Update to latest project files and templates, based on
charlike
scaffolder | homepage - asia: Blazingly fast, magical and minimalist testing framework, for Today and Tomorrow | homepage
- charlike: Small, fast and streaming project scaffolder with support for hundreds of… more | homepage
- docks: Extensible system for parsing and generating documentation. It just freaking works! | homepage
- git-commits-since: Get all commits since given period of time or by default… more | homepage
- gitcommit: Lightweight and joyful
git commit
replacement. Conventional Commits compliant. | homepage
Contributing
Follow the Guidelines
Please read the Contributing Guide and Code of Conduct documents for advices.
For bugs reports and feature requests, please create an issue or ping
@tunnckoCore at Twitter.
Support the project
Become a Partner or Sponsor? :dollar: Check the Partner, Sponsor or Omega-level tiers! :tada: You can get your company logo, link & name on this file. It's also rendered on package page in npmjs.com and yarnpkg.com sites too! :rocket:
Not financial support? Okey! Pull requests, stars and all kind of contributions are always welcome. :sparkles:
OPEN Open Source
This project is following OPEN Open Source model
Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is built on collective efforts and it's not strongly guarded by its founders.
There are a few basic ground-rules for its contributors
- Any significant modifications must be subject to a pull request to get feedback from other contributors.
- Pull requests to get feedback are encouraged for any other trivial contributions, but are not required.
- Contributors should attempt to adhere to the prevailing code-style and development workflow.
Wonderful Contributors
Thanks to the hard work of these wonderful people this project is alive! It follows the
all-contributors specification.
Don't hesitate to add yourself to that list if you have made any contribution! ;) See how,
here.
<img src="https://avatars3.githubusercontent.com/u/5038030?v=4" width="120px;"/><br /><sub><b>Charlike Mike Reagent</b></sub><br />💻 📖 💬 👀 🔍 |
---|
Consider showing your support to them. :sparkling_heart:
License
Copyright (c) 2017-present, Charlike Mike Reagent <mameto2011@gmail.com>
& contributors.
Released under the Apache-2.0 License.