-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: site api and add plugin-api-doc(remain to improve)
- Loading branch information
Showing
9 changed files
with
458 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* eslint-disable */ | ||
import path from 'path' | ||
|
||
export default function renderDemo(md, container) { | ||
console.log('renderDemo') | ||
md.use(container, 'demo', { | ||
validate(params) { | ||
return params.trim().match(/^demo\s+([\\/.\w-]+)(\s+(.+?))?(\s+--dev)?$/) | ||
}, | ||
render(tokens, idx) { | ||
if (tokens[idx].nesting === 1) { | ||
const match = tokens[idx].info.trim().match(/^demo\s+([\\/.\w-]+)(\s+(.+?))?(\s+--dev)?$/) | ||
const [, demoPath, componentName = ''] = match | ||
const demoPathOnlyLetters = demoPath.replace(/[^a-zA-Z\d]/g, '') | ||
const demoName = path.basename(demoPath) | ||
const demoDefName = `Demo${demoPathOnlyLetters}` | ||
const demoCodeDefName = `Demo${demoPathOnlyLetters}Code` | ||
const tpl = ` | ||
<td-doc-demo component-name="${componentName.trim()}" :code=${demoCodeDefName} demo-name="${demoName}" language="markup"> | ||
<div slot="action"> | ||
<Stackblitz demo-name="${demoName}" component-name="${componentName}" :code=${demoCodeDefName} /> | ||
</div> | ||
<div class="tdesign-demo-item__body"> | ||
<${demoDefName} /> | ||
</div> | ||
</td-doc-demo> | ||
` | ||
|
||
tokens.tttpl = tpl | ||
|
||
return `<div class="tdesign-demo-wrapper tdesign-demo-item--${componentName.trim()}-${demoName} tdesign-demo-item--${componentName.trim()}">` | ||
} | ||
if (tokens.tttpl) { | ||
return `${tokens.tttpl || ''}</div>` | ||
} | ||
return '' | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import vitePluginTdoc from 'vite-plugin-tdoc' | ||
import renderDemo from './demo' | ||
import transforms from './transforms' | ||
|
||
export default () => | ||
vitePluginTdoc({ | ||
transforms, // 解析markdown 数据 | ||
markdown: { | ||
anchor: { | ||
tabIndex: false, | ||
config: (anchor) => ({ | ||
permalink: anchor.permalink.linkInsideHeader({ symbol: '' }), | ||
}), | ||
}, | ||
toc: { | ||
listClass: 'tdesign-toc_list', | ||
itemClass: 'tdesign-toc_list_item', | ||
linkClass: 'tdesign-toc_list_item_a', | ||
containerClass: 'tdesign-toc_container', | ||
}, | ||
container(md, container) { | ||
renderDemo(md, container) | ||
}, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* eslint-disable */ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import matter from 'gray-matter' | ||
import { getGitTimestamp } from '../../src/_common/docs/compile' | ||
import { transformSync } from '@babel/core' | ||
|
||
const DEFAULT_TABS = [ | ||
{ tab: 'demo', name: '示例' }, | ||
{ tab: 'api', name: 'API' }, | ||
{ tab: 'design', name: '指南' }, | ||
] | ||
|
||
const DEFAULT_EN_TABS = [ | ||
{ tab: 'demo', name: 'DEMO' }, | ||
{ tab: 'api', name: 'API' }, | ||
{ tab: 'design', name: 'Guideline' }, | ||
] | ||
|
||
export default async function mdToOmi(options) { | ||
const mdSegment = await customRender(options) | ||
|
||
const omiSource = ` | ||
import { h, tag, WeElement } from 'omi' | ||
export default class ButtonMd extends WeElement { | ||
render() { | ||
return <div style={isShow('api')} name="API" dangerouslySetInnerHTML={{ __html: ${JSON.stringify( | ||
mdSegment.apiMd, | ||
)} }}></div> | ||
} | ||
} | ||
` | ||
|
||
const result = transformSync(omiSource, { | ||
babelrc: false, | ||
configFile: false, | ||
sourceMaps: true, | ||
generatorOpts: { | ||
decoratorsBeforeExport: true, | ||
}, | ||
plugins: [[require('@babel/plugin-transform-react-jsx'), { isTSX: true }]], | ||
}) | ||
|
||
return { code: result.code, map: result.map } | ||
} | ||
|
||
// 解析 markdown 内容 | ||
async function customRender({ source, file, md }) { | ||
const { content, data } = matter(source) | ||
const lastUpdated = (await getGitTimestamp(file)) || Math.round(fs.statSync(file).mtimeMs) | ||
// console.log('data', data); | ||
const isEn = file.endsWith('en-US.md') | ||
|
||
// md top data | ||
const pageData = { | ||
spline: '', | ||
toc: true, | ||
title: '', | ||
description: '', | ||
isComponent: false, | ||
tdDocHeader: true, | ||
tdDocTabs: !isEn ? DEFAULT_TABS : DEFAULT_EN_TABS, | ||
apiFlag: /#+\s*API/, | ||
docClass: '', | ||
lastUpdated, | ||
designDocLastUpdated: lastUpdated, | ||
...data, | ||
} | ||
|
||
// md filename | ||
const reg = file.match(/([\w-]+)\.?([\w-]+)?\.md/) | ||
const componentName = reg && reg[1] | ||
|
||
// split md | ||
let [demoMd = '', apiMd = ''] = content.split(pageData.apiFlag) | ||
|
||
const mdSegment = { | ||
...pageData, | ||
componentName, | ||
apiMd: '<td-doc-empty></td-doc-empty>', | ||
} | ||
|
||
mdSegment.apiMd = md.render.call(md, `${pageData.toc ? '[toc]\n' : ''}${apiMd.replace(/<!--[\s\S]+?-->/g, '')}`).html | ||
|
||
return mdSegment | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import path from 'path' | ||
import fs from 'fs' | ||
|
||
import mdToOmi from './md-to-omi' | ||
|
||
let demoImports = {} | ||
let demoCodesImports = {} | ||
|
||
export default { | ||
before({ source, file }) { | ||
const resourceDir = path.dirname(file) | ||
const reg = file.match(/([\w-]+)\.?([\w-]+)?\.md/) | ||
const fileName = reg && reg[0] | ||
const componentName = reg && reg[1] | ||
const localeName = reg && reg[2] | ||
|
||
// 统一换成 common 公共文档内容 | ||
if (fileName && source.includes(':: BASE_DOC ::')) { | ||
const localeDocPath = path.resolve(__dirname, `../../src/_common/docs/web/api/${fileName}`) | ||
const defaultDocPath = path.resolve( | ||
__dirname, | ||
`../../src/_common/docs/web/api/${localeName ? `${componentName}.${localeName}` : componentName}.md`, | ||
) | ||
let baseDoc = '' | ||
|
||
if (fs.existsSync(localeDocPath)) { | ||
// 优先载入语言版本 | ||
baseDoc = fs.readFileSync(localeDocPath, 'utf-8') | ||
} else if (fs.existsSync(defaultDocPath)) { | ||
// 回退中文默认版本 | ||
baseDoc = fs.readFileSync(defaultDocPath, 'utf-8') | ||
} else { | ||
console.error(`未找到 ${defaultDocPath} 文件`) | ||
} | ||
source = source.replace(':: BASE_DOC ::', baseDoc) | ||
} | ||
|
||
return source | ||
}, | ||
render({ source, file, md }) { | ||
// console.log('source: ', source, ' file: ', file, ' md: ', md) | ||
const demoDefsStr = Object.keys(demoImports) | ||
.map((key) => demoImports[key]) | ||
.join(';\n') | ||
const demoCodesDefsStr = Object.keys(demoCodesImports) | ||
.map((key) => demoCodesImports[key]) | ||
.join(';\n') | ||
|
||
const demoInstallStr = Object.keys(demoImports).join(',') | ||
const demoCodeInstallStr = Object.keys(demoCodesImports).join(',') | ||
|
||
const sfc = mdToOmi({ | ||
md, | ||
file, | ||
source, | ||
demoDefsStr, | ||
demoCodesDefsStr, | ||
demoInstallStr, | ||
demoCodeInstallStr, | ||
}) | ||
|
||
return sfc | ||
}, | ||
} |
Oops, something went wrong.
51677e9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dntzhang 导师有时间的话,还请帮忙看看目前遇到的问题
思路
主要参考tdesign-react的plugin-doc,尝试实现plugin-api-doc,用于api文档代码的自动生成(逻辑:引入md文件, 插件会对md文件进行解析生成jsx)
(备注:tdesign-react、tdesign-vue的组件展示页面都是自动生成的,计划在plugin-api-doc跑通之后,完善实现omi版本的plugin-doc,可以统一组件展示页面,把现在site\src\components\web目录下的文件都去掉)
mdToReact
mdToOmi
目前plugin-api-doc可以跑通,并生成需要的HTML代码,但是如何将这一部分引入omi组件内部,还没有解决
site\src\components\web\button\index.tsx
注释的两个部分,是分别引用md的两种尝试,但是都没有实现预期的效果
问题:
如何正确实现类似tdesign-react中对react代码的解析,可以对omi正确解析且导入文件?
当前实现
因为上述问题没有解决,目前只尝试实现了button的api页面,手动将插件生成的HTML代码封装为组件site\src\components\web\button\button_md.tsx,目前的实现效果与tdesign-react一致:
51677e9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/Tdesignoteam/tdesign-api
看下这个项目。同事说可以录入到这里自动生成
51677e9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
点击 “生成文件” 按钮,指定生成组件和技术栈框架平台,确认后会在本地 packages/products/ 对应仓库目录下生成对应 md 文档、API 定义等文件。
51677e9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
嗯嗯,我看了这个项目,这个项目可以生成md文件、api文件,但和上面的问题没什么关系,我的问题是用plugin把md转成组件代码过程遇到的