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.* 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方法 ``` - 方法验证: - 你写完了一个方法,肯定要验证这个方法是否正确的,怎么验证呢?来,跟上我的脚步。 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..c8ca641 --- /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) +} + +// 创建函数 +export 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..5646ff3 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