@tianyio/quality-helper
Version:
A comprehensive quality helper tool for project scaffolding and management
3 lines (2 loc) • 12 kB
JavaScript
;const e=require("child_process"),n=require("fs/promises"),t=require("path"),s=require("chalk"),r=require("ora"),i=require("fs"),o=require("./core-file-ops-CkY4H0C_.cjs");async function c(s){const r={"pnpm-lock.yaml":"pnpm","yarn.lock":"yarn","package-lock.json":"npm"};for(const[e,o]of Object.entries(r))try{const r=t.join(s,e);return await n.access(r),o}catch{continue}const i=["pnpm","yarn","npm"];for(const n of i)try{return e.execSync(`${n} --version`,{stdio:"ignore"}),n}catch{continue}return"npm"}async function a(n){const t={},s=n.map(async n=>{const s=await async function(n){try{const t=`npm view ${n} version --json`,s=e.execSync(t,{encoding:"utf8",timeout:3e4,stdio:["pipe","pipe","pipe"]}).split("\n").filter(e=>!e.startsWith("npm warn")&&!e.startsWith("npm notice")&&""!==e.trim()).join("\n").trim();if(!s)return console.warn(`No valid JSON response for ${n}`),"latest";const r=JSON.parse(s);return"string"==typeof r?r:r[r.length-1]}catch(t){return"ETIMEDOUT"===t.code||-4039===t.errno?console.warn(`Timeout getting version for ${n}, using 'latest'`):console.warn(`Failed to get latest version for ${n}:`,t.message),"latest"}}(n);t[n]=s});return await Promise.all(s),t}async function l(e){const n={...e},t=[];for(const[s,r]of Object.entries(e))r&&"latest"!==r||t.push(s);if(t.length>0){const e=await a(t);for(const s of t)e[s]&&(n[s]=e[s])}return n}const p={vue:"3.5.18","vue-router":"4.5.1",pinia:"3.0.3","@vueuse/core":"13.9.0","lodash-es":"4.17.21",axios:"1.12.2","@tianyio/fast-util-lib":"latest"},d={"@tianyio/quality-helper":"latest",vite:"7.1.5","@vitejs/plugin-vue":"6.0.1","@vitejs/plugin-legacy":"7.2.1","vite-plugin-vue-devtools":"8.0.0","vite-plugin-dts":"4.5.4","@originjs/vite-plugin-federation":"1.4.1","vite-bundle-analyzer":"1.2.3","vue-tsc":"3.1.1",typescript:"5.9.2","@types/node":"24.3.0","@vue/tsconfig":"0.8.1",eslint:"9.33.0","@eslint/js":"9.38.0","eslint-config-prettier":"10.1.8","eslint-plugin-prettier":"5.5.4","eslint-plugin-promise":"7.2.1","eslint-plugin-vue":"10.4.0","@typescript-eslint/eslint-plugin":"8.40.0","@typescript-eslint/parser":"8.40.0","eslint-plugin-complexity":"^1.0.0","vue-eslint-parser":"10.2.0",prettier:"3.6.2",husky:"9.1.7","lint-staged":"16.1.5","@commitlint/cli":"19.8.1","@commitlint/config-conventional":"19.8.1","unplugin-auto-import":"20.0.0","unplugin-vue-components":"29.0.0","unplugin-icons":"22.3.0","@babel/core":"7.28.3","@babel/preset-env":"7.28.3","@babel/preset-typescript":"7.27.1","@babel/plugin-proposal-decorators":"7.28.0","@babel/plugin-syntax-dynamic-import":"7.8.3","@rollup/plugin-babel":"6.0.4","@vue/babel-plugin-jsx":"1.5.0","react-refresh":"0.17.0"};function u(e){return e in p||e in d}const g={templatePriority:!0,preserveUserDependencies:!0,syncNewTemplateDependencies:!0};async function y(e=!0){const n={...p};return e?await l(n):n}async function h(e=!0){const n={...d};return e?await l(n):n}class f{strategy;customDependencies;customDevDependencies;constructor(e=g,n){this.strategy=e,n?.customDependencies&&(this.customDependencies=n.customDependencies),n?.customDevDependencies&&(this.customDevDependencies=n.customDevDependencies)}async updateToRecommendedVersions(e){const n=t.join(e,"package.json"),s=JSON.parse(await o.FileOperations.readFile(n)),r=this.customDependencies??await y(),i=this.customDevDependencies??await h();s.dependencies??={},s.devDependencies??={};let c=!1;const a=[],l=[],p=[];return c=this.updateDependencyGroup(s.dependencies,r,a,l,p)||c,c=this.updateDependencyGroup(s.devDependencies,i,a,l,p)||c,c&&await o.FileOperations.writeFile(n,JSON.stringify(s,null,2)),c}updateDependencyGroup(e,n,t,s,r){let i=!1;for(const[o,c]of Object.entries(n)){const n=e[o];n?n!==c&&(e[o]=c,s.push(o),i=!0):(e[o]=c,r.push(o),i=!0)}if(this.strategy.preserveUserDependencies)for(const[o]of Object.entries(e))u(o)||n[o]||t.push(o);return i}async analyzeDependencies(e){const n=t.join(e,"package.json"),s=JSON.parse(await o.FileOperations.readFile(n)),r=this.customDependencies??await y(),i=this.customDevDependencies??await h(),c=s.dependencies??{},a=s.devDependencies??{},l={toUpdate:{},toAdd:{},userAdded:{},synced:{}};return this.analyzeDepGroup(c,r,l),this.analyzeDepGroup(a,i,l),l}analyzeDepGroup(e,n,t){for(const[s,r]of Object.entries(n)){const n=e[s];n?n!==r?t.toUpdate[s]={current:n,template:r}:t.synced[s]=r:t.toAdd[s]=r}if(this.strategy.preserveUserDependencies)for(const[s,r]of Object.entries(e))u(s)||(t.userAdded[s]=r)}generateReport(e){const{toUpdate:n,toAdd:t,userAdded:r,synced:i}=e,o=Object.keys(i).length+Object.keys(n).length+Object.keys(t).length+Object.keys(r).length;console.log(s.blue("\n📊 依赖分析结果:")),Object.keys(i).length>0&&console.log(s.green(`✅ 已同步: ${Object.keys(i).length} 个依赖`)),Object.keys(n).length>0&&(console.log(s.yellow(`🔄 需要更新: ${Object.keys(n).length} 个依赖`)),Object.entries(n).slice(0,3).forEach(([e,{current:n,template:t}])=>{console.log(s.gray(` ${e}: ${n} → ${t}`))}),Object.keys(n).length>3&&console.log(s.gray(` ... 还有 ${Object.keys(n).length-3} 个`))),Object.keys(t).length>0&&console.log(s.cyan(`➕ 需要添加: ${Object.keys(t).length} 个依赖`)),Object.keys(r).length>0&&console.log(s.magenta(`👤 用户自定义: ${Object.keys(r).length} 个依赖`)),console.log(s.gray(`总计: ${o} 个依赖`))}checkCompatibility(e){const n=[];for(const[t,{current:s,template:r}]of Object.entries(e.toUpdate)){this.extractMajorVersion(s)!==this.extractMajorVersion(r)&&n.push(`${t}: ${s} → ${r} (主版本变更)`)}return!(n.length>0)||(console.log(s.red("⚠️ 发现潜在的版本冲突:")),n.forEach(e=>{console.log(s.red(` ${e}`))}),!1)}extractMajorVersion(e){const n=e.match(/\d+/);return n?n[0]:"0"}}class m{validate(e){const n={isValid:!0,errors:[],warnings:[]};if(!e||"string"!=typeof e)return n.isValid=!1,n.errors.push("包名不能为空"),n;if(0===e.trim().length)return n.isValid=!1,n.errors.push("包名不能为空"),n;if(e.startsWith(".")||e.startsWith("_"))return n.isValid=!1,n.errors.push("包名不能以点或下划线开头"),n;if(e.includes("@")){const t=e.split("/");if(2!==t.length)return n.isValid=!1,n.errors.push("作用域包格式无效"),n;const s=t[0]?.substring(1),[,r]=t;if(!s||!r)return n.isValid=!1,n.errors.push("作用域包格式无效"),n;if(!/^[a-z0-9_-]+$/.test(s)||!/^[a-z0-9_-]+$/.test(r))return n.isValid=!1,n.errors.push("作用域包名格式无效"),n}else if(!/^[a-z0-9_-]+$/.test(e))return n.isValid=!1,n.errors.push("包名格式无效"),n;return n}}class w{versionPatterns=[/^\d+\.\d+\.\d+$/,/^\d+\.\d+\.\d+-\w+$/,/^\d+\.\d+\.\d+\+\w+$/,/^\^\d+\.\d+\.\d+$/,/^~\d+\.\d+\.\d+$/,/^>=?\d+\.\d+\.\d+$/,/^<=?\d+\.\d+\.\d+$/,/^latest$/,/^next$/,/^beta$/,/^alpha$/,/^rc$/,/^\*$/,/^x$/,/^\d+\.\d+\.\d+ - \d+\.\d+\.\d+$/];validate(e){const n={isValid:!0,errors:[],warnings:[]};return e&&"string"==typeof e?(this.versionPatterns.some(n=>n.test(e))||n.warnings.push(`版本格式可能无效: ${e}`),n):(n.isValid=!1,n.errors.push("版本号不能为空"),n)}}class v{static createPackageNameRule(){return new m}static createVersionRule(){return new w}}class j{packageNameRule=v.createPackageNameRule();versionRule=v.createVersionRule();async validateDependencyFile(e){const t={isValid:!1,errors:[],warnings:[]};try{const r=await n.readFile(e,"utf-8");let i;try{i=JSON.parse(r)}catch(s){return t.errors.push("文件不是有效的 JSON 格式"),t}return this.validateBasicStructure(i,t),t.isValid&&(t.dependencies=i.dependencies??{},t.devDependencies=i.devDependencies??{},this.validateDependencyFormat(t.dependencies,"dependencies",t),this.validateDependencyFormat(t.devDependencies,"devDependencies",t)),t}catch(r){return t.errors.push(`读取文件失败: ${r.message}`),t}}validateBasicStructure(e,n){const t="dependencies"in e,s="devDependencies"in e;t||s?t&&"object"!=typeof e.dependencies?n.errors.push("dependencies 字段必须是对象类型"):s&&"object"!=typeof e.devDependencies?n.errors.push("devDependencies 字段必须是对象类型"):(t&&0===Object.keys(e.dependencies??{}).length&&n.warnings.push("dependencies 字段为空"),s&&0===Object.keys(e.devDependencies??{}).length&&n.warnings.push("devDependencies 字段为空"),n.isValid=!0):n.errors.push("文件必须包含 dependencies 或 devDependencies 字段")}validateDependencyFormat(e,n,t){for(const[s,r]of Object.entries(e))this.isValidPackageName(s)?this.isValidVersion(r)||t.warnings.push(`${n}.${s}: 版本格式可能无效 (${r})`):t.errors.push(`${n}.${s}: 包名格式无效`)}isValidPackageName(e){return this.packageNameRule.validate(e).isValid}isValidVersion(e){return this.versionRule.validate(e).isValid}printValidationResult(e,n){console.log(s.blue(`\n📋 依赖列表文件验证结果: ${n}`)),e.isValid?(console.log(s.green("✅ 文件结构有效")),e.dependencies&&Object.keys(e.dependencies).length>0&&console.log(s.cyan(`📦 运行时依赖: ${Object.keys(e.dependencies).length} 个`)),e.devDependencies&&Object.keys(e.devDependencies).length>0&&console.log(s.cyan(`🔧 开发依赖: ${Object.keys(e.devDependencies).length} 个`))):console.log(s.red("❌ 文件结构无效")),e.errors.length>0&&(console.log(s.red("\n❌ 错误:")),e.errors.forEach(e=>{console.log(s.red(` • ${e}`))})),e.warnings.length>0&&(console.log(s.yellow("\n⚠️ 警告:")),e.warnings.forEach(e=>{console.log(s.yellow(` • ${e}`))}))}}exports.ArrayUtils=class{static groupBy(e,n){const t=new Map;for(const s of e){const e=n(s);t.has(e)||t.set(e,[]),t.get(e).push(s)}return t}static safeGet(e,n){return e[n]}},exports.cleanDependencies=async function(s){const r=t.join(s,"node_modules"),i=["pnpm-lock.yaml","yarn.lock","package-lock.json"],o=[".pnpm-store",".pnpm-debug.log"];try{await n.rm(r,{recursive:!0,force:!0});for(const e of i)try{await n.unlink(t.join(s,e))}catch{}for(const e of o)try{const r=t.join(s,e);await n.rm(r,{recursive:!0,force:!0})}catch{}try{"pnpm"===await c(s)&&e.execSync("pnpm store prune",{cwd:s,stdio:"ignore"})}catch{}}catch(a){throw console.warn("依赖清理失败:",a.message),a}},exports.createDependencyManager=function(e){if(e&&"customDependencies"in e){return new f(g,e)}const n={...g,...e};return new f(n)},exports.createDependencyValidator=function(){return new j},exports.formatProject=async function(n,o=!1){const c=o?null:r("格式化代码中...").start();try{if(!i.existsSync(n))throw new Error(`项目路径不存在: ${n}`);const r=t.join(n,"package.json");if(!i.existsSync(r))throw new Error("项目中未找到package.json文件");let a=!1;try{e.execSync("eslint . --fix",{cwd:n,stdio:o?"ignore":"pipe",timeout:6e4}),a=!0}catch{}a?c&&c.succeed(s.green("代码格式化成功")):c?c.warn(s.yellow("代码格式化失败,请手动运行格式化命令")):o||console.log(s.yellow("⚠️ 代码格式化失败,请手动运行格式化命令"))}catch(a){c?c.fail(s.red("代码格式化失败")):o||console.warn("代码格式化失败:",a),o||console.log(s.yellow("提示: 可以稍后手动运行 npm run format 进行代码格式化"))}},exports.initializeGit=async function(n){try{e.execSync("git init",{cwd:n,stdio:"ignore"})}catch(t){throw console.warn("Git仓库初始化失败,请手动初始化"),t}},exports.initializeHusky=async function(n){try{e.execSync("npx husky init",{cwd:n,stdio:"ignore"})}catch(t){throw console.warn("Husky初始化失败,请手动初始化"),t}},exports.installProjectDependencies=async function(n){const t=await c(n);try{const r=function(e){switch(e){case"pnpm":return"pnpm install";case"yarn":return"yarn install";default:return"npm install"}}(t);if("pnpm"===t)try{e.execSync(`${r} --no-frozen-lockfile`,{cwd:n,stdio:"inherit"})}catch(s){throw console.error("❌ 重新安装失败:"),console.log("\n💡 请手动执行以下命令解决:"),console.log("1. rm -rf node_modules pnpm-lock.yaml"),console.log("2. pnpm install --no-frozen-lockfile"),s}else e.execSync(r,{cwd:n,stdio:"inherit"})}catch(r){throw console.warn("依赖安装失败:",r),r}};
//# sourceMappingURL=utils-CuBC1baf.cjs.map