unist#Node TypeScript Examples
The following examples show how to use
unist#Node.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts From dendron with GNU Affero General Public License v3.0 | 7 votes |
/**
* Recursively check if two given node has identical children.
* At each level _position_ is omitted as this can change if
* you are comparing from two different trees.
* @param a first {@link Node} to compare
* @param b second {@link Node} to compare
* @returns boolean
*/
static hasIdenticalChildren = (a: Node, b: Node): boolean => {
if (_.isEqual(Object.keys(a).sort(), Object.keys(b).sort())) {
const aOmit = _.omit(a, ["position", "children"]);
const bOmit = _.omit(b, ["position", "children"]);
if (_.isEqual(aOmit, bOmit)) {
if (_.has(a, "children")) {
return _.every(
// @ts-ignore
a.children as Node[],
(aChild: Node, aIndex: number) => {
// @ts-ignore
const bChild = (b.children as Node[])[aIndex];
return RemarkUtils.hasIdenticalChildren(aChild, bChild);
}
);
}
return true;
} else {
return false;
}
} else {
return false;
}
};
Example #2
Source File: serverSide.ts From roamjs-com with MIT License | 6 votes |
debug = (tree: Node) => {
if (process.env.NODE_ENV === "development") {
let charcode = 97;
while (charcode < 123) {
const fn = `out/${String.fromCharCode(charcode)}.json`;
if (!fs.existsSync(fn)) {
fs.writeFileSync(fn, JSON.stringify(tree, null, 2));
} else {
charcode++;
}
}
}
}
Example #3
Source File: JoplinNoteHandler.ts From joplin-utils with MIT License | 6 votes |
static convertLink(
node: Node,
note: CommonNote & { tags: CommonTag[]; resources: CommonResource[] },
converter: JoplinNoteHandlerLinkConverter,
) {
function getLink() {
const res: string[] = []
visit(node, ['link', 'image'], (node: Link) => {
res.push(node.url)
})
return res.filter((link) => link.startsWith(':/')).map((link) => link.slice(2))
}
const linkIdList = getLink()
const resourceMap = note.resources.reduce((res, resource) => {
res.set(resource.id, resource)
return res
}, new Map<string, CommonResource>())
const idLinkMap = linkIdList.reduce((res, id) => {
const link = resourceMap.has(id) ? converter.convertResource(resourceMap.get(id)!) : converter.convertNote(id)
res.set(id, link)
return res
}, new Map<string, string>())
return unistUtilMap(node, (node) => {
if (node.type !== 'link' && node.type !== 'image') {
return node
}
const link = node as Link
if (!link.url.startsWith(':/')) {
return link
}
return {
...node,
url: idLinkMap.get(link.url.slice(2)),
} as Link
})
}
Example #4
Source File: stringify.ts From uniorg with GNU General Public License v3.0 | 6 votes |
function stringifyOne(node: Node | string): string {
if (typeof node === 'string') {
return node;
}
const org = node as OrgNode & Partial<WithAffiliatedKeywords>;
const result: string[] = [];
if (org.affiliated) {
result.push(stringifyAffiliated(org.affiliated as AffiliatedKeywords));
}
result.push(stringifyNode(org));
return result.join('');
}
Example #5
Source File: transformLinks.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
/**
* Used from renaming wikilinks
*/
function plugin(this: Unified.Processor, opts: PluginOpts): Transformer {
// @ts-ignore
const proc = this;
function transformer(tree: Node, _file: VFile) {
visit(tree, (node, _idx, _parent) => {
if (node.type === DendronASTTypes.WIKI_LINK) {
let cnode = node as WikiLinkNoteV4;
if (cnode.value.toLowerCase() === opts.from.fname.toLowerCase()) {
cnode.value = opts.to.fname;
// if alias the same, change that to
if (
cnode.data.alias.toLowerCase() === opts.from.fname.toLowerCase()
) {
cnode.data.alias = opts.to.fname;
}
}
}
if (node.type === DendronASTTypes.REF_LINK_V2) {
let cnode = node as NoteRefNoteV4;
if (
cnode.data.link.from.fname.toLowerCase() ===
opts.from.fname.toLowerCase()
) {
cnode.data.link.from.fname = opts.to.fname;
}
}
});
return tree;
}
return transformer;
}
Example #6
Source File: remarkTransclusion.ts From vite-plugin-mdx with MIT License | 6 votes |
function findMdxImports(ast: import('mdast').Root) {
const imports: ParsedImport[] = []
ast.children.forEach((node: Node, index) => {
// "import" type is used by @mdx-js/[email protected] and under
if (node.type === 'mdxjsEsm' || node.type === 'import') {
const id = importRE.exec(node.value as string)?.[1]
if (id && mdxRE.test(id)) {
imports.push({ id, node, index })
}
}
})
return imports
}
Example #7
Source File: posts.ts From blog with GNU General Public License v3.0 | 6 votes |
getTOCNodes = (results: TOCRecord[]) => () => (tree) => {
const nodes: Node[] = tree.children || [];
const topTOC = {
href: '/',
label: 'Root',
level: 0,
children: []
};
getTOC(nodes, topTOC);
topTOC.children.forEach(toc => results.push(toc));
}
Example #8
Source File: dendronPreview.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
export function dendronHoverPreview(
this: Unified.Processor,
_opts?: PluginOpts
): Transformer {
const proc = this;
function transformer(tree: Node, _file: VFile) {
visit(
tree,
[
DendronASTTypes.FRONTMATTER,
DendronASTTypes.IMAGE,
DendronASTTypes.EXTENDED_IMAGE,
DendronASTTypes.WIKI_LINK,
DendronASTTypes.USERTAG,
DendronASTTypes.HASHTAG,
],
(node, index, parent) => {
// Remove the frontmatter because it will break the output
if (RemarkUtils.isFrontmatter(node) && parent) {
// Remove this node
parent.children.splice(index, 1);
// Since this removes the frontmatter node, the next node to visit is at the same index.
return index;
}
if (RemarkUtils.isImage(node) || RemarkUtils.isExtendedImage(node)) {
makeImageUrlFullPath({ proc, node });
} else if (RemarkUtils.isWikiLink(node)) {
modifyWikilinkValueToCommandUri({ proc, node });
} else if (RemarkUtils.isUserTag(node) || RemarkUtils.isHashTag(node)) {
modifyTagValueToCommandUri({ proc, node });
}
return undefined; // continue
}
);
}
return transformer;
}
Example #9
Source File: posts.ts From blog with GNU General Public License v3.0 | 6 votes |
htmlParser = () => (tree) => {
const nodes: Node[] = tree.children || [];
const images = findNodes(nodes, node => node.tagName === 'img');
images.forEach((img: NodeElement) => {
img.properties.loading = 'lazy';
});
const preCodeBlocks = findNodes(nodes, node => {
return node.tagName === 'pre' && (node.children as Node[]).some(child => child.tagName === 'code');
});
preCodeBlocks.forEach(pre => {
const codeEl: NodeElement = (pre.children as any[]).find(child => child.tagName === 'code');
const codeContent = codeEl.children[0].value || "";
codeEl.children = [{
type: 'raw',
value: hljs.highlightAuto(codeContent).value
}];
if (!codeEl.properties.className) {
codeEl.properties.className = [];
}
(codeEl.properties.className as string[]).push('hljs');
});
const headersElements = findNodes(nodes, node => {
return ['h1', 'h2', 'h3', 'h4', 'h5'].includes(node.tagName as string);
});
headersElements.forEach((header: NodeElement) => {
const textNode = findNodes((header.children as Node[] || []), (node) => node.type === 'text')[0];
const text: string = textNode.value as string || '-empty-';
const id = text.toLowerCase().replace(/\W/g, '-');
header.properties.id = id;
});
}
Example #10
Source File: dendronPub.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
/**
* Returns a new copy of children array where the first un-rendered
* reference ![[ref]] in children array is replaced with the given `data`. */
function replacedUnrenderedRefWithConvertedData(
data: Parent[],
children: Node[]
) {
if (children.length > 1) {
const idx = _.findIndex(children, RemarkUtils.isNoteRefV2);
const processedChildren = children
.slice(0, idx)
.concat(data)
.concat(children.slice(idx + 1));
return processedChildren;
} else {
return data;
}
}
Example #11
Source File: parsing.ts From blog with GNU General Public License v3.0 | 6 votes |
parserPlugin = (postPath: string) => async tree => {
const images = findImages(tree.children as Node[] || []);
if (images.length === 0) {
return;
}
const s3Urls = await copyImagesToAssets(postPath, images.map(token => decodeURI(token.url as string)));
images.forEach((token, index) => {
token.url = `/${s3Urls[index]}`;
});
}
Example #12
Source File: noteRefsV2.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
function findHeader({
nodes,
match,
slugger,
}: {
nodes: DendronASTNode["children"];
match: string;
slugger: ReturnType<typeof getSlugger>;
}): FindAnchorResult {
const foundIndex = MdastUtils.findIndex(nodes, (node: Node, idx: number) => {
if (idx === 0 && match === "*") {
return false;
}
return MdastUtils.matchHeading(node, match, { slugger });
});
if (foundIndex < 0) return null;
return { type: "header", index: foundIndex, anchorType: "header" };
}
Example #13
Source File: rehypeReplaceJoplinUrl.ts From joplin-utils with MIT License | 6 votes |
export function rehypeReplaceJoplinUrl(note: RenderNote) {
return function transformer(tree: Node) {
visit(tree, 'element', function (node) {
modifyLink(node, 'href')
modifyMedia(node, 'src')
})
}
function modifyLink(node: Node, prop: any) {
if (has(node, prop)) {
const url = (node.properties as any)[prop]
;(node.properties as any)[prop] = replaceUrl(url, note)
;(node.properties as any).target = '_blank'
}
}
function modifyMedia(node: Node, prop: any) {
if (has(node, prop)) {
const url = (node.properties as any)[prop]
;(node.properties as any)[prop] = replaceUrl(url, note)
;(node.properties as any).style = 'max-width: 100%;'
}
}
}
Example #14
Source File: publishSite.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
/**
* Used when publishing
* Rewrite index note
*/
function plugin(this: Unified.Processor, opts: PluginOpts): Transformer {
const proc = this;
const { dest, config } = MDUtilsV5.getProcData(proc);
function transformer(tree: Node, _file: VFile) {
if (dest !== DendronASTDest.HTML) {
return;
}
visit(tree, (node, _idx, _parent) => {
if (node.type === DendronASTTypes.WIKI_LINK) {
const cnode = node as WikiLinkNoteV4;
const value = cnode.value;
const href = PublishUtils.getSiteUrl(config);
if (value === opts.noteIndex.fname) {
node.data!.hProperties = { href };
}
}
});
return tree;
}
return transformer;
}
Example #15
Source File: JoplinNoteHandler.ts From joplin-blog with MIT License | 5 votes |
static format(node: Node) {
return format(this.md.stringify(node), {
parser: 'markdown',
tabWidth: 2,
} as Options)
}
Example #16
Source File: stringify.ts From uniorg with GNU General Public License v3.0 | 5 votes |
export function stringify(org: string | Node | Node[]): string {
const result = Array.isArray(org)
? org.map(stringify).join('')
: stringifyOne(org);
return result;
}
Example #17
Source File: toc.ts From next-cms-ghost with MIT License | 5 votes |
generateTableOfContents = (htmlAst: Node) => {
const tags = [`h1`, `h2`, `h3`, `h4`, `h5`, `h6`]
function headings(node: unknown): node is TocElement {
return tags.includes((node as TocElement).tagName)
}
// recursive walk to visit all children
const walk = (children: TocElement[], text = ``, depth = 0) => {
children.forEach((child) => {
if (child.type === `text`) {
text = text + child.value
} else if (child.children && depth < 3) {
depth = depth + 1
text = walk(child.children, text, depth)
}
})
return text
}
let toc: TOC[] = []
visit(htmlAst, headings, (node: TocElement) => {
const text = walk(node.children || [])
if (text.length > 0) {
const id = (node.properties as NodeProperties).id || `error-missing-id`
const level = (node.tagName as string).substr(1, 1)
toc.push({ level: level, id: id, heading: text, parentIndex: -1, items: [] })
}
})
// Walk up the list to find matching parent
const findParent = (toc: TOC[], parentIndex: number, level: string) => {
while (parentIndex >= 0 && level < toc[parentIndex].level) {
parentIndex = toc[parentIndex].parentIndex
}
return parentIndex >= 0 ? toc[parentIndex].parentIndex : -1
}
// determine parents
toc.forEach((node, index) => {
const prev = toc[index > 0 ? index - 1 : 0]
node.parentIndex = node.level > prev.level ? (node.parentIndex = index - 1) : prev.parentIndex
node.parentIndex = node.level < prev.level ? findParent(toc, node.parentIndex, node.level) : node.parentIndex
})
// add children to their parent
toc.forEach((node: TOC) => node.parentIndex >= 0 && (toc[node.parentIndex].items as TOC[]).push(node))
// make final tree
let tocTree = toc.filter(({ parentIndex }) => parentIndex === -1)
const removeProps = ({ id, heading, items }: TOC): IToC => (items.length > 0 ? { id, heading, items: (items as TOC[]).map((item) => removeProps(item)) } : { id, heading })
return tocTree.map((node) => removeProps(node))
}
Example #18
Source File: index.ts From uniorg with GNU General Public License v3.0 | 5 votes |
export function uniorgStringify(this: any) {
this.Compiler = (node: Node) => {
return stringify(node);
};
}
Example #19
Source File: JoplinNoteHandler.ts From joplin-utils with MIT License | 5 votes |
static format(node: Node) {
return format(this.md.stringify(node), {
parser: 'markdown',
tabWidth: 2,
} as Options)
}
Example #20
Source File: index.spec.ts From uniorg with GNU General Public License v3.0 | 5 votes |
process = (s: string, options?: Options): Node => {
const processor = unified().use(uniorg).use(uniorgSlug, options);
const f = new VFile(s);
return processor.runSync(processor.parse(f), f);
}
Example #21
Source File: remark-img-to-jsx.ts From portfolio with MIT License | 5 votes |
export default function remarkImgToJsx() {
return (tree: Node) => {
visit(
tree,
// only visit p tags that contain an img element
(node: Parent): node is Parent =>
node.type === 'paragraph' &&
node.children.some(n => n.type === 'image'),
(node: Parent) => {
const imageNode = node.children.find(
n => n.type === 'image',
) as ImageNode;
// only local files
if (fs.existsSync(`${process.cwd()}/public${imageNode.url}`)) {
const dimensions = sizeOf(`${process.cwd()}/public${imageNode.url}`);
// Convert original node to next/image
(imageNode.type = 'mdxJsxFlowElement'),
(imageNode.name = 'Image'),
(imageNode.attributes = [
{ type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt },
{ type: 'mdxJsxAttribute', name: 'src', value: imageNode.url },
{
type: 'mdxJsxAttribute',
name: 'width',
value: dimensions.width,
},
{
type: 'mdxJsxAttribute',
name: 'height',
value: dimensions.height,
},
]);
// Change node type from p to div to avoid nesting error
node.type = 'div';
node.children = [imageNode];
}
},
);
};
}
Example #22
Source File: serverSide.ts From roamjs-com with MIT License | 5 votes |
serialize = (
s: string
): Promise<MDXRemoteSerializeResult<Record<string, unknown>>> => {
if (process.env.NODE_ENV === "development")
fs.readdirSync("./out")
.filter((s) => s.endsWith(".json"))
.forEach((s) => fs.unlinkSync(`./out/${s}`));
return mdxSerialize(s, {
mdxOptions: {
rehypePlugins: [
() => (tree) => {
debug(tree);
const expandJsx = async (n: Node) => {
if (n.type === "jsx") {
const match = /^<(\w*)((?: \w*={"[\w\d_-]*"})*?)>(.*)$/s.exec(
n.value as string
);
if (match && match.length >= 3) {
const [, tag, props, rest] = match;
const content = new RegExp(`^(.*?)(</${tag}>)$`, "s").exec(
rest
)?.[1];
if (content) {
n.type = "element";
n.tagName = tag;
n.children = await strToHastCompiler
.run(strToHastCompiler.parse(content))
.then((c) => c.children);
n.properties = props
? Object.fromEntries(
props
.trim()
.split(" ")
.map((prop) =>
/(\w*)={"([\w\d_-]*)"}/.exec(prop.trim())
)
.filter((prop) => !!prop)
.map(([, key, value]) => [key, value])
)
: {};
delete n.value;
}
}
}
((n.children as Node[]) || []).forEach(expandJsx);
};
debug(tree);
return Promise.all((tree.children as Node[]).map(expandJsx))
.then((a) => {
return a[0];
})
.catch((e) => {
console.error(e);
});
},
],
},
});
}
Example #23
Source File: utils.ts From dendron with GNU Affero General Public License v3.0 | 5 votes |
/** Extract all blocks from the note which could be referenced by a block anchor.
*
* If those blocks already have anchors (or if they are a header), this will also find that anchor.
*
* @param note The note from which blocks will be extracted.
*/
static async extractBlocks({
note,
engine,
}: {
note: NoteProps;
engine: DEngineClient;
}): Promise<NoteBlock[]> {
const proc = MDUtilsV5.procRemarkFull({
engine,
vault: note.vault,
fname: note.fname,
dest: DendronASTDest.MD_DENDRON,
});
const slugger = getSlugger();
// Read and parse the note
const noteText = NoteUtils.serialize(note);
const noteAST = proc.parse(noteText);
// @ts-ignore
if (_.isUndefined(noteAST.children)) return [];
// @ts-ignore
const nodesToSearch = _.filter(noteAST.children as Node[], (node) =>
_.includes(NODE_TYPES_TO_EXTRACT, node.type)
);
// Extract the blocks
const blocks: NoteBlock[] = [];
for (const node of nodesToSearch) {
// Block anchors at top level refer to the blocks before them
if (node.type === DendronASTTypes.PARAGRAPH) {
// These look like a paragraph...
const parent = node as Paragraph;
if (parent.children.length === 1) {
// ... that has only a block anchor in it ...
const child = parent.children[0] as Node;
if (child.type === DendronASTTypes.BLOCK_ANCHOR) {
// ... in which case this block anchor refers to the previous block, if any
const previous = _.last(blocks);
if (!_.isUndefined(previous))
[, previous.anchor] =
AnchorUtils.anchorNode2anchor(child as BlockAnchor, slugger) ||
[];
// Block anchors themselves are not blocks, don't extract them
continue;
}
}
}
// Extract list items out of lists. We also extract them from nested lists,
// because block anchors can't refer to nested lists, only items inside of them
if (node.type === DendronASTTypes.LIST) {
visit(node, [DendronASTTypes.LIST_ITEM], (listItem: ListItem) => {
// The list item might have a block anchor inside of it.
let anchor: DNoteAnchorPositioned | undefined;
visit(
listItem,
[DendronASTTypes.BLOCK_ANCHOR, DendronASTTypes.LIST],
(inListItem) => {
// Except if we hit a nested list, because then the block anchor refers to the item in the nested list
if (inListItem.type === DendronASTTypes.LIST) return "skip";
[, anchor] =
AnchorUtils.anchorNode2anchor(
inListItem as BlockAnchor,
slugger
) || [];
return;
}
);
blocks.push({
text: proc.stringify(listItem),
anchor,
// position can only be undefined for generated nodes, not for parsed ones
position: listItem.position!,
type: listItem.type,
});
});
}
// extract the anchor for this block, if it exists
let anchor: DNoteAnchorPositioned | undefined;
if (node.type === DendronASTTypes.HEADING) {
// Headings are anchors themselves
[, anchor] =
AnchorUtils.anchorNode2anchor(node as Heading, slugger) || [];
} else if (node.type !== DendronASTTypes.LIST) {
// Other nodes might have block anchors inside them
// Except lists, because anchors inside lists only refer to specific list items
visit(node, [DendronASTTypes.BLOCK_ANCHOR], (child) => {
[, anchor] =
AnchorUtils.anchorNode2anchor(child as BlockAnchor, slugger) || [];
});
}
// extract the block
blocks.push({
text: proc.stringify(node),
anchor,
// position can only be undefined for generated nodes, not for parsed ones
position: node.position!,
type: node.type,
});
}
return blocks;
}
Example #24
Source File: remarkTransclusion.ts From vite-plugin-mdx with MIT License | 5 votes |
function isRootNode(node: Node): node is import('mdast').Root {
return node.type === 'root'
}
Example #25
Source File: index.ts From gatsby-project-kb with MIT License | 4 votes |
processWikiLinks = (
{ markdownAST }: { markdownAST: Node },
options?: { titleToURLPath?: string; stripBrackets?: boolean, stripDefinitionExts?: string[] }
) => {
const { stripDefinitionExts } = options
const titleToURL = options?.titleToURLPath
? require(options.titleToURLPath)
: defaultTitleToURLPath
const definitions: { [identifier: string]: Definition } = {}
const getLinkInfo = (definition: Definition) => {
if (typeof definition.identifier !== 'string') return
let linkUrl = definition.url
const isExternalLink = /\/\//.test(linkUrl)
let shouldReplace = !isExternalLink
if (shouldReplace && stripDefinitionExts) {
const extname = path.extname(definition.url || '')
const matchedExtname = stripDefinitionExts.find((n) => extname === n)
if (matchedExtname) {
linkUrl = linkUrl.slice(0, linkUrl.length - matchedExtname.length)
}
}
return {
linkUrl,
shouldReplace
}
}
visit(markdownAST, `definition`, (node: Definition) => {
if (!node.identifier || typeof node.identifier !== 'string') {
return
}
definitions[node.identifier] = node
})
visit(markdownAST, `linkReference`, (node: LinkReferenceNode, index, parent) => {
if (node.referenceType !== 'shortcut') {
return
}
const definition = definitions[node.identifier]
const linkInfo = definition ? getLinkInfo(definition): null
const linkUrl = linkInfo ? linkInfo.linkUrl: definition?.url
if ((linkInfo && !linkInfo.shouldReplace)) {
// console.log('should not replace', definitions, node.identifier)
return
}
const siblings = parent.children
if (!siblings || !Array.isArray(siblings)) {
return
}
const previous: StaticPhrasingContent = siblings[index - 1] as any
const next: StaticPhrasingContent = siblings[index + 1] as any
if (!(previous && next)) {
return
}
if (!('value' in previous && 'value' in next)) {
return
}
const previousValue = previous.value as string
const nextValue = next.value as string
if (
previous.type !== 'text' ||
previous.value[previousValue.length - 1] !== '[' ||
next.type !== 'text' ||
next.value[0] !== ']'
) {
return
}
previous.value = previousValue.replace(/\[$/, '')
next.value = nextValue.replace(/^\]/, '')
;(node as any).type = 'link' // cast it to link
if (definition) {
node.url = linkUrl
} else {
node.url = titleToURL(node.label as string)
}
node.title = node.label
if (!options?.stripBrackets && Array.isArray(node.children)) {
const firstChild = node.children[0];
if (firstChild && 'value' in firstChild) {
firstChild.value = `[[${firstChild.value}]]`
}
}
delete node.label
delete node.referenceType
delete node.identifier
})
}
Example #26
Source File: hierarchies.ts From dendron with GNU Affero General Public License v3.0 | 4 votes |
plugin: Plugin = function (this: Unified.Processor, _opts?: PluginOpts) {
const proc = this;
const { config } = MDUtilsV5.getProcData(this);
let hierarchyDisplayTitle = config?.hierarchyDisplayTitle || "Children";
let hierarchyDisplay = config?.hierarchyDisplay;
if (MDUtilsV5.shouldApplyPublishingRules(proc)) {
const hierarchyConfigForPublishing =
ConfigUtils.getHierarchyDisplayConfigForPublishing(config);
hierarchyDisplay = hierarchyConfigForPublishing.hierarchyDisplay;
if (!_.isUndefined(hierarchyConfigForPublishing.hierarchyDisplayTitle)) {
hierarchyDisplayTitle =
hierarchyConfigForPublishing.hierarchyDisplayTitle;
}
}
if (hierarchyDisplay === undefined) hierarchyDisplay = true;
function transformer(tree: Node): void {
const root = tree as Root;
const { fname, vault, dest, config, insideNoteRef } =
MDUtilsV4.getDendronData(proc);
let addedBreak = false;
if (dest !== DendronASTDest.HTML) {
return;
}
// TODO: remove
if (!hierarchyDisplay) {
return;
}
function addBreak() {
if (addedBreak) return;
root.children.push({
type: "thematicBreak",
});
addedBreak = true;
}
function addFootnotes() {
/** Maps footnote identifiers to their definitions. */
const footnotes = new Map(
RemarkUtils.extractFootnoteDefs(root).map((definition) => [
definition.identifier,
definition,
])
);
/** All footnote definitions that have been referenced in this document. */
const usedFootnotes = new Set<FootnoteDefinition>();
visit(
root,
[DendronASTTypes.FOOTNOTE_REFERENCE],
(reference: FootnoteReference, index, parent) => {
const definition = footnotes.get(reference.identifier);
if (definition && parent) {
parent.children[index] = footnote2html(reference);
usedFootnotes.add(definition);
}
}
);
if (usedFootnotes.size > 0) {
addBreak();
root.children.push(heading(2, text("Footnotes")) as Content);
const footnoteItems: Node[] = [];
for (const definition of usedFootnotes) {
footnoteItems.push(listItem(footnoteDef2html(definition)));
}
root.children.push(list("ordered", footnoteItems) as Content);
}
}
if (!fname || insideNoteRef) {
// Even inside a note ref, render footnotes because we want them in there too
addFootnotes();
return;
}
const { engine } = MDUtilsV4.getEngineFromProc(proc);
const note = NoteUtils.getNoteByFnameFromEngine({
fname,
engine,
vault: vault!,
});
// check if v5 is active
if (MDUtilsV5.isV5Active(proc)) {
const resp = MDUtilsV5.getProcData(proc);
hierarchyDisplay = ConfigUtils.getEnableChildLinks(resp.config, { note });
}
/** Add frontmatter tags, if any, ahead of time. This way wikilink compiler will pick them up and render them. */
function addTags() {
const shouldApplyPublishRules =
MDUtilsV5.shouldApplyPublishingRules(proc);
const enableFrontmatterTags = ConfigUtils.getEnableFrontmatterTags({
config,
shouldApplyPublishRules,
});
const enableHashesForFMTags = ConfigUtils.getEnableHashesForFMTags({
config,
shouldApplyPublishRules,
});
if (
enableFrontmatterTags !== false &&
note?.tags &&
note.tags.length > 0
) {
addBreak();
root.children.push(heading(2, text("Tags")) as Content);
const tags = _.isString(note.tags) ? [note.tags] : note.tags;
const tagLinks = _.sortBy(
_.map(tags, (tag) =>
listItem(
paragraph(
frontmatterTag2WikiLinkNoteV4(tag, enableHashesForFMTags)
)
)
),
["custom.nav_order", "title"]
);
root.children.push(list("ordered", tagLinks) as Content);
}
}
function addChildren() {
// don't include if collection present
if (!note || note.children.length <= 0 || note?.custom?.has_collection) {
return;
}
if (
_.isBoolean(note.custom?.hierarchyDisplay) &&
!note.custom.hierarchyDisplay
) {
return;
}
const children = HierarchyUtils.getChildren({
skipLevels: note.custom?.skipLevels || 0,
note,
notes: engine.notes,
})
.filter((note) => SiteUtils.canPublish({ note, engine, config }))
.filter(
(note) =>
_.isUndefined(note.custom?.nav_exclude) || !note.custom?.nav_exclude
);
if (!_.isEmpty(children)) {
addBreak();
root.children.push(
u("strong", [{ type: "text", value: hierarchyDisplayTitle }])
);
root.children.push(
list(
"ordered",
_.sortBy(children, ["custom.nav_order", "title"]).map((note) => {
return listItem(
paragraph({
type: DendronASTTypes.WIKI_LINK,
value: note.fname,
data: {
alias: note.title,
vaultName: VaultUtils.getName(note.vault),
},
children: [],
} as WikiLinkNoteV4)
);
})
) as Content
);
}
}
// Will appear on page in this order
if (hierarchyDisplay) {
addChildren();
}
addTags();
addFootnotes();
// end transformer
}
return transformer;
}