mdast#Link TypeScript Examples
The following examples show how to use
mdast#Link.
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: dendronPreview.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
/**
* Transforms any UserTag or HashTag nodes into a vscode command URI for gotoNote.
*/
function modifyTagValueToCommandUri({
proc,
node,
}: {
proc: Unified.Processor;
node: UserTag | HashTag;
}) {
const { vault } = MDUtilsV5.getProcData(proc);
const goToNoteCommandOpts = {
qs: node.fname,
vault,
};
const encodedArgs = encodeURIComponent(JSON.stringify(goToNoteCommandOpts));
// Convert the node to a 'link' type so that it can behave properly like a
// link instead of the tag behavior, since we've changed the value to a
// command URI
(node as unknown as Link).type = "link";
(node as unknown as Link).url = `command:dendron.gotoNote?${encodedArgs}`;
const childTextNode: Text = {
type: "text",
value: node.value,
};
(node as unknown as Link).children = [childTextNode];
}
Example #2
Source File: utils.ts From dendron with GNU Affero General Public License v3.0 | 6 votes |
static isLink(node: Node): node is Link {
return node.type === DendronASTTypes.LINK;
}
Example #3
Source File: JoplinNoteParser.ts From joplin-blog with MIT License | 6 votes |
/**
* 扫描笔记中的 joplin 内部链接
* 包括
* 图像/附件
* 引用笔记
*/
scanResource(content: string): string[] {
const res: string[] = []
visit(this.processor.parse(content), ['link', 'image'], (node: Link) => {
res.push(node.url)
})
return res
.filter((link) => link.startsWith(':/'))
.map((link) => link.slice(2))
}
Example #4
Source File: JoplinNoteParser.ts From joplin-blog with MIT License | 6 votes |
/**
* 转换笔记中的 joplin 内部链接
* @param content
* @param map
*/
convertResource(content: string, map: Map<string, string>) {
const tree = unistUtilMap(this.processor.parse(content), (node) => {
if (node.type !== 'link' && node.type !== 'image') {
return node
}
const link = node as Link
if (!link.url.startsWith(':/')) {
return link
}
return {
...node,
url: map.get(link.url.slice(2)),
} as Link
})
const options: Options = { parser: 'markdown', tabWidth: 2 }
return format(this.processor.stringify(tree), options)
}
Example #5
Source File: MarkdownLinkUtil.ts From joplin-utils with MIT License | 6 votes |
/**
* 解析 markdown 文本中的链接
* @param content
*/
static parseLink(content: string): ContentLink[] {
const node = mdParser.parse(content)
const res: ContentLink[] = []
visit(node, (node) => {
// console.log(node.type)
if (node.type !== 'link') {
return
}
const link = node as Link
if (link.url.startsWith('https')) {
// console.log(link.children[0])
}
res.push({
title: (link.children[0] as any)?.value as string,
url: link.url as string,
})
})
return res
}
Example #6
Source File: MarkdownLinkUtil.ts From joplin-utils with MIT License | 6 votes |
/**
* 转换笔记中的链接
* @param content
* @param convertLinkMap
*/
static convertLink(
content: string,
convertLinkMap: Record<string, ContentLink>,
): string {
const node = mdParser.parse(content)
visit(node, (node) => {
if (node.type !== 'link') {
return
}
const link = node as Link
const map = convertLinkMap[link.url]
if (map) {
link.url = map.url
if (link.children.length === 0) {
link.children.push({
type: 'text',
value: '',
})
}
;(link.children[0] as any).value = map.title
}
})
return mdParser.stringify(node)
}
Example #7
Source File: remark.test.ts From joplin-utils with MIT License | 6 votes |
it('测试', () => {
const md = unified().use(remarkParse).use(remarkGfm).use(remarkStringify, {
bullet: '-',
fences: true,
incrementListMarker: false,
})
const res: Pick<ResourceProperties, 'id' | 'title'>[] = []
visit(md.parse(data.body), (node) => {
if (node.type !== 'link' && node.type !== 'image') {
return
}
const link = node as Link | Image
if (!link.url.startsWith(':/')) {
return
}
res.push({
id: link.url.slice(2),
title: (link.type === 'link'
? link.title ?? (link.children[0] as any).value
: link.alt) as string,
})
})
console.log('res: ', res)
})
Example #8
Source File: parseInternalLink.ts From joplin-utils with MIT License | 6 votes |
/**
* 解析 markdown 中所有引用的附件资源
* @param content
*/
export function parseInternalLink(content: string): Pick<ResourceProperties, 'id' | 'title'>[] {
const res: Pick<ResourceProperties, 'id' | 'title'>[] = []
visit(mdParser.parse(content), (node) => {
if (node.type !== 'link' && node.type !== 'image') {
return
}
const link = node as Link | Image
if (!link.url.startsWith(':/')) {
return
}
res.push({
id: parseInternalLinkToId(link.url),
title: (link.type === 'link' ? link.title ?? (link.children[0] as any).value : link.alt) as string,
})
})
return res
}
Example #9
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 #10
Source File: index.ts From website-docs with MIT License | 5 votes |
module.exports = function ({
markdownAST,
markdownNode,
}: {
markdownAST: Root
markdownNode: { fileAbsolutePath: string }
}) {
visit(markdownAST, (node: any) => {
if (Array.isArray(node.children)) {
node.children = node.children.flatMap((node: any) => {
if (node.type === 'link' && !node.url.startsWith('#')) {
const ele = node as Link
if (ele.url.startsWith('http')) {
return [
{
type: 'jsx',
value: `<a href="${ele.url}" target="_blank" referrerPolicy="no-referrer-when-downgrade">`,
},
...node.children,
{ type: 'jsx', value: '</a>' },
]
} else {
const urlSeg = ele.url.split('/')
const fileName = urlSeg[urlSeg.length - 1].replace('.md', '')
const path = markdownNode.fileAbsolutePath.endsWith('_index.md')
? fileName
: '../' + fileName
return [
{
type: 'jsx',
value: `<Link to="${path}">`,
},
...node.children,
{ type: 'jsx', value: '</Link>' },
]
}
}
if (node.type === 'blockquote') {
const ele = node as Blockquote
const first = ele.children[0]
if (
first?.type === 'paragraph' &&
first.children?.[0].type === 'strong' &&
first.children[0].children?.[0].type === 'text'
) {
const text = first.children[0].children[0].value
switch (text) {
case 'Note:':
case '注意:':
case 'Warning:':
case '警告:':
case 'Tip:':
case '建议:':
case 'Important:':
case '重要:': {
const children = node.children.slice(1)
const jsx = textToJsx(text)
return [
{ type: 'jsx', value: `<${jsx}>` },
...children,
{ type: 'jsx', value: `</${jsx}>` },
]
}
default:
return ele
}
}
return ele
}
return node
})
}
})
}
Example #11
Source File: toc.ts From website-docs with MIT License | 5 votes |
function getContentFromLink(
content: Paragraph,
config: PathConfig
): RepoNavLink {
if (content.type !== 'paragraph' || content.children.length === 0) {
throw new Error(`incorrect format in TOC.md`)
}
const child = content.children[0] as Link | Text
if (child.type === 'link') {
if (child.children.length === 0) {
throw new Error(`incorrect link in TOC.md`)
}
const content = child.children.map(node => {
switch (node.type) {
case 'text':
return node.value
case 'inlineCode':
return { code: true, value: node.value }
default:
throw new Error(`unsupported tag ${node.type} in TOC link`)
}
})
if (child.url.startsWith('https://')) {
return {
link: child.url,
content,
}
}
const urlSegs = child.url.split('/')
const filename = urlSegs[urlSegs.length - 1].replace('.md', '')
return {
link: generateUrl(filename, config),
content,
}
} else {
return {
content: [child.value],
}
}
}
Example #12
Source File: JoplinNoteHandler.ts From joplin-blog with MIT License | 5 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 #13
Source File: descriptionFormatter.ts From prettier-plugin-jsdoc with MIT License | 4 votes |
/**
* Trim, make single line with capitalized text. Insert dot if flag for it is
* set to true and last character is a word character
*
* @private
*/
function formatDescription(
tag: string,
text: string,
options: AllOptions,
formatOptions: FormatOptions,
): string {
if (!text) return text;
const { printWidth } = options;
const { tagStringLength = 0, beginningSpace } = formatOptions;
/**
* change list with dash to dot for example:
* 1- a thing
*
* to
*
* 1. a thing
*/
text = text.replace(/^(\d+)[-][\s|]+/g, "$1. "); // Start
text = text.replace(/\n+(\s*\d+)[-][\s]+/g, "\n$1. ");
const fencedCodeBlocks = text.matchAll(/```\S*?\n[\s\S]+?```/gm);
const indentedCodeBlocks = text.matchAll(
/^\r?\n^(?:(?:(?:[ ]{4}|\t).*(?:\r?\n|$))+)/gm,
);
const allCodeBlocks = [...fencedCodeBlocks, ...indentedCodeBlocks];
const tables: string[] = [];
text = text.replace(
/((\n|^)\|[\s\S]*?)((\n[^|])|$)/g,
(code, _1, _2, _3, _, offs: number) => {
// If this potential table is inside a code block, don't touch it
for (const block of allCodeBlocks) {
if (
block.index !== undefined &&
block.index <= offs + 1 &&
offs + code.length + 1 <= block.index + block[0].length
) {
return code;
}
}
code = _3 ? code.slice(0, -1) : code;
tables.push(code);
return `\n\n${TABLE}\n\n${_3 ? _3.slice(1) : ""}`;
},
);
if (
options.jsdocCapitalizeDescription &&
!TAGS_PEV_FORMATE_DESCRIPTION.includes(tag)
) {
text = capitalizer(text);
}
text = `${tagStringLength ? `${"!".repeat(tagStringLength - 1)}?` : ""}${
text.startsWith("```") ? "\n" : ""
}${text}`;
let tableIndex = 0;
const rootAst = fromMarkdown(text);
function stringifyASTWithoutChildren(
mdAst: Content | Root,
intention: string,
parent: Content | Root | null,
) {
if (mdAst.type === "inlineCode") {
return `\`${mdAst.value}\``;
}
if (mdAst.type === "code") {
let result = mdAst.value || "";
let _intention = intention;
if (result) {
// Remove two space from lines, maybe added previous format
if (mdAst.lang) {
const supportParsers = parserSynonyms(mdAst.lang.toLowerCase());
const parser = supportParsers?.includes(options.parser as any)
? options.parser
: supportParsers?.[0] || mdAst.lang;
result = formatCode(result, intention, {
...options,
parser,
jsdocKeepUnParseAbleExampleIndent: true,
});
} else if (options.jsdocPreferCodeFences || false) {
result = formatCode(result, _intention, {
...options,
jsdocKeepUnParseAbleExampleIndent: true,
});
} else {
_intention = intention + " ".repeat(4);
result = formatCode(result, _intention, {
...options,
jsdocKeepUnParseAbleExampleIndent: true,
});
}
}
const addFence = options.jsdocPreferCodeFences || !!mdAst.lang;
result = addFence ? result : result.trimEnd();
return result
? addFence
? `\n\n${_intention}\`\`\`${mdAst.lang || ""}${result}\`\`\``
: `\n${result}`
: "";
}
if ((mdAst as Text).value === TABLE) {
if (parent) {
(parent as any).costumeType = TABLE;
}
if (tables.length > 0) {
let result = tables?.[tableIndex] || "";
tableIndex++;
if (result) {
result = format(result, {
...options,
parser: "markdown",
}).trim();
}
return `${
result
? `\n\n${intention}${result.split("\n").join(`\n${intention}`)}`
: (mdAst as Text).value
}`;
}
}
if (mdAst.type === "break") {
return `\\\n`;
}
return ((mdAst as Text).value ||
(mdAst as Link).title ||
(mdAst as Image).alt ||
"") as string;
}
function stringyfy(
mdAst: Content | Root,
intention: string,
parent: Content | Root | null,
): string {
if (!Array.isArray((mdAst as Root).children)) {
return stringifyASTWithoutChildren(mdAst, intention, parent);
}
return ((mdAst as Root).children as Content[])
.map((ast, index) => {
switch (ast.type) {
case "listItem": {
let _listCount = `\n${intention}- `;
// .replace(/((?!(^))\n)/g, "\n" + _intention);
if (typeof (mdAst as List).start === "number") {
const count = index + (((mdAst as List).start as number) ?? 1);
_listCount = `\n${intention}${count}. `;
}
const _intention = intention + " ".repeat(_listCount.length - 1);
const result = stringyfy(ast, _intention, mdAst).trim();
return `${_listCount}${result}`;
}
case "list": {
let end = "";
/**
* Add empty line after list if that is end of description
* issue: {@link https://github.com/hosseinmd/prettier-plugin-jsdoc/issues/98}
*/
if (
tag !== DESCRIPTION &&
mdAst.type === "root" &&
index === mdAst.children.length - 1
) {
end = "\n";
}
return `\n${stringyfy(ast, intention, mdAst)}${end}`;
}
case "paragraph": {
const paragraph = stringyfy(ast, intention, parent);
if ((ast as any).costumeType === TABLE) {
return paragraph;
}
return `\n\n${paragraph
/**
* Break by backslash\
* issue: https://github.com/hosseinmd/prettier-plugin-jsdoc/issues/102
*/
.split("\\\n")
.map((_paragraph) => {
const links: string[] = [];
// Find jsdoc links and remove spaces
_paragraph = _paragraph.replace(
/{@(link|linkcode|linkplain)[\s](([^{}])*)}/g,
(_, tag: string, link: string) => {
links.push(link);
return `{@${tag}${"_".repeat(link.length)}}`;
},
);
_paragraph = _paragraph.replace(/\s+/g, " "); // Make single line
if (
options.jsdocCapitalizeDescription &&
!TAGS_PEV_FORMATE_DESCRIPTION.includes(tag)
)
_paragraph = capitalizer(_paragraph);
if (options.jsdocDescriptionWithDot)
_paragraph = _paragraph.replace(/([\w\p{L}])$/u, "$1."); // Insert dot if needed
let result = breakDescriptionToLines(
_paragraph,
printWidth,
intention,
);
// Replace links
result = result.replace(
/{@(link|linkcode|linkplain)([_]+)}/g,
(original: string, tag: string, underline: string) => {
const link = links[0];
if (link.length === underline.length) {
links.shift();
return `{@${tag} ${link}}`;
}
return original;
},
);
return result;
})
.join("\\\n")}`;
}
case "strong": {
return `**${stringyfy(ast, intention, mdAst)}**`;
}
case "emphasis": {
return `_${stringyfy(ast, intention, mdAst)}_`;
}
case "heading": {
return `\n\n${intention}${"#".repeat(ast.depth)} ${stringyfy(
ast,
intention,
mdAst,
)}`;
}
case "link":
case "image": {
return `[${stringyfy(ast, intention, mdAst)}](${ast.url})`;
}
case "linkReference": {
return `[${stringyfy(ast, intention, mdAst)}][${ast.label}]`;
}
case "definition": {
return `\n\n[${ast.label}]: ${ast.url}`;
}
case "blockquote": {
const paragraph = stringyfy(ast, "", mdAst);
return `${intention}> ${paragraph
.trim()
.replace(/(\n+)/g, `$1${intention}> `)}`;
}
}
return stringyfy(ast, intention, mdAst);
})
.join("");
}
let result = stringyfy(rootAst, beginningSpace, null);
result = result.replace(/^[\s\n]+/g, "");
result = result.replace(/^([!]+\?)/g, "");
return result;
}