Skip to content

Commit

Permalink
Convert lint-teleport-docs-links to a lintRule
Browse files Browse the repository at this point in the history
Apply gravitational/docs#505

Also fix type errors required to transpile our remark linters from
TypeScript.
  • Loading branch information
ptgott committed Dec 11, 2024
1 parent 5d4b91f commit d0c5b4f
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 42 deletions.
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

0 comments on commit d0c5b4f

Please sign in to comment.