Skip to content

Commit 11e61a1

Browse files
authored
feat: accept options object, add removeMarkdown option (#29)
* feat: allow to optionally removeMarkdown or not through an options object * feat: optionally accept options object as first argument (non-breaking) * ci: drop 4 & 6, add 10
1 parent ef3202f commit 11e61a1

File tree

8 files changed

+337
-130
lines changed

8 files changed

+337
-130
lines changed

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
language: node_js
22
node_js:
3-
- '4'
4-
- '6'
53
- '8'
4+
- '10'
65
cache:
76
directories:
87
- node_modules

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,35 @@ If no callback is provided, `parseChangelog` will return a [Promise](https://dev
4545

4646
```js
4747
parseChangelog('path/to/CHANGELOG.md')
48-
.then(function(result) {
48+
.then(function (result) {
4949
// changelog object
5050
console.log(result)
5151
})
52-
.catch(() {
52+
.catch(function (err) {
5353
// Whoops, something went wrong!
54+
console.error(err)
5455
})
5556
```
5657

58+
### Options
59+
60+
You can optionally provide a configuration object `parseChangelog` function.
61+
62+
```js
63+
parseChangelog({
64+
filePath: 'path/to/CHANGELOG.md',
65+
removeMarkdown: false // default: true
66+
})
67+
```
68+
69+
#### filePath
70+
71+
Path to changelog file.
72+
73+
#### removeMarkdown
74+
75+
Removes the markdown markup from the changelog entries by default. You can change its value to `false` to keep the markdown.
76+
5777
### Command-line interface
5878

5979
There is also a command-line interface available if you install it with `-g`.

index.js

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,57 @@ var date = /.*[ ](\d\d?\d?\d?[-/.]\d\d?[-/.]\d\d?\d?\d?).*/
88
var subhead = /^###/
99
var listitem = /^[*-]/
1010

11-
function parseChangelog (file, callback) {
12-
// return a Promise if invoked without a `callback`
13-
if (!callback || typeof callback !== 'function') {
14-
return doParse(file)
11+
var defaultOptions = { removeMarkdown: true }
12+
13+
/**
14+
* Changelog parser.
15+
*
16+
* @param {string|object} options - changelog file string or options object containing file string
17+
* @param {string} options.filePath - path to changelog file
18+
* @param {boolean} [options.removeMarkdown=true] - changelog file string to parse
19+
* @param {function} [callback] - optional callback
20+
* @returns {Promise<object>} - parsed changelog object
21+
*/
22+
function parseChangelog (options, callback) {
23+
if (typeof options === 'undefined') throw new Error('missing options argument')
24+
if (typeof options === 'string') options = { filePath: options }
25+
if (typeof options === 'object' && typeof options.filePath !== 'string') {
26+
throw new Error('invalid path to file, expected string')
1527
}
1628

17-
// otherwise, parse log and invoke callback
18-
doParse(file).then(function (log) {
19-
callback(null, log)
20-
})
29+
var opts = Object.assign({}, defaultOptions, options)
30+
var changelog = parse(opts)
31+
32+
if (typeof callback === 'function') {
33+
changelog
34+
.then(function (log) { callback(null, log) })
35+
.catch(function (err) { callback(err) })
36+
}
37+
38+
// otherwise, invoke callback
39+
return changelog
2140
}
2241

23-
function doParse (file) {
42+
/**
43+
* Internal parsing logic.
44+
*
45+
* @param {options} options - options object
46+
* @param {string} options.filePath - path to changelog file
47+
* @param {boolean} [options.removeMarkdown] - remove markdown
48+
* @returns {Promise<object>} - parsed changelog object
49+
*/
50+
function parse (options) {
51+
var filePath = options.filePath
2452
var data = {
2553
log: { versions: [] },
2654
current: null
2755
}
2856

2957
// allow `handleLine` to mutate log/current data as `this`.
30-
var cb = handleLine.bind(data)
58+
var cb = handleLine.bind(data, options)
3159

3260
return new Promise(function (resolve, reject) {
33-
lineReader.eachLine(file, cb, EOL).then(function () {
61+
lineReader.eachLine(filePath, cb, EOL).then(function () {
3462
// push last version into log
3563
if (data.current) {
3664
pushCurrent(data)
@@ -45,7 +73,14 @@ function doParse (file) {
4573
})
4674
}
4775

48-
function handleLine (line) {
76+
/**
77+
* Handles each line and mutates data object (bound to `this`) as needed.
78+
*
79+
* @param {object} options - options object
80+
* @param {boolean} options.removeMarkdown - whether or not to remove markdown
81+
* @param {string} line - line from changelog file
82+
*/
83+
function handleLine (options, line) {
4984
// skip line if it's a link label
5085
if (line.match(/^\[[^[\]]*\] *?:/)) return
5186

@@ -88,12 +123,13 @@ function handleLine (line) {
88123

89124
// handle case where current line is a 'list item':
90125
if (listitem.exec(line)) {
126+
const log = options.removeMarkdown ? removeMarkdown(line) : line
91127
// add line to 'catch all' array
92-
this.current.parsed._.push(removeMarkdown(line))
128+
this.current.parsed._.push(log)
93129

94130
// add line to 'active subhead' if applicable (eg. 'Added', 'Changed', etc.)
95131
if (this.current._private.activeSubhead) {
96-
this.current.parsed[this.current._private.activeSubhead].push(removeMarkdown(line))
132+
this.current.parsed[this.current._private.activeSubhead].push(log)
97133
}
98134
}
99135
} else {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"Rachel Nehmer <[email protected]>",
1515
"Viktor Havrylin <[email protected]>",
1616
"J R Mykolyn <[email protected]>",
17-
"Bogdan Plieshka <[email protected]>"
17+
"Bogdan Plieshka <[email protected]>",
18+
"Ciro Nunes <[email protected]>"
1819
],
1920
"dependencies": {
2021
"line-reader": "^0.2.4",
File renamed without changes.

test/fixtures/expected.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
var EOL = require('os').EOL
2+
3+
module.exports = {
4+
title: 'changelog title',
5+
description: 'A cool description (optional).',
6+
versions: [
7+
{
8+
version: null,
9+
title: 'unreleased',
10+
'date': null,
11+
body: '* foo',
12+
parsed: {
13+
_: [
14+
'foo'
15+
]
16+
}
17+
},
18+
{
19+
version: 'x.y.z',
20+
title: 'x.y.z - YYYY-MM-DD',
21+
'date': null,
22+
body: '* bar',
23+
parsed: {
24+
_: [
25+
'bar'
26+
]
27+
}
28+
},
29+
{
30+
version: 'a.b.c',
31+
title: '[a.b.c]',
32+
'date': null,
33+
body: '### Changes' + EOL + EOL + '* Update API' + EOL + '* Fix bug #1',
34+
parsed: {
35+
_: [
36+
'Update API',
37+
'Fix bug #1'
38+
],
39+
Changes: [
40+
'Update API',
41+
'Fix bug #1'
42+
]
43+
}
44+
},
45+
{
46+
version: '2.3.0',
47+
title: '2.3.0 - 2018-12-18',
48+
'date': '2018-12-18',
49+
body: '### Added' + EOL + EOL + '- Some changelog generators such as [standard-version](https://github.com/conventional-changelog/standard-version) would produce H1s for major versions and H2s for minor versions. We want the parser to be able to parse both.',
50+
parsed: {
51+
_: [
52+
'Some changelog generators such as standard-version would produce H1s for major versions and H2s for minor versions. We want the parser to be able to parse both.'
53+
],
54+
Added: [
55+
'Some changelog generators such as standard-version would produce H1s for major versions and H2s for minor versions. We want the parser to be able to parse both.'
56+
]
57+
}
58+
},
59+
{
60+
version: '2.2.3-pre.1',
61+
title: '2.2.3-pre.1 - 2013-02-14',
62+
'date': '2013-02-14',
63+
body: '### Added' + EOL + '- Added an item.' + EOL + '* Added another item.' + EOL + EOL + '* Update API',
64+
parsed: {
65+
_: [
66+
'Added an item.',
67+
'Added another item.',
68+
'Update API'
69+
],
70+
Added: [
71+
'Added an item.',
72+
'Added another item.',
73+
'Update API'
74+
]
75+
}
76+
},
77+
{
78+
version: '2.0.0-x.7.z.92',
79+
title: '2.0.0-x.7.z.92 - 2013-02-14',
80+
'date': '2013-02-14',
81+
body: '* bark bark' + EOL + '* woof' + EOL + '* arf',
82+
parsed: {
83+
_: [
84+
'bark bark',
85+
'woof',
86+
'arf'
87+
]
88+
}
89+
},
90+
{
91+
version: '1.3.0',
92+
title: 'v1.3.0',
93+
'date': null,
94+
body: '* make it so',
95+
parsed: {
96+
_: [
97+
'make it so'
98+
]
99+
}
100+
},
101+
{
102+
version: '1.2.3',
103+
title: '[1.2.3](link)',
104+
'date': null,
105+
body: '* init',
106+
parsed: {
107+
_: [
108+
'init'
109+
]
110+
}
111+
}
112+
]
113+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
var EOL = require('os').EOL
2+
3+
module.exports = {
4+
title: 'changelog title',
5+
description: 'A cool description (optional).',
6+
versions: [
7+
{
8+
version: null,
9+
title: 'unreleased',
10+
'date': null,
11+
body: '* foo',
12+
parsed: {
13+
_: [
14+
'* foo'
15+
]
16+
}
17+
},
18+
{
19+
version: 'x.y.z',
20+
title: 'x.y.z - YYYY-MM-DD',
21+
'date': null,
22+
body: '* bar',
23+
parsed: {
24+
_: [
25+
'* bar'
26+
]
27+
}
28+
},
29+
{
30+
version: 'a.b.c',
31+
title: '[a.b.c]',
32+
'date': null,
33+
body: '### Changes' + EOL + EOL + '* Update API' + EOL + '* Fix bug #1',
34+
parsed: {
35+
_: [
36+
'* Update API',
37+
'* Fix bug #1'
38+
],
39+
Changes: [
40+
'* Update API',
41+
'* Fix bug #1'
42+
]
43+
}
44+
},
45+
{
46+
version: '2.3.0',
47+
title: '2.3.0 - 2018-12-18',
48+
'date': '2018-12-18',
49+
body: '### Added' + EOL + EOL + '- Some changelog generators such as [standard-version](https://github.com/conventional-changelog/standard-version) would produce H1s for major versions and H2s for minor versions. We want the parser to be able to parse both.',
50+
parsed: {
51+
_: [
52+
'- Some changelog generators such as [standard-version](https://github.com/conventional-changelog/standard-version) would produce H1s for major versions and H2s for minor versions. We want the parser to be able to parse both.'
53+
],
54+
Added: [
55+
'- Some changelog generators such as [standard-version](https://github.com/conventional-changelog/standard-version) would produce H1s for major versions and H2s for minor versions. We want the parser to be able to parse both.'
56+
]
57+
}
58+
},
59+
{
60+
version: '2.2.3-pre.1',
61+
title: '2.2.3-pre.1 - 2013-02-14',
62+
'date': '2013-02-14',
63+
body: '### Added' + EOL + '- Added an item.' + EOL + '* Added another item.' + EOL + EOL + '* Update API',
64+
parsed: {
65+
_: [
66+
'- Added an item.',
67+
'* Added another item.',
68+
'* Update API'
69+
],
70+
Added: [
71+
'- Added an item.',
72+
'* Added another item.',
73+
'* Update API'
74+
]
75+
}
76+
},
77+
{
78+
version: '2.0.0-x.7.z.92',
79+
title: '2.0.0-x.7.z.92 - 2013-02-14',
80+
'date': '2013-02-14',
81+
body: '* bark bark' + EOL + '* woof' + EOL + '* arf',
82+
parsed: {
83+
_: [
84+
'* bark bark',
85+
'* woof',
86+
'* arf'
87+
]
88+
}
89+
},
90+
{
91+
version: '1.3.0',
92+
title: 'v1.3.0',
93+
'date': null,
94+
body: '* make it so',
95+
parsed: {
96+
_: [
97+
'* make it so'
98+
]
99+
}
100+
},
101+
{
102+
version: '1.2.3',
103+
title: '[1.2.3](link)',
104+
'date': null,
105+
body: '* init',
106+
parsed: {
107+
_: [
108+
'* init'
109+
]
110+
}
111+
}
112+
]
113+
}

0 commit comments

Comments
 (0)