Skip to content

Commit

Permalink
feat: site api and add plugin-api-doc(remain to improve)
Browse files Browse the repository at this point in the history
  • Loading branch information
GuYith committed Oct 24, 2023
1 parent abadc78 commit 51677e9
Show file tree
Hide file tree
Showing 9 changed files with 458 additions and 17 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"author": "tdesign",
"license": "MIT",
"dependencies": {
"@babel/plugin-proposal-decorators": "^7.23.2",
"@babel/plugin-syntax-jsx": "^7.22.5",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.23.0",
Expand Down Expand Up @@ -150,7 +151,7 @@
"omi-twind": "^0.0.4",
"prismjs": "^1.24.0",
"sortablejs": "^1.15.0",
"tdesign-icons-omi": "^0.0.10",
"tdesign-icons-omi": "^0.0.12",
"tinycolor2": "^1.6.0",
"twind": "^0.16.16",
"validator": "^13.9.0"
Expand Down
39 changes: 39 additions & 0 deletions site/plugin-api-doc/demo.js
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 ''
},
})
}
25 changes: 25 additions & 0 deletions site/plugin-api-doc/index.js
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)
},
},
})
87 changes: 87 additions & 0 deletions site/plugin-api-doc/md-to-omi.js
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
}
64 changes: 64 additions & 0 deletions site/plugin-api-doc/transforms.js
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
},
}
Loading

4 comments on commit 51677e9

@GuYith
Copy link
Collaborator Author

@GuYith GuYith commented on 51677e9 Oct 24, 2023

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
image

mdToOmi
image

目前plugin-api-doc可以跑通,并生成需要的HTML代码,但是如何将这一部分引入omi组件内部,还没有解决

site\src\components\web\button\index.tsx

注释的两个部分,是分别引用md的两种尝试,但是都没有实现预期的效果
image

问题:

如何正确实现类似tdesign-react中对react代码的解析,可以对omi正确解析且导入文件?

当前实现

因为上述问题没有解决,目前只尝试实现了button的api页面,手动将插件生成的HTML代码封装为组件site\src\components\web\button\button_md.tsx,目前的实现效果与tdesign-react一致:
image

@dntzhang
Copy link
Contributor

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

看下这个项目。同事说可以录入到这里自动生成

@dntzhang
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

点击 “生成文件” 按钮,指定生成组件和技术栈框架平台,确认后会在本地 packages/products/ 对应仓库目录下生成对应 md 文档、API 定义等文件。

@GuYith
Copy link
Collaborator Author

@GuYith GuYith commented on 51677e9 Oct 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嗯嗯,我看了这个项目,这个项目可以生成md文件、api文件,但和上面的问题没什么关系,我的问题是用plugin把md转成组件代码过程遇到的

Please sign in to comment.