/** * 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 moo from 'moo' import eol from 'eol' import { RawSceneObject } from '../../types' import { exposeMeta } from '../../tools/expose-meta' import { parseTOMLMeta } from '../../tools/parse-toml-meta' import { parseInlineMeta } from '../../tools/parse-inline-meta' export const genSceneObjects = (preprocessedString: string): RawSceneObject[] => { const scenes: RawSceneObject[] = [] const lexer = moo.states({ main: { sceneDefStart: { match: /\#[ \t]*\n/, lineBreaks: true, push: 'sceneDefinition' }, sceneWithTitleStart: { match: /\#:[ \t]*.*\n/, lineBreaks: true, push: 'sceneDefinition' }, text: { match: /[^]+?/, lineBreaks: true }, }, sceneDefinition: { tomlStartDash: { match: '---', push: 'sceneTomlDash' }, tomlStartPlus: { match: '+++', push: 'sceneTomlPlus' }, sceneDefEnd: { match: /\n/, lineBreaks: true, push: 'main' }, }, sceneTomlDash: { tomlEnd: { match: '---', push: 'sceneDefinition' }, toml: { match: /[^]+?(?=---)/, lineBreaks: true }, }, sceneTomlPlus: { tomlEnd: { match: '+++', push: 'sceneDefinition' }, toml: { match: /[^]+?(?=\+\+\+)/, lineBreaks: true }, } }) // first # can be omitted if we immediately start with toml frontmatter let lexerRaw = eol.lf(preprocessedString) if (lexerRaw.startsWith('---\n') || lexerRaw.startsWith('+++\n')) { lexerRaw = '#\n' + lexerRaw } lexer.reset(eol.lf(lexerRaw)) let currentScene: RawSceneObject = { type: 'scene', raw: '', } for (let token of Array.from(lexer) as any[]) { switch (token.type) { case 'sceneDefStart': if (!currentScene.raw.length) { continue } scenes.push(currentScene) currentScene = { type: 'scene', raw: '', } break case 'sceneWithTitleStart': if (currentScene.raw.length) { scenes.push(currentScene) } const inlineMeta: string = (token.value as string).substring(2).trim() const inlineMetaObject = inlineMeta ? parseInlineMeta(inlineMeta.trim()) : undefined currentScene = { type: 'scene', raw: '', meta: inlineMetaObject, } break case 'toml': const tomlObj = parseTOMLMeta(token.value) if (tomlObj === undefined) { throw new Error(lexer.formatError(token, 'empty TOML frontmatter in scene.')) } if (currentScene.meta) { currentScene.meta = { ...currentScene.meta, ...tomlObj } } else { currentScene.meta = tomlObj } exposeMeta(currentScene) break case 'text': currentScene.raw += token.value break } } if (currentScene.raw.length) { scenes.push(currentScene) } return scenes }