From fa0020d694fd67798e6de0cd4d52f16631fbd9bb Mon Sep 17 00:00:00 2001 From: Steve Mao Date: Fri, 7 Aug 2015 10:21:07 +1000 Subject: [PATCH] feat(newline): fields does not contain leading or trailing newlines Let downstream (such as handlebars template) to worry about newlines. This is more flexiable and easier. It also makes more sense to do this way. Fixes #14 --- README.md | 8 ++++---- lib/parser.js | 36 +++++++++++++++++++----------------- test/cli.spec.js | 2 +- test/index.spec.js | 20 ++++++++++---------- test/parser.spec.js | 32 ++++++++++++++++---------------- 5 files changed, 50 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 488d60e..ce5681c 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ You will enter an interactive shell. To show your parsed output enter "return" t > fix(title): a title is fixed -{"type":"fix","scope":"title","subject":"a title is fixed","header":"fix(title): a title is fixed\n","body":null,"footer":null,"notes":[],"references":[],"revert":null} +{"type":"fix","scope":"title","subject":"a title is fixed","header":"fix(title): a title is fixed","body":null,"footer":null,"notes":[],"references":[],"revert":null} ``` You can also use cli to parse messages from files. @@ -255,7 +255,7 @@ An array of json will be printed to stdout. ```sh [ -{"type":"feat","scope":"ngMessages","subject":"provide support for dynamic message resolution","header":"feat(ngMessages): provide support for dynamic message resolution\n","body":"Prior to this fix it was impossible to apply a binding to a the ngMessage directive to represent the name of the error.\n","footer":"BREAKING CHANGE: The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive.\nCloses #10036\nCloses #9338\n","notes":[{"title":"BREAKING CHANGE","text":"The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive.\n"}],"references":[{"action":"Closes","owner":null,"repository":null,"issue":"10036","raw":"#10036"},{"action":"Closes","owner":null,"repository":null,"issue":"9338","raw":"#9338"}],"revert":null} +{"type":"feat","scope":"ngMessages","subject":"provide support for dynamic message resolution","header":"feat(ngMessages): provide support for dynamic message resolution","body":"Prior to this fix it was impossible to apply a binding to a the ngMessage directive to represent the name of the error.","footer":"BREAKING CHANGE: The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive.\nCloses #10036\nCloses #9338","notes":[{"title":"BREAKING CHANGE","text":"The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive."}],"references":[{"action":"Closes","owner":null,"repository":null,"issue":"10036","raw":"#10036"},{"action":"Closes","owner":null,"repository":null,"issue":"9338","raw":"#9338"}],"revert":null} ] ``` @@ -281,9 +281,9 @@ $ conventional-commits-parser log2.txt '===' ```sh [ -{"type":"docs","scope":"ngMessageExp","subject":"split ngMessage docs up to show its alias more clearly","header":"docs(ngMessageExp): split ngMessage docs up to show its alias more clearly\n","body":null,"footer":null,"notes":[],"references":[],"revert":null} +{"type":"docs","scope":"ngMessageExp","subject":"split ngMessage docs up to show its alias more clearly","header":"docs(ngMessageExp): split ngMessage docs up to show its alias more clearly","body":null,"footer":null,"notes":[],"references":[],"revert":null} , -{"type":"fix","scope":"$animate","subject":"applyStyles from options on leave","header":"fix($animate): applyStyles from options on leave\n","body":null,"footer":"Closes #10068\n","notes":[],"references":[{"action":"Closes","owner":null,"repository":null,"issue":"10068","raw":"#10068"}],"revert":null} +{"type":"fix","scope":"$animate","subject":"applyStyles from options on leave","header":"fix($animate): applyStyles from options on leave","body":null,"footer":"Closes #10068","notes":[],"references":[{"action":"Closes","owner":null,"repository":null,"issue":"10068","raw":"#10068"}],"revert":null} ] ``` diff --git a/lib/parser.js b/lib/parser.js index a53a519..e4842a6 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -1,6 +1,16 @@ 'use strict'; var _ = require('lodash'); +function append(src, line) { + if (src) { + src += '\n' + line; + } else { + src = line; + } + + return src; +} + function parser(raw, options, regex) { if (!raw || !raw.trim()) { throw new TypeError('Expected a raw commit'); @@ -99,11 +109,7 @@ function parser(raw, options, regex) { } if (currentProcessedField) { - if (otherFields[currentProcessedField]) { - otherFields[currentProcessedField] += line + '\n'; - } else { - otherFields[currentProcessedField] = line + '\n'; - } + otherFields[currentProcessedField] = append(otherFields[currentProcessedField], line); return; } @@ -116,15 +122,13 @@ function parser(raw, options, regex) { if (notesMatch) { continueNote = true; isBody = false; - footer += line + '\n'; + footer = append(footer, line); var note = { title: notesMatch[1], text: notesMatch[2] }; - if (note.text.trim()) { - note.text += '\n'; - } + notes.push(note); return; @@ -164,32 +168,30 @@ function parser(raw, options, regex) { } if (referenceMatched) { - footer += line + '\n'; + footer = append(footer, line); return; } // this is the continued important note if (continueNote) { - notes[notes.length - 1].text += line + '\n'; - footer += line + '\n'; + notes[notes.length - 1].text = append(notes[notes.length - 1].text, line); + footer = append(footer, line); return; } // this is the body if (isBody) { - body += line + '\n'; + body = append(body, line); } // this is the continued footer else { - footer += line + '\n'; + footer = append(footer, line); } }); - body = body; - footer = footer; if (!body) { body = null; } @@ -211,7 +213,7 @@ function parser(raw, options, regex) { } var msg = _.merge(headerParts, { - header: header + '\n', + header: header, body: body, footer: footer, notes: notes, diff --git a/test/cli.spec.js b/test/cli.spec.js index 24764f6..b3d0ad8 100644 --- a/test/cli.spec.js +++ b/test/cli.spec.js @@ -81,7 +81,7 @@ describe('cli', function() { .pipe(concat(function(chunk) { expect(chunk.toString()).to.include('"scope":"category","type":"fix:subcategory","subject":"My subject"'); expect(chunk.toString()).to.include('"references":[{"action":"Close","owner":null,"repository":null,"issue":"10036","raw":"#10036"},{"action":"fix","owner":null,"repository":null,"issue":"9338","raw":"#9338"}]'); - expect(chunk.toString()).to.include('"notes":[{"title":"BREAKING NEWS","text":"A lot of changes!\\n"}]'); + expect(chunk.toString()).to.include('"notes":[{"title":"BREAKING NEWS","text":"A lot of changes!"}]'); done(); })); diff --git a/test/index.spec.js b/test/index.spec.js index 6f81575..a94f4ad 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -42,16 +42,16 @@ describe('conventionalCommitsParser', function() { .pipe(conventionalCommitsParser()) .pipe(through.obj(function(chunk, enc, cb) { if (i === 0) { - expect(chunk.header).to.equal('feat(ng-list): Allow custom separator\n'); + expect(chunk.header).to.equal('feat(ng-list): Allow custom separator'); } else if (i === 1) { expect(chunk.notes).to.eql([{ title: 'BREAKING CHANGE', - text: 'some breaking change\n' + text: 'some breaking change' }]); } else if (i === 2) { - expect(chunk.header).to.equal('fix(zzz): Very cool commit\n'); + expect(chunk.header).to.equal('fix(zzz): Very cool commit'); } else if (i === 3) { - expect(chunk.header).to.equal('chore(scope with spaces): some chore\n'); + expect(chunk.header).to.equal('chore(scope with spaces): some chore'); } else if (i === 4) { expect(chunk.revert).to.eql({ header: 'throw an error if a callback is passed to animate methods', @@ -182,7 +182,7 @@ describe('conventionalCommitsParser', function() { expect(chunk.subject).to.equal('Another custom separator'); expect(chunk.notes[0]).to.eql({ title: 'BREAKING CHANGES', - text: 'some breaking changes\n' + text: 'some breaking changes' }); } @@ -240,11 +240,11 @@ describe('conventionalCommitsParser', function() { expect(chunk.subject).to.equal('fix'); expect(chunk.notes[0]).to.eql({ title: 'BREAKING CHANGES', - text: 'some breaking changes\n' + text: 'some breaking changes' }); } else if (i === 2) { - expect(chunk.header).to.equal('blabla\n'); - expect(chunk.hash).to.equal('9b1aff905b638aa274a5fc8f88662df446d374bd\n'); + expect(chunk.header).to.equal('blabla'); + expect(chunk.hash).to.equal('9b1aff905b638aa274a5fc8f88662df446d374bd'); } else if (i === 3) { expect(chunk.revert.header).to.equal('throw an error if a callback is passed to animate methods'); } @@ -265,7 +265,7 @@ describe('sync', function() { 'Closes #123\nCloses #25\nFixes #33\n'; var result = conventionalCommitsParser.sync(commit); - expect(result.header).to.equal('feat(ng-list): Allow custom separator\n'); - expect(result.footer).to.equal('Closes #123\nCloses #25\nFixes #33\n'); + expect(result.header).to.equal('feat(ng-list): Allow custom separator'); + expect(result.footer).to.equal('Closes #123\nCloses #25\nFixes #33'); }); }); diff --git a/test/parser.spec.js b/test/parser.spec.js index 92b31c3..790312a 100644 --- a/test/parser.spec.js +++ b/test/parser.spec.js @@ -115,7 +115,7 @@ describe('parser', function() { }); it('should parse header', function() { - expect(msg.header).to.equal('feat(scope): broadcast $destroy event on scope destruction\n'); + expect(msg.header).to.equal('feat(scope): broadcast $destroy event on scope destruction'); }); it('should understand header parts', function() { @@ -182,7 +182,7 @@ describe('parser', function() { it('should parse body', function() { expect(msg.body).to.equal( 'perf testing shows that in chrome this change adds 5-15% overhead\n' + - 'when destroying 10k nested scopes where each scope has a $destroy listener\n'); + 'when destroying 10k nested scopes where each scope has a $destroy listener'); }); it('should be null if not found', function() { @@ -201,7 +201,7 @@ describe('parser', function() { 'Kills #1, #123\n' + 'killed #25\n' + 'handle #33, Closes #100, Handled #3 kills repo#77\n' + - 'kills stevemao/conventional-commits-parser#1\n' + 'kills stevemao/conventional-commits-parser#1' ); }); @@ -212,14 +212,14 @@ describe('parser', function() { it('should parse important notes', function() { expect(msg.notes[0]).to.eql({ title: 'BREAKING AMEND', - text: 'some breaking change\n' + text: 'some breaking change' }); }); it('should parse important notes with more than one paragraphs', function() { expect(longNoteMsg.notes[0]).to.eql({ title: 'BREAKING AMEND', - text: 'some breaking change\nsome other breaking change\n' + text: 'some breaking change\nsome other breaking change' }); }); @@ -293,7 +293,7 @@ describe('parser', function() { regex ); - expect(msg.footer).to.equal('Kills #1, #123\nwhat\nkilled #25\nhandle #33, Closes #100, Handled #3\nother\n'); + expect(msg.footer).to.equal('Kills #1, #123\nwhat\nkilled #25\nhandle #33, Closes #100, Handled #3\nother'); }); it('should parse properly if important notes comes after references', function() { @@ -308,7 +308,7 @@ describe('parser', function() { ); expect(msg.notes[0]).to.eql({ title: 'BREAKING AMEND', - text: 'some breaking change\n' + text: 'some breaking change' }); expect(msg.references).to.eql([{ action: 'Kills', @@ -323,7 +323,7 @@ describe('parser', function() { issue: '123', raw: ', #123' }]); - expect(msg.footer).to.equal('Kills #1, #123\nBREAKING AMEND: some breaking change\n'); + expect(msg.footer).to.equal('Kills #1, #123\nBREAKING AMEND: some breaking change'); }); it('shoudl parse properly if important notes comes with more than one paragraphs after references', function() { @@ -338,7 +338,7 @@ describe('parser', function() { ); expect(msg.notes[0]).to.eql({ title: 'BREAKING AMEND', - text: 'some breaking change\nsome other breaking change\n' + text: 'some breaking change\nsome other breaking change' }); expect(msg.references).to.eql([{ action: 'Kills', @@ -353,7 +353,7 @@ describe('parser', function() { issue: '123', raw: ', #123' }]); - expect(msg.footer).to.equal('Kills #1, #123\nBREAKING AMEND: some breaking change\nsome other breaking change\n'); + expect(msg.footer).to.equal('Kills #1, #123\nBREAKING AMEND: some breaking change\nsome other breaking change'); }); it('shoudl parse properly if important notes comes after references with something after references', function() { @@ -369,7 +369,7 @@ describe('parser', function() { ); expect(msg.notes[0]).to.eql({ title: 'BREAKING AMEND', - text: 'some breaking change\n' + text: 'some breaking change' }); expect(msg.references).to.eql([{ action: 'Kills', @@ -384,7 +384,7 @@ describe('parser', function() { issue: '123', raw: ', #123' }]); - expect(msg.footer).to.equal('Kills #1, #123\nother\nBREAKING AMEND: some breaking change\n'); + expect(msg.footer).to.equal('Kills #1, #123\nother\nBREAKING AMEND: some breaking change'); }); }); @@ -410,7 +410,7 @@ describe('parser', function() { regex ); - expect(msg.hash).to.equal('9b1aff905b638aa274a5fc8f88662df446d374bd\n'); + expect(msg.hash).to.equal('9b1aff905b638aa274a5fc8f88662df446d374bd'); }); it('should parse sideNotes', function() { @@ -438,7 +438,7 @@ describe('parser', function() { expect(msg.sideNotes).to.equal('It should warn the correct unfound file names.\n' + 'Also it should continue if one file cannot be found.\n' + - 'Tests are added for these\n'); + 'Tests are added for these'); }); it('should parse committer name and email', function() { @@ -464,8 +464,8 @@ describe('parser', function() { regex ); - expect(msg.committerName).to.equal('Steve Mao\n'); - expect(msg[' committerEmail']).to.equal('test@github.com\n'); + expect(msg.committerName).to.equal('Steve Mao'); + expect(msg[' committerEmail']).to.equal('test@github.com'); }); });