Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fountain-js

Package Overview
Dependencies
Maintainers
2
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fountain-js - npm Package Compare versions

Comparing version 1.1.2 to 1.1.3

16

CHANGELOG.md

@@ -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 @@

2

dist.esm/lexer.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc