Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert lint-teleport-docs-links to a lintRule #80

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions server/lint-teleport-docs-links.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { lintRule } from "unified-lint-rule";
import { visit } from "unist-util-visit";
import type { Link } from "mdast";
import type { EsmNode, MdxAnyElement, MdxastNode } from "./types-unist";
import type { Node } from "unist";
import type { Transformer } from "unified";
import type { Root, Link as MdastLink } from "mdast";
import type { EsmNode, MdxAnyElement } from "./types-unist";

import { visit } from "unist-util-visit";
import { isExternalLink, isHash, isPage } from "../utils/url";

interface ObjectHref {
Expand All @@ -29,17 +29,13 @@ const isAnAbsoluteDocsLink = (href: string): boolean => {
);
};

export function remarkLintTeleportDocsLinks(): Transformer {
return (root: Root, vfile) => {
visit(root, (node: Node) => {
if (
node.type == "link" &&
isAnAbsoluteDocsLink((node as MdastLink).url)
) {
export const remarkLintTeleportDocsLinks = lintRule(
"remark-lint:absolute-docs-links",
(root: Node, vfile) => {
visit(root, undefined, (node: Node) => {
if (node.type == "link" && isAnAbsoluteDocsLink((node as Link).url)) {
vfile.message(
`Link reference ${
(node as MdastLink).url
} must be a relative link to an *.mdx page`,
`Link reference ${(node as Link).url} must be a relative link to an *.mdx page`,
node.position
);
return;
Expand All @@ -58,5 +54,5 @@ export function remarkLintTeleportDocsLinks(): Transformer {
}
}
});
};
}
}
);
26 changes: 14 additions & 12 deletions server/rehype-hljs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import rehypeHighlight, {
Options as RehypeHighlightOptions,
} from "rehype-highlight";
import { common } from "lowlight";
import type { Node as UnistNode, Parent as UnistParent } from "unist";
import { visit, CONTINUE, SKIP } from "unist-util-visit";
import { v4 as uuid } from "uuid";
import remarkParse from "remark-parse";
Expand All @@ -20,11 +21,11 @@ const makePlaceholder = (): string => {
const placeholderPattern = "var[a-z0-9]{32}";

export const rehypeHLJS = (options?: RehypeHighlightOptions): Transformer => {
return (root: Parent, file: VFile) => {
return (root: UnistNode, file: VFile) => {
// We only visit text nodes inside code snippets that include either the
// <Var tag or (if we have already swapped out Vars with placeholders) a
// placeholder.
const isPossibleVarContainer = (node: Node) => {
const isPossibleVarContainer = (node: UnistParent) => {
let textValue;
if (
node.type === "text" ||
Expand Down Expand Up @@ -56,14 +57,15 @@ export const rehypeHLJS = (options?: RehypeHighlightOptions): Transformer => {
visit(
root,
isPossibleVarContainer,
(node: Node, index: number, parent: Parent) => {
(node: UnistNode, index: number, parent: Parent) => {
const varPattern = new RegExp("<Var [^>]+/>", "g");
const unknownText = node as unknown;
let txt: Text;
if (node.type == "text") {
txt = node;
txt = unknownText as Text;
} else {
// isPossibleVarContainer enforces having a single child text node
txt = node.children[0];
txt = (unknownText as Parent).children[0] as Text;
}

const newVal = txt.value.replace(varPattern, (match) => {
Expand All @@ -72,18 +74,18 @@ export const rehypeHLJS = (options?: RehypeHighlightOptions): Transformer => {
// its properties. The result should be a small HTML AST with a root
// node and one child, the Var node.
const varElement = unified()
.use(remarkParse)
// Converting to "any" since, for some reason, the type of
// remarkParse doesn't match the signature of "use" despite this
// being a common use case in the unified documentation.
.use(remarkParse as any)
.use(remarkMDX)
.parse(match);

placeholdersToVars[placeholder] = varElement.children[0];
placeholdersToVars[placeholder] = (varElement as Parent).children[0];
return placeholder;
});
if (node.type == "text") {
node.value = newVal;
} else {
node.children[0].value = newVal;
}

txt.value = newVal;
}
);

Expand Down
26 changes: 12 additions & 14 deletions server/remark-code-snippet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
*/

import type { Transformer } from "unified";
import type { Code as MdastCode } from "mdast";
import type { Code as MdastCode, Text } from "mdast";
import type { Node } from "unist";
import type {
MdxastNode,
MdxJsxAttribute,
Expand All @@ -37,10 +38,10 @@ const RULE_ID = "code-snippet";

const isCode =
(langs: string[]) =>
(node: MdxastNode): node is MdastCode =>
node.type === "code" && langs.includes(node.lang);
(node: Node): node is MdastCode =>
node.type === "code" && langs.includes((node as MdastCode).lang);

const getTextChildren = (contentValue: string): MdxastNode => ({
const getTextChildren = (contentValue: string): Text => ({
type: "text",
value: contentValue,
});
Expand Down Expand Up @@ -72,9 +73,9 @@ const getVariableNode = (
};
};

const getChildrenNode = (content: string): MdxastNode[] => {
const getChildrenNode = (content: string): Array<Text | MdxJsxFlowElement> => {
const hasVariable = content?.includes("<Var");
const nodeChildren: MdxastNode[] = [];
const nodeChildren: Array<Text | MdxJsxFlowElement> = [];

if (hasVariable) {
const contentVars = content.match(/(?:\<Var .+?\/\>)/gm);
Expand Down Expand Up @@ -111,7 +112,7 @@ const getChildrenNode = (content: string): MdxastNode[] => {
return nodeChildren;
};

const getCommandNode = (content: string, prefix = "$"): MdxJsxFlowElement => {
const getCommandNode = (content: string, prefix = "$") => {
const children = getChildrenNode(content);

return {
Expand All @@ -135,7 +136,7 @@ const getCommandNode = (content: string, prefix = "$"): MdxJsxFlowElement => {
};
};

const getLineNode = (content: string, attributes = []): MdxJsxFlowElement => {
const getLineNode = (content: string, attributes = []) => {
const children = getChildrenNode(content);

return {
Expand All @@ -149,7 +150,7 @@ const getLineNode = (content: string, attributes = []): MdxJsxFlowElement => {
const getCommentNode = (
content: string,
attributes: MdxJsxAttribute[] = []
): MdxJsxFlowElement => ({
) => ({
type: "mdxJsxFlowElement",
name: "commandcomment",
attributes,
Expand All @@ -161,10 +162,7 @@ const getCommentNode = (
],
});

const getCodeLine = (
content: string,
attributes: MdxJsxAttribute[] = []
): MdxJsxFlowElement => {
const getCodeLine = (content: string, attributes: MdxJsxAttribute[] = []) => {
const children = getChildrenNode(content);

return {
Expand All @@ -185,7 +183,7 @@ export default function remarkCodeSnippet({
langs = ["code"],
lint = false,
}: RemarkCodeSnippetOptions): Transformer {
return (root, vfile) => {
return (root: Node, vfile) => {
visit(
root,
isCode(langs),
Expand Down
Loading