@soybeanjs/cli 0.5.1 → 0.5.3

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.cjs CHANGED
@@ -12,10 +12,7 @@ const promises = require('fs/promises');
12
12
  const EE = require('events');
13
13
  const Stream = require('stream');
14
14
  const stringdecoder = require('string_decoder');
15
- const cliProgress = require('cli-progress');
16
- const ofetch = require('ofetch');
17
- const dayjs = require('dayjs');
18
- const convertGitmoji = require('convert-gitmoji');
15
+ const changelog = require('@soybeanjs/changelog');
19
16
  const versionBumpp = require('bumpp');
20
17
 
21
18
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
@@ -38,55 +35,15 @@ const actualFS__namespace = /*#__PURE__*/_interopNamespaceCompat(actualFS);
38
35
  const EE__default = /*#__PURE__*/_interopDefaultCompat(EE);
39
36
  const Stream__default = /*#__PURE__*/_interopDefaultCompat(Stream);
40
37
  const stringdecoder__default = /*#__PURE__*/_interopDefaultCompat(stringdecoder);
41
- const cliProgress__default = /*#__PURE__*/_interopDefaultCompat(cliProgress);
42
- const dayjs__default = /*#__PURE__*/_interopDefaultCompat(dayjs);
43
38
  const versionBumpp__default = /*#__PURE__*/_interopDefaultCompat(versionBumpp);
44
39
 
45
- const version = "0.5.1";
40
+ const version = "0.5.3";
46
41
 
47
42
  async function execCommand(cmd, args, options) {
48
43
  const { execa } = await import('execa');
49
44
  const res = await execa(cmd, args, options);
50
45
  return res?.stdout?.trim() || "";
51
46
  }
52
- function notNullish(v) {
53
- return v !== null && v !== void 0;
54
- }
55
- function partition(array, ...filters) {
56
- const result = new Array(filters.length + 1).fill(null).map(() => []);
57
- array.forEach((e, idx, arr) => {
58
- let i = 0;
59
- for (const filter of filters) {
60
- if (filter(e, idx, arr)) {
61
- result[i].push(e);
62
- return;
63
- }
64
- i += 1;
65
- }
66
- result[i].push(e);
67
- });
68
- return result;
69
- }
70
- function groupBy(items, key, groups = {}) {
71
- for (const item of items) {
72
- const v = item[key];
73
- groups[v] = groups[v] || [];
74
- groups[v].push(item);
75
- }
76
- return groups;
77
- }
78
- function capitalize(str) {
79
- return str.charAt(0).toUpperCase() + str.slice(1);
80
- }
81
- function join(array, glue = ", ", finalGlue = " and ") {
82
- if (!array || array.length === 0)
83
- return "";
84
- if (array.length === 1)
85
- return array[0];
86
- if (array.length === 2)
87
- return array.join(finalGlue);
88
- return `${array.slice(0, -1).join(glue)}${finalGlue}${array.slice(-1)}`;
89
- }
90
47
 
