diff --git a/.gitignore b/.gitignore index 81d2659..5fff046 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,8 @@ local/ tmp/ .idea/ +report.*.json changelog.txt -npm-debug.log \ No newline at end of file +npm-debug.log +yarn.lock +.vscode/launch.json \ No newline at end of file diff --git a/parser.js b/parser.js index c7464c6..e46fb11 100644 --- a/parser.js +++ b/parser.js @@ -14,6 +14,7 @@ var regex = { transition: /^((?:FADE (?:TO BLACK|OUT)|CUT TO BLACK)\.|.+ TO\:|^TO\:$)|^(?:> *)(.+)/, dialogue: /^([A-Z*_]+[0-9A-Z (._\-')]*)(\^?)?(?:\n(?!\n+))([\s\S]+)/, + dialogue_double_line_break: /^\s*\{two spaces}\s*$/, character: /^([A-Z*_]+[0-9A-Z (._\-')]*)\^?$|^@.*$/, parenthetical: /^(\(.+\))$/, @@ -21,7 +22,7 @@ var regex = { centered: /^(?:> *)(.+)(?: *<)(\n.+)*/g, page_break: /^\={3,}$/, - line_break: /^ {2}$/ + line_break: /^ {2}$/, }; parser.parse = function(original_script, cfg) { @@ -184,7 +185,7 @@ parser.parse = function(original_script, cfg) { token.text = token.text.substr(1); } else if ((token.text.length > 0 && token.text[0] === "@") || (token.text === token.text.toUpperCase() && top_or_separated)) { if (i === lines_length || i === lines_length - 1 || lines[i + 1].trim().length === 0) { - token.type = "shot"; + token.type = "shot"; } else { state = "dialogue"; token.type = "character"; @@ -192,7 +193,7 @@ parser.parse = function(original_script, cfg) { if (token.text[token.text.length - 1] === "^") { if (cfg.use_dual_dialogue) { // update last dialogue to be dual:left - var dialogue_tokens = ["dialogue", "character", "parenthetical"]; + var dialogue_tokens = ["dialogue", "character", "parenthetical", "dialogue_double_line_break"]; while (dialogue_tokens.indexOf(result.tokens[last_character_index].type) !== -1) { result.tokens[last_character_index].dual = "left"; last_character_index++; @@ -209,8 +210,11 @@ parser.parse = function(original_script, cfg) { token.type = "action"; } } else { - if (token.text.match(regex.parenthetical)) { + if (token.text.match(regex.parenthetical)) { token.type = "parenthetical"; + } else if (token.text.match(regex.dialogue_double_line_break)) { + token.type = "dialogue_double_line_break"; + token.text = ""; } else { token.type = "dialogue"; } @@ -258,6 +262,14 @@ parser.parse = function(original_script, cfg) { result.tokens.splice(current_index, 0, additional_separator); current_index++; } + + if (current_token.is("dialogue_double_line_break")) { + var separators = + h.create_separator(token.end + 1, token.end + 1); + result.tokens.splice(current_index + 1, 0, separators); + current_index++; + } + previous_type = current_token.type; current_index++; } diff --git a/test/parser.test.js b/test/parser.test.js index 1fc66d1..d1e18b0 100644 --- a/test/parser.test.js +++ b/test/parser.test.js @@ -1,3 +1,5 @@ +/* eslint-disable quotes */ + var parser = require('../parser'); var testHelper = require('./helper/test-helper'); var chai = require('chai'); @@ -14,16 +16,18 @@ describe('Parser', function() { it('Parsing types', function() { config = testHelper.getConfigWith(true); - script = '#Section\n\n=Synopsis\n\nINT. HEADER 1\n\nAction\n\nHERO\n(Parenthetical)\nDialogue'; + script = '#Section\n\n=Synopsis\n\nINT. HEADER 1\n\nAction\n\nHERO\n(Parenthetical)\nDialogue\n {two spaces} \nDialogue'; result = parser.parse(script, config); testHelper.verifyTokenTypes(result.tokens, [ 'section', 'separator', 'synopsis', 'separator', 'scene_heading', 'separator', - 'action', 'separator', + 'action', 'separator', 'character', 'parenthetical', + 'dialogue', + 'dialogue_double_line_break', "separator", 'dialogue' ]); @@ -193,7 +197,36 @@ describe('Parser', function() { chai.assert.strictEqual(result.tokens[3].text, lines[3].trim()); }); + it('Adds double line break between dialogue', function() { + var lines = [ + 'HERO', + 'Dialogue line.', + '{two spaces}', // double line break - no spaces + 'Dialogue line.', + 'Dialogue line.', + ' {two spaces} ', // double line break - spaces + 'Dialogue line.' + ]; + + var renderedLines = [ + 'HERO', + 'Dialogue line.', + "", "", // double line break - no spaces + 'Dialogue line.', + 'Dialogue line.', + "", "", + 'Dialogue line.' + ]; + script = lines.join('\n'); + result = parser.parse(script, config); + testHelper.verifyTokenTypes(result.tokens, ['character', 'dialogue', 'dialogue_double_line_break', 'separator', 'dialogue', 'dialogue', 'dialogue_double_line_break', 'separator', 'dialogue']); + + result.tokens.forEach(function(token, index) { + chai.assert.strictEqual(token.text, renderedLines[index].trim()); + }); + }); }); + describe('Newline', function() {