docs: ts and js language switch (#1616)

* feat: add ts/js check

* feat: add ts/js checkout

* fix: update dependencies

* fix: markdown support ts

* feat: change to vue

* fix: update

* feat: compatiable vue and md of demo

Co-authored-by: yugang.cao <yugang.cao@tusimple.ai>
Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
Yugang Cao 2021-12-13 03:55:41 +08:00 committed by GitHub
parent 8d870e24b2
commit 99bc46685a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 349 additions and 145 deletions

View File

@ -1,12 +1,19 @@
module.exports = {
extends: ['plugin:markdown/recommended', 'prettier'],
overrides: [
{
files: '*.vue',
extends: [
'@vue/typescript/recommended',
'plugin:vue/vue3-recommended',
'@vue/typescript'
]
},
{
files: ['*.vue', '*.js'],
extends: [
'plugin:vue/essential',
'@vue/standard'
// '@vue/typescript/recommended'
],
rules: {
'vue/max-attributes-per-line': [
@ -54,6 +61,15 @@ module.exports = {
'no-undef': 0
}
},
{
files: ['**/*.md/*.ts'],
processor: 'markdown/markdown',
rules: {
'import/order': 0,
'prettier/prettier': 0,
'@typescript-eslint/consistent-type-definitions': 0
}
},
{
files: '*.spec.ts',
globals: {

View File

@ -4,6 +4,7 @@
relative-url="<!--URL-->"
title="<!--TITLE_SLOT-->"
code="<!--CODE_SLOT-->"
js-code="<!--JS_CODE_SLOT-->"
>
<template #title>
<!--TITLE_SLOT-->

View File

@ -2,6 +2,7 @@ const { marked } = require('marked')
const fs = require('fs')
const path = require('path')
const createRenderer = require('./md-renderer')
const tsToJs = require('../utils/tsToJs')
const mdRenderer = createRenderer()
const __HTTP__ = process.env.NODE_ENV !== 'production' ? 'http' : 'https'
@ -17,6 +18,7 @@ function getPartsOfDemo (tokens) {
let title = null
const contentTokens = []
contentTokens.links = tokens.links
let languageType = 'js'
for (const token of tokens) {
if (token.type === 'heading' && token.depth === 1) {
title = token.text
@ -27,8 +29,9 @@ function getPartsOfDemo (tokens) {
template = token.text
} else if (
token.type === 'code' &&
(token.lang === 'script' || token.lang === 'js')
(token.lang === 'script' || token.lang === 'js' || token.lang === 'ts')
) {
languageType = token.lang
script = token.text
} else if (
token.type === 'code' &&
@ -46,7 +49,8 @@ function getPartsOfDemo (tokens) {
title: title,
content: marked.parser(contentTokens, {
renderer: mdRenderer
})
}),
language: languageType
}
}
@ -57,25 +61,46 @@ function mergeParts (parts) {
mergedParts.title = parts.title
mergedParts.content = parts.content
mergedParts.code = ''
mergedParts.jsCode = ''
let jsCode = ''
if (parts.template) {
mergedParts.code += `<template>\n${parts.template
.split('\n')
.map((line) => (line.length ? ' ' + line : line))
.join('\n')}\n</template>`
mergedParts.jsCode = mergedParts.code
}
if (parts.script) {
if (parts.template) mergedParts.code += '\n\n'
mergedParts.code += `<script>
if (parts.template) {
mergedParts.code += '\n\n'
mergedParts.jsCode += '\n\n'
}
const startScriptTag = parts.language === 'ts' ? '<script lang="ts">' : '<script>'
mergedParts.code += `${startScriptTag}
${parts.script}
</script>`
if (parts.language === 'ts') {
jsCode = tsToJs(parts.script)
mergedParts.jsCode += `<script>
${jsCode}
</script>`
} else {
mergedParts.jsCode = mergedParts.code
}
}
if (parts.style) {
if (parts.template || parts.script) mergedParts.code += '\n\n'
mergedParts.code += `<style>
if (parts.template || parts.script) {
mergedParts.code += '\n\n'
mergedParts.jsCode += '\n\n'
}
const style = `<style>
${parts.style}
</style>`
mergedParts.code += style
mergedParts.jsCode += style
}
mergedParts.code = encodeURIComponent(mergedParts.code)
mergedParts.jsCode = encodeURIComponent(mergedParts.jsCode)
return mergedParts
}
@ -112,6 +137,7 @@ function genVueComponent (parts, fileName, relativeUrl, noRunning = false) {
const titleReg = /<!--TITLE_SLOT-->/g
const contentReg = /<!--CONTENT_SLOT-->/
const codeReg = /<!--CODE_SLOT-->/
const jsCodeReg = /<!--JS_CODE_SLOT-->/
const scriptReg = /<!--SCRIPT_SLOT-->/
const styleReg = /<!--STYLE_SLOT-->/
const demoReg = /<!--DEMO_SLOT-->/
@ -127,8 +153,12 @@ function genVueComponent (parts, fileName, relativeUrl, noRunning = false) {
if (parts.code) {
src = src.replace(codeReg, parts.code)
}
if (parts.jsCode) {
src = src.replace(jsCodeReg, parts.jsCode)
}
if (parts.script && !noRunning) {
src = src.replace(scriptReg, '<script>\n' + parts.script + '\n</script>')
const startScriptTag = parts.language === 'ts' ? '<script lang="ts">\n' : '<script>\n'
src = src.replace(scriptReg, startScriptTag + parts.script + '\n</script>')
}
if (parts.style) {
const style = genStyle(parts.style)
@ -166,4 +196,9 @@ function convertMd2Demo (text, { resourcePath, relativeUrl }) {
return vueComponent
}
module.exports = convertMd2Demo
module.exports = {
getFileName,
genVueComponent,
mergeParts,
convertMd2Demo
}

View File

@ -25,7 +25,12 @@ async function resolveDemoInfos (literal, url, env) {
if (env === 'production' && debug) {
continue
}
const fileName = `${id}.demo.md`
let fileName
if (id.includes('.vue')) {
fileName = id.slice(0, -4) + '.demo.vue'
} else {
fileName = `${id}.demo.md`
}
const variable = `${camelCase(id)}Demo`
infos.push({
id,

View File

@ -0,0 +1,52 @@
const { marked } = require('marked')
const createRenderer = require('./md-renderer')
const mdRenderer = createRenderer()
const { genVueComponent, getFileName, mergeParts } = require('./convert-md-to-demo')
function getPartsOfDemo (text) {
const template = text.match(/<template>([\s\S]+?)<\/template>/)[1].trim()
const script = text.match(/<script.*?>([\s\S]+?)<\/script>/)?.[1]?.trim()
const style = text.match(/<style>([\s\S]*?)<\/style>/)?.[1]?.trim()
let title = null
const markdownText = text.match(/<markdown>([\s\S]*?)<\/markdown>/)?.[1]?.trim()
const tokens = marked.lexer(markdownText)
const contentTokens = []
contentTokens.links = tokens.links
for (const token of tokens) {
if (token.type === 'heading' && token.depth === 1) {
title = token.text
} else {
contentTokens.push(token)
}
}
const languageArr = text.match(/<script .*?lang="(.+?)"/)
let languageType
if (!languageArr || !languageArr.length) languageType = 'js'
else languageType = languageArr[1]
return {
template,
script,
style,
title,
content: marked.parser(contentTokens, {
renderer: mdRenderer
}),
language: languageType
}
}
function convertVue2Demo (content, { resourcePath, relativeUrl }) {
const noRunning = /<!--no-running-->/.test(content)
const parts = getPartsOfDemo(content)
const mergedParts = mergeParts(parts)
const [fileName] = getFileName(resourcePath)
const vueComponent = genVueComponent(
mergedParts,
fileName,
relativeUrl,
noRunning
)
return vueComponent
}
module.exports = convertVue2Demo

View File

@ -1,8 +1,15 @@
const convertMd2Demo = require('./convert-md-to-demo')
const { convertMd2Demo } = require('./convert-md-to-demo')
const convertVue2Demo = require('./convert-vue-to-demo')
const projectPath = require('./project-path')
module.exports = function (content, path) {
module.exports = function (content, path, type) {
const relativeUrl = path.replace(projectPath + '/', '')
if (type === 'vue') {
return convertVue2Demo(content, {
relativeUrl,
resourcePath: path
})
}
return convertMd2Demo(content, {
relativeUrl,
resourcePath: path

View File

@ -4,9 +4,10 @@ const demoLoader = require('../loaders/naive-ui-demo-loader')
const docLoader = require('../loaders/naive-ui-doc-loader')
module.exports = async function getTransformedVueSrc (path) {
if (path.endsWith('.demo.md')) {
if (path.endsWith('.demo.md') || path.endsWith('.demo.vue')) {
const code = await fs.readFile(path, 'utf-8')
return demoLoader(code, path)
const type = path.endsWith('.demo.vue') ? 'vue' : 'md'
return demoLoader(code, path, type)
} else if (path.endsWith('.md')) {
const code = await fs.readFile(path, 'utf-8')
return docLoader(code, path)

18
build/utils/tsToJs.js Normal file
View File

@ -0,0 +1,18 @@
const { transformSync } = require('esbuild')
const tsToJs = (content) => {
if (!content) {
return ''
}
// esbuild will remove blank line
const beforeTransformContent = content.replace(/\n(\n)*( )*(\n)*\n/g, '\n__blankline\n')
const { code } = transformSync(beforeTransformContent, {
loader: 'ts',
minify: false,
minifyWhitespace: false,
charset: 'utf8'
})
return code.trim().replace(/__blankline;/g, '')
}
module.exports = tsToJs

View File

@ -3,7 +3,7 @@ const getTransformedVueSrc = require('./utils/get-demo-by-path')
const createCssrPlugin = require('./vite-plugin-css-render')
const siteIndexTransFormPlugin = require('./vite-plugin-index-tranform')
const fileRegex = /\.(md|entry)$/
const fileRegex = /\.(md|entry|vue)$/
const vuePlugin = createVuePlugin({
include: [/\.vue$/, /\.md$/, /\.entry$/]

View File

@ -19,7 +19,7 @@
<edit-in-code-sandbox-button
style="padding: 0; margin-right: 6px"
size="tiny"
:code="sfcCode"
:code="showLanguage === 'TS' ? sfcTsCode : sfcJsCode"
/>
</template>
{{ t('editInCodeSandbox') }}
@ -41,12 +41,26 @@
depth="3"
style="padding: 0; margin-right: 6px"
size="tiny"
:code="sfcCode"
:code="showLanguage === 'TS' ? sfcTsCode : sfcJsCode"
:success-text="t('copySuccess')"
/>
</template>
{{ t('copyCode') }}
</n-tooltip>
<n-tooltip v-if="sfcCodeIsTsType">
<template #trigger>
<n-button
style="padding: 0; margin-right: 6px"
size="tiny"
text
depth="3"
@click="toggleLanguageChange"
>
{{showLanguage}}
</n-button>
</template>
{{ t(showLanguage) }}
</n-tooltip>
<n-tooltip ref="expandCodeButtonRef">
<template #trigger>
<n-button
@ -70,7 +84,8 @@
<slot name="demo" />
<template v-if="showCode" #footer>
<n-scrollbar x-scrollable content-style="padding: 20px 24px;">
<n-code language="html" :code="sfcCode" />
<n-code v-if='showLanguage === "TS"' language="html" :code="sfcTsCode" />
<n-code v-else language="html" :code="sfcJsCode" />
</n-scrollbar>
</template>
</n-card>
@ -108,6 +123,10 @@ export default {
relativeUrl: {
type: String,
required: true
},
jsCode: {
type: String,
required: false
}
},
setup (props) {
@ -117,23 +136,31 @@ export default {
return !(isDebugDemo && displayModeRef.value !== 'debug')
})
const showCodeRef = ref(false)
const showLanguageRef = ref('JS')
const expandCodeButtonRef = ref(null)
watch(showCodeRef, () => {
nextTick(() => {
expandCodeButtonRef.value.syncPosition()
})
})
const sfcCodeIsTsType = decodeURIComponent(props.code).includes('<script lang="ts">')
return {
expandCodeButtonRef,
showDemo: showDemoRef,
showCode: showCodeRef,
sfcCode: decodeURIComponent(props.code),
showLanguage: showLanguageRef,
sfcTsCode: decodeURIComponent(props.code),
sfcJsCode: decodeURIComponent(props.jsCode),
sfcCodeIsTsType,
toggleCodeDisplay () {
showCodeRef.value = !showCodeRef.value
},
handleTitleClick: () => {
window.location.hash = `#${props.demoFileName}`
},
toggleLanguageChange () {
showLanguageRef.value = showLanguageRef.value === 'JS' ? 'TS' : 'JS'
},
...i18n({
'zh-CN': {
show: '显示代码',
@ -141,7 +168,9 @@ export default {
editOnGithub: '在 GitHub 中编辑',
editInCodeSandbox: '在 CodeSandbox 中编辑',
copyCode: '复制代码',
copySuccess: '复制成功'
copySuccess: '复制成功',
JS: '切换到 TypeScript',
TS: '切换到 JavaScript'
},
'en-US': {
show: 'Show Code',
@ -149,7 +178,9 @@ export default {
editOnGithub: 'Edit on GitHub',
editInCodeSandbox: 'Edit in CodeSandbox',
copyCode: 'Copy Code',
copySuccess: 'Successfully Copied'
copySuccess: 'Successfully Copied',
JS: 'Switch to TypeScript',
TS: 'Switch to JavaScript'
}
})
}

View File

@ -62,6 +62,7 @@
]
},
"devDependencies": {
"esbuild": "^0.13.14",
"@babel/eslint-parser": "^7.15.8",
"@babel/generator": "^7.12.11",
"@babel/parser": "^7.12.11",

View File

@ -1,17 +0,0 @@
# Embedded effect
In light mode, sometimes you may need to make background a bit darker to distinguish card from white background.
```html
<n-card title="🎸 Rock N' Roll Star" embedded :bordered="false"
>Tonight I'm a rock 'n' roll star
<br />
Tonight I'm a rock 'n' roll star</n-card
>
```
```css
.n-card {
max-width: 300px;
}
```

View File

@ -0,0 +1,23 @@
<markdown>
# Embedded effect
In light mode, sometimes you may need to make background a bit darker to distinguish card from white background.
</markdown>
<template>
<n-card
title="🎸 Rock N' Roll Star"
embedded
:bordered="false"
>
Tonight I'm a rock 'n' roll star
<br>
Tonight I'm a rock 'n' roll star
</n-card>
</template>
<style>
.n-card {
max-width: 300px;
}
</style>

View File

@ -16,7 +16,7 @@ closable
no-title
loading
custom-style
embedded
embedded.vue
```
## Card

View File

@ -0,0 +1,22 @@
<markdown>
# 嵌入效果
在亮色模式下有的时候你希望背景色暗一点来和纯色背景分割
</markdown>
<template>
<n-card
title="📖 如何成功"
embedded
:bordered="false"
>
如果你年轻的时候不 996你什么时候可以 996你一辈子没有
996你觉得你就很骄傲了这个世界上我们每一个人都希望成功都希望美好生活都希望被尊重我请问大家你不付出超越别人的努力和时间你怎么能够实现你想要的成功
</n-card>
</template>
<style>
.n-card {
max-width: 300px;
}
</style>

View File

@ -16,7 +16,7 @@ closable
no-title
loading
custom-style
embedded
embedded.vue
rtl-debug
```

View File

@ -1,43 +0,0 @@
# Basic
For example, javascript, python and cpp.
```html
<div style="overflow: auto;">
<n-space vertical :size="16">
<n-code
:code="`
function sleep (ms = 1000) {
return new Promise(resolve => setTimeout(resolve, ms))
}
`"
language="javascript"
/>
<n-code
:code="`
def say_hello():
print('Hello Naive UI')
`"
language="python"
/>
<n-code :code="cppCode" language="cpp" />
</n-space>
</div>
```
```js
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return {
cppCode: `int main () {
std::cout << "Hello Naive UI";
return 0;
}`
}
}
})
```

View File

@ -0,0 +1,44 @@
<markdown>
# Basic
For example, javascript, python and cpp.
</markdown>
<template>
<div style="overflow: auto;">
<n-space vertical :size="16">
<n-code
:code="`
function sleep (ms = 1000) {
return new Promise(resolve => setTimeout(resolve, ms))
}
`"
language="javascript"
/>
<n-code
:code="`
def say_hello():
print('Hello Naive UI')
`"
language="python"
/>
<n-code :code="cppCode" language="cpp" />
</n-space>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return {
cppCode: `int main () {
std::cout << "Hello Naive UI";
return 0;
}`
}
}
})
</script>

View File

@ -35,7 +35,7 @@ The following code shows how to set hljs of Code. Importing highlight.js on dema
## Demos
```demo
basic
basic.vue
inline
```

View File

@ -1,42 +0,0 @@
# 基础用法
Javascript、Python、Cpp 的例子。
```html
<div style="overflow: auto;">
<n-space vertical :size="16">
<n-code
:code="`
function sleep (ms = 1000) {
return new Promise(resolve => setTimeout(resolve, ms))
}
`"
language="javascript"
/>
<n-code
:code="`
def say_hello():
print('Hello Naive UI')
`"
language="python"
/>
<n-code :code="cppCode" language="cpp" />
</n-space>
</div>
```
```js
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return {
cppCode: `int main () {
std::cout << "Hello Naive UI";
return 0;
}`
}
}
})
```

View File

@ -0,0 +1,44 @@
<markdown>
# 基础用法
JavascriptPythonCpp 的例子
</markdown>
<template>
<div style="overflow: auto;">
<n-space vertical :size="16">
<n-code
:code="`
function sleep (ms = 1000) {
return new Promise(resolve => setTimeout(resolve, ms))
}
`"
language="javascript"
/>
<n-code
:code="`
def say_hello():
print('Hello Naive UI')
`"
language="python"
/>
<n-code :code="cppCode" language="cpp" />
</n-space>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return {
cppCode: `int main () {
std::cout << "Hello Naive UI";
return 0;
}`
}
}
})
</script>

View File

@ -35,7 +35,7 @@
## 演示
```demo
basic
basic.vue
inline
```

View File

@ -122,7 +122,7 @@ striped
#### DataTableCreateSummary Type
```__ts
```ts
type DataTableCreateSummary = (
pageData: RowData[]
) =>
@ -144,7 +144,7 @@ type DataTableCreateSummary = (
#### SortState Type
```__ts
```ts
type SortState = {
columnKey: string | number,
sorter: 'default' | function | boolean,

View File

@ -125,7 +125,7 @@ height-debug
#### DataTableCreateSummary Type
```__ts
```ts
type DataTableCreateSummary = (
pageData: RowData[]
) =>
@ -147,7 +147,7 @@ type DataTableCreateSummary = (
#### SortState Type
```__ts
```ts
type SortState = {
columnKey: string | number,
sorter: 'default' | function | boolean,

View File

@ -52,7 +52,7 @@ page-size-option
### PaginationInfo Type
```__ts
```ts
interface PaginationInfo {
startIndex: number
endIndex: number

View File

@ -52,7 +52,7 @@ page-size-option
### PaginationInfo Type
```__ts
```ts
interface PaginationInfo {
startIndex: number
endIndex: number

View File

@ -6,19 +6,19 @@ Use the `render-option` property to control rendering of the entire option.
<n-select :options="options" :render-option="renderOption" />
```
```js
import { defineComponent, h } from 'vue'
import { NTooltip } from 'naive-ui'
```ts
import { defineComponent, h, VNode, ref } from 'vue'
import { NTooltip, SelectOption } from 'naive-ui'
export default defineComponent({
setup () {
return {
renderOption: ({ node, option }) =>
renderOption: ({ node, option }: { node: VNode, option: SelectOption }) =>
h(NTooltip, null, {
trigger: () => node,
default: () => 'Rubber Soul -' + option.label
}),
options: [
options: ref<SelectOption[]>([
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
@ -74,7 +74,7 @@ export default defineComponent({
label: 'Wait',
value: 'song12'
}
]
])
}
}
})

View File

@ -6,19 +6,19 @@
<n-select :options="options" :render-option="renderOption" />
```
```js
import { defineComponent, h } from 'vue'
import { NTooltip } from 'naive-ui'
```ts
import { defineComponent, h, VNode, ref } from 'vue'
import { NTooltip, SelectOption } from 'naive-ui'
export default defineComponent({
setup () {
return {
renderOption: ({ node, option }) =>
renderOption: ({ node, option }: { node: VNode, option: SelectOption }) =>
h(NTooltip, null, {
trigger: () => node,
default: () => 'Rubber Soul -' + option.label
}),
options: [
options: ref<SelectOption[]>([
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
@ -74,7 +74,7 @@ export default defineComponent({
label: 'Wait',
value: 'song12'
}
]
])
}
}
})

6
src/shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
// shims-vue.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}