mdast-util-wikirefs
Version:
Converts a `micromark` token stream into an `mdast` syntax tree.
1,122 lines (1,057 loc) • 37.4 kB
JavaScript
// 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