91
48
  const gitCommitTypes = [
92
49
  { value: "init", title: "init: \u9879\u76EE\u521D\u59CB\u5316" },
@@ -145,11 +102,9 @@ async function gitCommit() {
145
102
  }
146
103
 
147
104
  function gitCommitVerify() {
148
- const gitMsgPath = "./.git/COMMIT_EDITMSG";
105
+ const gitMsgPath = `${process.cwd()}/.git/COMMIT_EDITMSG`;
149
106
  const commitMsg = actualFS.readFileSync(gitMsgPath, "utf-8").trim();
150
- const types = gitCommitTypes.map((item) => item.value).join("|");
151
- const scopes = gitCommitScopes.map((item) => item.value).join("|");
152
- const REG_EXP = new RegExp(`(${types})!*(\\((${scopes})\\))*!*:\\s.{1,100}`);
107
+ const REG_EXP = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
153
108
  if (!REG_EXP.test(commitMsg)) {
154
109
  throw new Error(
155
110
  `${kolorist.bgRed(" ERROR ")} ${kolorist.red("Git\u63D0\u4EA4\u4FE1\u606F\u4E0D\u7B26\u5408 Angular \u89C4\u8303!\n\n")}${kolorist.green(
@@ -7479,10 +7434,10 @@ async function initSimpleGitHooks() {
7479
7434
  const huskyDir = `${process.cwd()}/.husky`;
7480
7435
  const existHusky = actualFS.existsSync(huskyDir);
7481
7436
  if (existHusky) {
7482
- await rimraf.rimraf(".husky");
7437
+ await rimraf.rimraf(huskyDir);
7483
7438
  await execCommand("git", ["config", "core.hooksPath", ".git/hooks/"], { stdio: "inherit" });
7484
7439
  }
7485
- await rimraf.rimraf(".git/hooks");
7440
+ await rimraf.rimraf(`${process.cwd()}/.git/hooks`);
7486
7441
  await execCommand("npx", ["simple-git-hooks"], { stdio: "inherit" });
7487
7442
  }
7488
7443
 
@@ -7525,524 +7480,12 @@ function lintStaged() {
7525
7480
  execCommand("npx", ["lint-staged", "--config", "@soybeanjs/cli/lint-staged"], { stdio: "inherit" });
7526
7481
  }
7527
7482
 
7528
- const VERSION_REG = /v\d+\.\d+\.\d+(-(beta|alpha)\.\d+)?/;
7529
- const VERSION_REG_OF_MARKDOWN = /## \[v\d+\.\d+\.\d+(-(beta|alpha)\.\d+)?]/g;
7530
-
7531
- async function getTotalGitTags() {
7532
- const tagStr = await execCommand("git", ["--no-pager", "tag", "-l", "--sort=creatordate"]);
7533
- const tags = tagStr.split("\n");
7534
- return tags;
7535
- }
7536
- async function getTagDateMap() {
7537
- const tagDateStr = await execCommand("git", [
7538
- "--no-pager",
7539
- "log",
7540
- "--tags",
7541
- "--simplify-by-decoration",
7542
- "--pretty=format:%ci %d"
7543
- ]);
7544
- const TAG_MARK = "tag: ";
7545
- const map = /* @__PURE__ */ new Map();
7546
- const dates = tagDateStr.split("\n").filter((item) => item.includes(TAG_MARK));
7547
- dates.forEach((item) => {
7548
- const [dateStr, tagStr] = item.split(TAG_MARK);
7549
- const date = dayjs__default(dateStr).format("YYYY-MM-DD");
7550
- const tag = tagStr.match(VERSION_REG)?.[0];
7551
- if (tag && date) {
7552
- map.set(tag.trim(), date);
7553
- }
7554
- });
7555
- return map;
7556
- }
7557
- function getFromToTags(tags) {
7558
- const result = [];
7559
- tags.forEach((tag, index) => {
7560
- if (index < tags.length - 1) {
7561
- result.push({ from: tag, to: tags[index + 1] });
7562
- }
7563
- });
7564
- return result;
7565
- }
7566
- async function getLastGitTag(delta = 0) {
7567
- const tags = await getTotalGitTags();
7568
- return tags[tags.length + delta - 1];
7569
- }
7570
- async function getGitMainBranchName() {
7571
- const main = await execCommand("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
7572
- return main;
7573
- }
7574
- async function getCurrentGitBranch() {
7575
- const tag = await execCommand("git", ["tag", "--points-at", "HEAD"]);
7576
- const main = getGitMainBranchName();
7577
- return tag || main;
7578
- }
7579
- async function getGitHubRepo() {
7580
- const url = await execCommand("git", ["config", "--get", "remote.origin.url"]);
7581
- const match = url.match(/github\.com[/:]([\w\d._-]+?)\/([\w\d._-]+?)(\.git)?$/i);
7582
- if (!match) {
7583
- throw new Error(`Can not parse GitHub repo from url ${url}`);
7584
- }
7585
- return `${match[1]}/${match[2]}`;
7586
- }
7587
- function isPrerelease(version) {
7588
- const REG = /^[^.]*[\d.]+$/;
7589
- return !REG.test(version);
7590
- }
7591
- function getFirstGitCommit() {
7592
- return execCommand("git", ["rev-list", "--max-parents=0", "HEAD"]);
7593
- }
7594
- async function getGitDiff(from, to = "HEAD") {
7595
- const rawGit = await execCommand("git", [
7596
- "--no-pager",
7597
- "log",
7598
- `${from ? `${from}...` : ""}${to}`,
7599
- '--pretty="----%n%s|%h|%an|%ae%n%b"',
7600
- "--name-status"
7601
- ]);
7602
- const rwaGitLines = rawGit.split("----\n").splice(1);
7603
- const gitCommits = rwaGitLines.map((line) => {
7604
- const [firstLine, ...body] = line.split("\n");
7605
- const [message, shortHash, authorName, authorEmail] = firstLine.split("|");
7606
- const gitCommmit = {
7607
- message,
7608
- shortHash,
7609
- author: { name: authorName, email: authorEmail },
7610
- body: body.join("\n")
7611
- };
7612
- return gitCommmit;
7613
- });
7614
- return gitCommits;
7615
- }
7616
- function parseGitCommit(commit, scopeMap) {
7617
- const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
7618
- const CoAuthoredByRegex = /co-authored-by:\s*(?<name>.+)(<(?<email>.+)>)/gim;
7619
- const PullRequestRE = /\([a-z]*(#\d+)\s*\)/gm;
7620
- const IssueRE = /(#\d+)/gm;
7621
- const match = commit.message.match(ConventionalCommitRegex);
7622
- if (!match?.groups) {
7623
- return null;
7624
- }
7625
- const type = match.groups.type;
7626
- let scope = match.groups.scope || "";
7627
- scope = scopeMap[scope] || scope;
7628
- const isBreaking = Boolean(match.groups.breaking);
7629
- let description = match.groups.description;
7630
- const references = [];
7631
- for (const m of description.matchAll(PullRequestRE)) {
7632
- references.push({ type: "pull-request", value: m[1] });
7633
- }
7634
- for (const m of description.matchAll(IssueRE)) {
7635
- if (!references.some((i) => i.value === m[1])) {
7636
- references.push({ type: "issue", value: m[1] });
7637
- }
7638
- }
7639
- references.push({ value: commit.shortHash, type: "hash" });
7640
- description = description.replace(PullRequestRE, "").trim();
7641
- const authors = [commit.author];
7642
- const matchs = commit.body.matchAll(CoAuthoredByRegex);
7643
- for (const $match of matchs) {
7644
- const { name = "", email = "" } = $match.groups || {};
7645
- const author = {
7646
- name: name.trim(),
7647
- email: email.trim()
7648
- };
7649
- authors.push(author);
7650
- }
7651
- return {
7652
- ...commit,
7653
- authors,
7654
- resolvedAuthors: [],
7655
- description,
7656
- type,
7657
- scope,
7658
- references,
7659
- isBreaking
7660
- };
7661
- }
7662
- async function getGitCommits(from, to = "HEAD", scopeMap = {}) {
7663
- const rwaGitCommits = await getGitDiff(from, to);
7664
- const commits = rwaGitCommits.map((commit) => parseGitCommit(commit, scopeMap)).filter(notNullish);
7665
- return commits;
7666
- }
7667
- function getHeaders(githubToken) {
7668
- return {
7669
- accept: "application/vnd.github.v3+json",
7670
- authorization: `token ${githubToken}`
7671
- };
7672
- }
7673
- async function getResolvedAuthorLogin(params) {
7674
- const { github, githubToken, commitHashes, email } = params;
7675
- let login = "";
7676
- try {
7677
- const data = await ofetch.ofetch(`https://ungh.cc/users/find/${email}`);
7678
- login = data?.user?.username || "";
7679
- } catch {
7680
- }
7681
- if (login) {
7682
- return login;
7683
- }
7684
- if (!githubToken) {
7685
- return login;
7686
- }
7687
- if (commitHashes.length) {
7688
- try {
7689
- const data = await ofetch.ofetch(`https://api.github.com/repos/${github}/commits/${commitHashes[0]}`, {
7690
- headers: getHeaders(githubToken)
7691
- });
7692
- login = data?.author?.login || "";
7693
- } catch (e) {
7694
- }
7695
- }
7696
- if (login) {
7697
- return login;
7698
- }
7699
- try {
7700
- const data = await ofetch.ofetch(`https://api.github.com/search/users?q=${encodeURIComponent(email)}`, {
7701
- headers: getHeaders(githubToken)
7702
- });
7703
- login = data.items[0].login;
7704
- } catch (e) {
7705
- }
7706
- return login;
7707
- }
7708
- async function getGitCommitsAndResolvedAuthors(commits, github, githubToken, resolvedLogins) {
7709
- const resultCommits = [];
7710
- const map = /* @__PURE__ */ new Map();
7711
- for (const commit of commits) {
7712
- const resolvedAuthors = [];
7713
- for (const [index, author] of Object.entries(commit.authors)) {
7714
- const { email, name } = author;
7715
- if (email && name) {
7716
- const commitHashes = [];
7717
- if (index === "0") {
7718
- commitHashes.push(commit.shortHash);
7719
- }
7720
- const resolvedAuthor = {
7721
- name,
7722
- email,
7723
- commits: commitHashes,
7724
- login: ""
7725
- };
7726
- if (!resolvedLogins?.has(email)) {
7727
- const login = await getResolvedAuthorLogin({ github, githubToken, commitHashes, email });
7728
- resolvedAuthor.login = login;
7729
- resolvedLogins?.set(email, login);
7730
- } else {
7731
- const login = resolvedLogins?.get(email) || "";
7732
- resolvedAuthor.login = login;
7733
- }
7734
- resolvedAuthors.push(resolvedAuthor);
7735
- if (!map.has(email)) {
7736
- map.set(email, resolvedAuthor);
7737
- }
7738
- }
7739
- }
7740
- const resultCommit = { ...commit, resolvedAuthors };
7741
- resultCommits.push(resultCommit);
7742
- }
7743
- return {
7744
- commits: resultCommits,
7745
- contributors: Array.from(map.values())
7746
- };
7747
- }
7748
-
7749
- function formatReferences(references, github, type) {
7750
- const refs = references.filter((i) => {
7751
- if (type === "issues")
7752
- return i.type === "issue" || i.type === "pull-request";
7753
- return i.type === "hash";
7754
- }).map((ref) => {
7755
- if (!github)
7756
- return ref.value;
7757
- if (ref.type === "pull-request" || ref.type === "issue")
7758
- return `https://github.com/${github}/issues/${ref.value.slice(1)}`;
7759
- return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${github}/commit/${ref.value})`;
7760
- });
7761
- const referencesString = join(refs).trim();
7762
- if (type === "issues")
7763
- return referencesString && `in ${referencesString}`;
7764
- return referencesString;
7765
- }
7766
- function formatLine(commit, options) {
7767
- const prRefs = formatReferences(commit.references, options.github, "issues");
7768
- const hashRefs = formatReferences(commit.references, options.github, "hash");
7769
- let authors = join([...new Set(commit.resolvedAuthors.map((i) => i.login ? `@${i.login}` : `**${i.name}**`))]).trim();
7770
- if (authors) {
7771
- authors = `by ${authors}`;
7772
- }
7773
- let refs = [authors, prRefs, hashRefs].filter((i) => i?.trim()).join(" ");
7774
- if (refs) {
7775
- refs = `&nbsp;-&nbsp; ${refs}`;
7776
- }
7777
- const description = options.capitalize ? capitalize(commit.description) : commit.description;
7778
- return [description, refs].filter((i) => i?.trim()).join(" ");
7779
- }
7780
- function formatTitle(name, options) {
7781
- const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
7782
- let formatName = name.trim();
7783
- if (!options.emoji) {
7784
- formatName = name.replace(emojisRE, "").trim();
7785
- }
7786
- return `### &nbsp;&nbsp;&nbsp;${formatName}`;
7787
- }
7788
- function formatSection(commits, sectionName, options) {
7789
- if (!commits.length)
7790
- return [];
7791
- const lines = ["", formatTitle(sectionName, options), ""];
7792
- const scopes = groupBy(commits, "scope");
7793
- let useScopeGroup = options.group;
7794
- if (!Object.entries(scopes).some(([k, v]) => k && v.length > 1))
7795
- useScopeGroup = false;
7796
- Object.keys(scopes).sort().forEach((scope) => {
7797
- let padding = "";
7798
- let prefix = "";
7799
- const scopeText = `**${options.scopeMap[scope] || scope}**`;
7800
- if (scope && (useScopeGroup === true || useScopeGroup === "multiple" && scopes[scope].length > 1)) {
7801
- lines.push(`- ${scopeText}:`);
7802
- padding = " ";
7803
- } else if (scope) {
7804
- prefix = `${scopeText}: `;
7805
- }
7806
- lines.push(...scopes[scope].reverse().map((commit) => `${padding}- ${prefix}${formatLine(commit, options)}`));
7807
- });
7808
- return lines;
7809
- }
7810
- function getUserGithub(userName) {
7811
- const githubUrl = `https://github.com/${userName}`;
7812
- return githubUrl;
7813
- }
7814
- function getGitUserAvatar(userName) {
7815
- const githubUrl = getUserGithub(userName);
7816
- const avatarUrl = `${githubUrl}.png?size=48`;
7817
- return avatarUrl;
7818
- }
7819
- function createContributorLine(contributors) {
7820
- let loginLine = "";
7821
- let unloginLine = "";
7822
- contributors.forEach((contributor, index) => {
7823
- const { name, email, login } = contributor;
7824
- if (!login) {
7825
- let line = `[${name}](mailto:${email})`;
7826
- if (index < contributors.length - 1) {
7827
- line += ",&nbsp;";
7828
- }
7829
- unloginLine += line;
7830
- } else {
7831
- const githubUrl = getUserGithub(login);
7832
- const avatar = getGitUserAvatar(login);
7833
- loginLine += `[![${login}](${avatar})](${githubUrl})&nbsp;&nbsp;`;
7834
- }
7835
- });
7836
- return `${loginLine}
7837
- ${unloginLine}`;
7838
- }
7839
- function generateMarkdown(params) {
7840
- const { commits, options, showTitle, contributors } = params;
7841
- const lines = [];
7842
- const url = `https://github.com/${options.github}/compare/${options.from}...${options.to}`;
7843
- if (showTitle) {
7844
- const isNewVersion = !VERSION_REG.test(options.to);
7845
- const version = isNewVersion ? options.newVersion : options.to;
7846
- const date = isNewVersion ? dayjs__default().format("YY-MM-DD") : options.tagDateMap.get(options.to);
7847
- let title = `## [${version}](${url})`;
7848
- if (date) {
7849
- title += ` (${date})`;
7850
- }
7851
- lines.push(title);
7852
- }
7853
- const [breaking, changes] = partition(commits, (c) => c.isBreaking);
7854
- const group = groupBy(changes, "type");
7855
- lines.push(...formatSection(breaking, options.titles.breakingChanges, options));
7856
- for (const type of Object.keys(options.types)) {
7857
- const items = group[type] || [];
7858
- lines.push(...formatSection(items, options.types[type].title, options));
7859
- }
7860
- if (!lines.length) {
7861
- lines.push("*No significant changes*");
7862
- }
7863
- if (!showTitle) {
7864
- lines.push("", `##### &nbsp;&nbsp;&nbsp;&nbsp;[View changes on GitHub](${url})`);
7865
- }
7866
- if (showTitle) {
7867
- lines.push("", "### &nbsp;&nbsp;&nbsp;\u2764\uFE0F Contributors", "");
7868
- const contributorLine = createContributorLine(contributors);
7869
- lines.push(contributorLine);
7870
- }
7871
- const md = convertGitmoji.convert(lines.join("\n").trim(), true);
7872
- return md;
7873
- }
7874
- async function isVersionInMarkdown(version, mdPath) {
7875
- let isIn = false;
7876
- const md = await promises.readFile(mdPath, "utf8");
7877
- if (md) {
7878
- const matches = md.match(VERSION_REG_OF_MARKDOWN);
7879
- if (matches?.length) {
7880
- const versionInMarkdown = `## [${version}]`;
7881
- isIn = matches.includes(versionInMarkdown);
7882
- }
7883
- }
7884
- return isIn;
7885
- }
7886
- async function writeMarkdown(md, mdPath, override = false) {
7887
- let changelogMD;
7888
- const changelogPrefix = "# Changelog";
7889
- if (!override && actualFS.existsSync(mdPath)) {
7890
- changelogMD = await promises.readFile(mdPath, "utf8");
7891
- if (!changelogMD.startsWith(changelogPrefix)) {
7892
- changelogMD = `${changelogPrefix}
7893
-
7894
- ${changelogMD}`;
7895
- }
7896
- } else {
7897
- changelogMD = `${changelogPrefix}
7898
-
7899
- `;
7900
- }
7901
- const lastEntry = changelogMD.match(/^###?\s+.*$/m);
7902
- if (lastEntry) {
7903
- changelogMD = `${changelogMD.slice(0, lastEntry.index) + md}
7904
-
7905
- ${changelogMD.slice(lastEntry.index)}`;
7906
- } else {
7907
- changelogMD += `
7908
- ${md}
7909
-
7910
- `;
7911
- }
7912
- await promises.writeFile(mdPath, changelogMD);
7913
- }
7914
-
7915
- function createDefaultOptions() {
7916
- const cwd = process.cwd();
7917
- const options = {
7918
- cwd,
7919
- types: {
7920
- feat: { title: "\u{1F680} Features" },
7921
- fix: { title: "\u{1F41E} Bug Fixes" },
7922
- perf: { title: "\u{1F525} Performance" },
7923
- refactor: { title: "\u{1F485} Refactors" },
7924
- docs: { title: "\u{1F4D6} Documentation" },
7925
- build: { title: "\u{1F4E6} Build" },
7926
- types: { title: "\u{1F30A} Types" },
7927
- chore: { title: "\u{1F3E1} Chore" },
7928
- examples: { title: "\u{1F3C0} Examples" },
7929
- test: { title: "\u2705 Tests" },
7930
- style: { title: "\u{1F3A8} Styles" },
7931
- ci: { title: "\u{1F916} CI" }
7932
- },
7933
- scopeMap: {},
7934
- github: "",
7935
- githubToken: process.env.GITHUB_TOKEN || "",
7936
- from: "",
7937
- to: "",
7938
- tags: [],
7939
- tagDateMap: /* @__PURE__ */ new Map(),
7940
- prerelease: false,
7941
- capitalize: true,
7942
- emoji: true,
7943
- titles: {
7944
- breakingChanges: "\u{1F6A8} Breaking Changes"
7945
- },
7946
- output: "CHANGELOG.md",
7947
- overrideChangelog: false,
7948
- newVersion: ""
7949
- };
7950
- return options;
7951
- }
7952
- async function getOptionsFromPkg(cwd) {
7953
- let githubToken = "";
7954
- let newVersion = "";
7955
- try {
7956
- const pkgJson = await promises.readFile(`${cwd}/package.json`, "utf-8");
7957
- const pkg = JSON.parse(pkgJson);
7958
- githubToken = pkg?.["github-token"] || "";
7959
- newVersion = pkg?.version || "";
7960
- } catch {
7961
- }
7962
- return {
7963
- githubToken,
7964
- newVersion
7965
- };
7966
- }
7967
- async function initOptions() {
7968
- const options = createDefaultOptions();
7969
- const { githubToken, newVersion } = await getOptionsFromPkg(options.cwd);
7970
- if (!options.githubToken) {
7971
- options.githubToken = githubToken;
7972
- }
7973
- if (newVersion) {
7974
- options.newVersion = `v${newVersion}`;
7975
- }
7976
- if (!options.from) {
7977
- options.from = await getLastGitTag();
7978
- }
7979
- if (!options.to) {
7980
- options.to = await getCurrentGitBranch();
7981
- }
7982
- if (options.to === options.from) {
7983
- const lastTag = await getLastGitTag(-1);
7984
- const firstCommit = await getFirstGitCommit();
7985
- options.from = lastTag || firstCommit;
7986
- }
7987
- options.tags = await getTotalGitTags();
7988
- options.tagDateMap = await getTagDateMap();
7989
- options.github = await getGitHubRepo();
7990
- options.prerelease = isPrerelease(options.to);
7991
- return options;
7992
- }
7993
- async function generateChangelogByTag(options) {
7994
- const gitCommits = await getGitCommits(options.from, options.to, options.scopeMap);
7995
- const { commits, contributors } = await getGitCommitsAndResolvedAuthors(
7996
- gitCommits,
7997
- options.github,
7998
- options.githubToken
7999
- );
8000
- const md = generateMarkdown({ commits, options, showTitle: true, contributors });
8001
- return md;
8002
- }
8003
- async function generateChangelogByTags(options) {
8004
- const tags = getFromToTags(options.tags);
8005
- const bar = new cliProgress__default.SingleBar({}, cliProgress__default.Presets.shades_classic);
8006
- bar.start(tags.length, 0);
8007
- let md = "";
8008
- const resolvedLogins = /* @__PURE__ */ new Map();
8009
- for (let i = 0; i < tags.length; i += 1) {
8010
- const { from, to } = tags[i];
8011
- const gitCommits = await getGitCommits(from, to, options.scopeMap);
8012
- const { commits, contributors } = await getGitCommitsAndResolvedAuthors(
8013
- gitCommits,
8014
- options.github,
8015
- options.githubToken,
8016
- resolvedLogins
8017
- );
8018
- const opts = { ...options, from, to };
8019
- const nextMd = generateMarkdown({ commits, options: opts, showTitle: true, contributors });
8020
- md = `${nextMd}
8021
-
8022
- ${md}`;
8023
- bar.update(i + 1);
8024
- }
8025
- bar.stop();
8026
- return md;
8027
- }
8028
- async function generateChangelog(total = false) {
8029
- const options = await initOptions();
8030
- let md = "";
7483
+ function genChangelog(total = false) {
8031
7484
  if (total) {
8032
- md = await generateChangelogByTags(options);
8033
- await writeMarkdown(md, options.output, true);
8034
- return;
8035
- }
8036
- const isIn = await isVersionInMarkdown(options.to, options.output);
8037
- if (!options.overrideChangelog && isIn) {
8038
- return;
7485
+ changelog.generateTotalChangelog();
7486
+ } else {
7487
+ changelog.generateChangelog();
8039
7488
  }
8040
- md = await generateChangelogByTag(options);
8041
- await writeMarkdown(md, options.output, false);
8042
- }
8043
-
8044
- async function genChangelog(total = false) {
8045
- await generateChangelog(total);
8046
7489
  }
8047
7490
 
8048
7491
  async function release() {
@@ -8106,3 +7549,8 @@ Object.entries(commands).forEach(([command, { desc, action }]) => {
8106
7549
  cli.command(command, desc).action(action);
8107
7550
  });
8108
7551
  cli.parse();
7552
+ function defineConfig(config) {
7553
+ return config;
7554
+ }
7555
+
7556
+ exports.defineConfig = defineConfig;
@@ -0,0 +1,15 @@
1
+ import { ChangelogOption } from '@soybeanjs/changelog';
2
+
3
+ interface CliOption {
4
+ name?: string;
5
+ /**
6
+ * options of generate changelog
7
+ * @link https://github.com/soybeanjs/changelog
8
+ */
9
+ changelogOptions?: Partial<ChangelogOption>;
10
+ prettierFormatFiles?: string[];
11
+ }
12
+
13
+ declare function defineConfig(config?: Partial<CliOption>): Partial<CliOption> | undefined;
14
+
15
+ export { CliOption, defineConfig };
package/dist/index.mjs CHANGED
@@ -7,61 +7,20 @@ import { bgRed, red, green } from 'kolorist';
7
7
  import { rimraf } from 'rimraf';
8
8
  import { win32, posix } from 'path';
9
9
  import { fileURLToPath } from 'url';
10
- import { lstat, readdir as readdir$1, readlink, realpath, readFile, writeFile } from 'fs/promises';
10
+ import { lstat, readdir as readdir$1, readlink, realpath } from 'fs/promises';
11
11
  import EE from 'events';
12
12
  import Stream from 'stream';
13
13
  import stringdecoder from 'string_decoder';
14
- import cliProgress from 'cli-progress';
15
- import { ofetch } from 'ofetch';
16
- import dayjs from 'dayjs';
17
- import { convert } from 'convert-gitmoji';
14
+ import { generateTotalChangelog, generateChangelog } from '@soybeanjs/changelog';
18
15
  import versionBumpp from 'bumpp';
19
16
 
20
- const version = "0.5.1";
17
+ const version = "0.5.3";
21
18
 
22
19
  async function execCommand(cmd, args, options) {
23
20
  const { execa } = await import('execa');
24
21
  const res = await execa(cmd, args, options);
25
22
  return res?.stdout?.trim() || "";
26
23
  }
27
- function notNullish(v) {
28
- return v !== null && v !== void 0;
29
- }
30
- function partition(array, ...filters) {
31
- const result = new Array(filters.length + 1).fill(null).map(() => []);
32
- array.forEach((e, idx, arr) => {
33
- let i = 0;
34
- for (const filter of filters) {
35
- if (filter(e, idx, arr)) {
36
- result[i].push(e);
37
- return;
38
- }
39
- i += 1;
40
- }
41
- result[i].push(e);
42
- });
43
- return result;
44
- }
45
- function groupBy(items, key, groups = {}) {
46
- for (const item of items) {
47
- const v = item[key];
48
- groups[v] = groups[v] || [];
49
- groups[v].push(item);
50
- }
51
- return groups;
52
- }
53
- function capitalize(str) {
54
- return str.charAt(0).toUpperCase() + str.slice(1);
55
- }
56
- function join(array, glue = ", ", finalGlue = " and ") {
57
- if (!array || array.length === 0)
58
- return "";
59
- if (array.length === 1)
60
- return array[0];
61
- if (array.length === 2)
62
- return array.join(finalGlue);
63
- return `${array.slice(0, -1).join(glue)}${finalGlue}${array.slice(-1)}`;
64
- }
65
24
 
66
25
  const gitCommitTypes = [
67
26
  { value: "init", title: "init: \u9879\u76EE\u521D\u59CB\u5316" },
@@ -120,11 +79,9 @@ async function gitCommit() {
120
79
  }
121
80
 
122
81
  function gitCommitVerify() {
123
- const gitMsgPath = "./.git/COMMIT_EDITMSG";
82
+ const gitMsgPath = `${process.cwd()}/.git/COMMIT_EDITMSG`;
124
83
  const commitMsg = readFileSync(gitMsgPath, "utf-8").trim();
125
- const types = gitCommitTypes.map((item) => item.value).join("|");
126
- const scopes = gitCommitScopes.map((item) => item.value).join("|");
127
- const REG_EXP = new RegExp(`(${types})!*(\\((${scopes})\\))*!*:\\s.{1,100}`);
84
+ const REG_EXP = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
128
85
  if (!REG_EXP.test(commitMsg)) {
129
86
  throw new Error(
130
87
  `${bgRed(" ERROR ")} ${red("Git\u63D0\u4EA4\u4FE1\u606F\u4E0D\u7B26\u5408 Angular \u89C4\u8303!\n\n")}${green(
@@ -7454,10 +7411,10 @@ async function initSimpleGitHooks() {
7454
7411
  const huskyDir = `${process.cwd()}/.husky`;
7455
7412
  const existHusky = existsSync(huskyDir);
7456
7413
  if (existHusky) {
7457
- await rimraf(".husky");
7414
+ await rimraf(huskyDir);
7458
7415
  await execCommand("git", ["config", "core.hooksPath", ".git/hooks/"], { stdio: "inherit" });
7459
7416
  }
7460
- await rimraf(".git/hooks");
7417
+ await rimraf(`${process.cwd()}/.git/hooks`);
7461
7418
  await execCommand("npx", ["simple-git-hooks"], { stdio: "inherit" });
7462
7419
  }
7463
7420
 
@@ -7500,524 +7457,12 @@ function lintStaged() {
7500
7457
  execCommand("npx", ["lint-staged", "--config", "@soybeanjs/cli/lint-staged"], { stdio: "inherit" });
7501
7458
  }
7502
7459
 
7503
- const VERSION_REG = /v\d+\.\d+\.\d+(-(beta|alpha)\.\d+)?/;
7504
- const VERSION_REG_OF_MARKDOWN = /## \[v\d+\.\d+\.\d+(-(beta|alpha)\.\d+)?]/g;
7505
-
7506
- async function getTotalGitTags() {
7507
- const tagStr = await execCommand("git", ["--no-pager", "tag", "-l", "--sort=creatordate"]);
7508
- const tags = tagStr.split("\n");
7509
- return tags;
7510
- }
7511
- async function getTagDateMap() {
7512
- const tagDateStr = await execCommand("git", [
7513
- "--no-pager",
7514
- "log",
7515
- "--tags",
7516
- "--simplify-by-decoration",
7517
- "--pretty=format:%ci %d"
7518
- ]);
7519
- const TAG_MARK = "tag: ";
7520
- const map = /* @__PURE__ */ new Map();
7521
- const dates = tagDateStr.split("\n").filter((item) => item.includes(TAG_MARK));
7522
- dates.forEach((item) => {
7523
- const [dateStr, tagStr] = item.split(TAG_MARK);
7524
- const date = dayjs(dateStr).format("YYYY-MM-DD");
7525
- const tag = tagStr.match(VERSION_REG)?.[0];
7526
- if (tag && date) {
7527
- map.set(tag.trim(), date);
7528
- }
7529
- });
7530
- return map;
7531
- }
7532
- function getFromToTags(tags) {
7533
- const result = [];
7534
- tags.forEach((tag, index) => {
7535
- if (index < tags.length - 1) {
7536
- result.push({ from: tag, to: tags[index + 1] });
7537
- }
7538
- });
7539
- return result;
7540
- }
7541
- async function getLastGitTag(delta = 0) {
7542
- const tags = await getTotalGitTags();
7543
- return tags[tags.length + delta - 1];
7544
- }
7545
- async function getGitMainBranchName() {
7546
- const main = await execCommand("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
7547
- return main;
7548
- }
7549
- async function getCurrentGitBranch() {
7550
- const tag = await execCommand("git", ["tag", "--points-at", "HEAD"]);
7551
- const main = getGitMainBranchName();
7552
- return tag || main;
7553
- }
7554
- async function getGitHubRepo() {
7555
- const url = await execCommand("git", ["config", "--get", "remote.origin.url"]);
7556
- const match = url.match(/github\.com[/:]([\w\d._-]+?)\/([\w\d._-]+?)(\.git)?$/i);
7557
- if (!match) {
7558
- throw new Error(`Can not parse GitHub repo from url ${url}`);
7559
- }
7560
- return `${match[1]}/${match[2]}`;
7561
- }
7562
- function isPrerelease(version) {
7563
- const REG = /^[^.]*[\d.]+$/;
7564
- return !REG.test(version);
7565
- }
7566
- function getFirstGitCommit() {
7567
- return execCommand("git", ["rev-list", "--max-parents=0", "HEAD"]);
7568
- }
7569
- async function getGitDiff(from, to = "HEAD") {
7570
- const rawGit = await execCommand("git", [
7571
- "--no-pager",
7572
- "log",
7573
- `${from ? `${from}...` : ""}${to}`,
7574
- '--pretty="----%n%s|%h|%an|%ae%n%b"',
7575
- "--name-status"
7576
- ]);
7577
- const rwaGitLines = rawGit.split("----\n").splice(1);
7578
- const gitCommits = rwaGitLines.map((line) => {
7579
- const [firstLine, ...body] = line.split("\n");
7580
- const [message, shortHash, authorName, authorEmail] = firstLine.split("|");
7581
- const gitCommmit = {
7582
- message,
7583
- shortHash,
7584
- author: { name: authorName, email: authorEmail },
7585
- body: body.join("\n")
7586
- };
7587
- return gitCommmit;
7588
- });
7589
- return gitCommits;
7590
- }
7591
- function parseGitCommit(commit, scopeMap) {
7592
- const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
7593
- const CoAuthoredByRegex = /co-authored-by:\s*(?<name>.+)(<(?<email>.+)>)/gim;
7594
- const PullRequestRE = /\([a-z]*(#\d+)\s*\)/gm;
7595
- const IssueRE = /(#\d+)/gm;
7596
- const match = commit.message.match(ConventionalCommitRegex);
7597
- if (!match?.groups) {
7598
- return null;
7599
- }
7600
- const type = match.groups.type;
7601
- let scope = match.groups.scope || "";
7602
- scope = scopeMap[scope] || scope;
7603
- const isBreaking = Boolean(match.groups.breaking);
7604
- let description = match.groups.description;
7605
- const references = [];
7606
- for (const m of description.matchAll(PullRequestRE)) {
7607
- references.push({ type: "pull-request", value: m[1] });
7608
- }
7609
- for (const m of description.matchAll(IssueRE)) {
7610
- if (!references.some((i) => i.value === m[1])) {
7611
- references.push({ type: "issue", value: m[1] });
7612
- }
7613
- }
7614
- references.push({ value: commit.shortHash, type: "hash" });
7615
- description = description.replace(PullRequestRE, "").trim();
7616
- const authors = [commit.author];
7617
- const matchs = commit.body.matchAll(CoAuthoredByRegex);
7618
- for (const $match of matchs) {
7619
- const { name = "", email = "" } = $match.groups || {};
7620
- const author = {
7621
- name: name.trim(),
7622
- email: email.trim()
7623
- };
7624
- authors.push(author);
7625
- }
7626
- return {
7627
- ...commit,
7628
- authors,
7629
- resolvedAuthors: [],
7630
- description,
7631
- type,
7632
- scope,
7633
- references,
7634
- isBreaking
7635
- };
7636
- }
7637
- async function getGitCommits(from, to = "HEAD", scopeMap = {}) {
7638
- const rwaGitCommits = await getGitDiff(from, to);
7639
- const commits = rwaGitCommits.map((commit) => parseGitCommit(commit, scopeMap)).filter(notNullish);
7640
- return commits;
7641
- }
7642
- function getHeaders(githubToken) {
7643
- return {
7644
- accept: "application/vnd.github.v3+json",
7645
- authorization: `token ${githubToken}`
7646
- };
7647
- }
7648
- async function getResolvedAuthorLogin(params) {
7649
- const { github, githubToken, commitHashes, email } = params;
7650
- let login = "";
7651
- try {
7652
- const data = await ofetch(`https://ungh.cc/users/find/${email}`);
7653
- login = data?.user?.username || "";
7654
- } catch {
7655
- }
7656
- if (login) {
7657
- return login;
7658
- }
7659
- if (!githubToken) {
7660
- return login;
7661
- }
7662
- if (commitHashes.length) {
7663
- try {
7664
- const data = await ofetch(`https://api.github.com/repos/${github}/commits/${commitHashes[0]}`, {
7665
- headers: getHeaders(githubToken)
7666
- });
7667
- login = data?.author?.login || "";
7668
- } catch (e) {
7669
- }
7670
- }
7671
- if (login) {
7672
- return login;
7673
- }
7674
- try {
7675
- const data = await ofetch(`https://api.github.com/search/users?q=${encodeURIComponent(email)}`, {
7676
- headers: getHeaders(githubToken)
7677
- });
7678
- login = data.items[0].login;
7679
- } catch (e) {
7680
- }
7681
- return login;
7682
- }
7683
- async function getGitCommitsAndResolvedAuthors(commits, github, githubToken, resolvedLogins) {
7684
- const resultCommits = [];
7685
- const map = /* @__PURE__ */ new Map();
7686
- for (const commit of commits) {
7687
- const resolvedAuthors = [];
7688
- for (const [index, author] of Object.entries(commit.authors)) {
7689
- const { email, name } = author;
7690
- if (email && name) {
7691
- const commitHashes = [];
7692
- if (index === "0") {
7693
- commitHashes.push(commit.shortHash);
7694
- }
7695
- const resolvedAuthor = {
7696
- name,
7697
- email,
7698
- commits: commitHashes,
7699
- login: ""
7700
- };
7701
- if (!resolvedLogins?.has(email)) {
7702
- const login = await getResolvedAuthorLogin({ github, githubToken, commitHashes, email });
7703
- resolvedAuthor.login = login;
7704
- resolvedLogins?.set(email, login);
7705
- } else {
7706
- const login = resolvedLogins?.get(email) || "";
7707
- resolvedAuthor.login = login;
7708
- }
7709
- resolvedAuthors.push(resolvedAuthor);
7710
- if (!map.has(email)) {
7711
- map.set(email, resolvedAuthor);
7712
- }
7713
- }
7714
- }
7715
- const resultCommit = { ...commit, resolvedAuthors };
7716
- resultCommits.push(resultCommit);
7717
- }
7718
- return {
7719
- commits: resultCommits,
7720
- contributors: Array.from(map.values())
7721
- };
7722
- }
7723
-
7724
- function formatReferences(references, github, type) {
7725
- const refs = references.filter((i) => {
7726
- if (type === "issues")
7727
- return i.type === "issue" || i.type === "pull-request";
7728
- return i.type === "hash";
7729
- }).map((ref) => {
7730
- if (!github)
7731
- return ref.value;
7732
- if (ref.type === "pull-request" || ref.type === "issue")
7733
- return `https://github.com/${github}/issues/${ref.value.slice(1)}`;
7734
- return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${github}/commit/${ref.value})`;
7735
- });
7736
- const referencesString = join(refs).trim();
7737
- if (type === "issues")
7738
- return referencesString && `in ${referencesString}`;
7739
- return referencesString;
7740
- }
7741
- function formatLine(commit, options) {
7742
- const prRefs = formatReferences(commit.references, options.github, "issues");
7743
- const hashRefs = formatReferences(commit.references, options.github, "hash");
7744
- let authors = join([...new Set(commit.resolvedAuthors.map((i) => i.login ? `@${i.login}` : `**${i.name}**`))]).trim();
7745
- if (authors) {
7746
- authors = `by ${authors}`;
7747
- }
7748
- let refs = [authors, prRefs, hashRefs].filter((i) => i?.trim()).join(" ");
7749
- if (refs) {
7750
- refs = `&nbsp;-&nbsp; ${refs}`;
7751
- }
7752
- const description = options.capitalize ? capitalize(commit.description) : commit.description;
7753
- return [description, refs].filter((i) => i?.trim()).join(" ");
7754
- }
7755
- function formatTitle(name, options) {
7756
- const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
7757
- let formatName = name.trim();
7758
- if (!options.emoji) {
7759
- formatName = name.replace(emojisRE, "").trim();
7760
- }
7761
- return `### &nbsp;&nbsp;&nbsp;${formatName}`;
7762
- }
7763
- function formatSection(commits, sectionName, options) {
7764
- if (!commits.length)
7765
- return [];
7766
- const lines = ["", formatTitle(sectionName, options), ""];
7767
- const scopes = groupBy(commits, "scope");
7768
- let useScopeGroup = options.group;
7769
- if (!Object.entries(scopes).some(([k, v]) => k && v.length > 1))
7770
- useScopeGroup = false;
7771
- Object.keys(scopes).sort().forEach((scope) => {
7772
- let padding = "";
7773
- let prefix = "";
7774
- const scopeText = `**${options.scopeMap[scope] || scope}**`;
7775
- if (scope && (useScopeGroup === true || useScopeGroup === "multiple" && scopes[scope].length > 1)) {
7776
- lines.push(`- ${scopeText}:`);
7777
- padding = " ";
7778
- } else if (scope) {
7779
- prefix = `${scopeText}: `;
7780
- }
7781
- lines.push(...scopes[scope].reverse().map((commit) => `${padding}- ${prefix}${formatLine(commit, options)}`));
7782
- });
7783
- return lines;
7784
- }
7785
- function getUserGithub(userName) {
7786
- const githubUrl = `https://github.com/${userName}`;
7787
- return githubUrl;
7788
- }
7789
- function getGitUserAvatar(userName) {
7790
- const githubUrl = getUserGithub(userName);
7791
- const avatarUrl = `${githubUrl}.png?size=48`;
7792
- return avatarUrl;
7793
- }
7794
- function createContributorLine(contributors) {
7795
- let loginLine = "";
7796
- let unloginLine = "";
7797
- contributors.forEach((contributor, index) => {
7798
- const { name, email, login } = contributor;
7799
- if (!login) {
7800
- let line = `[${name}](mailto:${email})`;
7801
- if (index < contributors.length - 1) {
7802
- line += ",&nbsp;";
7803
- }
7804
- unloginLine += line;
7805
- } else {
7806
- const githubUrl = getUserGithub(login);
7807
- const avatar = getGitUserAvatar(login);
7808
- loginLine += `[![${login}](${avatar})](${githubUrl})&nbsp;&nbsp;`;
7809
- }
7810
- });
7811
- return `${loginLine}
7812
- ${unloginLine}`;
7813
- }
7814
- function generateMarkdown(params) {
7815
- const { commits, options, showTitle, contributors } = params;
7816
- const lines = [];
7817
- const url = `https://github.com/${options.github}/compare/${options.from}...${options.to}`;
7818
- if (showTitle) {
7819
- const isNewVersion = !VERSION_REG.test(options.to);
7820
- const version = isNewVersion ? options.newVersion : options.to;
7821
- const date = isNewVersion ? dayjs().format("YY-MM-DD") : options.tagDateMap.get(options.to);
7822
- let title = `## [${version}](${url})`;
7823
- if (date) {
7824
- title += ` (${date})`;
7825
- }
7826
- lines.push(title);
7827
- }
7828
- const [breaking, changes] = partition(commits, (c) => c.isBreaking);
7829
- const group = groupBy(changes, "type");
7830
- lines.push(...formatSection(breaking, options.titles.breakingChanges, options));
7831
- for (const type of Object.keys(options.types)) {
7832
- const items = group[type] || [];
7833
- lines.push(...formatSection(items, options.types[type].title, options));
7834
- }
7835
- if (!lines.length) {
7836
- lines.push("*No significant changes*");
7837
- }
7838
- if (!showTitle) {
7839
- lines.push("", `##### &nbsp;&nbsp;&nbsp;&nbsp;[View changes on GitHub](${url})`);
7840
- }
7841
- if (showTitle) {
7842
- lines.push("", "### &nbsp;&nbsp;&nbsp;\u2764\uFE0F Contributors", "");
7843
- const contributorLine = createContributorLine(contributors);
7844
- lines.push(contributorLine);
7845
- }
7846
- const md = convert(lines.join("\n").trim(), true);
7847
- return md;
7848
- }
7849
- async function isVersionInMarkdown(version, mdPath) {
7850
- let isIn = false;
7851
- const md = await readFile(mdPath, "utf8");
7852
- if (md) {
7853
- const matches = md.match(VERSION_REG_OF_MARKDOWN);
7854
- if (matches?.length) {
7855
- const versionInMarkdown = `## [${version}]`;
7856
- isIn = matches.includes(versionInMarkdown);
7857
- }
7858
- }
7859
- return isIn;
7860
- }
7861
- async function writeMarkdown(md, mdPath, override = false) {
7862
- let changelogMD;
7863
- const changelogPrefix = "# Changelog";
7864
- if (!override && existsSync(mdPath)) {
7865
- changelogMD = await readFile(mdPath, "utf8");
7866
- if (!changelogMD.startsWith(changelogPrefix)) {
7867
- changelogMD = `${changelogPrefix}
7868
-
7869
- ${changelogMD}`;
7870
- }
7871
- } else {
7872
- changelogMD = `${changelogPrefix}
7873
-
7874
- `;
7875
- }
7876
- const lastEntry = changelogMD.match(/^###?\s+.*$/m);
7877
- if (lastEntry) {
7878
- changelogMD = `${changelogMD.slice(0, lastEntry.index) + md}
7879
-
7880
- ${changelogMD.slice(lastEntry.index)}`;
7881
- } else {
7882
- changelogMD += `
7883
- ${md}
7884
-
7885
- `;
7886
- }
7887
- await writeFile(mdPath, changelogMD);
7888
- }
7889
-
7890
- function createDefaultOptions() {
7891
- const cwd = process.cwd();
7892
- const options = {
7893
- cwd,
7894
- types: {
7895
- feat: { title: "\u{1F680} Features" },
7896
- fix: { title: "\u{1F41E} Bug Fixes" },
7897
- perf: { title: "\u{1F525} Performance" },
7898
- refactor: { title: "\u{1F485} Refactors" },
7899
- docs: { title: "\u{1F4D6} Documentation" },
7900
- build: { title: "\u{1F4E6} Build" },
7901
- types: { title: "\u{1F30A} Types" },
7902
- chore: { title: "\u{1F3E1} Chore" },
7903
- examples: { title: "\u{1F3C0} Examples" },
7904
- test: { title: "\u2705 Tests" },
7905
- style: { title: "\u{1F3A8} Styles" },
7906
- ci: { title: "\u{1F916} CI" }
7907
- },
7908
- scopeMap: {},
7909
- github: "",
7910
- githubToken: process.env.GITHUB_TOKEN || "",
7911
- from: "",
7912
- to: "",
7913
- tags: [],
7914
- tagDateMap: /* @__PURE__ */ new Map(),
7915
- prerelease: false,
7916
- capitalize: true,
7917
- emoji: true,
7918
- titles: {
7919
- breakingChanges: "\u{1F6A8} Breaking Changes"
7920
- },
7921
- output: "CHANGELOG.md",
7922
- overrideChangelog: false,
7923
- newVersion: ""
7924
- };
7925
- return options;
7926
- }
7927
- async function getOptionsFromPkg(cwd) {
7928
- let githubToken = "";
7929
- let newVersion = "";
7930
- try {
7931
- const pkgJson = await readFile(`${cwd}/package.json`, "utf-8");
7932
- const pkg = JSON.parse(pkgJson);
7933
- githubToken = pkg?.["github-token"] || "";
7934
- newVersion = pkg?.version || "";
7935
- } catch {
7936
- }
7937
- return {
7938
- githubToken,
7939
- newVersion
7940
- };
7941
- }
7942
- async function initOptions() {
7943
- const options = createDefaultOptions();
7944
- const { githubToken, newVersion } = await getOptionsFromPkg(options.cwd);
7945
- if (!options.githubToken) {
7946
- options.githubToken = githubToken;
7947
- }
7948
- if (newVersion) {
7949
- options.newVersion = `v${newVersion}`;
7950
- }
7951
- if (!options.from) {
7952
- options.from = await getLastGitTag();
7953
- }
7954
- if (!options.to) {
7955
- options.to = await getCurrentGitBranch();
7956
- }
7957
- if (options.to === options.from) {
7958
- const lastTag = await getLastGitTag(-1);
7959
- const firstCommit = await getFirstGitCommit();
7960
- options.from = lastTag || firstCommit;
7961
- }
7962
- options.tags = await getTotalGitTags();
7963
- options.tagDateMap = await getTagDateMap();
7964
- options.github = await getGitHubRepo();
7965
- options.prerelease = isPrerelease(options.to);
7966
- return options;
7967
- }
7968
- async function generateChangelogByTag(options) {
7969
- const gitCommits = await getGitCommits(options.from, options.to, options.scopeMap);
7970
- const { commits, contributors } = await getGitCommitsAndResolvedAuthors(
7971
- gitCommits,
7972
- options.github,
7973
- options.githubToken
7974
- );
7975
- const md = generateMarkdown({ commits, options, showTitle: true, contributors });
7976
- return md;
7977
- }
7978
- async function generateChangelogByTags(options) {
7979
- const tags = getFromToTags(options.tags);
7980
- const bar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
7981
- bar.start(tags.length, 0);
7982
- let md = "";
7983
- const resolvedLogins = /* @__PURE__ */ new Map();
7984
- for (let i = 0; i < tags.length; i += 1) {
7985
- const { from, to } = tags[i];
7986
- const gitCommits = await getGitCommits(from, to, options.scopeMap);
7987
- const { commits, contributors } = await getGitCommitsAndResolvedAuthors(
7988
- gitCommits,
7989
- options.github,
7990
- options.githubToken,
7991
- resolvedLogins
7992
- );
7993
- const opts = { ...options, from, to };
7994
- const nextMd = generateMarkdown({ commits, options: opts, showTitle: true, contributors });
7995
- md = `${nextMd}
7996
-
7997
- ${md}`;
7998
- bar.update(i + 1);
7999
- }
8000
- bar.stop();
8001
- return md;
8002
- }
8003
- async function generateChangelog(total = false) {
8004
- const options = await initOptions();
8005
- let md = "";
7460
+ function genChangelog(total = false) {
8006
7461
  if (total) {
8007
- md = await generateChangelogByTags(options);
8008
- await writeMarkdown(md, options.output, true);
8009
- return;
8010
- }
8011
- const isIn = await isVersionInMarkdown(options.to, options.output);
8012
- if (!options.overrideChangelog && isIn) {
8013
- return;
7462
+ generateTotalChangelog();
7463
+ } else {
7464
+ generateChangelog();
8014
7465
  }
8015
- md = await generateChangelogByTag(options);
8016
- await writeMarkdown(md, options.output, false);
8017
- }
8018
-
8019
- async function genChangelog(total = false) {
8020
- await generateChangelog(total);
8021
7466
  }
8022
7467
 
8023
7468
  async function release() {
@@ -8081,3 +7526,8 @@ Object.entries(commands).forEach(([command, { desc, action }]) => {
8081
7526
  cli.command(command, desc).action(action);
8082
7527
  });
8083
7528
  cli.parse();
7529
+ function defineConfig(config) {
7530
+ return config;
7531
+ }
7532
+
7533
+ export { defineConfig };
@@ -0,0 +1,3 @@
1
+ declare const config: Record<string, string | string[]>;
2
+
3
+ export { config as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soybeanjs/cli",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "SoybeanJS's command line tools",
5
5
  "author": {
6
6
  "name": "Soybean",
@@ -32,23 +32,20 @@
32
32
  "dist"
33
33
  ],
34
34
  "dependencies": {
35
+ "@soybeanjs/changelog": "0.0.2",
35
36
  "bumpp": "9.1.0",
37
+ "c12": "1.4.1",
36
38
  "cac": "6.7.14",
37
- "cli-progress": "^3.12.0",
38
- "convert-gitmoji": "0.1.3",
39
- "dayjs": "1.11.8",
40
39
  "enquirer": "2.3.6",
41
40
  "execa": "7.1.1",
42
41
  "kolorist": "1.8.0",
43
42
  "lint-staged": "13.2.2",
44
43
  "minimist": "1.2.8",
45
44
  "npm-check-updates": "16.10.12",
46
- "ofetch": "1.0.1",
47
45
  "rimraf": "5.0.1"
48
46
  },
49
47
  "devDependencies": {
50
48
  "@soybeanjs/cli": "link:",
51
- "@types/cli-progress": "^3.11.0",
52
49
  "@types/node": "20.2.5",
53
50
  "eslint": "8.41.0",
54
51
  "eslint-config-soybeanjs": "0.4.7",