jja 2.3.21 → 2.5.0

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 ADDED
@@ -0,0 +1,200 @@
1
+ # jolly job aid
2
+
3
+ ## v2.5.0 (2026-6-24)
4
+
5
+ - 维护依赖
6
+ - 添加了使用 dns 后的一个修改 dns 文件路径的提示
7
+
8
+ ## v2.4.0 (2026-1-12)
9
+
10
+ - 添加了工作区中(非子包内)使用 `jja pkg --diff` 时自动添加工作区标识,且不可配置(貌似没有配置的需要)
11
+
12
+ ## v2.3.21 (2025-8-18)
13
+
14
+ - 修改已知问题,该问题是由上游依赖 [a-command](https://www.npmjs.com/package/a-command) 的错误解析导致的 `双等号丢失数据问题`
15
+
16
+ ## v2.3.20 (2025-8-16)
17
+
18
+ - 修改已知问题,该问题导致使用 `run` 时识别玩第一个参数项后直接退出了环境参数的设置
19
+
20
+ ## v2.3.19 (2025-8-13)
21
+
22
+ - 修复一个已知问题,该问题将导致使用 `run` 时遇见 `jja cls && jja run PORT=9463 NODE_OPTIONS='--max-old-space-size=768' docusaurus start` 这种命令解析出错
23
+
24
+ ## v2.3.18 (2025-8-12)
25
+
26
+ - 修复已知问题,该问题造成在 windows 上终端中使用 `jja pkg -d` 时返回了 `\` 结尾.
27
+
28
+ ## v2.3.18-beta.0 (2025-8-12)
29
+
30
+ - 添加 `run`, 使用 `unix` 的方式来创建环境变量值
31
+
32
+ ## v2.3.17 (2025-8-1)
33
+
34
+ - 文档修复
35
+
36
+ ## v2.3.16 (2025-7-30)
37
+
38
+ - 文档修复
39
+
40
+ ## v2.3.15 (2025-7-30)
41
+
42
+ ### 🔧 优化
43
+
44
+ - 优化了 `package` 下 `--diff` 的逻辑,检测包版本的用时是上一版本的 1/3。更快的速度,更好的交互体验
45
+
46
+ 在使用 `--diff` 时,发现
47
+
48
+ ```bash
49
+ npx jja package --diff # 耗时 16s ,有时候甚至达到 42s
50
+ npx jja package --diff=淘宝 # 耗时平均在 4s 左右
51
+ ```
52
+
53
+ ### ✨ 新增
54
+
55
+ 在未使用 `package` 的 `--diff` 值且依赖数超过 18 时,会先判定最快的 npm registry 链接,然后再进行请求。而在使用指定源时,不会触发(有时候当然时官方的好,毕竟,别的在同步包版本时会有 1 个小时的延迟)
56
+
57
+ ## v2.3.14 (2025-7-25)
58
+
59
+ - 修复已知问题
60
+
61
+ ## v2.3.13 (2025-7-24)
62
+
63
+ - 在使用 `package` 下 `--diff` 时,先根据包所在文件的包管理锁定文件的文件名判断当前使用的包管理器的类型,仅支持 `npm`、`yarn`、`pnpm`,未识别的会以 `npm install --save` 形式返回
64
+
65
+ ## v2.3.12 (2025-7-19)
66
+
67
+ - 么事
68
+
69
+ ## v2.3.11 (2025-7-16)
70
+
71
+ - 修改了不知所谓的 `package` 子命令下参数 `--diff` 执行命令的反馈效果,隐藏了行末的 `\`
72
+
73
+ ## v2.3.10 (2025-6-21)
74
+
75
+ - 修复已知 bug
76
+
77
+ ## v2.3.9 (2025-6-21)
78
+
79
+ - 在使用 `pkg` 的 `--diff` 参数时,现在过滤 'package.json' 的 'overrides' 配置的依赖项,展示效果如下
80
+
81
+ ```bash
82
+ ◼︎ xxxx 被锁定在 xx.xx.xx
83
+ ```
84
+
85
+ ## v2.3.8 (2025-6-10)
86
+
87
+ - 么事
88
+
89
+ ## v2.3.7 (2025-6-6)
90
+
91
+ - 本来不想更新着一个版本的,奈何在更新别的库时,发现一个问题,那就是在使用 [npx jja pkg -d](https://www.npmjs.com/package/jja) 时反馈包的线上版本与 [npx vjj -b](https://www.npmjs.com/package/vjj) 反馈的线上版本不一致。然而,两个不同的线上版本的数据都是可靠。但他们来自于不同的 npm registry 源。所以,现在,可在使用 `npx jja pkg -d` 时指定 npm 源,npm 源支持情况目前仅支持 [a-node-tools](https://www.npmjs.com/package/a-node-tools) 支持的。就像,你在领先的电脑上无法安装开发领先自己自主研发的开发自家软件的开发工具
92
+
93
+ ## v2.3.6 (2025-6-5)
94
+
95
+ - 优化部分逻辑
96
+
97
+ ## v2.3.5 (2025-5-31)
98
+
99
+ - 没事
100
+
101
+ ## v2.3.4 (2025-5-27)
102
+
103
+ - 更新了 `package --diff` 界面显示
104
+
105
+ ## v2.3.3 (5 🈷️ 11 日 2025 年)
106
+
107
+ - 更新了依赖,避免了因依赖问题而导致的问题
108
+
109
+ ## v2.3.2 (5 🈷️ 8 日 2025 年)
110
+
111
+ - 更新了依赖,避免了因依赖问题而导致的问题
112
+
113
+ ```bash
114
+ # VERSION=$(node -p "require('./package.json').version")
115
+
116
+ # echo "获取全称 npm version : $VERSION"
117
+ # if [[ $VERSION =~ -([a-zA-Z0-9]+)(\.|$) ]]; then
118
+ # TAG=${BASH_REMATCH[1]}
119
+ # echo "捕获到 npm tag : $TAG"
120
+ # else
121
+ # TAG="latest"
122
+ # echo "未捕获到 npm tag 使用默认 : $TAG"
123
+ # fi
124
+ ```
125
+
126
+ ## v2.3.1 (5 🈷️ 3 日 2025 年)
127
+
128
+ - 优化了 `dns` 子命令在没有解析到 ip 时的反馈
129
+
130
+ ## v2.3.0 (4 🈷️ 30 日 2025 年)
131
+
132
+ - ✨ 添加了 `dns` 子命令,用于检测出给定的域名的解析信息
133
+
134
+ ## v2.2.3 (4 🈷️ 27 日 2025 年)
135
+
136
+ - 更改了 `jja package --diff` 的返回值的渲染方式,如果存在多个依赖版本需要更新,现返回以 '\' 为分割的
137
+
138
+ ## v2.2.2 (4 🈷️ 27 日 2025 年)
139
+
140
+ - 补充发布
141
+
142
+ ## v2.2.1 (4 🈷️ 27 日 2025 年)
143
+
144
+ - 优化代码逻辑
145
+
146
+ ## v2.2.0 (4 🈷️ 25 日 2025 年)
147
+
148
+ - 移除了冗余文件
149
+ - 优化了 `jja remove` 子命令
150
+ - 优化了 `jja package` 子命令
151
+
152
+ ## v2.1.1 (4 月 16 日 2025 年)
153
+
154
+ - 修复了已知 🐛
155
+
156
+ ## v2.1.0 (4 月 16 日 2025 年)
157
+
158
+ - `npx jja pkg -d` 命令添加了返回当前包依赖的版本差异
159
+
160
+ ## v2.0.2 (4 月 13 日 2025 年)
161
+
162
+ - 修复已知 bug
163
+
164
+ ## v2.0.1 (4 月 13 日 2025 年)
165
+
166
+ - 文档更新 📝
167
+
168
+ ## v2.0.0 (4 月 12 日 2025 年)
169
+
170
+ ### 重大变更 🚨
171
+
172
+ - 依赖 `a-node-tools` 的更新导致 `jja` 更新到最新版本有更好的使用体验
173
+ - 移除了 `jja` 的 `up -n` 命令,该命令现在🈶 `vjj` 单独提供
174
+ - 由于执行的顺序性及执行效果,暂移除了 `runOther` 子命令
175
+
176
+ ## v1.0.3 (4 月 8 日 2025 年)
177
+
178
+ - 🐛 修复了使用 `jja cls` 在非交互式运行环境(如 github actions)造成的运行时错误
179
+
180
+ ## v1.0.2 (4 月 1 日 2025 年)
181
+
182
+ - 🐛 更新由于依赖 bug 而导致的 bug
183
+
184
+ ## v1.0.0 (3 月 30 日 2025 年)
185
+
186
+ - 🎉 更新了依赖
187
+
188
+ ## v0.0.4 ( 6 月 14 日 2024 年)
189
+
190
+ - 🔧 `pkg -d` 使用返回值进行了调整
191
+
192
+ ## v0.0.3 ( 6 月 14 日 2024 年)
193
+
194
+ - 修复 remove 命令在 windows 下文件分隔符不正确
195
+ - 修复 remove 在删除目标失败后无限重试
196
+ - 修复 package 命令下更新依赖显示被覆盖的问题
197
+
198
+ ## v0.0.1
199
+
200
+ - 🎉 添加了 git 下的 merge --squash
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright (c) <2025> <earthnut.dev>
3
+ Copyright (c) <2025> <Mr.MudBean>
4
4
 
5
5
  Permission to use, copy, modify, and/or distribute this software for any
6
6
  purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
16
 
17
17
  # MIT 许可证
18
18
 
19
- 版权所有 (c) [2025] [花生亻]
19
+ 版权所有 (c) [2025] [泥豆君]
20
20
 
21
21
  特此免费授予任何获得本软件及相关文档文件(以下简称“软件”)副本的人不受限制地处置该软件的权利,包括不受限制地使用、复制、修改、合并、发布、分发、再许可和/或出售该软件副本的权利,并允许向其提供该软件的人这样做,但须遵守以下条件:
22
22
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # jolly job aid (开心工作助手)
2
2
 
3
- [![version](<https://img.shields.io/npm/v/jja.svg?logo=npm&logoColor=rgb(0,0,0)&label=版本号&labelColor=rgb(73,73,228)&color=rgb(0,0,0)>)](https://www.npmjs.com/package/jja) [![issues 提交](<https://img.shields.io/badge/issues-提交-rgb(255,0,63)?logo=github>)](https://github.com/earthnutDev/jja/issues)
3
+ [![version](<https://img.shields.io/npm/v/jja.svg?logo=npm&logoColor=rgb(0,0,0)&label=版本号&labelColor=rgb(73,73,228)&color=rgb(0,0,0)>)](https://www.npmjs.com/package/jja) [![issues 提交](<https://img.shields.io/badge/issues-提交-rgb(255,0,63)?logo=github>)](https://github.com/MrMudBean/jja/issues)
4
4
 
5
5
  ---
6
6
 
@@ -107,6 +107,8 @@ npx jja dns -n
107
107
  }
108
108
  ```
109
109
 
110
- ## 📄 文档地址
110
+ ## 状态
111
111
 
112
- 参看 [https://earthnut.dev/npm/jja/](https://earthnut.dev/npm/jja/)
112
+ 此软件包是 `MrMudBean` 生态系统的一部分。
113
+ 它使用严格的 TypeScript 编写,并通过 Rollup 构建进行验证。
114
+ 虽然单元测试较少,但 API 稳定,并在生产环境中大量使用。
package/bin.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{isFalse as n,isUndefined as e,isBoolean as t,isNull as o,isEmptyArray as i,isEmptyObject as r,isBusinessEmptyString as s,isPlainObject as a,isString as c,isArray as l,isZero as p}from"@vvi/is";import{isTTY as u,runOtherCode as d,isWindows as g,__p as m,cursorMoveUp as f,cursorAfterClear as $,_p as w,waitingTips as y,typewrite as h,getDirectoryBy as v,readFileToJsonSync as b,pathJoin as k,detectShell as j,detectPackageManager as D,getPackageJsonSync as S,fileExist as V,getNpmPkgInfo as A,colorLine as O}from"@vvi/node";import{redPen as P,hexPen as C,randomPen as T,boldPen as x,reversedPen as E,greenPen as R,strInOneLineOnTerminal as L,brightMagentaPen as M,cyanPen as N,magentaPen as q,hidePen as W,pen as G,italicPen as X,yellowPen as Y}from"@vvi/pen";import{Args as _,question as B,ERROR as F,selection as H,WARN as I,prefixList as J,INFO as U,SUCCESS as z}from"@vvi/command";import{Dog as K}from"@vvi/log";import Q,{Resolver as Z}from"node:dns";import{copyTextToClipboard as nn}from"@vvi/copy-text";import{intersection as en}from"@vvi/utils";import tn from"node:net";import{terminalRegExp as on}from"@vvi/pen-static";import{Table as rn}from"@vvi/table";import{readFileSync as sn}from"node:fs";import{dirname as an}from"node:path";import cn from"node:https";import{spawn as ln}from"node:child_process";const pn=new K({name:"jja",type:!1}),un=n(pn.type),dn=new _("jja");dn.bind({"package <pkg> (包管理)":["--diff <-d> (分析当下包的差异)","--upDependencies <-u> (更新依赖,强制更新到 'latest',使用需谨慎)"],"remove <rm> (做一个简单的兼容的移除文件或文件夹的命令)":["--ignore <-i> (不打印日志(默认打印的))","--subdirectories <-s> (这是一个危险的命令,用于 windows 下递归删除执行命令下所有的给定文件名称)"],"update <up> (做一个简单的 npm 升级程序,对,简单的)":["--ignore <-i> (不建议你这么用,你会发现你像个傻子一样在那等结果)",`--dependencies <-d> (更新依赖,跟 ${T("npm update")} 一样)`],"clearScreen <cls> (清理终端显示屏幕,同 clearTerminal )":"","clearTerminal <clear> (清理终端显示屏幕,同 clearScreen )":"","git (一些关于 git 的操作)":[`commit (git 提交代码,是 ${P("commit")} 提交啊,不是 ${C("#666")("push")} 推送)`,"merge (合并两个分支)","tag (给提交打上 tag)"],"dns (使用 dns 获取 ip 地址)":["--domain <-d> (获取给定域名获取 ip 地址,默认 github.com )","--port <-p> (配置要校验的 port 端口号,默认为 443)"],"runOtherCode <run> (执行其他的代码,使用 )":[]}).run(),pn("参数已绑定,且已解析用户参数",dn.args),pn.warn("当前的执行状态",dn.state),dn.isEnd(!0);const gn=x.green,mn=C("0x993311"),fn=C("0x339999"),$n=C("0x666666"),wn=y({show:!1,info:"请稍等",beforeDestroyed:n=>n&&dn.end()}),yn=["A","AAAA","ANY","CAA","CNAME","MX","NAPTR","NS","PTR","SOA","SRV","TLSA","TXT"],hn={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(n){this.ips={},this.domain="github.com",this.port=443,this.rrtype=[],e(n)||n.forEach(n=>{const t=n["--domain"];!e(t)&&t.length>0&&(this.domain=t[0].toString());const o=n["--port"];!e(o)&&o.length>0&&(this.port=Number(o[0]));const i=n["--rrtype"];if(!e(i)&&i.length>0){const n=en(yn,i);n.length>0&&(this.rrtype=n)}})},noCopy:!0};async function vn(n){return Promise.all(n.map(n=>async function(n,e=3e3){const{ips:o,port:i}=hn;if(t(o[n]))return un||wn.log(`${n} 联通性已校验过 ${o[n]?"🔥":"⛓️‍💥"}`),Promise.resolve(null);o[n]=!1,un||wn.log(`校验 ${n} 的联通性`);return new Promise(t=>{const r=new tn.Socket,s=(e=!1)=>{o[n]=e,r.destroy(),t(null)};r.setTimeout(e),r.on("connect",()=>s(!0)),r.on("timeout",()=>s()),r.on("error",()=>s()),un||wn.log("测试的接口为:",i),r.connect(i,n)})}(n)))}async function bn(n="1.1.1.1"){const{domain:e}=hn;try{const t=await async function(n,e){return new Promise(t=>{const o=new Z;wn.run(`使用 ${e} 获取 ${n} 的 ip`),o.setServers([e]),o.resolve4(n,(o,i)=>{if(o)return un||wn.run(`使用 ${e} 获取 ${n} 的 ip 出错`),t(null);un||wn.log(`使用 ${e} 获取 ${n} 的 ip 值为 ${i.join(" --- ")}`),t(i)})})}(e,n);if(o(t))return un||wn.log(`${n} 获取 ${e} 的 ip 失败`),0;const r=(await vn(t)).filter(n=>!o(n));return i(r)?0:(wn.destroyed(),w(),w(E`DNS: ${n}`),w(),r.forEach(({ip:n,isAlive:e})=>{const t=e?`${R(n)} ${mn`->`} ✅`:`${$n(n)} ${P`⛓️‍💥`} ❌`;w(L(t))}),3+r.length)}catch(n){return un||wn.log("'获取 ip 错误'",n),0}}async function kn(n){hn.reset(n.options),await async function(){const{domain:n,ips:e}=hn;wn.run(`正在获取本地的 ${n} 的 ip 地址`);try{const t=await async function(n){return new Promise(e=>{Q.lookup(n,{all:!0,family:4},(t,o)=>{if(t)return pn.error(`获取本地 ${n} 的 ip 出错`,t),void e(null);un||wn.log(`获取本地 ${n} 的 ip 值为 ${o.join(" --- ")}`),e(o.map(n=>n.address))})})}(n);if(o(t))return;await vn(t),r(e)||function(n){const{ips:e}=hn;w(mn`本地配置 ${n} 的 ip 地址及联通性为:\n`),Object.keys(e).forEach(n=>{const t=e[n];t&&(hn.noCopy=!1),w(N`- ${n}`,!1),w(t?mn` -> ✅`:$n` -> ❌`)}),w()}(n)}catch(n){pn.error(n)}}(),await async function(){const{domain:n,dnsServers:e}=hn;wn.log(`${n} ip 列表:`);const t=e.map(n=>bn(n)),o=await Promise.all(t);un&&(f(o.reduce((n,e)=>n+e,0)+1),$(!0))}(),wn.destroyed();const{ips:e}=hn;Object.keys(e).length>0?await async function(){const{domain:n,ips:e,port:t}=hn;await h(`${M`${n}`} 域名解析结果:`),w();let o=hn.noCopy;for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){const i=e[t],r=i?`${R`- ${t.padEnd(16)}`} ${mn`->`} ✅${o?N`(已复制)`:""}`:`${$n`- ${t.padEnd(16)}`} ${P`⛓️‍💥`} ❌`;w(r),i&&o&&(nn(`${t} ${n}`),o=!1)}w(),await h(P.italic.dim`${n} 联通性接口判断为 ${t.toString()}`),w(),w($n(g?`请在文件「 ${q("C:\\Windows\\System32\\drivers\\etc\\hosts")} 」 中修改`:`请执行修改:「 ${q("sudo vim /etc/hosts")} 」`))}():await async function(){const{domain:n,port:e}=hn;await h(`\n找不到 ${P(n)} 的服务器 IP 地址 ${$n`测试使用 ${e.toString()} 端口`}\n`)}()}async function jn(n){const e=v("package.json","file",process.cwd());if(null==e)return!0;const t=b(k(e,"package.json"));if(o(t)||!t.version)return!0;const i=t.version;await d({code:`git tag -a v${i} -m '${n}'`,cwd:e}),await d({code:"git push origin --tag",cwd:e})}async function Dn(n){n.commit?await async function(n="版本维护",e=!1){const t=v(".git","directory");if(null==t)return w(C("#ff0")("not a git repository(当前目录非 git 储存库)"));const o=await d({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);const i=await d({code:"git status",cwd:t});if(!/nothing to commit, working tree clean/.test(i.data||"")){const o=await d({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);""==n.trim()&&(n=await B({text:"请输入提交信息"})??"");const i=await d({code:`git commit -m "${n}"`,cwd:t});return i.success?(i.error&&console.log(i.error),await d({code:"git push",cwd:t}),e&&await jn(n),!0):null!=console.log(i.error)}return!1}(n.commit.join(" ")):n.merge?await async function(n){if(s(n)){const e=await d("git branch -a");console.log(e.data),n=await B({text:"请输入要合并分支的名称"})??""}if(s(n))return F("没有获取到要合并的分支");const t=await H({data:[{label:"正常快进合并",value:""},{label:"非快进合并 (--no-ff)",value:"--no-ff"},{label:"多提交记录合并为一条 (--squash)",value:"--squash",tip:"适用于将众多小的提交合并成一个提交"}]});e(t)?F("您选择退出合并"):await d(`git merge ${n} ${t}`)}(n.merge.join("")):n.tag?await async function(){const n=await B({text:"请输入待标记的信息"});e(n)||await jn(n)}():dn.help("git")}const Sn={local:null,online:null,dependenceList:{},updateDependence:[],latestDependence:[],binning:function(n,t=!1){if(e(n)||r(n)||o(this.local))return;const{overrides:i}=this.local;for(const e in n){if(c(i?.[e])){I(`${e} 被锁定在 ${i[e]}`);continue}const o=n[e];this.dependenceList[e]={type:t?"devDependencies":"dependencies",version:o,localVersion:"",latestVersion:"",onlineVersion:"",tag:"",time:""}}},preReleaseDependence:[],timeoutDependence:[],registry:void 0},Vn=g?"cmd"===j()?"^":"`":"\\";const An=(()=>{const n=D(),e=function(n){const e=S();if(null===e)return!1;const{content:t,path:o}=e,i=an(o);if("pnpm"===n){const n=k(i,"pnpm-workspace.yaml");if(!V(n))return!1;if(sn(n,{encoding:"utf-8"}).split("\n").some(n=>n.startsWith("packages:")))return!0}if(t.workspaces){if("yarn"===n){const n=k(i,".yarnrc.yml");if(V(n))return!0}if("npm"===n)return!0}return!1}(n);return"npm"===n?"npm install --save".concat(e?" --include-workspace-root ":""):"yarn"===n?"yarn add".concat(e?" -W ":""):"pnpm add".concat(e?" -w ":"")})();async function On(){const e={"淘宝":"registry.npmmirror.com","官方":"registry.npmjs.org","腾讯":"mirrors.tencent.com/npm","中科大":"npmreg.proxy.ustclug.org",yarn:"registry.yarnpkg.com"},t=()=>Object.keys(e).map(n=>function(n){const e=Date.now();return new Promise(t=>{const o=`https://${n}/nry`,i=cn.request(o,{method:"HEAD",timeout:3500},o=>{t((o?.statusCode??0)>=200&&(o?.statusCode??0)<300?{url:n,time:Date.now()-e,success:!0}:{url:n,time:Date.now()-e,success:!1})});i.on("error",()=>t({url:n,time:Date.now()-e,success:!1})),i.on("timeout",()=>{i.destroy(),t({url:n,time:Date.now()-e,success:!1})}),i.end()})}(e[n])),o={};for(let e=0;e<3;e++){wn.run(`请稍等,正在进行第${["一","二","三","四","五"][e]}次安装源延迟测试`);(await Promise.all(t())).forEach(e=>{n(e.success)||(o[e.url]?o[e.url]=(o[e.url]+e.time)/2:o[e.url]=e.time)})}return wn.destroyed(),Object.keys(e).reduce((n,t)=>o[e[t]]<(o[e[n]]??1/0)?t:n,"")}async function Pn(){const{dependenceList:n,timeoutDependence:t}=Sn,i=Object.keys(n);i.length>18&&(e(Sn.registry)||!["官方","淘宝","腾讯","中科大","yarn"].some(n=>n===Sn.registry))&&(Sn.registry=await On(),w(`由于您未设置或者设置有误,现使用 ${N(Sn.registry)} npm 源`));const r=i.map(e=>new Promise(i=>{(async()=>{const r=n[e],s=n[e].version;wn.run(`${J.current()}获取 ${e} 的本地安装信息`);const a=function(n){const e=b(k("node_modules/",n,"package.json"));let t="";t=o(e)?"":e.version||"";return Sn.dependenceList[n].localVersion=t,pn(n,"本地安装的版本为:",t),t}(e);if(wn.run(`${J.success()} ${e} 的本地安装版本:${r.localVersion}`),await async function(n){const e=await A(n,Sn.registry,9867);if("timeout"===e.status)return void pn.warn("请求超时");if(o(e.data))return void pn.warn("获取包信息失败");const t=Date.now();pn("获取数据",n,"包信息");const i=Sn.dependenceList[n],{"dist-tags":r,time:s,version:a}=e.data;let c=a,l="latest";i.onlineVersion=c,i.tag=l;const p=Object.keys(r);pn("共需比对",p.length);for(let n=0,e=p.length;n<e;n++){const e=p[n],t=r[e];s[t]>s[c]&&(c=t,l=e)}pn("比对",n,"完成"),pn("耗时",Date.now()-t),"latest"!==l&&(pn(n,"最新版本为:",c,"tag为:",l),i.tag=l,i.latestVersion=c);const u=new Date(s[c]).toLocaleString();i.time=u,pn(`${n} 的最后发布时间为:${u}`)}(e),""===r.onlineVersion&&""===r.latestVersion)return t.push(e),wn.log(`${J.error()} ${e} 本地 ${r.localVersion} 请求错误`),i(!0);if(a===r.onlineVersion){const n=`${e} 的本地${s} 安装版本为 ${a} 最新是 ${r.onlineVersion} `;return""===r.latestVersion?(wn.run(J.info()+n),i(!0)):(Sn.preReleaseDependence.push(e),wn.log(`${J.info()} ${n};最新预发布版本为 ${R(r.latestVersion)}`),i(!0))}if(a===r.latestVersion)return wn.log(`${J.info()} ${e} 的本地版本${s} 安装版本为 ${a}`),i(!0);const c=`${e} 的本地 ${R(s)} 安装版本为 ${R(a)} 最新是 ${fn(r.onlineVersion)} `;Sn.latestDependence.push(e),""===r.latestVersion?(wn.log(J.info()+c),i(!0)):(Sn.preReleaseDependence.push(e),wn.log(`${J.info()} ${c};最新预发布版本为 ${R(r.latestVersion)}`),i(!0))})()}));return Promise.all(r).then(()=>{wn.destroyed()})}async function Cn(){const{local:n,preReleaseDependence:e,latestDependence:t,dependenceList:i,timeoutDependence:r}=Sn;if(o(n))return;const{dependencies:s,devDependencies:a}=n;if(Sn.binning(s),Sn.binning(a,!0),await Pn(),0===e.length&&0===t.length&&0===r.length)return w($n`看起来似乎没有依赖版本差异`);if(0===e.length&&0===t.length)return w(P`看起来网络不太好讷,所有的包线上版本的请求都出错了。或者是还没有执行 npm install 呐`);w(G.brightGreen`\n版本差异的依赖为:\n`);const c=[...t,...e];var l;new rn({header:[N("包名"),{content:"发布时间",color:"#f26"},R`最新版本`],body:[...c.map(n=>{const{type:e,latestVersion:t,time:o,onlineVersion:r}=i[n];return["dependencies"===e?x(n):X(n),T(o),t||X(r)]})]})(),w(G.brightRed(`\n目前仅关注版本号是否为最新 ${G.brightMagenta("latest")}`)),w(`使用 ${An} 命令安装更新\n`),r.length>0&&(l=P`有一些包没有返回结果,请注意:`,w(L(l)),new rn([...r.map(n=>[n])])());const p=[...t.filter(n=>!1===e.includes(n)).map(n=>G.bold(n).concat("@latest")),...e.map(n=>Tn(n,i[n].tag))],u=t.map(n=>xn(n)),d=[...t.map(n=>xn(n)),...e.filter(n=>!1===t.includes(n)).map(n=>Tn(n,i[n].tag))],g=p.length<e.length+t.length,m=e.length>0,f=t.length>0;m&&(g&&await En({msg:"‼️ 预发布版本优先:",list:p,type:"brightRed"}),await En({msg:"⚠️ latest 版本优先:",list:d,type:"brightMagenta",copy:!f})),f&&await En({msg:"🎉 最佳安装:",list:u,type:"brightGreen",copy:!0})}function Tn(n,e){return`${X(n)}@${X.random(e)}`}function xn(n){return`${x(n)}@${gn`latest`}`}async function En(n){const{msg:e,list:t,type:o,copy:i}=n,r=G[o];w(),w(r.reversed(e),!1),w(i?$n.reversed`已复制到剪切板 📋`:""),w(),w(`${r(An)} ${W(Vn)}\n${function(n){if(!l(n)||n.some(n=>!c(n)))throw new TypeError("参数必须为字符串数组");return n.map((e,t)=>t%3==2&&t!==n.length-1?`${e} ${W(Vn)}\n`:e.concat(" ")).join("")}(t)}`),w(),i&&nn(`${An} ${t.join(" ")}`.replace(on(),""))}async function Rn(n){Sn.registry=n[0]?.toString()||void 0,await async function(){const n=v("package.json","file");if(e(n))return void pn.warn("未找到当前包的 package.json 文件的位置");const t=b(k(n,"package.json"));if(o(t))return void pn.error("未找到当前包的 package.json 文件,该事件发生的概率极低");const i=t.name||"",r=await A(i,Sn.registry,9800);Sn.local=t,Sn.online=r.data}();const{local:t,online:i}=Sn,r=t?.version||"",s=i?.version||"";if(o(t))return pn("未找到包 package.json 文件退出"),w(mn("未找到当前包 package.json"));const a=mn(`当前包本地版本为: ${r}`);if(i){w(a);const n=" ".repeat(6);w(fn(`${n}线上版本为:${s}@latest`));const e=new Date(i&&i.time.modified||"").toLocaleString();U(`最后的发布时间为: ${e.toString()}`),O()}await Cn()}async function Ln(n=!0){const e=v("package.json","file");if(null==e)return w("当前目录下不存在 package.json 文件");const t=b(k(e,"package.json"))?.dependencies||{};if(n&&w(R("初始化完成,等待下一步命令")),Object.keys(t).length>0){let n="npm install --save";for(let e=Object.keys(t),o=e.length,i=0;i<o;i++){n+=` ${e[i]}@latest `}await d(n)}var o;n&&w(N("正在更新 dev 依赖")),await d("npm update --save"),n&&(o="开发依赖更新完毕",f(),$(),w(o))}async function Mn(n){n["--upDependencies"]?await Ln(!0):n["--diff"]?await Rn(n["--diff"]):dn.help("package")}const Nn={log:!1,subdirectories:!1};function qn(n,e){w(`清理 ${n} 文件${e?"完成":"失败"}`)}async function Wn(n,e){Nn.log||w(C("#aaa")(` ${n} 文件/夹存在,准备删除`));let t={error:null};return g?e.isDirectory()?(t=await d(`rd /q /s ${n.replace(/\//,"\\")}`),qn(n,t.success)):e.isFile()&&(t=await d(`del ${Nn.subdirectories?"/s":""} /q ${n.replace(/\//,"\\")}`),qn(n,t.success)):(t=await d(`rm -rf ${n.replace(/\\/,"/")}`),qn(n,t.success)),!!t.success||(console.log(t.error),!1)}async function Gn(n,e,t=5){return!await Reflect.apply(n,void 0,e)&&t--?(w(R("执行失败,现在重试中")),pn.warn(e,"执行失败,第",5-t,"次执行"),await Gn(n,e,t)):await Reflect.apply(n,void 0,e)}async function Xn(n){Nn.log||w(C("#336")(`当前清理文件为 ${n}`));const t=V(n);Nn.log||w(C("#666")(`正在检测 ${n} 文件/夹是否存在`)),pn(`文件${n} 数据为 ${t}`),e(t)?Nn.log||w(Y(`${n} 文件不存在`)):await Gn(Wn,[n,t])}const Yn={log:!0};async function _n(n){Boolean(n["--dependencies"])&&await Ln(Yn.log)}const Bn=dn.args.$arrMap;pn(Bn),pn(dn.args.$original),dn.args.$isVoid?(pn("没有匹配到子命令,打印帮助信息并退出"),dn.help(),dn.end()):i(dn.args.$only)&&(console.log(`${dn.args.$nomatch.map(n=>T(n)).join("、")} 不是有效的参数`),dn.end());try{await async function n(){if(0===Bn.length)return;const t=Bn.shift();if(e(t))return await n();t.remove?(pn("执行文件移除"),await async function(n){const e=n.value||[],t=n.options;for(t?.forEach(n=>{const t=n["--ignore"];t&&(Nn.log=!0,e.concat(t));const o=n["--subdirectories"];o&&(Nn.subdirectories=!0,e.concat(o))}),Nn.log||w(G.brightCyan`当前系统为: ${g?"windows":"linux/mac"}`),0==e.length&&(pn.warn("待删除列表",e),w(G.random`没有待清理的文件/文件夹`));e.length;){let n=e.pop();n=void 0===n?"undefined":n.toString(),await Xn(n)}}(t.remove)):t.clearScreen||t.clearTerminal?(pn("执行清屏"),await async function(){u()?(pn("执行第一遍清理"),await d({code:g?"cls":"clear",printLog:!1}),pn("执行第二遍清理"),m("3J"),m("c",!1),f(1/0),$(!0)):(pn.warn("当前系统不支持 TTY"),w("当前环境不支持 "))}()):t.git?(pn("执行 git 相关命令"),await async function(n){if(a(n)&&(n={value:[]}),e(n.options)||0===n.options.length)return pn.warn("没有配置项,直接返回的帮助文档"),dn.help("git");const t=n.options;for(let n=0,e=t.length;n<e;n++)pn("本次执行",t[n]),await Dn(t[n])}(t.git)):t.package?(pn("执行 package 相关命令"),await async function(n){if(e(n.options)||0==n.options.length)return pn.warn("没有参数输入"),dn.help("package");const t=n.options;for(let n=0,e=t.length;n<e;n++)await Mn(t[n])}(t.package)):t.update?(pn("执行 update 相关命令"),await async function(n){if(e(n.options)||0==n.options.length)return pn.warn("没有匹配到选项,自动抛出帮助文档"),dn.help("update");const t=n.options;Yn.log=!t.some(n=>n["--ignore"]);for(let n=0,e=t.length;n<e;n++)await _n(t[n])}(t.update)):t.dns?(pn("执行 dns 相关的命令"),await kn(t.dns)):t.runOtherCode&&(pn("执行运行其他命令"),await async function(n){const{value:t}=n;if(e(t)||p(t.length))return;for(const n in t){const e=t[n].toString(),o=e.indexOf("=");if(-1===o)break;if(0===o){F(`未识别 "${e}" 且已移除该项 ❌`),t[n]="";continue}const[i,r]=[e.slice(0,o),e.slice(o+1)||"true"];process.env[i]=r,z(`设置环境变量 ${i}=${r} ✅`),t[n]=""}const o=t.join(" ").trim();pn("执行代码",o);const i=ln(o,[],{stdio:"inherit",env:process.env,shell:!0});i.on("close",n=>n),i.on("error",n=>n),i.on("exit",n=>n)}(t.runOtherCode));try{await n()}catch(n){pn.error("执行 run 报错",n)}}(),O(" 终结分割线 ",!0)}catch(n){pn.error("执行 run 报错",n)}
package/package.json CHANGED
@@ -1,45 +1,43 @@
1
1
  {
2
2
  "name": "jja",
3
3
  "type": "module",
4
- "version": "2.3.21",
5
- "description": "一些在终端的执行动作 🥜",
6
- "license": "MIT",
7
- "dependencies": {
8
- "@color-pen/static": "^1.0.1",
9
- "@qqi/copy-text": "^1.0.7",
10
- "@qqi/log": "^0.1.1",
11
- "a-command": "^2.3.16",
12
- "a-js-tools": "^1.0.12",
13
- "a-node-tools": "^4.2.20",
14
- "a-type-of-js": "^1.0.7",
15
- "color-pen": "^2.0.13",
16
- "colored-table": "^0.1.0"
17
- },
4
+ "version": "2.5.0",
18
5
  "author": {
19
- "name": "🥜",
20
- "email": "earthnut.dev@outlook.com",
21
- "url": "https://earthnut.dev"
6
+ "name": "泥豆君",
7
+ "email": "Mr.MudBean@outlook.com",
8
+ "url": "https://mudbean.cn"
22
9
  },
10
+ "description": "一些在终端的执行动作 🥜",
11
+ "license": "MIT",
23
12
  "files": [
24
- "bin.mjs"
13
+ "bin.js",
14
+ "LICENSE",
15
+ "README.md",
16
+ "THIRD-PARTY-LICENSES.txt",
17
+ "CHANGELOG.md"
25
18
  ],
26
19
  "keywords": [
27
- "jja"
20
+ "jja",
21
+ "mudbean",
22
+ "vvi"
28
23
  ],
24
+ "homepage": "https://npm.lmssee.com/jja",
25
+ "bugs": {
26
+ "url": "https://github.com/MrMudBean/jja/issues",
27
+ "email": "Mr.MudBean@outlook.com"
28
+ },
29
29
  "repository": {
30
30
  "type": "git",
31
- "url": "git+https://github.com/earthnutDev/jja.git"
32
- },
33
- "homepage": "https://earthnut.dev/npm/jja",
34
- "bugs": {
35
- "url": "https://github.com/earthnutDev/jja/issues",
36
- "email": "earthnut.dev@outlook.com"
31
+ "url": "git+https://github.com/MrMudBean/jja.git"
37
32
  },
38
33
  "publishConfig": {
39
34
  "access": "public",
40
35
  "registry": "https://registry.npmjs.org/"
41
36
  },
42
37
  "bin": {
43
- "jja": "bin.mjs"
38
+ "jja": "bin.js"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
44
42
  }
45
43
  }
package/bin.mjs DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{Dog as e}from"@qqi/log";import{isFalse as n,isUndefined as t,isArray as o,isString as i,isEmptyObject as r,isNull as s,isBusinessEmptyString as a,isPlainObject as c,isBoolean as l,isEmptyArray as p,isZero as u}from"a-type-of-js";import{Command as d,enPrefixList as g}from"a-command";import{redPen as m,hexPen as f,randomPen as $,greenPen as w,yellowPen as y,pen as h,strInOneLineOnTerminal as v,hidePen as b,cyanPen as j,boldPen as k,italicPen as D,reversedPen as S}from"color-pen";import{_p as V,isWindows as R,runOtherCode as O,fileExist as A,detectShell as E,detectPackageManager as P,cursorMoveUp as C,cursorAfterClear as q,getDirectoryBy as T,readFileToJsonSync as x,pathJoin as L,getNpmPkgInfo as N,waitingTips as M,colorLine as F,isTTY as G,__p as I,typewrite as U}from"a-node-tools";import X from"node:https";import{copyTextToClipboard as Y}from"@qqi/copy-text";import{terminalRegExp as _}from"@color-pen/static";import{Table as B}from"colored-table";import{intersection as H}from"a-js-tools";import J,{Resolver as W}from"node:dns";import z from"node:net";import{spawn as K}from"node:child_process";const Q=new e({name:"jja",type:!1}),Z=n(Q.type),ee=new d("jja");ee.bind({"package <pkg> (包管理)":["--diff <-d> (分析当下包的差异)","--upDependencies <-u> (更新依赖,强制更新到 'latest',使用需谨慎)"],"remove <rm> (做一个简单的兼容的移除文件或文件夹的命令)":["--ignore <-i> (不打印日志(默认打印的))","--subdirectories <-s> (这是一个危险的命令,用于 windows 下递归删除执行命令下所有的给定文件名称)"],"update <up> (做一个简单的 npm 升级程序,对,简单的)":["--ignore <-i> (不建议你这么用,你会发现你像个傻子一样在那等结果)",`--dependencies <-d> (更新依赖,跟 ${$("npm update")} 一样)`],"clearScreen <cls> (清理终端显示屏幕,同 clearTerminal )":"","clearTerminal <clear> (清理终端显示屏幕,同 clearScreen )":"","git (一些关于 git 的操作)":[`commit (git 提交代码,是 ${m("commit")} 提交啊,不是 ${f("#666")("push")} 推送)`,"merge (合并两个分支)","tag (给提交打上 tag)"],"dns (使用 dns 获取 ip 地址)":["--domain <-d> (获取给定域名获取 ip 地址,默认 github.com )","--port <-p> (配置要校验的 port 端口号,默认为 443)"],"runOtherCode <run> (执行其他的代码,使用 )":[]}).run(),Q("参数已绑定,且已解析用户参数",ee.args),Q.warn("当前的执行状态",ee.state),ee.isEnd(!0);const ne={log:!1,subdirectories:!1};async function te(e,n,t=5){return!await Reflect.apply(e,void 0,n)&&t--?(V(w("执行失败,现在重试中")),Q.warn(n,"执行失败,第",5-t,"次执行"),await te(e,n,t)):await Reflect.apply(e,void 0,n)}function oe(e,n){V(`清理 ${e} 文件${n?"完成":"失败"}`)}async function ie(e,n){ne.log||V(f("#aaa")(` ${e} 文件/夹存在,准备删除`));let t={error:null};return R?n.isDirectory()?(t=await O(`rd /q /s ${e.replace(/\//,"\\")}`),oe(e,t.success)):n.isFile()&&(t=await O(`del ${ne.subdirectories?"/s":""} /q ${e.replace(/\//,"\\")}`),oe(e,t.success)):(t=await O(`rm -rf ${e.replace(/\\/,"/")}`),oe(e,t.success)),!!t.success||(console.log(t.error),!1)}async function re(e){ne.log||V(f("#336")(`当前清理文件为 ${e}`));const n=A(e);ne.log||V(f("#666")(`正在检测 ${e} 文件/夹是否存在`)),Q(`文件${e} 数据为 ${n}`),t(n)?ne.log||V(y(`${e} 文件不存在`)):await te(ie,[e,n])}const se=R?"cmd"===E()?"^":"`":"\\";const ae=(()=>{const e=P();return"npm"===e?"npm install --save":"yarn"===e?"yarn add":"pnpm add"})();async function ce(e=!0){const n=T("package.json","file");if(null==n)return V("当前目录下不存在 package.json 文件");const t=x(L(n,"package.json"))?.dependencies||{};if(e&&V(w("初始化完成,等待下一步命令")),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 O(e)}var o;e&&V(j("正在更新 dev 依赖")),await O("npm update --save"),e&&(o="开发依赖更新完毕",C(),q(),V(o))}const le={log:!0};async function pe(e){Boolean(e["--dependencies"])&&await ce(le.log)}const ue={local:null,online:null,dependenceList:{},updateDependence:[],latestDependence:[],binning:function(e,n=!1){if(t(e)||r(e)||s(this.local))return;const{overrides:o}=this.local;for(const t in e){if(i(o?.[t])){ee.WARN(`${t} 被锁定在 ${o[t]}`);continue}const r=e[t];this.dependenceList[t]={type:n?"devDependencies":"dependencies",version:r,localVersion:"",latestVersion:"",onlineVersion:"",tag:"",time:""}}},preReleaseDependence:[],timeoutDependence:[],registry:void 0};const de=k.green,ge=f("0x993311"),me=f("0x339999"),fe=f("0x666666");const $e=M({show:!1,info:"请稍等",beforeDestroyed:e=>e&&ee.end()});async function we(){const e={"淘宝":"registry.npmmirror.com","官方":"registry.npmjs.org","腾讯":"mirrors.tencent.com/npm","中科大":"npmreg.proxy.ustclug.org",yarn:"registry.yarnpkg.com"},t=()=>Object.keys(e).map(n=>function(e){const n=Date.now();return new Promise(t=>{const o=`https://${e}/nry`,i=X.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()})}(e[n])),o={};for(let e=0;e<3;e++){$e.run(`请稍等,正在进行第${["一","二","三","四","五"][e]}次安装源延迟测试`);(await Promise.all(t())).forEach(e=>{n(e.success)||(o[e.url]?o[e.url]=(o[e.url]+e.time)/2:o[e.url]=e.time)})}return $e.destroyed(),Object.keys(e).reduce((n,t)=>o[e[t]]<(o[e[n]]??1/0)?t:n,"")}async function ye(){const{dependenceList:e,timeoutDependence:n}=ue,o=Object.keys(e);o.length>18&&(t(ue.registry)||!["官方","淘宝","腾讯","中科大","yarn"].some(e=>e===ue.registry))&&(ue.registry=await we(),V(`由于您未设置或者设置有误,现使用 ${j(ue.registry)} npm 源`));const i=o.map(t=>new Promise(o=>{(async()=>{const i=e[t],r=e[t].version;$e.run(`${g.current()}获取 ${t} 的本地安装信息`);const a=function(e){const n=x(L("node_modules/",e,"package.json"));let t="";return t=s(n)?"":n.version||"",ue.dependenceList[e].localVersion=t,Q(e,"本地安装的版本为:",t),t}(t);if($e.run(`${g.success()} ${t} 的本地安装版本:${i.localVersion}`),await async function(e){const n=await N(e,ue.registry,9867);if("timeout"===n.status)return void Q.warn("请求超时");if(s(n.data))return void Q.warn("获取包信息失败");const t=Date.now();Q("获取数据",e,"包信息");const o=ue.dependenceList[e],{"dist-tags":i,time:r,version:a}=n.data;let c=a,l="latest";o.onlineVersion=c,o.tag=l;const p=Object.keys(i);Q("共需比对",p.length);for(let e=0,n=p.length;e<n;e++){const n=p[e],t=i[n];r[t]>r[c]&&(c=t,l=n)}Q("比对",e,"完成"),Q("耗时",Date.now()-t),"latest"!==l&&(Q(e,"最新版本为:",c,"tag为:",l),o.tag=l,o.latestVersion=c);const u=new Date(r[c]).toLocaleString();o.time=u,Q(`${e} 的最后发布时间为:${u}`)}(t),""===i.onlineVersion&&""===i.latestVersion)return n.push(t),$e.log(`${g.error()} ${t} 本地 ${i.localVersion} 请求错误`),o(!0);if(a===i.onlineVersion){const e=`${t} 的本地${r} 安装版本为 ${a} 最新是 ${i.onlineVersion} `;return""===i.latestVersion?($e.run(g.info()+e),o(!0)):(ue.preReleaseDependence.push(t),$e.log(`${g.info()} ${e};最新预发布版本为 ${w(i.latestVersion)}`),o(!0))}if(a===i.latestVersion)return $e.log(`${g.info()} ${t} 的本地版本${r} 安装版本为 ${a}`),o(!0);const c=`${t} 的本地 ${w(r)} 安装版本为 ${w(a)} 最新是 ${me(i.onlineVersion)} `;ue.latestDependence.push(t),""===i.latestVersion?($e.log(g.info()+c),o(!0)):(ue.preReleaseDependence.push(t),$e.log(`${g.info()} ${c};最新预发布版本为 ${w(i.latestVersion)}`),o(!0))})()}));return Promise.all(i).then(()=>{$e.destroyed()})}async function he(e){const{msg:n,list:t,type:r,copy:s}=e,a=h[r];V(),V(a.reversed(n),!1),V(s?fe.reversed`已复制到剪切板 📋`:""),V(),V(`${a(ae)} ${b(se)}\n${function(e){if(!o(e)||e.some(e=>!i(e)))throw new TypeError("参数必须为字符串数组");return e.map((n,t)=>t%3==2&&t!==e.length-1?`${n} ${b(se)}\n`:n.concat(" ")).join("")}(t)}`),V(),s&&Y(`${ae} ${t.join(" ")}`.replace(_(),""))}function ve(e){return`${k(e)}@${de`latest`}`}function be(e,n){return`${D(e)}@${D.random(n)}`}async function je(){const{local:e,preReleaseDependence:n,latestDependence:t,dependenceList:o,timeoutDependence:i}=ue;if(s(e))return;const{dependencies:r,devDependencies:a}=e;if(ue.binning(r),ue.binning(a,!0),await ye(),0===n.length&&0===t.length&&0===i.length)return V(fe`看起来似乎没有依赖版本差异`);if(0===n.length&&0===t.length)return V(m`看起来网络不太好讷,所有的包线上版本的请求都出错了。或者是还没有执行 npm install 呐`);V(h.brightGreen`\n版本差异的依赖为:\n`);const c=[...t,...n];var l;new B({header:[j("包名"),{content:"发布时间",color:"#f26"},w`最新版本`],body:[...c.map(e=>{const{type:n,latestVersion:t,time:i,onlineVersion:r}=o[e];return["dependencies"===n?k(e):D(e),$(i),t||D(r)]})]})(),V(h.brightRed(`\n目前仅关注版本号是否为最新 ${h.brightMagenta("latest")}`)),V(`使用 ${ae} 命令安装更新\n`),i.length>0&&(l=m`有一些包没有返回结果,请注意:`,V(v(l)),new B([...i.map(e=>[e])])());const p=[...t.filter(e=>!1===n.includes(e)).map(e=>h.bold(e).concat("@latest")),...n.map(e=>be(e,o[e].tag))],u=t.map(e=>ve(e)),d=[...t.map(e=>ve(e)),...n.filter(e=>!1===t.includes(e)).map(e=>be(e,o[e].tag))],g=p.length<n.length+t.length,f=n.length>0,y=t.length>0;f&&(g&&await he({msg:"‼️ 预发布版本优先:",list:p,type:"brightRed"}),await he({msg:"⚠️ latest 版本优先:",list:d,type:"brightMagenta",copy:!y})),y&&await he({msg:"🎉 最佳安装:",list:u,type:"brightGreen",copy:!0})}async function ke(e){ue.registry=e[0]?.toString()||void 0,await async function(){const e=T("package.json","file");if(t(e))return void Q.warn("未找到当前包的 package.json 文件的位置");const n=x(L(e,"package.json"));if(s(n))return void Q.error("未找到当前包的 package.json 文件,该事件发生的概率极低");const o=n.name||"",i=await N(o,ue.registry,9800);ue.local=n,ue.online=i.data}();const{local:n,online:o}=ue,i=n?.version||"",r=o?.version||"";if(s(n))return Q("未找到包 package.json 文件退出"),V(ge("未找到当前包 package.json"));const a=ge(`当前包本地版本为: ${i}`);if(o){V(a);const e=" ".repeat(6);V(me(`${e}线上版本为:${r}@latest`));const n=new Date(o&&o.time.modified||"").toLocaleString();ee.INFO(`最后的发布时间为: ${n.toString()}`),F()}await je()}async function De(e){e["--upDependencies"]?await ce(!0):e["--diff"]?await ke(e["--diff"]):ee.help("package")}async function Se(e){const n=T("package.json","file",process.cwd());if(null==n)return!0;const t=x(L(n,"package.json"));if(s(t)||!t.version)return!0;const o=t.version;await O({code:`git tag -a v${o} -m '${e}'`,cwd:n}),await O({code:"git push origin --tag",cwd:n})}async function Ve(e){e.commit?await async function(e="版本维护",n=!1){const t=T(".git","directory");if(null==t)return V(f("#ff0")("not a git repository(当前目录非 git 储存库)"));const o=await O({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);const i=await O({code:"git status",cwd:t});if(!/nothing to commit, working tree clean/.test(i.data||"")){const o=await O({code:"git add .",cwd:t});if(!o.success)return null!=console.log(o.error);""==e.trim()&&(e=await ee.question({text:"请输入提交信息"})??"");const i=await O({code:`git commit -m "${e}"`,cwd:t});return i.success?(i.error&&console.log(i.error),await O({code:"git push",cwd:t}),n&&await Se(e),!0):null!=console.log(i.error)}return!1}(e.commit.join(" ")):e.merge?await async function(e){if(a(e)){const n=await O("git branch -a");console.log(n.data),e=await ee.question({text:"请输入要合并分支的名称"})??""}if(a(e))return ee.ERROR("没有获取到要合并的分支");const n=await ee.selection({data:[{label:"正常快进合并",value:""},{label:"非快进合并 (--no-ff)",value:"--no-ff"},{label:"多提交记录合并为一条 (--squash)",value:"--squash",tip:"适用于将众多小的提交合并成一个提交"}]});t(n)?ee.ERROR("您选择退出合并"):await O(`git merge ${e} ${n}`)}(e.merge.join("")):e.tag?await async function(){const e=await ee.question({text:"请输入待标记的信息"});t(e)||await Se(e)}():ee.help("git")}const Re=["A","AAAA","ANY","CAA","CNAME","MX","NAPTR","NS","PTR","SOA","SRV","TLSA","TXT"],Oe={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=[],t(e)||e.forEach(e=>{const n=e["--domain"];!t(n)&&n.length>0&&(this.domain=n[0].toString());const o=e["--port"];!t(o)&&o.length>0&&(this.port=Number(o[0]));const i=e["--rrtype"];if(!t(i)&&i.length>0){const e=H(Re,i);e.length>0&&(this.rrtype=e)}})},noCopy:!0};async function Ae(e){return Promise.all(e.map(e=>async function(e,n=3e3){const{ips:t,port:o}=Oe;if(l(t[e]))return Z||$e.log(`${e} 联通性已校验过 ${t[e]?"🔥":"⛓️‍💥"}`),Promise.resolve(null);t[e]=!1,Z||$e.log(`校验 ${e} 的联通性`);return new Promise(i=>{const r=new z.Socket,s=(n=!1)=>{t[e]=n,r.destroy(),i(null)};r.setTimeout(n),r.on("connect",()=>s(!0)),r.on("timeout",()=>s()),r.on("error",()=>s()),Z||$e.log("测试的接口为:",o),r.connect(o,e)})}(e)))}async function Ee(e="1.1.1.1"){const{domain:n}=Oe;try{const t=await async function(e,n){return new Promise(t=>{const o=new W;$e.run(`使用 ${n} 获取 ${e} 的 ip`),o.setServers([n]),o.resolve4(e,(o,i)=>{if(o)return Z||$e.run(`使用 ${n} 获取 ${e} 的 ip 出错`),t(null);Z||$e.log(`使用 ${n} 获取 ${e} 的 ip 值为 ${i.join(" --- ")}`),t(i)})})}(n,e);if(s(t))return Z||$e.log(`${e} 获取 ${n} 的 ip 失败`),0;const o=(await Ae(t)).filter(e=>!s(e));return p(o)?0:($e.destroyed(),V(),V(S`DNS: ${e}`),V(),o.forEach(({ip:e,isAlive:n})=>{const t=n?`${w(e)} ${ge`->`} ✅`:`${fe(e)} ${m`⛓️‍💥`} ❌`;V(v(t))}),3+o.length)}catch(e){return Z||$e.log("'获取 ip 错误'",e),0}}async function Pe(){const{domain:e,ips:n}=Oe;$e.run(`正在获取本地的 ${e} 的 ip 地址`);try{const t=await async function(e){return new Promise(n=>{J.lookup(e,{all:!0,family:4},(t,o)=>{if(t)return Q.error(`获取本地 ${e} 的 ip 出错`,t),void n(null);Z||$e.log(`获取本地 ${e} 的 ip 值为 ${o.join(" --- ")}`),n(o.map(e=>e.address))})})}(e);if(s(t))return;await Ae(t),r(n)||function(e){const{ips:n}=Oe;V(ge`本地配置 ${e} 的 ip 地址及联通性为:\n`),Object.keys(n).forEach(e=>{const t=n[e];t&&(Oe.noCopy=!1),V(j`- ${e}`,!1),V(t?ge` -> ✅`:fe` -> ❌`)}),V()}(e)}catch(e){Q.error(e)}}async function Ce(e){Oe.reset(e.options),await Pe(),await async function(){const{domain:e,dnsServers:n}=Oe;$e.log(`${e} ip 列表:`);const t=n.map(e=>Ee(e)),o=await Promise.all(t);Z&&(C(o.reduce((e,n)=>e+n,0)+1),q(!0))}(),$e.destroyed();const{ips:n}=Oe;Object.keys(n).length>0?await async function(){const{domain:e,ips:n,port:t}=Oe;await U(`${h.brightMagenta`${e}`} 域名解析结果:`),V();let o=Oe.noCopy;for(const t in n)if(Object.prototype.hasOwnProperty.call(n,t)){const i=n[t],r=i?`${w`- ${t.padEnd(16)}`} ${ge`->`} ✅${o?j`(已复制)`:""}`:`${fe`- ${t.padEnd(16)}`} ${m`⛓️‍💥`} ❌`;V(r),i&&o&&(Y(`${t} ${e}`),o=!1)}V(),await U(m.italic.dim`${e} 联通性接口判断为 ${t.toString()}`),V()}():await async function(){const{domain:e,port:n}=Oe;await U(`\n找不到 ${m(e)} 的服务器 IP 地址 ${fe`测试使用 ${n.toString()} 端口`}\n`)}()}const qe=ee.args.$arrMap;Q(qe),Q(ee.args.$original),ee.args.$isVoid?(Q("没有匹配到子命令,打印帮助信息并退出"),ee.help(),ee.end()):p(ee.args.$only)&&(console.log(`${ee.args.$nomatch.map(e=>$(e)).join("、")} 不是有效的参数`),ee.end());try{await async function e(){if(0===qe.length)return;const n=qe.shift();if(t(n))return await e();n.remove?(Q("执行文件移除"),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||V(h.brightCyan`当前系统为: ${R?"windows":"linux/mac"}`),0==n.length&&(Q.warn("待删除列表",n),V(h.random`没有待清理的文件/文件夹`));n.length;){let e=n.pop();e=void 0===e?"undefined":e.toString(),await re(e)}}(n.remove)):n.clearScreen||n.clearTerminal?(Q("执行清屏"),await async function(){G()?(Q("执行第一遍清理"),await O({code:R?"cls":"clear",printLog:!1}),Q("执行第二遍清理"),I("3J"),I("c",!1),C(1/0),q(!0)):(Q.warn("当前系统不支持 TTY"),V("当前环境不支持 "))}()):n.git?(Q("执行 git 相关命令"),await async function(e){if(c(e)&&(e={value:[]}),t(e.options)||0===e.options.length)return Q.warn("没有配置项,直接返回的帮助文档"),ee.help("git");const n=e.options;for(let e=0,t=n.length;e<t;e++)Q("本次执行",n[e]),await Ve(n[e])}(n.git)):n.package?(Q("执行 package 相关命令"),await async function(e){if(t(e.options)||0==e.options.length)return Q.warn("没有参数输入"),ee.help("package");const n=e.options;for(let e=0,t=n.length;e<t;e++)await De(n[e])}(n.package)):n.update?(Q("执行 update 相关命令"),await async function(e){if(t(e.options)||0==e.options.length)return Q.warn("没有匹配到选项,自动抛出帮助文档"),ee.help("update");const n=e.options;le.log=!n.some(e=>e["--ignore"]);for(let e=0,t=n.length;e<t;e++)await pe(n[e])}(n.update)):n.dns?(Q("执行 dns 相关的命令"),await Ce(n.dns)):n.runOtherCode&&(Q("执行运行其他命令"),await async function(e){const{value:n}=e;if(t(n)||u(n.length))return;for(const e in n){const t=n[e].toString(),o=t.indexOf("=");if(-1===o)break;if(0===o){ee.ERROR(`未识别 "${t}" 且已移除该项 ❌`),n[e]="";continue}const[i,r]=[t.slice(0,o),t.slice(o+1)||"true"];process.env[i]=r,ee.SUCCESS(`设置环境变量 ${i}=${r} ✅`),n[e]=""}const o=n.join(" ").trim();Q("执行代码",o);const i=K(o,[],{stdio:"inherit",env:process.env,shell:!0});i.on("close",e=>e),i.on("error",e=>e),i.on("exit",e=>e)}(n.runOtherCode));try{await e()}catch(e){Q.error("执行 run 报错",e)}}(),F(" 终结分割线 ",!0)}catch(e){Q.error("执行 run 报错",e)}