From bad8c0daa6c7f45344827bb03bb09a77de551fa0 Mon Sep 17 00:00:00 2001 From: GaoNeng <31283122+GaoNeng-wWw@users.noreply.github.com> Date: Sat, 20 May 2023 20:25:21 +0800 Subject: [PATCH] =?UTF-8?q?Refactor:=20=E9=87=8D=E6=9E=84cli=20(#238)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 重构shared/utils * fix: 修复shared/utils类型错误 * refactor: 重构cli --- .../src/commands/build/handlebars.render.ts | 63 +++++++++++-------- .../cli/src/commands/create/create-ui.ts | 22 +++---- internals/cli/src/shared/module-utils.ts | 25 +++++--- internals/cli/src/shared/utils.ts | 55 +++++++++------- 4 files changed, 93 insertions(+), 72 deletions(-) diff --git a/internals/cli/src/commands/build/handlebars.render.ts b/internals/cli/src/commands/build/handlebars.render.ts index 86951745c..7d3750e98 100644 --- a/internals/cli/src/commands/build/handlebars.render.ts +++ b/internals/cli/src/commands/build/handlebars.render.ts @@ -8,10 +8,11 @@ import Handlebars from 'handlebars' let RegCache = {} let HandlebarsCompile -const replaceDelimiters = function (str, sourceReg, escape) { +const replaceDelimiters = function (str, sourceReg, escape?: boolean) { let regex = RegCache[sourceReg] || (RegCache[sourceReg] = new RegExp(sourceReg, 'g')) let match + // eslint-disable-next-line no-cond-assign while ((match = regex.exec(str))) { let prefix = str.slice(0, match.index) let inner = (escape ? '\\' : '') + '{{' + match[1] + '}}' @@ -23,31 +24,34 @@ const replaceDelimiters = function (str, sourceReg, escape) { return str } -Handlebars.setDelimiter = function (delimiters) { - if (delimiters[0].slice(-1) !== '=') { - delimiters[0] += '(?!=)' - } - - let source = delimiters[0] + '([\\s\\S]+?)' + delimiters[1] - - if (!HandlebarsCompile) { - HandlebarsCompile = Handlebars.compile - } - - Handlebars.compile = function (str) { - let args = [].slice.call(arguments) - - if (typeof str === 'string') { - if (delimiters[0] !== '{{' && delimiters[1] !== '}}') { - args[0] = replaceDelimiters(args[0], '{{([\\s\\S]+?)}}', true) - } - - args[0] = replaceDelimiters(args[0], source) +Object.defineProperty(Handlebars, 'setDelimiter', { + value(delimiters: string[]) { + if (delimiters[0].slice(-1) !== '=') { + delimiters[0] += '(?!=)' } - return HandlebarsCompile.apply(Handlebars, args) + let source = delimiters[0] + '([\\s\\S]+?)' + delimiters[1] + + if (!HandlebarsCompile) { + HandlebarsCompile = Handlebars.compile + } + + Handlebars.compile = function (str) { + // eslint-disable-next-line prefer-rest-params + let args = [].slice.call(arguments) + + if (typeof str === 'string') { + if (delimiters[0] !== '{{' && delimiters[1] !== '}}') { + args[0] = replaceDelimiters(args[0], '{{([\\s\\S]+?)}}', true) + } + + args[0] = replaceDelimiters(args[0], source) + } + + return HandlebarsCompile.apply(Handlebars, args) + } } -} +}) /** * 格式化模板 @@ -59,8 +63,13 @@ Handlebars.setDelimiter = function (delimiters) { * @param {Object} delimiter * @returns {String} */ -export default function ({ delimiter, template, options, data }) { - delimiter && Handlebars.setDelimiter(delimiter) - - return Handlebars.compile(template, options)(data) +export default function ({ delimiter, template, options, data }: { + delimiter?: string[] + template: string + options?: CompileOptions + data: any +}) { + delimiter && (Handlebars as typeof Handlebars & { setDelimiter: (delimiter: string[]) => any }).setDelimiter(delimiter) + const compile = Handlebars.compile(template, options) + return compile(data) } diff --git a/internals/cli/src/commands/create/create-ui.ts b/internals/cli/src/commands/create/create-ui.ts index 14f44a49e..c3445ceda 100644 --- a/internals/cli/src/commands/create/create-ui.ts +++ b/internals/cli/src/commands/create/create-ui.ts @@ -5,21 +5,21 @@ * yarn create:ui img-preview -single 输出纯净模板(没有 pc 等模板/单层组件) * yarn create:ui img-preview -mobile 创建纯移动组件 */ -const path = require('path') -const fs = require('fs-extra') -const semver = require('semver') -const utils = require('./utils') -const { createModuleMapping } = require('./module-utils') -const handlebarsRender = require('./handlebars.render') +import path from 'path' +import fs from 'fs-extra' +import semver from 'semver' +import * as utils from '../../shared/utils' +import { createModuleMapping } from '../../shared/module-utils' +import handlebarsRender from '../build/handlebars.render' const args = utils.getInputCmd() if (args.length > 0) { - const commands = [] - const components = [] - const templateDir = utils.pathJoin('../template/component') - const componetDir = utils.pathJoin('../../packages/vue/components') - const { version } = fs.readJSONSync(utils.pathJoin('../../packages/vue/package.json')) + const commands: string[] = [] + const components: string[] = [] + const templateDir = utils.pathJoin('../../public/template/component') + const componetDir = utils.pathJoin('../../../../packages/vue/src') + const { version } = fs.readJSONSync(utils.pathJoin('../../../../packages/vue/package.json')) args.forEach((item) => { if (item.indexOf('-') === 0) { diff --git a/internals/cli/src/shared/module-utils.ts b/internals/cli/src/shared/module-utils.ts index 969e2994b..5e070e102 100644 --- a/internals/cli/src/shared/module-utils.ts +++ b/internals/cli/src/shared/module-utils.ts @@ -47,7 +47,7 @@ export interface Module { * @param {Boolean} isSort 是否需要排序 * @returns 模块对象 */ -const getAllModules = (isSort) => { +const getAllModules = (isSort: boolean) => { return getSortModules({ filterIntercept: () => true, isSort }) } @@ -55,7 +55,7 @@ const getAllModules = (isSort) => { * @param {String} key 根据模块对象的 Key 获取对应的值 * @returns 模块对象 */ -const getModuleInfo = (key) => { +const getModuleInfo = (key: string) => { return moduleMap[key] || {} } @@ -66,7 +66,10 @@ const getModuleInfo = (key) => { * @param {Boolean} isOriginal 是否取原始数据 * @param {Boolean} isSort 是否需要排序 */ -const getByName = ({ name, inversion = false, isOriginal = false, isSort = true }) => { +const getByName = ( + { name, inversion = false, isOriginal = false, isSort = true }: + { name: string;inversion: boolean;isOriginal: boolean;isSort: boolean } +) => { const callback = (item) => { const result = new RegExp(`/${name}/|^vue-${name}/`).test(item.path) return inversion ? !result : result @@ -80,7 +83,7 @@ const getByName = ({ name, inversion = false, isOriginal = false, isSort = true * @private * @param {Function} filterIntercept 搜索条件 */ -const getModules = (filterIntercept) => { +const getModules = (filterIntercept: Function) => { let modules = {} if (typeof filterIntercept === 'function') { @@ -104,7 +107,7 @@ const getModules = (filterIntercept) => { * @param {Function} filterIntercept 搜索条件 * @param {Boolean} isSort 是否需要排序 */ -const getSortModules = ({ filterIntercept, isSort = true }) => { +const getSortModules = ({ filterIntercept, isSort = true }: { filterIntercept: Function; isSort: boolean }) => { let modules: Module[] = [] let componentCount = 0 const importName = '@opentiny/vue' @@ -119,7 +122,7 @@ const getSortModules = ({ filterIntercept, isSort = true }) => { // 这段逻辑暂时没有用到 const componentName = dirs.slice(1, dirs.indexOf('src')) // UpperName: Todo - component.UpperName = utils.capitalizeKebabCase(componentName.pop()) + component.UpperName = utils.capitalizeKebabCase(componentName.pop() ?? '') // LowerName: todo component.LowerName = utils.kebabCase({ str: component.UpperName }) @@ -331,7 +334,7 @@ const isNotArrayObject = (sortData, key, setIndex) => { let sortItem = {} if (typeof dataItem !== 'object') { - sortItem.__real_value = dataItem + (sortItem as unknown as Record).__real_value = dataItem } else { sortItem = { ...sortData[sortKey] @@ -375,11 +378,13 @@ const getComponents = (mode, isSort = true) => { * 获取模块项的模块 * @param {String} componentName 组件名称(大写,例如:img-preview) * @param {Oject} newObj 新增对象 - * @param {Boolean} isMobile 是否为移动组件 * @returns 模块对象 */ -export const addModule = ({ componentName, templateName, newObj = {}, isMobile = false }) => { - const isEntry = templateName.endsWith('index') +export const addModule = ( + { componentName, templateName, newObj = {} }: + { componentName: string; templateName?: string; newObj?: object; isMobile: boolean } +) => { + const isEntry = templateName?.endsWith('index') ?? false return { path: `vue/src/${componentName}/` + (isEntry ? `${templateName}.ts` : `src/${templateName}.vue`), type: isEntry ? 'component' : 'template', diff --git a/internals/cli/src/shared/utils.ts b/internals/cli/src/shared/utils.ts index a09be9feb..e73a5dfbf 100644 --- a/internals/cli/src/shared/utils.ts +++ b/internals/cli/src/shared/utils.ts @@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url' import { searchForWorkspaceRoot } from 'vite' const workspaceRoot = searchForWorkspaceRoot(process.cwd()) -const pathFromWorkspaceRoot = (...args) => path.resolve(workspaceRoot, ...args) +const pathFromWorkspaceRoot = (...args: string[]) => path.resolve(workspaceRoot, ...args) const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -17,7 +17,7 @@ const dirname = path.dirname(filename) * 根据运行上下文获取路径(运行时打包用) * @returns 文件绝对路径 */ -const resolveCwd = (...args) => { +const resolveCwd = (...args: any[]) => { return path.join(process.cwd(), ...args) } @@ -26,7 +26,7 @@ const resolveCwd = (...args) => { * @param {String} posixPath 路径 * @returns 文件绝对路径 */ -const assetsPath = (posixPath) => { +const assetsPath = (posixPath: string) => { return path.posix.join('static', posixPath) } @@ -42,7 +42,7 @@ const getComponentName = () => { * 获取当前上下文的路径 * @returns 文件绝对路径 */ -const pathJoin = (...args) => { +const pathJoin = (...args: string[]) => { return path.join(dirname, ...args) } @@ -79,7 +79,7 @@ const getCurrentCliTool = () => { * 执行 node 命令 * @param {String} cmdStr 命令字符串 */ -const execCmd = (cmdStr) => { +const execCmd = (cmdStr: string) => { cmdStr && execSync(cmdStr, { stdio: 'inherit' }) } @@ -88,7 +88,7 @@ const execCmd = (cmdStr) => { * @param {String} str 字符串 * @returns 字符串 */ -const capitalize = (str) => { +const capitalize = (str: string) => { return typeof str === 'string' ? str.slice(0, 1).toUpperCase() + str.slice(1) : str } @@ -97,7 +97,7 @@ const capitalize = (str) => { * @param {String} str 字符串 * @returns 字符串 */ -const capitalizeKebabCase = (str, splitChar = '-') => { +const capitalizeKebabCase = (str: string, splitChar = '-') => { return typeof str === 'string' ? str.split(splitChar).map(capitalize).join('') : str } @@ -109,7 +109,7 @@ const capitalizeKebabCase = (str, splitChar = '-') => { * @param str 字符串 * @param splitChar 分隔符 */ -const kebabCase = ({ str, splitChar = '-' }) => { +const kebabCase = ({ str, splitChar = '-' }: { str: string; splitChar?: string }) => { if (!str || typeof str !== 'string') return str return str @@ -119,7 +119,7 @@ const kebabCase = ({ str, splitChar = '-' }) => { if (charCod < 65 || charCod > 122) return char - return (charCod >= 65 && charCod) <= 90 ? (index !== 0 ? splitChar : '') + char.toLowerCase() : char + return (charCod >= 65 && charCod <= 90) ? (index !== 0 ? splitChar : '') + char.toLowerCase() : char }) .join('') } @@ -129,7 +129,7 @@ const kebabCase = ({ str, splitChar = '-' }) => { * @param {String} str 格式字符 * @param {Object} options 格式字符 */ -const prettierFormat = ({ str, options = {} }) => { +const prettierFormat = ({ str, options = {} }: { str: string; options: object }) => { return prettier.format( str, Object.assign( @@ -156,7 +156,10 @@ const prettierFormat = ({ str, options = {} }) => { * @param {Function} fileFilter 文件筛选拦截函数 * @param {Function} callback 遍历回调 */ -const walkFileTree = ({ dirPath, isDeep = false, fileFilter, callback }) => { +const walkFileTree = ( + { dirPath, isDeep = false, fileFilter, callback }: + { dirPath: string; isDeep: boolean; fileFilter?: Function; callback: Function } +) => { if (!dirPath || typeof callback !== 'function') { return } @@ -192,7 +195,7 @@ const walkFileTree = ({ dirPath, isDeep = false, fileFilter, callback }) => { * @param {Boolean} 是否为 vue2 环境 * @returns 版本号 */ -const getVersion = ({ name, context, isVue2 }) => { +const getVersion = ({ name, context, isVue2 }: { name: string; context: string; isVue2: boolean }) => { return getComponentVersion({ name, context, dir: 'node_modules', isVue2 }) } @@ -204,8 +207,11 @@ const getVersion = ({ name, context, isVue2 }) => { * @param {Boolean} 是否为 vue2 环境 * @returns 版本号 */ -const getComponentVersion = ({ name, context = '..', dir = 'packages', isOrigin = false, isVue2 }) => { - let version +const getComponentVersion = ( + { name, context = '..', dir = 'packages', isOrigin = false, isVue2 }: + { name: string; context?: string; dir?: string; isOrigin?: boolean; isVue2: boolean } +) => { + let version: string const packageJSONPath = pathJoin(context, dir, name, 'package.json') if (fs.existsSync(packageJSONPath)) { @@ -228,7 +234,7 @@ const getComponentVersion = ({ name, context = '..', dir = 'packages', isOrigin * @param {Boolean} 是否为 vue2 环境 * @returns */ -const getPublichVersion = ({ version, isVue2 }) => { +const getPublichVersion = ({ version, isVue2 }: { version: string; isVue2: boolean }) => { if (isVue2) { return version.replace(/^4/, '3').replace('?v=4', '?v=3') } @@ -243,7 +249,7 @@ const getPublichVersion = ({ version, isVue2 }) => { * @param {Boolean} 是否为 vue2 环境 * @returns 版本号 */ -const getPackageVersion = ({ name, isRoot = false, isVue2 = false }) => { +const getPackageVersion = ({ name, isRoot = false, isVue2 = false }: { name: string; isRoot: boolean; isVue2: boolean }) => { let version = isRoot ? getopentinyVersion({ key: name }) : getComponentVersion({ name, isOrigin: true, isVue2 }) return getBigVersion(version) @@ -259,7 +265,7 @@ const getBigVersion = (version) => { * @param {Boolean} 是否为 vue2 环境 * @returns 版本号 */ -const getComponentOriginVersion = ({ name, isVue2 }) => { +const getComponentOriginVersion = ({ name, isVue2 }: { name: string; isVue2: boolean }) => { return getComponentVersion({ name, isOrigin: true, isVue2 }) } @@ -269,7 +275,7 @@ const getComponentOriginVersion = ({ name, isVue2 }) => { * @param {Boolean} 是否为 vue2 环境 * @returns 版本号 */ -const getopentinyVersion = ({ key = 'version' }) => { +const getopentinyVersion = ({ key = 'version' }: { key: string }) => { const packageJson = fs.readJsonSync(pathFromWorkspaceRoot('packages/vue/package.json')) const packageJsonOption = packageJson[key] || packageJson @@ -318,7 +324,7 @@ const getInnerDependenciesVersion = ({ isTestEnv, tag, version }) => { * 在控制台显示绿色提示 * @param {String} 提示内容 */ -const logGreen = (str) => { +const logGreen = (str: string) => { /* eslint-disable no-console */ console.log(chalk.green('### ' + str)) } @@ -327,7 +333,7 @@ const logGreen = (str) => { * 在控制台显示黄色提示 * @param {String} 提示内容 */ -const logYellow = (str) => { +const logYellow = (str: string) => { console.log(chalk.yellow('### ' + str)) } @@ -335,7 +341,7 @@ const logYellow = (str) => { * 在控制台显示青色提示 * @param {String} 提示内容 */ -const logCyan = (str) => { +const logCyan = (str: string) => { console.log(chalk.cyan('### ' + str)) } @@ -343,7 +349,7 @@ const logCyan = (str) => { * 在控制台显示红色提示 * @param {String} 提示内容 */ -const logRed = (str) => { +const logRed = (str: string) => { console.log(chalk.red('### ' + str)) } @@ -421,7 +427,7 @@ const getBuildTag = ({ version }) => { * * @return {Array} filesPath */ -const getFilesPath = (folderPath) => { +const getFilesPath = (folderPath: string): Array => { let filesPath: string[] = [] try { let files = fs.readdirSync(folderPath) @@ -430,6 +436,7 @@ const getFilesPath = (folderPath) => { let stats = fs.statSync(tempPath) if (stats.isDirectory()) { + // eslint-disable-next-line prefer-spread filesPath.push.apply(filesPath, getFilesPath(tempPath)) } else { filesPath.push(tempPath) @@ -469,7 +476,7 @@ const fragmentReplace = (filePath, regExpStr, targetStr) => { * @param {Array | string} regExpStr * @param {Array | string} targetStr */ -const filesFragmentReplace = (folderPath, regExpStr, targetStr) => { +const filesFragmentReplace = (folderPath, regExpStr: Array | string, targetStr: Array | string) => { let filesPath = getFilesPath(folderPath) if (filesPath) {