From 0e5a082bc6de16607e9154e65f03ed5f0d39dcfb Mon Sep 17 00:00:00 2001 From: VictorBo Date: Thu, 27 Jun 2024 12:14:08 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=87=BD=E6=95=B0=E8=84=9A=E6=9C=AC=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=88=9B=E5=BB=BA=E4=BD=BF=E7=94=A8=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 6 +- packages/is/index.ts | 44 +++--- pnpm-lock.yaml | 64 +++----- scripts/create-function.ts | 66 ++++++++ scripts/create-subpackage.ts | 233 +++++++++++++++-------------- scripts/create.ts | 47 ++++++ scripts/utils.ts | 86 ++++++++++- template/__test__/index.test.ts | 8 - template/__test__/template.test.ts | 8 + template/index.ts | 2 +- template/src/index.ts | 3 - template/src/template.ts | 3 + 12 files changed, 381 insertions(+), 189 deletions(-) create mode 100644 scripts/create-function.ts create mode 100644 scripts/create.ts delete mode 100644 template/__test__/index.test.ts create mode 100644 template/__test__/template.test.ts delete mode 100644 template/src/index.ts create mode 100644 template/src/template.ts diff --git a/package.json b/package.json index 6c16ed4..39831c8 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,9 @@ "node": ">=18.0.0" }, "scripts": { - "create": "esno scripts/create-subpackage.ts", + "create:subpackage": "esno scripts/create-subpackage.ts", + "create:function": "esno scripts/create-function.ts", + "create": "esno scripts/create.ts", "build": "pnpm -r --filter=./packages/* run build", "docs": "pnpm -F xparcai-utils-docs run docs:dev", "docs:build": "pnpm -F xparcai-utils-docs run docs:build", @@ -48,6 +50,7 @@ "devDependencies": { "@antfu/eslint-config": "^2.21.1", "@babel/preset-env": "^7.24.7", + "@posva/prompts": "^2.4.4", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-eslint": "^9.0.5", @@ -59,6 +62,7 @@ "bumpp": "^9.4.1", "eslint-plugin-format": "^0.1.1", "esno": "^4.7.0", + "fast-glob": "^3.3.2", "jsdom": "^24.1.0", "lint-staged": "^15.2.7", "magic-string": "^0.30.10", diff --git a/packages/is/index.ts b/packages/is/index.ts index 0157a92..ed46b2f 100644 --- a/packages/is/index.ts +++ b/packages/is/index.ts @@ -1,29 +1,29 @@ -export * from './src/isType' -export * from './src/isString' -export * from './src/isNull' -export * from './src/isRegExp' -export * from './src/isUndefined' -export * from './src/isDate' -export * from './src/isNumber' -export * from './src/isPromise' -export * from './src/isFunction' +export * from './src/isArray' export * from './src/isBigInt' -export * from './src/isSymbol' -export * from './src/isFalse' -export * from './src/isTrue' -export * from './src/isNaN' -export * from './src/isMap' export * from './src/isBoolean' -export * from './src/isSet' -export * from './src/isArray' -export * from './src/isObject' -export * from './src/isMobile' -export * from './src/isEmail' +export * from './src/isDate' export * from './src/isElement' -export * from './src/isHttp' -export * from './src/isLowerCase' -export * from './src/isEmptyObject' +export * from './src/isEmail' export * from './src/isEmptyArray' +export * from './src/isEmptyObject' export * from './src/isError' +export * from './src/isFalse' +export * from './src/isFunction' +export * from './src/isHttp' export * from './src/isIDCard' +export * from './src/isLowerCase' +export * from './src/isMap' +export * from './src/isMobile' +export * from './src/isNaN' +export * from './src/isNull' +export * from './src/isNumber' export * from './src/isNumberString' +export * from './src/isObject' +export * from './src/isPromise' +export * from './src/isRegExp' +export * from './src/isSet' +export * from './src/isString' +export * from './src/isSymbol' +export * from './src/isTrue' +export * from './src/isType' +export * from './src/isUndefined' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0769d03..0224d6d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@babel/preset-env': specifier: ^7.24.7 version: 7.24.7(@babel/core@7.24.7) + '@posva/prompts': + specifier: ^2.4.4 + version: 2.4.4 '@rollup/plugin-babel': specifier: ^6.0.4 version: 6.0.4(@babel/core@7.24.7)(rollup@4.18.0) @@ -47,6 +50,9 @@ importers: esno: specifier: ^4.7.0 version: 4.7.0 + fast-glob: + specifier: ^3.3.2 + version: 3.3.2 jsdom: specifier: ^24.1.0 version: 24.1.0 @@ -1118,6 +1124,10 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@posva/prompts@2.4.4': + resolution: {integrity: sha512-8aPwklhbSV2VN/NQMBNFkuo8+hlJVdcFRXp4NCIfdcahh3qNEcaSoD8qXjru0OlN1sONJ7le7p6+YUbALaG6Mg==} + engines: {node: '>= 14'} + '@rollup/plugin-babel@6.0.4': resolution: {integrity: sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==} engines: {node: '>=14.0.0'} @@ -1663,10 +1673,6 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -2292,10 +2298,6 @@ packages: fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2313,10 +2315,6 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -2846,6 +2844,10 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -2947,10 +2949,6 @@ packages: micromark@2.11.4: resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} @@ -5318,6 +5316,11 @@ snapshots: '@pkgr/core@0.1.1': {} + '@posva/prompts@2.4.4': + dependencies: + kleur: 4.1.5 + sisteransi: 1.0.5 + '@rollup/plugin-babel@6.0.4(@babel/core@7.24.7)(rollup@4.18.0)': dependencies: '@babel/core': 7.24.7 @@ -5905,10 +5908,6 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: - dependencies: - fill-range: 7.0.1 - braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -6018,7 +6017,7 @@ snapshots: chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -6734,21 +6733,13 @@ snapshots: fast-diff@1.3.0: {} - fast-glob@3.3.1: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-json-stable-stringify@2.1.0: {} @@ -6762,10 +6753,6 @@ snapshots: dependencies: flat-cache: 3.2.0 - fill-range@7.0.1: - dependencies: - to-regex-range: 5.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -6951,7 +6938,7 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.3.2 ignore: 5.3.0 merge2: 1.4.1 slash: 3.0.0 @@ -7300,6 +7287,8 @@ snapshots: kleur@3.0.3: {} + kleur@4.1.5: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -7430,11 +7419,6 @@ snapshots: transitivePeerDependencies: - supports-color - micromatch@4.0.5: - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - micromatch@4.0.7: dependencies: braces: 3.0.3 diff --git a/scripts/create-function.ts b/scripts/create-function.ts new file mode 100644 index 0000000..10f1495 --- /dev/null +++ b/scripts/create-function.ts @@ -0,0 +1,66 @@ +import process from 'node:process' +import fs from 'node:fs' +import prompts from '@posva/prompts' +import ora from 'ora' +import { loadFunction, loadSubpackage, packagePrefix, resolveRealPath, spinnersPrefixText, toCamelCase, writeSubpackageFunction, writeSubpackageFunctionTest } from './utils' + +const [, , ...args] = process.argv + +// 写子包的index.ts - 这里侧重的是增加导出 +function writeSubpackageIndex(subpackageName: string, functionName: string) { + const exportPath = resolveRealPath(`../packages/${subpackageName}/index.ts`) + let exportContent = fs.readFileSync(exportPath, 'utf-8').trim().split('\n').sort().join('\n') + exportContent += '\n' + `export * from './src/${functionName}'` + '\n' + fs.writeFileSync(exportPath, exportContent) +} + +// 创建函数 +async function createFunction() { + let subpackageName = args[0] + let functionName = args[1] + const { choices } = loadSubpackage() + if (!subpackageName || !functionName) { + // 无参调起交互式命令行 + const response = await prompts([ + { + name: 'subpackage', + type: 'select', + message: '请选择子包', + choices, + }, + { + name: 'name', + type: 'text', + message: '请输入函数名称', + validate: (value) => { + if (!value.trim()) { + return '请输入函数名称' + } + return true + }, + }, + ]) + subpackageName = response.subpackage.trim() + functionName = response.name.trim() + } + + // 转换为小驼峰 + functionName = toCamelCase(functionName) + + const { dirNames: functionDirNames } = loadFunction(subpackageName) + + // 校验方法是否存在 + if (functionDirNames.includes(functionName)) { + return console.error(`方法${functionName}已存在`) + } + + const spinners = ora() + spinners.text = `${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}] => ${functionName}中...` + spinners.start() + writeSubpackageIndex(subpackageName, functionName) + writeSubpackageFunction(subpackageName, functionName) + writeSubpackageFunctionTest(subpackageName, functionName) + spinners.succeed(`${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}] => ${functionName}成功`) +} + +await createFunction() diff --git a/scripts/create-subpackage.ts b/scripts/create-subpackage.ts index 57ccd83..6e7e1df 100644 --- a/scripts/create-subpackage.ts +++ b/scripts/create-subpackage.ts @@ -1,162 +1,171 @@ import process from 'node:process' import fs from 'node:fs' -import { basename, resolve } from 'node:path' +import { resolve } from 'node:path' import { fileURLToPath } from 'node:url' import ora from 'ora' import MagicString from 'magic-string' -import { resolveRealPath, runCommand } from './utils' +import prompts from '@posva/prompts' +import { loadFunction, loadSubpackage, packagePrefix, resolveRealPath, runCommand, sortJsonObject, spinnersPrefixText, toCamelCase, toLinesCase, writeSubpackageFunction, writeSubpackageFunctionTest } from './utils' const [, , ...args] = process.argv -const subpackageNamePrefix = '@xparcai-utils/' -const packagesDirPath = resolveRealPath('../packages') -const templateDirPath = resolveRealPath('../template') - -// 复制模板文件 -function copySubpackageTemplate({ - templateDirPath, - subpackageDirPath, - subpackageName, -}: { - templateDirPath: string - subpackageDirPath: string - subpackageName: string -}) { +// 复制模板 +function copyTemplate(templatePath: string, subpackagePath: string, functionName: string) { + const templateDirPath = resolveRealPath(templatePath) + const subpackageDirPath = resolveRealPath(subpackagePath) + const stats = fs.statSync(templateDirPath) - // 创建文件夹 if (stats.isDirectory()) { fs.mkdirSync(subpackageDirPath, { recursive: true }) for (const file of fs.readdirSync(templateDirPath)) { - copySubpackageTemplate({ - templateDirPath: resolve(templateDirPath, file), - subpackageDirPath: resolve(subpackageDirPath, file), - subpackageName, - }) + const waitRenameFileNames = ['template.test.ts', 'template.ts'] + let renameFile = file + if (waitRenameFileNames.includes(file)) { + renameFile = file.replace(/template/g, functionName) + } + copyTemplate(resolve(templateDirPath, file), resolve(subpackageDirPath, renameFile), functionName) } return } - // 写package.json - if (basename(templateDirPath) === 'package.json') { - const pkg = JSON.parse(fs.readFileSync(templateDirPath, 'utf-8')) - pkg.name = `@xparcai-utils/${subpackageName}` - fs.writeFileSync(subpackageDirPath, `${JSON.stringify(pkg, null, 2)}\n`) - return - } - - // 写tsconfig.json - if (basename(templateDirPath) === 'tsconfig.json') { - const tsconfig = JSON.parse(fs.readFileSync(templateDirPath, 'utf-8')) - tsconfig.extends = '../../tsconfig.json' - fs.writeFileSync(subpackageDirPath, `${JSON.stringify(tsconfig, null, 2)}\n`) - return - } + fs.copyFileSync(templateDirPath, subpackageDirPath) +} - // 改rollup.config.ts - if (basename(templateDirPath) === 'rollup.config.ts') { - let rollupConfig = fs.readFileSync(templateDirPath, 'utf-8') - rollupConfig = rollupConfig.replace('../scripts/rollup-config', '../../scripts/rollup-config') - fs.writeFileSync(subpackageDirPath, rollupConfig) - return - } +// 写core的index.ts +function writeCoreIndex(subpackageName: string) { + const filePath = resolveRealPath('../packages/core/index.ts') + const fileContent = fs.readFileSync(filePath, 'utf-8') + const mst = new MagicString(fileContent) + mst.append(`export * from '${packagePrefix}/${subpackageName}'\n`) + fs.writeFileSync(filePath, mst.toString()) +} - // 改index.test.ts - if (basename(templateDirPath) === 'index.test.ts') { - let testContent = fs.readFileSync(templateDirPath, 'utf-8') - testContent = testContent.replace('vitest module', `@xparcai-utils/${subpackageName}`) - fs.writeFileSync(subpackageDirPath, testContent) - return - } +// 写core的package.json +function writeCorePackage(subpackageName: string) { + const filePath = resolveRealPath('../packages/core/package.json') + const fileContent = JSON.parse(fs.readFileSync(filePath, 'utf-8')) + fileContent.dependencies = sortJsonObject({ + ...fileContent.dependencies, + [`${packagePrefix}/${subpackageName}`]: 'workspace:*', + }) + fs.writeFileSync(filePath, `${JSON.stringify(fileContent, null, 2)}\n`) +} - fs.copyFileSync(templateDirPath, subpackageDirPath) +// 写子包的tsconfig.json +function writeSubpackageTsconfig(subpackageName: string) { + const filePath = resolveRealPath(`../packages/${subpackageName}/tsconfig.json`) + const fileContent = JSON.parse(fs.readFileSync(filePath, 'utf-8')) + fileContent.extends = '../../tsconfig.json' + fs.writeFileSync(filePath, `${JSON.stringify(fileContent, null, 2)}\n`) } -// 排序package.json dependencies -function sortPackageDependencies(obj: Record) { - const keys = Object.keys(obj).sort() - return keys.reduce((acc: Record, key) => { - acc[key] = obj[key] - return acc - }, {}) +// 写子包的rollup.config.ts +function writeSubpackageRollupconfig(subpackageName: string) { + const filePath = resolveRealPath(`../packages/${subpackageName}/rollup.config.ts`) + let fileContent = fs.readFileSync(filePath, 'utf-8') + fileContent = fileContent.replace('../scripts/rollup-config', '../../scripts/rollup-config') + fs.writeFileSync(filePath, fileContent) } -// 添加到core包依赖 -function insertCorePackageDependencies(subpackageNameFull: string) { - const coreDirPath = resolveRealPath(`${packagesDirPath}/core/package.json`) - const pkg = JSON.parse(fs.readFileSync(coreDirPath, 'utf-8')) - pkg.dependencies = sortPackageDependencies({ - ...pkg.dependencies, - [subpackageNameFull]: 'workspace:*', - }) - fs.writeFileSync(coreDirPath, `${JSON.stringify(pkg, null, 2)}\n`) +// 写子包的package.json +function writeSubpackagePackage(subpackageName: string) { + const filePath = resolveRealPath(`../packages/${subpackageName}/package.json`) + const fileContent = JSON.parse(fs.readFileSync(filePath, 'utf-8')) + fileContent.name = `${packagePrefix}/${subpackageName}` + fs.writeFileSync(filePath, `${JSON.stringify(fileContent, null, 2)}\n`) } -// 添加到core包主入口导出 -function insertCorePackageExport(subpackageNameFull: string) { - const coreDirPath = resolveRealPath(`${packagesDirPath}/core/index.ts`) - const coreExport = fs.readFileSync(coreDirPath, 'utf-8') - const mst = new MagicString(coreExport) - mst.append(`export * from '${subpackageNameFull}'`) - fs.writeFileSync(coreDirPath, `${mst.toString()}\n`) +// 写子包的index.ts - 这里侧重的是修改导出名称 +function writeSubpackageIndex(subpackageName: string, functionName: string) { + const filePath = resolveRealPath(`../packages/${subpackageName}/index.ts`) + let fileContent = fs.readFileSync(filePath, 'utf-8') + fileContent = fileContent.replace(/template/g, functionName) + fs.writeFileSync(filePath, fileContent) } // 安装依赖 -function installDependencies() { +function pnpmInstall() { const dirname = fileURLToPath(new URL('../', import.meta.url)) return runCommand(`pnpm install`, dirname) } -// 转换为_-连接的字符 -function toLinesCase(str: string, isUnder: boolean = false): string { - return str - .replace(/^[-|_]+|[-|_]+$/g, '') - .replace(/^[A-Z]/g, key => key.toLowerCase()) - .replace(/[A-Z]/g, key => `${isUnder ? '_' : '-'}${key.toLowerCase()}`) -} - // 创建子包 -function createSubpackage() { +async function createSubpackage() { let subpackageName = args[0] - if (!subpackageName) { - return console.log('未提供子包的名称') + let functionName = args[1] + + if (!subpackageName || !functionName) { + // 无参调起交互式命令行 + const response = await prompts([ + { + name: 'subpackage', + type: 'text', + message: '请输入包名', + validate: (value) => { + if (!value.trim()) { + return '请输入包名' + } + return true + }, + }, + { + name: 'function', + type: 'text', + message: '请输入函数名称', + validate: (value) => { + if (!value.trim()) { + return '请输入函数名称' + } + return true + }, + }, + ]) + subpackageName = response.subpackage.trim() + functionName = response.function.trim() } - // 转换为短横线连接 + // 转换为短横线 subpackageName = toLinesCase(subpackageName) + // 转换为小驼峰 + functionName = toCamelCase(functionName) - // 子包全名 - const subpackageNameFull = `${subpackageNamePrefix}${subpackageName}` + const { dirNames: subpackageDirNames } = loadSubpackage() // 校验子包是否存在 - const subpackageDirPath = resolveRealPath(`${packagesDirPath}/${subpackageName}`) - if (fs.existsSync(subpackageDirPath)) { - return console.log(`子包[${subpackageNameFull}]已存在`) + if (subpackageDirNames.includes(subpackageName)) { + return console.error(`子包${subpackageName}已存在`) } - const spinnersPrefixText = '[xparcai-utils]: ' - const spinners = ora() - - spinners.text = `${spinnersPrefixText}创建[${subpackageNameFull}]子包中...` - spinners.start() + const { dirNames: functionDirNames } = loadFunction(subpackageName) - // 复制模板文件 - copySubpackageTemplate({ templateDirPath, subpackageDirPath, subpackageName }) - // 添加到core的生产依赖中 - insertCorePackageDependencies(subpackageNameFull) - // 添加到core包主入口导出 - insertCorePackageExport(subpackageNameFull) - - spinners.succeed(`${spinnersPrefixText}创建[${subpackageNameFull}]子包成功`) + // 校验方法是否存在 + if (functionDirNames.includes(functionName)) { + return console.error(`方法${functionName}已存在`) + } - spinners.text = `${spinnersPrefixText}依赖安装中...` + const spinners = ora() + spinners.text = `${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}]子包中...` spinners.start() - // 安装依赖 - installDependencies().then(() => { - spinners.succeed(`${spinnersPrefixText}安装依赖成功`) + const innerSpinners = ora() + innerSpinners.text = `${spinnersPrefixText}复制模板...` + innerSpinners.start() + copyTemplate('../template', `../packages/${subpackageName}`, functionName) + writeCoreIndex(subpackageName) + writeCorePackage(subpackageName) + writeSubpackageTsconfig(subpackageName) + writeSubpackageRollupconfig(subpackageName) + writeSubpackagePackage(subpackageName) + writeSubpackageIndex(subpackageName, functionName) + writeSubpackageFunction(subpackageName, functionName) + writeSubpackageFunctionTest(subpackageName, functionName) + innerSpinners.succeed(`${spinnersPrefixText}复制模板成功`) + + pnpmInstall().then(() => { + spinners.succeed(`${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}]子包成功`) }).catch(() => { - spinners.fail(`${spinnersPrefixText}安装依赖失败`) + spinners.fail(`${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}]子包失败`) }) } -createSubpackage() +await createSubpackage() diff --git a/scripts/create.ts b/scripts/create.ts new file mode 100644 index 0000000..cabcd09 --- /dev/null +++ b/scripts/create.ts @@ -0,0 +1,47 @@ +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import prompts from '@posva/prompts' +import { loadSubpackage, runCommand } from './utils' + +const [, , ...args] = process.argv + +async function create() { + if (args.length !== 2) { + const type = ( + await prompts([ + { + name: 'type', + type: 'select', + message: '请选择子包', + choices: [ + { title: '创建子包', value: 'subpackage' }, + { title: '创建函数', value: 'function' }, + ], + }, + ]) + ).type + + const dirname = fileURLToPath(new URL('../', import.meta.url)) + runCommand(`pnpm run create:${type}`, dirname) + } + else { + const subpackageName = args[0] + const functionName = args[1] + + const { dirNames: subpackageDirNames } = loadSubpackage() + + // 校验子包是否存在 + if (!subpackageDirNames.includes(subpackageName)) { + // 不存在: 创建子包 + const dirname = fileURLToPath(new URL('../', import.meta.url)) + runCommand(`pnpm run create:subpackage ${subpackageName} ${functionName}`, dirname) + } + else { + // 存在: 创建函数 + const dirname = fileURLToPath(new URL('../', import.meta.url)) + runCommand(`pnpm run create:function ${subpackageName} ${functionName}`, dirname) + } + } +} + +await create() diff --git a/scripts/utils.ts b/scripts/utils.ts index 8b01abc..9a243ed 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -1,13 +1,18 @@ import type { ProcessEnvOptions } from 'node:child_process' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' +import fs from 'node:fs' import type { ExecOptions } from 'shelljs' +import fg from 'fast-glob' import shell from 'shelljs' -export function resolveRealPath(path: string) { +export const packagePrefix = '@xparcai-utils' +export const spinnersPrefixText = '[xparcai-utils]: ' + +export function resolveRealPath(...args: string[]) { const fileName = fileURLToPath(import.meta.url) const dirName = dirname(fileName) - return resolve(dirName, path) + return resolve(dirName, ...args) } export function runCommand(command: string, dir: ProcessEnvOptions['cwd'], userOptions: ExecOptions = {}) { @@ -43,3 +48,80 @@ export function runCommand(command: string, dir: ProcessEnvOptions['cwd'], userO } }) } + +// 加载子包 +export function loadSubpackage() { + const packageFiles = fg.globSync(['packages/*/package.json', '!packages/core/package.json']) + return { + dirs: packageFiles.map(m => m.split('/').slice(0, 2).join('/')), + dirNames: packageFiles.map(m => m.split('/')[1]), + subpackages: packageFiles.map(m => `${packagePrefix}/${m.split('/')[1]}`), + choices: packageFiles.map((m) => { + const title = `${packagePrefix}/${m.split('/')[1]}` + const value = m.split('/')[1] + return { + title, + value, + } + }), + } +} + +// 加载方法 +export function loadFunction(subpackage: string) { + const functionFiles = fg.globSync(`packages/${subpackage}/src/*.ts`) + return { + dirs: functionFiles.map(m => m.split('/').slice(0, 3).join('/')), + dirNames: functionFiles.map(m => m.split('/')[3].replace(/\.ts/g, '')), + subpackages: functionFiles.map(m => `${packagePrefix}/${m.split('/')[1]}`), + } +} + +// 转换为_-连接的字符 +export function toLinesCase(str: string, isUnder: boolean = false): string { + return str + .replace(/^[-|_]+|[-|_]+$/g, '') + .replace(/^[A-Z]/g, key => key.toLowerCase()) + .replace(/[A-Z]/g, key => `${isUnder ? '_' : '-'}${key.toLowerCase()}`) +} + +// 首字母大写 +export function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1) +} + +// 转驼峰 +export function toCamelCase(str: string, isUpper: boolean = false): string { + const camelCase = str + .replace(/^[-|_]+|[-|_]+$/g, '') + .replace(/[-|_]+([a-z])/g, (_, key) => key.toUpperCase()) + .replace(/[-|_]+/g, '') + return isUpper ? capitalize(camelCase) : camelCase +} + +// json 对象排序 +export function sortJsonObject(obj: Record) { + const keys = Object.keys(obj).sort() + return keys.reduce((acc: Record, key) => { + acc[key] = obj[key] + return acc + }, {}) +} + +// 写子包函数 +export function writeSubpackageFunction(subpackageName: string, functionName: string) { + const implPath = resolveRealPath(`../packages/${subpackageName}/src/${functionName}.ts`) + const templatePath = resolveRealPath('../template/src/template.ts') + let implContent = fs.readFileSync(templatePath, 'utf-8') + implContent = implContent.replace(/template/g, functionName) + fs.writeFileSync(implPath, implContent) +} + +// 写子包函数单测 +export function writeSubpackageFunctionTest(subpackageName: string, functionName: string) { + const testPath = resolveRealPath(`../packages/${subpackageName}/__test__/${functionName}.test.ts`) + const templatePath = resolveRealPath('../template/__test__/template.test.ts') + let testContent = fs.readFileSync(templatePath, 'utf-8') + testContent = testContent.replace('vitest module', `${packagePrefix}/${subpackageName}`).replace(/template/g, functionName) + fs.writeFileSync(testPath, testContent) +} diff --git a/template/__test__/index.test.ts b/template/__test__/index.test.ts deleted file mode 100644 index ef8eeb1..0000000 --- a/template/__test__/index.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { add } from '..' - -describe('vitest module', () => { - it('add', () => { - expect(add(1, 2)).toBe(3) - }) -}) diff --git a/template/__test__/template.test.ts b/template/__test__/template.test.ts new file mode 100644 index 0000000..f399fe0 --- /dev/null +++ b/template/__test__/template.test.ts @@ -0,0 +1,8 @@ +import { describe, expect, it } from 'vitest' +import { template } from '../src/template' + +describe('vitest module', () => { + it('template', () => { + expect(template()).toBe(undefined) + }) +}) diff --git a/template/index.ts b/template/index.ts index 6f39cd4..e4be7cd 100644 --- a/template/index.ts +++ b/template/index.ts @@ -1 +1 @@ -export * from './src' +export * from './src/template' diff --git a/template/src/index.ts b/template/src/index.ts deleted file mode 100644 index fb7ab89..0000000 --- a/template/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function add(x: number, y: number) { - return x + y -} diff --git a/template/src/template.ts b/template/src/template.ts new file mode 100644 index 0000000..837c4ca --- /dev/null +++ b/template/src/template.ts @@ -0,0 +1,3 @@ +export function template() { + +} From a2fe5735eba48a10668a5939d88d3b332aa77b0b Mon Sep 17 00:00:00 2001 From: VictorBo Date: Thu, 27 Jun 2024 12:21:25 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4create=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E7=9A=84=E5=AE=9E=E7=8E=B0=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/create-function.ts | 16 ++++++++-------- scripts/create-subpackage.ts | 10 +++++----- scripts/create.ts | 21 ++++++++++++--------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/scripts/create-function.ts b/scripts/create-function.ts index 10f1495..ec25745 100644 --- a/scripts/create-function.ts +++ b/scripts/create-function.ts @@ -15,9 +15,9 @@ function writeSubpackageIndex(subpackageName: string, functionName: string) { } // 创建函数 -async function createFunction() { - let subpackageName = args[0] - let functionName = args[1] +export async function createFunction(subpackageName?: string, functionName?: string) { + subpackageName = subpackageName ?? args[0] + functionName = functionName ?? args[1] const { choices } = loadSubpackage() if (!subpackageName || !functionName) { // 无参调起交互式命令行 @@ -45,9 +45,9 @@ async function createFunction() { } // 转换为小驼峰 - functionName = toCamelCase(functionName) + functionName = toCamelCase(functionName!) - const { dirNames: functionDirNames } = loadFunction(subpackageName) + const { dirNames: functionDirNames } = loadFunction(subpackageName!) // 校验方法是否存在 if (functionDirNames.includes(functionName)) { @@ -57,9 +57,9 @@ async function createFunction() { const spinners = ora() spinners.text = `${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}] => ${functionName}中...` spinners.start() - writeSubpackageIndex(subpackageName, functionName) - writeSubpackageFunction(subpackageName, functionName) - writeSubpackageFunctionTest(subpackageName, functionName) + writeSubpackageIndex(subpackageName!, functionName) + writeSubpackageFunction(subpackageName!, functionName) + writeSubpackageFunctionTest(subpackageName!, functionName) spinners.succeed(`${spinnersPrefixText}创建[${packagePrefix}/${subpackageName}] => ${functionName}成功`) } diff --git a/scripts/create-subpackage.ts b/scripts/create-subpackage.ts index 6e7e1df..f8628fa 100644 --- a/scripts/create-subpackage.ts +++ b/scripts/create-subpackage.ts @@ -90,9 +90,9 @@ function pnpmInstall() { } // 创建子包 -async function createSubpackage() { - let subpackageName = args[0] - let functionName = args[1] +export async function createSubpackage(subpackageName?: string, functionName?: string) { + subpackageName = subpackageName ?? args[0] + functionName = functionName ?? args[1] if (!subpackageName || !functionName) { // 无参调起交互式命令行 @@ -125,9 +125,9 @@ async function createSubpackage() { } // 转换为短横线 - subpackageName = toLinesCase(subpackageName) + subpackageName = toLinesCase(subpackageName!) // 转换为小驼峰 - functionName = toCamelCase(functionName) + functionName = toCamelCase(functionName!) const { dirNames: subpackageDirNames } = loadSubpackage() diff --git a/scripts/create.ts b/scripts/create.ts index cabcd09..aedd4ec 100644 --- a/scripts/create.ts +++ b/scripts/create.ts @@ -1,13 +1,14 @@ import process from 'node:process' -import { fileURLToPath } from 'node:url' import prompts from '@posva/prompts' -import { loadSubpackage, runCommand } from './utils' +import { loadSubpackage } from './utils' +import { createSubpackage } from './create-subpackage' +import { createFunction } from './create-function' const [, , ...args] = process.argv async function create() { if (args.length !== 2) { - const type = ( + const type: 'subpackage' | 'function' = ( await prompts([ { name: 'type', @@ -21,8 +22,12 @@ async function create() { ]) ).type - const dirname = fileURLToPath(new URL('../', import.meta.url)) - runCommand(`pnpm run create:${type}`, dirname) + const typeCreateFn = { + subpackage: createSubpackage, + function: createFunction, + } + + typeCreateFn[type]() } else { const subpackageName = args[0] @@ -33,13 +38,11 @@ async function create() { // 校验子包是否存在 if (!subpackageDirNames.includes(subpackageName)) { // 不存在: 创建子包 - const dirname = fileURLToPath(new URL('../', import.meta.url)) - runCommand(`pnpm run create:subpackage ${subpackageName} ${functionName}`, dirname) + createSubpackage(subpackageName, functionName) } else { // 存在: 创建函数 - const dirname = fileURLToPath(new URL('../', import.meta.url)) - runCommand(`pnpm run create:function ${subpackageName} ${functionName}`, dirname) + createFunction(subpackageName, functionName) } } } From 3faa0a1934eeb5113511965f44cb1c6b3ccda9ab Mon Sep 17 00:00:00 2001 From: VictorBo Date: Thu, 27 Jun 2024 14:11:04 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E5=AD=90=E5=91=BD=E4=BB=A4=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/create-function.ts | 6 ++--- scripts/create-subpackage.ts | 6 ++--- scripts/create.ts | 43 +++++++++++++++--------------------- 3 files changed, 24 insertions(+), 31 deletions(-) diff --git a/scripts/create-function.ts b/scripts/create-function.ts index ec25745..c8ca641 100644 --- a/scripts/create-function.ts +++ b/scripts/create-function.ts @@ -15,9 +15,9 @@ function writeSubpackageIndex(subpackageName: string, functionName: string) { } // 创建函数 -export async function createFunction(subpackageName?: string, functionName?: string) { - subpackageName = subpackageName ?? args[0] - functionName = functionName ?? args[1] +export async function createFunction() { + let subpackageName = args[0] + let functionName = args[1] const { choices } = loadSubpackage() if (!subpackageName || !functionName) { // 无参调起交互式命令行 diff --git a/scripts/create-subpackage.ts b/scripts/create-subpackage.ts index f8628fa..5646ff3 100644 --- a/scripts/create-subpackage.ts +++ b/scripts/create-subpackage.ts @@ -90,9 +90,9 @@ function pnpmInstall() { } // 创建子包 -export async function createSubpackage(subpackageName?: string, functionName?: string) { - subpackageName = subpackageName ?? args[0] - functionName = functionName ?? args[1] +export async function createSubpackage() { + let subpackageName = args[0] + let functionName = args[1] if (!subpackageName || !functionName) { // 无参调起交互式命令行 diff --git a/scripts/create.ts b/scripts/create.ts index aedd4ec..9e8a6bf 100644 --- a/scripts/create.ts +++ b/scripts/create.ts @@ -1,33 +1,26 @@ import process from 'node:process' import prompts from '@posva/prompts' -import { loadSubpackage } from './utils' -import { createSubpackage } from './create-subpackage' -import { createFunction } from './create-function' +import { loadSubpackage, runCommand } from './utils' const [, , ...args] = process.argv async function create() { + console.log('--------') + console.log(args.length, process.cwd()) if (args.length !== 2) { - const type: 'subpackage' | 'function' = ( - await prompts([ - { - name: 'type', - type: 'select', - message: '请选择子包', - choices: [ - { title: '创建子包', value: 'subpackage' }, - { title: '创建函数', value: 'function' }, - ], - }, - ]) - ).type - - const typeCreateFn = { - subpackage: createSubpackage, - function: createFunction, - } - - typeCreateFn[type]() + const response = await prompts([ + { + name: 'type', + type: 'select', + message: '请选择子包', + choices: [ + { title: '创建子包', value: 'subpackage' }, + { title: '创建函数', value: 'function' }, + ], + }, + ]) + const type: 'subpackage' | 'function' = response.type + runCommand(`pnpm run create:${type}`, process.cwd(), { silent: false }) } else { const subpackageName = args[0] @@ -38,11 +31,11 @@ async function create() { // 校验子包是否存在 if (!subpackageDirNames.includes(subpackageName)) { // 不存在: 创建子包 - createSubpackage(subpackageName, functionName) + runCommand(`pnpm run create:subpackage ${subpackageName} ${functionName}`, process.cwd(), { silent: false }) } else { // 存在: 创建函数 - createFunction(subpackageName, functionName) + runCommand(`pnpm run create:function ${subpackageName} ${functionName}`, process.cwd(), { silent: false }) } } } From 9afb4a261cd38c34b3ce379a38f78e14f5e5cc9a Mon Sep 17 00:00:00 2001 From: VictorBo Date: Thu, 27 Jun 2024 14:21:07 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E5=BF=BD?= =?UTF-8?q?=E7=95=A5=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 56bb8d3..5ed27de 100644 --- a/.gitignore +++ b/.gitignore @@ -98,5 +98,5 @@ dist-* **/types/auto-*.d.ts # build runtime -**/rollup.config*.* -**/vite.config.ts*.* +**/rollup.config-* +**/vite.config.ts.* From b7bdc0ef02e8490b96fae83e08611c5879e7c79c Mon Sep 17 00:00:00 2001 From: VictorBo Date: Thu, 27 Jun 2024 14:34:00 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E8=80=85=E6=8C=87=E5=8D=97=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b59f6e3..e2394bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ # xparcai-utils

小趴菜,你是否想在你的简历上添上一笔开源项目的记录?

-

跟进我的步伐,手摸手教你如何加入小趴菜工具的开发

+

跟紧我的步伐,手摸手教你如何加入小趴菜工具的开发

这也基本是所有的开源项目加入的必须步骤

# 操作步骤 @@ -34,7 +34,7 @@ 找到代码的位置,通常是在packages目录下,不同的轮子有不同的目录,举个栗子,如果你想优化或者是想修复深拷贝方法(deepCopy)。你可以根据使用文档找到它在哪个工具类下,找到对应的目录:packages => object => src => deepCopy.ts 找到后,在你的编辑器内进行修改 ``` - - 方法添加 + - 工具类添加 - 有工具类 ``` 进入到该工具类下的目录,这里还以深拷贝举例,找到对应的目录:packages => object => src => @@ -42,9 +42,10 @@ ``` - 无工具类 ``` - 如果小趴菜没有你要添加的方法或者工具的类,你可以到根目录下,执行 pnpm run create命令,不过要加上你要创建的类的名字。 - 比如:pnpm run create object - 这就是创建了一个对象工具集合的类 + 如果小趴菜没有你要添加的方法或者工具的类,你可以到根目录下,执行 pnpm run create,执行后可以交互式的添加工具类或者方法。 + 当然你也可以直接使用命令行 + 比如:pnpm run create object deepCopy + 这就是创建了一个object工具集合的类和一个deepCopy方法 ``` - 方法验证: - 你写完了一个方法,肯定要验证这个方法是否正确的,怎么验证呢?来,跟上我的脚步。