@quiteer/scripts 0.0.6 → 0.0.7
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/dist/index.mjs +151 -23
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import cac from "cac";
|
|
3
3
|
import { bgGreen, bgRed, blue, gray, green, lightBlue, lightCyan, lightGreen, red, white, yellow } from "kolorist";
|
|
4
|
-
import { access, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { access, readFile, readdir, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import process from "node:process";
|
|
7
7
|
import { execa } from "execa";
|
|
@@ -12,7 +12,7 @@ import enquirer from "enquirer";
|
|
|
12
12
|
import { versionBump } from "bumpp";
|
|
13
13
|
|
|
14
14
|
//#region package.json
|
|
15
|
-
var version = "0.0.
|
|
15
|
+
var version = "0.0.6";
|
|
16
16
|
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region src/locales/changelog.ts
|
|
@@ -213,18 +213,40 @@ async function getCommitsInRange(range) {
|
|
|
213
213
|
])).split("\n").filter(Boolean).map(parseCommit).filter((x) => !!x);
|
|
214
214
|
}
|
|
215
215
|
/**
|
|
216
|
-
* 读取 package homepage
|
|
217
|
-
* @returns
|
|
216
|
+
* 读取 package homepage(若为 GitHub Pages URL,转换为仓库地址)
|
|
217
|
+
* @returns 可能的仓库主页 URL
|
|
218
218
|
*/
|
|
219
219
|
async function readHomepage() {
|
|
220
220
|
try {
|
|
221
221
|
const content = await readFile(path.join(process.cwd(), "scripts", "package.json"), "utf8");
|
|
222
222
|
const json = JSON.parse(content);
|
|
223
|
-
|
|
223
|
+
const home = typeof json.homepage === "string" ? json.homepage.replace(/\/$/, "") : void 0;
|
|
224
|
+
if (!home) return void 0;
|
|
225
|
+
const m = home.match(/^https:\/\/([\w-]+)\.github\.io\/([\w.-]+)\//);
|
|
226
|
+
if (m) return `https://github.com/${m[1]}/${m[2]}`;
|
|
227
|
+
return home;
|
|
224
228
|
} catch {
|
|
225
229
|
return;
|
|
226
230
|
}
|
|
227
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* 获取 Web 版仓库地址(优先使用 git remote,回退到 homepage 推断)
|
|
234
|
+
* @returns 仓库 Web URL(如 https://github.com/<owner>/<repo>)
|
|
235
|
+
*/
|
|
236
|
+
async function getRepoWebUrl() {
|
|
237
|
+
try {
|
|
238
|
+
const remote = await execCommand("git", [
|
|
239
|
+
"remote",
|
|
240
|
+
"get-url",
|
|
241
|
+
"origin"
|
|
242
|
+
]);
|
|
243
|
+
if (remote) {
|
|
244
|
+
if (remote.startsWith("git@github.com:")) return `https://github.com/${remote.replace("git@github.com:", "").replace(/\.git$/, "")}`;
|
|
245
|
+
if (remote.startsWith("https://github.com/")) return `https://github.com/${remote.replace("https://github.com/", "").replace(/\.git$/, "")}`;
|
|
246
|
+
}
|
|
247
|
+
} catch {}
|
|
248
|
+
return await readHomepage();
|
|
249
|
+
}
|
|
228
250
|
async function prependFile(filePath, content) {
|
|
229
251
|
try {
|
|
230
252
|
await access(filePath);
|
|
@@ -313,9 +335,18 @@ function formatSection(title, date, items, repoUrl, lang) {
|
|
|
313
335
|
lines.push(`- ${typeIcon} ${typeLabel} ${scopeFmt ? `${scopeFmt}: ` : ""}${it.description}`);
|
|
314
336
|
lines.push(` > **🕒 ${time}** · \`➕${it.added}\` / \`➖${it.deleted}\``);
|
|
315
337
|
lines.push(` > \`👤 ${it.author}\` ${email}${link}`);
|
|
316
|
-
for (const f of it.filesAdded ?? [])
|
|
317
|
-
|
|
318
|
-
|
|
338
|
+
for (const f of it.filesAdded ?? []) {
|
|
339
|
+
const url = repoUrl ? `${repoUrl}/blob/${it.hash}/${f}` : void 0;
|
|
340
|
+
lines.push(url ? ` - ➕ [\`${f}\`](${url})` : ` - ➕ \`${f}\``);
|
|
341
|
+
}
|
|
342
|
+
for (const f of it.filesModified ?? []) {
|
|
343
|
+
const url = repoUrl ? `${repoUrl}/blob/${it.hash}/${f}` : void 0;
|
|
344
|
+
lines.push(url ? ` - ✏️ [\`${f}\`](${url})` : ` - ✏️ \`${f}\``);
|
|
345
|
+
}
|
|
346
|
+
for (const f of it.filesDeleted ?? []) {
|
|
347
|
+
const url = repoUrl ? `${repoUrl}/commit/${it.hash}` : void 0;
|
|
348
|
+
lines.push(url ? ` - 🗑️ [~~\`${f}\`~~](${url})` : ` - 🗑️ ~~\`${f}\`~~`);
|
|
349
|
+
}
|
|
319
350
|
}
|
|
320
351
|
lines.push("");
|
|
321
352
|
}
|
|
@@ -342,9 +373,18 @@ function formatTimeline(items, repoUrl) {
|
|
|
342
373
|
lines.push(`- ${typeIcon} ${typeLabel} ${scopeFmt ? `${scopeFmt}: ` : ""}${it.description}`);
|
|
343
374
|
lines.push(` > **🕒 ${time}** · \`➕${it.added}\` / \`➖${it.deleted}\``);
|
|
344
375
|
lines.push(` > \`👤 ${it.author}\` ${email}${link}`);
|
|
345
|
-
for (const f of it.filesAdded ?? [])
|
|
346
|
-
|
|
347
|
-
|
|
376
|
+
for (const f of it.filesAdded ?? []) {
|
|
377
|
+
const url = repoUrl ? `${repoUrl}/blob/${it.hash}/${f}` : void 0;
|
|
378
|
+
lines.push(url ? ` - ➕ [\`${f}\`](${url})` : ` - ➕ \`${f}\``);
|
|
379
|
+
}
|
|
380
|
+
for (const f of it.filesModified ?? []) {
|
|
381
|
+
const url = repoUrl ? `${repoUrl}/blob/${it.hash}/${f}` : void 0;
|
|
382
|
+
lines.push(url ? ` - ✏️ [\`${f}\`](${url})` : ` - ✏️ \`${f}\``);
|
|
383
|
+
}
|
|
384
|
+
for (const f of it.filesDeleted ?? []) {
|
|
385
|
+
const url = repoUrl ? `${repoUrl}/commit/${it.hash}` : void 0;
|
|
386
|
+
lines.push(url ? ` - 🗑️ [~~\`${f}\`~~](${url})` : ` - 🗑️ ~~\`${f}\`~~`);
|
|
387
|
+
}
|
|
348
388
|
}
|
|
349
389
|
lines.push("");
|
|
350
390
|
}
|
|
@@ -361,7 +401,7 @@ function formatTimeline(items, repoUrl) {
|
|
|
361
401
|
*/
|
|
362
402
|
async function generateChangelogFiles(options) {
|
|
363
403
|
const repoRoot = await execCommand("git", ["rev-parse", "--show-toplevel"]);
|
|
364
|
-
const homepage = await
|
|
404
|
+
const homepage = await getRepoWebUrl();
|
|
365
405
|
const root = await getRootCommit();
|
|
366
406
|
const title = "全部历史";
|
|
367
407
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -435,7 +475,18 @@ const defaultOptions = {
|
|
|
435
475
|
timelineOutput: "CHANGELOG_TIMELINE.md",
|
|
436
476
|
formats: "both"
|
|
437
477
|
},
|
|
438
|
-
gitCommit: { add: true }
|
|
478
|
+
gitCommit: { add: true },
|
|
479
|
+
dirTree: {
|
|
480
|
+
md: false,
|
|
481
|
+
output: "DIRECTORY_TREE.md",
|
|
482
|
+
ignore: [
|
|
483
|
+
"node_modules",
|
|
484
|
+
".git",
|
|
485
|
+
"dist",
|
|
486
|
+
"out",
|
|
487
|
+
"logs"
|
|
488
|
+
]
|
|
489
|
+
}
|
|
439
490
|
};
|
|
440
491
|
async function loadCliOptions(overrides, cwd = process.cwd()) {
|
|
441
492
|
const { config } = await loadConfig({
|
|
@@ -786,20 +837,16 @@ async function release(tagPrefix) {
|
|
|
786
837
|
`chore(projects): release ${tagName}`,
|
|
787
838
|
tagName
|
|
788
839
|
]);
|
|
840
|
+
const cli = await loadCliOptions();
|
|
841
|
+
const lang = cli.lang;
|
|
789
842
|
await generateChangelogFiles({
|
|
790
|
-
lang
|
|
791
|
-
format:
|
|
792
|
-
groupOutput:
|
|
793
|
-
timelineOutput:
|
|
843
|
+
lang,
|
|
844
|
+
format: cli.changelog.formats,
|
|
845
|
+
groupOutput: cli.changelog.groupOutput,
|
|
846
|
+
timelineOutput: cli.changelog.timelineOutput
|
|
794
847
|
});
|
|
795
848
|
}
|
|
796
849
|
|
|
797
|
-
//#endregion
|
|
798
|
-
//#region src/commands/update-pkg.ts
|
|
799
|
-
async function updatePkg(args = ["--deep", "-u"]) {
|
|
800
|
-
execCommand("npx", ["npm-check-updates", ...args], { stdio: "inherit" });
|
|
801
|
-
}
|
|
802
|
-
|
|
803
850
|
//#endregion
|
|
804
851
|
//#region src/commands/self-update.ts
|
|
805
852
|
/**
|
|
@@ -847,6 +894,80 @@ async function selfUpdate() {
|
|
|
847
894
|
}
|
|
848
895
|
}
|
|
849
896
|
|
|
897
|
+
//#endregion
|
|
898
|
+
//#region src/commands/update-pkg.ts
|
|
899
|
+
async function updatePkg(args = ["--deep", "-u"]) {
|
|
900
|
+
execCommand("npx", ["npm-check-updates", ...args], { stdio: "inherit" });
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
//#endregion
|
|
904
|
+
//#region src/commands/dir-tree.ts
|
|
905
|
+
/**
|
|
906
|
+
* 生成目录树结构字符串(ASCII Tree)
|
|
907
|
+
* - 默认忽略常见目录:node_modules、.git、dist、out、logs
|
|
908
|
+
* @param root 起始目录,默认为当前工作目录
|
|
909
|
+
* @returns 目录树字符串
|
|
910
|
+
*/
|
|
911
|
+
async function buildDirTree(root = process.cwd(), ignoreList) {
|
|
912
|
+
const ignore = new Set(ignoreList ?? [
|
|
913
|
+
"node_modules",
|
|
914
|
+
".git",
|
|
915
|
+
"dist",
|
|
916
|
+
"out",
|
|
917
|
+
"logs"
|
|
918
|
+
]);
|
|
919
|
+
async function walk(dir, prefix = "") {
|
|
920
|
+
const items = (await readdir(dir, { withFileTypes: true })).filter((e) => !ignore.has(e.name)).map((e) => ({
|
|
921
|
+
name: e.name,
|
|
922
|
+
isDir: e.isDirectory()
|
|
923
|
+
})).sort((a, b) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1);
|
|
924
|
+
const lines = [];
|
|
925
|
+
const lastIdx = items.length - 1;
|
|
926
|
+
for (let i = 0; i < items.length; i++) {
|
|
927
|
+
const it = items[i];
|
|
928
|
+
const isLast = i === lastIdx;
|
|
929
|
+
const connector = isLast ? "└── " : "├── ";
|
|
930
|
+
const nextPrefix = prefix + (isLast ? " " : "│ ");
|
|
931
|
+
lines.push(`${prefix}${connector}${it.name}`);
|
|
932
|
+
if (it.isDir) {
|
|
933
|
+
const sub = await walk(path.join(dir, it.name), nextPrefix);
|
|
934
|
+
lines.push(...sub);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return lines;
|
|
938
|
+
}
|
|
939
|
+
const title = path.basename(root);
|
|
940
|
+
const content = await walk(root);
|
|
941
|
+
return [`|-- ${title}`, ...content].join("\n");
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* 根据目录树内容生成 Markdown 并写入文件
|
|
945
|
+
* - 使用代码块包裹,便于阅读
|
|
946
|
+
* @param tree 目录树字符串
|
|
947
|
+
* @param outfile 输出文件路径,默认 `DIRECTORY_TREE.md`
|
|
948
|
+
*/
|
|
949
|
+
async function writeDirTreeMd(tree, outfile = "DIRECTORY_TREE.md") {
|
|
950
|
+
const md = `## 目录结构
|
|
951
|
+
|
|
952
|
+
\`\`\`text\n${tree}\n\`\`\`\n`;
|
|
953
|
+
await writeFile(path.join(process.cwd(), outfile), md, "utf8");
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* 生成并输出目录结构,支持可选生成 Markdown 文件
|
|
957
|
+
* - 默认只在控制台输出
|
|
958
|
+
* @param dir 目标目录,默认当前工作目录
|
|
959
|
+
* @param md 是否生成 Markdown 文件,默认 false
|
|
960
|
+
*/
|
|
961
|
+
async function generateDirTree(dir, opts) {
|
|
962
|
+
const tree = await buildDirTree(dir ? path.resolve(process.cwd(), dir) : process.cwd(), opts?.ignore);
|
|
963
|
+
console.info("quiteer-script :>>", gray(`\n${tree}\n`));
|
|
964
|
+
if (opts?.md) {
|
|
965
|
+
const out = opts?.output || "DIRECTORY_TREE.md";
|
|
966
|
+
await writeDirTreeMd(tree, out);
|
|
967
|
+
console.info(lightCyan("quiteer-script :>>"), lightGreen(`已生成 Markdown: ${lightBlue(out)}`));
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
850
971
|
//#endregion
|
|
851
972
|
//#region src/index.ts
|
|
852
973
|
async function setupCli() {
|
|
@@ -878,6 +999,13 @@ async function setupCli() {
|
|
|
878
999
|
cli.command("self-update", `${bgGreen(white("便捷命令"))} ${lightCyan("qui su")} 自更新:检查并更新 @quiteer/scripts 到最新版本`).alias("su").action(async () => {
|
|
879
1000
|
await selfUpdate();
|
|
880
1001
|
});
|
|
1002
|
+
cli.command("tree [path]", `${bgGreen(white("便捷命令"))} ${lightBlue("qui t")} 生成当前目录结构(默认控制台输出),可选生成 Markdown`).alias("t").option("--md", "是否生成 Markdown 文件", { default: cliOptions.dirTree.md }).action(async (path$1, args) => {
|
|
1003
|
+
await generateDirTree(path$1, {
|
|
1004
|
+
md: !!args?.md,
|
|
1005
|
+
output: cliOptions.dirTree.output,
|
|
1006
|
+
ignore: cliOptions.dirTree.ignore
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
881
1009
|
cli.command("git-commit", `${bgGreen(white("便捷命令"))} ${lightBlue("qui gc")} git 提交前后的操作和规范等`).alias("gc").option("--add", "添加所有变更文件到暂存区", { default: cliOptions.gitCommit.add }).option("-l ,--lang", "校验提交信息的语言", { default: cliOptions.lang }).action(async (args) => {
|
|
882
1010
|
if (args?.add) await gitCommitAdd();
|
|
883
1011
|
await gitCommit(args?.lang);
|