jja 2.5.4 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/bin.js +1 -1
- package/package.json +10 -16
package/CHANGELOG.md
CHANGED
package/bin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{isFalse as e,isUndefined as n,isBoolean as t,isNull as o,isEmptyArray as i,isEmptyObject as r,isBusinessEmptyString as s,isPlainObject as a,isType as c,isArray as l,isString as p,isZero as u}from"@vvi/is";import{isTTY as d,runOtherCode as g,isWindows as m,__p as f,cursorMoveUp as $,cursorAfterClear as w,_p as y,waitingTips as h,typewrite as v,getDirectoryBy as b,readFileToJsonSync as j,pathJoin as k,detectShell as D,detectPackageManager as S,getPackageJsonSync as V,fileExist as O,getNpmPkgInfo as A,colorLine as P}from"@vvi/node";import{redPen as C,hexPen as T,randomPen as x,boldPen as E,reversedPen as R,greenPen as L,strInOneLineOnTerminal as M,brightMagentaPen as N,cyanPen as q,magentaPen as W,hidePen as G,pen as X,italicPen as Y,yellowPen as _}from"@vvi/pen";import{Args as B,question as F,ERROR as H,selection as I,WARN as J,prefixList as U,INFO as z,SUCCESS as K}from"@vvi/command";import{Dog as Q}from"@vvi/log";import Z,{Resolver as ee}from"node:dns";import{copyTextToClipboard as ne}from"@vvi/copy-text";import{intersection as te}from"@vvi/utils";import oe from"node:net";import{terminalRegExp as ie}from"@vvi/pen-static";import{Table as re}from"@vvi/table";import{readFileSync as se}from"node:fs";import{dirname as ae}from"node:path";import ce from"node:https";import{spawn as le}from"node:child_process";const pe=new Q({name:"jja",type:!1}),ue=e(pe.type),de=new B("jja");de.bind({"package <pkg> (包管理)":["--diff <-d> (分析当下包的差异)","--upDependencies <-u> (更新依赖,强制更新到 'latest',使用需谨慎)"],"remove <rm> (做一个简单的兼容的移除文件或文件夹的命令)":["--ignore <-i> (不打印日志(默认打印的))","--subdirectories <-s> (这是一个危险的命令,用于 windows 下递归删除执行命令下所有的给定文件名称)"],"update <up> (做一个简单的 npm 升级程序,对,简单的)":["--ignore <-i> (不建议你这么用,你会发现你像个傻子一样在那等结果)",`--dependencies <-d> (更新依赖,跟 ${x("npm update")} 一样)`],"clearScreen <cls> (清理终端显示屏幕,同 clearTerminal )":"","clearTerminal <clear> (清理终端显示屏幕,同 clearScreen )":"","git (一些关于 git 的操作)":[`commit (git 提交代码,是 ${C("commit")} 提交啊,不是 ${T("#666")("push")} 推送)`,"merge (合并两个分支)","tag (给提交打上 tag)"],"dns (使用 dns 获取 ip 地址)":["--domain <-d> (获取给定域名获取 ip 地址,默认 github.com )","--port <-p> (配置要校验的 port 端口号,默认为 443)"],"runOtherCode <run> (执行其他的代码,使用 )":[]}).run(),pe("参数已绑定,且已解析用户参数",de.args),pe.warn("当前的执行状态",de.state),de.isEnd(!0);const ge=E.green,me=T("0x993311"),fe=T("0x339999"),$e=T("0x666666"),we=h({show:!1,info:"请稍等",beforeDestroyed:e=>e&&de.end()}),ye=["A","AAAA","ANY","CAA","CNAME","MX","NAPTR","NS","PTR","SOA","SRV","TLSA","TXT"],he={domain:"github.com",port:443,dnsServers:["1.1.1.1","8.8.8.8","8.8.4.4","208.67.222.222","114.114.115.115","223.5.5.5","180.76.76.76"],ips:{},rrtype:["A"],reset(e){this.ips={},this.domain="github.com",this.port=443,this.rrtype=[],n(e)||e.forEach(e=>{const t=e["--domain"];!n(t)&&t.length>0&&(this.domain=t[0].toString());const o=e["--port"];!n(o)&&o.length>0&&(this.port=Number(o[0]));const i=e["--rrtype"];if(!n(i)&&i.length>0){const e=te(ye,i);e.length>0&&(this.rrtype=e)}})},noCopy:!0};async function ve(e){return Promise.all(e.map(e=>async function(e,n=3e3){const{ips:o,port:i}=he;if(t(o[e]))return ue||we.log(`${e} 联通性已校验过 ${o[e]?"🔥":"⛓️💥"}`),Promise.resolve(null);o[e]=!1,ue||we.log(`校验 ${e} 的联通性`);return new Promise(t=>{const r=new oe.Socket,s=(n=!1)=>{o[e]=n,r.destroy(),t(null)};r.setTimeout(n),r.on("connect",()=>s(!0)),r.on("timeout",()=>s()),r.on("error",()=>s()),ue||we.log("测试的接口为:",i),r.connect(i,e)})}(e)))}async function be(e="1.1.1.1"){const{domain:n}=he;try{const t=await async function(e,n){return new Promise(t=>{const o=new ee;we.run(`使用 ${n} 获取 ${e} 的 ip`),o.setServers([n]),o.resolve4(e,(o,i)=>{if(o)return ue||we.run(`使用 ${n} 获取 ${e} 的 ip 出错`),t(null);ue||we.log(`使用 ${n} 获取 ${e} 的 ip 值为 ${i.join(" --- ")}`),t(i)})})}(n,e);if(o(t))return ue||we.log(`${e} 获取 ${n} 的 ip 失败`),0;const r=(await ve(t)).filter(e=>!o(e));return i(r)?0:(we.destroyed(),y(),y(R`DNS: ${e}`),y(),r.forEach(({ip:e,isAlive:n})=>{const t=n?`${L(e)} ${me`->`} ✅`:`${$e(e)} ${C`⛓️💥`} ❌`;y(M(t))}),3+r.length)}catch(e){return ue||we.log("'获取 ip 错误'",e),0}}async function je(e){he.reset(e.options),await async function(){const{domain:e,ips:n}=he;we.run(`正在获取本地的 ${e} 的 ip 地址`);try{const t=await async function(e){return new Promise(n=>{Z.lookup(e,{all:!0,family:4},(t,o)=>{if(t)return pe.error(`获取本地 ${e} 的 ip 出错`,t),void n(null);ue||we.log(`获取本地 ${e} 的 ip 值为 ${o.join(" --- ")}`),n(o.map(e=>e.address))})})}(e);if(o(t))return;await ve(t),r(n)||function(e){const{ips:n}=he;y(me`本地配置 ${e} 的 ip 地址及联通性为:\n`),Object.keys(n).forEach(e=>{const t=n[e];t&&(he.noCopy=!1),y(q`- ${e}`,!1),y(t?me` -> ✅`:$e` -> ❌`)}),y()}(e)}catch(e){pe.error(e)}}(),await async function(){const{domain:e,dnsServers:n}=he;we.log(`${e} ip 列表:`);const t=n.map(e=>be(e)),o=await Promise.all(t);ue&&($(o.reduce((e,n)=>e+n,0)+1),w(!0))}(),we.destroyed();const{ips:n}=he;Object.keys(n).length>0?await async function(){const{domain:e,ips:n,port:t}=he;await v(`${N`${e}`} 域名解析结果:`),y();let o=he.noCopy;for(const t in n)if(Object.prototype.hasOwnProperty.call(n,t)){const i=n[t],r=i?`${L`- ${t.padEnd(16)}`} ${me`->`} ✅${o?q`(已复制)`:""}`:`${$e`- ${t.padEnd(16)}`} ${C`⛓️💥`} ❌`;y(r),i&&o&&(ne(`${t} ${e}`),o=!1)}y(),await v(C.italic.dim`${e} 联通性接口判断为 ${t.toString()}`),y(),y($e(m?`请在文件「 ${W("C:\\Windows\\System32\\drivers\\etc\\hosts")} 」 中修改`:`请执行修改:「 ${W("sudo vim /etc/hosts")} 」`))}():await async function(){const{domain:e,port:n}=he;await v(`\n找不到 ${C(e)} 的服务器 IP 地址 ${$e`测试使用 ${n.toString()} 端口`}\n`)}()}async function ke(e){const n=b("package.json","file",process.cwd());if(null==n)return!0;const t=j(k(n,"package.json"));if(o(t)||!t.version)return!0;const i=t.version;await g({code:`git tag -a v${i} -m '${e}'`,cwd:n}),await g({code:"git push origin --tag",cwd:n})}async function De(e){e.commit?await async function(e="版本维护",n=!1){const t=b(".git","directory");if(null==t)return y(T("#ff0")("not a git repository(当前目录非 git 储存库)"));const o=await g({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);const i=await g({code:"git status",cwd:t});if(!/nothing to commit, working tree clean/.test(i.data||"")){const o=await g({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);""==e.trim()&&(e=await F({text:"请输入提交信息"})??"");const i=await g({code:`git commit -m "${e}"`,cwd:t});return i.success?(i.error&&console.log(i.error),await g({code:"git push",cwd:t}),n&&await ke(e),!0):null!=console.log(i.error)}return!1}(e.commit.join(" ")):e.merge?await async function(e){if(s(e)){const n=await g("git branch -a");console.log(n.data),e=await F({text:"请输入要合并分支的名称"})??""}if(s(e))return H("没有获取到要合并的分支");const t=await I({data:[{label:"正常快进合并",value:""},{label:"非快进合并 (--no-ff)",value:"--no-ff"},{label:"多提交记录合并为一条 (--squash)",value:"--squash",tip:"适用于将众多小的提交合并成一个提交"}]});n(t)?H("您选择退出合并"):await g(`git merge ${e} ${t}`)}(e.merge.join("")):e.tag?await async function(){const e=await F({text:"请输入待标记的信息"});n(e)||await ke(e)}():de.help("git")}const Se={local:null,online:null,dependenceList:{},updateDependence:[],latestDependence:[],binning:function(e,t=!1){if(n(e)||r(e)||o(this.local))return;const{overrides:i}=this.local;let s=i&&a(i)?Object.keys(i):[];if(this.local?.jja?.pkg){const e=this.local.jja.pkg;c(e,e=>l(e)&&e.every(e=>p(e)))&&(s=s.concat(e)),c(e,e=>a(e))&&(s=s.concat(Object.keys(e)))}for(const n in e){if(s.includes(n)){J(`${n} 被锁定在`);continue}const o=e[n];this.dependenceList[n]={type:t?"devDependencies":"dependencies",version:o,localVersion:"",latestVersion:"",onlineVersion:"",tag:"",time:""}}},preReleaseDependence:[],timeoutDependence:[],registry:void 0},Ve=m?"cmd"===D()?"^":"`":"\\";const Oe=(()=>{const e=S(),n=function(e){const n=V();if(null===n)return!1;const{content:t,path:o}=n,i=ae(o);if("pnpm"===e){const e=k(i,"pnpm-workspace.yaml");if(!O(e))return!1;if(se(e,{encoding:"utf-8"}).split("\n").some(e=>e.startsWith("packages:")))return!0}if(t.workspaces){if("yarn"===e){const e=k(i,".yarnrc.yml");if(O(e))return!0}if("npm"===e)return!0}return!1}(e);return"npm"===e?"npm install --save".concat(n?" --include-workspace-root ":""):"yarn"===e?"yarn add".concat(n?" -W ":""):"pnpm add".concat(n?" -w ":"")})();async function Ae(){const n={"淘宝":"registry.npmmirror.com","官方":"registry.npmjs.org","腾讯":"mirrors.tencent.com/npm","中科大":"npmreg.proxy.ustclug.org",yarn:"registry.yarnpkg.com"},t=()=>Object.keys(n).map(e=>function(e){const n=Date.now();return new Promise(t=>{const o=`https://${e}/nry`,i=ce.request(o,{method:"HEAD",timeout:3500},o=>{t((o?.statusCode??0)>=200&&(o?.statusCode??0)<300?{url:e,time:Date.now()-n,success:!0}:{url:e,time:Date.now()-n,success:!1})});i.on("error",()=>t({url:e,time:Date.now()-n,success:!1})),i.on("timeout",()=>{i.destroy(),t({url:e,time:Date.now()-n,success:!1})}),i.end()})}(n[e])),o={};for(let n=0;n<3;n++){we.run(`请稍等,正在进行第${["一","二","三","四","五"][n]}次安装源延迟测试`);(await Promise.all(t())).forEach(n=>{e(n.success)||(o[n.url]?o[n.url]=(o[n.url]+n.time)/2:o[n.url]=n.time)})}return we.destroyed(),Object.keys(n).reduce((e,t)=>o[n[t]]<(o[n[e]]??1/0)?t:e,"")}async function Pe(){const{dependenceList:e,timeoutDependence:t}=Se,i=Object.keys(e);i.length>18&&(n(Se.registry)||!["官方","淘宝","腾讯","中科大","yarn"].some(e=>e===Se.registry))&&(Se.registry=await Ae(),y(`由于您未设置或者设置有误,现使用 ${q(Se.registry)} npm 源`));const r=i.map(n=>new Promise(i=>{(async()=>{const r=e[n],s=e[n].version;we.run(`${U.current()}获取 ${n} 的本地安装信息`);const a=function(e){const n=j(k("node_modules/",e,"package.json"));let t="";t=o(n)?"":n.version||"";return Se.dependenceList[e].localVersion=t,pe(e,"本地安装的版本为:",t),t}(n);if(we.run(`${U.success()} ${n} 的本地安装版本:${r.localVersion}`),await async function(e){const n=await A(e,Se.registry,9867);if("timeout"===n.status)return void pe.warn("请求超时");if(o(n.data))return void pe.warn("获取包信息失败");const t=Date.now();pe("获取数据",e,"包信息");const i=Se.dependenceList[e],{"dist-tags":r,time:s,version:a}=n.data;let c=a,l="latest";i.onlineVersion=c,i.tag=l;const p=Object.keys(r);pe("共需比对",p.length);for(let e=0,n=p.length;e<n;e++){const n=p[e],t=r[n];s[t]>s[c]&&(c=t,l=n)}pe("比对",e,"完成"),pe("耗时",Date.now()-t),"latest"!==l&&(pe(e,"最新版本为:",c,"tag为:",l),i.tag=l,i.latestVersion=c);const u=new Date(s[c]).toLocaleString();i.time=u,pe(`${e} 的最后发布时间为:${u}`)}(n),""===r.onlineVersion&&""===r.latestVersion)return t.push(n),we.log(`${U.error()} ${n} 本地 ${r.localVersion} 请求错误`),i(!0);if(a===r.onlineVersion){const e=`${n} 的本地${s} 安装版本为 ${a} 最新是 ${r.onlineVersion} `;return""===r.latestVersion?(we.run(U.info()+e),i(!0)):(Se.preReleaseDependence.push(n),we.log(`${U.info()} ${e};最新预发布版本为 ${L(r.latestVersion)}`),i(!0))}if(a===r.latestVersion)return we.log(`${U.info()} ${n} 的本地版本${s} 安装版本为 ${a}`),i(!0);const c=`${n} 的本地 ${L(s)} 安装版本为 ${L(a)} 最新是 ${fe(r.onlineVersion)} `;Se.latestDependence.push(n),""===r.latestVersion?(we.log(U.info()+c),i(!0)):(Se.preReleaseDependence.push(n),we.log(`${U.info()} ${c};最新预发布版本为 ${L(r.latestVersion)}`),i(!0))})()}));return Promise.all(r).then(()=>{we.destroyed()})}async function Ce(){const{local:e,preReleaseDependence:n,latestDependence:t,dependenceList:i,timeoutDependence:r}=Se;if(o(e))return;const{dependencies:s,devDependencies:a}=e;if(Se.binning(s),Se.binning(a,!0),await Pe(),0===n.length&&0===t.length&&0===r.length)return y($e`看起来似乎没有依赖版本差异`);if(0===n.length&&0===t.length)return y(C`看起来网络不太好讷,所有的包线上版本的请求都出错了。或者是还没有执行 npm install 呐`);y(X.brightGreen`\n版本差异的依赖为:\n`);const c=[...t,...n];var l;new re({header:[q("包名"),{content:"发布时间",color:"#f26"},L`最新版本`],body:[...c.map(e=>{const{type:n,latestVersion:t,time:o,onlineVersion:r}=i[e];return["dependencies"===n?E(e):Y(e),x(o),t||Y(r)]})]})(),y(X.brightRed(`\n目前仅关注版本号是否为最新 ${X.brightMagenta("latest")}`)),y(`使用 ${Oe} 命令安装更新\n`),r.length>0&&(l=C`有一些包没有返回结果,请注意:`,y(M(l)),new re([...r.map(e=>[e])])());const p=[...t.filter(e=>!1===n.includes(e)).map(e=>X.bold(e).concat("@latest")),...n.map(e=>Te(e,i[e].tag))],u=t.map(e=>xe(e)),d=[...t.map(e=>xe(e)),...n.filter(e=>!1===t.includes(e)).map(e=>Te(e,i[e].tag))],g=p.length<n.length+t.length,m=n.length>0,f=t.length>0;m&&(g&&await Ee({msg:"‼️ 预发布版本优先:",list:p,type:"brightRed"}),await Ee({msg:"⚠️ latest 版本优先:",list:d,type:"brightMagenta",copy:!f})),f&&await Ee({msg:"🎉 最佳安装:",list:u,type:"brightGreen",copy:!0})}function Te(e,n){return`${Y(e)}@${Y.random(n)}`}function xe(e){return`${E(e)}@${ge`latest`}`}async function Ee(e){const{msg:n,list:t,type:o,copy:i}=e,r=X[o];y(),y(r.reversed(n),!1),y(i?$e.reversed`已复制到剪切板 📋`:""),y(),y(`${r(Oe)} ${G(Ve)}\n${function(e){if(!l(e)||e.some(e=>!p(e)))throw new TypeError("参数必须为字符串数组");return e.map((n,t)=>t%3==2&&t!==e.length-1?`${n} ${G(Ve)}\n`:n.concat(" ")).join("")}(t)}`),y(),i&&ne(`${Oe} ${t.join(" ")}`.replace(ie(),""))}async function Re(e){Se.registry=e[0]?.toString()||void 0,await async function(){const e=b("package.json","file");if(n(e))return void pe.warn("未找到当前包的 package.json 文件的位置");const t=j(k(e,"package.json"));if(o(t))return void pe.error("未找到当前包的 package.json 文件,该事件发生的概率极低");const i=t.name||"",r=await A(i,Se.registry,9800);Se.local=t,Se.online=r.data}();const{local:t,online:i}=Se,r=t?.version||"",s=i?.version||"";if(o(t))return pe("未找到包 package.json 文件退出"),y(me("未找到当前包 package.json"));const a=me(`当前包本地版本为: ${r}`);if(i){y(a);const e=" ".repeat(6);y(fe(`${e}线上版本为:${s}@latest`));const n=new Date(i&&i.time.modified||"").toLocaleString();z(`最后的发布时间为: ${n.toString()}`),P()}await Ce()}async function Le(e=!0){const n=b("package.json","file");if(null==n)return y("当前目录下不存在 package.json 文件");const t=j(k(n,"package.json"))?.dependencies||{};if(e&&y(L("初始化完成,等待下一步命令")),Object.keys(t).length>0){let e="npm install --save";for(let n=Object.keys(t),o=n.length,i=0;i<o;i++){e+=` ${n[i]}@latest `}await g(e)}var o;e&&y(q("正在更新 dev 依赖")),await g("npm update --save"),e&&(o="开发依赖更新完毕",$(),w(),y(o))}async function Me(e){e["--upDependencies"]?await Le(!0):e["--diff"]?await Re(e["--diff"]):de.help("package")}const Ne={log:!1,subdirectories:!1};function qe(e,n){y(`清理 ${e} 文件${n?"完成":"失败"}`)}async function We(e,n){Ne.log||y(T("#aaa")(` ${e} 文件/夹存在,准备删除`));let t={error:null};return m?n.isDirectory()?(t=await g(`rd /q /s ${e.replace(/\//,"\\")}`),qe(e,t.success)):n.isFile()&&(t=await g(`del ${Ne.subdirectories?"/s":""} /q ${e.replace(/\//,"\\")}`),qe(e,t.success)):(t=await g(`rm -rf ${e.replace(/\\/,"/")}`),qe(e,t.success)),!!t.success||(console.log(t.error),!1)}async function Ge(e,n,t=5){return!await Reflect.apply(e,void 0,n)&&t--?(y(L("执行失败,现在重试中")),pe.warn(n,"执行失败,第",5-t,"次执行"),await Ge(e,n,t)):await Reflect.apply(e,void 0,n)}async function Xe(e){Ne.log||y(T("#336")(`当前清理文件为 ${e}`));const t=O(e);Ne.log||y(T("#666")(`正在检测 ${e} 文件/夹是否存在`)),pe(`文件${e} 数据为 ${t}`),n(t)?Ne.log||y(_(`${e} 文件不存在`)):await Ge(We,[e,t])}const Ye={log:!0};async function _e(e){Boolean(e["--dependencies"])&&await Le(Ye.log)}const Be=de.args.$arrMap;pe(Be),pe(de.args.$original),de.args.$isVoid?(pe("没有匹配到子命令,打印帮助信息并退出"),de.help(),de.end()):i(de.args.$only)&&(console.log(`${de.args.$nomatch.map(e=>x(e)).join("、")} 不是有效的参数`),de.end());try{await async function e(){if(0===Be.length)return;const t=Be.shift();if(n(t))return await e();t.remove?(pe("执行文件移除"),await async function(e){const n=e.value||[],t=e.options;for(t?.forEach(e=>{const t=e["--ignore"];t&&(Ne.log=!0,n.concat(t));const o=e["--subdirectories"];o&&(Ne.subdirectories=!0,n.concat(o))}),Ne.log||y(X.brightCyan`当前系统为: ${m?"windows":"linux/mac"}`),0==n.length&&(pe.warn("待删除列表",n),y(X.random`没有待清理的文件/文件夹`));n.length;){let e=n.pop();e=void 0===e?"undefined":e.toString(),await Xe(e)}}(t.remove)):t.clearScreen||t.clearTerminal?(pe("执行清屏"),await async function(){d()?(pe("执行第一遍清理"),await g({code:m?"cls":"clear",printLog:!1}),pe("执行第二遍清理"),f("3J"),f("c",!1),$(1/0),w(!0)):(pe.warn("当前系统不支持 TTY"),y("当前环境不支持 "))}()):t.git?(pe("执行 git 相关命令"),await async function(e){if(a(e)&&(e={value:[]}),n(e.options)||0===e.options.length)return pe.warn("没有配置项,直接返回的帮助文档"),de.help("git");const t=e.options;for(let e=0,n=t.length;e<n;e++)pe("本次执行",t[e]),await De(t[e])}(t.git)):t.package?(pe("执行 package 相关命令"),await async function(e){if(n(e.options)||0==e.options.length)return pe.warn("没有参数输入"),de.help("package");const t=e.options;for(let e=0,n=t.length;e<n;e++)await Me(t[e])}(t.package)):t.update?(pe("执行 update 相关命令"),await async function(e){if(n(e.options)||0==e.options.length)return pe.warn("没有匹配到选项,自动抛出帮助文档"),de.help("update");const t=e.options;Ye.log=!t.some(e=>e["--ignore"]);for(let e=0,n=t.length;e<n;e++)await _e(t[e])}(t.update)):t.dns?(pe("执行 dns 相关的命令"),await je(t.dns)):t.runOtherCode&&(pe("执行运行其他命令"),await async function(e){const{value:t}=e;if(n(t)||u(t.length))return;for(const e in t){const n=t[e].toString(),o=n.indexOf("=");if(-1===o)break;if(0===o){H(`未识别 "${n}" 且已移除该项 ❌`),t[e]="";continue}const[i,r]=[n.slice(0,o),n.slice(o+1)||"true"];process.env[i]=r,K(`设置环境变量 ${i}=${r} ✅`),t[e]=""}const o=t.join(" ").trim();pe("执行代码",o);const i=le(o,[],{stdio:"inherit",env:process.env,shell:!0});i.on("close",e=>e),i.on("error",e=>e),i.on("exit",e=>e)}(t.runOtherCode));try{await e()}catch(e){pe.error("执行 run 报错",e)}}(),P(" 终结分割线 ",!0)}catch(e){pe.error("执行 run 报错",e)}
|
|
2
|
+
import{isFalse as e,isUndefined as n,isBoolean as t,isNull as o,isEmptyArray as i,isEmptyObject as r,isBusinessEmptyString as s,isPlainObject as a,isType as c,isArray as l,isString as p,isZero as u}from"@vvi/is";import{isTTY as d,runOtherCode as g,isWindows as m,__p as f,cursorMoveUp as $,cursorAfterClear as w,_p as y,waitingTips as h,typewrite as v,getDirectoryBy as j,readFileToJsonSync as b,pathJoin as k,detectShell as D,detectPackageManager as S,getPackageJsonSync as V,fileExist as O,getNpmPkgInfo as A,colorLine as P}from"@vvi/node";import{redPen as C,hexPen as T,randomPen as x,boldPen as E,reversedPen as R,greenPen as L,strInOneLineOnTerminal as M,brightMagentaPen as N,cyanPen as q,magentaPen as W,hidePen as G,pen as X,italicPen as Y,yellowPen as _}from"@vvi/pen";import{Args as B,question as F,ERROR as H,selection as I,WARN as J,prefixList as U,INFO as z,SUCCESS as K}from"@vvi/command";import{Dog as Q}from"@vvi/log";import Z,{Resolver as ee}from"node:dns";import{copyTextToClipboard as ne}from"@vvi/copy-text";import{intersection as te}from"@vvi/utils";import oe from"node:net";import{terminalRegExp as ie}from"@vvi/pen-static";import{Table as re}from"@vvi/table";import{readFileSync as se}from"node:fs";import{dirname as ae}from"node:path";import ce from"node:https";import{spawn as le}from"node:child_process";const pe=new Q({name:"jja",type:!1}),ue=e(pe.type),de=new B("jja");de.bind({"package <pkg> (包管理)":["--diff <-d> (分析当下包的差异)","--upDependencies <-u> (更新依赖,强制更新到 'latest',使用需谨慎)"],"remove <rm> (做一个简单的兼容的移除文件或文件夹的命令)":["--ignore <-i> (不打印日志(默认打印的))","--subdirectories <-s> (这是一个危险的命令,用于 windows 下递归删除执行命令下所有的给定文件名称)"],"update <up> (做一个简单的 npm 升级程序,对,简单的)":["--ignore <-i> (不建议你这么用,你会发现你像个傻子一样在那等结果)",`--dependencies <-d> (更新依赖,跟 ${x("npm update")} 一样)`],"clearScreen <cls> (清理终端显示屏幕,同 clearTerminal )":"","clearTerminal <clear> (清理终端显示屏幕,同 clearScreen )":"","git (一些关于 git 的操作)":[`commit (git 提交代码,是 ${C("commit")} 提交啊,不是 ${T("#666")("push")} 推送)`,"merge (合并两个分支)","tag (给提交打上 tag)"],"dns (使用 dns 获取 ip 地址)":["--domain <-d> (获取给定域名获取 ip 地址,默认 github.com )","--port <-p> (配置要校验的 port 端口号,默认为 443)"],"runOtherCode <run> (执行其他的代码,使用 )":[]}).run(),pe("参数已绑定,且已解析用户参数",de.args),pe.warn("当前的执行状态",de.state),de.isEnd(!0);const ge=E.green,me=T("0x993311"),fe=T("0x339999"),$e=T("0x666666"),we=h({show:!1,info:"请稍等",beforeDestroyed:e=>e&&de.end()}),ye=["A","AAAA","ANY","CAA","CNAME","MX","NAPTR","NS","PTR","SOA","SRV","TLSA","TXT"],he={domain:"github.com",port:443,dnsServers:["1.1.1.1","8.8.8.8","8.8.4.4","208.67.222.222","114.114.115.115","223.5.5.5","180.76.76.76"],ips:{},rrtype:["A"],reset(e){this.ips={},this.domain="github.com",this.port=443,this.rrtype=[],n(e)||e.forEach(e=>{const t=e["--domain"];!n(t)&&t.length>0&&(this.domain=t[0].toString());const o=e["--port"];!n(o)&&o.length>0&&(this.port=Number(o[0]));const i=e["--rrtype"];if(!n(i)&&i.length>0){const e=te(ye,i);e.length>0&&(this.rrtype=e)}})},noCopy:!0};async function ve(e){return Promise.all(e.map(e=>async function(e,n=3e3){const{ips:o,port:i}=he;if(t(o[e]))return ue||we.log(`${e} 联通性已校验过 ${o[e]?"🔥":"⛓️💥"}`),Promise.resolve(null);o[e]=!1,ue||we.log(`校验 ${e} 的联通性`);return new Promise(t=>{const r=new oe.Socket,s=(n=!1)=>{o[e]=n,r.destroy(),t(null)};r.setTimeout(n),r.on("connect",()=>s(!0)),r.on("timeout",()=>s()),r.on("error",()=>s()),ue||we.log("测试的接口为:",i),r.connect(i,e)})}(e)))}async function je(e="1.1.1.1"){const{domain:n}=he;try{const t=await async function(e,n){return new Promise(t=>{const o=new ee;we.run(`使用 ${n} 获取 ${e} 的 ip`),o.setServers([n]),o.resolve4(e,(o,i)=>{if(o)return ue||we.run(`使用 ${n} 获取 ${e} 的 ip 出错`),t(null);ue||we.log(`使用 ${n} 获取 ${e} 的 ip 值为 ${i.join(" --- ")}`),t(i)})})}(n,e);if(o(t))return ue||we.log(`${e} 获取 ${n} 的 ip 失败`),0;const r=(await ve(t)).filter(e=>!o(e));return i(r)?0:(we.destroyed(),y(),y(R`DNS: ${e}`),y(),r.forEach(({ip:e,isAlive:n})=>{const t=n?`${L(e)} ${me`->`} ✅`:`${$e(e)} ${C`⛓️💥`} ❌`;y(M(t))}),3+r.length)}catch(e){return ue||we.log("'获取 ip 错误'",e),0}}async function be(e){he.reset(e.options),await async function(){const{domain:e,ips:n}=he;we.run(`正在获取本地的 ${e} 的 ip 地址`);try{const t=await async function(e){return new Promise(n=>{Z.lookup(e,{all:!0,family:4},(t,o)=>{if(t)return pe.error(`获取本地 ${e} 的 ip 出错`,t),void n(null);ue||we.log(`获取本地 ${e} 的 ip 值为 ${o.join(" --- ")}`),n(o.map(e=>e.address))})})}(e);if(o(t))return;await ve(t),r(n)||function(e){const{ips:n}=he;y(me`本地配置 ${e} 的 ip 地址及联通性为:\n`),Object.keys(n).forEach(e=>{const t=n[e];t&&(he.noCopy=!1),y(q`- ${e}`,!1),y(t?me` -> ✅`:$e` -> ❌`)}),y()}(e)}catch(e){pe.error(e)}}(),await async function(){const{domain:e,dnsServers:n}=he;we.log(`${e} ip 列表:`);const t=n.map(e=>je(e)),o=await Promise.all(t);ue&&($(o.reduce((e,n)=>e+n,0)+1),w(!0))}(),we.destroyed();const{ips:n}=he;Object.keys(n).length>0?await async function(){const{domain:e,ips:n,port:t}=he;await v(`${N`${e}`} 域名解析结果:`),y();let o=he.noCopy;for(const t in n)if(Object.prototype.hasOwnProperty.call(n,t)){const i=n[t],r=i?`${L`- ${t.padEnd(16)}`} ${me`->`} ✅${o?q`(已复制)`:""}`:`${$e`- ${t.padEnd(16)}`} ${C`⛓️💥`} ❌`;y(r),i&&o&&(ne(`${t} ${e}`),o=!1)}y(),await v(C.italic.dim`${e} 联通性接口判断为 ${t.toString()}`),y(),y($e(m?`请在文件「 ${W("C:\\Windows\\System32\\drivers\\etc\\hosts")} 」 中修改`:`请执行修改:「 ${W("sudo vim /etc/hosts")} 」`))}():await async function(){const{domain:e,port:n}=he;await v(`\n找不到 ${C(e)} 的服务器 IP 地址 ${$e`测试使用 ${n.toString()} 端口`}\n`)}()}async function ke(e){const n=j("package.json","file",process.cwd());if(null==n)return!0;const t=b(k(n,"package.json"));if(o(t)||!t.version)return!0;const i=t.version;await g({code:`git tag -a v${i} -m '${e}'`,cwd:n}),await g({code:"git push origin --tag",cwd:n})}async function De(e){e.commit?await async function(e="版本维护",n=!1){const t=j(".git","directory");if(null==t)return y(T("#ff0")("not a git repository(当前目录非 git 储存库)"));const o=await g({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);const i=await g({code:"git status",cwd:t});if(!/nothing to commit, working tree clean/.test(i.data||"")){const o=await g({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);""==e.trim()&&(e=await F({text:"请输入提交信息"})??"");const i=await g({code:`git commit -m "${e}"`,cwd:t});return i.success?(i.error&&console.log(i.error),await g({code:"git push",cwd:t}),n&&await ke(e),!0):null!=console.log(i.error)}return!1}(e.commit.join(" ")):e.merge?await async function(e){if(s(e)){const n=await g("git branch -a");console.log(n.data),e=await F({text:"请输入要合并分支的名称"})??""}if(s(e))return H("没有获取到要合并的分支");const t=await I({data:[{label:"正常快进合并",value:""},{label:"非快进合并 (--no-ff)",value:"--no-ff"},{label:"多提交记录合并为一条 (--squash)",value:"--squash",tip:"适用于将众多小的提交合并成一个提交"}]});n(t)?H("您选择退出合并"):await g(`git merge ${e} ${t}`)}(e.merge.join("")):e.tag?await async function(){const e=await F({text:"请输入待标记的信息"});n(e)||await ke(e)}():de.help("git")}let Se=!1;const Ve={local:null,online:null,dependenceList:{},updateDependence:[],latestDependence:[],binning:function(e,t=!1){if(n(e)||r(e)||o(this.local))return;const{overrides:i}=this.local;let s=i&&a(i)?Object.keys(i):[];if(this.local?.jja?.pkg){const e=this.local.jja.pkg;c(e,e=>l(e)&&e.every(e=>p(e)))&&(s=s.concat(e)),c(e,e=>a(e))&&(s=s.concat(Object.keys(e)))}Se||(J(`${s.join("、")} 已被锁定`),Se=!0);for(const n in e){if(s.includes(n))continue;const o=e[n];this.dependenceList[n]={type:t?"devDependencies":"dependencies",version:o,localVersion:"",latestVersion:"",onlineVersion:"",tag:"",time:""}}},preReleaseDependence:[],timeoutDependence:[],registry:void 0},Oe=m?"cmd"===D()?"^":"`":"\\";const Ae=(()=>{const e=S(),n=function(e){const n=V();if(null===n)return!1;const{content:t,path:o}=n,i=ae(o);if("pnpm"===e){const e=k(i,"pnpm-workspace.yaml");if(!O(e))return!1;if(se(e,{encoding:"utf-8"}).split("\n").some(e=>e.startsWith("packages:")))return!0}if(t.workspaces){if("yarn"===e){const e=k(i,".yarnrc.yml");if(O(e))return!0}if("npm"===e)return!0}return!1}(e);return"npm"===e?"npm install --save".concat(n?" --include-workspace-root ":""):"yarn"===e?"yarn add".concat(n?" -W ":""):"pnpm add".concat(n?" -w ":"")})();async function Pe(){const n={"淘宝":"registry.npmmirror.com","官方":"registry.npmjs.org","腾讯":"mirrors.tencent.com/npm","中科大":"npmreg.proxy.ustclug.org",yarn:"registry.yarnpkg.com"},t=()=>Object.keys(n).map(e=>function(e){const n=Date.now();return new Promise(t=>{const o=`https://${e}/nry`,i=ce.request(o,{method:"HEAD",timeout:3500},o=>{t((o?.statusCode??0)>=200&&(o?.statusCode??0)<300?{url:e,time:Date.now()-n,success:!0}:{url:e,time:Date.now()-n,success:!1})});i.on("error",()=>t({url:e,time:Date.now()-n,success:!1})),i.on("timeout",()=>{i.destroy(),t({url:e,time:Date.now()-n,success:!1})}),i.end()})}(n[e])),o={};for(let n=0;n<3;n++){we.run(`请稍等,正在进行第${["一","二","三","四","五"][n]}次安装源延迟测试`);(await Promise.all(t())).forEach(n=>{e(n.success)||(o[n.url]?o[n.url]=(o[n.url]+n.time)/2:o[n.url]=n.time)})}return we.destroyed(),Object.keys(n).reduce((e,t)=>o[n[t]]<(o[n[e]]??1/0)?t:e,"")}async function Ce(){const{dependenceList:e,timeoutDependence:t}=Ve,i=Object.keys(e);i.length>18&&(n(Ve.registry)||!["官方","淘宝","腾讯","中科大","yarn"].some(e=>e===Ve.registry))&&(Ve.registry=await Pe(),y(`由于您未设置或者设置有误,现使用 ${q(Ve.registry)} npm 源`));const r=i.map(n=>new Promise(i=>{(async()=>{const r=e[n],s=e[n].version;we.run(`${U.current()}获取 ${n} 的本地安装信息`);const a=function(e){const n=b(k("node_modules/",e,"package.json"));let t="";t=o(n)?"":n.version||"";return Ve.dependenceList[e].localVersion=t,pe(e,"本地安装的版本为:",t),t}(n);if(we.run(`${U.success()} ${n} 的本地安装版本:${r.localVersion}`),await async function(e){const n=await A(e,Ve.registry,9867);if("timeout"===n.status)return void pe.warn("请求超时");if(o(n.data))return void pe.warn("获取包信息失败");const t=Date.now();pe("获取数据",e,"包信息");const i=Ve.dependenceList[e],{"dist-tags":r,time:s,version:a}=n.data;let c=a,l="latest";i.onlineVersion=c,i.tag=l;const p=Object.keys(r);pe("共需比对",p.length);for(let e=0,n=p.length;e<n;e++){const n=p[e],t=r[n];s[t]>s[c]&&(c=t,l=n)}pe("比对",e,"完成"),pe("耗时",Date.now()-t),"latest"!==l&&(pe(e,"最新版本为:",c,"tag为:",l),i.tag=l,i.latestVersion=c);const u=new Date(s[c]).toLocaleString();i.time=u,pe(`${e} 的最后发布时间为:${u}`)}(n),""===r.onlineVersion&&""===r.latestVersion)return t.push(n),we.log(`${U.error()} ${n} 本地 ${r.localVersion} 请求错误`),i(!0);if(a===r.onlineVersion){const e=`${n} 的本地${s} 安装版本为 ${a} 最新是 ${r.onlineVersion} `;return""===r.latestVersion?(we.run(U.info()+e),i(!0)):(Ve.preReleaseDependence.push(n),we.log(`${U.info()} ${e};最新预发布版本为 ${L(r.latestVersion)}`),i(!0))}if(a===r.latestVersion)return we.log(`${U.info()} ${n} 的本地版本${s} 安装版本为 ${a}`),i(!0);const c=`${n} 的本地 ${L(s)} 安装版本为 ${L(a)} 最新是 ${fe(r.onlineVersion)} `;Ve.latestDependence.push(n),""===r.latestVersion?(we.log(U.info()+c),i(!0)):(Ve.preReleaseDependence.push(n),we.log(`${U.info()} ${c};最新预发布版本为 ${L(r.latestVersion)}`),i(!0))})()}));return Promise.all(r).then(()=>{we.destroyed()})}async function Te(){const{local:e,preReleaseDependence:n,latestDependence:t,dependenceList:i,timeoutDependence:r}=Ve;if(o(e))return;const{dependencies:s,devDependencies:a}=e;if(Ve.binning(s),Ve.binning(a,!0),await Ce(),0===n.length&&0===t.length&&0===r.length)return y($e`看起来似乎没有依赖版本差异`);if(0===n.length&&0===t.length)return y(C`看起来网络不太好讷,所有的包线上版本的请求都出错了。或者是还没有执行 npm install 呐`);y(X.brightGreen`\n版本差异的依赖为:\n`);const c=[...t,...n];var l;new re({header:[q("包名"),{content:"发布时间",color:"#f26"},L`最新版本`],body:[...c.map(e=>{const{type:n,latestVersion:t,time:o,onlineVersion:r}=i[e];return["dependencies"===n?E(e):Y(e),x(o),t||Y(r)]})]})(),y(X.brightRed(`\n目前仅关注版本号是否为最新 ${X.brightMagenta("latest")}`)),y(`使用 ${Ae} 命令安装更新\n`),r.length>0&&(l=C`有一些包没有返回结果,请注意:`,y(M(l)),new re([...r.map(e=>[e])])());const p=[...t.filter(e=>!1===n.includes(e)).map(e=>X.bold(e).concat("@latest")),...n.map(e=>xe(e,i[e].tag))],u=t.map(e=>Ee(e)),d=[...t.map(e=>Ee(e)),...n.filter(e=>!1===t.includes(e)).map(e=>xe(e,i[e].tag))],g=p.length<n.length+t.length,m=n.length>0,f=t.length>0;m&&(g&&await Re({msg:"‼️ 预发布版本优先:",list:p,type:"brightRed"}),await Re({msg:"⚠️ latest 版本优先:",list:d,type:"brightMagenta",copy:!f})),f&&await Re({msg:"🎉 最佳安装:",list:u,type:"brightGreen",copy:!0})}function xe(e,n){return`${Y(e)}@${Y.random(n)}`}function Ee(e){return`${E(e)}@${ge`latest`}`}async function Re(e){const{msg:n,list:t,type:o,copy:i}=e,r=X[o];y(),y(r.reversed(n),!1),y(i?$e.reversed`已复制到剪切板 📋`:""),y(),y(`${r(Ae)} ${G(Oe)}\n${function(e){if(!l(e)||e.some(e=>!p(e)))throw new TypeError("参数必须为字符串数组");return e.map((n,t)=>t%3==2&&t!==e.length-1?`${n} ${G(Oe)}\n`:n.concat(" ")).join("")}(t)}`),y(),i&&ne(`${Ae} ${t.join(" ")}`.replace(ie(),""))}async function Le(e){Ve.registry=e[0]?.toString()||void 0,await async function(){const e=j("package.json","file");if(n(e))return void pe.warn("未找到当前包的 package.json 文件的位置");const t=b(k(e,"package.json"));if(o(t))return void pe.error("未找到当前包的 package.json 文件,该事件发生的概率极低");const i=t.name||"",r=await A(i,Ve.registry,9800);Ve.local=t,Ve.online=r.data}();const{local:t,online:i}=Ve,r=t?.version||"",s=i?.version||"";if(o(t))return pe("未找到包 package.json 文件退出"),y(me("未找到当前包 package.json"));const a=me(`当前包本地版本为: ${r}`);if(i){y(a);const e=" ".repeat(6);y(fe(`${e}线上版本为:${s}@latest`));const n=new Date(i&&i.time.modified||"").toLocaleString();z(`最后的发布时间为: ${n.toString()}`),P()}await Te()}async function Me(e=!0){const n=j("package.json","file");if(null==n)return y("当前目录下不存在 package.json 文件");const t=b(k(n,"package.json"))?.dependencies||{};if(e&&y(L("初始化完成,等待下一步命令")),Object.keys(t).length>0){let e="npm install --save";for(let n=Object.keys(t),o=n.length,i=0;i<o;i++){e+=` ${n[i]}@latest `}await g(e)}var o;e&&y(q("正在更新 dev 依赖")),await g("npm update --save"),e&&(o="开发依赖更新完毕",$(),w(),y(o))}async function Ne(e){e["--upDependencies"]?await Me(!0):e["--diff"]?await Le(e["--diff"]):de.help("package")}const qe={log:!1,subdirectories:!1};function We(e,n){y(`清理 ${e} 文件${n?"完成":"失败"}`)}async function Ge(e,n){qe.log||y(T("#aaa")(` ${e} 文件/夹存在,准备删除`));let t={error:null};return m?n.isDirectory()?(t=await g(`rd /q /s ${e.replace(/\//,"\\")}`),We(e,t.success)):n.isFile()&&(t=await g(`del ${qe.subdirectories?"/s":""} /q ${e.replace(/\//,"\\")}`),We(e,t.success)):(t=await g(`rm -rf ${e.replace(/\\/,"/")}`),We(e,t.success)),!!t.success||(console.log(t.error),!1)}async function Xe(e,n,t=5){return!await Reflect.apply(e,void 0,n)&&t--?(y(L("执行失败,现在重试中")),pe.warn(n,"执行失败,第",5-t,"次执行"),await Xe(e,n,t)):await Reflect.apply(e,void 0,n)}async function Ye(e){qe.log||y(T("#336")(`当前清理文件为 ${e}`));const t=O(e);qe.log||y(T("#666")(`正在检测 ${e} 文件/夹是否存在`)),pe(`文件${e} 数据为 ${t}`),n(t)?qe.log||y(_(`${e} 文件不存在`)):await Xe(Ge,[e,t])}const _e={log:!0};async function Be(e){Boolean(e["--dependencies"])&&await Me(_e.log)}const Fe=de.args.$arrMap;pe(Fe),pe(de.args.$original),de.args.$isVoid?(pe("没有匹配到子命令,打印帮助信息并退出"),de.help(),de.end()):i(de.args.$only)&&(console.log(`${de.args.$nomatch.map(e=>x(e)).join("、")} 不是有效的参数`),de.end());try{await async function e(){if(0===Fe.length)return;const t=Fe.shift();if(n(t))return await e();t.remove?(pe("执行文件移除"),await async function(e){const n=e.value||[],t=e.options;for(t?.forEach(e=>{const t=e["--ignore"];t&&(qe.log=!0,n.concat(t));const o=e["--subdirectories"];o&&(qe.subdirectories=!0,n.concat(o))}),qe.log||y(X.brightCyan`当前系统为: ${m?"windows":"linux/mac"}`),0==n.length&&(pe.warn("待删除列表",n),y(X.random`没有待清理的文件/文件夹`));n.length;){let e=n.pop();e=void 0===e?"undefined":e.toString(),await Ye(e)}}(t.remove)):t.clearScreen||t.clearTerminal?(pe("执行清屏"),await async function(){d()?(pe("执行第一遍清理"),await g({code:m?"cls":"clear",printLog:!1}),pe("执行第二遍清理"),f("3J"),f("c",!1),$(1/0),w(!0)):(pe.warn("当前系统不支持 TTY"),y("当前环境不支持 "))}()):t.git?(pe("执行 git 相关命令"),await async function(e){if(a(e)&&(e={value:[]}),n(e.options)||0===e.options.length)return pe.warn("没有配置项,直接返回的帮助文档"),de.help("git");const t=e.options;for(let e=0,n=t.length;e<n;e++)pe("本次执行",t[e]),await De(t[e])}(t.git)):t.package?(pe("执行 package 相关命令"),await async function(e){if(n(e.options)||0==e.options.length)return pe.warn("没有参数输入"),de.help("package");const t=e.options;for(let e=0,n=t.length;e<n;e++)await Ne(t[e])}(t.package)):t.update?(pe("执行 update 相关命令"),await async function(e){if(n(e.options)||0==e.options.length)return pe.warn("没有匹配到选项,自动抛出帮助文档"),de.help("update");const t=e.options;_e.log=!t.some(e=>e["--ignore"]);for(let e=0,n=t.length;e<n;e++)await Be(t[e])}(t.update)):t.dns?(pe("执行 dns 相关的命令"),await be(t.dns)):t.runOtherCode&&(pe("执行运行其他命令"),await async function(e){const{value:t}=e;if(n(t)||u(t.length))return;for(const e in t){const n=t[e].toString(),o=n.indexOf("=");if(-1===o)break;if(0===o){H(`未识别 "${n}" 且已移除该项 ❌`),t[e]="";continue}const[i,r]=[n.slice(0,o),n.slice(o+1)||"true"];process.env[i]=r,K(`设置环境变量 ${i}=${r} ✅`),t[e]=""}const o=t.join(" ").trim();pe("执行代码",o);const i=le(o,[],{stdio:"inherit",env:process.env,shell:!0});i.on("close",e=>e),i.on("error",e=>e),i.on("exit",e=>e)}(t.runOtherCode));try{await e()}catch(e){pe.error("执行 run 报错",e)}}(),P(" 终结分割线 ",!0)}catch(e){pe.error("执行 run 报错",e)}
|
package/package.json
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jja",
|
|
3
|
-
"
|
|
4
|
-
"version": "2.5.4",
|
|
5
|
-
"jja": {
|
|
6
|
-
"pkg": [
|
|
7
|
-
"eslint"
|
|
8
|
-
]
|
|
9
|
-
},
|
|
3
|
+
"version": "2.5.5",
|
|
10
4
|
"author": {
|
|
11
5
|
"name": "泥豆君",
|
|
12
6
|
"email": "Mr.MudBean@outlook.com",
|
|
@@ -28,15 +22,15 @@
|
|
|
28
22
|
],
|
|
29
23
|
"homepage": "https://npm.lmssee.com/jja",
|
|
30
24
|
"dependencies": {
|
|
31
|
-
"@vvi/command": "^4.0.
|
|
32
|
-
"@vvi/copy-text": "^1.1.
|
|
33
|
-
"@vvi/is": "^2.0.
|
|
34
|
-
"@vvi/log": "^1.1.
|
|
35
|
-
"@vvi/node": "^5.0.
|
|
36
|
-
"@vvi/pen": "^3.0.
|
|
37
|
-
"@vvi/pen-static": "^1.1.
|
|
38
|
-
"@vvi/table": "^0.2.
|
|
39
|
-
"@vvi/utils": "^2.0.
|
|
25
|
+
"@vvi/command": "^4.0.2",
|
|
26
|
+
"@vvi/copy-text": "^1.1.3",
|
|
27
|
+
"@vvi/is": "^2.0.6",
|
|
28
|
+
"@vvi/log": "^1.1.6",
|
|
29
|
+
"@vvi/node": "^5.0.1",
|
|
30
|
+
"@vvi/pen": "^3.0.3",
|
|
31
|
+
"@vvi/pen-static": "^1.1.4",
|
|
32
|
+
"@vvi/table": "^0.2.3",
|
|
33
|
+
"@vvi/utils": "^2.0.7"
|
|
40
34
|
},
|
|
41
35
|
"bugs": {
|
|
42
36
|
"url": "https://github.com/MrMudBean/jja/issues",
|