From f34d1d67abdfbab304677cf802d5351d68a71684 Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Wed, 15 May 2024 18:01:25 -0700 Subject: [PATCH] create mdx-utils --- src/transformers/api-labels.ts | 7 +- src/transformers/api-options-class.ts | 14 +--- src/transformers/api-structure-previews.ts | 73 ++++------------ src/transformers/fiddle-embedder.ts | 42 +--------- src/transformers/js-code-blocks.ts | 42 +--------- src/util/mdx-utils.ts | 97 ++++++++++++++++++++++ 6 files changed, 121 insertions(+), 154 deletions(-) create mode 100644 src/util/mdx-utils.ts diff --git a/src/transformers/api-labels.ts b/src/transformers/api-labels.ts index fef236566..af68801a1 100644 --- a/src/transformers/api-labels.ts +++ b/src/transformers/api-labels.ts @@ -1,7 +1,8 @@ import { Parent } from 'unist'; import { visitParents } from 'unist-util-visit-parents'; import { Data as HastData } from 'hast'; -import { Emphasis, PhrasingContent, Text } from 'mdast'; +import { Emphasis } from 'mdast'; +import { isText } from '../util/mdx-utils'; /** * This transformer adds badge styling to our raw API documentation. @@ -63,7 +64,3 @@ function visitor(node: Emphasis) { } } } - -function isText(node: PhrasingContent): node is Text { - return node.type === 'text'; -} diff --git a/src/transformers/api-options-class.ts b/src/transformers/api-options-class.ts index ad4cbc5db..be861ba2a 100644 --- a/src/transformers/api-options-class.ts +++ b/src/transformers/api-options-class.ts @@ -1,7 +1,8 @@ -import { Node, Parent } from 'unist'; -import { InlineCode, ListItem, Paragraph } from 'mdast'; +import { Parent } from 'unist'; +import { ListItem } from 'mdast'; import { Data as HastData } from 'hast'; import { visitParents } from 'unist-util-visit-parents'; +import { isOptions, isParagraph } from '../util/mdx-utils'; /** * This transformer adds the class="electron-api-options-list" @@ -41,12 +42,3 @@ function visitor(node: ListItem) { node.data = hastProperties; } } - -function isParagraph(node: Node): node is Paragraph { - return node.type === 'paragraph'; -} - -function isOptions(node: Node): node is InlineCode { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return node.type === 'inlineCode' && (node as any).value === 'options'; -} diff --git a/src/transformers/api-structure-previews.ts b/src/transformers/api-structure-previews.ts index f84627b8d..1e2f47b40 100644 --- a/src/transformers/api-structure-previews.ts +++ b/src/transformers/api-structure-previews.ts @@ -3,19 +3,20 @@ import { visitParents } from 'unist-util-visit-parents'; import fs from 'fs'; import path from 'path'; import { Node, Parent } from 'unist'; -import type { - Definition, - InlineCode, - Link, - LinkReference, - Nodes, - Text, -} from 'mdast'; +import type { InlineCode, Link, LinkReference, Nodes, Text } from 'mdast'; import { gfmTableToMarkdown } from 'mdast-util-gfm-table'; import { frontmatterToMarkdown } from 'mdast-util-frontmatter'; import { toMarkdown } from 'mdast-util-to-markdown'; import { MdxJsxFlowElement } from 'mdast-util-mdx-jsx'; import type { VFile } from 'vfile'; +import { + getJSXImport, + isDefinition, + isInlineCode, + isLink, + isLinkReference, + isText, +} from '../util/mdx-utils'; const fileContent = new Map< string, @@ -81,38 +82,9 @@ async function transformer(tree: Parent, file: VFile) { modifiers.clear(); visitParents(tree, checkLinksandDefinitions, replaceLinkWithPreview); visitParents(tree, isStructureLinkReference, replaceLinkWithPreview); + const importNode = getJSXImport('APIStructurePreview'); if (modifiers.size) { - tree.children.unshift({ - type: 'mdxjsEsm', - value: - "import APIStructurePreview from '@site/src/components/APIStructurePreview'", - data: { - estree: { - type: 'Program', - body: [ - { - type: 'ImportDeclaration', - specifiers: [ - { - type: 'ImportDefaultSpecifier', - local: { - type: 'Identifier', - name: 'APIStructurePreview', - }, - }, - ], - source: { - type: 'Literal', - value: '@site/src/components/APIStructurePreview', - raw: "'@site/src/components/APIStructurePreview'", - }, - }, - ], - sourceType: 'module', - comments: [], - }, - }, - } as unknown as MdxJsxFlowElement); + tree.children.unshift(importNode); await Promise.all(Array.from(modifiers)); } } @@ -214,9 +186,10 @@ function replaceLinkWithPreview(node: Link | LinkReference) { // replace the raw link file with our JSX component. // See src/components/APIStructurePreview.jsx for implementation. if ( - Array.isArray(node.children) && - node.children.length > 0 && - isTextOrInlineCode(node.children[0]) + (Array.isArray(node.children) && + node.children.length > 0 && + isText(node.children[0])) || + isInlineCode(node.children[0]) ) { modifiers.add( promise @@ -257,19 +230,3 @@ function replaceLinkWithPreview(node: Link | LinkReference) { ); } } - -function isDefinition(node: Node): node is Definition { - return node.type === 'definition'; -} - -function isLink(node: Node): node is Link { - return node.type === 'link'; -} - -function isLinkReference(node: Node): node is LinkReference { - return node.type === 'linkReference'; -} - -function isTextOrInlineCode(node: Node): node is Text | InlineCode { - return node.type === 'text' || node.type === 'inlineCode'; -} diff --git a/src/transformers/fiddle-embedder.ts b/src/transformers/fiddle-embedder.ts index 5c7d3fb0f..2d8a6a6c4 100644 --- a/src/transformers/fiddle-embedder.ts +++ b/src/transformers/fiddle-embedder.ts @@ -1,12 +1,11 @@ import { Node, Parent } from 'unist'; import { Code } from 'mdast'; -import { MdxjsEsm } from 'mdast-util-mdxjs-esm'; import { MdxJsxFlowElement } from 'mdast-util-mdx-jsx'; - import { visitParents, ActionTuple, SKIP } from 'unist-util-visit-parents'; import path from 'path'; import fs from 'fs-extra'; import latestVersion from 'latest-version'; +import { getJSXImport, isCode, isImport } from '../util/mdx-utils'; let _version = ''; async function getVersion() { @@ -40,36 +39,7 @@ function matchFiddleBlock(node: Node): node is Code { ); } -const importNode = { - type: 'mdxjsEsm', - value: "import FiddleEmbed from '@site/src/components/FiddleEmbed'", - data: { - estree: { - type: 'Program', - body: [ - { - type: 'ImportDeclaration', - specifiers: [ - { - type: 'ImportDefaultSpecifier', - local: { - type: 'Identifier', - name: 'FiddleEmbed', - }, - }, - ], - source: { - type: 'Literal', - value: '@site/src/components/FiddleEmbed', - raw: "'@site/src/components/FiddleEmbed'", - }, - }, - ], - sourceType: 'module', - comments: [], - }, - }, -}; +const importNode = getJSXImport('FiddleEmbed'); async function transformer(tree: Parent) { let needImport = false; @@ -225,11 +195,3 @@ async function transformer(tree: Parent) { return children; } } - -function isImport(node: Node): node is MdxjsEsm { - return node.type === 'mdxjsEsm'; -} - -function isCode(node: Node): node is Code { - return node.type === 'code'; -} diff --git a/src/transformers/js-code-blocks.ts b/src/transformers/js-code-blocks.ts index 8240944f6..10c9f94bd 100644 --- a/src/transformers/js-code-blocks.ts +++ b/src/transformers/js-code-blocks.ts @@ -1,8 +1,8 @@ import { Node, Parent } from 'unist'; import { Code } from 'mdast'; -import { MdxjsEsm } from 'mdast-util-mdxjs-esm'; import { visitParents, ActionTuple, SKIP } from 'unist-util-visit-parents'; +import { getJSXImport, isCode, isImport } from '../util/mdx-utils'; const CJS_PREAMBLE = '// CommonJS\n'; const MJS_PREAMBLE = '// ESM\n'; @@ -20,44 +20,13 @@ function matchMjsCodeBlock(node: Node): node is Code { return isCode(node) && node.lang === 'mjs'; } -const importNode = { - type: 'mdxjsEsm', - value: "import JsCodeBlock from '@site/src/components/JsCodeBlock'", - data: { - estree: { - type: 'Program', - body: [ - { - type: 'ImportDeclaration', - specifiers: [ - { - type: 'ImportDefaultSpecifier', - local: { - type: 'Identifier', - name: 'JsCodeBlock', - }, - }, - ], - source: { - type: 'Literal', - value: '@site/src/components/JsCodeBlock', - raw: "'@site/src/components/JsCodeBlock'", - }, - }, - ], - sourceType: 'module', - comments: [], - }, - }, -}; - async function transformer(tree: Parent) { let needImport = false; visitParents(tree, matchCjsCodeBlock, maybeGenerateJsCodeBlock); visitParents(tree, 'mdxjsEsm', checkForJsCodeBlockImport); if (needImport) { - tree.children.unshift(importNode); + tree.children.unshift(getJSXImport('JsCodeBlock')); } function checkForJsCodeBlockImport(node: Node) { @@ -132,10 +101,3 @@ async function transformer(tree: Parent) { return [SKIP, idx + 1]; } } -function isImport(node: Node): node is MdxjsEsm { - return node.type === 'mdxjsEsm'; -} - -function isCode(node: Node): node is Code { - return node.type === 'code'; -} diff --git a/src/util/mdx-utils.ts b/src/util/mdx-utils.ts new file mode 100644 index 000000000..33046d1a0 --- /dev/null +++ b/src/util/mdx-utils.ts @@ -0,0 +1,97 @@ +import { + PhrasingContent, + Text, + Paragraph, + InlineCode, + LinkReference, + Link, + Definition, + Code, +} from 'mdast'; +import { MdxjsEsm } from 'mdast-util-mdxjs-esm'; +import { Node } from 'unist'; + +export function isCode(node: Node): node is Code { + return node.type === 'code'; +} + +export function isDefinition(node: Node): node is Definition { + return node.type === 'definition'; +} + +export function isImport(node: Node): node is MdxjsEsm { + return node.type === 'mdxjsEsm'; +} + +export function isInlineCode(node: Node): node is InlineCode { + return node.type === 'inlineCode'; +} + +export function isLink(node: Node): node is Link { + return node.type === 'link'; +} + +export function isLinkReference(node: Node): node is LinkReference { + return node.type === 'linkReference'; +} + +export function isOptions(node: Node): node is InlineCode { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return node.type === 'inlineCode' && (node as any).value === 'options'; +} + +export function isParagraph(node: Node): node is Paragraph { + return node.type === 'paragraph'; +} + +export function isText(node: PhrasingContent): node is Text { + return node.type === 'text'; +} + +/** + * Imports a component from `@site/src/components`. + * + * @example + * + * To import the default exported `JsCodeBlock` React component from + * `src/components/JsCodeBlock.tsx`, import the name of the component with no file extension: + * + * ```js + * getJSXIMport('JsCodeBlock') + * ``` + * + * @param componentName name of the TSX file + * @returns MDX AST + */ +export function getJSXImport(componentName: string): MdxjsEsm { + return { + type: 'mdxjsEsm', + value: `import ${componentName} from '@site/src/components/${componentName}'`, + data: { + estree: { + type: 'Program', + body: [ + { + type: 'ImportDeclaration', + specifiers: [ + { + type: 'ImportDefaultSpecifier', + local: { + type: 'Identifier', + name: componentName, + }, + }, + ], + source: { + type: 'Literal', + value: `@site/src/components/${componentName}`, + raw: `'@site/src/components/${componentName}'`, + }, + }, + ], + sourceType: 'module', + comments: [], + }, + }, + }; +}