recital / exporters / fountain / src / index.ts
index.ts
Raw
/**
 * Copyright (c) 2022 Amorphous
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import parse, { genFlattenedObject } from "@a-morphous/recital"

const splitStringIntoWords = (string) => {
	const splits = string.split(/\-|\_/gm)
	return splits.join(' ')
}

const capitalize = (string) => {
	return string[0].toUpperCase() + string.substring(1)
}

export const sceneToFountain = (scene) => {
	let text = ''

	// scene meta
	text += '===' + '\n\n'
	const flatScene = genFlattenedObject([scene])
	for (let token of flatScene) {
		switch (token.type) {
			case 'scene':
				// scenes start with . and are in all caps
				let sceneTitle = token.primary || 'scene'
				if (token.meta) {
					sceneTitle = token.meta.title || token.meta.scene || sceneTitle
				}
				text += '.' + splitStringIntoWords(sceneTitle).toUpperCase() + '\n\n'
				break
			case 'paragraph':
				let isDialogue = false
				if (token.primary) {
					// it's a character
					isDialogue = true
					text += '\t\t\t' + splitStringIntoWords(token.primary).toUpperCase() + '\n'
				}

				if (token.classes && token.classes.length > 1 && isDialogue) {
					// the remainder of the classes becomes the parenthetical
					const parenClasses = token.classes.concat([])
					parenClasses.splice(0, 1)
					text += '\t\t(' + capitalize(splitStringIntoWords(parenClasses.join(' '))) + ')\n'
				}

				// get the rest of the text in there
				if (!isDialogue) {
					text += token.text + '\n\n'
				} else {
					text += '\t' + token.text + '\n\n'
				}
				break
		}
	}
	return text
}

export const stageToFountain = (stageScriptString) => {
	let finalString = ''
	const scenes = parse(stageScriptString)

	for (let scene of scenes) {
		finalString += sceneToFountain(scene)
	}

	return finalString
}