UNPKG

aife-twee2

Version:

190 lines (161 loc) 5.21 kB
'use strict'; const {titleParser,} = require('./titleParser.js'); /** * @deprecated * @param {IPassage} passage * @return {IStoryMeta} */ function extractMetaFromStoryTitle(passage) { const meta = passage.tags.reduce((/** IStoryMeta */acc, tag) => { if (tag.startsWith('ifid-')) { acc.ifid = tag.replace('ifid-', ''); } if (tag.startsWith('story-format-')) { acc.format = tag.replace('story-format-', ''); } if (tag.startsWith('format-version-')) { acc.formatVer = tag.replace('format-version-', ''); } return acc; }, { title: passage.text, // sic! }); if (Object.keys(meta).length > 1) { console.warn('Using StoryTitle tags to pass metadata is deprecated, use StoryData passage as per Twee 3 spec.'); } return meta; } /** * @deprecated * @param {IPassage} passage * @return {IStoryMeta} */ function extractMetaFromStorySettings(passage) { const meta = passage.text.split(/\s*\n\s*/).reduce((/** IStoryMeta */acc, line) => { if (line !== '') { if (line.startsWith('ifid:')) { acc.ifid = line.replace('ifid:', ''); } if (line.startsWith('story-format:')) { acc.format = line.replace('story-format:', ''); } if (line.startsWith('format-version:')) { acc.formatVer = line.replace('format-version:', ''); } if (line.startsWith('tag-colors:')) { let tagColors; try { tagColors = JSON.parse(line.replace('tag-colors:', '')); } catch (e) { console.warn('Failed to parse tag colors:', e.message); tagColors = {}; } acc.tagColors = tagColors; } } return acc; }, {}); if (Object.keys(meta).length > 1) { console.warn('Using StorySettings to pass metadata is deprecated, use StoryData passage as per Twee 3 spec.'); } return meta; } function extractMetaFromStoryData(passage) { try { const meta = JSON.parse(passage.text); return { ifid: meta.ifid, format: meta.format, formatVer: meta['format-version'], tagColors: meta['tag-colors'] || {}, zoom: meta.zoom || 1, starting: meta.start, }; } catch (e) { return {}; } } /** * @param {string} storyString * @return {Partial<IStory>} */ function importTwee(storyString) { const passages = storyString.trim().split(/(?:\r?\n){2}::/mg); const story = passages.reduce( (/** {Partial<IStory>} */storyProgress, passageString, index) => { const passage = parsePassageString(passageString.trim()); if (passage.title === 'StoryTitle') { Object.assign(storyProgress, extractMetaFromStoryTitle(passage)); } else if (passage.title === 'StorySettings') { Object.assign(storyProgress, extractMetaFromStorySettings(passage)); } else if (passage.title === 'StoryData') { Object.assign(storyProgress, extractMetaFromStoryData(passage)); } else if (passage.tags.includes('stylesheet')) { storyProgress.styleSheet += passage.text + '\n'; // eslint-disable-line prefer-template } else if (passage.tags.includes('script')) { storyProgress.script += passage.text + '\n'; // eslint-disable-line prefer-template } else { storyProgress.passages.push( Object.assign( {pid: index + 1,}, passage ) ); } return storyProgress; }, { styleSheet: '', script: '', passages: [], } ); story.styleSheet = story.styleSheet.trim(); story.script = story.script.trim(); if (story.starting) { story.passages.forEach((passage) => { if (passage.title === story.starting) { passage.starting = true; } }); } else { story.passages.forEach((passage) => { if (passage.title === 'Start') { passage.starting = true; } }); } return story; } /** * @param {string} passageString * @return Partial<IPassage> */ function parsePassageString(passageString) { const passage = {}; const [titleLine, ...text] = passageString.split('\n'); const {title, tags, meta,} = titleParser(titleLine); passage.text = text.join('\n').trim(); const {x, y, width, height, ...rest} = meta; const position = { x, y, }; if (width !== undefined) { position.width = width; } if (height !== undefined) { position.height = height; } return { title, tags, starting: title === 'Start', position, text: text.join('\n').trim(), ...rest, }; } module.exports = { importTwee, };