/** * 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 { FlatObject, FragmentObject, SceneObject } from '@a-morphous/recital/dist/types/types' import { enforceIds, findObjectViaLink } from '../tools/stage-tools' import { parseWikiLink } from '../tools/text-tools' /** * Converts all the wiki links in a .stage file into valid Markdown links. * Wiki links have the format [[link]], and can also have an arrow to have text separate from the destination, e.g. * [[This is the displayed text->destination]] * @param stageObjects * @returns an array of FlatObjects that has all the text converted over */ export const convertWikiLinkToMd = (stageObjects: FlatObject[]): FlatObject[] => { const newFlatObjects: FlatObject[] = [] const stageObjectsWithId = enforceIds(stageObjects) for (let obj of stageObjectsWithId) { if (obj.type !== 'paragraph') { newFlatObjects.push(obj) continue } // now, we check for wikilinks. const newText = renderWikilinks(stageObjectsWithId, obj.text) newFlatObjects.push({ ...obj, text: newText, }) } return newFlatObjects } // inspired by // https://github.com/klembot/chapbook/blob/92e6d5c2b0e6c1cec10d4cad226bf207013746ca/src/template/render-links.js#L30 const renderWikilinks = (stageObjects: FlatObject[], source: string): string => { return source.replace(/\[\[(.*?)\]\]/g, (_, target) => { const parsedLink = parseWikiLink(target) return renderLink(stageObjects, parsedLink.target, parsedLink.label || parsedLink.target) }) } /** * Renders a markdown-style link from the target (which can resolve to an object) and a label * If the target does indeed resolve to an object, the link will point to the object's id * @param stageObjects reference list of objects that we can find links to * @param target string that can be the url (for an external link), or the title or primary of * the target object. Targets prefixed with '#' will only point to primaries. * @param label Text that is displayed on the link. * @returns */ const renderLink = (stageObjects: FlatObject[], target: string, label: string) => { if (/^\w+:\/\/\/?\w/i.test(target)) { // this is an external link. We convert it as-is to a Markdown link. return `[${label}](${target})` } const linkTarget = findObjectViaLink(stageObjects, target) if (!linkTarget) { console.warn( 'link to ' + target + ' did not produce a valid link, and may not resolve correctly in editor.' ) return `[${label}](${target})` } return `[${label}](${getHrefForObject(linkTarget)})` } /** * Gets what should go into the link for the object. * This keys off of id. * @param object */ const getHrefForObject = (object: SceneObject | FragmentObject) => { if (!object.id) { throw new Error('Cannot create a link to an object without an id') } return `#${object.id}` }