diff --git a/.gitignore b/.gitignore index 7db53e38e91e812e04b17ba4da0bff69cc00e2d7..fa4da9be8f31c1d453cab0e49a160bcb5e584c34 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ yarn-error.log packages/devui-vue/devui/vue-devui.ts packages/devui-vue/devui/theme/theme.scss packages/devui-vue/docs/.vitepress/config/sidebar.ts +/packages/devui-cli/lib/ diff --git a/README.md b/README.md index 7032a70ee6a51adac432ab6b7df70bea3d641396..a930fe3ad9699f981e3cebadf5f9b352de1d0cd5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- DevUI Logo + DevUI Logo

diff --git a/package.json b/package.json index 05e54180e333e016861f725422283e2fa6f925e4..89d20a4803ba8ba21e061c95c090e031a395598a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,9 @@ "name": "root", "private": true, "scripts": { - "dev": "lerna run dev", + "prepare": "yarn build:cli", + "build:cli": "lerna exec --scope @devui/cli yarn build", + "dev": "lerna exec --scope vue-devui yarn dev", "build": "lerna run build", "build:lib": "lerna run build:lib" }, diff --git a/packages/devui-cli/README.md b/packages/devui-cli/README.md new file mode 100644 index 0000000000000000000000000000000000000000..396c156323d35cb97645e695fd67aac08d54f609 --- /dev/null +++ b/packages/devui-cli/README.md @@ -0,0 +1,3 @@ +# devui-cli + +devui-cli diff --git a/packages/devui-cli/bin.js b/packages/devui-cli/bin.js new file mode 100755 index 0000000000000000000000000000000000000000..3bd8a4236df14e12ab0f9cad53212b3c6d92e4e2 --- /dev/null +++ b/packages/devui-cli/bin.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require("./lib/bin"); diff --git a/packages/devui-cli/package.json b/packages/devui-cli/package.json new file mode 100644 index 0000000000000000000000000000000000000000..187c7a92cc412fd722ac8e7a5f5ad0f42f618dcf --- /dev/null +++ b/packages/devui-cli/package.json @@ -0,0 +1,30 @@ +{ + "name": "@devui/cli", + "version": "1.0.0", + "license": "MIT", + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "bin": { + "devui-cli": "./bin.js" + }, + "scripts": { + "dev": "tsc --watch", + "build": "tsc" + }, + "devDependencies": { + "@types/chalk": "^2.2.0", + "@types/commander": "^2.12.2", + "@types/ora": "^3.2.0", + "@types/node": "^14.11.8", + "@types/fs-extra": "^9.0.2", + "@babel/traverse": "^7.15.4", + "@babel/parser": "^7.15.5", + "@types/babel-traverse": "^6.25.7", + "vite": "^2.4.4", + "chalk": "^4.1.2", + "commander": "^8.1.0", + "inquirer": "^8.1.2", + "ora": "^5.4.1", + "typescript": "^4.3.2" + } +} diff --git a/packages/devui-cli/src/bin.ts b/packages/devui-cli/src/bin.ts new file mode 100644 index 0000000000000000000000000000000000000000..79eaabc8d40a56899c9f971fadc03ad44999c6f2 --- /dev/null +++ b/packages/devui-cli/src/bin.ts @@ -0,0 +1,33 @@ +#!/usr/bin/env node +import { Command } from "commander"; +import { create, validateCreateType } from "./commands/create"; +import { generateTheme } from "./commands/generate-theme"; +import { CREATE_SUPPORT_TYPES, VERSION } from "./shared/constant"; + +import {build} from '.'; + + +const program = new Command(); + +program.version(VERSION); + +program + .command("create") + .description("创建一个组件模板或配置文件") + .option( + "-t --type ", + `创建类型,可选值:${CREATE_SUPPORT_TYPES.join(", ")}`, + validateCreateType + ) + .option("--ignore-parse-error", "忽略解析错误", false) + .option("--cover", "覆盖原文件", false) + .action(create); + +program.command("build").description("打包组件库").action(build); + +program + .command("generate:theme") + .description("生成主题变量文件") + .action(generateTheme); + +program.parse().version(VERSION); diff --git a/packages/devui-vue/devui-cli/commands/build.js b/packages/devui-cli/src/commands/build.ts similarity index 32% rename from packages/devui-vue/devui-cli/commands/build.js rename to packages/devui-cli/src/commands/build.ts index 48c472f47b673f88f715fc4b738f97ea93d45a35..362dd98437843ce1700ab35d5ea1a0a2de1b679a 100644 --- a/packages/devui-vue/devui-cli/commands/build.js +++ b/packages/devui-cli/src/commands/build.ts @@ -1,59 +1,62 @@ -const path = require('path') -const fs = require('fs') -const fsExtra = require('fs-extra') -const { defineConfig, build } = require('vite') -const vue = require('@vitejs/plugin-vue') -const vueJsx = require('@vitejs/plugin-vue-jsx') +import fs from "fs"; +import fsExtra from "fs-extra"; +import path from "path"; +import type { InlineConfig } from "vite"; +import { build as ViteBuild } from "vite"; +import { CWD } from "../shared/constant"; -const entryDir = path.resolve(__dirname, '../../devui') -const outputDir = path.resolve(__dirname, '../../build') +const vue = require("@vitejs/plugin-vue"); +const vueJsx = require("@vitejs/plugin-vue-jsx"); -const baseConfig = defineConfig({ +const entryDir = path.join(CWD, "/devui"); +const outputDir = path.join(CWD, "build"); + +const baseConfig: InlineConfig = { configFile: false, publicDir: false, - plugins: [ vue(), vueJsx() ] -}) + plugins: [vue(), vueJsx()], +}; const rollupOptions = { - external: ['vue', 'vue-router'], + external: ["vue", "vue-router"], output: { globals: { - vue: 'Vue' - } - } -} + vue: "Vue", + }, + }, +}; const buildSingle = async (name) => { - await build(defineConfig({ + await ViteBuild({ ...baseConfig, build: { rollupOptions, lib: { entry: path.resolve(entryDir, name), - name: 'index', - fileName: 'index', - formats: ['es', 'umd'] + name: "index", + fileName: "index", + formats: ["es", "umd"], }, - outDir: path.resolve(outputDir, name) - } - })) -} + outDir: path.resolve(outputDir, name), + }, + }); +}; const buildAll = async () => { - await build(defineConfig({ + await ViteBuild({ ...baseConfig, build: { rollupOptions, lib: { - entry: path.resolve(entryDir, 'vue-devui.ts'), - name: 'vue-devui', - fileName: 'vue-devui', - formats: ['es', 'umd'] + entry: path.resolve(entryDir, "vue-devui.ts"), + name: "vue-devui", + fileName: "vue-devui", + formats: ["es", "umd"], }, - outDir: outputDir - } - })) -} + outDir: outputDir, + }, + }); +}; const createPackageJson = (name) => { const fileStr = `{ @@ -62,26 +65,26 @@ const createPackageJson = (name) => { "main": "index.umd.js", "module": "index.es.js", "style": "style.css" -}` +}`; fsExtra.outputFile( path.resolve(outputDir, `${name}/package.json`), fileStr, - 'utf-8' - ) -} + "utf-8" + ); +}; -exports.build = async () => { - await buildAll() +export const build = async () => { + await buildAll(); - const components = fs.readdirSync(entryDir).filter(name => { - const componentDir = path.resolve(entryDir, name) - const isDir = fs.lstatSync(componentDir).isDirectory() - return isDir && fs.readdirSync(componentDir).includes('index.ts') - }) + const components = fs.readdirSync(entryDir).filter((name) => { + const componentDir = path.resolve(entryDir, name); + const isDir = fs.lstatSync(componentDir).isDirectory(); + return isDir && fs.readdirSync(componentDir).includes("index.ts"); + }); - for(const name of components) { - await buildSingle(name) - createPackageJson(name) + for (const name of components) { + await buildSingle(name); + createPackageJson(name); } -} +}; diff --git a/packages/devui-vue/devui-cli/commands/create.js b/packages/devui-cli/src/commands/create.ts similarity index 35% rename from packages/devui-vue/devui-cli/commands/create.js rename to packages/devui-cli/src/commands/create.ts index 91433ada765ab462e4ed653fca4eecaf3aa28150..08042ef5212b3e3c7cb215e28c58cf059af4b977 100644 --- a/packages/devui-vue/devui-cli/commands/create.js +++ b/packages/devui-cli/src/commands/create.ts @@ -1,106 +1,117 @@ -const logger = require('../shared/logger') -const { - bigCamelCase, - resolveDirFilesInfo, - parseExportByFileInfo, - parseComponentInfo -} = require('../shared/utils') -const fs = require('fs-extra') -const { resolve } = require('path') -const { - DEVUI_NAMESPACE, - DEVUI_DIR, - TESTS_DIR_NAME, - COMPONENT_PARTS_MAP, - INDEX_FILE_NAME, - DOCS_FILE_NAME, - VUE_DEVUI_FILE, - VUE_DEVUI_IGNORE_DIRS, - VUE_DEVUI_FILE_NAME, +import fs from "fs-extra"; +import inquirer from "inquirer"; +import { isEmpty, kebabCase } from "lodash"; +import ora from "ora"; +import { resolve } from "path"; +import { + selectCategory, + selectParts, + typeName, + typeTitle, +} from "../inquirers/component"; +import { selectCreateType } from "../inquirers/create"; +import { CREATE_SUPPORT_TYPES, - CREATE_UNFINISHED_TYPES, CREATE_SUPPORT_TYPE_MAP, + CREATE_UNFINISHED_TYPES, + DEVUI_DIR, + DOCS_FILE_NAME, + INDEX_FILE_NAME, SITES_COMPONENTS_DIR, + TESTS_DIR_NAME, VITEPRESS_SIDEBAR_FILE, - VITEPRESS_SIDEBAR_FILE_NAME -} = require('../shared/constant') -const { isEmpty, kebabCase } = require('lodash') -const inquirer = require('inquirer') -const { selectCreateType } = require('../inquirers/create') -const { selectCategory, selectParts, typeName, typeTitle } = require('../inquirers/component') -const { + VITEPRESS_SIDEBAR_FILE_NAME, + VUE_DEVUI_FILE, + VUE_DEVUI_FILE_NAME, + VUE_DEVUI_IGNORE_DIRS, +} from "../shared/constant"; +import { logger } from "../shared/logger"; +import { + bigCamelCase, + parseComponentInfo, + parseExportByFileInfo, + resolveDirFilesInfo, +} from "../shared/utils"; +import { createComponentTemplate, - createStyleTemplate, - createTypesTemplate, createDirectiveTemplate, - createServiceTemplate, + createDocumentTemplate, createIndexTemplate, + createServiceTemplate, + createStyleTemplate, createTestsTemplate, - createDocumentTemplate -} = require('../templates/component') -const { createVueDevuiTemplate } = require('../templates/vue-devui') -const ora = require('ora') -const { createVitepressSidebarTemplate } = require('../templates/vitepress-sidebar') + createTypesTemplate, +} from "../templates/component"; +import { createVitepressSidebarTemplate } from "../templates/vitepress-sidebar"; +import { createVueDevuiTemplate } from "../templates/vue-devui"; -exports.validateCreateType = (type) => { - const re = new RegExp('^(' + CREATE_SUPPORT_TYPES.map((t) => `(${t})`).join('|') + ')$') - const flag = re.test(type) +export const validateCreateType = (type) => { + const re = new RegExp( + "^(" + CREATE_SUPPORT_TYPES.map((t) => `(${t})`).join("|") + ")$" + ); + const flag = re.test(type); - !flag && logger.error(`类型错误,可选类型为:${CREATE_SUPPORT_TYPES.join(', ')}`) + !flag && + logger.error(`类型错误,可选类型为:${CREATE_SUPPORT_TYPES.join(", ")}`); - return flag ? type : null -} + return flag ? type : null; +}; // TODO: 待优化代码结构 -exports.create = async (cwd) => { - let { type } = cwd +export const create = async (cwd) => { + let { type } = cwd; if (isEmpty(type)) { - const result = await inquirer.prompt([selectCreateType()]) - type = result.type + const result = await inquirer.prompt([selectCreateType()]); + type = result.type; } if (CREATE_UNFINISHED_TYPES.includes(type)) { - logger.info('抱歉,该功能暂未完成!') - process.exit(0) + logger.info("抱歉,该功能暂未完成!"); + process.exit(0); } - let params = {} + let params: any = {}; try { switch (type) { case CREATE_SUPPORT_TYPE_MAP.component: - params = await inquirer.prompt([typeName(), typeTitle(), selectCategory(), selectParts()]) - params.hasComponent = params.parts.includes('component') - params.hasDirective = params.parts.includes('directive') - params.hasService = params.parts.includes('service') - - await createComponent(params, cwd) - break - case CREATE_SUPPORT_TYPE_MAP['vue-devui']: + params = await inquirer.prompt([ + typeName(), + typeTitle(), + selectCategory(), + selectParts(), + ]); + params.hasComponent = params.parts.includes("component"); + params.hasDirective = params.parts.includes("directive"); + params.hasService = params.parts.includes("service"); + + await createComponent({ params, cwd }); + break; + case CREATE_SUPPORT_TYPE_MAP["vue-devui"]: // 创建 devui/vue-devui.ts - await createVueDevui(params, cwd) + await createVueDevui(params, cwd); // 创建 docs/.vitepress/config/sidebar.ts - await createVitepressSidebar() - break + await createVitepressSidebar(); + break; default: - break + break; } } catch (e) { - logger.error(e.toString()) - process.exit(1) + logger.error(e.toString()); + process.exit(1); } -} +}; -async function createComponent(params = {}) { - let { name, hasComponent, hasDirective, hasService } = params +async function createComponent(params) { + let { name, hasComponent, hasDirective, hasService } = params; - const componentName = kebabCase(name) - const styleName = kebabCase(name) - const typesName = kebabCase(name) + '-types' - const directiveName = kebabCase(name) + '-directive' - const serviceName = kebabCase(name) + '-service' - const testName = kebabCase(name) + '.spec' + const componentName = kebabCase(name); + const styleName = kebabCase(name); + const typesName = kebabCase(name) + "-types"; + const directiveName = kebabCase(name) + "-directive"; + const serviceName = kebabCase(name) + "-service"; + const testName = kebabCase(name) + ".spec"; const _params = { ...params, @@ -109,126 +120,146 @@ async function createComponent(params = {}) { directiveName, serviceName, styleName, - testName - } - - const componentTemplate = createComponentTemplate(_params) - const styleTemplate = createStyleTemplate(_params) - const typesTemplate = createTypesTemplate(_params) - const directiveTemplate = createDirectiveTemplate(_params) - const serviceTemplate = createServiceTemplate(_params) - const indexTemplate = createIndexTemplate(_params) + testName, + }; + + const componentTemplate = createComponentTemplate(_params); + const styleTemplate = createStyleTemplate(_params); + const typesTemplate = createTypesTemplate(_params); + const directiveTemplate = createDirectiveTemplate(); + const serviceTemplate = createServiceTemplate(_params); + const indexTemplate = createIndexTemplate(_params); // 增加测试模板 - const testsTemplate = createTestsTemplate(_params) + const testsTemplate = createTestsTemplate(_params); // 增加文档模板 - const docTemplate = createDocumentTemplate(_params) + const docTemplate = createDocumentTemplate(_params); - const componentDir = resolve(DEVUI_DIR, componentName) - const srcDir = resolve(componentDir, 'src') - const testsDir = resolve(DEVUI_DIR, componentName, TESTS_DIR_NAME) - const docsDir = resolve(SITES_COMPONENTS_DIR, componentName) + const componentDir = resolve(DEVUI_DIR, componentName); + const srcDir = resolve(componentDir, "src"); + const testsDir = resolve(DEVUI_DIR, componentName, TESTS_DIR_NAME); + const docsDir = resolve(SITES_COMPONENTS_DIR, componentName); if (fs.pathExistsSync(componentDir)) { - logger.error(`${bigCamelCase(componentName)} 组件目录已存在!`) - process.exit(1) + logger.error(`${bigCamelCase(componentName)} 组件目录已存在!`); + process.exit(1); } - let spinner = ora(`创建组件 ${bigCamelCase(componentName)} 开始...`).start() + let spinner = ora(`创建组件 ${bigCamelCase(componentName)} 开始...`).start(); try { - await Promise.all([fs.mkdirs(componentDir), fs.mkdirs(srcDir), fs.mkdirs(testsDir)]) + await Promise.all([ + fs.mkdirs(componentDir), + fs.mkdirs(srcDir), + fs.mkdirs(testsDir), + ]); const writeFiles = [ fs.writeFile(resolve(componentDir, INDEX_FILE_NAME), indexTemplate), fs.writeFile(resolve(testsDir, `${testName}.ts`), testsTemplate), - ] + ]; if (!fs.existsSync(docsDir)) { - fs.mkdirSync(docsDir) - writeFiles.push(fs.writeFile(resolve(docsDir, DOCS_FILE_NAME), docTemplate)) + fs.mkdirSync(docsDir); + writeFiles.push( + fs.writeFile(resolve(docsDir, DOCS_FILE_NAME), docTemplate) + ); } else { - logger.warning(`\n${bigCamelCase(componentName)} 组件文档已存在:${resolve(docsDir, DOCS_FILE_NAME)}`) + logger.warning( + `\n${bigCamelCase(componentName)} 组件文档已存在:${resolve( + docsDir, + DOCS_FILE_NAME + )}` + ); } if (hasComponent || hasService) { - writeFiles.push(fs.writeFile(resolve(srcDir, `${typesName}.ts`), typesTemplate)) + writeFiles.push( + fs.writeFile(resolve(srcDir, `${typesName}.ts`), typesTemplate) + ); } if (hasComponent) { writeFiles.push( - fs.writeFile(resolve(srcDir, `${componentName}.tsx`), componentTemplate), + fs.writeFile( + resolve(srcDir, `${componentName}.tsx`), + componentTemplate + ), fs.writeFile(resolve(srcDir, `${styleName}.scss`), styleTemplate) - ) + ); } if (hasDirective) { - writeFiles.push(fs.writeFile(resolve(srcDir, `${directiveName}.ts`), directiveTemplate)) + writeFiles.push( + fs.writeFile(resolve(srcDir, `${directiveName}.ts`), directiveTemplate) + ); } if (hasService) { - writeFiles.push(fs.writeFile(resolve(srcDir, `${serviceName}.ts`), serviceTemplate)) + writeFiles.push( + fs.writeFile(resolve(srcDir, `${serviceName}.ts`), serviceTemplate) + ); } - await Promise.all(writeFiles) + await Promise.all(writeFiles); - spinner.succeed(`创建组件 ${bigCamelCase(componentName)} 成功!`) - logger.info(`组件目录:${componentDir}`) + spinner.succeed(`创建组件 ${bigCamelCase(componentName)} 成功!`); + logger.info(`组件目录:${componentDir}`); } catch (e) { - spinner.fail(e.toString()) - process.exit(1) + spinner.fail(e.toString()); + process.exit(1); } } async function createVueDevui(params, { ignoreParseError }) { - const fileInfo = resolveDirFilesInfo(DEVUI_DIR, VUE_DEVUI_IGNORE_DIRS) - const exportModules = [] + const fileInfo = resolveDirFilesInfo(DEVUI_DIR, VUE_DEVUI_IGNORE_DIRS); + const exportModules = []; fileInfo.forEach((f) => { - const em = parseExportByFileInfo(f, ignoreParseError) + const em = parseExportByFileInfo(f, ignoreParseError); - if (isEmpty(em)) return + if (isEmpty(em)) return; - exportModules.push(em) - }) + exportModules.push(em); + }); - const template = createVueDevuiTemplate(exportModules) + const template = createVueDevuiTemplate(exportModules); - let spinner = ora(`创建 ${VUE_DEVUI_FILE_NAME} 文件开始...`).start() + let spinner = ora(`创建 ${VUE_DEVUI_FILE_NAME} 文件开始...`).start(); try { - await fs.writeFile(VUE_DEVUI_FILE, template, { encoding: 'utf-8' }) + await fs.writeFile(VUE_DEVUI_FILE, template, { encoding: "utf-8" }); - spinner.succeed(`创建 ${VUE_DEVUI_FILE_NAME} 文件成功!`) - logger.info(`文件地址:${VUE_DEVUI_FILE}`) + spinner.succeed(`创建 ${VUE_DEVUI_FILE_NAME} 文件成功!`); + logger.info(`文件地址:${VUE_DEVUI_FILE}`); } catch (e) { - spinner.fail(e.toString()) - process.exit(1) + spinner.fail(e.toString()); + process.exit(1); } } async function createVitepressSidebar() { - const fileInfo = resolveDirFilesInfo(DEVUI_DIR, VUE_DEVUI_IGNORE_DIRS) - const componentsInfo = [] + const fileInfo = resolveDirFilesInfo(DEVUI_DIR, VUE_DEVUI_IGNORE_DIRS); + const componentsInfo = []; fileInfo.forEach((f) => { - const info = parseComponentInfo(f.dirname) + const info = parseComponentInfo(f.dirname); - if (isEmpty(info)) return + if (isEmpty(info)) return; - componentsInfo.push(info) - }) + componentsInfo.push(info); + }); - const template = createVitepressSidebarTemplate(componentsInfo) + const template = createVitepressSidebarTemplate(componentsInfo); - let spinner = ora(`创建 ${VITEPRESS_SIDEBAR_FILE_NAME} 文件开始...`).start() + let spinner = ora(`创建 ${VITEPRESS_SIDEBAR_FILE_NAME} 文件开始...`).start(); try { - await fs.writeFile(VITEPRESS_SIDEBAR_FILE, template, { encoding: 'utf-8' }) + await fs.writeFile(VITEPRESS_SIDEBAR_FILE, template, { encoding: "utf-8" }); - spinner.succeed(`创建 ${VITEPRESS_SIDEBAR_FILE_NAME} 文件成功!`) - logger.info(`文件地址:${VITEPRESS_SIDEBAR_FILE}`) + spinner.succeed(`创建 ${VITEPRESS_SIDEBAR_FILE_NAME} 文件成功!`); + logger.info(`文件地址:${VITEPRESS_SIDEBAR_FILE}`); } catch (e) { - spinner.fail(e.toString()) - process.exit(1) + spinner.fail(e.toString()); + process.exit(1); } } diff --git a/packages/devui-cli/src/commands/generate-theme.ts b/packages/devui-cli/src/commands/generate-theme.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8aea78a8d25f4d2b1397ceb4c0c435a07454768 --- /dev/null +++ b/packages/devui-cli/src/commands/generate-theme.ts @@ -0,0 +1,14 @@ +import fs from "fs-extra"; +import path from "path"; +import { CWD } from "../shared/constant"; + +require("esbuild-register"); +const theme = require(path.join(CWD, "/devui/theme/themes/light")); +const themeFilePath = path.join(CWD, "/devui/theme/theme.scss"); +const fileStr = Object.entries(theme) + .map(([key, value]) => `$${key}: var(--${key}, ${value})`) + .join(";\n"); + +export const generateTheme = async () => { + await fs.outputFile(themeFilePath, fileStr, "utf-8"); +}; diff --git a/packages/devui-cli/src/index.ts b/packages/devui-cli/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e80f56a8d3fc54c9813c04d2d7bd266bcec5f5e --- /dev/null +++ b/packages/devui-cli/src/index.ts @@ -0,0 +1,4 @@ +import { create } from "./commands/create"; +import { build } from './commands/build'; + +export { build, create }; diff --git a/packages/devui-cli/src/inquirers/component.ts b/packages/devui-cli/src/inquirers/component.ts new file mode 100644 index 0000000000000000000000000000000000000000..99485f0c9594f979e3fef99b313d7cf3e20d3e10 --- /dev/null +++ b/packages/devui-cli/src/inquirers/component.ts @@ -0,0 +1,56 @@ +import { + COMPONENT_PARTS_MAP, + VITEPRESS_SIDEBAR_CATEGORY, +} from "../shared/constant"; + +export const typeName = () => ({ + name: "name", + type: "input", + message: "(必填)请输入组件 name ,将用作目录及文件名:", + validate: (value) => { + if (value.trim() === "") { + return "组件 name 是必填项!"; + } + return true; + }, +}); + +export const typeTitle = () => ({ + name: "title", + type: "input", + message: "(必填)请输入组件中文名称,将用作文档列表显示:", + validate: (value) => { + if (value.trim() === "") { + return "组件名称是必填项!"; + } + return true; + }, +}); + +export const selectCategory = () => ({ + name: "category", + type: "list", + message: "(必填)请选择组件分类,将用作文档列表分类:", + choices: VITEPRESS_SIDEBAR_CATEGORY, + default: 0, +}); + +export const typeAliasName = () => ({ + name: "alias", + type: "input", + message: "(选填)请输入组件 name 别名,将用作组件别名被导出:", +}); + +export const selectParts = () => ({ + name: "parts", + type: "checkbox", + message: "(必填)请选择包含部件,将自动生成部件文件:", + choices: COMPONENT_PARTS_MAP, + default: [], + validate: (value) => { + if (value.length === 0) { + return "部件必须包含至少一项"; + } + return true; + }, +}); diff --git a/packages/devui-cli/src/inquirers/create.ts b/packages/devui-cli/src/inquirers/create.ts new file mode 100644 index 0000000000000000000000000000000000000000..01b9a46267fe89cca6160f60c0994921c7489a17 --- /dev/null +++ b/packages/devui-cli/src/inquirers/create.ts @@ -0,0 +1,9 @@ +import { CREATE_SUPPORT_TYPES } from "../shared/constant"; + +export const selectCreateType = () => ({ + name: "type", + type: "list", + message: "(必填)请选择创建类型:", + choices: CREATE_SUPPORT_TYPES, + default: 0, +}); diff --git a/packages/devui-cli/src/shared/constant.ts b/packages/devui-cli/src/shared/constant.ts new file mode 100644 index 0000000000000000000000000000000000000000..853b4dcbad54f691747a71a2b1cf80cba10f9c23 --- /dev/null +++ b/packages/devui-cli/src/shared/constant.ts @@ -0,0 +1,58 @@ +import { join } from "path"; +// @ts-ignore +import packageJson from "../../package.json"; + +const { version } = packageJson; +export const VERSION = version; +export const CWD = process.cwd(); +export const DEVUI_DIR = join(CWD, "devui"); +export const DEVUI_NAMESPACE = "d"; +export const CSS_CLASS_PREFIX = "devui"; +export const TESTS_DIR_NAME = "__tests__"; +export const INDEX_FILE_NAME = "index.ts"; +export const DOCS_FILE_NAME = "index.md"; +export const VUE_DEVUI_IGNORE_DIRS = ["shared", "style"]; +export const VUE_DEVUI_FILE_NAME = "vue-devui.ts"; +export const VUE_DEVUI_FILE = join(DEVUI_DIR, VUE_DEVUI_FILE_NAME); +export const SITES_DIR = join(CWD, "docs"); +export const SITES_COMPONENTS_DIR_NAME = "components"; +export const SITES_COMPONENTS_DIR = join(SITES_DIR, SITES_COMPONENTS_DIR_NAME); +export const VITEPRESS_DIR = join(SITES_DIR, ".vitepress"); +export const VITEPRESS_SIDEBAR_FILE_NAME = "sidebar.ts"; +export const VITEPRESS_SIDEBAR_FILE = join( + VITEPRESS_DIR, + `config/${VITEPRESS_SIDEBAR_FILE_NAME}` +); + +// 这里的分类顺序将会影响最终生成的页面侧边栏顺序 +export const VITEPRESS_SIDEBAR_CATEGORY = [ + "通用", + "导航", + "反馈", + "数据录入", + "数据展示", + "布局", +]; + +export const COMPONENT_PARTS_MAP = [ + { + name: "component(组件)", + value: "component", + }, + { + name: "directive(指令)", + value: "directive", + }, + { + name: "service(服务)", + value: "service", + }, +]; + +export const CREATE_SUPPORT_TYPE_MAP = Object.freeze({ + component: "component", + "vue-devui": "vue-devui", + "theme-variable": "theme-variable", +}); +export const CREATE_SUPPORT_TYPES = Object.keys(CREATE_SUPPORT_TYPE_MAP); +export const CREATE_UNFINISHED_TYPES = []; diff --git a/packages/devui-cli/src/shared/logger.ts b/packages/devui-cli/src/shared/logger.ts new file mode 100644 index 0000000000000000000000000000000000000000..680d5583a24562c8a03116745a2f7c07c98956f3 --- /dev/null +++ b/packages/devui-cli/src/shared/logger.ts @@ -0,0 +1,16 @@ +import chalk from "chalk"; + +export const logger = { + info(text: string) { + console.log(chalk.hex("#00afef")(text)); + }, + success(text: string) { + console.log(chalk.hex("#00c48f")(text)); + }, + warning(text: string) { + console.log(chalk.hex("#ff9800")(text)); + }, + error(text: string) { + console.log(chalk.hex("#f44336")(text)); + }, +}; diff --git a/packages/devui-vue/devui-cli/shared/utils.js b/packages/devui-cli/src/shared/utils.ts similarity index 33% rename from packages/devui-vue/devui-cli/shared/utils.js rename to packages/devui-cli/src/shared/utils.ts index 11fb60c7065a929734587fda721d59df57f0960a..436848cb1c3040e08bdc54d095c9bc677e84d903 100644 --- a/packages/devui-vue/devui-cli/shared/utils.js +++ b/packages/devui-cli/src/shared/utils.ts @@ -1,16 +1,17 @@ -const { camelCase, upperFirst } = require('lodash') -const { INDEX_FILE_NAME, DEVUI_DIR } = require('./constant') -const { resolve } = require('path') -const logger = require('./logger') -const fs = require('fs-extra') -const traverse = require("@babel/traverse").default -const babelParser = require("@babel/parser") - -exports.bigCamelCase = (str) => { - return upperFirst(camelCase(str)) -} +import fs from "fs-extra"; +import { camelCase, upperFirst } from "lodash"; +import { resolve } from "path"; +import { DEVUI_DIR, INDEX_FILE_NAME } from "./constant"; +import { logger } from "./logger"; + +const traverse = require("@babel/traverse").default; +const babelParser = require("@babel/parser"); + +export const bigCamelCase = (str: string) => { + return upperFirst(camelCase(str)); +}; -exports.resolveDirFilesInfo = (targetDir, ignoreDirs = []) => { +export const resolveDirFilesInfo = (targetDir: string, ignoreDirs = []) => { return fs .readdirSync(targetDir) .filter( @@ -21,104 +22,111 @@ exports.resolveDirFilesInfo = (targetDir, ignoreDirs = []) => { fs.existsSync(resolve(targetDir, dir, INDEX_FILE_NAME)) ) .map((dir) => ({ - name: this.bigCamelCase(dir), + name: bigCamelCase(dir), dirname: dir, - path: resolve(targetDir, dir, INDEX_FILE_NAME) - })) + path: resolve(targetDir, dir, INDEX_FILE_NAME), + })); +}; + +interface exportModuleI { + default: string; + parts: Array; + fileInfo: string; } -exports.parseExportByFileInfo = (fileInfo, ignoreParseError) => { - const exportModule = {} - const indexContent = fs.readFileSync(fileInfo.path, { encoding: 'utf-8' }) +export const parseExportByFileInfo = (fileInfo, ignoreParseError) => { + const exportModule: exportModuleI = { default: "", fileInfo: "", parts: [] }; + const indexContent = fs.readFileSync(fileInfo.path, { encoding: "utf-8" }); const ast = babelParser.parse(indexContent, { - sourceType: 'module', - plugins: [ - 'typescript' - ] - }) + sourceType: "module", + plugins: ["typescript"], + }); - const exportName = [] - let exportDefault = null + const exportName = []; + let exportDefault = null; traverse(ast, { - ExportNamedDeclaration({node}) { + ExportNamedDeclaration({ node }) { if (node.specifiers.length) { - node.specifiers.forEach(specifier => { - exportName.push(specifier.local.name) - }) + node.specifiers.forEach((specifier) => { + exportName.push(specifier.local.name); + }); } else if (node.declaration) { if (node.declaration.declarations) { - node.declaration.declarations.forEach(dec => { - exportName.push(dec.id.name) - }) + node.declaration.declarations.forEach((dec) => { + exportName.push(dec.id.name); + }); } else if (node.declaration.id) { - exportName.push(node.declaration.id.name) + exportName.push(node.declaration.id.name); } } }, ExportDefaultDeclaration() { - exportDefault = fileInfo.name + 'Install' - } - }) + exportDefault = fileInfo.name + "Install"; + }, + }); if (!exportDefault) { - logger.error(`${fileInfo.path} must have "export default".`) + logger.error(`${fileInfo.path} must have "export default".`); if (ignoreParseError) { - return exportModule + return exportModule; } else { - process.exit(1) + process.exit(1); } } if (!exportName.length) { - logger.error(`${fileInfo.path} must have "export xxx".`) - + logger.error(`${fileInfo.path} must have "export xxx".`); + if (ignoreParseError) { - return exportModule + return exportModule; } else { - process.exit(1) + process.exit(1); } } - exportModule.default = exportDefault - exportModule.parts = exportName - exportModule.fileInfo = fileInfo + exportModule.default = exportDefault; + exportModule.parts = exportName; + exportModule.fileInfo = fileInfo; - return exportModule -} + return exportModule; +}; -exports.parseComponentInfo = (name) => { +export const parseComponentInfo = (name: string) => { const componentInfo = { - name: this.bigCamelCase(name) - } - let hasExportDefault = false - const indexContent = fs.readFileSync(resolve(DEVUI_DIR, name, INDEX_FILE_NAME), { encoding: 'utf-8' }) + name: bigCamelCase(name), + }; + let hasExportDefault = false; + const indexContent = fs.readFileSync( + resolve(DEVUI_DIR, name, INDEX_FILE_NAME), + { encoding: "utf-8" } + ); const ast = babelParser.parse(indexContent, { - sourceType: 'module', - plugins: [ - 'typescript' - ] - }) + sourceType: "module", + plugins: ["typescript"], + }); traverse(ast, { - ExportDefaultDeclaration({node}) { - hasExportDefault = true + ExportDefaultDeclaration({ node }) { + hasExportDefault = true; if (node.declaration && node.declaration.properties) { - const properties = node.declaration.properties - properties.forEach(pro => { - if (pro.type === 'ObjectProperty') { - componentInfo[pro.key.name] = pro.value.value + const properties = node.declaration.properties; + properties.forEach((pro) => { + if (pro.type === "ObjectProperty") { + componentInfo[pro.key.name] = pro.value.value; } - }) + }); } - } - }) + }, + }); if (!hasExportDefault) { - logger.warning(`${componentInfo.name} must have "export default" and component info.`) + logger.warning( + `${componentInfo.name} must have "export default" and component info.` + ); } - return componentInfo -} + return componentInfo; +}; diff --git a/packages/devui-vue/devui-cli/templates/component.js b/packages/devui-cli/src/templates/component.ts similarity index 61% rename from packages/devui-vue/devui-cli/templates/component.js rename to packages/devui-cli/src/templates/component.ts index 8e0909c48621ec4cf315e1321554456a05282cc7..d70617bbbee89a49c9230a0f357783215a1e7ec0 100644 --- a/packages/devui-vue/devui-cli/templates/component.js +++ b/packages/devui-cli/src/templates/component.ts @@ -1,11 +1,17 @@ -const { DEVUI_NAMESPACE, CSS_CLASS_PREFIX } = require('../shared/constant') -const { camelCase } = require('lodash') -const { bigCamelCase } = require('../shared/utils') +import { camelCase } from "lodash"; +import { CSS_CLASS_PREFIX, DEVUI_NAMESPACE } from "../shared/constant"; +import { bigCamelCase } from "../shared/utils"; // 创建组件模板 -exports.createComponentTemplate = ({ styleName, componentName, typesName }) => `\ +export const createComponentTemplate = ({ + styleName, + componentName, + typesName, +}) => `\ import { defineComponent } from 'vue' -import { ${camelCase(componentName)}Props, ${bigCamelCase(componentName)}Props } from './${typesName}' +import { ${camelCase(componentName)}Props, ${bigCamelCase( + componentName +)}Props } from './${typesName}' import './${styleName}.scss' export default defineComponent({ @@ -18,10 +24,10 @@ export default defineComponent({ } } }) -` +`; // 创建类型声明模板 -exports.createTypesTemplate = ({ componentName }) => `\ +export const createTypesTemplate = ({ componentName }) => `\ import type { PropType, ExtractPropTypes } from 'vue' export const ${camelCase(componentName)}Props = { @@ -30,11 +36,13 @@ export const ${camelCase(componentName)}Props = { } \*\/ } as const -export type ${bigCamelCase(componentName)}Props = ExtractPropTypes -` +export type ${bigCamelCase( + componentName +)}Props = ExtractPropTypes +`; // 创建指令模板 -exports.createDirectiveTemplate = () => `\ +export const createDirectiveTemplate = () => `\ // can export function. export default { created() { }, @@ -45,9 +53,13 @@ export default { beforeUnmount() { }, unmounted() { } } -` +`; // 创建server模板 -exports.createServiceTemplate = ({ componentName, typesName, serviceName }) => `\ +export const createServiceTemplate = ({ + componentName, + typesName, + serviceName, +}) => `\ import { ${bigCamelCase(componentName)}Props } from './${typesName}' const ${bigCamelCase(serviceName)} = { @@ -55,17 +67,17 @@ const ${bigCamelCase(serviceName)} = { } export default ${bigCamelCase(serviceName)} -` +`; // 创建scss模板 -exports.createStyleTemplate = ({ componentName }) => `\ +export const createStyleTemplate = ({ componentName }) => `\ .${CSS_CLASS_PREFIX}-${componentName} { // } -` +`; // 创建index模板 -exports.createIndexTemplate = ({ +export const createIndexTemplate = ({ title, category, hasComponent, @@ -73,27 +85,39 @@ exports.createIndexTemplate = ({ hasService, componentName, directiveName, - serviceName + serviceName, }) => { - const importComponentStr = `\nimport ${bigCamelCase(componentName)} from './src/${componentName}'` - const importDirectiveStr = `\nimport ${bigCamelCase(directiveName)} from './src/${directiveName}'` - const importServiceStr = `\nimport ${bigCamelCase(serviceName)} from './src/${serviceName}'` - - const installComponentStr = ` app.use(${bigCamelCase(componentName)} as any)` - const installDirectiveStr = `\n app.directive('${bigCamelCase(componentName)}', ${bigCamelCase(directiveName)})` - const installServiceStr = `\n app.config.globalProperties.$${camelCase(serviceName)} = ${bigCamelCase( + const importComponentStr = `\nimport ${bigCamelCase( + componentName + )} from './src/${componentName}'`; + const importDirectiveStr = `\nimport ${bigCamelCase( + directiveName + )} from './src/${directiveName}'`; + const importServiceStr = `\nimport ${bigCamelCase( + serviceName + )} from './src/${serviceName}'`; + + const installComponentStr = ` app.use(${bigCamelCase( + componentName + )} as any)`; + const installDirectiveStr = `\n app.directive('${bigCamelCase( + componentName + )}', ${bigCamelCase(directiveName)})`; + const installServiceStr = `\n app.config.globalProperties.$${camelCase( serviceName - )}` + )} = ${bigCamelCase(serviceName)}`; - const getPartStr = (state, str) => (state ? str : '') + const getPartStr = (state, str) => (state ? str : ""); - const importStr = getPartStr(hasComponent, importComponentStr) + - getPartStr(hasDirective, importDirectiveStr) + - getPartStr(hasService, importServiceStr) + const importStr = + getPartStr(hasComponent, importComponentStr) + + getPartStr(hasDirective, importDirectiveStr) + + getPartStr(hasService, importServiceStr); - const installStr = getPartStr(hasComponent, installComponentStr) + - getPartStr(hasDirective, installDirectiveStr) + - getPartStr(hasService, installServiceStr) + const installStr = + getPartStr(hasComponent, installComponentStr) + + getPartStr(hasDirective, installDirectiveStr) + + getPartStr(hasService, installServiceStr); return `\ import type { App } from 'vue'\ @@ -101,17 +125,19 @@ ${importStr} ${ hasComponent ? `\n${bigCamelCase(componentName)}.install = function(app: App): void { - app.component(${bigCamelCase(componentName)}.name, ${bigCamelCase(componentName)}) + app.component(${bigCamelCase(componentName)}.name, ${bigCamelCase( + componentName + )}) }\n` - : '' + : "" } export { ${[ hasComponent ? bigCamelCase(componentName) : null, hasDirective ? bigCamelCase(directiveName) : null, - hasService ? bigCamelCase(serviceName) : null + hasService ? bigCamelCase(serviceName) : null, ] .filter((p) => p !== null) - .join(', ')} } + .join(", ")} } export default { title: '${bigCamelCase(componentName)} ${title}', @@ -121,39 +147,36 @@ export default { ${installStr} } } -` -} +`; +}; // 创建测试模板 -exports.createTestsTemplate = ({ +export const createTestsTemplate = ({ componentName, directiveName, serviceName, hasComponent, hasDirective, - hasService + hasService, }) => `\ import { mount } from '@vue/test-utils'; import { ${[ - hasComponent ? bigCamelCase(componentName) : null, - hasDirective ? bigCamelCase(directiveName) : null, - hasService ? bigCamelCase(serviceName) : null - ] - .filter((p) => p !== null) - .join(', ')} } from '../index'; + hasComponent ? bigCamelCase(componentName) : null, + hasDirective ? bigCamelCase(directiveName) : null, + hasService ? bigCamelCase(serviceName) : null, +] + .filter((p) => p !== null) + .join(", ")} } from '../index'; describe('${componentName} test', () => { it('${componentName} init render', async () => { // todo }) }) -` +`; // 创建文档模板 -exports.createDocumentTemplate = ({ - componentName, - title -}) => `\ +export const createDocumentTemplate = ({ componentName, title }) => `\ # ${bigCamelCase(componentName)} ${title} // todo 组件描述 @@ -209,4 +232,4 @@ d-${componentName} 事件 | | | | | | | | | | -` +`; diff --git a/packages/devui-vue/devui-cli/templates/vitepress-sidebar.js b/packages/devui-cli/src/templates/vitepress-sidebar.ts similarity index 35% rename from packages/devui-vue/devui-cli/templates/vitepress-sidebar.js rename to packages/devui-cli/src/templates/vitepress-sidebar.ts index ee079340e486e227daea5c8190784cbeea83c7ad..452a48466f0f15f921a70818a91e166bf69a6873 100644 --- a/packages/devui-vue/devui-cli/templates/vitepress-sidebar.js +++ b/packages/devui-cli/src/templates/vitepress-sidebar.ts @@ -1,35 +1,47 @@ -const { kebabCase } = require('lodash') -const { SITES_COMPONENTS_DIR_NAME, VITEPRESS_SIDEBAR_CATEGORY } = require('../shared/constant') -const logger = require('../shared/logger') +import { kebabCase } from "lodash"; +import { + SITES_COMPONENTS_DIR_NAME, + VITEPRESS_SIDEBAR_CATEGORY, +} from "../shared/constant"; +import { logger } from "../shared/logger"; function buildComponentOptions(text, name, status) { - return { text, link: `/${SITES_COMPONENTS_DIR_NAME}/${kebabCase(name)}/`, status } + return { + text, + link: `/${SITES_COMPONENTS_DIR_NAME}/${kebabCase(name)}/`, + status, + }; } function buildCategoryOptions(text, children = []) { - return { text, children } + return { text, children }; } -exports.createVitepressSidebarTemplate = (componentsInfo = []) => { - const rootNav = { text: '快速开始', link: '/' } - const categoryMap = VITEPRESS_SIDEBAR_CATEGORY.reduce((map, cate) => map.set(cate, []), new Map()) +export const createVitepressSidebarTemplate = (componentsInfo = []) => { + const rootNav = { text: "快速开始", link: "/" }; + const categoryMap = VITEPRESS_SIDEBAR_CATEGORY.reduce( + (map, cate) => map.set(cate, []), + new Map() + ); componentsInfo.forEach((info) => { if (categoryMap.has(info.category)) { - categoryMap.get(info.category).push(buildComponentOptions(info.title, info.name, info.status)) + categoryMap + .get(info.category) + .push(buildComponentOptions(info.title, info.name, info.status)); } else { - logger.warning(`组件 ${info.name} 的分类 ${info.category} 不存在!`) + logger.warning(`组件 ${info.name} 的分类 ${info.category} 不存在!`); } - }) + }); const sidebar = [].concat( rootNav, Array.from(categoryMap).map(([k, v]) => buildCategoryOptions(k, v)) - ) + ); return `\ export default { - '/': ${JSON.stringify(sidebar, null, 2).replace(/\n/g, '\n\t')} -} -` + '/': ${JSON.stringify(sidebar, null, 2).replace(/\n/g, "\n\t")} } +`; +}; diff --git a/packages/devui-vue/devui-cli/templates/vue-devui.js b/packages/devui-cli/src/templates/vue-devui.ts similarity index 31% rename from packages/devui-vue/devui-cli/templates/vue-devui.js rename to packages/devui-cli/src/templates/vue-devui.ts index c6def01b3867c322248f3e06ce151b9f4d15b30e..14be28eaff4aa767e5f0116122f56001e3d6e5fc 100644 --- a/packages/devui-vue/devui-cli/templates/vue-devui.js +++ b/packages/devui-cli/src/templates/vue-devui.ts @@ -1,36 +1,38 @@ -const { relative } = require('path') -const { INDEX_FILE_NAME, VERSION, VUE_DEVUI_FILE } = require('../shared/constant') +import { relative } from "path"; +import { INDEX_FILE_NAME, VERSION, VUE_DEVUI_FILE } from "../shared/constant"; -exports.createVueDevuiTemplate = (exportModules = []) => { - const packages = [] - const imports = [] - const installs = [] +export const createVueDevuiTemplate = (exportModules = []) => { + const packages = []; + const imports = []; + const installs = []; exportModules.forEach((m) => { - const { fileInfo } = m + const { fileInfo } = m; const relativePath = relative(VUE_DEVUI_FILE, fileInfo.path) - .replace(/\\/g, '/') - .replace('..', '.') - .replace('/' + INDEX_FILE_NAME, '') + .replace(/\\/g, "/") + .replace("..", ".") + .replace("/" + INDEX_FILE_NAME, ""); - const importStr = `import ${m.default}, { ${m.parts.join(', ')} } from '${relativePath}'` + const importStr = `import ${m.default}, { ${m.parts.join( + ", " + )} } from '${relativePath}'`; - packages.push(...m.parts) - imports.push(importStr) - installs.push(m.default) - }) + packages.push(...m.parts); + imports.push(importStr); + installs.push(m.default); + }); const template = `\ import type { App } from 'vue' -${imports.join('\n')} +${imports.join("\n")} const installs = [ - ${installs.join(',\n\t')} + ${installs.join(",\n\t")} ] export { - ${packages.join(',\n\t')} + ${packages.join(",\n\t")} } export default { @@ -39,7 +41,7 @@ export default { installs.forEach((p) => app.use(p as any)) } } -` +`; - return template -} + return template; +}; diff --git a/packages/devui-cli/tsconfig.json b/packages/devui-cli/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..2d6eda1d30bd1985352e529fa63762c03ca0397a --- /dev/null +++ b/packages/devui-cli/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2017", + "outDir": "./lib", + "module": "commonjs", + "declaration": true, + "skipLibCheck": true, + "esModuleInterop": true, + "lib": ["esnext", "dom"] + }, + "include": ["src/**/*", "site"], + "exclude": ["node_modules"] +} diff --git a/packages/devui-vue/devui-cli/commands/generate-theme.js b/packages/devui-vue/devui-cli/commands/generate-theme.js deleted file mode 100644 index 3acfa026b87d7bc467abdb1015a9d2cae6cc2d0b..0000000000000000000000000000000000000000 --- a/packages/devui-vue/devui-cli/commands/generate-theme.js +++ /dev/null @@ -1,16 +0,0 @@ -require('esbuild-register') -const path = require('path') -const fs = require('fs-extra') -const theme = require('../../devui/theme/themes/light.ts').default - -const fileStr = Object.entries(theme) -.map(([key, value]) => `$${key}: var(--${key}, ${value})`) -.join(';\n') - -exports.generateTheme = async () => { - await fs.outputFile( - path.resolve(__dirname, '../../devui/theme/theme.scss'), - fileStr, - 'utf-8' - ) -} \ No newline at end of file diff --git a/packages/devui-vue/devui-cli/index.js b/packages/devui-vue/devui-cli/index.js deleted file mode 100755 index d4ed9906e6fe7e2f2b8c41cab1765391bdae6fd0..0000000000000000000000000000000000000000 --- a/packages/devui-vue/devui-cli/index.js +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env node -const { Command } = require('commander') -const { create, validateCreateType } = require('./commands/create') -const { build } = require('./commands/build') -const { generateTheme } = require('./commands/generate-theme') -const { VERSION, CREATE_SUPPORT_TYPES } = require('./shared/constant') - -const program = new Command() - -program - .command('create') - .description('创建一个组件模板或配置文件') - .option('-t --type ', `创建类型,可选值:${CREATE_SUPPORT_TYPES.join(', ')}`, validateCreateType) - .option('--ignore-parse-error', '忽略解析错误', false) - .option('--cover', '覆盖原文件', false) - .action(create) - -program - .command('build') - .description('打包组件库') - .action(build) - -program - .command('generate:theme') - .description('生成主题变量文件') - .action(generateTheme) - -program.parse().version(VERSION) diff --git a/packages/devui-vue/devui-cli/inquirers/component.js b/packages/devui-vue/devui-cli/inquirers/component.js deleted file mode 100644 index 355a2b09470c21a9c0f78df8314393d67da0f72d..0000000000000000000000000000000000000000 --- a/packages/devui-vue/devui-cli/inquirers/component.js +++ /dev/null @@ -1,53 +0,0 @@ -const { COMPONENT_PARTS_MAP, VITEPRESS_SIDEBAR_CATEGORY } = require('../shared/constant') - -exports.typeName = () => ({ - name: 'name', - type: 'input', - message: '(必填)请输入组件 name ,将用作目录及文件名:', - validate: (value) => { - if (value.trim() === '') { - return '组件 name 是必填项!' - } - return true - } -}) - -exports.typeTitle = () => ({ - name: 'title', - type: 'input', - message: '(必填)请输入组件中文名称,将用作文档列表显示:', - validate: (value) => { - if (value.trim() === '') { - return '组件名称是必填项!' - } - return true - } -}) - -exports.selectCategory = () => ({ - name: 'category', - type: 'list', - message: '(必填)请选择组件分类,将用作文档列表分类:', - choices: VITEPRESS_SIDEBAR_CATEGORY, - default: 0 -}) - -exports.typeAliasName = () => ({ - name: 'alias', - type: 'input', - message: '(选填)请输入组件 name 别名,将用作组件别名被导出:' -}) - -exports.selectParts = () => ({ - name: 'parts', - type: 'checkbox', - message: '(必填)请选择包含部件,将自动生成部件文件:', - choices: COMPONENT_PARTS_MAP, - default: [], - validate: (value) => { - if (value.length === 0) { - return '部件必须包含至少一项' - } - return true - } -}) diff --git a/packages/devui-vue/devui-cli/inquirers/create.js b/packages/devui-vue/devui-cli/inquirers/create.js deleted file mode 100644 index 5bc07766b51469dd82c4cd1a75ac125ad5d81065..0000000000000000000000000000000000000000 --- a/packages/devui-vue/devui-cli/inquirers/create.js +++ /dev/null @@ -1,9 +0,0 @@ -const { CREATE_SUPPORT_TYPES } = require('../shared/constant') - -exports.selectCreateType = () => ({ - name: 'type', - type: 'list', - message: '(必填)请选择创建类型:', - choices: CREATE_SUPPORT_TYPES, - default: 0 -}) diff --git a/packages/devui-vue/devui-cli/shared/constant.js b/packages/devui-vue/devui-cli/shared/constant.js deleted file mode 100644 index 6288409782d590df0d3e450b4f279a854a627793..0000000000000000000000000000000000000000 --- a/packages/devui-vue/devui-cli/shared/constant.js +++ /dev/null @@ -1,46 +0,0 @@ -const { resolve } = require('path') -const { version } = require('../../package.json') - -exports.VERSION = version -exports.CWD = process.cwd() -exports.DEVUI_DIR = resolve(this.CWD, 'devui') -exports.DEVUI_NAMESPACE = 'd' -exports.CSS_CLASS_PREFIX = 'devui' -exports.TESTS_DIR_NAME = '__tests__' -exports.INDEX_FILE_NAME = 'index.ts' -exports.DOCS_FILE_NAME = 'index.md' -exports.VUE_DEVUI_IGNORE_DIRS = ['shared', 'style'] -exports.VUE_DEVUI_FILE_NAME = 'vue-devui.ts' -exports.VUE_DEVUI_FILE = resolve(this.DEVUI_DIR, this.VUE_DEVUI_FILE_NAME) -exports.SITES_DIR = resolve(this.CWD, 'docs') -exports.SITES_COMPONENTS_DIR_NAME = 'components' -exports.SITES_COMPONENTS_DIR = resolve(this.SITES_DIR, this.SITES_COMPONENTS_DIR_NAME) -exports.VITEPRESS_DIR = resolve(this.SITES_DIR, '.vitepress') -exports.VITEPRESS_SIDEBAR_FILE_NAME = 'sidebar.ts' -exports.VITEPRESS_SIDEBAR_FILE = resolve(this.VITEPRESS_DIR, `config/${this.VITEPRESS_SIDEBAR_FILE_NAME}`) - -// 这里的分类顺序将会影响最终生成的页面侧边栏顺序 -exports.VITEPRESS_SIDEBAR_CATEGORY = ['通用', '导航', '反馈', '数据录入', '数据展示', '布局'] - -exports.COMPONENT_PARTS_MAP = [ - { - name: 'component(组件)', - value: 'component' - }, - { - name: 'directive(指令)', - value: 'directive' - }, - { - name: 'service(服务)', - value: 'service' - } -] - -exports.CREATE_SUPPORT_TYPE_MAP = Object.freeze({ - component: 'component', - 'vue-devui': 'vue-devui', - 'theme-variable': 'theme-variable', -}) -exports.CREATE_SUPPORT_TYPES = Object.keys(this.CREATE_SUPPORT_TYPE_MAP) -exports.CREATE_UNFINISHED_TYPES = [] diff --git a/packages/devui-vue/devui-cli/shared/logger.js b/packages/devui-vue/devui-cli/shared/logger.js deleted file mode 100644 index 4b97da0e33d88dd6405d4b16747d46d099617f4f..0000000000000000000000000000000000000000 --- a/packages/devui-vue/devui-cli/shared/logger.js +++ /dev/null @@ -1,16 +0,0 @@ -const chalk = require('chalk') - -module.exports = { - info(text) { - console.log(chalk.hex('#00afef')(text)) - }, - success(text) { - console.log(chalk.hex('#00c48f')(text)) - }, - warning(text) { - console.log(chalk.hex('#ff9800')(text)) - }, - error(text) { - console.log(chalk.hex('#f44336')(text)) - } -} diff --git a/packages/devui-vue/package.json b/packages/devui-vue/package.json index 991512f692cde0eefdf39f67d004a08557ba627f..00356e6147e72cf119dddb10fe8ec43a1cfba8a0 100644 --- a/packages/devui-vue/package.json +++ b/packages/devui-vue/package.json @@ -22,7 +22,8 @@ "devui-cli": "./devui-cli/index.js" }, "scripts": { - "dev": "yarn generate:theme && vitepress dev docs", + "predev": "devui-cli create -t vue-devui --ignore-parse-error && yarn generate:theme", + "dev": "vitepress dev docs", "build": "yarn generate:theme && vitepress build docs && cp public/* docs/.vitepress/dist/assets", "serve": "vitepress serve docs", "app:dev": "vite", @@ -33,15 +34,15 @@ "lint": "eslint \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", "lint:fix": "eslint --fix \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", "stylelint": "stylelint --fix \"{devui,src}/**/*.{scss,css}\"", - "build:components": "node ./devui-cli/index.js build", - "generate:theme": "node ./devui-cli/index.js generate:theme", + "build:components": "devui-cli build", + "generate:theme": "devui-cli generate:theme", "copy": "cp package.json build && cp README.md build && cp devui/theme/theme.scss build/theme", "clean:cli": "npm uninstall -g devui-cli & npm uninstall -g vue-devui", - "cli:create": "node ./devui-cli/index.js create -t component", - "predev": "node ./devui-cli/index.js create -t vue-devui --ignore-parse-error", - "prebuild": "node ./devui-cli/index.js create -t vue-devui --ignore-parse-error" + "cli:create": "devui-cli create -t component", + "prebuild": "devui-cli create -t vue-devui --ignore-parse-error" }, "dependencies": { + "@devui/cli": "^1.0.0", "@devui-design/icons": "^1.3.0", "@types/lodash-es": "^4.17.4", "async-validator": "^4.0.2",