UNPKG

mdast-util-wikirefs

Version:

Converts a `micromark` token stream into an `mdast` syntax tree.

1,122 lines (1,057 loc) 37.4 kB
// mdast-util-wikirefs v0.0.5-md - https://github.com/wikibonsai/remark-wikirefs.git import { merge } from 'lodash-es'; import * as wikirefs from 'wikirefs'; import { selectAll } from 'unist-util-select'; import { defaultsWikiRefs, defaultsWikiAttrs, defaultsWikiLinks, defaultsWikiEmbeds } from 'micromark-extension-wikirefs'; import path from 'path'; import { safe } from 'mdast-util-to-markdown/lib/util/safe.js'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray$1(arr, i) || _nonIterableRest(); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function initWikiAttrBox(tree, opts) { // options var fullOpts = merge(defaultsWikiRefs(), defaultsWikiAttrs(), opts); // todo: should i be making node assertions...? // https://github.com/syntax-tree/unist-util-is#isnode-test-index-parent-context // test for primitive caml attrs var hasAttrbox = selectAll('attrbox', tree).length !== 0; if (!hasAttrbox) { // extract attr data nodes var attrDataNodes = selectAll('attrbox-data', tree); // extract attr data var attrData = attrDataNodes.reduce(function (acc, node) { Object.entries(node.data.items).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), key = _ref2[0], value = _ref2[1]; if (acc[key]) { acc[key] = acc[key].concat(value); } else { acc[key] = value; } }); return acc; }, {}); // build attrbox and return return Object.keys(attrData).length > 0 ? buildWikiAttrBox(attrData, fullOpts) : undefined; } } // hProperties are meant to build an element like this: // // <aside class="attrbox"> // <span class="attrbox-title">Attributes</span> // <dl> // <dt>attrtype</dt> // <dd><a class="attr wiki reftype__attrtype doctype__doctype" href="/tests/fixtures/fname-a" data-href="/tests/fixtures/fname-a">title a</a></dd> // <dd><a class="attr wiki reftype__attrtype doctype__doctype" href="/tests/fixtures/fname-b" data-href="/tests/fixtures/fname-b">title b</a></dd> // <dd><a class="attr wiki reftype__attrtype doctype__doctype" href="/tests/fixtures/fname-c" data-href="/tests/fixtures/fname-c">title c</a></dd> // ... // </dl> // </aside> // rehype properties: // https://github.com/rehypejs/rehype // https://github.com/syntax-tree/mdast-util-to-hast function buildWikiAttrBox(attrData, fullOpts) { // init var attrbox = { type: 'attrbox', children: [], data: { items: {}, hName: 'aside', hProperties: { className: [fullOpts.cssNames.attrbox] } } }; var attrboxTitle = { type: 'attrbox-title', children: [{ type: 'text', value: fullOpts.attrs.title }], data: { hName: 'span', hProperties: { className: [fullOpts.cssNames.attrboxTitle] } } }; var attrBoxListNode = { type: 'attrbox-list', children: [], data: { hName: 'dl' } }; // construct attrbox.children.push(attrboxTitle); attrbox.children.push(attrBoxListNode); // if we have attr items, process them if (Object.keys(attrData).length > 0) { // copy item data attrbox.data.items = _objectSpread({}, attrData); // build item hProperties from item data for (var _i = 0, _Object$entries = Object.entries(attrData); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), attrtype = _Object$entries$_i[0], items = _Object$entries$_i[1]; addWikiAttrKey(attrbox, attrtype); var _iterator = _createForOfIteratorHelper(items), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var item = _step.value; addWikiAttrVal(attrbox, attrtype, item, fullOpts); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } } return attrbox; } function addWikiAttrKey(attrbox, attrtype, fullOpts) { var attrType = attrtype ? attrtype : undefined; var keyNode = { type: 'attr-key', children: [{ type: 'text', value: attrType ? attrType : 'attrtype error' }], data: { hName: 'dt' } }; // add to attrbox-list attrbox.children[1].children.push(keyNode); } function addWikiAttrVal(attrbox, attrtype, wikiVal, fullOpts) { var wikiNode; var valNode = { type: 'attr-val', children: [], data: { hName: 'dd' } }; // invalid if (!wikiVal.htmlHref) { wikiNode = { type: 'wikiattr', children: [{ type: 'text', value: wikirefs.CONST.MARKER.OPEN + wikiVal.filename + wikirefs.CONST.MARKER.CLOSE }], data: { hName: 'a', hProperties: { className: [fullOpts.cssNames.attr, fullOpts.cssNames.wiki, fullOpts.cssNames.invalid] } } }; // valid } else { wikiNode = { type: 'wikiattr', children: [{ type: 'text', value: wikiVal.htmlText ? wikiVal.htmlText : wikiVal.filename }], data: { hName: 'a', hProperties: { className: wikiVal.doctype.length > 0 // with doctype ? [fullOpts.cssNames.attr, fullOpts.cssNames.wiki, attrtype ? fullOpts.cssNames.reftype + attrtype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, '') : fullOpts.cssNames.reftype + 'attrtype-error', fullOpts.cssNames.doctype + wikiVal.doctype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, '')] // without doctype : [fullOpts.cssNames.attr, fullOpts.cssNames.wiki, attrtype ? fullOpts.cssNames.reftype + attrtype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, '') : fullOpts.cssNames.reftype + 'attrtype-error'], href: wikiVal.baseUrl + wikiVal.htmlHref, dataHref: wikiVal.baseUrl + wikiVal.htmlHref } } }; } // add wikiattr to attr-val valNode.children.push(wikiNode); // add to attrbox-list attrbox.children[1].children.push(valNode); } function fromMarkdownWikiAttrs(opts) { var fullOpts = merge(defaultsWikiRefs(), defaultsWikiAttrs(), opts); // note: enter/exit keys should match a token name return { enter: { wikiAttrBox: enterWikiAttrBox }, exit: { wikiAttrKey: exitWikiAttrKey, wikiAttrVal: exitWikiAttrVal, wikiAttrBox: exitWikiAttrBox } }; function enterWikiAttrBox(token) { var attrBoxDataNode = { type: 'attrbox-data', data: { items: {} } }; // is accessible via 'this.stack' (see below) this.enter(attrBoxDataNode, token); // current key var curKey = this.getData('curKey'); if (curKey === undefined) { this.setData('curKey', ''); } } function exitWikiAttrKey(token) { var attrtype = this.sliceSerialize(token).trim(); var current = top(this.stack); if (current.data && current.data.items && !Object.keys(current.data.items).includes(attrtype)) { current.data.items[attrtype] = []; } this.setData('curKey', attrtype); } function exitWikiAttrVal(token) { var filename = this.sliceSerialize(token); var current = top(this.stack); // build vars var baseUrl = fullOpts.baseUrl; var htmlHref; var htmlText; if (!fullOpts.resolveHtmlHref || !fullOpts.resolveHtmlText) { htmlHref = undefined; htmlText = undefined; } else { htmlHref = fullOpts.resolveHtmlHref(filename); htmlText = fullOpts.resolveHtmlText(filename); } var doctype = ''; if (fullOpts.resolveDocType) { var resolvedDocType = fullOpts.resolveDocType(filename); doctype = resolvedDocType ? resolvedDocType : ''; } // construct data var item = { type: 'wiki', doctype: doctype, filename: filename, htmlHref: htmlHref ? htmlHref : '', htmlText: htmlText ? htmlText : '', baseUrl: baseUrl }; if (current.data && current.data.items) { var curKey = this.getData('curKey'); if (curKey !== undefined) { current.data.items[curKey].push(item); } } } // note: leaving this here to close the token function exitWikiAttrBox(token) { this.exit(token); return; } // util function top(stack) { return Array.from(stack)[Array.from(stack).length - 1]; } } function fromMarkdownWikiLinks(opts) { var fullOpts = merge(defaultsWikiRefs(), defaultsWikiLinks(), opts); // note: enter/exit keys should match a token name return { enter: { wikiLink: enterWikiLink }, exit: { wikiLinkTypeTxt: exitLinkTypeTxt, wikiLinkFileNameTxt: exitFileNameTxt, wikiLinkLabelTxt: exitLabelTxt, wikiLink: exitWikiLink } }; function enterWikiLink(token) { var startWikiLinkNode = { type: 'wikilink', children: [], data: { item: { doctype: '', filename: '', label: '', linktype: '', htmlHref: '', htmlText: '' }, hName: 'a', hProperties: { className: [] } } }; // is accessible via 'this.stack' (see below) this.enter(startWikiLinkNode, token); } function exitLinkTypeTxt(token) { var linktype = this.sliceSerialize(token); var current = top(this.stack); current.data.item.linktype = linktype; } function exitFileNameTxt(token) { var filename = this.sliceSerialize(token); var current = top(this.stack); current.data.item.filename = filename; } function exitLabelTxt(token) { var label = this.sliceSerialize(token); var current = top(this.stack); current.data.item.label = label; } // hProperties are meant to build an element like this: // // typed // // <a class="wiki link type reftype__linktype doctype__doctype" href="/tests/fixtures/fname-a" data-href="/tests/fixtures/fname-a">title a</a> // // untyped // // <a class="wiki link doctype__doctype" href="/tests/fixtures/fname-a" data-href="/tests/fixtures/fname-a">title a</a> function exitWikiLink(token) { var wikiLink = this.exit(token); // html-text var labelText = wikiLink.data.item.label; var filename = wikiLink.data.item.filename; // resolvers var htmlHref = fullOpts.resolveHtmlHref(wikiLink.data.item.filename) ? fullOpts.resolveHtmlHref(wikiLink.data.item.filename) : ''; var htmlText = fullOpts.resolveHtmlText(wikiLink.data.item.filename) ? fullOpts.resolveHtmlText(wikiLink.data.item.filename) : wikiLink.data.item.filename; // invalid if (htmlHref.length === 0) { htmlText = ''; if (wikiLink.data.item.linktype) { htmlText += wikirefs.CONST.MARKER.PREFIX + wikiLink.data.item.linktype + wikirefs.CONST.MARKER.TYPE; } htmlText += wikirefs.CONST.MARKER.OPEN + wikiLink.data.item.filename; if (wikiLink.data.item.label) { htmlText += wikirefs.CONST.MARKER.LABEL + wikiLink.data.item.label; } htmlText += wikirefs.CONST.MARKER.CLOSE; // valid } else { // html text, order of precedence for (var _i = 0, _arr = [labelText, htmlText, filename]; _i < _arr.length; _i++) { var content = _arr[_i]; if (typeof content === 'string' && content.length > 0) { htmlText = content; break; } } } var doctype = fullOpts.resolveDocType ? fullOpts.resolveDocType(filename) : ''; // finish populating data wikiLink.data.item.htmlHref = htmlHref; wikiLink.data.item.htmlText = htmlText; wikiLink.data.item.doctype = doctype; //// // render // css var cssClassArray = []; cssClassArray.push(fullOpts.cssNames.wiki); cssClassArray.push(fullOpts.cssNames.link); // invalid if (htmlHref.length === 0) { cssClassArray.push(fullOpts.cssNames.invalid); // valid } else { // linktype /* eslint-disable indent */ var linktype = wikiLink.data.item.linktype ? wikiLink.data.item.linktype : undefined; /* eslint-enable indent */ if (linktype !== undefined && linktype.length !== 0) { var type = fullOpts.cssNames.type; var linkTypeSlug = linktype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(type); cssClassArray.push(fullOpts.cssNames.reftype + linkTypeSlug); } // doctype if (doctype.length > 0) { var docTypeSlug = doctype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(fullOpts.cssNames.doctype + docTypeSlug); } } // populate final node properties // rehype properties: // https://github.com/rehypejs/rehype // https://github.com/syntax-tree/mdast-util-to-hast wikiLink.data.hProperties.className = cssClassArray; if (htmlHref !== undefined && htmlHref.length > 0) { wikiLink.data.hProperties.href = fullOpts.baseUrl + htmlHref; wikiLink.data.hProperties.dataHref = fullOpts.baseUrl + htmlHref; } wikiLink.children = [{ type: 'text', value: htmlText }]; } // util function top(stack) { return stack[stack.length - 1]; } } function fromMarkdownWikiEmbeds(opts) { var fullOpts = merge(defaultsWikiRefs(), defaultsWikiEmbeds(), opts); // note: enter/exit keys should match a token name return { enter: { wikiEmbed: enterWikiEmbed }, exit: { wikiEmbedFileNameTxt: exitFileNameTxt, wikiEmbed: exitWikiEmbed } }; function enterWikiEmbed(token) { var startWikiEmbedNode = { type: 'wikiembed', children: [], data: { item: { doctype: '', filename: '' }, hName: 'p' } }; // is accessible via 'this.stack' (see below) this.enter(startWikiEmbedNode, token); } function exitFileNameTxt(token) { var filename = this.sliceSerialize(token); var current = top(this.stack); current.data.item.filename = filename; } // hProperties are meant to build an element like this: // // markdown embeds: // // <p> // <div class="embed-wrapper"> // <div class="embed-title"> // <a class="wikilink 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 embed-audio" src="audio.mp3" alt="audio.mp3"> // <audio controls src="/tests/fixtures/audio.mp3"></audio> // </span> // </p> // image: // // <p> // <span class="embed-media embed-image" src="image.png" alt="image.png"> // <img src="/tests/fixtures/image.png"> // </span> // </p> // video: // // <p> // <span class="embed-media embed-audio" src="video.mp4" alt="video.mp4"> // <video controls src="/tests/fixtures/video.mp4"></video> // </span> // </p> // rehype properties: // https://github.com/rehypejs/rehype // https://github.com/syntax-tree/mdast-util-to-hast function exitWikiEmbed(token) { var wikiEmbed = this.exit(token); // init vars var filename = wikiEmbed.data.item.filename; var filenameSlug = filename.trim().toLowerCase().replace(/ /g, '-'); //.replace(/[^\w-]+/g, ''); var mediaExt = path.extname(filename).toLowerCase(); var mime = path.extname(filename).replace('.', '').toLowerCase(); // resolvers var htmlHref = fullOpts.resolveHtmlHref(filename); var htmlText = fullOpts.resolveHtmlText(filename) ? fullOpts.resolveHtmlText(filename) : filename; var doctype = fullOpts.resolveDocType ? fullOpts.resolveDocType(filename) : ''; // finish populating data wikiEmbed.data.item.htmlHref = htmlHref; wikiEmbed.data.item.doctype = doctype; //// // render //// // media if (wikirefs.isMedia(filename)) { wikiEmbed.children.push({ type: 'embed-media-span', children: [], data: { hName: 'span', hProperties: { className: [fullOpts.cssNames.embedMedia], src: filenameSlug, alt: filenameSlug } } }); // audio if (wikirefs.CONST.EXTS.AUD.has(mediaExt)) { wikiEmbed.data.item.media = wikirefs.CONST.MEDIA.AUD; wikiEmbed.children[0].children.push({ type: 'embed-media-audio', data: { hName: 'audio', hProperties: { className: [fullOpts.cssNames.embedAudio], controls: true, type: "audio/".concat(mime) // src: if 'htmlHref' exists, add below... } } }); // image } else if (wikirefs.CONST.EXTS.IMG.has(mediaExt)) { wikiEmbed.data.item.media = wikirefs.CONST.MEDIA.IMG; wikiEmbed.children[0].children.push({ type: 'embed-media-image', data: { hName: 'img', hProperties: { className: [fullOpts.cssNames.embedImage] // src: if 'htmlHref' exists, add below... } } }); // video } else if (wikirefs.CONST.EXTS.VID.has(mediaExt)) { wikiEmbed.data.item.media = wikirefs.CONST.MEDIA.VID; wikiEmbed.children[0].children.push({ type: 'embed-media-video', data: { hName: 'video', hProperties: { className: [fullOpts.cssNames.embedVideo], controls: true, type: "video/".concat(mime) // src: if 'htmlHref' exists, add below... } } }); // invalid () // note: this is probably not technically possible (due to 'wikirefs.isMedia()' check) } else { wikiEmbed.children[0].data.hProperties.className.push(fullOpts.cssNames.invalid); wikiEmbed.children[0].children.push({ type: 'text', value: 'media error' }); } if (htmlHref && wikiEmbed.children[0].children[0].type !== 'text') { wikiEmbed.children[0].children[0].data.hProperties.src = fullOpts.baseUrl + htmlHref; } //// // markdown } else { wikiEmbed.data.item.media = wikirefs.CONST.MEDIA.MD; // embed mkdn wrapper wikiEmbed.children.push({ type: 'embed-mkdn-wrapper', children: [], data: { hName: 'div', hProperties: { className: [fullOpts.cssNames.embedWrapper] } } }); // title wikiEmbed.children[0].children.push({ type: 'embed-mkdn-title', children: [], data: { hName: 'div', hProperties: { className: [fullOpts.cssNames.embedTitle] } } }); wikiEmbed.children[0].children[0].children.push({ type: 'a', children: [{ type: 'text', value: htmlText }], data: { hName: 'a', hProperties: { className: [ // add below based on 'htmlhref'... ] // href: if 'htmlHref' exists, add below... // dataHref: if 'htmlHref' exists, add below... } } }); // build css string var cssClassArray = []; cssClassArray.push(fullOpts.cssNames.wiki); cssClassArray.push(fullOpts.cssNames.embed); if (!htmlHref) { cssClassArray.push(fullOpts.cssNames.invalid); } else { // '<doctype>' if (doctype !== null && doctype !== undefined && doctype.length !== 0) { var docTypeSlug = doctype.trim().toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); cssClassArray.push(fullOpts.cssNames.doctype + docTypeSlug); } // handle href if it exists wikiEmbed.children[0].children[0].children[0].data.hProperties.href = fullOpts.baseUrl + htmlHref; wikiEmbed.children[0].children[0].children[0].data.hProperties.dataHref = fullOpts.baseUrl + htmlHref; } wikiEmbed.children[0].children[0].children[0].data.hProperties.className = cssClassArray; // link wikiEmbed.children[0].children.push({ type: 'embed-mkdn-link', children: [], data: { hName: 'div', hProperties: { className: [fullOpts.cssNames.embedLink] } } }); wikiEmbed.children[0].children[1].children.push({ type: 'a', children: [{ type: 'i', data: { hName: 'i', hProperties: { className: [fullOpts.cssNames.linkIcon] } } }], data: { hName: 'a', hProperties: { className: [fullOpts.cssNames.embedLinkIcon] } } }); if (!htmlHref) { wikiEmbed.children[0].children[1].children[0].data.hProperties.className.push(fullOpts.cssNames.invalid); } else { wikiEmbed.children[0].children[1].children[0].data.hProperties.href = fullOpts.baseUrl + htmlHref; wikiEmbed.children[0].children[1].children[0].data.hProperties.dataHref = fullOpts.baseUrl + htmlHref; } // content wikiEmbed.children[0].children.push({ type: 'embed-mkdn-content', children: [], data: { hName: 'div', hProperties: { className: [fullOpts.cssNames.embedContent] } } }); // embed content if (fullOpts.resolveEmbedContent) { var htmlContent = fullOpts.resolveEmbedContent(filename); // todo: 'fullOpts.embeds.format' option // if (fullOpts.embeds.format === 'string') { // // for raw string // wikiEmbed.children[0].children[2].children = [{ // type: 'text', // value: (htmlContent !== undefined) // ? htmlContent // : fullOpts.embeds.errorContent + '\'' + filename + '\'', // }]; // } // if (fullOpts.embeds.format === 'mdast-node') { // // for mdast node wikiEmbed.children[0].children[2].children = htmlContent !== undefined ? [htmlContent] : [{ type: 'text', value: fullOpts.embeds.errorContent + '\'' + filename + '\'' }]; // } } } } // util function top(stack) { return stack[stack.length - 1]; } } function fromMarkdownWikiRefs(opts) { var fullOpts = merge(defaultsWikiRefs(), opts); var wikiRefsPlugins = []; if (fullOpts.attrs && fullOpts.attrs.enable) { wikiRefsPlugins.push(fromMarkdownWikiAttrs(fullOpts)); } if (fullOpts.links && fullOpts.links.enable) { wikiRefsPlugins.push(fromMarkdownWikiLinks(fullOpts)); } if (fullOpts.embeds && fullOpts.embeds.enable) { wikiRefsPlugins.push(fromMarkdownWikiEmbeds(fullOpts)); } return wikiRefsPlugins; } function toMarkdownWikiAttrs() { var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var fullOpts = merge(defaultsWikiRefs(), defaultsWikiAttrs(), opts); // 'defaults' ensure 'fullOpts.attrs' will be populated above var format = fullOpts.attrs.toMarkdown.format; var listKind = fullOpts.attrs.toMarkdown.listKind; var prefixed = fullOpts.attrs.toMarkdown.prefixed; // let attrboxFound: boolean = false; return { // TODO: I don't fully understand what this does, but I did my // best to fill it in based on what I saw in other mdast utils // (e.g. https://github.com/syntax-tree/mdast-util-math/blob/main/index.js#L135) unsafe: [{ character: '[', inConstruct: ['phrasing', 'label', 'reference'] }, { character: ']', inConstruct: ['label', 'reference'] }], handlers: { // as of (2021-05-07), the typings for Handle do not reflect // that the handler will be passed nodes of a specific type // note: name should match 'Node.type' // attrbox: handleNode as Handle, // note: 'case-conversion' <-> caseConversion seems to not be working... 'attrbox-data': handleData, attrboxData: handleData } }; // note: this handler will generate markdown from the in-place data function handleData(node, _, context) { var exit = context.enter('attrbox-data'); var value = buildMkdn(node.data.items, context); // const value: string = (!attrboxFound) ? buildMkdn(node.data.items, context) : ''; exit(); return value; } // note: this handler will generate markdown from the content's top-level attrbox // function handleNode( // node: (AttrBoxNode), // _: Uni.Parent | null | undefined, // context: Context, // ): string { // attrboxFound = true; // const exit = context.enter('attrbox' as ConstructName); // const value: string = buildMkdn(node.data.items, context); // exit(); // return value; // } function buildMkdn(wikiattrs, context) { // init vars / build string value var value = ''; for (var _i = 0, _Object$entries = Object.entries(wikiattrs); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), attrtype = _Object$entries$_i[0], wikiattr = _Object$entries$_i[1]; var wikiAttrPayLoad = wikiattr; // attrtype / key /* eslint-disable indent */ var nodeAttrType = safe(context, // todo: 'context' -> 'state' (see: https://github.com/syntax-tree/mdast-util-to-markdown/commit/e812c7954f8b8ea5dd68476c856cbfd7cc4c442b) attrtype, { before: ':', after: ':' }); /* eslint-enable indent */ if (nodeAttrType) { if (prefixed) { value += wikirefs.CONST.MARKER.PREFIX; if (format === 'pad') { value += ' '; } } value += nodeAttrType; if (format === 'pad') { value += ' '; } value += wikirefs.CONST.MARKER.TYPE; if (format === 'pad') { value += ' '; } } // filenames / items / values for (var i = 0; i < wikiAttrPayLoad.length; i++) { var isLastItem = i === wikiAttrPayLoad.length - 1; /* eslint-disable indent */ var nodeFileName = safe(context, wikiAttrPayLoad[i].filename, { before: '[', after: ']' }); /* eslint-enable indent */ // single item or list comma-separated if (wikiAttrPayLoad.length === 1 || listKind === 'comma') { value += wikirefs.CONST.MARKER.OPEN + nodeFileName + wikirefs.CONST.MARKER.CLOSE; if (!isLastItem) { value += ','; if (format === 'pad') { value += ' '; } } } // multiple items, list mkdn-separated if (wikiAttrPayLoad.length > 1 && listKind === 'mkdn') { value += '\n' + '- ' + wikirefs.CONST.MARKER.OPEN + nodeFileName + wikirefs.CONST.MARKER.CLOSE; } // add last newline after last item if (isLastItem) { value += '\n'; } } } return value; } } // eslint-disable-next-line @typescript-eslint/no-unused-vars function toMarkdownWikiLinks(opts) { return { // TODO: I don't fully understand what this does, but I did my // best to fill it in based on what I saw in other mdast utils // (e.g. https://github.com/syntax-tree/mdast-util-math/blob/main/index.js#L135) unsafe: [{ character: '[', inConstruct: ['phrasing', 'label', 'reference'] }, { character: ']', inConstruct: ['label', 'reference'] }], handlers: { // as of (2021-05-07), the typings for Handle do not reflect // that the handler will be passed nodes of a specific type // note: name should match 'Node.type' wikilink: handler } }; function handler(node, _, context) { var exit = context.enter('wikilink'); // init vars /* eslint-disable indent */ var nodeFileName = safe(context, node.data.item.filename, { before: '[', after: ']' }); var nodeLinkType = safe(context, node.data.item.linktype, { before: ':', after: ':' }); var nodeLabel = node.data.item.label && node.data.item.label !== '' ? safe(context, node.data.item.label, { before: '|', after: ']' }) : undefined; /* eslint-enable indent */ // build string value var value = ''; if (nodeLinkType) { value += wikirefs.CONST.MARKER.PREFIX + nodeLinkType + wikirefs.CONST.MARKER.TYPE; } value += wikirefs.CONST.MARKER.OPEN + nodeFileName; if (nodeLabel) { value += wikirefs.CONST.MARKER.LABEL + nodeLabel; } value += wikirefs.CONST.MARKER.CLOSE; exit(); return value; } } // eslint-disable-next-line @typescript-eslint/no-unused-vars function toMarkdownWikiEmbeds(opts) { return { // TODO: I don't fully understand what this does, but I did my // best to fill it in based on what I saw in other mdast utils // (e.g. https://github.com/syntax-tree/mdast-util-math/blob/main/index.js#L135) unsafe: [{ character: '[', inConstruct: ['phrasing', 'label', 'reference'] }, { character: ']', inConstruct: ['label', 'reference'] }], handlers: { // as of (2021-05-07), the typings for Handle do not reflect // that the handler will be passed nodes of a specific type // note: name should match 'Node.type' wikiembed: handler } }; function handler(node, _, context) { var exit = context.enter('embed-mkdn-wrapper'); // init vars /* eslint-disable indent */ var nodeFileName = safe(context, node.data.item.filename, { before: '[', after: ']' }); /* eslint-enable indent */ exit(); return wikirefs.CONST.MARKER.EMBED + wikirefs.CONST.MARKER.OPEN + nodeFileName + wikirefs.CONST.MARKER.CLOSE; } } // from: https://github.com/syntax-tree/mdast-util-gfm-strikethrough/blob/main/index.js#L5 function toMarkdownWikiRefs(opts) { var fullOpts = merge(defaultsWikiRefs(), opts); var wikiRefsPlugins = []; if (fullOpts.attrs && fullOpts.attrs.enable) { wikiRefsPlugins.push(toMarkdownWikiAttrs(fullOpts)); } if (fullOpts.links && fullOpts.links.enable) { wikiRefsPlugins.push(toMarkdownWikiLinks()); } if (fullOpts.embeds && fullOpts.embeds.enable) { wikiRefsPlugins.push(toMarkdownWikiEmbeds()); } return { extensions: wikiRefsPlugins }; } // patch visit-related dependencies in order to add 'visitNodeType'. // // from: https://github.com/benrbray/remark-cite/blob/master/mdast-util-cite/test/test.ts#L17-L87 // // https://github.com/syntax-tree/unist-util-visit // https://github.com/syntax-tree/unist-util-visit-parents var VisitorAction; (function (VisitorAction) { VisitorAction[VisitorAction["CONTINUE"] = 1] = "CONTINUE"; VisitorAction[VisitorAction["SKIP"] = 2] = "SKIP"; VisitorAction[VisitorAction["EXIT"] = 3] = "EXIT"; })(VisitorAction || (VisitorAction = {})); function unistIsParent(node) { return Boolean(Object.keys(node).includes('children')); } /** * Visit every node in the tree using a depth-first preorder traversal. */ function visit(tree, visitor) { recurse(tree); function recurse(node) { // visit the node itself and handle the result var action = visitor(node) || VisitorAction.CONTINUE; if (action === VisitorAction.EXIT) { return VisitorAction.EXIT; } if (action === VisitorAction.SKIP) { return VisitorAction.SKIP; } if (!unistIsParent(node)) { return action; } // visit the node's children from first to last for (var childIdx = 0; childIdx < node.children.length; childIdx++) { // visit child and handle the subtree result var subresult = recurse(node.children[childIdx]); if (subresult === VisitorAction.EXIT) { return VisitorAction.EXIT; } // TODO: if visitor modified the tree, we might want to allow it // to return a new childIdx to continue iterating from } return action; } } /** * Visit a specific type of node. */ function visitNodeType(tree, type, visitor) { // filter nodes by type function predicate(node) { return node.type === type; } // apply the provided visitor only if type predicate matches visit(tree, function (node) { if (predicate(node)) { return visitor(node); } else { return VisitorAction.CONTINUE; } }); } export { fromMarkdownWikiAttrs, fromMarkdownWikiEmbeds, fromMarkdownWikiLinks, fromMarkdownWikiRefs, initWikiAttrBox, toMarkdownWikiAttrs, toMarkdownWikiEmbeds, toMarkdownWikiLinks, toMarkdownWikiRefs, visitNodeType }; //# sourceMappingURL=index.js.map