From 7be9c893f5a937231091d5fef4490efe7cd9782c Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Sun, 8 Jul 2018 15:57:13 -0400 Subject: [PATCH] feat: allow to override preconfigured options --- README.md | 17 ++++++++++++++--- index.js | 19 ++++++++++++++++--- test/index.test.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e1abf98..8b2d625 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ issueParser('Issue description, ref group/user/package#1, !2, implement #3, /dup ### Bitbucket format ```js -const issueParser = require('issue-parser') +const issueParser = require('issue-parser'); const parse = issueParser('bitbucket'); issueParser('Issue description, ref user/package#1, fixing #2. /cc @user'); @@ -76,7 +76,7 @@ issueParser('Issue description, ref user/package#1, fixing #2. /cc @user'); ### Custom format ```js -const issueParser = require('issue-parser') +const issueParser = require('issue-parser'); const parse = issueParser({referenceActions: ['complete'], issuePrefixes: ['🐛']}); issueParser('Issue description, related to user/package🐛1, Complete 🐛2'); @@ -266,7 +266,7 @@ Fix #1 Fix #2a Fix a#3 ## API -### issueParser([options]) => parse +### issueParser([options], [overrides]) => parse Create a [parser](#parsetext--result). @@ -317,6 +317,17 @@ Default: `['issues', 'pull', 'merge_requests']` List of URL segment used to identify issues and pull requests with [full URL](#parse-references-with-full-issue-url). +#### overrides + +Type: `Object`
+Option overrides. Useful when using predefined [`options`](#options) (such as `github`, `gitlab` or `bitbucket`). The `overrides` object can define the same properties as [`options`](#options). + +For example, the following will use all the `github` predefined options but with a different `hosts` option: +```js +const issueParser = require('issue-parser'); +const parse = issueParser('github', {hosts: ['https://custom-url.com']}); +``` + ### parse(text) => Result Parse an issue description and returns a [Result](#result) object. diff --git a/index.js b/index.js index d10529b..0e540be 100644 --- a/index.js +++ b/index.js @@ -103,12 +103,25 @@ function parse(text, regexp, mentionRegexp, {issuePrefixes, hosts, referenceActi return results; } -module.exports = options => { - if (options !== undefined && !isString(options) && !isPlainObject(options)) { +module.exports = (options = 'default', overrides = {}) => { + if (!isString(options) && !isPlainObject(options)) { throw new TypeError('Options must be a String or an Object'); } - const opts = Object.assign({}, hostConfig.default, isString(options) ? hostConfig[options.toLowerCase()] : options); + if (isString(options) && !includesIgnoreCase(Object.keys(hostConfig), options)) { + throw new TypeError(`The supported configuration are [${Object.keys(hostConfig).join(', ')}], got '${options}'`); + } + + if (!isPlainObject(overrides)) { + throw new TypeError('Override must be an Object'); + } + + const opts = Object.assign( + {}, + hostConfig.default, + isString(options) ? hostConfig[options.toLowerCase()] : options, + overrides + ); for (const opt of Object.keys(opts)) { if (isString(opts[opt])) { diff --git a/test/index.test.js b/test/index.test.js index 76a27e8..070e3a3 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -135,6 +135,35 @@ test('Parse with custom options', t => { ); }); +test('Parse with options overrides', t => { + t.deepEqual( + m('default', { + referenceActions: ['fix'], + duplicateActions: [], + mentionsPrefixes: '!', + issuePrefixes: ['#'], + hosts: ['http://host1.com/', 'http://host2.com'], + issueURLSegments: ['bugs'], + })( + 'Fix #1 reSOLved gh-2 CLOSES Gh-3 fixed o/r#4 #5 o/r#6 fixing #7 http://host1.com/o/r/bugs/8 http://host2.com/o/r/bugs/9 Duplicate OF #10 !user @other' + ), + { + actions: [{raw: 'Fix #1', action: 'Fix', slug: undefined, prefix: '#', issue: '1'}], + refs: [ + {raw: 'o/r#4', slug: 'o/r', prefix: '#', issue: '4'}, + {raw: '#5', slug: undefined, prefix: '#', issue: '5'}, + {raw: 'o/r#6', slug: 'o/r', prefix: '#', issue: '6'}, + {raw: '#7', slug: undefined, prefix: '#', issue: '7'}, + {raw: 'http://host1.com/o/r/bugs/8', slug: 'o/r', prefix: undefined, issue: '8'}, + {raw: 'http://host2.com/o/r/bugs/9', slug: 'o/r', prefix: undefined, issue: '9'}, + {raw: '#10', slug: undefined, prefix: '#', issue: '10'}, + ], + duplicates: [], + mentions: [{raw: '!user', prefix: '!', user: 'user'}], + } + ); +}); + test('"allRefs" returns "refs", "actions" and "duplicates"', t => { t.deepEqual(m('github')('Fix #1 #2 Duplicate of #3').allRefs, [ {raw: 'Fix #1', action: 'Fix', slug: undefined, prefix: '#', issue: '1'}, @@ -269,12 +298,22 @@ test('Empty String', t => { }); test('Throw TypeError for invalid options', t => { + t.throws(() => m('missing-option'), TypeError); t.throws(() => m([]), TypeError); t.throws(() => m(1), TypeError); t.throws(() => m({referenceActions: 1}), TypeError); t.throws(() => m({referenceActions: [1]}), TypeError); }); +test('Throw TypeError for invalid overrides', t => { + t.throws(() => m({}, []), TypeError); + t.throws(() => m({}, 1), TypeError); + t.throws(() => m({}, {referenceActions: 1}), TypeError); + t.throws(() => m({}, {referenceActions: [1]}), TypeError); + t.throws(() => m({}, ''), TypeError); + t.throws(() => m({}, 'string'), TypeError); +}); + test('Throw TypeError for invalid input', t => { t.throws(() => m()(), TypeError); t.throws(() => m()(1), TypeError);