Files
datahub/packages/remark-wiki-link/src/lib/html.ts
Ola Rubaj af134cac8b Integrate flowershow packages (#923)
* [packages][m]: mv @flowershow/core package here

* [packages/core][xs]: rename to @portaljs/core

* [package.json][xs]: setup npm workspaces

* [packages/core][xs]:replace deprecated rollup executor

* [core/package.json][s]: fix mermaid versions

* [core/tsconfig][xs]: rm extends

* [core/jest.config][xs]: rm coverageDirectory

* [core/package.json][xs]: install core-js

* [packages.json][s]:use same version for all nrwl packages

* [core/.eslintrc][xs]: adjust ignorePatterns

* [core/project.json][xs]: rm publish targets

* [packages][m]: mv @flowershow/remark-wiki-link here

* [packages][m]: mv @flowershow/remark-wiki-link here

* [packages][m]: mv @flowershow/remark-embed here

* [remark-callouts/project.json][xs]: adjst test pattern

* [package.json][s]: install missing deps

* [remark-callouts][xs]: adjst fields in package.json

* [remark-callouts][s]: rm pubish targets and adjst build executor

* [remark-embed/jest.config][xs]: rm unknown option coverageDirectory

* [remark-embed][xs]: rm publish targets

* [remark-embed][s]: rename to @portaljs/remark-embed

* [remark-wiki-link/eslintrc][xs]:adjst ignorePatterns

* [package.json][xs]: install missing deps

* [remark-wiki-link/test][xs]:specify format

- also temporarily force any type on htmlExtension

* [remark-wiki-link/README][xs]: replace @flowershow with @portaljs

* [remark-wiki-link][xs]:rm old changelog

* [remark-wiki-link][xs]: adjst package.json

* [remark-wiki-link/project.json][xs]: rm publish targets

* [core][s]: rm old changelog

* [core/README][xs]:correct scope name

* [remark-callouts/README][xs]: add @portaljs to pckg name

* [remark-embed/README][xs]: add @portaljs to pckg name

* [package-lock.json][xs]: refresh after rebasing on main
2023-06-07 07:21:00 -03:00

147 lines
4.6 KiB
TypeScript

import { isSupportedFileFormat } from "./isSupportedFileFormat";
const defaultWikiLinkResolver = (target: string) => {
// for [[#heading]] links
if (!target) {
return [];
}
let permalink = target.replace(/\/index$/, "");
// TODO what to do with [[index]] link?
if (permalink.length === 0) {
permalink = "/";
}
return [permalink];
};
export interface HtmlOptions {
pathFormat?:
| "raw" // default; use for regular relative or absolute paths
| "obsidian-absolute" // use for Obsidian-style absolute paths (with no leading slash)
| "obsidian-short"; // use for Obsidian-style shortened paths (shortest path possible)
permalinks?: string[]; // list of permalinks to match possible permalinks of a wiki link against
wikiLinkResolver?: (name: string) => string[]; // function to resolve wiki links to an array of possible permalinks
newClassName?: string; // class name to add to links that don't have a matching permalink
wikiLinkClassName?: string; // class name to add to all wiki links
hrefTemplate?: (permalink: string) => string; // function to generate the href attribute of a link
}
// Micromark HtmlExtension
// https://github.com/micromark/micromark#htmlextension
function html(opts: HtmlOptions = {}) {
const pathFormat = opts.pathFormat || "raw";
const permalinks = opts.permalinks || [];
const wikiLinkResolver = opts.wikiLinkResolver || defaultWikiLinkResolver;
const newClassName = opts.newClassName || "new";
const wikiLinkClassName = opts.wikiLinkClassName || "internal";
const defaultHrefTemplate = (permalink: string) => permalink;
const hrefTemplate = opts.hrefTemplate || defaultHrefTemplate;
function top(stack) {
return stack[stack.length - 1];
}
function enterWikiLink() {
let stack = this.getData("wikiLinkStack");
if (!stack) this.setData("wikiLinkStack", (stack = []));
stack.push({});
}
function exitWikiLinkTarget(token) {
const target = this.sliceSerialize(token);
const current = top(this.getData("wikiLinkStack"));
current.target = target;
}
function exitWikiLinkAlias(token) {
const alias = this.sliceSerialize(token);
const current = top(this.getData("wikiLinkStack"));
current.alias = alias;
}
function exitWikiLink(token) {
const wikiLink = this.getData("wikiLinkStack").pop();
const { target, alias } = wikiLink;
const isEmbed = token.isType === "embed";
// eslint-disable-next-line no-useless-escape
const wikiLinkWithHeadingPattern = /([\w\s\/\.-]*)(#.*)?/;
const [, path, heading = ""] = target.match(wikiLinkWithHeadingPattern);
const possibleWikiLinkPermalinks = wikiLinkResolver(path);
const matchingPermalink = permalinks.find((e) => {
return possibleWikiLinkPermalinks.find((p) => {
if (pathFormat === "obsidian-short") {
if (e === p || e.endsWith(p)) {
return true;
}
} else if (pathFormat === "obsidian-absolute") {
if (e === "/" + p) {
return true;
}
} else {
if (e === p) {
return true;
}
}
return false;
});
});
// TODO this is ugly
const link =
matchingPermalink ||
(pathFormat === "obsidian-absolute"
? "/" + possibleWikiLinkPermalinks[0]
: possibleWikiLinkPermalinks[0]) ||
"";
// remove leading # if the target is a heading on the same page
const displayName = alias || target.replace(/^#/, "");
// replace spaces with dashes and lowercase headings
const headingId = heading.replace(/\s+/, "-").toLowerCase();
let classNames = wikiLinkClassName;
if (!matchingPermalink) {
classNames += " " + newClassName;
}
if (isEmbed) {
const [isSupportedFormat, format] = isSupportedFileFormat(target);
if (!isSupportedFormat) {
this.raw(`![[${target}]]`);
} else if (format === "pdf") {
this.tag(
`<iframe width="100%" src="${hrefTemplate(
link
)}#toolbar=0" class="${classNames}" />`
);
} else {
this.tag(
`<img src="${hrefTemplate(
link
)}" alt="${displayName}" class="${classNames}" />`
);
}
} else {
this.tag(
`<a href="${hrefTemplate(link + headingId)}" class="${classNames}">`
);
this.raw(displayName);
this.tag("</a>");
}
}
return {
enter: {
wikiLink: enterWikiLink,
},
exit: {
wikiLinkTarget: exitWikiLinkTarget,
wikiLinkAlias: exitWikiLinkAlias,
wikiLink: exitWikiLink,
},
};
}
export { html };