├── .eslintignore ├── packages ├── create-vlib │ ├── template-vue-ts │ │ ├── .eslintignore │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── __docs__ │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── index.en-US.md │ │ │ │ └── demo.vue │ │ │ └── button.vue │ │ ├── .gitignore │ │ ├── .prettierrc.js │ │ ├── docs │ │ │ ├── .vitepress │ │ │ │ ├── sidebar.js │ │ │ │ ├── theme │ │ │ │ │ ├── index.ts │ │ │ │ │ └── var.css │ │ │ │ └── config.js │ │ │ └── public │ │ │ │ └── logo.svg │ │ ├── vite.config.ts │ │ ├── .eslintrc.cjs │ │ ├── tsconfig.json │ │ └── package.json │ ├── template-ts │ │ ├── docs │ │ │ ├── .vitepress │ │ │ │ ├── shim.ts │ │ │ │ ├── theme │ │ │ │ │ ├── Layout.vue │ │ │ │ │ ├── index.ts │ │ │ │ │ └── var.css │ │ │ │ └── config.js │ │ │ ├── index.md │ │ │ └── public │ │ │ │ └── logo.svg │ │ ├── .gitignore │ │ ├── src │ │ │ └── index.ts │ │ ├── .prettierrc.cjs │ │ ├── README.md │ │ ├── build.config.js │ │ ├── .eslintrc.cjs │ │ ├── tsconfig.json │ │ └── package.json │ ├── bin │ │ └── create-vlib.js │ ├── build.config.js │ ├── src │ │ ├── constants.ts │ │ ├── tsconfig.json │ │ ├── create-dir │ │ │ └── index.ts │ │ ├── generator │ │ │ └── index.ts │ │ ├── index.ts │ │ └── prompt │ │ │ └── index.ts │ ├── readme.md │ ├── CHANGELOG.md │ └── package.json ├── doc-site │ ├── src │ │ ├── index.ts │ │ ├── button.vue │ │ └── __docs__ │ │ │ ├── index.en-US.md │ │ │ ├── index.zh-CN.md │ │ │ └── demo.vue │ ├── docs │ │ ├── guide │ │ │ ├── getting-started.zh-CN.md │ │ │ ├── getting-started.en-US.md │ │ │ ├── index.zh-CN.md │ │ │ └── index.en-US.md │ │ ├── features │ │ │ ├── demo.en-US.md │ │ │ ├── api-demo.ts │ │ │ ├── mapping.en-US.md │ │ │ ├── mapping.zh-CN.md │ │ │ ├── demo.zh-CN.md │ │ │ ├── api-ts.en-US.md │ │ │ ├── api-ts.zh-CN.md │ │ │ ├── api.en-US.md │ │ │ └── api.zh-CN.md │ │ ├── .postcssrc.cjs │ │ ├── demo.vue │ │ ├── .vitepress │ │ │ ├── theme │ │ │ │ ├── index.ts │ │ │ │ └── var.css │ │ │ ├── sidebar.js │ │ │ └── config.js │ │ ├── index.zh-CN.md │ │ ├── index.en-US.md │ │ └── public │ │ │ └── logo.svg │ ├── tsconfig.json │ ├── package.json │ └── CHANGELOG.md ├── vite-plugin-gen-api-doc │ ├── src │ │ ├── constants.ts │ │ ├── templates │ │ │ ├── index.ts │ │ │ ├── slots.ts │ │ │ ├── events.ts │ │ │ ├── methods.ts │ │ │ └── props.ts │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── parse-interface.ts │ │ │ └── parse-material.ts │ │ ├── plugin-api.ts │ │ ├── getApiTmpl.ts │ │ └── index.ts │ ├── build.config.js │ ├── README.md │ ├── package.json │ └── CHANGELOG.md ├── vitepress-demo-block │ ├── src │ │ ├── index.ts │ │ ├── useTheme.ts │ │ ├── useCopyCode.ts │ │ ├── Icons │ │ │ ├── copy.vue │ │ │ └── code.vue │ │ ├── demo.less │ │ ├── SfcPlayground.vue │ │ └── Demo.vue │ ├── tsconfig.json │ ├── shim.ts │ ├── vite.config.ts │ ├── package.json │ ├── README.md │ └── CHANGELOG.md ├── utils │ ├── src │ │ ├── index.ts │ │ ├── parseProps.ts │ │ └── resolveLocaleConfigs.ts │ ├── build.config.js │ ├── package.json │ └── CHANGELOG.md ├── md-demo-plugins │ ├── src │ │ ├── constants.ts │ │ ├── types.ts │ │ ├── index.ts │ │ ├── plugin-fence.ts │ │ ├── plugin-demo-block.ts │ │ └── utils.ts │ ├── build.config.js │ ├── package.json │ ├── README.md │ └── CHANGELOG.md └── vite-plugin-gen-temp │ ├── bin │ └── initial-scan.js │ ├── src │ ├── types.ts │ ├── utils.ts │ ├── constants.ts │ ├── copyDocs.ts │ ├── copySrcMd.ts │ ├── index.ts │ └── handleCopy.ts │ ├── build.config.js │ ├── README.md │ ├── package.json │ ├── scripts │ └── patchCJS.ts │ └── CHANGELOG.md ├── .vscode └── settings.json ├── .gitignore ├── test.js ├── pnpm-workspace.yaml ├── .prettierrc.js ├── .changeset ├── config.json └── README.md ├── turbo.json ├── tsconfig.json ├── .eslintrc.cjs ├── package.json └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /packages/doc-site/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './button.vue'; 2 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const ApiTag = 'api'; 2 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/.vitepress/shim.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue'; 2 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Demo.vue'; 2 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './button.vue'; 2 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | dist 3 | node_modules 4 | .temp 5 | .docs 6 | .turbo 7 | ruabick-project -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const { extname } = require('path'); 2 | 3 | console.log(extname('doc/a.zh-cn.md')); 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - '!packages/create-vlib/template-vue-ts' 4 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parseProps'; 2 | export * from './resolveLocaleConfigs'; 3 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | dist 3 | node_modules 4 | .temp 5 | .docs 6 | .turbo -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | dist 3 | node_modules 4 | .temp 5 | .docs 6 | .turbo -------------------------------------------------------------------------------- /packages/md-demo-plugins/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const FenceDemoTag = 'vue:demo'; 2 | export const DemoTag = 'demo'; 3 | -------------------------------------------------------------------------------- /packages/create-vlib/bin/create-vlib.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { cli } = require('../dist/index.cjs'); 3 | 4 | cli(); 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | singleQuote: true, 4 | tabWidth: 2, 5 | trailingComma: 'all', 6 | printWidth: 80, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/doc-site/docs/guide/getting-started.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | 3 | ### 新建项目 4 | 5 | `pnpm create @ruabick/vlib` 6 | 7 | ### 现有项目 8 | 9 | TODO 10 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface DemoInfos { 2 | title?: string; 3 | desc?: string; 4 | path: string; 5 | code: string; 6 | } 7 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/bin/initial-scan.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { initialScan } = require('../dist/index.cjs'); 4 | 5 | initialScan(); 6 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Example function 3 | */ 4 | export function add(a: number, b: number) { 5 | return a + b; 6 | } 7 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/shim.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { ComponentOptions } from 'vue'; 3 | const comp: ComponentOptions; 4 | export default comp; 5 | } 6 | -------------------------------------------------------------------------------- /packages/doc-site/docs/guide/getting-started.en-US.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ### New project 4 | 5 | `pnpm create @ruabick/vlib` 6 | 7 | ### Existing project 8 | 9 | TODO 10 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | singleQuote: true, 4 | tabWidth: 2, 5 | trailingComma: 'all', 6 | printWidth: 80, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Options { 2 | srcDir?: string; 3 | tempDir?: string; 4 | docsDir?: string; 5 | initial?: boolean; 6 | lang?: string; 7 | } 8 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | singleQuote: true, 4 | tabWidth: 2, 5 | trailingComma: 'all', 6 | printWidth: 80, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/README.md: -------------------------------------------------------------------------------- 1 | # @{projectName} 2 | 3 | @{description} 4 | 5 | ### Install 6 | ``` 7 | pnpm install @{projectName} 8 | ``` 9 | 10 | ### Usage 11 | 12 | ... -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/index.md: -------------------------------------------------------------------------------- 1 | # @{projectName} 2 | 3 | @{description} 4 | 5 | ### Install 6 | 7 | ``` 8 | pnpm install @{projectName} 9 | ``` 10 | 11 | ### Usage 12 | 13 | ... 14 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/demo.en-US.md: -------------------------------------------------------------------------------- 1 | # 在`.md`文件里展示 demo 2 | 3 | ```html 4 | 5 | ``` 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/doc-site/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "my-button": [ 6 | "src/index.ts" 7 | ] 8 | }, 9 | } 10 | } -------------------------------------------------------------------------------- /packages/utils/build.config.js: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index'], 5 | clean: true, 6 | declaration: true, 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/create-vlib/build.config.js: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index'], 5 | clean: true, 6 | declaration: true, 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/build.config.js: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index'], 5 | clean: true, 6 | declaration: true, 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/build.config.js: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index'], 5 | clean: true, 6 | declaration: true, 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/.vitepress/theme/Layout.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/build.config.js: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index'], 5 | clean: true, 6 | declaration: true, 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/build.config.js: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index'], 5 | clean: true, 6 | declaration: true, 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/src/__docs__/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | map: 3 | path: / 4 | --- 5 | 6 | ## 按钮 7 | 8 | 渲染效果如下 9 | 10 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/src/index.ts: -------------------------------------------------------------------------------- 1 | import { demoBlockPlugin } from './plugin-demo-block'; 2 | import { fencePlugin } from './plugin-fence'; 3 | 4 | export function applyPlugins(md: any) { 5 | md.use(fencePlugin); 6 | md.use(demoBlockPlugin); 7 | } 8 | 9 | export * from './constants'; 10 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/templates/index.ts: -------------------------------------------------------------------------------- 1 | import props from './props'; 2 | import events from './events'; 3 | import methods from './methods'; 4 | import slots from './slots'; 5 | 6 | export default { 7 | props, 8 | events, 9 | methods, 10 | slots, 11 | }; 12 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/src/__docs__/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | map: 3 | path: / 4 | --- 5 | 6 | ## Button 7 | This is a button component! 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/utils.ts: -------------------------------------------------------------------------------- 1 | import fsExtra from 'fs-extra'; 2 | import { green } from 'colorette'; 3 | 4 | export const LOG_PREFIX = '[ruabick:gen-temp]'; 5 | 6 | export const removeFile = (file: string) => { 7 | fsExtra.remove(file); 8 | console.log(`${LOG_PREFIX} ${green('remove')} ${file}`); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/api-demo.ts: -------------------------------------------------------------------------------- 1 | export interface DemoProps { 2 | /** 3 | * 源码字符串(需经过encodeURIComponent处理) 4 | */ 5 | code: string; 6 | /** 7 | * 标题 8 | */ 9 | title?: string; 10 | /** 11 | * 描述 12 | */ 13 | desc?: string; 14 | /** 15 | * 语言 16 | */ 17 | lang?: string; 18 | } 19 | -------------------------------------------------------------------------------- /packages/doc-site/src/button.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.1.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "master", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /packages/doc-site/src/__docs__/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | map: 3 | path: /demo 4 | --- 5 | 6 | 渲染效果如下 7 | 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/doc-site/src/__docs__/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | map: 3 | path: /demo 4 | --- 5 | 6 | 渲染效果如下 7 | 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/src/button.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/useTheme.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | const query = window.matchMedia('(prefers-color-scheme: dark)'); 4 | 5 | const isDark = ref(query.matches); 6 | 7 | query.onchange = () => { 8 | isDark.value = query.matches; 9 | }; 10 | 11 | export function useTheme() { 12 | return { 13 | isDark, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { Options } from './types'; 2 | 3 | export const TempDir = '.docs'; 4 | export const DocsDir = 'docs'; 5 | export const SrcDir = 'src'; 6 | 7 | export const DefaultOptions: Required = { 8 | srcDir: SrcDir, 9 | tempDir: TempDir, 10 | docsDir: DocsDir, 11 | initial: false, 12 | lang: 'zh-CN', 13 | }; 14 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/docs/.vitepress/sidebar.js: -------------------------------------------------------------------------------- 1 | export const sidebar = { 2 | '/en/': [ 3 | { 4 | text: 'Guide', 5 | items: [ 6 | { text: 'Button', link: '/en/' }, 7 | ], 8 | }, 9 | ], 10 | '/': [ 11 | { 12 | text: '介绍', 13 | items: [ 14 | { text: '按钮', link: '/' }, 15 | ], 16 | }, 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | "pipeline": { 4 | "dev": { 5 | "dependsOn": ["^build"], 6 | "cache": false 7 | }, 8 | "build": { 9 | "dependsOn": ["^build"], 10 | "outputs": ["dist/**"] 11 | }, 12 | "site:build": { 13 | "dependsOn": ["^build"], 14 | "outputs": ["dist/**"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/create-vlib/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const CLI_NAME = 'create-vlib'; 2 | export const TEMPLATE_NAME = './temp'; 3 | 4 | export function pkgFromUserAgent(userAgent?: string) { 5 | if (!userAgent) return undefined; 6 | const pkgSpec = userAgent.split(' ')[0]; 7 | const pkgSpecArr = pkgSpec.split('/'); 8 | return { 9 | name: pkgSpecArr[0], 10 | version: pkgSpecArr[1], 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /packages/doc-site/docs/.postcssrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'postcss-prefix-selector': { 4 | prefix: ':not(:where(.vp-raw *))', 5 | includeFiles: [/vp-doc\.css/], 6 | transform(prefix, _selector) { 7 | const [selector, pseudo = ''] = _selector.split(/(:\S*)$/); 8 | return selector + prefix + pseudo; 9 | }, 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/mapping.en-US.md: -------------------------------------------------------------------------------- 1 | ## 文件映射 2 | 3 | 使用 `ruabick` 一个常见的目录如下: 4 | 5 | ```md 6 | docs 7 | ├── index.en-US.md // ruabick 会自动处理`.[lang].md`后缀的文件 8 | ├── index.zh-CN.md 9 | src 10 | ├── loading 11 | │ ├── demo 12 | │ │ └── demo.vue 13 | │ ├── index.en-US.md // 通过 `frontmatter` 设置的`map.path`映射到 docs 目录下 14 | │ ├── index.zh-CN.md 15 | │ └── loading.vue 16 | └── ... 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/mapping.zh-CN.md: -------------------------------------------------------------------------------- 1 | ## 文件映射 2 | 3 | 使用 `ruabick` 一个常见的目录如下: 4 | 5 | ```md 6 | docs 7 | ├── index.en-US.md // ruabick 会自动处理`.[lang].md`后缀的文件 8 | ├── index.zh-CN.md 9 | src 10 | ├── loading 11 | │ ├── demo 12 | │ │ └── demo.vue 13 | │ ├── index.en-US.md // 通过 `frontmatter` 设置的`map.path`映射到 docs 目录下 14 | │ ├── index.zh-CN.md 15 | │ └── loading.vue 16 | └── ... 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/demo.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 在`.md`文件里展示 demo 2 | 3 | ```html 4 | 5 | ``` 6 | 7 | 8 | 9 | ```vue:demo 10 | 13 | 16 | ``` 17 | -------------------------------------------------------------------------------- /packages/create-vlib/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "moduleResolution": "node", 5 | "strict": true, 6 | "declaration": true, 7 | "noUnusedLocals": true, 8 | "esModuleInterop": true, 9 | "outDir": "../dist", 10 | "module": "commonjs", 11 | "lib": ["esnext"], 12 | "sourceMap": true 13 | }, 14 | "include": ["."] 15 | } 16 | -------------------------------------------------------------------------------- /packages/create-vlib/readme.md: -------------------------------------------------------------------------------- 1 | # @ruabick/create-vlib 2 | 3 | 快速创建 Vue 组件库的脚手架。 4 | 5 | # Features 6 | 7 | - 基于[`ruabick`](https://github.com/dewfall123/ruabick.git)一键启动开发环境,一键生成文档。 8 | - 基于`vite`一键打包。 9 | - 使用[`np`](https://github.com/sindresorhus/np)发布版本(非常 nice 的发布工具)。 10 | - 使用`gh-pages`一键发布 github.io 文档。 11 | - 集成`eslint` `prettier` `ls-lint` 等 lint 工具。 12 | - 集成`husky` `conventional-changelog-cli`等工具。 13 | 14 | # 使用 15 | 16 | 执行命令 `yarn create @ruabick/vlib`。 17 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/useCopyCode.ts: -------------------------------------------------------------------------------- 1 | import { reactive, toRefs } from 'vue'; 2 | 3 | export function useCopyCode(code: string) { 4 | const state = reactive({ 5 | showTip: false, 6 | }); 7 | 8 | function copyCode() { 9 | navigator.clipboard.writeText(code); 10 | state.showTip = true; 11 | setTimeout(() => { 12 | state.showTip = false; 13 | }, 5 * 1000); 14 | } 15 | 16 | return { 17 | ...toRefs(state), 18 | copyCode, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/doc-site/docs/demo.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const { defineConfig } = require('eslint-define-config'); 3 | 4 | module.exports = defineConfig({ 5 | root: true, 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:node/recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | ], 11 | plugins: ['import'], 12 | parser: '@typescript-eslint/parser', 13 | parserOptions: { 14 | sourceType: 'module', 15 | ecmaVersion: 2021, 16 | }, 17 | rules: {}, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/src/__docs__/demo.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 26 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme'; 2 | import DemoBlock from '@ruabick/vitepress-demo-block'; 3 | import '@ruabick/vitepress-demo-block/dist/style.css'; 4 | import './var.css'; 5 | 6 | export default { 7 | ...DefaultTheme, 8 | 9 | enhanceApp({ app, router, siteData }) { 10 | // app is the Vue 3 app instance from `createApp()`. 11 | // router is VitePress' custom router. `siteData` is 12 | // a `ref` of current site-level metadata. 13 | app.component('demo', DemoBlock); 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /packages/create-vlib/src/create-dir/index.ts: -------------------------------------------------------------------------------- 1 | import globby from 'globby'; 2 | import { mkdirSync } from 'fs'; 3 | import { Meta } from '../prompt'; 4 | 5 | async function checkDir(name: string) { 6 | const list = await globby('*', { onlyDirectories: true }); 7 | if (list.includes(name)) { 8 | const msg = `Directory ${name} already exists.`; 9 | console.error(msg); 10 | throw new Error(msg); 11 | } 12 | } 13 | 14 | export async function createDir(meta: Meta) { 15 | await checkDir(meta.projectName); 16 | 17 | await mkdirSync(meta.projectName); 18 | 19 | return meta.projectName; 20 | } 21 | -------------------------------------------------------------------------------- /packages/utils/src/parseProps.ts: -------------------------------------------------------------------------------- 1 | import { baseParse, ElementNode, AttributeNode } from '@vue/compiler-core'; 2 | 3 | export function parseProps(content: string) { 4 | const ast = baseParse(content); 5 | const demoElement = ast.children[0] as ElementNode; 6 | 7 | const props = getPropsMap(demoElement.props as AttributeNode[]); 8 | 9 | return props; 10 | } 11 | 12 | function getPropsMap(attrs: AttributeNode[]) { 13 | const map: Record = {}; 14 | for (const { name, value } of attrs) { 15 | map[name] = value?.content; 16 | } 17 | return map; 18 | } 19 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme'; 2 | import DemoBlock from '@ruabick/vitepress-demo-block'; 3 | import '@ruabick/vitepress-demo-block/dist/style.css'; 4 | import './var.css'; 5 | import Layout from './Layout.vue'; 6 | 7 | export default { 8 | ...DefaultTheme, 9 | Layout, 10 | enhanceApp({ app, router, siteData }) { 11 | // app is the Vue 3 app instance from `createApp()`. 12 | // router is VitePress' custom router. `siteData` is 13 | // a `ref` of current site-level metadata. 14 | app.component('demo', DemoBlock); 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/doc-site/docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme'; 2 | import DemoBlock from '@ruabick/vitepress-demo-block'; 3 | import '@ruabick/vitepress-demo-block/dist/style.css'; 4 | import './var.css'; 5 | 6 | // import { DemoTag } from '@ruabick/md-demo-plugins'; 7 | 8 | export default { 9 | ...DefaultTheme, 10 | 11 | enhanceApp({ app, router, siteData }) { 12 | // app is the Vue 3 app instance from `createApp()`. 13 | // router is VitePress' custom router. `siteData` is 14 | // a `ref` of current site-level metadata. 15 | app.component('demo', DemoBlock); 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/api-ts.en-US.md: -------------------------------------------------------------------------------- 1 | # Ts api 文档自动生成 2 | 3 | markdown 写一个 API 组件,传入 src 属性。 4 | 5 | 暂时只支持生成 interface 文档,而且必须要有 jsDoc 格式的注释。 6 | 7 | ```md 8 | 9 | ``` 10 | 11 | 生成的结果: 12 | 13 | 14 | 15 | Demo.vue Props 内容如下 16 | 17 | ```ts 18 | export interface DemoProps { 19 | /** 20 | * 源码字符串(需经过encodeURIComponent处理) 21 | */ 22 | code: string; 23 | /** 24 | * 标题 25 | */ 26 | title?: string; 27 | /** 28 | * 描述 29 | */ 30 | desc?: string; 31 | /** 32 | * 语言 33 | */ 34 | lang?: string; 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/api-ts.zh-CN.md: -------------------------------------------------------------------------------- 1 | # Ts api 文档自动生成 2 | 3 | markdown 写一个 API 组件,传入 src 属性。 4 | 5 | 暂时只支持生成 interface 文档,而且必须要有 jsDoc 格式的注释。 6 | 7 | ```md 8 | 9 | ``` 10 | 11 | 生成的结果: 12 | 13 | 14 | 15 | Demo.vue Props 内容如下 16 | 17 | ```ts 18 | export interface DemoProps { 19 | /** 20 | * 源码字符串(需经过encodeURIComponent处理) 21 | */ 22 | code: string; 23 | /** 24 | * 标题 25 | */ 26 | title?: string; 27 | /** 28 | * 描述 29 | */ 30 | desc?: string; 31 | /** 32 | * 语言 33 | */ 34 | lang?: string; 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/utils", 3 | "version": "0.3.3", 4 | "license": "MIT", 5 | "bin": {}, 6 | "files": [ 7 | "dist", 8 | "bin" 9 | ], 10 | "main": "./dist/index.cjs", 11 | "module": "./dist/index.mjs", 12 | "types": "./dist/index.d.ts", 13 | "exports": { 14 | ".": { 15 | "types": "./dist/index.d.ts", 16 | "import": "./dist/index.mjs", 17 | "require": "./dist/index.cjs" 18 | } 19 | }, 20 | "scripts": { 21 | "build": "unbuild" 22 | }, 23 | "dependencies": { 24 | "@vue/compiler-core": "^3.2.37", 25 | "vitepress": "1.0.0-alpha.29" 26 | }, 27 | "devDependencies": { 28 | "unbuild": "^0.7.6" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/src/plugin-fence.ts: -------------------------------------------------------------------------------- 1 | import { MarkdownRenderer } from 'vitepress'; 2 | import { FenceDemoTag } from './constants'; 3 | import { genDemoByCode } from './utils'; 4 | 5 | export function fencePlugin(md: MarkdownRenderer) { 6 | const defaultRender = md.renderer.rules.fence; 7 | 8 | md.renderer.rules.fence = (tokens, idx, options, env, self) => { 9 | const token = tokens[idx]; 10 | if (token.info.trim() !== FenceDemoTag) { 11 | return defaultRender!(tokens, idx, options, env, self); 12 | } 13 | 14 | const content = token.content; 15 | const path = env.path; 16 | 17 | const demoScripts = genDemoByCode(md, env, path, content); 18 | return demoScripts; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/doc-site/src/__docs__/demo.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 27 | 28 | 33 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/Icons/copy.vue: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/README.md: -------------------------------------------------------------------------------- 1 | # @ruabick/vite-plugin-gen-api-doc 2 | 3 | > 基于`vue-docgen-api`项目, 参考了很多[arco-design-vue](https://github.com/arco-design/arco-design-vue/tree/main/packages/arco-vue-scripts)的代码。 4 | 5 | ## 开始使用 6 | 7 | ### 步骤 1 8 | 9 | 安装插件 `pnpm add @ruabick/vite-plugin-gen-api-doc -D` 10 | 11 | ### 步骤 2 12 | 13 | `.vitepress/config.js` 14 | 15 | ```js 16 | import { genApiDoc } from '@ruabick/vite-plugin-gen-api-doc'; 17 | 18 | export default defineConfig({ 19 | // ... 20 | vite: { 21 | plugins: [genApiDoc()], 22 | }, 23 | }); 24 | ``` 25 | 26 | ## 示例 27 | 28 | 注释用参考[vue-docgen-api](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api) 29 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { defineConfig } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import dts from 'vite-plugin-dts'; 5 | 6 | export default defineConfig({ 7 | plugins: [vue(), dts()], 8 | build: { 9 | lib: { 10 | entry: resolve(__dirname, './src/index.ts'), 11 | name: 'vitepress-demo-block', 12 | // the proper extensions will be added 13 | fileName: 'vitepress-demo-block', 14 | }, 15 | rollupOptions: { 16 | // 确保外部化处理那些你不想打包进库的依赖 17 | external: ['vue'], 18 | output: { 19 | // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量 20 | globals: { 21 | vue: 'Vue', 22 | }, 23 | }, 24 | }, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /packages/doc-site/docs/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: ruabick 5 | titleTemplate: Ruabick 6 | 7 | hero: 8 | text: Ruabick 9 | tagline: 让开发vue组件变得简单 10 | actions: 11 | - theme: brand 12 | text: 快速上手 13 | link: /guide/ 14 | - theme: alt 15 | text: Github 16 | link: https://github.com/dewfall123/ruabick 17 | 18 | features: 19 | - title: 基于VitePress 20 | details: 基于VitePress,加上增强插件,开箱即用 21 | - title: Demo展示 22 | details: 像dumi一样在markdown里面展示demo 23 | - title: 支持API文档自动生成 24 | details: 自动生成vue组件api文档 25 | - title: 支持文件映射 26 | details: 你可以把.md文件写在任何目录 27 | 28 | footer: 29 | license: MIT Licensed 30 | since: 2022 31 | author: 32 | name: dewfall123 33 | url: https://github.com/dewfall123 34 | --- 35 | -------------------------------------------------------------------------------- /packages/utils/src/resolveLocaleConfigs.ts: -------------------------------------------------------------------------------- 1 | import { resolveConfig } from 'vitepress'; 2 | 3 | export interface LocaleConfigs { 4 | defaultLang: string; 5 | langToPathMap: Record; 6 | } 7 | 8 | export async function resolveLocaleConfigs( 9 | root = 'docs', 10 | ): Promise { 11 | const vitepressConfigs = await resolveConfig(root); 12 | 13 | const siteData = vitepressConfigs.site; 14 | 15 | const defaultLang = siteData.lang; 16 | 17 | const langToPathMap = Object.entries(siteData.locales).reduce( 18 | (map, [path, localeConfig]) => { 19 | map[localeConfig.lang!] = path; 20 | return map; 21 | }, 22 | {} as Record, 23 | ); 24 | 25 | return { 26 | defaultLang, 27 | langToPathMap, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/vitepress-demo-block", 3 | "version": "0.3.3", 4 | "license": "MIT", 5 | "type": "module", 6 | "types": "./dist/index.d.ts", 7 | "main": "./dist/vitepress-demo-block.umd.cjs", 8 | "module": "./dist/vitepress-demo-block.js", 9 | "exports": { 10 | ".": { 11 | "import": "./dist/vitepress-demo-block.js", 12 | "require": "./dist/vitepress-demo-block.umd.cjs" 13 | }, 14 | "./dist/style.css": "./dist/style.css" 15 | }, 16 | "files": [ 17 | "dist" 18 | ], 19 | "devDependencies": { 20 | "@vitejs/plugin-vue": "^3.0.1", 21 | "less": "^4.1.3", 22 | "vite": "~3.0.3", 23 | "vite-plugin-dts": "^1.4.0", 24 | "vue": "^3.2.37" 25 | }, 26 | "scripts": { 27 | "build": "vite build" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/api.en-US.md: -------------------------------------------------------------------------------- 1 | # Vue API 文档自动生成 2 | 3 | markdown 写一个 API 组件,传入 src 属性。 4 | 5 | ```md 6 | 7 | ``` 8 | 9 | 生成的 API 文档: 10 | 11 | 12 | 13 | Demo.vue Props 内容如下 14 | 15 | ```ts 16 | const props = withDefaults( 17 | defineProps<{ 18 | /** 19 | * @zh 源码字符串(需经过encodeURIComponent处理) 20 | */ 21 | code: string; 22 | highlightedCode: string; 23 | title?: string; 24 | desc?: string; 25 | lang?: string; 26 | defaultExpand?: boolean; 27 | importMap?: Record; 28 | }>(), 29 | { 30 | lang: 'vue', 31 | defaultExpand: false, 32 | importMap: () => ({}), 33 | }, 34 | ); 35 | ``` 36 | -------------------------------------------------------------------------------- /packages/doc-site/docs/features/api.zh-CN.md: -------------------------------------------------------------------------------- 1 | # Vue API 文档自动生成 2 | 3 | markdown 写一个 API 组件,传入 src 属性。 4 | 5 | ```md 6 | 7 | ``` 8 | 9 | 生成的 API 文档: 10 | 11 | 12 | 13 | Demo.vue Props 内容如下 14 | 15 | ```ts 16 | const props = withDefaults( 17 | defineProps<{ 18 | /** 19 | * @zh 源码字符串(需经过encodeURIComponent处理) 20 | */ 21 | code: string; 22 | highlightedCode: string; 23 | title?: string; 24 | desc?: string; 25 | lang?: string; 26 | defaultExpand?: boolean; 27 | importMap?: Record; 28 | }>(), 29 | { 30 | lang: 'vue', 31 | defaultExpand: false, 32 | importMap: () => ({}), 33 | }, 34 | ); 35 | ``` 36 | -------------------------------------------------------------------------------- /packages/doc-site/docs/guide/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 项目介绍 2 | 3 | `ruabick` 是一个基于 VitePress 的组件开发工具。功能设计是`抄`的 [dumi](https://d.umijs.org/zh-CN),但是`dumi`目前不支持`vue`。而且我觉得使用 [VitePress](https://vitepress.vuejs.org/)来构建 vue 组件文档更轻量。 4 | 5 | ::: info 6 | 项目前身是 [vitepress-for-components](https://github.com/dewfall123/vitepress-for-component) 7 | ::: 8 | 9 | ## 解决问题 10 | 11 | VitePress 很轻量很快,但是在`写组件文档的场景`下有以下不足之处: 12 | 13 | ##### 1. 文档和 Demo 得重复写两遍。 14 | 15 | > 参考 [dumi 的 demo 理念](https://d.umijs.org/zh-CN/guide/demo-principle) 16 | 17 | ##### 2. 文档,Demo 和源码在不同的目录,联系感不强。 18 | 19 | > 源码和 Demo 一般在`src`目录下面,但是 VitePress 通常需要新建一个`docs`目录,它们之间应该放在同一个地方。 20 | > 参考[dumi 的目录结构](https://d.umijs.org/zh-CN/guide/basic) 21 | 22 | ##### 3. 需要自动生成组件 API 文档功能。 23 | 24 | > 基于`vue-docgen-api`自动生成 api 文档(参考[arco-design-vue](https://github.com/arco-design/arco-design-vue/tree/main/packages/arco-vue-scripts)的代码)。 25 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/README.md: -------------------------------------------------------------------------------- 1 | ## 2 | 3 | 像 dumi 一样使用 `VitePress`,此插件包含一个`initial-scan`脚本和一个vite插件,需要配合使用。 4 | 5 | 6 | ## 参考示例 7 | 8 | 示例项目 https://github.com/dewfall123/ruabick/tree/master/packages/doc-site 9 | 10 | 示例站点 https://dewfall123.github.io/ruabick/guide/ 11 | 12 | ## 使用步骤 13 | 14 | ### 步骤 1 15 | 16 | `pnpm add @ruabick/vite-plugin-gen-temp -D` 17 | 18 | ### 步骤 2 19 | 20 | 修改 package.json 脚本。 21 | 22 | ::: warning 23 | 注意`vitepress dev .docs` 是`.docs`而不是`docs`,因为`.docs`是脚本处理后的目录。 24 | ::: 25 | 26 | ```json 27 | { 28 | "dev": "initial-scan && vitepress dev .docs" 29 | } 30 | ``` 31 | 32 | ### 步骤 3 33 | 34 | 增加插件配置 35 | 36 | ```js 37 | // .vitepress/config.js 38 | import { genTemp } from '@ruabick/vite-plugin-gen-temp'; 39 | 40 | export default defineConfig({ 41 | ... 42 | vite: { 43 | plugins: [genTemp()], 44 | } 45 | ... 46 | }) 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { defineConfig } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import dts from 'vite-plugin-dts'; 5 | import packageJson from './package.json' 6 | 7 | export default defineConfig({ 8 | plugins: [vue(), dts()], 9 | build: { 10 | lib: { 11 | entry: resolve(__dirname, './src/index.ts'), 12 | name: '@{projectName}', 13 | // the proper extensions will be added 14 | fileName: '@{projectName}', 15 | }, 16 | rollupOptions: { 17 | // 确保外部化处理那些你不想打包进库的依赖 18 | // @ts-ignore 19 | external: ['vue', ...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.peerDependencies || {})], 20 | output: { 21 | // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量 22 | globals: { 23 | vue: 'Vue', 24 | }, 25 | }, 26 | }, 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/md-demo-plugins", 3 | "version": "0.3.3", 4 | "license": "MIT", 5 | "bin": {}, 6 | "files": [ 7 | "dist", 8 | "bin" 9 | ], 10 | "main": "./dist/index.cjs", 11 | "module": "./dist/index.mjs", 12 | "types": "./dist/index.d.ts", 13 | "exports": { 14 | ".": { 15 | "types": "./dist/index.d.ts", 16 | "import": "./dist/index.mjs", 17 | "require": "./dist/index.cjs" 18 | } 19 | }, 20 | "scripts": { 21 | "build": "unbuild" 22 | }, 23 | "keywords": [], 24 | "author": "dewfall123", 25 | "dependencies": { 26 | "@ruabick/utils": "workspace:^0.3.3", 27 | "fs-extra": "^10.1.0", 28 | "markdown-it": "^13.0.1", 29 | "vitepress": "1.0.0-alpha.29" 30 | }, 31 | "devDependencies": { 32 | "@types/fs-extra": "^9.0.13", 33 | "@types/markdown-it": "^12.2.3", 34 | "unbuild": "^0.7.6" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/Icons/code.vue: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | import { applyPlugins } from '@ruabick/md-demo-plugins'; 3 | import { genTemp } from '@ruabick/vite-plugin-gen-temp'; 4 | import { genApiDoc } from '@ruabick/vite-plugin-gen-api-doc'; 5 | import { resolve } from 'path'; 6 | 7 | export default defineConfig({ 8 | lang: 'zh-CN', 9 | lastUpdated: true, 10 | title: '@{projectName}', 11 | base: process.env.NODE_ENV === 'production' ? '/@{projectName}' : '/', 12 | vue: {}, 13 | vite: { 14 | plugins: [genTemp(), genApiDoc()], 15 | resolve: { 16 | alias: { 17 | '@{projectName}': resolve('./src/'), 18 | }, 19 | }, 20 | }, 21 | markdown: { 22 | config: (md) => { 23 | applyPlugins(md); 24 | }, 25 | theme: { 26 | light: 'github-light', 27 | dark: 'github-dark', 28 | }, 29 | }, 30 | buildEnd() { 31 | process.exit(0); 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /packages/create-vlib/src/generator/index.ts: -------------------------------------------------------------------------------- 1 | import { src, dest } from 'gulp'; 2 | import replace from 'gulp-replace'; 3 | import { resolve } from 'node:path'; 4 | import { fileURLToPath } from 'node:url'; 5 | import { Meta } from '../prompt'; 6 | 7 | export async function generator(meta: Meta) { 8 | console.log(meta.template); 9 | const templateDir = resolve( 10 | // @ts-ignore 11 | fileURLToPath(import.meta.url), 12 | '../..', 13 | meta.template, 14 | ); 15 | 16 | return new Promise((resolve, reject) => { 17 | src([`${templateDir}/**/**`, '!node_modules'], { dot: true }) 18 | .pipe(replace('@{projectName}', meta.projectName)) 19 | .pipe(replace('@{description}', meta.description)) 20 | .pipe(replace('@{user}', meta.user)) 21 | .pipe(dest(meta.projectName)) 22 | .on('error', (err) => { 23 | reject(err); 24 | }) 25 | .on('end', () => { 26 | resolve(true); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /packages/doc-site/docs/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: ruabick 5 | titleTemplate: Ruabick. 6 | 7 | hero: 8 | text: Ruabick. 9 | tagline: Make the development Vue component easier 10 | actions: 11 | - theme: brand 12 | text: Get Started 13 | link: /en/guide/ 14 | - theme: alt 15 | text: View on Github 16 | link: https://github.com/dewfall123/ruabick 17 | 18 | features: 19 | - title: Based on Vitepress 20 | details: Based on VitePress, with enhance plugin, out of the box. 21 | - title: Support demo display 22 | details: Display you component demo in VitePress. 23 | - title: Support api doc auto generation 24 | details: Auto generation api doc based on `vue-docgen-api`. 25 | - title: Support file mapping 26 | details: Write doc file in any directory. 27 | 28 | footer: 29 | license: MIT Licensed 30 | since: 2022 31 | author: 32 | name: dewfall123 33 | url: https://github.com/dewfall123 34 | --- 35 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/copyDocs.ts: -------------------------------------------------------------------------------- 1 | import { LocaleConfigs } from '@ruabick/utils'; 2 | import chokidar from 'chokidar'; 3 | import { handleCopy } from './handleCopy'; 4 | import { Options } from './types'; 5 | import { removeFile } from './utils'; 6 | import fg from 'fast-glob'; 7 | 8 | export async function copyDocs( 9 | options: Required, 10 | localeConfigs: LocaleConfigs, 11 | ) { 12 | const { docsDir, initial } = options; 13 | 14 | const globSource = `${docsDir}/**`; 15 | 16 | const copyFile = (file: string) => 17 | handleCopy(docsDir, file, { options, localeConfigs }); 18 | 19 | if (initial) { 20 | const files = await fg(globSource, { dot: true, cwd: process.cwd() }); 21 | await Promise.all(files.map(copyFile)); 22 | } else { 23 | chokidar 24 | .watch(globSource, { 25 | cwd: process.cwd(), 26 | ignored: [], 27 | ignoreInitial: !initial, 28 | persistent: !initial, 29 | }) 30 | .on('change', copyFile) 31 | .on('add', copyFile) 32 | .on('unlink', (file) => removeFile(file)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "outDir": "dist", 5 | "sourceMap": false, 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "moduleResolution": "node", 9 | "allowJs": false, 10 | "noUnusedLocals": true, 11 | "strictNullChecks": true, 12 | "noImplicitAny": true, 13 | "noImplicitThis": true, 14 | "experimentalDecorators": true, 15 | "resolveJsonModule": true, 16 | "esModuleInterop": true, 17 | "removeComments": false, 18 | "declaration": true, 19 | "isolatedModules": true, 20 | "jsx": "preserve", 21 | "lib": [ 22 | "esnext", 23 | "dom", 24 | ], 25 | "types": [], 26 | "skipLibCheck": true, 27 | // "files": "src/index.ts", 28 | "emitDeclarationOnly": true, 29 | "declarationDir": "dist", 30 | "rootDir": ".", 31 | "paths": { 32 | "@/*": [ 33 | "packages/src/*" 34 | ] 35 | } 36 | }, 37 | "include": [ 38 | "packages/doc-site/src/index.ts" 39 | ], 40 | "exclude": [ 41 | "node_modules", 42 | "dist", 43 | "packages/**/__tests__" 44 | ] 45 | } -------------------------------------------------------------------------------- /packages/doc-site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/doc-site", 3 | "private": true, 4 | "version": "0.3.3", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "dev": "initial-scan docs --srcDir=src && pnpm site:dev", 9 | "site:dev": "vitepress dev .docs --host", 10 | "site:build": "cross-env NODE_ENV=production vitepress build .docs", 11 | "site:serve": "cross-env NODE_ENV=production vitepress serve .docs --host", 12 | "site:deploy": "gh-pages -d .docs/.vitepress/dist -t true" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "@ruabick/md-demo-plugins": "workspace:^0.3.3", 19 | "@ruabick/vite-plugin-gen-api-doc": "workspace:^0.3.3", 20 | "@ruabick/vite-plugin-gen-temp": "workspace:^0.3.3", 21 | "@ruabick/vitepress-demo-block": "workspace:^0.3.3", 22 | "cross-env": "^7.0.3", 23 | "gh-pages": "^4.0.0", 24 | "postcss": "^8.4.16", 25 | "postcss-prefix-selector": "^1.16.0", 26 | "vite": "^3.0.2", 27 | "vitepress": "1.0.0-alpha.29", 28 | "vue": "^3.2.37", 29 | "vue-typical": "^2.1.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const { defineConfig } = require('eslint-define-config'); 3 | 4 | module.exports = defineConfig({ 5 | root: true, 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:node/recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | ], 11 | plugins: ['import'], 12 | parser: '@typescript-eslint/parser', 13 | parserOptions: { 14 | sourceType: 'module', 15 | ecmaVersion: 2021, 16 | }, 17 | rules: { 18 | 'no-debugger': ['error'], 19 | '@typescript-eslint/no-var-requires': 'off', 20 | 'node/no-unpublished-require': 'off', 21 | 'node/no-extraneous-import': 'off', 22 | 'node/no-extraneous-require': 'off', 23 | 'node/no-missing-import': 'off', 24 | 'node/no-missing-require': 'off', 25 | 'no-undef': 'off', 26 | 'node/no-unpublished-import': 'off', 27 | 'node/no-unsupported-features/es-syntax': 'off', 28 | 'no-process-exit': 'off', 29 | '@typescript-eslint/ban-ts-comment': 'off', 30 | 'no-constant-condition': 'off', 31 | '@typescript-eslint/no-non-null-assertion': 'off', 32 | '@typescript-eslint/no-explicit-any': 'off', 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /packages/doc-site/docs/guide/index.en-US.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | `ruabick` is documentation tool for developing libraries (based on VitePress)。The functional design was copied from [dumi](https://d.umijs.org). But `dumi` currently does not support `vue`. 4 | 5 | ::: info 6 | The predecessor of the project was [vitepress-for-components](https://github.com/dewfall123/vitepress-for-component) 7 | ::: 8 | 9 | ## Motivation 10 | 11 | VitePress is very fast and lightweight, but there is the following shortcomings under the scene of the component document: 12 | 13 | ##### 1. The document and Demo have to be written twice. 14 | 15 | > Refer to [dumi's demo-principle](https://d.umijs.org/guide/demo-principle) 16 | 17 | ##### 2. Documentation, Demo and source code in different directories, The sense of contact is not strong. 18 | 19 | > The source code and Demo are usually in the `src` directory, but VitePress usually needs to create a new 'docs' directory, which should be in the same place. 20 | 21 | > Refer to [dumi's directory structure](https://d.umijs.org/guide/basic) 22 | 23 | ##### 3. We need the function of automatically generate component API document. 24 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/README.md: -------------------------------------------------------------------------------- 1 | `@ruabick/md-demo-plugins` 与 `@ruabick/vitepress-demo-block` 配合使用在 VirePress 里面支持`demo-block`。 2 | 3 | ### 步骤 1: 增加 markdown 插件 4 | 5 | 安装插件 `pnpm add @ruabick/md-demo-plugins -D` 6 | 7 | ```js 8 | // .vitepress/config.js 9 | import { applyPlugins } from '@ruabick/md-demo-plugins'; 10 | 11 | export default defineConfig({ 12 | markdown: { 13 | config: (md) => { 14 | applyPlugins(md); 15 | }, 16 | }, 17 | }); 18 | ``` 19 | 20 | ### 步骤 2: 注册 demo 组件 21 | 22 | 安装插件 `pnpm add @ruabick/vitepress-demo-block -D` 23 | 24 | ```js 25 | // docs/.vitepress/theme/index.ts 26 | import DemoBlock from '@ruabick/vitepress-demo-block'; 27 | import '@ruabick/vitepress-demo-block/dist/style.css'; 28 | 29 | export default { 30 | ...DefaultTheme, 31 | enhanceApp({ app, router, siteData }) { 32 | app.component('demo', DemoBlock); 33 | }, 34 | }; 35 | ``` 36 | 37 | ### 步骤 3: 修改 VitePress `Code Blocks` 样式 (可选) 38 | 39 | `VitePress` 默认 `Code Blocks` 是黑色,与 demo 样式不太符合,所以建议修改 `Code Blocks` 样式。 40 | 41 | [`Code Blocks` 样式在这里](https://github.com/dewfall123/ruabick/blob/master/packages/doc-site/docs/.vitepress/theme/var.css) 42 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/copySrcMd.ts: -------------------------------------------------------------------------------- 1 | import { LocaleConfigs } from '@ruabick/utils'; 2 | import chokidar from 'chokidar'; 3 | import { handleCopy } from './handleCopy'; 4 | import { Options } from './types'; 5 | import { removeFile } from './utils'; 6 | import fg from 'fast-glob'; 7 | 8 | export async function copySrcMd( 9 | options: Required, 10 | localeConfigs: LocaleConfigs, 11 | ) { 12 | const { srcDir, initial } = options; 13 | 14 | const copyFile = (file: string) => 15 | handleCopy(srcDir, file, { options, localeConfigs }); 16 | 17 | const globSource = `${srcDir}/**/*.md`; 18 | 19 | if (initial) { 20 | const mdFiles = await fg(globSource, { 21 | dot: true, 22 | cwd: process.cwd(), 23 | ignore: ['**/node_modules/**'], 24 | }); 25 | await Promise.all(mdFiles.map(copyFile)); 26 | } else { 27 | chokidar 28 | .watch(globSource, { 29 | cwd: process.cwd(), 30 | ignored: [/node_modules/], 31 | ignoreInitial: true, 32 | }) 33 | .on('change', copyFile) 34 | .on('add', copyFile) 35 | .on('unlink', (file) => removeFile(file)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/README.md: -------------------------------------------------------------------------------- 1 | `@ruabick/md-demo-plugins` 与 `@ruabick/vitepress-demo-block` 配合使用在 VirePress 里面支持`demo-block`。 2 | 3 | ### 步骤 1: 增加 markdown 插件 4 | 5 | 安装插件 `pnpm add @ruabick/md-demo-plugins -D` 6 | 7 | ```js 8 | // .vitepress/config.js 9 | import { applyPlugins } from '@ruabick/md-demo-plugins'; 10 | 11 | export default defineConfig({ 12 | markdown: { 13 | config: (md) => { 14 | applyPlugins(md); 15 | }, 16 | }, 17 | }); 18 | ``` 19 | 20 | ### 步骤 2: 注册 demo 组件 21 | 22 | 安装插件 `pnpm add @ruabick/vitepress-demo-block -D` 23 | 24 | ```js 25 | // docs/.vitepress/theme/index.ts 26 | import DemoBlock from '@ruabick/vitepress-demo-block'; 27 | import '@ruabick/vitepress-demo-block/dist/style.css'; 28 | 29 | export default { 30 | ...DefaultTheme, 31 | enhanceApp({ app, router, siteData }) { 32 | app.component('demo', DemoBlock); 33 | }, 34 | }; 35 | ``` 36 | 37 | ### 步骤 3: 修改 VitePress `Code Blocks` 样式 (可选) 38 | 39 | `VitePress` 默认 `Code Blocks` 是黑色,与 demo 样式不太符合,所以建议修改 `Code Blocks` 样式。 40 | 41 | [`Code Blocks` 样式在这里](https://github.com/dewfall123/ruabick/blob/master/packages/doc-site/docs/.vitepress/theme/var.css) 42 | -------------------------------------------------------------------------------- /packages/doc-site/docs/.vitepress/sidebar.js: -------------------------------------------------------------------------------- 1 | export const sidebar = { 2 | '/en/': [ 3 | { 4 | text: 'Guide', 5 | items: [ 6 | { text: 'Introduction', link: '/en/guide/' }, 7 | { text: 'Getting Started', link: '/en/guide/getting-started' }, 8 | ], 9 | }, 10 | { 11 | text: 'featrues', 12 | items: [ 13 | { text: 'Demo display', link: '/en/features/demo' }, 14 | { text: 'Vue api auto gen', link: '/en/features/api' }, 15 | { text: 'Ts api auto gen', link: '/en/features/api-ts' }, 16 | { text: 'File mapping', link: '/en/features/mapping' }, 17 | ], 18 | }, 19 | ], 20 | '/': [ 21 | { 22 | text: '介绍', 23 | items: [ 24 | { text: '项目介绍', link: '/guide/' }, 25 | { text: '快速开始', link: '/guide/getting-started' }, 26 | ], 27 | }, 28 | { 29 | text: '特性', 30 | items: [ 31 | { text: 'Demo展示', link: '/features/demo' }, 32 | { text: 'Vue文档生成', link: '/features/api' }, 33 | { text: 'ts文档生成', link: '/features/api-ts' }, 34 | { text: '文件映射', link: '/features/mapping' }, 35 | ], 36 | }, 37 | ], 38 | }; 39 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const { defineConfig } = require('eslint-define-config'); 3 | 4 | module.exports = defineConfig({ 5 | root: true, 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:node/recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | ], 11 | plugins: ['import'], 12 | parser: '@typescript-eslint/parser', 13 | parserOptions: { 14 | sourceType: 'module', 15 | ecmaVersion: 2021, 16 | }, 17 | rules: { 18 | 'no-debugger': ['error'], 19 | '@typescript-eslint/no-var-requires': 'off', 20 | 'node/no-unpublished-require': 'off', 21 | 'node/no-extraneous-import': 'off', 22 | 'node/no-extraneous-require': 'off', 23 | 'node/no-missing-import': 'off', 24 | 'node/no-missing-require': 'off', 25 | 'no-undef': 'off', 26 | 'node/no-unpublished-import': 'off', 27 | 'node/no-unsupported-features/es-syntax': 'off', 28 | 'no-process-exit': 'off', 29 | '@typescript-eslint/ban-ts-comment': 'off', 30 | 'no-constant-condition': 'off', 31 | '@typescript-eslint/no-non-null-assertion': 'off', 32 | '@typescript-eslint/no-explicit-any': 'off', 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/vite-plugin-gen-api-doc", 3 | "version": "0.3.3", 4 | "description": "", 5 | "main": "./dist/index.cjs", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "exports": { 9 | ".": { 10 | "types": "./dist/index.d.ts", 11 | "import": "./dist/index.mjs", 12 | "require": "./dist/index.cjs" 13 | } 14 | }, 15 | "scripts": { 16 | "build": "unbuild" 17 | }, 18 | "keywords": [], 19 | "author": "dewfall123", 20 | "license": "MIT", 21 | "dependencies": { 22 | "@babel/parser": "^7.18.11", 23 | "@ruabick/utils": "workspace:^0.3.3", 24 | "@vue/compiler-core": "^3.2.37", 25 | "chalk": "^5.0.1", 26 | "comment-parser": "^1.3.1", 27 | "fs-extra": "^10.1.0", 28 | "gray-matter": "^4.0.3", 29 | "markdown-it": "^13.0.1", 30 | "ts-morph": "^15.1.0", 31 | "vitepress": "1.0.0-alpha.29", 32 | "vue-docgen-api": "^4.50.0" 33 | }, 34 | "devDependencies": { 35 | "@types/markdown-it": "^12.2.3", 36 | "unbuild": "^0.7.6", 37 | "vite": "^3.0.5" 38 | }, 39 | "peerDependencies": { 40 | "vite": "^3.0.5" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/vite-plugin-gen-temp", 3 | "version": "0.3.3", 4 | "description": "", 5 | "license": "MIT", 6 | "bin": { 7 | "initial-scan": "bin/initial-scan.js" 8 | }, 9 | "files": [ 10 | "dist", 11 | "bin" 12 | ], 13 | "main": "./dist/index.cjs", 14 | "module": "./dist/index.mjs", 15 | "types": "./dist/index.d.ts", 16 | "exports": { 17 | ".": { 18 | "types": "./dist/index.d.ts", 19 | "import": "./dist/index.mjs", 20 | "require": "./dist/index.cjs" 21 | } 22 | }, 23 | "scripts": { 24 | "build": "unbuild" 25 | }, 26 | "keywords": [], 27 | "author": "dewfall123", 28 | "devDependencies": { 29 | "@types/fs-extra": "^9.0.13", 30 | "@types/is-plain-object": "^2.0.4", 31 | "@types/minimist": "^1.2.2", 32 | "lodash-es": "^4.17.21", 33 | "picocolors": "^1.0.0", 34 | "rollup": "^2.77.0", 35 | "tsx": "^3.8.0", 36 | "unbuild": "^0.7.6" 37 | }, 38 | "dependencies": { 39 | "@ruabick/utils": "workspace:^0.3.3", 40 | "chokidar": "^3.5.3", 41 | "colorette": "^2.0.19", 42 | "fast-glob": "^3.2.11", 43 | "fs-extra": "^10.1.0", 44 | "globby": "^13.1.2", 45 | "gray-matter": "^4.0.3", 46 | "is-plain-object": "^5.0.0", 47 | "minimist": "^1.2.6" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "outDir": "dist", 5 | "sourceMap": false, 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "moduleResolution": "node", 9 | "allowJs": false, 10 | "noUnusedLocals": true, 11 | "strictNullChecks": true, 12 | "noImplicitAny": true, 13 | "noImplicitThis": true, 14 | "experimentalDecorators": true, 15 | "resolveJsonModule": true, 16 | "esModuleInterop": true, 17 | "removeComments": false, 18 | "declaration": true, 19 | "isolatedModules": true, 20 | "jsx": "preserve", 21 | "lib": [ 22 | "esnext", 23 | "dom", 24 | ], 25 | "types": [], 26 | "skipLibCheck": true, 27 | // "files": "src/index.ts", 28 | "emitDeclarationOnly": true, 29 | "declarationDir": "dist", 30 | "rootDir": ".", 31 | "paths": { 32 | "@/*": [ 33 | "src/*" 34 | ], 35 | "@{projectName}": [ 36 | "src/index.ts" 37 | ] 38 | } 39 | }, 40 | "include": [ 41 | "src/*" 42 | ], 43 | "exclude": [ 44 | "node_modules", 45 | "dist", 46 | "packages/**/__tests__" 47 | ] 48 | } -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "outDir": "dist", 5 | "sourceMap": false, 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "moduleResolution": "node", 9 | "allowJs": false, 10 | "noUnusedLocals": true, 11 | "strictNullChecks": true, 12 | "noImplicitAny": true, 13 | "noImplicitThis": true, 14 | "experimentalDecorators": true, 15 | "resolveJsonModule": true, 16 | "esModuleInterop": true, 17 | "removeComments": false, 18 | "declaration": true, 19 | "isolatedModules": true, 20 | "jsx": "preserve", 21 | "lib": [ 22 | "esnext", 23 | "dom", 24 | ], 25 | "types": [], 26 | "skipLibCheck": true, 27 | // "files": "src/index.ts", 28 | "emitDeclarationOnly": true, 29 | "declarationDir": "dist", 30 | "rootDir": ".", 31 | "paths": { 32 | "@/*": [ 33 | "src/*" 34 | ], 35 | "@{projectName}": [ 36 | "src/index.ts" 37 | ] 38 | } 39 | }, 40 | "include": [ 41 | "src/*" 42 | ], 43 | "exclude": [ 44 | "node_modules", 45 | "dist", 46 | "packages/**/__tests__" 47 | ] 48 | } -------------------------------------------------------------------------------- /packages/utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/utils 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | 9 | ## 0.3.2 10 | 11 | ### Patch Changes 12 | 13 | - adapt viteptess 0.7.2 beta 14 | 15 | ## 0.3.1 16 | 17 | ### Patch Changes 18 | 19 | - fix create-vlib `pnpm serve` bug 20 | 21 | ## 0.3.0 22 | 23 | ### Minor Changes 24 | 25 | - #fix 18 #20 26 | 27 | ## 0.2.9 28 | 29 | ### Patch Changes 30 | 31 | - fix #13 32 | 33 | ## 0.2.8 34 | 35 | ### Patch Changes 36 | 37 | - fix: #6 38 | 39 | ## 0.2.7 40 | 41 | ### Patch Changes 42 | 43 | - 0.2.7 44 | 45 | ## 0.2.6 46 | 47 | ### Patch Changes 48 | 49 | - support monorepo 50 | 51 | ## 0.2.5 52 | 53 | ### Patch Changes 54 | 55 | - fix 56 | 57 | ## 0.2.4 58 | 59 | ### Patch Changes 60 | 61 | - v0.2.4 62 | 63 | ## 0.2.3 64 | 65 | ### Patch Changes 66 | 67 | - add ts library template 68 | 69 | ## 0.2.2 70 | 71 | ### Patch Changes 72 | 73 | - fix initial scan error 74 | 75 | ## 0.2.1 76 | 77 | ### Patch Changes 78 | 79 | - 5a61563: add --srcDir args 80 | 81 | ## 0.2.0 82 | 83 | ### Minor Changes 84 | 85 | - v0.2 86 | 87 | ## 0.1.5 88 | 89 | ### Patch Changes 90 | 91 | - template update 92 | 93 | ## 0.1.4 94 | 95 | ### Patch Changes 96 | 97 | - fix bugs 98 | 99 | ## 0.1.3 100 | 101 | ### Patch Changes 102 | 103 | - Support api auto generation. 104 | -------------------------------------------------------------------------------- /packages/doc-site/docs/.vitepress/theme/var.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --vp-code-block-bg: #f9fafb; 3 | /* --vp-code-block-bg: var(--vp-c-bg-alt); */ 4 | 5 | --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); 6 | --vp-code-line-number-color: var(--vp-c-text-dark-3); 7 | 8 | --vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05); 9 | --vp-code-copy-code-active-text: var(--vp-c-bg-alt); 10 | 11 | --demi-border-color: #ebedf1; 12 | } 13 | 14 | .dark { 15 | --vp-code-block-bg: var(--vp-c-bg-alt); 16 | } 17 | 18 | .vp-doc [class*='language-']:before { 19 | color: var(--vp-c-text-2); 20 | } 21 | 22 | @media (min-width: 640px) { 23 | .vp-doc div[class*='language-'] { 24 | border-radius: 4px; 25 | margin: 16px 0; 26 | } 27 | } 28 | 29 | @media (max-width: 639px) { 30 | .vp-doc div[class*='language-'] { 31 | border-radius: 4px; 32 | } 33 | } 34 | 35 | .vp-doc table { 36 | display: table; 37 | width: 100%; 38 | font-size: 15px; 39 | } 40 | 41 | .vp-doc tr { 42 | border-top: 1px solid var(--demi-border-color); 43 | } 44 | 45 | .vp-doc tr:nth-child(2n) { 46 | background-color: unset; 47 | } 48 | 49 | .vp-doc th, 50 | .vp-doc td { 51 | border: 1px solid var(--demi-border-color); 52 | padding: 10px 20px; 53 | } 54 | 55 | .vp-doc th { 56 | font-size: 15px; 57 | font-weight: 600; 58 | background-color: var(--vp-c-white-soft); 59 | } 60 | 61 | .vp-doc table td:first-child { 62 | font-size: 15px; 63 | font-weight: 600; 64 | } 65 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/.vitepress/theme/var.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --vp-code-block-bg: #f9fafb; 3 | /* --vp-code-block-bg: var(--vp-c-bg-alt); */ 4 | 5 | --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); 6 | --vp-code-line-number-color: var(--vp-c-text-dark-3); 7 | 8 | --vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05); 9 | --vp-code-copy-code-active-text: var(--vp-c-bg-alt); 10 | 11 | --demi-border-color: #ebedf1; 12 | } 13 | 14 | .dark { 15 | --vp-code-block-bg: var(--vp-c-bg-alt); 16 | } 17 | 18 | .vp-doc [class*='language-']:before { 19 | color: var(--vp-c-text-2); 20 | } 21 | 22 | @media (min-width: 640px) { 23 | .vp-doc div[class*='language-'] { 24 | border-radius: 4px; 25 | margin: 16px 0; 26 | } 27 | } 28 | 29 | @media (max-width: 639px) { 30 | .vp-doc div[class*='language-'] { 31 | border-radius: 4px; 32 | } 33 | } 34 | 35 | .vp-doc table { 36 | display: table; 37 | width: 100%; 38 | font-size: 15px; 39 | } 40 | 41 | .vp-doc tr { 42 | border-top: 1px solid var(--demi-border-color); 43 | } 44 | 45 | .vp-doc tr:nth-child(2n) { 46 | background-color: unset; 47 | } 48 | 49 | .vp-doc th, 50 | .vp-doc td { 51 | border: 1px solid var(--demi-border-color); 52 | padding: 10px 20px; 53 | } 54 | 55 | .vp-doc th { 56 | font-size: 15px; 57 | font-weight: 600; 58 | background-color: var(--vp-c-white-soft); 59 | } 60 | 61 | .vp-doc table td:first-child { 62 | font-size: 15px; 63 | font-weight: 600; 64 | } 65 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/docs/.vitepress/theme/var.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --vp-code-block-bg: #f9fafb; 3 | /* --vp-code-block-bg: var(--vp-c-bg-alt); */ 4 | 5 | --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); 6 | --vp-code-line-number-color: var(--vp-c-text-dark-3); 7 | 8 | --vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05); 9 | --vp-code-copy-code-active-text: var(--vp-c-bg-alt); 10 | 11 | --demi-border-color: #ebedf1; 12 | } 13 | 14 | .dark { 15 | --vp-code-block-bg: var(--vp-c-bg-alt); 16 | } 17 | 18 | .vp-doc [class*='language-']:before { 19 | color: var(--vp-c-text-2); 20 | } 21 | 22 | @media (min-width: 640px) { 23 | .vp-doc div[class*='language-'] { 24 | border-radius: 4px; 25 | margin: 16px 0; 26 | } 27 | } 28 | 29 | @media (max-width: 639px) { 30 | .vp-doc div[class*='language-'] { 31 | border-radius: 4px; 32 | } 33 | } 34 | 35 | .vp-doc table { 36 | display: table; 37 | width: 100%; 38 | font-size: 15px; 39 | } 40 | 41 | .vp-doc tr { 42 | border-top: 1px solid var(--demi-border-color); 43 | } 44 | 45 | .vp-doc tr:nth-child(2n) { 46 | background-color: unset; 47 | } 48 | 49 | .vp-doc th, 50 | .vp-doc td { 51 | border: 1px solid var(--demi-border-color); 52 | padding: 10px 20px; 53 | } 54 | 55 | .vp-doc th { 56 | font-size: 15px; 57 | font-weight: 600; 58 | background-color: var(--vp-c-white-soft); 59 | } 60 | 61 | .vp-doc table td:first-child { 62 | font-size: 15px; 63 | font-weight: 600; 64 | } 65 | -------------------------------------------------------------------------------- /packages/doc-site/docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/create-vlib/src/index.ts: -------------------------------------------------------------------------------- 1 | import program from 'commander'; 2 | import kolorist from 'kolorist'; 3 | import del from 'del'; 4 | import { CLI_NAME, pkgFromUserAgent } from './constants'; 5 | import { createDir } from './create-dir'; 6 | import { generator } from './generator'; 7 | import { TEMPLATE_NAME } from './constants'; 8 | import { prompt } from './prompt'; 9 | 10 | export async function cli() { 11 | program.usage('').parse(process.argv); 12 | 13 | const argProjectName = program.args[0]; 14 | // const root = process.cwd(); 15 | let createdFile; 16 | try { 17 | const meta = await prompt(argProjectName); 18 | 19 | createdFile = await createDir(meta); 20 | 21 | await generator(meta); 22 | 23 | clean(); 24 | 25 | const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent); 26 | const pkgManager = pkgInfo ? pkgInfo.name : 'npm'; 27 | 28 | console.log(`\n🎉 Successfully created project ${meta.projectName}.`); 29 | console.log(`👉 Get started with the following commands:\n`); 30 | 31 | console.log( 32 | `${kolorist.gray('$')} ${kolorist.cyan(`cd ${meta.projectName}`)}`, 33 | ); 34 | console.log( 35 | `${kolorist.gray('$')} ${kolorist.cyan( 36 | `${pkgManager} install && ${pkgManager} dev`, 37 | )}\n`, 38 | ); 39 | } catch (err) { 40 | console.error(err); 41 | console.warn(`[${CLI_NAME}] failed.`); 42 | if (createdFile) { 43 | del(createdFile); 44 | } 45 | } 46 | 47 | function clean() { 48 | del(TEMPLATE_NAME); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/src/plugin-demo-block.ts: -------------------------------------------------------------------------------- 1 | import { dirname, resolve } from 'path'; 2 | import { MarkdownRenderer } from 'vitepress'; 3 | import { parseProps } from '@ruabick/utils'; 4 | import { DemoTag } from './constants'; 5 | import { getDemoComponent } from './utils'; 6 | import fsExtra from 'fs-extra'; 7 | 8 | export function demoBlockPlugin(md: MarkdownRenderer) { 9 | const addRenderRule = (type: string) => { 10 | const defaultRender = md.renderer.rules[type]; 11 | 12 | md.renderer.rules[type] = (tokens, idx, options, env, self) => { 13 | const token = tokens[idx]; 14 | const content = token.content.trim(); 15 | 16 | if (!content.match(new RegExp(`^<${DemoTag}\\s`))) { 17 | return defaultRender!(tokens, idx, options, env, self); 18 | } 19 | 20 | const { path } = env; 21 | 22 | const props = parseProps(content); 23 | 24 | if (!props.src) { 25 | console.error(`miss src props in ${path} demo.`); 26 | return defaultRender!(tokens, idx, options, env, self); 27 | } 28 | 29 | const frontmatter = env.frontmatter; 30 | 31 | const mdDir = dirname(frontmatter.realPath ?? path); 32 | const srcPath = resolve(mdDir, props.src); 33 | const code = fsExtra.readFileSync(srcPath, 'utf-8'); 34 | 35 | const demoScripts = getDemoComponent(md, env, { 36 | title: props.title, 37 | desc: props.desc, 38 | path: srcPath, 39 | code, 40 | }); 41 | 42 | return demoScripts; 43 | }; 44 | }; 45 | 46 | addRenderRule('html_block'); 47 | addRenderRule('html_inline'); 48 | } 49 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/scripts/patchCJS.ts: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | It converts 4 | 5 | ```ts 6 | exports["default"] = vuePlugin; 7 | exports.parseVueRequest = parseVueRequest; 8 | ``` 9 | 10 | to 11 | 12 | ```ts 13 | module.exports = vuePlugin; 14 | module.exports["default"] = vuePlugin; 15 | module.exports.parseVueRequest = parseVueRequest; 16 | ``` 17 | */ 18 | 19 | import { readFileSync, writeFileSync } from 'fs'; 20 | import colors from 'picocolors'; 21 | 22 | const indexPath = 'dist/index.cjs'; 23 | let code = readFileSync(indexPath, 'utf-8'); 24 | 25 | const matchMixed = code.match(/\nexports\["default"\] = (\w+);/); 26 | if (matchMixed) { 27 | const name = matchMixed[1]; 28 | 29 | const lines = code.trimEnd().split('\n'); 30 | 31 | // search from the end to prepend `modules.` to `export[xxx]` 32 | for (let i = lines.length - 1; i > 0; i--) { 33 | if (lines[i].startsWith('exports')) lines[i] = 'module.' + lines[i]; 34 | else { 35 | // at the beginning of exports, export the default function 36 | lines[i] += `\nmodule.exports = ${name};`; 37 | break; 38 | } 39 | } 40 | 41 | writeFileSync(indexPath, lines.join('\n')); 42 | 43 | console.log(colors.bold(`${indexPath} CJS patched`)); 44 | process.exit(0); 45 | } 46 | 47 | const matchDefault = code.match(/\nmodule.exports = (\w+);/); 48 | 49 | if (matchDefault) { 50 | code += `module.exports["default"] = ${matchDefault[1]};\n`; 51 | writeFileSync(indexPath, code); 52 | console.log(colors.bold(`${indexPath} CJS patched`)); 53 | process.exit(0); 54 | } 55 | 56 | console.error(colors.red(`${indexPath} CJS patch failed`)); 57 | process.exit(1); 58 | -------------------------------------------------------------------------------- /packages/create-vlib/src/prompt/index.ts: -------------------------------------------------------------------------------- 1 | import inquirer from 'inquirer'; 2 | import { red, reset } from 'kolorist'; 3 | 4 | export interface Meta { 5 | projectName: string; 6 | description: string; 7 | user: string; 8 | template: string; 9 | } 10 | 11 | export async function prompt(targetDir: string) { 12 | const defaultTargetDir = 'ruabick-project'; 13 | 14 | const questions = [ 15 | { 16 | type: targetDir ? null : 'text', 17 | name: 'projectName', 18 | message: reset('Project name:'), 19 | initial: defaultTargetDir, 20 | default: defaultTargetDir, 21 | onState: (state: any) => { 22 | targetDir = formatTargetDir(state.value) || defaultTargetDir; 23 | }, 24 | }, 25 | { 26 | name: 'template', 27 | type: 'list', 28 | message: 'Please select a template.', 29 | choices: [ 30 | { 31 | name: 'vue-ts-components', 32 | value: 'template-vue-ts', 33 | }, 34 | { 35 | name: 'ts-library', 36 | value: 'template-ts', 37 | }, 38 | ], 39 | }, 40 | { 41 | name: 'description', 42 | message: 'project description', 43 | default: ``, 44 | }, 45 | { 46 | name: 'user', 47 | message: 'your github user name', 48 | default: ``, 49 | }, 50 | ]; 51 | 52 | const meta = (await inquirer.prompt(questions, { 53 | onCancel: () => { 54 | throw new Error(red('✖') + ' Operation cancelled'); 55 | }, 56 | })) as Meta; 57 | 58 | return meta; 59 | } 60 | 61 | function formatTargetDir(targetDir: string) { 62 | return targetDir?.trim().replace(/\/+$/g, ''); 63 | } 64 | -------------------------------------------------------------------------------- /packages/doc-site/docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | import { applyPlugins } from '@ruabick/md-demo-plugins'; 2 | import { genTemp } from '@ruabick/vite-plugin-gen-temp'; 3 | import { genApiDoc } from '@ruabick/vite-plugin-gen-api-doc'; 4 | import { defineConfig } from 'vitepress'; 5 | import { resolve } from 'node:path'; 6 | import { sidebar } from './sidebar'; 7 | 8 | export default defineConfig({ 9 | lang: 'zh-CN', 10 | lastUpdated: true, 11 | base: process.env.NODE_ENV === 'production' ? '/ruabick' : '/', 12 | locales: { 13 | '/': { 14 | lang: 'zh-CN', 15 | title: 'ruabick', 16 | description: '针对组件开发的VitePress', 17 | }, 18 | '/en/': { 19 | lang: 'en-US', 20 | title: 'ruabick', 21 | description: 'A tool to document VUE components', 22 | }, 23 | }, 24 | themeConfig: { 25 | logo: '/logo.svg', 26 | localeLinks: { 27 | text: '', 28 | items: [ 29 | { text: '简体中文', link: '/' }, 30 | { text: 'English', link: '/en/' }, 31 | ], 32 | }, 33 | nav: [{ text: '指南', link: '/guide' }], 34 | sidebar, 35 | algolia: {}, 36 | socialLinks: [ 37 | { icon: 'github', link: 'https://github.com/dewfall123/ruabick' }, 38 | ], 39 | }, 40 | vue: {}, 41 | vite: { 42 | plugins: [genTemp(), genApiDoc()], 43 | resolve: { 44 | alias: { 45 | 'my-button': resolve('./src/'), 46 | }, 47 | }, 48 | }, 49 | markdown: { 50 | config: (md) => { 51 | applyPlugins(md); 52 | }, 53 | theme: { 54 | light: 'github-light', 55 | dark: 'github-dark', 56 | }, 57 | }, 58 | buildEnd() { 59 | process.exit(0); 60 | }, 61 | }); 62 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | import { applyPlugins } from '@ruabick/md-demo-plugins'; 3 | import { genTemp } from '@ruabick/vite-plugin-gen-temp'; 4 | import { genApiDoc } from '@ruabick/vite-plugin-gen-api-doc'; 5 | import { sidebar } from './sidebar.js'; 6 | import { resolve } from 'path'; 7 | 8 | export default defineConfig({ 9 | lang: 'zh-CN', 10 | lastUpdated: true, 11 | base: process.env.NODE_ENV === 'production' ? '/@{projectName}' : '/', 12 | locales: { 13 | '/': { 14 | lang: 'zh-CN', 15 | title: '@{projectName}', 16 | description: '@{description}', 17 | }, 18 | '/en/': { 19 | lang: 'en-US', 20 | title: '@{projectName}', 21 | description: '@{description}', 22 | }, 23 | }, 24 | themeConfig: { 25 | logo: '/logo.svg', 26 | localeLinks: { 27 | text: '', 28 | items: [ 29 | { text: '简体中文', link: '/' }, 30 | { text: 'English', link: '/en/' }, 31 | ], 32 | }, 33 | nav: [{ text: '指南', link: '/guide' }], 34 | sidebar, 35 | algolia: {}, 36 | socialLinks: [ 37 | { icon: 'github', link: 'https://github.com/@{user}/@{projectName}' }, 38 | ], 39 | }, 40 | vue: {}, 41 | vite: { 42 | plugins: [genTemp(), genApiDoc()], 43 | resolve: { 44 | alias: { 45 | '@{projectName}': resolve('./src/'), 46 | }, 47 | }, 48 | }, 49 | markdown: { 50 | config: (md) => { 51 | applyPlugins(md); 52 | }, 53 | theme: { 54 | light: 'github-light', 55 | dark: 'github-dark', 56 | }, 57 | }, 58 | buildEnd() { 59 | process.exit(0); 60 | }, 61 | }); 62 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 替换换行和竖线使其能在markdown中显示 3 | * @param str 4 | */ 5 | export const escapeCharacter = (str: string) => { 6 | return str.replace(/\r?\n/g, '
').replace(/\|/g, '\\|'); 7 | }; 8 | 9 | /** 10 | * 转为 kebab-case 11 | * @param str 12 | */ 13 | export const toKebabCase = (str: string): string => { 14 | return str.replace(/[A-Z]/g, (match, offset) => { 15 | return `${offset > 0 ? '-' : ''}${match.toLocaleLowerCase()}`; 16 | }); 17 | }; 18 | 19 | const opt = Object.prototype.toString; 20 | export function isBoolean(obj: unknown): obj is boolean { 21 | return opt.call(obj) === '[object Boolean]'; 22 | } 23 | 24 | /** 25 | * 去掉包裹字符串的引号 26 | * @param {str} string 27 | * @returns {string} 28 | */ 29 | export function unquote(str: string) { 30 | return str && str.replace(/^['"]|['"]$/g, ''); 31 | } 32 | 33 | /** 34 | * 清理字符串前后的空格,竖线和 \n 35 | * @param {str} string 36 | * @returns {string} 37 | */ 38 | export function trimStr(str: string) { 39 | return str && str.replace(/^(\s|\||\r?\n)*|(\s|\||\r?\n)*$/g, ''); 40 | } 41 | 42 | /** 43 | * 清理字符串中不符合预期的字符,如 \n 44 | * @param {str} string 45 | * @returns {string} 46 | */ 47 | export function cleanStr(str: string) { 48 | return str && str.replace(/\r?\n/g, ''); 49 | } 50 | 51 | export const getTemplate = (src: string, lang: 'zh' | 'en') => { 52 | const matches = Array.from( 53 | src.matchAll(/##\s+(zh-CN|en-US)\n+(.+?)\n+---(?:\n|$)/gs) 54 | ); 55 | for (const item of matches) { 56 | if (new RegExp(lang).test(item[1])) { 57 | src = src.replace(item[0], `${item[2]}\n`); 58 | } else { 59 | src = src.replace(item[0], ''); 60 | } 61 | } 62 | 63 | return src; 64 | }; 65 | -------------------------------------------------------------------------------- /packages/doc-site/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/doc-site 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | 9 | ## 0.3.2 10 | 11 | ### Patch Changes 12 | 13 | - adapt viteptess 0.7.2 beta 14 | 15 | ## 0.3.1 16 | 17 | ### Patch Changes 18 | 19 | - fix create-vlib `pnpm serve` bug 20 | 21 | ## 0.3.0 22 | 23 | ### Minor Changes 24 | 25 | - #fix 18 #20 26 | 27 | ## 0.2.9 28 | 29 | ### Patch Changes 30 | 31 | - fix #13 32 | 33 | ## 0.2.8 34 | 35 | ### Patch Changes 36 | 37 | - fix: #6 38 | 39 | ## 0.2.7 40 | 41 | ### Patch Changes 42 | 43 | - 0.2.7 44 | 45 | ## 0.2.6 46 | 47 | ### Patch Changes 48 | 49 | - support monorepo 50 | 51 | ## 0.2.5 52 | 53 | ### Patch Changes 54 | 55 | - fix 56 | 57 | ## 0.2.4 58 | 59 | ### Patch Changes 60 | 61 | - v0.2.4 62 | 63 | ## 0.2.3 64 | 65 | ### Patch Changes 66 | 67 | - add ts library template 68 | 69 | ## 0.2.2 70 | 71 | ### Patch Changes 72 | 73 | - fix initial scan error 74 | 75 | ## 0.2.1 76 | 77 | ### Patch Changes 78 | 79 | - 5a61563: add --srcDir args 80 | 81 | ## 0.2.0 82 | 83 | ### Minor Changes 84 | 85 | - v0.2 86 | 87 | ## 0.1.5 88 | 89 | ### Patch Changes 90 | 91 | - template update 92 | 93 | ## 0.1.4 94 | 95 | ### Patch Changes 96 | 97 | - fix bugs 98 | 99 | ## 0.1.3 100 | 101 | ### Patch Changes 102 | 103 | - Support api auto generation. 104 | 105 | ## 0.1.2 106 | 107 | ### Patch Changes 108 | 109 | - build 110 | 111 | ## 0.1.1 112 | 113 | ### Patch Changes 114 | 115 | - 5852508: bug fix 116 | 117 | ## 0.1.0 118 | 119 | ### Minor Changes 120 | 121 | - rename package 122 | 123 | ### Patch Changes 124 | 125 | - fc64aac: add create-vlib 126 | 127 | ## 0.0.2 128 | 129 | ### Patch Changes 130 | 131 | - first publish 132 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/vitepress-demo-block 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | 9 | ## 0.3.2 10 | 11 | ### Patch Changes 12 | 13 | - adapt viteptess 0.7.2 beta 14 | 15 | ## 0.3.1 16 | 17 | ### Patch Changes 18 | 19 | - fix create-vlib `pnpm serve` bug 20 | 21 | ## 0.3.0 22 | 23 | ### Minor Changes 24 | 25 | - #fix 18 #20 26 | 27 | ## 0.2.9 28 | 29 | ### Patch Changes 30 | 31 | - fix #13 32 | 33 | ## 0.2.8 34 | 35 | ### Patch Changes 36 | 37 | - fix: #6 38 | 39 | ## 0.2.7 40 | 41 | ### Patch Changes 42 | 43 | - 0.2.7 44 | 45 | ## 0.2.6 46 | 47 | ### Patch Changes 48 | 49 | - support monorepo 50 | 51 | ## 0.2.5 52 | 53 | ### Patch Changes 54 | 55 | - fix 56 | 57 | ## 0.2.4 58 | 59 | ### Patch Changes 60 | 61 | - v0.2.4 62 | 63 | ## 0.2.3 64 | 65 | ### Patch Changes 66 | 67 | - add ts library template 68 | 69 | ## 0.2.2 70 | 71 | ### Patch Changes 72 | 73 | - fix initial scan error 74 | 75 | ## 0.2.1 76 | 77 | ### Patch Changes 78 | 79 | - 5a61563: add --srcDir args 80 | 81 | ## 0.2.0 82 | 83 | ### Minor Changes 84 | 85 | - v0.2 86 | 87 | ## 0.1.5 88 | 89 | ### Patch Changes 90 | 91 | - template update 92 | 93 | ## 0.1.4 94 | 95 | ### Patch Changes 96 | 97 | - fix bugs 98 | 99 | ## 0.1.3 100 | 101 | ### Patch Changes 102 | 103 | - Support api auto generation. 104 | 105 | ## 0.1.2 106 | 107 | ### Patch Changes 108 | 109 | - build 110 | 111 | ## 0.1.1 112 | 113 | ### Patch Changes 114 | 115 | - 5852508: bug fix 116 | 117 | ## 0.1.0 118 | 119 | ### Minor Changes 120 | 121 | - rename package 122 | 123 | ### Patch Changes 124 | 125 | - fc64aac: add create-vlib 126 | 127 | ## 0.0.2 128 | 129 | ### Patch Changes 130 | 131 | - first publish 132 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Options } from './types'; 2 | import { copyDocs } from './copyDocs'; 3 | import { copySrcMd } from './copySrcMd'; 4 | import { DefaultOptions } from './constants'; 5 | import fsExtra from 'fs-extra'; 6 | import { cyan } from 'colorette'; 7 | import minimist from 'minimist'; 8 | import { resolveLocaleConfigs } from '@ruabick/utils'; 9 | import { LOG_PREFIX } from './utils'; 10 | 11 | async function genTempDocs(root: string, inputOptions: Options) { 12 | const options = { 13 | ...DefaultOptions, 14 | ...inputOptions, 15 | }; 16 | 17 | const localeConfigs = await resolveLocaleConfigs(root); 18 | 19 | if (options.initial) { 20 | await fsExtra.remove(options.tempDir); 21 | console.log(`${LOG_PREFIX} remove ${options.tempDir}.`); 22 | } 23 | 24 | console.log(`${LOG_PREFIX} ${cyan(`Start generate ${options.tempDir}...`)}`); 25 | await Promise.all([ 26 | copyDocs(options, localeConfigs), 27 | copySrcMd(options, localeConfigs), 28 | ]); 29 | 30 | if (options.initial) { 31 | console.log(`${LOG_PREFIX} ${cyan('Initial scan complete.')}`); 32 | process.exit(0); 33 | } else { 34 | console.warn( 35 | `${cyan( 36 | `${LOG_PREFIX} watching ${options.docsDir} and ${options.srcDir}/**/*.md files changes...`, 37 | )}`, 38 | ); 39 | } 40 | } 41 | 42 | export async function initialScan() { 43 | const argv: any = minimist(process.argv.slice(2)); 44 | 45 | const root = argv._[0]; 46 | genTempDocs(root, { 47 | initial: true, 48 | srcDir: argv.srcDir ?? DefaultOptions.srcDir, 49 | }); 50 | } 51 | 52 | // vite-plugin 53 | export function genTemp() { 54 | return { 55 | name: 'vite-plugin-gen-temp', 56 | config: async (config: any) => { 57 | await genTempDocs(config.root, { initial: false }); 58 | }, 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruabick", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/*" 6 | ], 7 | "version": "0.0.3", 8 | "main": "index.js", 9 | "license": "MIT", 10 | "devDependencies": { 11 | "@changesets/cli": "^2.24.1", 12 | "@types/node": "^18.6.1", 13 | "@typescript-eslint/eslint-plugin": "^5.31.0", 14 | "@typescript-eslint/parser": "^5.31.0", 15 | "eslint": "^8.20.0", 16 | "eslint-define-config": "^1.5.1", 17 | "eslint-plugin-import": "^2.26.0", 18 | "eslint-plugin-node": "^11.1.0", 19 | "lint-staged": "^13.0.3", 20 | "prettier": "^2.7.1", 21 | "turbo": "^1.4.3", 22 | "typescript": "^4.7.4" 23 | }, 24 | "scripts": { 25 | "dev": "turbo run dev --filter=@ruabick/doc-site", 26 | "build:site": "turbo run site:build", 27 | "serve": "pnpm build:site && pnpm -F @ruabick/doc-site run site:serve", 28 | "deploy": "pnpm build:site && pnpm -F @ruabick/doc-site site:deploy", 29 | "dev:create-vlib": "pnpm -F @ruabick/create-vlib run dev test-project", 30 | "build:create-vlib": "pnpm -F @ruabick/create-vlib run build", 31 | "lint": "eslint --cache packages/*/{src,types,__tests__}/**", 32 | "format": "prettier --write --cache .", 33 | "np": "np", 34 | "version": "changeset version" 35 | }, 36 | "lint-staged": { 37 | "*": [ 38 | "prettier --write --cache --ignore-unknown" 39 | ], 40 | "packages/*/{src,types}/**/*.ts": [ 41 | "eslint --cache --fix" 42 | ], 43 | "packages/**/*.d.ts": [ 44 | "eslint --cache --fix" 45 | ], 46 | "playground/**/__tests__/**/*.ts": [ 47 | "eslint --cache --fix" 48 | ] 49 | }, 50 | "packageManager": "pnpm@7.5.2", 51 | "pnpm": { 52 | "overrides": { 53 | "vitepress": "latest" 54 | } 55 | }, 56 | "dependencies": { 57 | "np": "^7.6.2" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/create-vlib/template-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@{projectName}", 3 | "version": "0.0.1", 4 | "description": "@{description}", 5 | "main": "./dist/index.cjs", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "exports": { 9 | ".": { 10 | "types": "./dist/index.d.ts", 11 | "import": "./dist/index.mjs", 12 | "require": "./dist/index.cjs" 13 | } 14 | }, 15 | "scripts": { 16 | "dev": "initial-scan docs && vitepress dev .docs --host", 17 | "build": "unbuild", 18 | "site:build": "initial-scan docs && cross-env NODE_ENV=production vitepress build .docs", 19 | "serve": "cross-env NODE_ENV=production vitepress serve .docs --host", 20 | "deploy": "gh-pages -d .docs/.vitepress/dist -t true", 21 | "docs-build-deploy": "yarn docs-build && yarn docs-deploy", 22 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", 23 | "lint": "eslint src/**/*.{vue,js,ts,tsx}", 24 | "lint-fix": "yarn lint -- --fix", 25 | "release": "np" 26 | }, 27 | "keywords": [], 28 | "author": "@{user}", 29 | "license": "MIT", 30 | "dependencies": { 31 | "@ruabick/md-demo-plugins": "latest", 32 | "@ruabick/vite-plugin-gen-api-doc": "latest", 33 | "@ruabick/vite-plugin-gen-temp": "latest", 34 | "@ruabick/vitepress-demo-block": "latest", 35 | "@vitejs/plugin-vue": "^3.0.1", 36 | "cross-env": "^7.0.3", 37 | "eslint": "^8.20.0", 38 | "gh-pages": "^4.0.0", 39 | "np": "^7.6.2", 40 | "prettier": "^2.7.1", 41 | "vitepress": "latest" 42 | }, 43 | "devDependencies": { 44 | "@typescript-eslint/eslint-plugin": "^5.33.1", 45 | "@typescript-eslint/parser": "^5.33.1", 46 | "eslint-define-config": "^1.6.0", 47 | "eslint-plugin-import": "^2.26.0", 48 | "eslint-plugin-node": "^11.1.0", 49 | "unbuild": "^0.7.6" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/create-vlib/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/create-vlib 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | 9 | ## 0.3.2 10 | 11 | ### Patch Changes 12 | 13 | - adapt viteptess 0.7.2 beta 14 | 15 | ## 0.3.1 16 | 17 | ### Patch Changes 18 | 19 | - fix create-vlib `pnpm serve` bug 20 | 21 | ## 0.3.0 22 | 23 | ### Minor Changes 24 | 25 | - #fix 18 #20 26 | 27 | ## 0.2.9 28 | 29 | ### Patch Changes 30 | 31 | - fix #13 32 | 33 | ## 0.2.8 34 | 35 | ### Patch Changes 36 | 37 | - fix: #6 38 | 39 | ## 0.2.7 40 | 41 | ### Patch Changes 42 | 43 | - 0.2.7 44 | 45 | ## 0.2.6 46 | 47 | ### Patch Changes 48 | 49 | - support monorepo 50 | 51 | ## 0.2.5 52 | 53 | ### Patch Changes 54 | 55 | - fix 56 | 57 | ## 0.2.4 58 | 59 | ### Patch Changes 60 | 61 | - v0.2.4 62 | 63 | ## 0.2.3 64 | 65 | ### Patch Changes 66 | 67 | - add ts library template 68 | 69 | ## 0.2.2 70 | 71 | ### Patch Changes 72 | 73 | - fix initial scan error 74 | 75 | ## 0.2.1 76 | 77 | ### Patch Changes 78 | 79 | - 5a61563: add --srcDir args 80 | 81 | ## 0.2.0 82 | 83 | ### Minor Changes 84 | 85 | - v0.2 86 | 87 | ## 0.1.6 88 | 89 | ### Patch Changes 90 | 91 | - template update 92 | 93 | ## 0.1.5 94 | 95 | ### Patch Changes 96 | 97 | - fix bugs 98 | 99 | ## 0.1.4 100 | 101 | ### Patch Changes 102 | 103 | - add gen-api-doc plugin 104 | 105 | ## 0.1.3 106 | 107 | ### Patch Changes 108 | 109 | - Support api auto generation. 110 | 111 | ## 0.1.2 112 | 113 | ### Patch Changes 114 | 115 | - build 116 | 117 | ## 0.1.1 118 | 119 | ### Patch Changes 120 | 121 | - 5852508: bug fix 122 | 123 | ## 0.1.0 124 | 125 | ### Minor Changes 126 | 127 | - rename package 128 | 129 | ### Patch Changes 130 | 131 | - fc64aac: add create-vlib 132 | 133 | ## 0.0.2 134 | 135 | ### Patch Changes 136 | 137 | - first publish 138 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/demo.less: -------------------------------------------------------------------------------- 1 | .vitepress-demo { 2 | --demo-border-color: #ebedf1; 3 | } 4 | 5 | .dark .vitepress-demo { 6 | --demo-border-color: #6b6c6d; 7 | } 8 | 9 | .vitepress-demo { 10 | border: 1px solid var(--demo-border-color); 11 | border-radius: 1px; 12 | margin-bottom: 24px; 13 | 14 | color: var(--vp-c-text-1); 15 | background-color: var(--vp-c-bg); 16 | 17 | div[class*='language-'] { 18 | border-radius: 0px; 19 | margin: 0 !important; 20 | line-height: 1.5 !important; 21 | } 22 | 23 | [class*='language-'] pre { 24 | padding: 0; 25 | } 26 | 27 | [class*='language-'] code { 28 | padding: 1em; 29 | } 30 | 31 | .demo-slot { 32 | padding: 40px 24px; 33 | } 34 | 35 | .demo-actions { 36 | display: flex; 37 | height: 40px; 38 | padding: 0 8px; 39 | align-items: center; 40 | justify-content: space-between; 41 | border-top: 1px dashed var(--demo-border-color); 42 | } 43 | 44 | .demo-buttons { 45 | display: flex; 46 | align-items: center; 47 | } 48 | 49 | .demo-actions-expand, 50 | .demo-actions-copy { 51 | margin: 0 0 0 16px; 52 | cursor: pointer; 53 | color: #666; 54 | } 55 | .demo-actions-tip { 56 | font-size: 12px; 57 | color: #3eaf7c; 58 | } 59 | 60 | .extra-class { 61 | border-top: 1px dashed var(--demo-border-color); 62 | box-sizing: border-box; 63 | } 64 | 65 | .demo-platforms { 66 | display: flex; 67 | align-items: center; 68 | } 69 | 70 | .demo-title-desc { 71 | border-top: 1px dashed var(--demo-border-color); 72 | padding: 1.2em 1em 1em; 73 | color: var(--vp-c-text-1); 74 | position: relative; 75 | font-size: 14px; 76 | } 77 | 78 | .demo-title { 79 | position: absolute; 80 | top: 0; 81 | left: 1em; 82 | transform: translateY(-50%); 83 | background: var(--vp-c-bg); 84 | font-weight: 500; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /packages/create-vlib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ruabick/create-vlib", 3 | "version": "0.3.3", 4 | "description": "@ruabick's cli", 5 | "files": [ 6 | "dist", 7 | "bin", 8 | "template-*" 9 | ], 10 | "main": "./dist/index.cjs", 11 | "module": "./dist/index.mjs", 12 | "types": "./dist/index.d.ts", 13 | "exports": { 14 | ".": { 15 | "types": "./dist/index.d.ts", 16 | "import": "./dist/index.mjs", 17 | "require": "./dist/index.cjs" 18 | } 19 | }, 20 | "scripts": { 21 | "dev": "pnpm build && node ./bin/create-vlib.js", 22 | "build": "unbuild" 23 | }, 24 | "bin": { 25 | "create-vlib": "bin/create-vlib.js" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/dewfall123/ruabick" 30 | }, 31 | "author": "dewfall123", 32 | "license": "MIT", 33 | "dependencies": { 34 | "kolorist": "latest", 35 | "commander": "^6.1.0", 36 | "del": "^6.0.0", 37 | "glob": "^7.1.6", 38 | "globby": "^11.0.1", 39 | "gulp": "^4.0.2", 40 | "gulp-replace": "^1.0.0", 41 | "gulp-template": "^5.0.0", 42 | "inquirer": "^6.5.2", 43 | "metalsmith": "^2.3.0", 44 | "ora": "^5.1.0", 45 | "strip-ansi": "^6.0.0" 46 | }, 47 | "homepage": "https://github.com/dewfall123/ruabick", 48 | "devDependencies": { 49 | "@types/gulp": "^4.0.7", 50 | "@types/gulp-replace": "^0.0.31", 51 | "@types/gulp-template": "^5.0.1", 52 | "@types/inquirer": "^7.3.1", 53 | "@types/node": "^14.14.7", 54 | "np": "^7.4.0", 55 | "prettier": "^2.1.2", 56 | "typescript": "^4.0.5", 57 | "unbuild": "^0.7.6", 58 | "rimraf": "^3.0.2" 59 | }, 60 | "publishConfig": { 61 | "access": "public", 62 | "registry": "https://registry.npmjs.org" 63 | }, 64 | "keywords": [ 65 | "documentation", 66 | "generator", 67 | "vuepress", 68 | "dumi", 69 | "vue", 70 | "vite", 71 | "cli" 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /packages/create-vlib/template-vue-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@{projectName}", 3 | "version": "0.0.0", 4 | "description": "@{description}", 5 | "type": "module", 6 | "types": "./dist/index.d.ts", 7 | "main": "./dist/@{projectName}.umd.cjs", 8 | "module": "./dist/@{projectName}.js", 9 | "exports": { 10 | ".": { 11 | "import": "./dist/@{projectName}.js", 12 | "require": "./dist/@{projectName}.umd.cjs" 13 | }, 14 | "./dist/style.css": "./dist/style.css" 15 | }, 16 | "scripts": { 17 | "dev": "initial-scan docs && vitepress dev .docs --host", 18 | "build": "vite build", 19 | "site:build": "initial-scan docs && cross-env NODE_ENV=production vitepress build .docs", 20 | "serve": "cross-env NODE_ENV=production vitepress serve .docs --host", 21 | "deploy": "gh-pages -d .docs/.vitepress/dist -t true", 22 | "docs-build-deploy": "yarn docs-build && yarn docs-deploy", 23 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", 24 | "lint": "eslint src/**/*.{vue,js,ts,tsx}", 25 | "lint-fix": "yarn lint -- --fix", 26 | "release": "np" 27 | }, 28 | "keywords": [], 29 | "author": "@{user}", 30 | "license": "MIT", 31 | "devDependencies": { 32 | "@ruabick/md-demo-plugins": "latest", 33 | "@ruabick/vite-plugin-gen-temp": "latest", 34 | "@ruabick/vitepress-demo-block": "latest", 35 | "@ruabick/vite-plugin-gen-api-doc": "latest", 36 | "@vitejs/plugin-vue": "^3.0.1", 37 | "cross-env": "^7.0.3", 38 | "eslint": "^8.20.0", 39 | "gh-pages": "^4.0.0", 40 | "np": "^7.6.2", 41 | "prettier": "^2.7.1", 42 | "vite": "latest", 43 | "vite-plugin-dts": "^1.4.0", 44 | "vitepress": "latest", 45 | "vue": "latest", 46 | "@typescript-eslint/eslint-plugin": "^5.33.1", 47 | "@typescript-eslint/parser": "^5.33.1", 48 | "eslint-define-config": "^1.6.0", 49 | "eslint-plugin-import": "^2.26.0", 50 | "eslint-plugin-node": "^11.1.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/plugin-api.ts: -------------------------------------------------------------------------------- 1 | import { dirname, resolve } from 'path'; 2 | import { MarkdownRenderer } from 'vitepress'; 3 | import { baseParse, ElementNode, AttributeNode } from '@vue/compiler-core'; 4 | import { ApiTag } from './constants'; 5 | import fsExtra from 'fs-extra'; 6 | import matter from 'gray-matter'; 7 | import { getApiTmpl } from './getApiTmpl'; 8 | import { parseSource } from 'vue-docgen-api'; 9 | 10 | export function demoBlockPlugin(md: MarkdownRenderer) { 11 | const defaultRender = md.renderer.rules.html_block; 12 | 13 | md.renderer.rules.html_block = (tokens, idx, ...args) => { 14 | const token = tokens[idx]; 15 | const content = token.content.trim(); 16 | 17 | if (!content.match(new RegExp(`^<${ApiTag}\\s`))) { 18 | return defaultRender!(tokens, idx, ...args); 19 | } 20 | 21 | const ast = baseParse(content); 22 | const demoElement = ast.children[0] as ElementNode; 23 | 24 | const props = getPropsMap(demoElement.props as AttributeNode[]); 25 | 26 | if (!props.src) { 27 | console.error(`miss src props in ${md.__path} demo.`); 28 | return defaultRender!(tokens, idx, ...args); 29 | } 30 | 31 | // TODO issue get frontmatter from md.__frontmatter 32 | const mdContent = fsExtra.readFileSync(md.__path); 33 | const { data: frontmatter } = matter(mdContent); 34 | 35 | const mdDir = dirname(frontmatter.realPath ?? md.__path); 36 | const srcPath = resolve(mdDir, props.src); 37 | 38 | const code = fsExtra.readFileSync(srcPath); 39 | const componentDoc = parseSource(code, srcPath); 40 | const apiTmpl = getApiTmpl(componentDoc, 'component', 'zh'); 41 | 42 | return apiTmpl; 43 | }; 44 | } 45 | 46 | function getPropsMap(attrs: AttributeNode[]) { 47 | const map: Record = {}; 48 | for (const { name, value } of attrs) { 49 | map[name] = value?.content; 50 | } 51 | return map; 52 | } 53 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/utils/parse-interface.ts: -------------------------------------------------------------------------------- 1 | import { JSDocTag, Project, PropertySignature } from 'ts-morph'; 2 | import { ComponentDoc, PropDescriptor } from 'vue-docgen-api'; 3 | 4 | const project = new Project(); 5 | 6 | const formatterTags = (jsDocsTags: JSDocTag[]) => { 7 | const tags: PropDescriptor['tags'] = {}; 8 | 9 | jsDocsTags.forEach((tag) => { 10 | const tagName = tag.getTagName(); 11 | 12 | tags[tagName] = [ 13 | { 14 | title: tagName, 15 | description: tag.getCommentText(), 16 | }, 17 | ]; 18 | }); 19 | 20 | return tags; 21 | }; 22 | 23 | const formatterProps = (properties: PropertySignature[]) => { 24 | const props: PropDescriptor[] = []; 25 | 26 | properties.forEach((p) => { 27 | const jsDocs = p.getJsDocs()[0]; 28 | if (!jsDocs) { 29 | return; 30 | } 31 | 32 | props.push({ 33 | name: p.getName(), 34 | type: { 35 | name: p.getTypeNode()?.getText() || '', 36 | }, 37 | description: jsDocs.getDescription(), 38 | tags: formatterTags(jsDocs.getTags()), 39 | }); 40 | }); 41 | 42 | return props; 43 | }; 44 | 45 | export default (filePath: string) => { 46 | project.addSourceFileAtPath(filePath); 47 | 48 | const sourceFile = project.getSourceFile(filePath); 49 | const componentDocList: ComponentDoc[] = []; 50 | 51 | if (sourceFile) { 52 | const interfaces = sourceFile.getInterfaces(); 53 | interfaces.forEach((interfaceDeclaration) => { 54 | const properties = interfaceDeclaration.getProperties(); 55 | const componentDoc = { 56 | displayName: interfaceDeclaration.getName(), 57 | exportName: interfaceDeclaration.getName(), 58 | props: formatterProps(properties), 59 | tags: {}, 60 | }; 61 | 62 | if (componentDoc.props.length) { 63 | componentDocList.push(componentDoc); 64 | } 65 | }); 66 | } 67 | 68 | return componentDocList; 69 | }; 70 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/getApiTmpl.ts: -------------------------------------------------------------------------------- 1 | import { ComponentDoc } from 'vue-docgen-api'; 2 | import templates from './templates'; 3 | import { toKebabCase } from './utils'; 4 | 5 | type ApiType = 'component' | 'interface'; 6 | 7 | export const getApiTmpl = ( 8 | componentDoc: ComponentDoc | ComponentDoc[], 9 | type: ApiType, 10 | lang: string, 11 | ) => { 12 | const componentDocList = Array.isArray(componentDoc) 13 | ? componentDoc 14 | : [componentDoc]; 15 | 16 | const res: string[] = []; 17 | 18 | componentDocList.forEach((item) => { 19 | const { displayName, props, events, methods, slots, tags } = item; 20 | 21 | const getTmpl = (suffix: string, content: string) => { 22 | if (!content) return ''; 23 | let title = displayName; 24 | 25 | if (type === 'component') { 26 | title = tags?.noBrackets 27 | ? displayName 28 | : `<${toKebabCase(displayName)}>`; 29 | title = `\`${title}\` ${suffix}`; 30 | } 31 | 32 | if (tags?.version) { 33 | const version = (tags.version[0] as any)?.description; 34 | version && (title += ` (${version})`); 35 | } 36 | 37 | let description = ''; 38 | if (suffix === 'Props' && tags?.[lang]) { 39 | description = (tags[lang][0] as any)?.description; 40 | } 41 | 42 | return `### ${title}${description ? `\n${description}` : ''}\n${content}`; 43 | }; 44 | 45 | const propsTmpl = getTmpl( 46 | 'Props', 47 | templates.props(props || [], { isInterface: type === 'interface' }, lang), 48 | ); 49 | const eventsTmpl = getTmpl('Events', templates.events(events || [], lang)); 50 | const methodsTmpl = getTmpl( 51 | 'Methods', 52 | templates.methods(methods || [], lang), 53 | ); 54 | const slotsTmpl = getTmpl('Slots', templates.slots(slots || [], lang)); 55 | 56 | res.push(`\n${propsTmpl}${eventsTmpl}${methodsTmpl}${slotsTmpl}\n`); 57 | }); 58 | 59 | return res.join('\n'); 60 | }; 61 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/SfcPlayground.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ruabick 2 | 3 | 一个 vue 组件库开发工具,类似[dumi](https://d.umijs.org/zh-CN),基于 VitePress。 4 | 5 | [English Introduction](./README.md) | 中文介绍 6 | 7 | ## 文档 8 | 9 | [详细文档](https://dewfall123.github.io/ruabick/) 10 | 11 | ## 功能 12 | 13 | ### 1. 在 markdown 里面使用 demo 组件 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | 也可以这样使用(去掉反斜杠) 20 | 21 | ````html 22 | \```vue:demo 23 | 26 | 27 | 30 | \``` 31 | ```` 32 | 33 | [渲染效果](https://dewfall123.github.io/ruabick/features/demo.html) 34 | 35 | ### 2. 自动生成 API 文档 36 | 37 | 在 markdown 里面使用``组件,只需要传入文件路径,自动生成文档。 38 | 39 | > 基于`vue-docgen-api`项目, 参考了很多[arco-design-vue](https://github.com/arco-design/arco-design-vue/tree/main/packages/arco-vue-scripts)的代码。 40 | 41 | ```html 42 | 43 | ``` 44 | 45 | [查看效果](https://dewfall123.github.io/ruabick/features/api.html#api-%E6%96%87%E6%A1%A3%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90) 46 | 47 | 对于 ts 文件,暂时只支持生成 ts 文件里面 interface 文档,而且必须要有 jsDoc 格式的注释。 48 | 49 | ```html 50 | 51 | ``` 52 | 53 | ### 3. 文件映射 54 | 55 | 一般来说,我们使用 VitePress 会单独建一个`docs`目录,把文档集中放在此目录下。但是`Demo`文件放在`docs`目录下面会让`组件源码`和`demo.vue`隔得太远,放到一起更为合理。 56 | 57 | 所以`ruabick`能把 markdown 写在`src`目录下 main,通过 formatter 指定映射路径,把改文件映射到`docs`目录下面。 58 | 59 | [更多说明](https://dewfall123.github.io/ruabick/features/mapping.html) 60 | 61 | ```md 62 | // src/dir/demo-introduction.md 63 | 64 | --- 65 | 66 | mapping: 67 | path: /demo 68 | 69 | --- 70 | ``` 71 | 72 | ## 开始使用 73 | 74 | > 提供了脚手架创建新项目。实际上也可以基于 VirePress 安装`ruabick/*`的一些插件来使用,但是较为繁琐,不推荐。 75 | 76 | ```shell 77 | pnpm create @ruabick/vlib 78 | ``` 79 | 80 | ## Packages 81 | 82 | > `ruabick`是一个 monorepo 库,包含的一些插件也可以单独使用。 83 | 84 | - [@ruabick/md-demo-plugins](https://github.com/dewfall123/ruabick/tree/master/packages/md-demo-plugins) 85 | - [vitepress-demo-block](https://github.com/dewfall123/ruabick/tree/master/packages/vitepress-demo-block) 86 | - [vite-plugin-gen-api-doc](https://github.com/dewfall123/ruabick/tree/master/packages/vite-plugin-gen-api-doc) 87 | 88 | ## License 89 | 90 | [MIT](http://opensource.org/licenses/MIT) 91 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/templates/slots.ts: -------------------------------------------------------------------------------- 1 | import { SlotDescriptor } from 'vue-docgen-api'; 2 | import { escapeCharacter, toKebabCase } from '../utils'; 3 | 4 | const bindingsTmpl = (bindings: SlotDescriptor['bindings']): string => { 5 | return (bindings || []) 6 | .map((binding) => { 7 | const { type, name, description } = binding; 8 | const res: any[] = []; 9 | name && res.push(name); 10 | if (type?.name) { 11 | res.length && res.push(': '); 12 | res.push(`\`${type.name}\``); 13 | } 14 | description && res.push(description); 15 | return res.join(''); 16 | }) 17 | .join('\n'); 18 | }; 19 | 20 | const tmpl = (slots: SlotDescriptor[], lang: string) => { 21 | const displayableSlots = slots; 22 | // .filter( 23 | // (slot) => slot.description || lang in (slot.tags ?? {}), 24 | // ); 25 | const hasVersion = displayableSlots.some((slot) => slot?.tags?.version); 26 | const content = displayableSlots 27 | .map((slot) => { 28 | const { name, bindings, tags } = slot; 29 | let { description } = slot; 30 | if (tags?.[lang]) { 31 | description = (tags[lang] as any).content as string; 32 | } 33 | 34 | let lineContent = `|${toKebabCase(name)}|${escapeCharacter( 35 | description || '', 36 | )}|${escapeCharacter(bindingsTmpl(bindings)) || '-'}|`; 37 | 38 | if (hasVersion) { 39 | const version = (tags?.version as any)?.content as string; 40 | lineContent += `${version || ''}|`; 41 | } 42 | 43 | return lineContent; 44 | }) 45 | .join('\n'); 46 | 47 | return { 48 | hasVersion, 49 | content, 50 | }; 51 | }; 52 | 53 | export default (slots: SlotDescriptor[], lang: string) => { 54 | const { content, hasVersion } = tmpl(slots, lang); 55 | if (!content) return ''; 56 | 57 | const header = 58 | lang === 'en' 59 | ? ['|Slot Name|Description|Parameters|', '|---|---|---|'] 60 | : ['|插槽名|描述|参数|', '|---|:---:|---|']; 61 | 62 | if (hasVersion) { 63 | header[0] += lang === 'en' ? 'version|' : '版本|'; 64 | header[1] += ':---|'; 65 | } 66 | 67 | return ` 68 | ${header[0]} 69 | ${header[1]} 70 | ${content} 71 | `; 72 | }; 73 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/utils/parse-material.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra'; 2 | import { parse } from 'comment-parser'; 3 | import { parse as babelParse } from '@babel/parser'; 4 | import path from 'path'; 5 | 6 | function getMaterialData(content: string) { 7 | const blocks = parse(content); 8 | const baseNode = babelParse(content, { 9 | sourceType: 'module', 10 | }); 11 | 12 | const materialData = []; 13 | 14 | for (const block of blocks) { 15 | const data: Record = { 16 | kind: 'member', 17 | }; 18 | for (const tag of block.tags) { 19 | if (tag.tag === 'file') { 20 | data.kind = 'file'; 21 | } else { 22 | data[tag.tag] = tag.name; 23 | } 24 | } 25 | materialData.push(data); 26 | } 27 | 28 | const imports: string[] = []; 29 | for (const node of baseNode.program.body) { 30 | if (node.type === 'ImportDeclaration' && node.source?.value) { 31 | imports.push(node.source.value); 32 | } 33 | } 34 | 35 | return { materialData, imports }; 36 | } 37 | 38 | const getMaterialMdContent = (materialData: Record) => { 39 | return `\`\`\`json type=description\n${JSON.stringify( 40 | materialData, 41 | null, 42 | 2 43 | )}\n\`\`\`\n`; 44 | }; 45 | 46 | async function getDemoMdContent(filename: string) { 47 | const code = await fs.readFile(filename, 'utf8'); 48 | return `\`\`\`vue\n${code}\n\`\`\`\n`; 49 | } 50 | 51 | export default async function parseMaterial( 52 | content: string, 53 | { matcher, dirname }: { matcher: RegExp; dirname: string } 54 | ) { 55 | const match = content.match(matcher); 56 | if (match && match[1]) { 57 | const filename = path.resolve(dirname, match[1]); 58 | const demoDirname = path.dirname(filename); 59 | const indexContent = await fs.readFile(filename, 'utf8'); 60 | const { materialData, imports } = getMaterialData(indexContent); 61 | let result = `${getMaterialMdContent(materialData)}\n`; 62 | 63 | for (const item of imports) { 64 | const filename = path.resolve(demoDirname, item); 65 | result += `${await getDemoMdContent(filename)}\n`; 66 | } 67 | 68 | return content.replace(match[0], result); 69 | } 70 | return content; 71 | } 72 | -------------------------------------------------------------------------------- /packages/vitepress-demo-block/src/Demo.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/vite-plugin-gen-api-doc 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | - Updated dependencies 9 | - @ruabick/utils@0.3.3 10 | 11 | ## 0.3.2 12 | 13 | ### Patch Changes 14 | 15 | - adapt viteptess 0.7.2 beta 16 | - Updated dependencies 17 | - @ruabick/utils@0.3.2 18 | 19 | ## 0.3.1 20 | 21 | ### Patch Changes 22 | 23 | - fix create-vlib `pnpm serve` bug 24 | - Updated dependencies 25 | - @ruabick/utils@0.3.1 26 | 27 | ## 0.3.0 28 | 29 | ### Minor Changes 30 | 31 | - #fix 18 #20 32 | 33 | ### Patch Changes 34 | 35 | - Updated dependencies 36 | - @ruabick/utils@0.3.0 37 | 38 | ## 0.2.9 39 | 40 | ### Patch Changes 41 | 42 | - fix #13 43 | - Updated dependencies 44 | - @ruabick/utils@0.2.9 45 | 46 | ## 0.2.8 47 | 48 | ### Patch Changes 49 | 50 | - fix: #6 51 | - Updated dependencies 52 | - @ruabick/utils@0.2.8 53 | 54 | ## 0.2.7 55 | 56 | ### Patch Changes 57 | 58 | - 0.2.7 59 | - Updated dependencies 60 | - @ruabick/utils@0.2.7 61 | 62 | ## 0.2.6 63 | 64 | ### Patch Changes 65 | 66 | - support monorepo 67 | - Updated dependencies 68 | - @ruabick/utils@0.2.6 69 | 70 | ## 0.2.5 71 | 72 | ### Patch Changes 73 | 74 | - fix 75 | - Updated dependencies 76 | - @ruabick/utils@0.2.5 77 | 78 | ## 0.2.4 79 | 80 | ### Patch Changes 81 | 82 | - v0.2.4 83 | - Updated dependencies 84 | - @ruabick/utils@0.2.4 85 | 86 | ## 0.2.3 87 | 88 | ### Patch Changes 89 | 90 | - add ts library template 91 | - Updated dependencies 92 | - @ruabick/utils@0.2.3 93 | 94 | ## 0.2.2 95 | 96 | ### Patch Changes 97 | 98 | - fix initial scan error 99 | - Updated dependencies 100 | - @ruabick/utils@0.2.2 101 | 102 | ## 0.2.1 103 | 104 | ### Patch Changes 105 | 106 | - 5a61563: add --srcDir args 107 | - Updated dependencies [5a61563] 108 | - @ruabick/utils@0.2.1 109 | 110 | ## 0.2.0 111 | 112 | ### Minor Changes 113 | 114 | - v0.2 115 | 116 | ### Patch Changes 117 | 118 | - Updated dependencies 119 | - @ruabick/utils@0.2.0 120 | 121 | ## 0.1.5 122 | 123 | ### Patch Changes 124 | 125 | - template update 126 | - Updated dependencies 127 | - @ruabick/utils@0.1.5 128 | 129 | ## 0.1.4 130 | 131 | ### Patch Changes 132 | 133 | - fix bugs 134 | - Updated dependencies 135 | - @ruabick/utils@0.1.4 136 | 137 | ## 0.1.3 138 | 139 | ### Patch Changes 140 | 141 | - Support api auto generation. 142 | - Updated dependencies 143 | - @ruabick/utils@0.1.3 144 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/templates/events.ts: -------------------------------------------------------------------------------- 1 | import { EventDescriptor, Tag } from 'vue-docgen-api'; 2 | import { escapeCharacter, toKebabCase } from '../utils'; 3 | 4 | const propertiesTmpl = (properties: EventDescriptor['properties']): string => { 5 | return (properties || []) 6 | .map((property) => { 7 | const { type, name, description } = property; 8 | const res: any[] = []; 9 | name && res.push(name); 10 | if (type.names.length) { 11 | res.length && res.push(': '); 12 | res.push(`\`${type.names.join(' | ')}\``); 13 | } 14 | description && res.push(description); 15 | return res.join(''); 16 | }) 17 | .join('\n'); 18 | }; 19 | 20 | const tmpl = (events: EventDescriptor[], lang: string) => { 21 | const displayableEvents = events; 22 | // .filter( 23 | // (event) => event.description || event.tags?.length, 24 | // ); 25 | const hasVersion = displayableEvents.some((event) => 26 | event?.tags?.some((tag) => tag.title === 'version'), 27 | ); 28 | const content = displayableEvents 29 | .map((event) => { 30 | const { name, tags } = event; 31 | let { description } = event; 32 | let version = ''; 33 | if (tags?.length) { 34 | for (const item of tags) { 35 | if (item.title === 'version') { 36 | version = (item as Tag).content as string; 37 | continue; 38 | } 39 | if (item.title === lang) { 40 | description = (item as Tag).content as string; 41 | } 42 | } 43 | } 44 | 45 | let lineContent = `|${toKebabCase(name)}|${escapeCharacter( 46 | description || '', 47 | )}|${escapeCharacter(propertiesTmpl(event.properties)) || '-'}|`; 48 | 49 | if (hasVersion) { 50 | lineContent += `${version}|`; 51 | } 52 | 53 | return lineContent; 54 | }) 55 | .join('\n'); 56 | return { 57 | content, 58 | hasVersion, 59 | }; 60 | }; 61 | 62 | export default (events: EventDescriptor[], lang: string) => { 63 | const { content, hasVersion } = tmpl(events, lang); 64 | if (!content) return ''; 65 | 66 | const header = 67 | lang === 'en' 68 | ? ['|Event Name|Description|Parameters|', '|---|---|---|'] 69 | : ['|事件名|描述|参数|', '|---|---|---|']; 70 | 71 | if (hasVersion) { 72 | header[0] += lang === 'en' ? 'version|' : '版本|'; 73 | header[1] += ':---|'; 74 | } 75 | 76 | return ` 77 | ${header[0]} 78 | ${header[1]} 79 | ${content} 80 | `; 81 | }; 82 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from 'vite'; 2 | import { 3 | LocaleConfigs, 4 | parseProps, 5 | resolveLocaleConfigs, 6 | } from '@ruabick/utils'; 7 | import MarkdownIt from 'markdown-it'; 8 | import matter from 'gray-matter'; 9 | import { dirname, resolve } from 'node:path'; 10 | import { getApiTmpl } from './getApiTmpl'; 11 | import { parse as parseVue } from 'vue-docgen-api'; 12 | import parseInterface from './utils/parse-interface'; 13 | 14 | const API_REG = /^|\/>)$/; 15 | const LOG_PREFIX = '[ruabick:gen-doc-api]'; 16 | 17 | export function genApiDoc(): Plugin { 18 | let localeConfigs: LocaleConfigs; 19 | let md: MarkdownIt; 20 | 21 | return { 22 | name: 'gen-api-doc', 23 | enforce: 'pre', 24 | configResolved: async (config) => { 25 | localeConfigs = await resolveLocaleConfigs(config.root); 26 | md = new MarkdownIt('zero'); 27 | }, 28 | transform: async (code, id) => { 29 | if (!id.endsWith('.md')) { 30 | return null; 31 | } 32 | 33 | const { data: frontmatter, content } = matter(code); 34 | const baseDir = frontmatter.realPath 35 | ? dirname(frontmatter.realPath) 36 | : __dirname; 37 | 38 | const blocks = md.parse(content, {}).map((i) => i.content); 39 | const replacedBlocks: string[] = []; 40 | 41 | for (const block of blocks) { 42 | if (!block.match(API_REG)) { 43 | replacedBlocks.push(block); 44 | } else { 45 | replacedBlocks.push( 46 | await getApiMarkdown(block, localeConfigs, baseDir), 47 | ); 48 | } 49 | } 50 | 51 | const replacedCode = matter.stringify(replacedBlocks.join('\n'), { 52 | ...frontmatter, 53 | }); 54 | 55 | return replacedCode; 56 | }, 57 | }; 58 | } 59 | 60 | async function getApiMarkdown( 61 | apiComponent: string, 62 | localeConfigs: LocaleConfigs, 63 | baseDir: string, 64 | ) { 65 | const props = parseProps(apiComponent); 66 | 67 | const lang = 68 | props.lang ?? (localeConfigs.defaultLang.includes('zh') ? 'zh' : 'en'); 69 | 70 | if (!props.src) { 71 | console.error(`${LOG_PREFIX} "${apiComponent}" missing src props.`); 72 | return apiComponent; 73 | } 74 | 75 | const srcPath = resolve(baseDir, props.src); 76 | 77 | const componentDoc = 78 | srcPath.endsWith('.vue') || srcPath.endsWith('.tsx') 79 | ? await parseVue(srcPath) 80 | : await parseInterface(srcPath); 81 | 82 | const apiMdContents = await getApiTmpl(componentDoc, 'component', lang); 83 | 84 | return apiMdContents || `${srcPath}'s api is empty!`; 85 | } 86 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/md-demo-plugins 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | - Updated dependencies 9 | - @ruabick/utils@0.3.3 10 | 11 | ## 0.3.2 12 | 13 | ### Patch Changes 14 | 15 | - adapt viteptess 0.7.2 beta 16 | - Updated dependencies 17 | - @ruabick/utils@0.3.2 18 | 19 | ## 0.3.1 20 | 21 | ### Patch Changes 22 | 23 | - fix create-vlib `pnpm serve` bug 24 | - Updated dependencies 25 | - @ruabick/utils@0.3.1 26 | 27 | ## 0.3.0 28 | 29 | ### Minor Changes 30 | 31 | - #fix 18 #20 32 | 33 | ### Patch Changes 34 | 35 | - Updated dependencies 36 | - @ruabick/utils@0.3.0 37 | 38 | ## 0.2.9 39 | 40 | ### Patch Changes 41 | 42 | - fix #13 43 | - Updated dependencies 44 | - @ruabick/utils@0.2.9 45 | 46 | ## 0.2.8 47 | 48 | ### Patch Changes 49 | 50 | - fix: #6 51 | - Updated dependencies 52 | - @ruabick/utils@0.2.8 53 | 54 | ## 0.2.7 55 | 56 | ### Patch Changes 57 | 58 | - 0.2.7 59 | - Updated dependencies 60 | - @ruabick/utils@0.2.7 61 | 62 | ## 0.2.6 63 | 64 | ### Patch Changes 65 | 66 | - support monorepo 67 | - Updated dependencies 68 | - @ruabick/utils@0.2.6 69 | 70 | ## 0.2.5 71 | 72 | ### Patch Changes 73 | 74 | - fix 75 | - Updated dependencies 76 | - @ruabick/utils@0.2.5 77 | 78 | ## 0.2.4 79 | 80 | ### Patch Changes 81 | 82 | - v0.2.4 83 | - Updated dependencies 84 | - @ruabick/utils@0.2.4 85 | 86 | ## 0.2.3 87 | 88 | ### Patch Changes 89 | 90 | - add ts library template 91 | - Updated dependencies 92 | - @ruabick/utils@0.2.3 93 | 94 | ## 0.2.2 95 | 96 | ### Patch Changes 97 | 98 | - fix initial scan error 99 | - Updated dependencies 100 | - @ruabick/utils@0.2.2 101 | 102 | ## 0.2.1 103 | 104 | ### Patch Changes 105 | 106 | - 5a61563: add --srcDir args 107 | - Updated dependencies [5a61563] 108 | - @ruabick/utils@0.2.1 109 | 110 | ## 0.2.0 111 | 112 | ### Minor Changes 113 | 114 | - v0.2 115 | 116 | ### Patch Changes 117 | 118 | - Updated dependencies 119 | - @ruabick/utils@0.2.0 120 | 121 | ## 0.1.5 122 | 123 | ### Patch Changes 124 | 125 | - template update 126 | - Updated dependencies 127 | - @ruabick/utils@0.1.5 128 | 129 | ## 0.1.4 130 | 131 | ### Patch Changes 132 | 133 | - fix bugs 134 | - Updated dependencies 135 | - @ruabick/utils@0.1.4 136 | 137 | ## 0.1.3 138 | 139 | ### Patch Changes 140 | 141 | - Support api auto generation. 142 | - Updated dependencies 143 | - @ruabick/utils@0.1.3 144 | 145 | ## 0.1.2 146 | 147 | ### Patch Changes 148 | 149 | - build 150 | 151 | ## 0.1.1 152 | 153 | ### Patch Changes 154 | 155 | - 5852508: bug fix 156 | 157 | ## 0.1.0 158 | 159 | ### Minor Changes 160 | 161 | - rename package 162 | 163 | ### Patch Changes 164 | 165 | - fc64aac: add create-vlib 166 | 167 | ## 0.0.2 168 | 169 | ### Patch Changes 170 | 171 | - first publish 172 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @ruabick/vite-plugin-gen-temp 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - build 8 | - Updated dependencies 9 | - @ruabick/utils@0.3.3 10 | 11 | ## 0.3.2 12 | 13 | ### Patch Changes 14 | 15 | - adapt viteptess 0.7.2 beta 16 | - Updated dependencies 17 | - @ruabick/utils@0.3.2 18 | 19 | ## 0.3.1 20 | 21 | ### Patch Changes 22 | 23 | - fix create-vlib `pnpm serve` bug 24 | - Updated dependencies 25 | - @ruabick/utils@0.3.1 26 | 27 | ## 0.3.0 28 | 29 | ### Minor Changes 30 | 31 | - #fix 18 #20 32 | 33 | ### Patch Changes 34 | 35 | - Updated dependencies 36 | - @ruabick/utils@0.3.0 37 | 38 | ## 0.2.9 39 | 40 | ### Patch Changes 41 | 42 | - fix #13 43 | - Updated dependencies 44 | - @ruabick/utils@0.2.9 45 | 46 | ## 0.2.8 47 | 48 | ### Patch Changes 49 | 50 | - fix: #6 51 | - Updated dependencies 52 | - @ruabick/utils@0.2.8 53 | 54 | ## 0.2.7 55 | 56 | ### Patch Changes 57 | 58 | - 0.2.7 59 | - Updated dependencies 60 | - @ruabick/utils@0.2.7 61 | 62 | ## 0.2.6 63 | 64 | ### Patch Changes 65 | 66 | - support monorepo 67 | - Updated dependencies 68 | - @ruabick/utils@0.2.6 69 | 70 | ## 0.2.5 71 | 72 | ### Patch Changes 73 | 74 | - fix 75 | - Updated dependencies 76 | - @ruabick/utils@0.2.5 77 | 78 | ## 0.2.4 79 | 80 | ### Patch Changes 81 | 82 | - v0.2.4 83 | - Updated dependencies 84 | - @ruabick/utils@0.2.4 85 | 86 | ## 0.2.3 87 | 88 | ### Patch Changes 89 | 90 | - add ts library template 91 | - Updated dependencies 92 | - @ruabick/utils@0.2.3 93 | 94 | ## 0.2.2 95 | 96 | ### Patch Changes 97 | 98 | - fix initial scan error 99 | - Updated dependencies 100 | - @ruabick/utils@0.2.2 101 | 102 | ## 0.2.1 103 | 104 | ### Patch Changes 105 | 106 | - 5a61563: add --srcDir args 107 | - Updated dependencies [5a61563] 108 | - @ruabick/utils@0.2.1 109 | 110 | ## 0.2.0 111 | 112 | ### Minor Changes 113 | 114 | - v0.2 115 | 116 | ### Patch Changes 117 | 118 | - Updated dependencies 119 | - @ruabick/utils@0.2.0 120 | 121 | ## 0.1.5 122 | 123 | ### Patch Changes 124 | 125 | - template update 126 | - Updated dependencies 127 | - @ruabick/utils@0.1.5 128 | 129 | ## 0.1.4 130 | 131 | ### Patch Changes 132 | 133 | - fix bugs 134 | - Updated dependencies 135 | - @ruabick/utils@0.1.4 136 | 137 | ## 0.1.3 138 | 139 | ### Patch Changes 140 | 141 | - Support api auto generation. 142 | - Updated dependencies 143 | - @ruabick/utils@0.1.3 144 | 145 | ## 0.1.2 146 | 147 | ### Patch Changes 148 | 149 | - build 150 | 151 | ## 0.1.1 152 | 153 | ### Patch Changes 154 | 155 | - 5852508: bug fix 156 | 157 | ## 0.1.0 158 | 159 | ### Minor Changes 160 | 161 | - rename package 162 | 163 | ### Patch Changes 164 | 165 | - fc64aac: add create-vlib 166 | 167 | ## 0.0.2 168 | 169 | ### Patch Changes 170 | 171 | - first publish 172 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/templates/methods.ts: -------------------------------------------------------------------------------- 1 | import { MethodDescriptor, ParamTag, ParamType } from 'vue-docgen-api'; 2 | import { escapeCharacter } from '../utils'; 3 | 4 | const paramsTmpl = (params: MethodDescriptor['params']): string => { 5 | return (params || []) 6 | .filter((param) => param.type) 7 | .map((param): string => { 8 | const { name, type, description } = param; 9 | const res: any[] = []; 10 | name && res.push(name); 11 | if (type?.name) { 12 | res.length && res.push(': '); 13 | res.push(`\`${type.name}\``); 14 | } 15 | description && res.push(description); 16 | return res.join(''); 17 | }) 18 | .join('\n'); 19 | }; 20 | 21 | const returnsTmpl = (returns: MethodDescriptor['returns']): string => { 22 | if (!returns) return ''; 23 | 24 | const { type, description } = returns; 25 | 26 | if (!type) return ''; 27 | 28 | const getNames = (type: ParamType): string => { 29 | const { name, elements } = type; 30 | if (!elements || !elements.length) return name || ''; 31 | 32 | const names: string[] = []; 33 | elements.forEach((element) => { 34 | names.push(getNames(element)); 35 | }); 36 | 37 | return `${name}\\<${names.join(',')}\\>`; 38 | }; 39 | 40 | const res = [ 41 | type.name ? `${getNames(type)}` : '', 42 | description ? ` - ${description}` : '', 43 | ]; 44 | return res.join(''); 45 | }; 46 | 47 | const tmpl = (methods: MethodDescriptor[], lang: string) => { 48 | const displayableMethods = methods.filter( 49 | (method) => method.description || lang in (method.tags ?? {}), 50 | ); 51 | const hasVersion = displayableMethods.some((method) => method?.tags?.version); 52 | const content = displayableMethods 53 | .map((method) => { 54 | const { name, tags } = method; 55 | let { description } = method; 56 | if (tags?.[lang]?.length) { 57 | description = (tags[lang][0] as ParamTag).description as string; 58 | } 59 | 60 | const readableParams = paramsTmpl(method.params) || '-'; 61 | const readableReturns = returnsTmpl(method.returns) || '-'; 62 | let lineContent = `|${name}|${escapeCharacter( 63 | description || '', 64 | )}|${escapeCharacter(readableParams)}|${escapeCharacter( 65 | readableReturns, 66 | )}|`; 67 | 68 | if (hasVersion) { 69 | const version = (tags?.version?.[0] as ParamTag)?.description as string; 70 | lineContent += `${version || ''}|`; 71 | } 72 | 73 | return lineContent; 74 | }) 75 | .join('\n'); 76 | 77 | return { 78 | hasVersion, 79 | content, 80 | }; 81 | }; 82 | 83 | export default (methods: MethodDescriptor[], lang: string) => { 84 | const { content, hasVersion } = tmpl(methods, lang); 85 | if (!content) return ''; 86 | 87 | const header = 88 | lang === 'en' 89 | ? ['|Method|Description|Parameters|Return|', '|---|---|---|:---:|'] 90 | : ['|方法名|描述|参数|返回值|', '|---|---|---|---|']; 91 | 92 | if (hasVersion) { 93 | header[0] += lang === 'en' ? 'version|' : '版本|'; 94 | header[1] += ':---|'; 95 | } 96 | 97 | return ` 98 | ${header[0]} 99 | ${header[1]} 100 | ${content} 101 | `; 102 | }; 103 | -------------------------------------------------------------------------------- /packages/md-demo-plugins/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { DemoInfos } from './types'; 2 | import fsExtra from 'fs-extra'; 3 | import { dirname, join, sep } from 'path'; 4 | import { MarkdownRenderer } from 'vitepress'; 5 | import { DemoTag } from './constants'; 6 | 7 | const scriptRE = /<\/script>/; 8 | const scriptLangTsRE = /<\s*script[^>]*\blang=['"]ts['"][^>]*/; 9 | const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/; 10 | const scriptClientRE = /<\s*script[^>]*\bclient\b[^>]*/; 11 | 12 | let index = 1; 13 | export function getDemoComponent( 14 | md: MarkdownRenderer, 15 | env: any, // TODO 16 | { title, desc, path, code }: DemoInfos, 17 | ) { 18 | const componentName = `DemoComponent${index++}`; 19 | 20 | path = normalizePath(path); 21 | 22 | injectImportStatement(env, componentName, path); 23 | 24 | const highlightedCode = md.options.highlight!(code, 'vue', ''); 25 | return ` 26 | <${DemoTag} 27 | code="${encodeURIComponent(code)}" 28 | highlightedCode="${encodeURIComponent(highlightedCode)}" 29 | src="${path}" 30 | title="${title ?? ''}" 31 | desc="${desc ?? ''}" 32 | > 33 | <${componentName}> 34 | 35 | `.trim(); 36 | } 37 | 38 | let fenceIndex = 1; 39 | const codeFileMap: Record = {}; 40 | 41 | export function genDemoByCode( 42 | md: MarkdownRenderer, 43 | env: any, 44 | path: string, 45 | code: string, 46 | ) { 47 | let { demoName = '', demoPath = '' } = codeFileMap[code] ?? {}; 48 | 49 | if (!codeFileMap[code]) { 50 | while (true) { 51 | demoName = `demo-${fenceIndex++}.vue`; 52 | demoPath = join(dirname(path), 'dist', demoName); 53 | if (!fsExtra.existsSync(demoPath)) { 54 | break; 55 | } 56 | } 57 | 58 | fsExtra.createFileSync(demoPath); 59 | fsExtra.writeFileSync(demoPath, code); 60 | 61 | codeFileMap[code] = { 62 | demoName, 63 | demoPath, 64 | }; 65 | } 66 | 67 | return getDemoComponent(md, env, { 68 | path: demoPath, 69 | code, 70 | }); 71 | } 72 | 73 | function injectImportStatement( 74 | env: any, // TODO this should import from vitepress 75 | componentName: string, 76 | path: string, 77 | ) { 78 | const componentRegistStatement = 79 | `import ${componentName} from '${path}'`.trim(); 80 | 81 | if (!env.sfcBlocks.scripts) { 82 | env.sfcBlocks.scripts = []; 83 | } 84 | // TODO type 85 | const tags = env.sfcBlocks.scripts as { content: string }[]; 86 | 87 | const isUsingTS = 88 | tags.findIndex((tag) => scriptLangTsRE.test(tag.content)) > -1; 89 | const existingSetupScriptIndex = tags?.findIndex((tag) => { 90 | return ( 91 | scriptRE.test(tag.content) && 92 | scriptSetupRE.test(tag.content) && 93 | !scriptClientRE.test(tag.content) 94 | ); 95 | }); 96 | 97 | if (existingSetupScriptIndex > -1) { 98 | const tagSrc = tags[existingSetupScriptIndex]; 99 | tags[existingSetupScriptIndex].content = tagSrc.content.replace( 100 | scriptRE, 101 | `${componentRegistStatement} 102 | 103 | `, 104 | ); 105 | } else { 106 | tags.unshift({ 107 | content: ` 108 | 111 | `.trim(), 112 | }); 113 | } 114 | } 115 | 116 | function normalizePath(path: string) { 117 | return path.split(sep).join('/'); 118 | } 119 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-temp/src/handleCopy.ts: -------------------------------------------------------------------------------- 1 | import { yellow, dim, green, red } from 'colorette'; 2 | import { basename, dirname, extname, join } from 'path'; 3 | import { Options } from './types'; 4 | import matter from 'gray-matter'; 5 | import fsExtra from 'fs-extra'; 6 | import { LOG_PREFIX } from './utils'; 7 | import { LocaleConfigs } from '@ruabick/utils'; 8 | 9 | export async function handleCopy( 10 | dir: string, 11 | path: string, 12 | { 13 | options, 14 | localeConfigs, 15 | }: { 16 | options: Required; 17 | localeConfigs: LocaleConfigs; 18 | }, 19 | ) { 20 | const { tempDir } = options; 21 | 22 | let destPath; 23 | if (!path.endsWith('.md')) { 24 | destPath = join(tempDir, path.replace(new RegExp(`^${dir}`), '')); 25 | await fsExtra.copy(path, destPath); 26 | } else { 27 | const { finnalPath, finnalContent } = await resolveFrontmatter( 28 | path, 29 | tempDir, 30 | dir, 31 | ); 32 | 33 | const fileInLangDir = handleLangSuffix(finnalPath, localeConfigs); 34 | 35 | destPath = join(tempDir, fileInLangDir); 36 | 37 | await fsExtra.ensureFile(destPath); 38 | await fsExtra.writeFile(destPath, finnalContent); 39 | } 40 | 41 | console.log(`${LOG_PREFIX} ${green('copy')} ${path} → ${destPath}`); 42 | } 43 | 44 | const checkDestFileExist = async (path: string, destPath) => { 45 | const exist = await fsExtra.pathExists(destPath); 46 | if (exist) { 47 | console.error( 48 | `${LOG_PREFIX} Error: ${red( 49 | `Trying to copy "${yellow(path)}" to "${yellow( 50 | destPath, 51 | )}", but "${yellow(destPath)}" already exists.`, 52 | )}`, 53 | ); 54 | } 55 | return !exist; 56 | }; 57 | 58 | async function resolveFrontmatter(path: string, tempDir: string, dir: string) { 59 | // TODO cache it 60 | const originalContent = await fsExtra.readFile(path, 'utf-8'); 61 | const { content, data: frontmatter } = matter(originalContent); 62 | 63 | const realPath = path; 64 | let finnalPath; 65 | let mappingPath = frontmatter.mapping?.path ?? frontmatter.map?.path; 66 | 67 | if (mappingPath) { 68 | if (!mappingPath.endsWith('.md')) { 69 | mappingPath = join(mappingPath, basename(path)); 70 | } 71 | finnalPath = mappingPath; 72 | } else { 73 | finnalPath = path.replace(new RegExp(`^${dir}`), ''); 74 | } 75 | 76 | const finnalContent = matter.stringify(content, { 77 | ...(frontmatter ?? {}), 78 | realPath, 79 | }); 80 | 81 | return { 82 | finnalPath, 83 | finnalContent, 84 | }; 85 | } 86 | 87 | function handleLangSuffix(path: string, localeConfigs: LocaleConfigs) { 88 | const { defaultLang, langToPathMap } = localeConfigs; 89 | if (!Object.keys(langToPathMap).length) { 90 | return path; 91 | } 92 | 93 | const fileName = basename(path); 94 | const dir = dirname(path); 95 | const fileNameWithoutMd = fileName.replace(/\.md$/, ''); 96 | 97 | const fileExtname = extname(fileNameWithoutMd); 98 | const langSuffix = fileExtname.slice(1) || defaultLang; 99 | 100 | const langPath = langToPathMap[langSuffix]; 101 | if (!langPath) { 102 | console.log( 103 | yellow( 104 | `${fileName} has a ${fileExtname} suffix. But ${langSuffix} not defined in locales`, 105 | ) + dim(` .vitepress.config.js`), 106 | ); 107 | return path; 108 | } 109 | 110 | const fileNameWithoutLangSuffix = 111 | fileNameWithoutMd.slice(0, -fileExtname.length || undefined) + '.md'; 112 | 113 | return join(langPath, dir, fileNameWithoutLangSuffix); 114 | } 115 | -------------------------------------------------------------------------------- /packages/vite-plugin-gen-api-doc/src/templates/props.ts: -------------------------------------------------------------------------------- 1 | import { ParamTag, PropDescriptor } from 'vue-docgen-api'; 2 | import { 3 | escapeCharacter, 4 | toKebabCase, 5 | unquote, 6 | trimStr, 7 | cleanStr, 8 | } from '../utils'; 9 | 10 | const tmpl = ( 11 | props: PropDescriptor[], 12 | { isInterface = false }: { isInterface: boolean }, 13 | lang: string, 14 | ) => { 15 | const displayableProps = props; 16 | // .filter( 17 | // ({ name, description, tags }) => 18 | // description || ['disabled'].includes(name) || lang in (tags ?? {}) 19 | // ); 20 | const hasVersion = displayableProps.some((prop) => prop?.tags?.version); 21 | const content = displayableProps 22 | .map((prop) => { 23 | const { name, type, values, defaultValue, required, tags } = prop; 24 | let { description } = prop; 25 | if (tags?.[lang]?.length) { 26 | description = (tags[lang][0] as ParamTag).description as string; 27 | } 28 | 29 | // 支持通过名为 type 的 tag 重新定义字段的类型 30 | const fixedType = cleanStr( 31 | // tag 的 ts 类型有问题,所以忽略 ts 规则检查 32 | // @ts-ignore-next-line 33 | trimStr(tags?.type?.[0]?.description || type?.name || ''), 34 | ); 35 | 36 | const getName = () => 37 | `${isInterface ? name : toKebabCase(name)}${ 38 | tags?.vModel || name === 'modelValue' ? ' **(v-model)**' : '' 39 | }${ 40 | required ? (lang === 'zh' ? ' **(必填)**' : ' **(required)**') : '' 41 | }`; 42 | 43 | const getDescription = () => { 44 | if (!description && name === 'disabled') { 45 | return lang === 'zh' ? '是否禁用' : 'Whether to disable'; 46 | } 47 | 48 | return escapeCharacter(trimStr(description || '')); 49 | }; 50 | 51 | const getType = () => { 52 | if (values) { 53 | return escapeCharacter( 54 | values 55 | .map((item) => { 56 | const fixItem = 57 | fixedType === 'string' ? `'${unquote(item)}'` : item; 58 | return fixItem; 59 | }) 60 | .join(' | '), 61 | ); 62 | } 63 | return escapeCharacter(fixedType); 64 | }; 65 | 66 | const getDefaultValue = () => { 67 | if (tags?.defaultValue) { 68 | // @ts-ignore-next-line 69 | return tags.defaultValue[0]?.description; 70 | } 71 | 72 | if (defaultValue?.value === 'undefined') { 73 | return '-'; 74 | } 75 | 76 | const regForArrayDefaultValue = /^\(\)\s*=>\s*(\[[^]*\]*\])$/; 77 | if ( 78 | (fixedType.includes('[]') || 79 | fixedType.includes('Array') || 80 | fixedType.includes('array')) && 81 | defaultValue?.func && 82 | regForArrayDefaultValue.test(defaultValue.value) 83 | ) { 84 | return cleanStr( 85 | defaultValue.value.match(regForArrayDefaultValue)?.[1] || '', 86 | ); 87 | } 88 | 89 | if (fixedType === 'boolean') { 90 | return cleanStr(defaultValue?.value || 'false'); 91 | } 92 | 93 | return defaultValue?.value || '-'; 94 | }; 95 | 96 | let lineContent = `|${getName()}|${getDescription()}|\`${getType()}\`|\`${getDefaultValue()}\`|`; 97 | 98 | if (hasVersion) { 99 | // tag 的 ts 类型有问题,所以忽略 ts 规则检查 100 | // @ts-ignore-next-line 101 | const version = tags?.version?.[0]?.description; 102 | lineContent += `${version || ''}|`; 103 | } 104 | 105 | return lineContent; 106 | }) 107 | .join('\n'); 108 | return { 109 | hasVersion, 110 | content, 111 | }; 112 | }; 113 | 114 | export default ( 115 | props: PropDescriptor[], 116 | options: { isInterface: boolean }, 117 | lang = 'zh', 118 | ) => { 119 | const { content, hasVersion } = tmpl(props, options, lang); 120 | if (!content) return ''; 121 | 122 | let header: [string, string] = ['', '']; 123 | if (lang === 'en') { 124 | header = options.isInterface 125 | ? ['|Name|Description|Type|Default|', '|---|---|---|:---:|'] 126 | : ['|Attribute|Description|Type|Default|', '|---|---|---|:---:|']; 127 | if (hasVersion) { 128 | header[0] += 'version|'; 129 | header[1] += ':---|'; 130 | } 131 | } else { 132 | header = ['|参数名|描述|类型|默认值|', '|---|---|---|:---:|']; 133 | if (hasVersion) { 134 | header[0] += '版本|'; 135 | header[1] += ':---|'; 136 | } 137 | } 138 | 139 | return ` 140 | ${header[0]} 141 | ${header[1]} 142 | ${content} 143 | `; 144 | }; 145 | --------------------------------------------------------------------------------