diff --git a/core/README-zh.md b/core/README-zh.md index 1e1d3d7..491cc3b 100644 --- a/core/README-zh.md +++ b/core/README-zh.md @@ -84,7 +84,7 @@ export default (conf: Configuration, env: 'development' | 'production', options: ```ts import { PluginItem } from '@babel/core'; -import { Options as RIOptions } from 'babel-plugin-transform-remove-imports' +import { Options as RemoveImportsOptions } from 'babel-plugin-transform-remove-imports' export type Options = { /** * 需要解析代码块的语言,默认: `["jsx","tsx"]` @@ -95,7 +95,7 @@ export type Options = { * babel (babel-plugin-transform-remove-imports) 包的 option 设置 * https://github.com/uiwjs/babel-plugin-transform-remove-imports */ - removeImports?: RIOptions; + removeImports?: RemoveImportsOptions; /** * 添加 babel 插件。 */ @@ -110,30 +110,54 @@ export type Options = { ```jsx import mdObj from 'markdown-react-code-preview-loader/README.md'; -mdObj.source // => `README.md` 原始字符串文本 -mdObj.components // => 组件索引对象,从 markdown 索引到的示例转换成的 React 组件。(需要配置 meta) -mdObj.codeBlock // => 组件源码索引对象,从 markdown 索引到的示例源码。(需要配置 meta) +mdObj.source // => `README.md` 原始字符串文本 +mdObj.components // => 组件索引对象,从 markdown 索引到的示例转换成的 React 组件。(可能需要配置 meta) +mdObj.data // => 组件源码索引对象,从 markdown 索引到的示例源码。(可能需要配置 meta) ``` ```js { - codeBlock: { - 17: 'import React from ...', - 77: 'import React from ...', - demo12: 'import React from ...' + data: { + 17: { + code: "\"use strict\";\n\nfunction ......" + language: "jsx" + name: 17, + value: "impo....." + }, + 77: { + code: "\"use strict\";\n\nfunction ......" + language: "jsx" + name: 17, + value: "impo....." + }, + demo12: { + code: "\"use strict\";\n\nfunction ......" + language: "jsx" + name: 17, + value: "impo....." + } }, components: { 17: ƒ, 77: ƒ, demo12: ƒ }, - languages: { 17: 'jsx', 77: 'jsx', demo12: 'jsx'}, source: "# Alert 确认对话框...." } ``` ```ts +export type CodeBlockItem = { + /** 源码转换后的代码。 **/ + code?: string; + /** 原始代码块 **/ + value?: string; + /** 代码块编程语言 **/ + language?: string; + /** 索引名称可以自定义,可以是行号。 */ + name?: string | number; +}; + export type CodeBlockData = { source: string; - components: Record; - codeBlock: Record; - languages: Record; + components: Record; + data: Record; }; ``` @@ -156,9 +180,11 @@ getMetaId('mdx:preview') // => '' getMetaId('mdx:preview:demo12') // => 'demo12' ``` -## getCodeBlockString +## getCodeBlock -传递 `markdown` 文件内容字符串,返回转换好的需要预览的代码块解析数据。 +```ts +const getCodeBlock: (child: MarkdownParseData['children'], opts?: Options) => CodeBlockData['data']; +``` ## 配置 meta 标识 diff --git a/core/README.md b/core/README.md index 7d89282..f2adc84 100644 --- a/core/README.md +++ b/core/README.md @@ -84,7 +84,7 @@ export default (conf: Configuration, env: 'development' | 'production', options: ```ts import { PluginItem } from '@babel/core'; -import { Options as RIOptions } from 'babel-plugin-transform-remove-imports' +import { Options as RemoveImportsOptions } from 'babel-plugin-transform-remove-imports' export type Options = { /** * Language to parse code blocks, default: `["jsx","tsx"]` @@ -94,7 +94,7 @@ export type Options = { * Option settings for the babel (babel-plugin-transform-remove-imports) package * https://github.com/uiwjs/babel-plugin-transform-remove-imports */ - removeImports?: RIOptions; + removeImports?: RemoveImportsOptions; /** * Add babel plugins. */ @@ -109,30 +109,54 @@ After adding `loader`, use the method to load `markdown` text in the project pro ```jsx import mdObj from 'markdown-react-code-preview-loader/README.md'; -mdObj.source // => `README.md` raw string text -mdObj.components // => The component index object, the React component converted from the markdown indexed example. (need to configure meta) -mdObj.codeBlock // => The component source code index object, the sample source code indexed from markdown. (need to configure meta) +mdObj.source // => `README.md` raw string text +mdObj.components // => The component index object, the React component converted from the markdown indexed example. (need to configure meta) +mdObj.data // => The component source code index object, the sample source code indexed from markdown. (need to configure meta) ``` ```js { - codeBlock: { - 17: 'import React from ...', - 77: 'import React from ...', - demo12: 'import React from ...' + data: { + 17: { + code: "\"use strict\";\n\nfunction ......" + language: "jsx" + name: 17, + value: "impo....." + }, + 77: { + code: "\"use strict\";\n\nfunction ......" + language: "jsx" + name: 17, + value: "impo....." + }, + demo12: { + code: "\"use strict\";\n\nfunction ......" + language: "jsx" + name: 17, + value: "impo....." + } }, components: { 17: ƒ, 77: ƒ, demo12: ƒ }, - languages: { 17: 'jsx', 77: 'jsx', demo12: 'jsx'}, source: "# Alert 确认对话框...." } ``` ```ts +export type CodeBlockItem = { + /** The code after the source code conversion. **/ + code?: string; + /** original code block **/ + value?: string; + /** code block programming language **/ + language?: string; + /** The index name, which can be customized, can be a row number. */ + name?: string | number; +}; + export type CodeBlockData = { source: string; - components: Record; - codeBlock: Record; - languages: Record; + components: Record; + data: Record; }; ``` @@ -155,9 +179,11 @@ getMetaId('mdx:preview') // => '' getMetaId('mdx:preview:demo12') // => 'demo12' ``` -## getCodeBlockString +## getCodeBlock -Pass the `markdown` file content string, and return the converted code block parsing data that needs to be previewed. +```ts +const getCodeBlock: (child: MarkdownParseData['children'], opts?: Options) => CodeBlockData['data']; +``` ## Configure meta ID diff --git a/core/src/index.ts b/core/src/index.ts index cf2f449..45b088a 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -1,16 +1,28 @@ import React from 'react'; import { PluginItem } from '@babel/core'; import { Options as RIOptions } from 'babel-plugin-transform-remove-imports'; -import { getCodeBlockString } from './utils'; +import { getProcessor, getCodeBlock } from './utils'; export * from './utils'; +export type CodeBlockItem = { + /** The code after the source code conversion. **/ + code?: string; + /** original code block **/ + value?: string; + /** code block programming language **/ + language?: string; + /** The index name, which can be customized, can be a row number. */ + name?: string | number; +}; + export type CodeBlockData = { source: string; - components: Record; - codeBlock: Record; - languages: Record; + components: Record; + data: Record; }; +export const FUNNAME_PREFIX = '__BaseCode__'; + export type Options = { /** * Language to parse code blocks, default: `["jsx","tsx"]` @@ -29,15 +41,16 @@ export type Options = { export default function (source: string) { const options: Options = this.getOptions(); - const result = getCodeBlockString(source, options); - return ` - ${result} - export default { - source:${JSON.stringify(source)}, - components, - codeBlock, - languages - } -`; + const codeBlock = getCodeBlock(getProcessor(source), options); + let components = ''; + Object.keys(codeBlock).forEach((key) => { + components += `${key}: (function() { ${codeBlock[key].code} })(),`; + }); + + return `\nexport default { + components: { ${components} }, + data: ${JSON.stringify(codeBlock, null, 2)}, + source: ${JSON.stringify(source)} + }`; } diff --git a/core/src/utils/index.ts b/core/src/utils/index.ts index ed9fa30..cae33c4 100644 --- a/core/src/utils/index.ts +++ b/core/src/utils/index.ts @@ -1,17 +1,21 @@ -/* - * @Description: markdown 转化 - */ -import { MarkDownTreeType, CodeBlockItemType } from './interface'; +import { Parent, Node } from 'unist'; import { getTransformValue } from './transform'; import webpack from 'webpack'; import remark from 'remark'; -export * from './interface'; -import { Options } from '../'; +import { Options, FUNNAME_PREFIX, CodeBlockItem, CodeBlockData } from '../'; + +export interface MarkdownDataChild extends Node { + lang: string; + meta: string; + value: string; +} + +export interface MarkdownParseData extends Parent {} /** 转换 代码*/ -const getProcessor = (scope: string) => { +export const getProcessor = (source: string) => { try { - const child = remark.parse(scope) as MarkDownTreeType; + const child = remark.parse(source) as MarkdownParseData; return child.children; } catch (err) { console.warn(err); @@ -43,22 +47,22 @@ export const getMetaId = (meta: string = '') => { export const isMeta = (meta: string = '') => meta && meta.includes('mdx:preview'); /** 获取需要渲染的代码块 **/ -const getCodeBlock = (child: MarkDownTreeType['children'], opts: Options = {}) => { +export const getCodeBlock = (child: MarkdownParseData['children'], opts: Options = {}): CodeBlockData['data'] => { const { lang = ['jsx', 'tsx'] } = opts; // 获取渲染部分 - const codeBlock: Record = {}; + const codeBlock: Record = {}; try { child.forEach((item) => { if (item && item.type === 'code' && lang.includes(item.lang)) { const line = item.position.start.line; const metaId = getMetaId(item.meta); if (isMeta(item.meta)) { - let name = typeof metaId === 'string' ? metaId : line; - const funName = `BaseCode${line}`; - const returnCode = getTransformValue(item.value, `${funName}.${lang}`, funName, opts); - codeBlock[line] = { - code: returnCode, + let name = metaId || line; + const funName = `${FUNNAME_PREFIX}${name}`; + const returnCode = getTransformValue(item.value, `${funName}.${lang}`, opts); + codeBlock[name] = { name, + code: returnCode, language: item.lang, value: item.value, }; @@ -71,35 +75,6 @@ const getCodeBlock = (child: MarkDownTreeType['children'], opts: Options = {}) = return codeBlock; }; -const createStr = (codeBlock: Record) => { - let baseCodeStr = ``; - let baseCodeObjStr = ``; - let codeBlockValue = ``; - let languageStr = ``; - - try { - Object.entries(codeBlock).forEach(([key, item]) => { - const { code, value, language, name } = item; - baseCodeStr += `${code};\n`; - baseCodeObjStr += `${name}:BaseCode${key},\n`; - codeBlockValue += `${name}:${JSON.stringify(value)},\n`; - languageStr += `${name}:\`${language}\`,\n`; - }); - } catch (err) { - console.warn(err); - } - - let indexStr = `${baseCodeStr} const languages={${languageStr}};\n const codeBlock={${codeBlockValue}};\n const components={${baseCodeObjStr}}`; - return indexStr; -}; - -export const getCodeBlockString = (scope: string, opts: Options = {}) => { - const children = getProcessor(scope); - const codeBlock = getCodeBlock(children, opts); - const result = createStr(codeBlock); - return result; -}; - /** * `mdCodeModulesLoader` method for adding `markdown-react-code-preview-loader` to webpack config. * @param {webpack.Configuration} config webpack config diff --git a/core/src/utils/interface.ts b/core/src/utils/interface.ts deleted file mode 100644 index b9d6341..0000000 --- a/core/src/utils/interface.ts +++ /dev/null @@ -1,34 +0,0 @@ -export type StartAndEndType = { - column: number; - offset: number; - line: number; -}; - -export type PositionType = { - start: StartAndEndType; - end: StartAndEndType; -}; - -export type MarkDownTreeType = { - children: { - lang: string; - meta?: any; - type: string; - value: string; - position: PositionType; - children?: MarkDownTreeType['children']; - }[]; - position: PositionType; - type: string; -}; - -export type CodeBlockItemType = { - /** 移出import引用,拼接用于渲染部分的代码 **/ - code?: string; - /** 原始代码块 **/ - value?: string; - /** 语言 **/ - language?: string; - /** 取值名称 */ - name?: string | number | boolean; -}; diff --git a/core/src/utils/transform.ts b/core/src/utils/transform.ts index 317b4c8..83c818f 100644 --- a/core/src/utils/transform.ts +++ b/core/src/utils/transform.ts @@ -1,30 +1,39 @@ import { transform } from '@babel/standalone'; -import { PluginItem } from '@babel/core'; +import { PluginItem, PluginObj } from '@babel/core'; import removeImports from 'babel-plugin-transform-remove-imports'; import { Options } from '../'; -export function babelTransform(input: string, filename: string, opts: Options = {}) { - const plugins: PluginItem[] = [...(opts.babelPlugins || [])]; - if (opts.removeImports) { - plugins.push([removeImports, opts.removeImports]); - } - return transform(input, { - filename, - presets: ['env', 'es2015', 'react', 'typescript'], - plugins: [...plugins], - }); +export function defaultExportReplace(): PluginObj { + return { + name: 'transform-replace-export-default-to-return', + visitor: { + ExportDefaultDeclaration(path, opts) { + const declaration = path.node.declaration; + if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') { + declaration.id.name = `return ${declaration.id.name}`; + } else if (declaration.type === 'Identifier') { + declaration.name = `return ${declaration.name}`; + } + if (declaration) { + path.replaceWith(declaration); + } + }, + }, + }; } -export const getTransformValue = (str: string, filename: string, funName: string, opts: Options) => { +export const getTransformValue = (str: string, filename: string, opts: Options) => { try { - const isReact = /import\x20+React(\x20+|[\x20+,]+({[a-zA-Z0-9,\s]+}|{})\x20+)from\x20+('|")react('|")/.test(str); - // 先判断 是否引入 react - const tran = isReact ? str : `import React from "react"\n ${str}`; - /** 先把默认导出 export default 进行替换 **/ - const newCode = `${tran.replace(/export\x20+default/, 'const _default = ')}\n`; - const tranCode = babelTransform(newCode, `${filename}`, opts).code; - const code = `${tranCode}\n return _react["default"].createElement(_default)`; - return `function ${funName}(){\n${code}\n};`; + const plugins: PluginItem[] = [...(opts.babelPlugins || [])]; + if (opts.removeImports) { + plugins.push([removeImports, opts.removeImports]); + } + const result = transform(str, { + filename, + presets: ['env', 'es2015', 'react', 'typescript'], + plugins: [...plugins, defaultExportReplace], + }); + return result.code; } catch (err) { console.warn(err); } diff --git a/website/src/components/useMdData/index.ts b/website/src/components/useMdData/index.ts index 655470f..926a37c 100644 --- a/website/src/components/useMdData/index.ts +++ b/website/src/components/useMdData/index.ts @@ -7,8 +7,7 @@ const useMdData = (path: (lang: string) => Promise<{ default: CodeBlockData }>, const [mdData, setMdData] = useState({ source: '', components: {}, - codeBlock: {}, - languages: {}, + data: {}, }); const lang = init.t(name); @@ -18,6 +17,7 @@ const useMdData = (path: (lang: string) => Promise<{ default: CodeBlockData }>, const getMd = async () => { try { const result = await path(lang); + console.log('result:', result.default); if (result.default) { setMdData(result.default); } diff --git a/website/src/pages/example/index.tsx b/website/src/pages/example/index.tsx index e0aab64..1fd1d16 100644 --- a/website/src/pages/example/index.tsx +++ b/website/src/pages/example/index.tsx @@ -1,8 +1,8 @@ import MarkdownPreview from '@uiw/react-markdown-preview'; -import { getMetaId } from 'markdown-react-code-preview-loader'; +import { getMetaId, isMeta } from 'markdown-react-code-preview-loader'; +import { Loader } from 'uiw'; import PreView from '../../components/CodeLayout'; import useMdData from './../../components/useMdData'; -import { Loader } from 'uiw'; import styles from './../index.module.less'; export function ExamplePage() { @@ -12,18 +12,19 @@ export function ExamplePage() {
{ const { 'data-meta': meta, ...rest } = props as any; - if (inline) { + if (inline || !isMeta(meta)) { return ; } const line = node.position?.start.line; - const metaId = getMetaId(meta) || line; - const Child = mdData.components[metaId || '']; + const metaId = getMetaId(meta) || String(line); + const Child = mdData.components[`${metaId}`]; if (metaId && typeof Child === 'function') { - const copyNodes = mdData.codeBlock[metaId] || ''; + const copyNodes = mdData.data[metaId].value || ''; return ( } copyNodes={copyNodes}>