UNPKG

markdown-it-wikirefs

Version:

markdown-it plugin to add wikirefs (including [[wikilinks]])

920 lines (836 loc) 31.7 kB
// markdown-it-wikirefs v0.0.2 - https://github.com/wikibonsai/markdown-it-wikirefs.git import path from 'path'; import { merge } from 'lodash'; import * as wikirefs from 'wikirefs'; // perform any file preparations before we do anything -- // (like flush the current file's entry in index if there is one) const prep_file = (md, opts) => { // insert the 'prep_file' token after all wikirefs have been tokenized. // this way, when 'prep_file' calls 'unshift' (see above) it will place the // render rule in front of all other tokens. otherwise, it might get shuffled // into an index other than the first one. md.core.ruler.push('prep_file', prep_file); function prep_file(state) { if (opts.prepFile) { const tok = new state.Token('trigger_prep_file', '', 0); state.tokens.unshift(tok); } } md.renderer.rules.trigger_prep_file = trigger_prep_file; /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function trigger_prep_file(tokens, index, mdOpts, env) { if (opts.prepFile) { opts.prepFile(env); } return ''; } }; const wikiattrs = (md, opts) => { // rulers // '.getRules('attrs')' is really testing for markdown-it-'caml' // 'attrs' is added as an extra dummy 'alt' specifically for this purpose // (directly accessing the 'caml' rule would be ideal, but markdown-it // doesn't seem to have a mechanism for that and not sure how to // attach a 'name' property to sinon fakes) const attrRules = md.block.ruler.getRules('attrs'); if (opts.attrs.render && attrRules.length === 0) { // the 'attrbox' rule is the midpoint between the parse and render rules. md.core.ruler.after('inline', 'wiki_attrbox', wiki_attrbox); } // should execute just after 'markdown-it-caml': // [ ..., 'hr', 'caml', 'wikiattr', 'list', ... ] md.block.ruler.before('list', 'wikiattr', wikiattr, { alt: ['paragraph', 'reference', 'blockquote', 'list', 'attrs'] }); // in case bugs show up: [ 'paragraph', 'reference', 'blockquote', 'list' ] // render md.renderer.rules.metadata_wikiattr = metadata_wikiattr; md.renderer.rules.wikiattr_open = wikiattr_open; md.renderer.rules.wikiattr_key = wikiattr_key; md.renderer.rules.wikiattr_val = wikiattr_val; md.renderer.rules.wikiattr_close = wikiattr_close; // rulers function wikiattr(state, startLine, endLine, silent) { // return false cases // //// // skip indented code blocks // from: https://github.com/markdown-it/markdown-it/blob/df4607f1d4d4be7fdc32e71c04109aea8cc373fa/lib/rules_block/list.js#L132 // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false; } //// // 'wikiattrs' must be at the top-most-level // todo: how to interrupt? // !('list' | 'blockquote' | 'reference' | 'footnote') if (state.parentType !== 'root' && state.parentType !== 'paragraph') { return false; } //// // check for matches // 'bMarks' = beginning of line markers // 'eMarks' = end of line markers let pos = state.bMarks[startLine]; let max = state.eMarks[startLine]; const thisChunk = state.src.substring(pos, max); const lineOneMatch = wikirefs.RGX.ATTR_LINE.TYPE.exec(thisChunk); // no match if (lineOneMatch === null) { return false; } // is in a list item // note: this is only necessary for unprefixed wikiattrs // todo: keep an eye on this...might cause problems... if (lineOneMatch[0].indexOf('- ') === 0 || lineOneMatch[0].indexOf('* ') === 0 || lineOneMatch[0].indexOf('+ ') === 0) { return false; } // "Don't run any pairs in validation mode": // 'silent' is used when this rule is being checked against // in another rule to see whether or not the other rule should // kick out for this (or some other) one. return 'true' to // signify that the kick out should happen if (silent) { return true; } // handle match and return true // let iterLine = 0; let m; const curFilenames = []; const attrTypeText = lineOneMatch[1].trim(); const filenamesText = lineOneMatch[2]; // links // - comma-separated list; '2' would be the first wikilink's filename if (filenamesText !== null && filenamesText !== undefined) { iterLine += 1; const gottaCatchEmAll = new RegExp(`${wikirefs.RGX.WIKI.BASE.source}`, 'ig'); // loop through all matches from 'g'lobal regex // do-while: https://stackoverflow.com/a/6323598 do { m = gottaCatchEmAll.exec(lineOneMatch[0]); if (m !== null) { // m[0]: full match; // m[1]: filename; curFilenames.push(m[1]); } } while (m); // - markdown-style list } else { // loop through each markdown-style list item // do-while: https://stackoverflow.com/a/6323598 do { // increment iterLine += 1; pos = state.bMarks[startLine + iterLine]; max = state.eMarks[startLine + iterLine]; const thisSubChunk = state.src.substring(pos, max); m = wikirefs.RGX.ATTR_LINE.LIST_ITEM.exec(thisSubChunk); if (m !== null) { // m[0]: full match; // m[1]: bullet type; // m[2]: wikistring; // m[3]: filename; curFilenames.push(m[3]); } } while (m); } // set 'state.env.attrs' to trigger tokens -- if valid. if (curFilenames.length === 0) { return false; } else { // init if (!state.env.attrs) { state.env.attrs = {}; } if (!state.env.attrs[attrTypeText]) { state.env.attrs[attrTypeText] = []; } // prep renderables for (const fname of curFilenames) { state.env.attrs[attrTypeText].push({ type: 'wiki', filename: fname }); } // metadata if (opts.addAttr) { const tok = new state.Token('metadata_wikiattr', '', 0); state.tokens.push(tok); tok.attrSet('key', attrTypeText); // note: tokens technically should only accept 'string' or 'null'...but an array of strings works so nicely here... tok.attrSet('vals', state.env.attrs[attrTypeText].map(item => item.filename)); } // continue; increment position state.line += iterLine; return true; } } function wiki_attrbox(state) { if (!state.env.attrs || Object.keys(state.env.attrs).length === 0) { return; } const tokens = []; // open // const tokOpen = new state.Token('wikiattr_open', '', 0); // tokOpen.map = [startLine, iterLine]; tokens.push(tokOpen); // body // for (const attrtype in state.env.attrs) { // key / attrtype const tokType = new state.Token('wikiattr_key', '', 0); tokType.attrSet('key', attrtype); tokens.push(tokType); // values / items for (const item of state.env.attrs[attrtype]) { const tokItem = new state.Token('wikiattr_val', '', 1); if (item.type === 'wiki') { const filename = item.filename; if (!filename) { continue; } tokItem.attrSet('key', attrtype); tokItem.attrSet('val', filename); } tokens.push(tokItem); } } // close // const tokClose = new state.Token('wikiattr_close', '', 0); tokens.push(tokClose); // add infobox to **front** of token stream if (tokens) { state.tokens = tokens.concat(state.tokens); } } // tokens /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function metadata_wikiattr(tokens, index, mdOpts, env) { const token = tokens[index]; const attrtype = token.attrGet('key'); // @ts-expect-error: forcing array -- technically not supposed to, but it works so nicely here (see note above) const filenames = token.attrGet('vals'); if (attrtype && filenames && opts.addAttr) { for (const filename of filenames) { opts.addAttr(env, attrtype, filename); } } return ''; } // render // example render output: // // <aside class="attrbox"> // <span class="attrbox-title">Attributes</span> // <dl> // <dt>attrtype</dt> // <dd><a class="attr wiki attrtype doctype" href="/tests/fixtures/fname-a" data-href="/tests/fixtures/fname-a">title a</a></dd> // <dd><a class="attr wiki attrtype doctype" href="/tests/fixtures/fname-b" data-href="/tests/fixtures/fname-b">title b</a></dd> // <dd><a class="attr wiki attrtype doctype" href="/tests/fixtures/fname-c" data-href="/tests/fixtures/fname-c">title c</a></dd> // ... // </dl> // </aside> /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiattr_open(tokens, index, mdOpts, env) { return `<aside class="${opts.cssNames.attrbox}">\n<span class="${opts.cssNames.attrboxTitle}">${opts.attrs.title}</span>\n<dl>\n`; } // attr : key : attrtype /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiattr_key(tokens, index, mdOpts, env) { const token = tokens[index]; const attrtype = token.attrGet('key'); return attrtype ? `<dt>${attrtype}</dt>\n` : '<dt>attrtype error</dt>\n'; } // attr : val(s) : item(s) /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiattr_val(tokens, index, mdOpts, env) { // load const token = tokens[index]; if (token === null) { return '<dd>token error</dd>\n'; } const filename = token.attrGet('val'); if (filename === null) { return '<dd>filename error</dd>\n'; } const htmlHref = opts.resolveHtmlHref(env, filename); const htmlText = opts.resolveHtmlText(env, filename) ? opts.resolveHtmlText(env, filename) : filename; const doctype = opts.resolveDocType ? opts.resolveDocType(env, filename) : ''; // render // invalid if (htmlHref === undefined) { const wikitext = filename !== null ? filename : 'error'; return `<dd><a class="${opts.cssNames.attr} ${opts.cssNames.wiki} ${opts.cssNames.invalid}">[[${wikitext}]]</a></dd>\n`; // valid } else { const attrtype = token.attrGet('key'); // css const cssClassArray = []; // 'attr' if (attrtype !== null && attrtype !== undefined) { cssClassArray.push(opts.cssNames.attr); } // 'wiki' cssClassArray.push(opts.cssNames.wiki); if (attrtype !== null && attrtype !== undefined) { const attrTypeSlug = attrtype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(opts.cssNames.reftype + attrTypeSlug); } // '<doctype>' if (doctype !== null && doctype !== undefined && doctype.length !== 0) { const docTypeSlug = doctype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(opts.cssNames.doctype + docTypeSlug); } const css = cssClassArray.join(' '); return `<dd><a class="${css}" href="${opts.baseUrl + htmlHref}" data-href="${opts.baseUrl + htmlHref}">${htmlText}</a></dd>\n`; } } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiattr_close(tokens, index, mdOpts, env) { delete env.cur_attr_type; return '</dl>\n</aside>\n'; } }; const wikilinks = (md, opts) => { // rulers md.inline.ruler.after('link', 'wikilink', wikilink); // render md.renderer.rules.metadata_wikilink = metadata_wikilink; md.renderer.rules.wikilink_open = wikilink_open; md.renderer.rules.wikilink_body = wikilink_body; md.renderer.rules.wikilink_close = wikilink_close; // rulers function wikilink(state, silent) { const srcText = state.src.substring(state.pos); // process match info const match = wikirefs.RGX.WIKI.LINK.exec(srcText); if (match == null || match.length < 1 || match.index !== 0) { return false; } // uncomment in case of skip wikiembeds // const embedChar: string = state.src.substring(state.pos - 1, state.pos); // if (embedChar === '!') { // return false; // } const matchText = match[0]; const linkTypeText = match[1] ? match[1].trim() : match[1]; const filenameText = match[2]; // const headerText : string = match[4]; // const blockText : string = match[5]; const labelText = match[3]; // handle early kick-out if we've hit a stop-char early // // untyped if (!linkTypeText && srcText[0] !== '[') { return false; } // typed if (linkTypeText && srcText[0] !== ':') { return false; } // "Don't run any pairs in validation mode": // 'silent' is used when this rule is being checked against // in another rule to see whether or not the other rule should // kick out for this (or some other) one. return 'true' to // signify that the kick out should happen if (silent) { return false; } let token; // open // token = state.push('wikilink_open', 'wikilink', 0); token.attrSet('filename', filenameText); if (linkTypeText !== null && linkTypeText !== undefined && linkTypeText.length !== 0) { token.attrSet('linktype', linkTypeText); } // body // token = state.push('wikilink_body', '', 0); token.attrSet('filename', filenameText); token.attrSet('matchText', matchText); if (labelText) { token.attrSet('label', labelText); } // close // token = state.push('wikilink_close', 'wikilink', 0); // metadata if (opts.addLink) { token = state.push('metadata_wikilink', 'wikilink', 0); token.attrSet('linktype', linkTypeText); token.attrSet('filename', filenameText); } // continue; increment position state.pos += matchText.length; return true; } // render /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function metadata_wikilink(tokens, index, mdOpts, env) { const token = tokens[index]; if (token === null) { return 'token error'; } // don't let 'linktype' be 'null' -- untyped wikilinks have empty strings for 'linktype' const linktype = token.attrGet('linktype') ? token.attrGet('linktype') : ''; const filename = token.attrGet('filename'); if (linktype !== null && filename !== null && opts.addLink) { opts.addLink(env, linktype, filename); } return ''; } // render // typed // // <a class="wiki link type linktype doctype" href="/tests/fixtures/fname-a" data-href="/tests/fixtures/fname-a">title a</a> // // untyped // // <a class="wiki link doctype" href="/tests/fixtures/fname-a" data-href="/tests/fixtures/fname-a">title a</a> /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikilink_open(tokens, index, mdOpts, env) { // load const token = tokens[index]; const invalidOpen = `<a class="${opts.cssNames.wiki} ${opts.cssNames.link} ${opts.cssNames.invalid}">`; if (token === null) { return invalidOpen; } const filename = token.attrGet('filename'); const linktype = token.attrGet('linktype'); if (filename === null) { return invalidOpen; } const htmlHref = opts.resolveHtmlHref(env, filename); const doctype = opts.resolveDocType ? opts.resolveDocType(env, filename) : ''; // render // invalid if (htmlHref === undefined) { return invalidOpen; // valid } else { // build css string const cssClassArray = []; // wikilink cssClassArray.push(opts.cssNames.wiki); cssClassArray.push(opts.cssNames.link); // linktype if (linktype !== null && linktype !== undefined && linktype.length !== 0) { cssClassArray.push(opts.cssNames.type); const linkTypeSlug = linktype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(opts.cssNames.reftype + linkTypeSlug); } // doctype if (doctype) { const docTypeSlug = doctype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(opts.cssNames.doctype + docTypeSlug); } const css = cssClassArray.join(' '); return `<a class="${css}" href="${opts.baseUrl + htmlHref}" data-href="${opts.baseUrl + htmlHref}">`; } } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikilink_body(tokens, index, mdOpts, env) { // load const token = tokens[index]; if (token === null) { return 'token error'; } const filename = token.attrGet('filename'); const labelText = token.attrGet('label'); const matchText = token.attrGet('matchText'); if (filename === null) { return 'filename error'; } const htmlHref = opts.resolveHtmlHref(env, filename); const htmlText = opts.resolveHtmlText(env, filename); // render // invalid if (!htmlHref && matchText) { token.content = matchText; // valid } else { // html text, order of precedence for (const content of [labelText, htmlText, filename]) { if (typeof content === 'string' && content.length > 0) { token.content = content; break; } } } return token.content; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikilink_close(tokens, index, mdOpts, env) { return '</a>'; } }; const wikiembeds = (md, opts) => { // rulers const wikiLinkRule = md.block.ruler.getRules('wikilink'); if (wikiLinkRule.length === 0) { md.inline.ruler.before('link', 'wikiembed', wikiembed); } else { md.inline.ruler.before('wikilink', 'wikiembed', wikiembed); } // render md.renderer.rules.metadata_wikiembed = metadata_wikiembed; md.renderer.rules.wikiembed_open = wikiembed_open; md.renderer.rules.wikiembed_close = wikiembed_close; // body md.renderer.rules.wikiembed_content_body_media = wikiembed_content_body_media; // markdown // title md.renderer.rules.wikiembed_title_open = wikiembed_title_open; md.renderer.rules.wikiembed_title_body = wikiembed_title_body; md.renderer.rules.wikiembed_title_close = wikiembed_title_close; // link md.renderer.rules.wikiembed_link_open = wikiembed_link_open; md.renderer.rules.wikiembed_link_body = wikiembed_link_body; md.renderer.rules.wikiembed_link_close = wikiembed_link_close; // content md.renderer.rules.wikiembed_content_open = wikiembed_content_open; md.renderer.rules.wikiembed_content_body_md = wikiembed_content_body_md; md.renderer.rules.wikiembed_content_close = wikiembed_content_close; // rulers // parsed as 'inline', but renders as a pseudo-'block' function wikiembed(state, silent) { const srcText = state.src.substring(state.pos); // process match info const match = wikirefs.RGX.WIKI.EMBED.exec(srcText); if (match == null || match.length < 1 || match.index !== 0) { return false; } const matchText = match[0]; const filenameText = match[1]; // "Don't run any pairs in validation mode": // 'silent' is used when this rule is being checked against // in another rule to see whether or not the other rule should // kick out for this (or some other) one. return 'true' to // signify that the kick out should happen if (silent) { return false; } let token; // open embed // token = state.push('wikiembed_open', 'wikiembed', 0); token.attrSet('filename', filenameText); // body if (wikirefs.isMedia(filenameText)) { token = state.push('wikiembed_content_body_media', 'wikiembed', 0); token.attrSet('filename', filenameText); // process as markdown (may contain invalid media extensions) } else { // title // token = state.push('wikiembed_title_open', 'wikiembed', 0); token = state.push('wikiembed_title_body', 'wikiembed', 0); token.attrSet('filename', filenameText); token = state.push('wikiembed_title_close', 'wikiembed', 0); // link // token = state.push('wikiembed_link_open', 'wikiembed', 0); token.attrSet('filename', filenameText); token = state.push('wikiembed_link_body', 'wikiembed', 0); token.attrSet('filename', filenameText); token = state.push('wikiembed_link_close', 'wikiembed', 0); // content // token = state.push('wikiembed_content_open', 'wikiembed', 0); token = state.push('wikiembed_content_body_md', 'wikiembed', 0); token.attrSet('filename', filenameText); token = state.push('wikiembed_content_close', 'wikiembed', 0); } // close embed // token = state.push('wikiembed_close', 'wikiembed', 0); token.attrSet('filename', filenameText); // metadata if (opts.addEmbed) { token = state.push('metadata_wikiembed', 'wikiembed', 0); token.attrSet('filename', filenameText); } // continue; increment position state.pos += matchText.length; return true; } // render // markdown embeds: // // <p> // <div class="embed-wrapper"> // <div class="embed-title"> // <a class="wiki embed doctype" href="/tests/fixtures/embed-doc" data-href="/tests/fixtures/embed-doc"> // embedded document // </a> // </div> // <div class="embed-link"> // <a class="embed-link-icon" href="/tests/fixtures/embed-doc" data-href="/tests/fixtures/embed-doc"> // <i class="link-icon"></i> // </a> // </div> // <div class="embed-content"> // <p>Here is some content.</p> // </div> // </div> // </p> // media embeds (audio, img, video): // audio: // // <p> // <span class="embed-media" src="audio.mp3" alt="audio.mp3"> // <audio class="embed-audio" controls type="audio/mp3" src="/tests/fixtures/audio.mp3"></audio> // </span> // </p> // image: // // <p> // <span class="embed-media" src="image.png" alt="image.png"> // <img class="embed-image" src="/tests/fixtures/image.png"> // </span> // </p> // video: // // <p> // <span class="embed-media" src="video.mp4" alt="video.mp4"> // <video class="embed-audio" controls type="video/mp4" src="/tests/fixtures/video.mp4"></video> // </span> // </p> /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function metadata_wikiembed(tokens, index, mdOpts, env) { const token = tokens[index]; if (token === null) { return 'token error'; } // don't let 'linktype' be 'null' -- untyped wikiembeds have empty strings for 'linktype' const filename = token.attrGet('filename'); if (filename !== null && opts.addEmbed) { opts.addEmbed(env, filename); } return ''; } // embed /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_open(tokens, index, mdOpts, env) { // load const token = tokens[index]; const filename = token.attrGet('filename'); if (filename === null) { return 'filename error'; } // render if (wikirefs.isMedia(filename)) { return '\n<p>\n'; } else { return `\n<p>\n<div class="${opts.cssNames.embedWrapper}">\n`; } } // title /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_title_open(tokens, index, mdOpts, env) { return `<div class="${opts.cssNames.embedTitle}">\n`; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_title_body(tokens, index, mdOpts, env) { // load const token = tokens[index]; if (token === null) { return 'token error'; } const filename = token.attrGet('filename'); if (filename === null) { return 'filename error'; } const htmlHref = opts.resolveHtmlHref(env, filename); const htmlText = opts.resolveHtmlText(env, filename) ? opts.resolveHtmlText(env, filename) : filename; const doctype = opts.resolveDocType ? opts.resolveDocType(env, filename) : ''; // render if (htmlHref === undefined) { return `<a class="${opts.cssNames.wiki} ${opts.cssNames.embed} ${opts.cssNames.invalid}">\n${htmlText}\n</a>\n`; } else { // build css string const cssClassArray = []; cssClassArray.push(opts.cssNames.wiki); cssClassArray.push(opts.cssNames.embed); // '<doctype>' if (doctype !== null && doctype !== undefined && doctype.length !== 0) { const docTypeSlug = doctype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(opts.cssNames.doctype + docTypeSlug); } const css = cssClassArray.join(' '); return `<a class="${css}" href="${opts.baseUrl + htmlHref}" data-href="${opts.baseUrl + htmlHref}">\n${htmlText}\n</a>\n`; } } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_title_close(tokens, index, mdOpts, env) { return '</div>\n'; } // link /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_link_open(tokens, index, mdOpts, env) { // load const token = tokens[index]; const invalidOpen = `<div class="${opts.cssNames.embedLink}">\n<a class="${opts.cssNames.embedLinkIcon} ${opts.cssNames.invalid}">\n`; if (token === null) { return invalidOpen; } const filename = token.attrGet('filename'); if (filename === null) { return invalidOpen; } // render const htmlHref = opts.resolveHtmlHref(env, filename); // invalid if (htmlHref === undefined) { return invalidOpen; // valid } else { return `<div class="${opts.cssNames.embedLink}">\n<a class="${opts.cssNames.embedLinkIcon}" href="${opts.baseUrl + htmlHref}" data-href="${opts.baseUrl + htmlHref}">\n`; } } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_link_body(tokens, index, mdOpts, env) { const token = tokens[index]; // error if (token === null) { return 'token error'; } return `<i class="${opts.cssNames.linkIcon}"></i>\n`; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_link_close(tokens, index, mdOpts, env) { return '</a>\n</div>\n'; } // content /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_content_open(tokens, index, mdOpts, env) { return `<div class="${opts.cssNames.embedContent}">\n`; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_content_body_md(tokens, index, mdOpts, env) { // load const token = tokens[index]; if (token === null) { return 'token error'; } const filename = token.attrGet('filename'); if (filename === null) { return opts.embeds.errorContent + '\'' + filename + '\''; } const htmlContent = opts.resolveEmbedContent(env, filename); // render token.content = htmlContent ? htmlContent : opts.embeds.errorContent + '\'' + filename + '\''; return token.content + '\n'; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_content_body_media(tokens, index, mdOpts, env) { // load const token = tokens[index]; if (token === null) { return 'token error'; } const filename = token.attrGet('filename'); if (filename === null) { return 'filename error'; } const filenameSlug = filename.trim().toLowerCase().replace(/ /g, '-'); //.replace(/[^\w-]+/g, ''); const htmlHref = opts.resolveHtmlHref(env, filename); const mediaExt = path.extname(filename).toLowerCase(); const mime = path.extname(filename).replace('.', '').toLowerCase(); // render if (wikirefs.CONST.EXTS.AUD.has(mediaExt)) { token.content = `<span class="${opts.cssNames.embedMedia}" src="${filenameSlug}" alt="${filenameSlug}">\n`; token.content += htmlHref ? `<audio class="${opts.cssNames.embedAudio}" controls type="audio/${mime}" src="${htmlHref}"></audio>\n` : `<audio class="${opts.cssNames.embedAudio}" controls type="audio/${mime}"></audio>\n`; } else if (wikirefs.CONST.EXTS.IMG.has(mediaExt)) { token.content = `<span class="${opts.cssNames.embedMedia}" src="${filenameSlug}" alt="${filenameSlug}">\n`; token.content += htmlHref ? `<img class="${opts.cssNames.embedImage}" src="${htmlHref}">\n` : `<img class="${opts.cssNames.embedImage}">\n`; } else if (wikirefs.CONST.EXTS.VID.has(mediaExt)) { token.content = `<span class="${opts.cssNames.embedMedia}" src="${filenameSlug}" alt="${filenameSlug}">\n`; token.content += htmlHref ? `<video class="${opts.cssNames.embedVideo}" controls type="video/${mime}" src="${htmlHref}"></video>\n` : `<video class="${opts.cssNames.embedVideo}" controls type="video/${mime}"></video>\n`; } else { // note: this is probably not technically possible (due to 'wikirefs.wikirefs.isMedia()' check) token.content = `<span class="${opts.cssNames.embedMedia} ${opts.cssNames.invalid}">\n`; token.content += 'media error\n'; } return token.content; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_content_close(tokens, index, mdOpts, env) { return '</div>\n'; } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function wikiembed_close(tokens, index, mdOpts, env) { // load const token = tokens[index]; const filename = token.attrGet('filename'); if (filename === null) { return 'filename error'; } // render if (wikirefs.isMedia(filename)) { return '</span>\n</p>\n'; } else { return '</div>\n</p>\n'; } } }; // import // export function wikirefs_plugin(md, opts) { // opts const defaults = { resolveHtmlText: (env, fname) => fname.replace(/-/g, ' '), resolveHtmlHref: (env, fname) => { const extname = wikirefs.isMedia(fname) ? path.extname(fname) : ''; fname = fname.replace(extname, ''); return '/' + fname.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, '') + extname; }, resolveEmbedContent: (env, fname) => fname + ' content', baseUrl: '', cssNames: { // wiki wiki: 'wiki', invalid: 'invalid', // kinds attr: 'attr', link: 'link', type: 'type', embed: 'embed', reftype: 'reftype__', doctype: 'doctype__', // attr attrbox: 'attrbox', attrboxTitle: 'attrbox-title', // embed embedWrapper: 'embed-wrapper', embedTitle: 'embed-title', embedLink: 'embed-link', embedContent: 'embed-content', embedLinkIcon: 'embed-link-icon', linkIcon: 'link-icon', embedMedia: 'embed-media', embedAudio: 'embed-audio', embedDoc: 'embed-doc', embedImage: 'embed-image', embedVideo: 'embed-video' }, attrs: { enable: true, render: true, title: 'Attributes' }, links: { enable: true }, embeds: { enable: true, title: 'Embed Content', errorContent: 'Error: Content not found for ' } }; const fullOpts = merge(defaults, opts); // by order of execution if (fullOpts.prepFile) { prep_file(md, fullOpts); } if (fullOpts.attrs && fullOpts.attrs.enable) { wikiattrs(md, fullOpts); } if (fullOpts.links && fullOpts.links.enable) { wikilinks(md, fullOpts); } if (fullOpts.embeds && fullOpts.embeds.enable) { wikiembeds(md, fullOpts); } } export { wikirefs_plugin as default }; //# sourceMappingURL=index.esm.js.map