diff --git a/README.md b/README.md index 227d96a..deff0c9 100644 --- a/README.md +++ b/README.md @@ -42,49 +42,53 @@ in sync with the written specification on conventionalcommits.org. ```ebnf /* See: https://tools.ietf.org/html/rfc3629#section-4 */ -<UTF8-char> ::= "Placeholder for UTF-8 grammar" -<UTF8-octets> ::= <UTF8char>+ - -<CR> ::= "0x000D" -<LF> ::= "0x000A" -<newline> ::= [<CR>], <LF> -<parens> ::= "(" | ")" -<ZWNBSP> ::= "U+FEFF" -<TAB> ::= "U+0009" -<VT> ::= "U+000B" -<FF> ::= "U+000C" -<SP> ::= "U+0020" -<NBSP> ::= "U+00A0" +<UTF8-char> ::= "Placeholder for UTF-8 grammar" +<UTF8-octets> ::= <UTF8char>+ + +<CR> ::= "0x000D" +<LF> ::= "0x000A" +<newline> ::= [<CR>], <LF> +<parens> ::= "(" | ")" +<ZWNBSP> ::= "U+FEFF" +<TAB> ::= "U+0009" +<VT> ::= "U+000B" +<FF> ::= "U+000C" +<SP> ::= "U+0020" +<NBSP> ::= "U+00A0" /* See: https://www.ecma-international.org/ecma-262/11.0/index.html#sec-white-space */ -<USP> ::= "Any other Unicode 'Space_Separator' code point" +<USP> ::= "Any other Unicode 'Space_Separator' code point" /* Any non-newline whitespace: */ -<whitespace> ::= <ZWNBSP> | <TAB> | <VT> | <FF> | <SP> | <NBSP> | <USP> - -<message> ::= <summary>, <newline>+, <body>, <newline>*, <footer>+ - | <summary>, <newline>*, <footer>+ - | <summary>, <newline>* - -<summary> ::= <type>, "(", <scope>, ")", ["!"], ":", <whitespace>*, <text> - | <type>, ["!"], ":", <whitespace>*, <text> -<type> ::= <any UTF8-octets except newline or parens or ":" or "!:" or whitespace>+ -<scope> ::= <any UTF8-octets except newline or parens>+ -<text> ::= <any UTF8-octets except newline>* - -/* - * Note: if the first <body> node starts with "BREAKING CHANGE:" this should - * be treated by parsers as a breaking change marker upstream: - */ -<body> ::= [<any text except pre-footer>], <newline>, <body>* - | [<any text except pre-footer>] -/* Note: <pre-footer> is used during parsing, but never returned in the AST. */ -<pre-footer> ::= <newline>*, <footer>+ - -<footer> ::= <token>, <separator>, <whitespace>*, <value>, [<newline>] -<token> ::= "BREAKING CHANGE" - | <type>, "(" <scope> ")", ["!"] - | <type>, ["!"] -<separator> ::= ":" | " #" -<value> ::= <text>, <continuation>+ - | <text> -<continuation> ::= <newline>, <whitespace>+, <text> +<whitespace> ::= <ZWNBSP> | <TAB> | <VT> | <FF> | <SP> | <NBSP> | <USP> + +<message> ::= <summary>, <newline>+, <body>, <newline>*, <footer>+ + | <summary>, <newline>*, <footer>+ + | <summary>, <newline>* + +/* "!" should be added to the AST as a <breaking-change> node with the value "!" */ +<summary> ::= <type>, "(", <scope>, ")", ["!"], ":", <whitespace>*, <text> + | <type>, ["!"], ":", <whitespace>*, <text> +<type> ::= <any UTF8-octets except newline or parens or ":" or "!:" or whitespace>+ +<scope> ::= <any UTF8-octets except newline or parens>+ +<text> ::= <any UTF8-octets except newline>* + + +<body> ::= [<any body-text except pre-footer>], <newline>, <body>* + | [<any body-text except pre-footer>] +/* For convenience the <breaking-change>, <separator>, <whitespace>, and + * <text> tokens of <body-text> should be appended as children to <body> */ +<body-text> ::= [<breaking-change>, ":", <whitespace>*], text +/* Note: <pre-footer> is used during parsing, but not returned in the AST. */ +<pre-footer> ::= <newline>*, <footer>+ + +<footer> ::= <token>, <separator>, <whitespace>*, <value>, [<newline>] +/* "!" should be added to the AST as a <breaking-change> node with the value "!" */ +<token> ::= <breaking-change> + | <type>, "(" <scope> ")", ["!"] + | <type>, ["!"] +<separator> ::= ":" | " #" +<value> ::= <text>, <continuation>+ + | <text> +<continuation> ::= <newline>, <whitespace>+, <text> + +<breaking-change> ::= "BREAKING CHANGE" | "BREAKING-CHANGE" ``` diff --git a/lib/parser.js b/lib/parser.js index c8946da..f3ddf80 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -166,15 +166,25 @@ function scope (scanner) { } /* - * <body> ::= [<any text except pre-footer>], <newline>, <body>* - * | [<any text except pre-footer>] + * <body> ::= [<any body-text except pre-footer>], <newline>, <body>* + * | [<any body-text except pre-footer>] */ function body (scanner) { const node = scanner.enter('body', []) - // <any text except pre-footer> + + // check except <pre-footer> condition: const pf = preFooter(scanner) if (!(pf instanceof Error)) return scanner.abort(node) + // ["BREAKING CHANGE", ":", <whitespace>*] + const b = breakingChange(scanner, false) + if (!(b instanceof Error) && scanner.peek() === ':') { + node.children.push(b) + node.children.push(separator(scanner)) + const w = whitespace(scanner) + if (!(w instanceof Error)) node.children.push(w) + } + // [<text>] const t = text(scanner) node.children.push(t) @@ -282,13 +292,15 @@ function token (scanner) { } /* - * <breaking-change> ::= "!" | "BREAKING CHANGE" + * <breaking-change> ::= "!" | "BREAKING CHANGE" | "BREAKING-CHANGE" + * + * Note: "!" is only allowed in <footer> and <summary>, not <body>. */ -function breakingChange (scanner) { +function breakingChange (scanner, allowBang = true) { const node = scanner.enter('breaking-change', '') - if (scanner.peek() === '!') { + if (scanner.peek() === '!' && allowBang) { node.value = scanner.next() - } else if (scanner.peekLiteral('BREAKING CHANGE')) { + } else if (scanner.peekLiteral('BREAKING CHANGE') || scanner.peekLiteral('BREAKING-CHANGE')) { node.value = scanner.next('BREAKING CHANGE'.length) } if (node.value === '') { diff --git a/test/parser.js b/test/parser.js index 026b2c4..328a993 100644 --- a/test/parser.js +++ b/test/parser.js @@ -70,7 +70,9 @@ describe('<message>', () => { parsed.should.matchSnapshot() }) it('parses BREAKING CHANGE literal as <token>', () => { - const parsed = parser('fix: address major bug\nBREAKING CHANGE: this change is breaking') + let parsed = parser('fix: address major bug\nBREAKING CHANGE: this change is breaking') + parsed.should.matchSnapshot() + parsed = parser('fix: address major bug\nBREAKING-CHANGE: this change is breaking') parsed.should.matchSnapshot() }) it('supports multiline BREAKING CHANGES, via continuation', () => { @@ -102,11 +104,25 @@ describe('<message>', () => { assertNodePositions('fix: address major bug\n\nthis is a free form body of text') }) }) + describe('<body>', () => { + it('parses BREAKING CHANGE at start of body', () => { + const parsed = parser('feat: breaking change\n\nBREAKING CHANGE: introduces breaking change\nsecond line') + parsed.should.matchSnapshot() + }) + }) describe('<body>, <newline>*, <footer>+', () => { it('parses footer after body', () => { const parsed = parser('fix: address major bug\n\nthis is a free form body of text\nAuthor: @bcoe\nRefs #392') parsed.should.matchSnapshot() }) + it('parses footer after body containing BREAKING CHANGE', () => { + const parsed = parser('fix: address major bug\n\nBREAKING CHANGE: this is breaking.\nthis is a free form body of text\nAuthor: @bcoe\nRefs #392') + parsed.should.matchSnapshot() + }) + it('parses BREAKING CHANGE footers with higher precedence than body', () => { + const parsed = parser('fix: address major bug\n\nBREAKING CHANGE: this is breaking.\n\nAuthor: @bcoe\nRefs #392') + parsed.should.matchSnapshot() + }) it('parses footer after multi-line body', () => { const parsed = parser('fix: address major bug\n\nthis is the first line of the body\n\nthis is the second line of body\n\nAuthor: @bcoe\nRefs #392') parsed.should.matchSnapshot() diff --git a/test/parser.js.snap b/test/parser.js.snap index ccd466c..ba74b63 100644 --- a/test/parser.js.snap +++ b/test/parser.js.snap @@ -1,5 +1,633 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`<message> <body> parses BREAKING CHANGE at start of body 1`] = ` +Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "type", + "value": "feat", + }, + Object { + "position": Object { + "end": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + "start": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 7, + "line": 1, + "offset": 6, + }, + "start": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "position": Object { + "end": Object { + "column": 22, + "line": 1, + "offset": 21, + }, + "start": Object { + "column": 7, + "line": 1, + "offset": 6, + }, + }, + "type": "text", + "value": "breaking change", + }, + ], + "position": Object { + "end": Object { + "column": 22, + "line": 1, + "offset": 21, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "summary", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 16, + "line": 3, + "offset": 38, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 23, + }, + }, + "type": "breaking-change", + "value": "BREAKING CHANGE", + }, + Object { + "position": Object { + "end": Object { + "column": 17, + "line": 3, + "offset": 39, + }, + "start": Object { + "column": 16, + "line": 3, + "offset": 38, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 18, + "line": 3, + "offset": 40, + }, + "start": Object { + "column": 17, + "line": 3, + "offset": 39, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "position": Object { + "end": Object { + "column": 44, + "line": 3, + "offset": 66, + }, + "start": Object { + "column": 18, + "line": 3, + "offset": 40, + }, + }, + "type": "text", + "value": "introduces breaking change", + }, + Object { + "position": Object { + "end": Object { + "column": 12, + "line": 4, + "offset": 78, + }, + "start": Object { + "column": 1, + "line": 4, + "offset": 67, + }, + }, + "type": "text", + "value": "second line", + }, + ], + "position": Object { + "end": Object { + "column": 12, + "line": 4, + "offset": 78, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 23, + }, + }, + "type": "body", + }, + ], + "position": Object { + "end": Object { + "column": 12, + "line": 4, + "offset": 78, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "message", +} +`; + +exports[`<message> <body>, <newline>*, <footer>+ parses BREAKING CHANGE footers with higher precedence than body 1`] = ` +Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 4, + "line": 1, + "offset": 3, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "type", + "value": "fix", + }, + Object { + "position": Object { + "end": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + "start": Object { + "column": 4, + "line": 1, + "offset": 3, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + "start": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "position": Object { + "end": Object { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "type": "text", + "value": "address major bug", + }, + ], + "position": Object { + "end": Object { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "summary", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 16, + "line": 3, + "offset": 39, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 24, + }, + }, + "type": "breaking-change", + "value": "BREAKING CHANGE", + }, + ], + "position": Object { + "end": Object { + "column": 16, + "line": 3, + "offset": 39, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 24, + }, + }, + "type": "token", + }, + Object { + "position": Object { + "end": Object { + "column": 17, + "line": 3, + "offset": 40, + }, + "start": Object { + "column": 16, + "line": 3, + "offset": 39, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 18, + "line": 3, + "offset": 41, + }, + "start": Object { + "column": 17, + "line": 3, + "offset": 40, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 35, + "line": 3, + "offset": 58, + }, + "start": Object { + "column": 18, + "line": 3, + "offset": 41, + }, + }, + "type": "text", + "value": "this is breaking.", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 4, + "offset": 59, + }, + "start": Object { + "column": 18, + "line": 3, + "offset": 41, + }, + }, + "type": "value", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 5, + "offset": 60, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 24, + }, + }, + "type": "footer", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 7, + "line": 5, + "offset": 66, + }, + "start": Object { + "column": 1, + "line": 5, + "offset": 60, + }, + }, + "type": "type", + "value": "Author", + }, + ], + "position": Object { + "end": Object { + "column": 7, + "line": 5, + "offset": 66, + }, + "start": Object { + "column": 7, + "line": 5, + "offset": 66, + }, + }, + "type": "token", + }, + Object { + "position": Object { + "end": Object { + "column": 8, + "line": 5, + "offset": 67, + }, + "start": Object { + "column": 7, + "line": 5, + "offset": 66, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 9, + "line": 5, + "offset": 68, + }, + "start": Object { + "column": 8, + "line": 5, + "offset": 67, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 14, + "line": 5, + "offset": 73, + }, + "start": Object { + "column": 9, + "line": 5, + "offset": 68, + }, + }, + "type": "text", + "value": "@bcoe", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 6, + "offset": 74, + }, + "start": Object { + "column": 9, + "line": 5, + "offset": 68, + }, + }, + "type": "value", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 6, + "offset": 74, + }, + "start": Object { + "column": 1, + "line": 5, + "offset": 60, + }, + }, + "type": "footer", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 5, + "line": 6, + "offset": 78, + }, + "start": Object { + "column": 1, + "line": 6, + "offset": 74, + }, + }, + "type": "type", + "value": "Refs", + }, + ], + "position": Object { + "end": Object { + "column": 5, + "line": 6, + "offset": 78, + }, + "start": Object { + "column": 5, + "line": 6, + "offset": 78, + }, + }, + "type": "token", + }, + Object { + "position": Object { + "end": Object { + "column": 7, + "line": 6, + "offset": 80, + }, + "start": Object { + "column": 5, + "line": 6, + "offset": 78, + }, + }, + "type": "separator", + "value": " #", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 10, + "line": 6, + "offset": 83, + }, + "start": Object { + "column": 7, + "line": 6, + "offset": 80, + }, + }, + "type": "text", + "value": "392", + }, + ], + "position": Object { + "end": Object { + "column": 10, + "line": 6, + "offset": 83, + }, + "start": Object { + "column": 7, + "line": 6, + "offset": 80, + }, + }, + "type": "value", + }, + ], + "position": Object { + "end": Object { + "column": 10, + "line": 6, + "offset": 83, + }, + "start": Object { + "column": 1, + "line": 6, + "offset": 74, + }, + }, + "type": "footer", + }, + ], + "position": Object { + "end": Object { + "column": 10, + "line": 6, + "offset": 83, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "message", +} +`; + exports[`<message> <body>, <newline>*, <footer>+ parses footer after body 1`] = ` Object { "children": Array [ @@ -89,9 +717,357 @@ Object { Object { "position": Object { "end": Object { - "column": 33, + "column": 33, + "line": 3, + "offset": 56, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 24, + }, + }, + "type": "text", + "value": "this is a free form body of text", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 4, + "offset": 57, + }, + "start": Object { + "column": 1, + "line": 3, + "offset": 24, + }, + }, + "type": "body", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 7, + "line": 4, + "offset": 63, + }, + "start": Object { + "column": 1, + "line": 4, + "offset": 57, + }, + }, + "type": "type", + "value": "Author", + }, + ], + "position": Object { + "end": Object { + "column": 7, + "line": 4, + "offset": 63, + }, + "start": Object { + "column": 7, + "line": 4, + "offset": 63, + }, + }, + "type": "token", + }, + Object { + "position": Object { + "end": Object { + "column": 8, + "line": 4, + "offset": 64, + }, + "start": Object { + "column": 7, + "line": 4, + "offset": 63, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 9, + "line": 4, + "offset": 65, + }, + "start": Object { + "column": 8, + "line": 4, + "offset": 64, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 14, + "line": 4, + "offset": 70, + }, + "start": Object { + "column": 9, + "line": 4, + "offset": 65, + }, + }, + "type": "text", + "value": "@bcoe", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 5, + "offset": 71, + }, + "start": Object { + "column": 9, + "line": 4, + "offset": 65, + }, + }, + "type": "value", + }, + ], + "position": Object { + "end": Object { + "column": 1, + "line": 5, + "offset": 71, + }, + "start": Object { + "column": 1, + "line": 4, + "offset": 57, + }, + }, + "type": "footer", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 5, + "line": 5, + "offset": 75, + }, + "start": Object { + "column": 1, + "line": 5, + "offset": 71, + }, + }, + "type": "type", + "value": "Refs", + }, + ], + "position": Object { + "end": Object { + "column": 5, + "line": 5, + "offset": 75, + }, + "start": Object { + "column": 5, + "line": 5, + "offset": 75, + }, + }, + "type": "token", + }, + Object { + "position": Object { + "end": Object { + "column": 7, + "line": 5, + "offset": 77, + }, + "start": Object { + "column": 5, + "line": 5, + "offset": 75, + }, + }, + "type": "separator", + "value": " #", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 10, + "line": 5, + "offset": 80, + }, + "start": Object { + "column": 7, + "line": 5, + "offset": 77, + }, + }, + "type": "text", + "value": "392", + }, + ], + "position": Object { + "end": Object { + "column": 10, + "line": 5, + "offset": 80, + }, + "start": Object { + "column": 7, + "line": 5, + "offset": 77, + }, + }, + "type": "value", + }, + ], + "position": Object { + "end": Object { + "column": 10, + "line": 5, + "offset": 80, + }, + "start": Object { + "column": 1, + "line": 5, + "offset": 71, + }, + }, + "type": "footer", + }, + ], + "position": Object { + "end": Object { + "column": 10, + "line": 5, + "offset": 80, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "message", +} +`; + +exports[`<message> <body>, <newline>*, <footer>+ parses footer after body containing BREAKING CHANGE 1`] = ` +Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 4, + "line": 1, + "offset": 3, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "type", + "value": "fix", + }, + Object { + "position": Object { + "end": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + "start": Object { + "column": 4, + "line": 1, + "offset": 3, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + "start": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "position": Object { + "end": Object { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "type": "text", + "value": "address major bug", + }, + ], + "position": Object { + "end": Object { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "summary", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 16, "line": 3, - "offset": 56, + "offset": 39, }, "start": Object { "column": 1, @@ -99,6 +1075,70 @@ Object { "offset": 24, }, }, + "type": "breaking-change", + "value": "BREAKING CHANGE", + }, + Object { + "position": Object { + "end": Object { + "column": 17, + "line": 3, + "offset": 40, + }, + "start": Object { + "column": 16, + "line": 3, + "offset": 39, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 18, + "line": 3, + "offset": 41, + }, + "start": Object { + "column": 17, + "line": 3, + "offset": 40, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "position": Object { + "end": Object { + "column": 35, + "line": 3, + "offset": 58, + }, + "start": Object { + "column": 18, + "line": 3, + "offset": 41, + }, + }, + "type": "text", + "value": "this is breaking.", + }, + Object { + "position": Object { + "end": Object { + "column": 33, + "line": 4, + "offset": 91, + }, + "start": Object { + "column": 1, + "line": 4, + "offset": 59, + }, + }, "type": "text", "value": "this is a free form body of text", }, @@ -106,8 +1146,8 @@ Object { "position": Object { "end": Object { "column": 1, - "line": 4, - "offset": 57, + "line": 5, + "offset": 92, }, "start": Object { "column": 1, @@ -125,13 +1165,13 @@ Object { "position": Object { "end": Object { "column": 7, - "line": 4, - "offset": 63, + "line": 5, + "offset": 98, }, "start": Object { "column": 1, - "line": 4, - "offset": 57, + "line": 5, + "offset": 92, }, }, "type": "type", @@ -141,13 +1181,13 @@ Object { "position": Object { "end": Object { "column": 7, - "line": 4, - "offset": 63, + "line": 5, + "offset": 98, }, "start": Object { "column": 7, - "line": 4, - "offset": 63, + "line": 5, + "offset": 98, }, }, "type": "token", @@ -156,13 +1196,13 @@ Object { "position": Object { "end": Object { "column": 8, - "line": 4, - "offset": 64, + "line": 5, + "offset": 99, }, "start": Object { "column": 7, - "line": 4, - "offset": 63, + "line": 5, + "offset": 98, }, }, "type": "separator", @@ -172,13 +1212,13 @@ Object { "position": Object { "end": Object { "column": 9, - "line": 4, - "offset": 65, + "line": 5, + "offset": 100, }, "start": Object { "column": 8, - "line": 4, - "offset": 64, + "line": 5, + "offset": 99, }, }, "type": "whitespace", @@ -190,13 +1230,13 @@ Object { "position": Object { "end": Object { "column": 14, - "line": 4, - "offset": 70, + "line": 5, + "offset": 105, }, "start": Object { "column": 9, - "line": 4, - "offset": 65, + "line": 5, + "offset": 100, }, }, "type": "text", @@ -206,13 +1246,13 @@ Object { "position": Object { "end": Object { "column": 1, - "line": 5, - "offset": 71, + "line": 6, + "offset": 106, }, "start": Object { "column": 9, - "line": 4, - "offset": 65, + "line": 5, + "offset": 100, }, }, "type": "value", @@ -221,13 +1261,13 @@ Object { "position": Object { "end": Object { "column": 1, - "line": 5, - "offset": 71, + "line": 6, + "offset": 106, }, "start": Object { "column": 1, - "line": 4, - "offset": 57, + "line": 5, + "offset": 92, }, }, "type": "footer", @@ -240,13 +1280,13 @@ Object { "position": Object { "end": Object { "column": 5, - "line": 5, - "offset": 75, + "line": 6, + "offset": 110, }, "start": Object { "column": 1, - "line": 5, - "offset": 71, + "line": 6, + "offset": 106, }, }, "type": "type", @@ -256,13 +1296,13 @@ Object { "position": Object { "end": Object { "column": 5, - "line": 5, - "offset": 75, + "line": 6, + "offset": 110, }, "start": Object { "column": 5, - "line": 5, - "offset": 75, + "line": 6, + "offset": 110, }, }, "type": "token", @@ -271,13 +1311,13 @@ Object { "position": Object { "end": Object { "column": 7, - "line": 5, - "offset": 77, + "line": 6, + "offset": 112, }, "start": Object { "column": 5, - "line": 5, - "offset": 75, + "line": 6, + "offset": 110, }, }, "type": "separator", @@ -289,13 +1329,13 @@ Object { "position": Object { "end": Object { "column": 10, - "line": 5, - "offset": 80, + "line": 6, + "offset": 115, }, "start": Object { "column": 7, - "line": 5, - "offset": 77, + "line": 6, + "offset": 112, }, }, "type": "text", @@ -305,13 +1345,13 @@ Object { "position": Object { "end": Object { "column": 10, - "line": 5, - "offset": 80, + "line": 6, + "offset": 115, }, "start": Object { "column": 7, - "line": 5, - "offset": 77, + "line": 6, + "offset": 112, }, }, "type": "value", @@ -320,13 +1360,13 @@ Object { "position": Object { "end": Object { "column": 10, - "line": 5, - "offset": 80, + "line": 6, + "offset": 115, }, "start": Object { "column": 1, - "line": 5, - "offset": 71, + "line": 6, + "offset": 106, }, }, "type": "footer", @@ -335,8 +1375,8 @@ Object { "position": Object { "end": Object { "column": 10, - "line": 5, - "offset": 80, + "line": 6, + "offset": 115, }, "start": Object { "column": 1, @@ -944,6 +1984,222 @@ Object { } `; +exports[`<message> <footer> parses BREAKING CHANGE literal as <token> 2`] = ` +Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 4, + "line": 1, + "offset": 3, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "type", + "value": "fix", + }, + Object { + "position": Object { + "end": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + "start": Object { + "column": 4, + "line": 1, + "offset": 3, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + "start": Object { + "column": 5, + "line": 1, + "offset": 4, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "position": Object { + "end": Object { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": Object { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "type": "text", + "value": "address major bug", + }, + ], + "position": Object { + "end": Object { + "column": 23, + "line": 1, + "offset": 22, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "summary", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 16, + "line": 2, + "offset": 38, + }, + "start": Object { + "column": 1, + "line": 2, + "offset": 23, + }, + }, + "type": "breaking-change", + "value": "BREAKING-CHANGE", + }, + ], + "position": Object { + "end": Object { + "column": 16, + "line": 2, + "offset": 38, + }, + "start": Object { + "column": 1, + "line": 2, + "offset": 23, + }, + }, + "type": "token", + }, + Object { + "position": Object { + "end": Object { + "column": 17, + "line": 2, + "offset": 39, + }, + "start": Object { + "column": 16, + "line": 2, + "offset": 38, + }, + }, + "type": "separator", + "value": ":", + }, + Object { + "position": Object { + "end": Object { + "column": 18, + "line": 2, + "offset": 40, + }, + "start": Object { + "column": 17, + "line": 2, + "offset": 39, + }, + }, + "type": "whitespace", + "value": " ", + }, + Object { + "children": Array [ + Object { + "position": Object { + "end": Object { + "column": 41, + "line": 2, + "offset": 63, + }, + "start": Object { + "column": 18, + "line": 2, + "offset": 40, + }, + }, + "type": "text", + "value": "this change is breaking", + }, + ], + "position": Object { + "end": Object { + "column": 41, + "line": 2, + "offset": 63, + }, + "start": Object { + "column": 18, + "line": 2, + "offset": 40, + }, + }, + "type": "value", + }, + ], + "position": Object { + "end": Object { + "column": 41, + "line": 2, + "offset": 63, + }, + "start": Object { + "column": 1, + "line": 2, + "offset": 23, + }, + }, + "type": "footer", + }, + ], + "position": Object { + "end": Object { + "column": 41, + "line": 2, + "offset": 63, + }, + "start": Object { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "type": "message", +} +`; + exports[`<message> <footer> parses commit summary footer 1`] = ` Object { "children": Array [