From 6d3c7d2212cc6fde0b360388a4a0e57ca4cde00d Mon Sep 17 00:00:00 2001 From: Fuma Nama Date: Thu, 19 Dec 2024 18:36:30 +0800 Subject: [PATCH] Docgen: Use `oxc` for `ts2js` remark plugins --- .changeset/tiny-pans-greet.md | 5 + packages/doc-gen/package.json | 2 +- packages/doc-gen/src/remark-ts2js.ts | 183 ++++++++++++++------------- pnpm-lock.yaml | 89 +++++++++++-- 4 files changed, 183 insertions(+), 96 deletions(-) create mode 100644 .changeset/tiny-pans-greet.md diff --git a/.changeset/tiny-pans-greet.md b/.changeset/tiny-pans-greet.md new file mode 100644 index 000000000..965f3d652 --- /dev/null +++ b/.changeset/tiny-pans-greet.md @@ -0,0 +1,5 @@ +--- +'fumadocs-docgen': patch +--- + +Use `oxc` for `ts2js` remark plugins diff --git a/packages/doc-gen/package.json b/packages/doc-gen/package.json index 8d24e7db5..818c011cd 100644 --- a/packages/doc-gen/package.json +++ b/packages/doc-gen/package.json @@ -27,11 +27,11 @@ "types:check": "tsc --noEmit" }, "dependencies": { - "@swc/wasm-typescript": "^1.10.1", "estree-util-value-to-estree": "^3.2.1", "fumadocs-typescript": "workspace:^", "hast-util-to-estree": "^3.1.0", "npm-to-yarn": "^3.0.0", + "oxc-transform": "^0.42.0", "ts-morph": "^24.0.0", "unist-util-visit": "^5.0.0", "zod": "^3.24.1" diff --git a/packages/doc-gen/src/remark-ts2js.ts b/packages/doc-gen/src/remark-ts2js.ts index 71371769b..0f3769407 100644 --- a/packages/doc-gen/src/remark-ts2js.ts +++ b/packages/doc-gen/src/remark-ts2js.ts @@ -1,11 +1,10 @@ import { Transformer } from 'unified'; import { type Code, Root } from 'mdast'; import { visit } from 'unist-util-visit'; -import { transform, Options as SWCOptions } from '@swc/wasm-typescript'; import { createElement, expressionToAttribute } from '@/utils'; +import oxc from 'oxc-transform'; export interface TypeScriptToJavaScriptOptions { - swc?: SWCOptions; /** * Persist Tab value (Fumadocs UI only) * @@ -16,105 +15,115 @@ export interface TypeScriptToJavaScriptOptions { id: string; } | false; + + /** + * Transform all TypeScript codeblocks by default, without a trigger + */ + disableTrigger?: boolean; } -export function remarkTs2js({ - swc = {}, +/** + * A remark plugin to transform TypeScript codeblocks into two tabs of codeblocks with its JS variant. + * + * Add `ts2js` to enable transformation: + * ````md + * ```tsx ts2js + * import { ReactNode } from "react"; + * + * export default function Layout({ children }: { children: ReactNode }) { + * return
{children}
+ * } + * ``` + * ```` + */ +export function remarkTypeScriptToJavaScript({ persist = false, + disableTrigger = false, }: TypeScriptToJavaScriptOptions = {}): Transformer { - return async (tree, file) => { - const queue: Promise[] = []; - + return (tree, file) => { visit(tree, 'code', (node) => { if (node.lang !== 'ts' && node.lang !== 'tsx') return; - const task = transform(node.value, { - filename: `${file.path}.${node.lang}`, - transform: { - importExportAssignConfig: 'Preserve', - verbatimModuleSyntax: true, + if (!disableTrigger && !node.meta?.includes('ts2js')) return; + + const result = oxc.transform( + `${file.path ?? 'test'}.${node.lang}`, + node.value, + { + sourcemap: false, + jsx: 'preserve', }, - sourceMap: false, - ...swc, - }) - .then((output) => { - const insert = createElement( - 'Tabs', - [ - ...(typeof persist === 'object' - ? [ - { - type: 'mdxJsxAttribute', - name: 'groupId', - value: persist.id, - }, - { - type: 'mdxJsxAttribute', - name: 'persist', - value: null, - }, - ] - : []), - expressionToAttribute('items', { - type: 'ArrayExpression', - elements: ['TypeScript', 'JavaScript'].map((name) => ({ - type: 'Literal', - value: name, - })), - }), - ], - [ + ); + + const insert = createElement( + 'Tabs', + [ + ...(typeof persist === 'object' + ? [ + { + type: 'mdxJsxAttribute', + name: 'groupId', + value: persist.id, + }, + { + type: 'mdxJsxAttribute', + name: 'persist', + value: null, + }, + ] + : []), + expressionToAttribute('items', { + type: 'ArrayExpression', + elements: ['TypeScript', 'JavaScript'].map((name) => ({ + type: 'Literal', + value: name, + })), + }), + ], + [ + { + type: 'mdxJsxFlowElement', + name: 'Tab', + attributes: [ { - type: 'mdxJsxFlowElement', - name: 'Tab', - attributes: [ - { - type: 'mdxJsxAttribute', - name: 'value', - value: 'TypeScript', - }, - ], - children: [ - { - type: 'code', - lang: node.lang, - meta: node.meta, - value: node.value, - } satisfies Code, - ], + type: 'mdxJsxAttribute', + name: 'value', + value: 'TypeScript', }, + ], + children: [ + { + type: 'code', + lang: node.lang, + meta: node.meta, + value: node.value, + } satisfies Code, + ], + }, + { + type: 'mdxJsxFlowElement', + name: 'Tab', + attributes: [ { - type: 'mdxJsxFlowElement', - name: 'Tab', - attributes: [ - { - type: 'mdxJsxAttribute', - name: 'value', - value: 'JavaScript', - }, - ], - children: [ - { - type: 'code', - lang: 'jsx', - meta: node.meta, - value: output.code, - } satisfies Code, - ], + type: 'mdxJsxAttribute', + name: 'value', + value: 'JavaScript', }, ], - ); - - Object.assign(node, insert); - }) - .catch((e) => { - // ignore node - console.error(e); - }); + children: [ + { + type: 'code', + lang: 'jsx', + meta: node.meta, + value: result.code, + } satisfies Code, + ], + }, + ], + ); - queue.push(task); + Object.assign(node, insert); + return 'skip'; }); - - await Promise.all(queue); }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 780452a2f..dfa63a294 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -695,9 +695,6 @@ importers: packages/doc-gen: dependencies: - '@swc/wasm-typescript': - specifier: ^1.10.1 - version: 1.10.1 estree-util-value-to-estree: specifier: ^3.2.1 version: 3.2.1 @@ -710,6 +707,9 @@ importers: npm-to-yarn: specifier: ^3.0.0 version: 3.0.0 + oxc-transform: + specifier: ^0.42.0 + version: 0.42.0 ts-morph: specifier: ^24.0.0 version: 24.0.0 @@ -2156,6 +2156,46 @@ packages: '@oramacloud/client@2.1.4': resolution: {integrity: sha512-uNPFs4wq/iOPbggCwTkVNbIr64Vfd7ZS/h+cricXVnzXWocjDTfJ3wLL4lr0qiSu41g8z+eCAGBqJ30RO2O4AA==} + '@oxc-transform/binding-darwin-arm64@0.42.0': + resolution: {integrity: sha512-/csANDgbNfpMHUEDuPYV1ZErvkDHck60tHBA8pXt3IUUDRruv1neLY0PVmxKVoTMpXhJBATVBalwQug1CSbKRg==} + cpu: [arm64] + os: [darwin] + + '@oxc-transform/binding-darwin-x64@0.42.0': + resolution: {integrity: sha512-P5Vdi3mp8ArYSYlDTHh45jiR14haP5+ayoKp3PGB3BQpgaXFIZ9Yrhy0Ew57He1khxbozE869TP3Db4XDDJH4A==} + cpu: [x64] + os: [darwin] + + '@oxc-transform/binding-linux-arm64-gnu@0.42.0': + resolution: {integrity: sha512-K2dUqks8Fl+NCVkubo2htgbRaRoEuaDVrGypK5IyajY2OTJeKFd13HMc2lc1L7vp7Cd7CcbPMupUvhJOVeGQrA==} + cpu: [arm64] + os: [linux] + + '@oxc-transform/binding-linux-arm64-musl@0.42.0': + resolution: {integrity: sha512-jMsuaUex0dBSS9fMjxP9r4MHV7LvjJVGPaMKY5Q0d9spId3AssWypbgEG0nh757maryd6fmCrP2Zz77xX9cumQ==} + cpu: [arm64] + os: [linux] + + '@oxc-transform/binding-linux-x64-gnu@0.42.0': + resolution: {integrity: sha512-RayahTPcfU8TIdTuTNrgACGc3yYGHeXYHHz0UO5DTBg3egbm+Hk5SOdrcU6KUD1vxaYnWDiK5mJKh0tQxqKcqA==} + cpu: [x64] + os: [linux] + + '@oxc-transform/binding-linux-x64-musl@0.42.0': + resolution: {integrity: sha512-N87yYj55kbwyTclwy5XdPrNSOTjT2zFz+0GpVUx16eQ6C/z5lnUY18fbHiU6b23GLlJhG5PJdXzNCBqeY0FKaQ==} + cpu: [x64] + os: [linux] + + '@oxc-transform/binding-win32-arm64-msvc@0.42.0': + resolution: {integrity: sha512-whVOuuk3C0alAwkV6HroQoPttopJ6NkOun9xwUL6ETQhHyiCodnKQJWP3SwGepHI2cLW0F5fTfxNBFa8xCYXaQ==} + cpu: [arm64] + os: [win32] + + '@oxc-transform/binding-win32-x64-msvc@0.42.0': + resolution: {integrity: sha512-0Gup7nOJMCLhUCpukSWHR2PKZ5oF4CebDMKIF6qhxfTHXLkQcV78z89B6Ek05QwHuLK84NWFRCgZIe0q5xEiBg==} + cpu: [x64] + os: [win32] + '@parcel/watcher-android-arm64@2.5.0': resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} engines: {node: '>= 10.0.0'} @@ -2950,9 +2990,6 @@ packages: '@swc/types@0.1.17': resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} - '@swc/wasm-typescript@1.10.1': - resolution: {integrity: sha512-k77Ltrgp4L1APToioEchu/bcZVE2Cdg3cTRkqQa14C5sllhmKEcJyElrjuxj/RbMGjLHSjA2rZuwFnPs+3eWBg==} - '@theguild/remark-mermaid@0.2.0': resolution: {integrity: sha512-o8n57TJy0OI4PCrNw8z6S+vpHtrwoQZzTA5Y3fL0U1NDRIoMg/78duWgEBFsCZcWM1G6zjE91yg1aKCsDwgE2Q==} peerDependencies: @@ -5281,6 +5318,9 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + oxc-transform@0.42.0: + resolution: {integrity: sha512-vkgXdj1YdVnb27FpaE8jvKKhTp+jcnMLtAzS1qo6EaTOwoF0upSS9sC/z7TvtjMn0tAvTr2Y4rB4sbUFpYGkSA==} + p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} @@ -7462,6 +7502,30 @@ snapshots: '@orama/orama': 3.0.2 lodash: 4.17.21 + '@oxc-transform/binding-darwin-arm64@0.42.0': + optional: true + + '@oxc-transform/binding-darwin-x64@0.42.0': + optional: true + + '@oxc-transform/binding-linux-arm64-gnu@0.42.0': + optional: true + + '@oxc-transform/binding-linux-arm64-musl@0.42.0': + optional: true + + '@oxc-transform/binding-linux-x64-gnu@0.42.0': + optional: true + + '@oxc-transform/binding-linux-x64-musl@0.42.0': + optional: true + + '@oxc-transform/binding-win32-arm64-msvc@0.42.0': + optional: true + + '@oxc-transform/binding-win32-x64-msvc@0.42.0': + optional: true + '@parcel/watcher-android-arm64@2.5.0': optional: true @@ -8188,8 +8252,6 @@ snapshots: dependencies: '@swc/counter': 0.1.3 - '@swc/wasm-typescript@1.10.1': {} - '@theguild/remark-mermaid@0.2.0(react@19.0.0)': dependencies: mermaid: 11.4.1 @@ -11196,6 +11258,17 @@ snapshots: outdent@0.5.0: {} + oxc-transform@0.42.0: + optionalDependencies: + '@oxc-transform/binding-darwin-arm64': 0.42.0 + '@oxc-transform/binding-darwin-x64': 0.42.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.42.0 + '@oxc-transform/binding-linux-arm64-musl': 0.42.0 + '@oxc-transform/binding-linux-x64-gnu': 0.42.0 + '@oxc-transform/binding-linux-x64-musl': 0.42.0 + '@oxc-transform/binding-win32-arm64-msvc': 0.42.0 + '@oxc-transform/binding-win32-x64-msvc': 0.42.0 + p-filter@2.1.0: dependencies: p-map: 2.1.0