fountain-js
Advanced tools
Comparing version 1.1.2 to 1.1.3
@@ -9,2 +9,18 @@ # Change Log | ||
## [1.1.3] - 2023-09-24 | ||
### Fixed | ||
- scene headings have more variation like `I./E.` is now valid where originally it wasn't. | ||
- Lyrics work better in dialogue and do not create multiple paragraph tags if there is more than one line of singing in the character's speech. | ||
- multiple spaces after a parenthetical no longer breaks the parenthetical and turns it into speech. | ||
- hanging parentheticals (at the end of dialogue) no longer disappear or break dialogue. | ||
### Changed | ||
- regex cleanup and removal of unnecessary capturing groups. | ||
- centered text is now stripped of all whitespace. | ||
- parentheticals now work with emphasis outside of the parenthesis e.g. `*(ah, wonderful)*` as well as inside. | ||
- all forms of emphasis around the parenthetical are now accepted. | ||
## [1.1.2] - 2023-09-17 | ||
@@ -11,0 +27,0 @@ |
@@ -40,5 +40,5 @@ import { regex } from './regex'; | ||
} | ||
return line.replace(/\[star\]/g, '*').replace(/\[underline\]/g, '_').trim(); | ||
return line.replace(/\[star]/g, '*').replace(/\[underline]/g, '_').trim(); | ||
} | ||
} | ||
//# sourceMappingURL=lexer.js.map |
@@ -18,3 +18,2 @@ export declare const regex: { | ||
line_break: RegExp; | ||
emphasis: RegExp; | ||
bold_italic_underline: RegExp; | ||
@@ -21,0 +20,0 @@ bold_underline: RegExp; |
export const regex = { | ||
title_page: /^((?:title|credit|author[s]?|source|notes|draft date|date|contact|copyright)\:)/gim, | ||
scene_heading: /^((?:\*{0,3}_?)?(?:(?:in|ex)t(?:\/ext)?|est|i\/e)[. ].+)|^(?:\.(?!\.+))(\S.*)/i, | ||
title_page: /^((?:title|credit|authors?|source|notes|draft date|date|contact|copyright)\:)/gim, | ||
scene_heading: /^((?:\*{0,3}_?)?(?:(?:int|i)\.?\/(?:ext|e)|int|ext|est)[. ].+)|^\.(?!\.+)(\S.*)/i, | ||
scene_number: /( *#(.+)# *)/, | ||
transition: /^((?:FADE (?:TO BLACK|OUT)|CUT TO BLACK)\.|.+ TO\:)|^(?:> *)(.+)/, | ||
dialogue: /(?!^[0-9 _*]+(?:\(.*\))?[ *_]*(?:\^?)?\s*\n)(^(?:(?!\\?@|!)[^\^\(\)\na-z]+|@[^\^\(\)\n]+)(?:[ ]*\(.*\))?[ *_]*)(\^?)?\s*(?:\n(?!\n+))([\s\S]+)/, | ||
parenthetical: /^(\(.+\))$/, | ||
transition: /^((?:FADE (?:TO BLACK|OUT)|CUT TO BLACK)\.|.+ TO\:)|^> *(.+)/, | ||
dialogue: /(?!^[0-9 _*]+(?:\(.*\))?[ *_]*(?:\^?)?\s*\n)(^(?:(?!\\?@|!)[^^()\na-z]+|@[^^()\n]+)(?: *\(.*\))?[ *_]*)(\^?)?\s*\n(?!\n+)([\s\S]+)/, | ||
parenthetical: /^ *(?:(?<u1>_{0,1})(?<s1>\*{0,3})(?=.+\k<s1>\k<u1>)|(?<s2>\*{0,3})(?<u2>_{0,1})(?=.+\k<u2>\k<s2>))(\(.+?\))(\k<s1>\k<u1>|\k<u2>\k<s2>) *$/, | ||
action: /^(.+)/g, | ||
centered: /^(?:> *)(.+)(?: *<)(\n.+)*/g, | ||
lyrics: /^~(?![ ]).+(?:\n.+)*/, | ||
section: /^(#+)(?: *)(.*)/, | ||
centered: /^> *(.+) *<(\n.+)*/g, | ||
lyrics: /^~(?! ).+(?:\n~(?! ).+)*/, | ||
section: /^(#+) *(.*)/, | ||
synopsis: /^(?:\=(?!\=+) *)(.*)/, | ||
note: /^(?:\[{2}(?!\[+))(.+)(?:\]{2}(?!\[+))$/, | ||
note_inline: /(?:\[{2}(?!\[+))([\s\S]+?)(?:\]{2}(?!\[+))/g, | ||
note: /^\[{2}(?!\[+)(.+)]{2}(?!\[+)$/, | ||
note_inline: /\[{2}(?!\[+)([\s\S]+?)]{2}(?!\[+)/g, | ||
boneyard: /(^\/\*|^\*\/)$/g, | ||
page_break: /^\={3,}$/, | ||
page_break: /^={3,}$/, | ||
line_break: /^ {2}$/, | ||
emphasis: /(_|\*{1,3}|_\*{1,3}|\*{1,3}_)(.+)(_|\*{1,3}|_\*{1,3}|\*{1,3}_)/g, | ||
bold_italic_underline: /(_{1}\*{3}(?=.+\*{3}_{1})|\*{3}_{1}(?=.+_{1}\*{3}))(.+?)(\*{3}_{1}|_{1}\*{3})/g, | ||
bold_underline: /(_{1}\*{2}(?=.+\*{2}_{1})|\*{2}_{1}(?=.+_{1}\*{2}))(.+?)(\*{2}_{1}|_{1}\*{2})/g, | ||
italic_underline: /(_{1}\*{1}(?=.+\*{1}_{1})|\*{1}_{1}(?=.+_{1}\*{1}))(.+?)(\*{1}_{1}|_{1}\*{1})/g, | ||
bold_italic_underline: /(_\*{3}(?=.+\*{3}_)|\*{3}_(?=.+_\*{3}))(.+?)(\*{3}_|_\*{3})/g, | ||
bold_underline: /(_\*{2}(?=.+\*{2}_)|\*{2}_(?=.+_\*{2}))(.+?)(\*{2}_|_\*{2})/g, | ||
italic_underline: /(_\*(?=.+\*_)|\*_(?=.+_\*))(.+?)(\*_|_\*)/g, | ||
bold_italic: /(\*{3}(?=.+\*{3}))(.+?)(\*{3})/g, | ||
bold: /(\*{2}(?=.+\*{2}))(.+?)(\*{2})/g, | ||
italic: /(\*{1}(?=.+\*{1}))(.+?)(\*{1})/g, | ||
underline: /(_{1}(?=.+_{1}))(.+?)(_{1})/g, | ||
italic: /(\*(?=.+\*))(.+?)(\*)/g, | ||
underline: /(_(?=.+_))(.+?)(_)/g, | ||
splitter: /\n{2,}/g, | ||
@@ -27,0 +26,0 @@ cleaner: /^\n+|\n+$/, |
@@ -48,3 +48,3 @@ import { regex } from './regex'; | ||
const match = line.match(regex.centered); | ||
this.text = match[0].replace(/>|</g, ''); | ||
this.text = match[0].replace(/ *[><] */g, ''); | ||
} | ||
@@ -76,7 +76,4 @@ addTo(tokens) { | ||
let name = match[1]; | ||
if (name.startsWith('@')) { | ||
name = name.substring(1); | ||
} | ||
// iterating from the bottom up, so push dialogue blocks in reverse order | ||
const isDualDialogue = !!(match[2]); | ||
const isDualDialogue = !!match[2]; | ||
if (isDualDialogue) { | ||
@@ -86,4 +83,6 @@ this.tokens.push(new DualDialogueEndToken()); | ||
this.tokens.push(new DialogueEndToken()); | ||
const parts = match[3].split(/(\(.+\))(?:\n+)/).reverse(); | ||
this.tokens.push(...parts.reduce((p, text = '') => { | ||
const parts = match[3].split(/\n/); | ||
let dialogue = parts.reduce((p, text = '') => { | ||
const lastIndex = p.length - 1; | ||
const previousToken = p[lastIndex]; | ||
if (!text.length) { | ||
@@ -96,7 +95,23 @@ return p; | ||
if (regex.lyrics.test(text)) { | ||
return [...p, new LyricsToken(text)]; | ||
if (previousToken.type === 'lyrics') { | ||
p[lastIndex].text = | ||
`${previousToken.text}\n${text.replace(/^~/, '')}`; | ||
return p; | ||
} | ||
else { | ||
return [...p, new LyricsToken(text)]; | ||
} | ||
} | ||
if (previousToken) { | ||
if (previousToken.type === 'dialogue') { | ||
p[lastIndex].text = `${previousToken.text}\n${text}`; | ||
return p; | ||
} | ||
} | ||
return [...p, new DialogueToken(text)]; | ||
}, [])); | ||
this.tokens.push(new CharacterToken(name.trim()), new DialogueBeginToken(isDualDialogue ? 'right' : dual ? 'left' : undefined)); | ||
}, []).reverse(); | ||
this.tokens.push(...dialogue); | ||
this.tokens.push(new CharacterToken(name.startsWith('@') | ||
? name.replace(/^@/, '').trim() | ||
: name.trim()), new DialogueBeginToken(isDualDialogue ? 'right' : dual ? 'left' : undefined)); | ||
if (dual) { | ||
@@ -177,3 +192,3 @@ this.tokens.push(new DualDialogueBeginToken()); | ||
this.type = 'lyrics'; | ||
this.text = line.replace(/^~(?![ ])/gm, ''); | ||
this.text = line.replace(/^~(?! )/gm, ''); | ||
} | ||
@@ -264,3 +279,3 @@ addTo(tokens) { | ||
this.type = 'action'; | ||
this.text = line.replace(/^!(?![ ])/gm, ''); | ||
this.text = line.replace(/^!(?! )/gm, ''); | ||
} | ||
@@ -267,0 +282,0 @@ addTo(tokens) { |
@@ -44,3 +44,3 @@ "use strict"; | ||
} | ||
return line.replace(/\[star\]/g, '*').replace(/\[underline\]/g, '_').trim(); | ||
return line.replace(/\[star]/g, '*').replace(/\[underline]/g, '_').trim(); | ||
} | ||
@@ -47,0 +47,0 @@ } |
@@ -18,3 +18,2 @@ export declare const regex: { | ||
line_break: RegExp; | ||
emphasis: RegExp; | ||
bold_italic_underline: RegExp; | ||
@@ -21,0 +20,0 @@ bold_underline: RegExp; |
@@ -5,26 +5,25 @@ "use strict"; | ||
exports.regex = { | ||
title_page: /^((?:title|credit|author[s]?|source|notes|draft date|date|contact|copyright)\:)/gim, | ||
scene_heading: /^((?:\*{0,3}_?)?(?:(?:in|ex)t(?:\/ext)?|est|i\/e)[. ].+)|^(?:\.(?!\.+))(\S.*)/i, | ||
title_page: /^((?:title|credit|authors?|source|notes|draft date|date|contact|copyright)\:)/gim, | ||
scene_heading: /^((?:\*{0,3}_?)?(?:(?:int|i)\.?\/(?:ext|e)|int|ext|est)[. ].+)|^\.(?!\.+)(\S.*)/i, | ||
scene_number: /( *#(.+)# *)/, | ||
transition: /^((?:FADE (?:TO BLACK|OUT)|CUT TO BLACK)\.|.+ TO\:)|^(?:> *)(.+)/, | ||
dialogue: /(?!^[0-9 _*]+(?:\(.*\))?[ *_]*(?:\^?)?\s*\n)(^(?:(?!\\?@|!)[^\^\(\)\na-z]+|@[^\^\(\)\n]+)(?:[ ]*\(.*\))?[ *_]*)(\^?)?\s*(?:\n(?!\n+))([\s\S]+)/, | ||
parenthetical: /^(\(.+\))$/, | ||
transition: /^((?:FADE (?:TO BLACK|OUT)|CUT TO BLACK)\.|.+ TO\:)|^> *(.+)/, | ||
dialogue: /(?!^[0-9 _*]+(?:\(.*\))?[ *_]*(?:\^?)?\s*\n)(^(?:(?!\\?@|!)[^^()\na-z]+|@[^^()\n]+)(?: *\(.*\))?[ *_]*)(\^?)?\s*\n(?!\n+)([\s\S]+)/, | ||
parenthetical: /^ *(?:(?<u1>_{0,1})(?<s1>\*{0,3})(?=.+\k<s1>\k<u1>)|(?<s2>\*{0,3})(?<u2>_{0,1})(?=.+\k<u2>\k<s2>))(\(.+?\))(\k<s1>\k<u1>|\k<u2>\k<s2>) *$/, | ||
action: /^(.+)/g, | ||
centered: /^(?:> *)(.+)(?: *<)(\n.+)*/g, | ||
lyrics: /^~(?![ ]).+(?:\n.+)*/, | ||
section: /^(#+)(?: *)(.*)/, | ||
centered: /^> *(.+) *<(\n.+)*/g, | ||
lyrics: /^~(?! ).+(?:\n~(?! ).+)*/, | ||
section: /^(#+) *(.*)/, | ||
synopsis: /^(?:\=(?!\=+) *)(.*)/, | ||
note: /^(?:\[{2}(?!\[+))(.+)(?:\]{2}(?!\[+))$/, | ||
note_inline: /(?:\[{2}(?!\[+))([\s\S]+?)(?:\]{2}(?!\[+))/g, | ||
note: /^\[{2}(?!\[+)(.+)]{2}(?!\[+)$/, | ||
note_inline: /\[{2}(?!\[+)([\s\S]+?)]{2}(?!\[+)/g, | ||
boneyard: /(^\/\*|^\*\/)$/g, | ||
page_break: /^\={3,}$/, | ||
page_break: /^={3,}$/, | ||
line_break: /^ {2}$/, | ||
emphasis: /(_|\*{1,3}|_\*{1,3}|\*{1,3}_)(.+)(_|\*{1,3}|_\*{1,3}|\*{1,3}_)/g, | ||
bold_italic_underline: /(_{1}\*{3}(?=.+\*{3}_{1})|\*{3}_{1}(?=.+_{1}\*{3}))(.+?)(\*{3}_{1}|_{1}\*{3})/g, | ||
bold_underline: /(_{1}\*{2}(?=.+\*{2}_{1})|\*{2}_{1}(?=.+_{1}\*{2}))(.+?)(\*{2}_{1}|_{1}\*{2})/g, | ||
italic_underline: /(_{1}\*{1}(?=.+\*{1}_{1})|\*{1}_{1}(?=.+_{1}\*{1}))(.+?)(\*{1}_{1}|_{1}\*{1})/g, | ||
bold_italic_underline: /(_\*{3}(?=.+\*{3}_)|\*{3}_(?=.+_\*{3}))(.+?)(\*{3}_|_\*{3})/g, | ||
bold_underline: /(_\*{2}(?=.+\*{2}_)|\*{2}_(?=.+_\*{2}))(.+?)(\*{2}_|_\*{2})/g, | ||
italic_underline: /(_\*(?=.+\*_)|\*_(?=.+_\*))(.+?)(\*_|_\*)/g, | ||
bold_italic: /(\*{3}(?=.+\*{3}))(.+?)(\*{3})/g, | ||
bold: /(\*{2}(?=.+\*{2}))(.+?)(\*{2})/g, | ||
italic: /(\*{1}(?=.+\*{1}))(.+?)(\*{1})/g, | ||
underline: /(_{1}(?=.+_{1}))(.+?)(_{1})/g, | ||
italic: /(\*(?=.+\*))(.+?)(\*)/g, | ||
underline: /(_(?=.+_))(.+?)(_)/g, | ||
splitter: /\n{2,}/g, | ||
@@ -31,0 +30,0 @@ cleaner: /^\n+|\n+$/, |
@@ -54,3 +54,3 @@ "use strict"; | ||
const match = line.match(regex_1.regex.centered); | ||
this.text = match[0].replace(/>|</g, ''); | ||
this.text = match[0].replace(/ *[><] */g, ''); | ||
} | ||
@@ -84,7 +84,4 @@ addTo(tokens) { | ||
let name = match[1]; | ||
if (name.startsWith('@')) { | ||
name = name.substring(1); | ||
} | ||
// iterating from the bottom up, so push dialogue blocks in reverse order | ||
const isDualDialogue = !!(match[2]); | ||
const isDualDialogue = !!match[2]; | ||
if (isDualDialogue) { | ||
@@ -94,4 +91,6 @@ this.tokens.push(new DualDialogueEndToken()); | ||
this.tokens.push(new DialogueEndToken()); | ||
const parts = match[3].split(/(\(.+\))(?:\n+)/).reverse(); | ||
this.tokens.push(...parts.reduce((p, text = '') => { | ||
const parts = match[3].split(/\n/); | ||
let dialogue = parts.reduce((p, text = '') => { | ||
const lastIndex = p.length - 1; | ||
const previousToken = p[lastIndex]; | ||
if (!text.length) { | ||
@@ -104,7 +103,23 @@ return p; | ||
if (regex_1.regex.lyrics.test(text)) { | ||
return [...p, new LyricsToken(text)]; | ||
if (previousToken.type === 'lyrics') { | ||
p[lastIndex].text = | ||
`${previousToken.text}\n${text.replace(/^~/, '')}`; | ||
return p; | ||
} | ||
else { | ||
return [...p, new LyricsToken(text)]; | ||
} | ||
} | ||
if (previousToken) { | ||
if (previousToken.type === 'dialogue') { | ||
p[lastIndex].text = `${previousToken.text}\n${text}`; | ||
return p; | ||
} | ||
} | ||
return [...p, new DialogueToken(text)]; | ||
}, [])); | ||
this.tokens.push(new CharacterToken(name.trim()), new DialogueBeginToken(isDualDialogue ? 'right' : dual ? 'left' : undefined)); | ||
}, []).reverse(); | ||
this.tokens.push(...dialogue); | ||
this.tokens.push(new CharacterToken(name.startsWith('@') | ||
? name.replace(/^@/, '').trim() | ||
: name.trim()), new DialogueBeginToken(isDualDialogue ? 'right' : dual ? 'left' : undefined)); | ||
if (dual) { | ||
@@ -193,3 +208,3 @@ this.tokens.push(new DualDialogueBeginToken()); | ||
this.type = 'lyrics'; | ||
this.text = line.replace(/^~(?![ ])/gm, ''); | ||
this.text = line.replace(/^~(?! )/gm, ''); | ||
} | ||
@@ -287,3 +302,3 @@ addTo(tokens) { | ||
this.type = 'action'; | ||
this.text = line.replace(/^!(?![ ])/gm, ''); | ||
this.text = line.replace(/^!(?! )/gm, ''); | ||
} | ||
@@ -290,0 +305,0 @@ addTo(tokens) { |
{ | ||
"name": "fountain-js", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"description": "A simple parser for Fountain, a markup language for formatting screenplays.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
96278
1456