@icebreakers/changelog-github 0.1.1 → 0.2.1
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/README.md +2 -2
- package/README.zh.md +2 -2
- package/dist/index.cjs +95 -36
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.mjs +94 -35
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ All other behaviours (tuple arguments, required `repo` option, rendered layout)
|
|
|
46
46
|
|
|
47
47
|
Leverage the summary tags to control the metadata the formatter displays:
|
|
48
48
|
|
|
49
|
-
```
|
|
49
|
+
```text
|
|
50
50
|
pr: #42
|
|
51
51
|
commit: 1234567890abcdef1234567890abcdef12345678
|
|
52
52
|
author: @octocat
|
|
@@ -59,7 +59,7 @@ Add optional `tailwind-config` flag to the lint preset
|
|
|
59
59
|
|
|
60
60
|
The rendered changelog entry becomes:
|
|
61
61
|
|
|
62
|
-
```
|
|
62
|
+
```md
|
|
63
63
|
- ✨ **Add optional `tailwind-config` flag** [#42] [`1234567`](https://github.com/org/repo/commit/1234567890abcdef1234567890abcdef12345678) by @octocat
|
|
64
64
|
- accepts a relative path to `tailwind.config.ts`
|
|
65
65
|
- falls back to the workspace root when unset
|
package/README.zh.md
CHANGED
|
@@ -44,7 +44,7 @@ pnpm add -D @changesets/cli @icebreakers/changelog-github
|
|
|
44
44
|
|
|
45
45
|
可以借助摘要指令精准控制展示的元数据:
|
|
46
46
|
|
|
47
|
-
```
|
|
47
|
+
```text
|
|
48
48
|
pr: #42
|
|
49
49
|
commit: 1234567890abcdef1234567890abcdef12345678
|
|
50
50
|
author: @octocat
|
|
@@ -57,7 +57,7 @@ author: @octocat
|
|
|
57
57
|
|
|
58
58
|
最终 changelog 会渲染为:
|
|
59
59
|
|
|
60
|
-
```
|
|
60
|
+
```md
|
|
61
61
|
- ✨ **为 lint preset 新增可选的 `tailwind-config` 配置项** [#42] [`1234567`](https://github.com/org/repo/commit/1234567890abcdef1234567890abcdef12345678) by @octocat
|
|
62
62
|
- 接受相对路径指向 `tailwind.config.ts`
|
|
63
63
|
- 未设置时默认读取工作区根目录
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/index.ts
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/index.ts
|
|
2
2
|
var _getgithubinfo = require('@changesets/get-github-info');
|
|
3
3
|
var _dotenv = require('dotenv');
|
|
4
4
|
_dotenv.config.call(void 0, );
|
|
@@ -15,7 +15,7 @@ function resolveReleaseType(type) {
|
|
|
15
15
|
return "none";
|
|
16
16
|
}
|
|
17
17
|
function assertRepo(options) {
|
|
18
|
-
if (!options ||
|
|
18
|
+
if (!options || typeof options["repo"] !== "string" || options["repo"].trim().length === 0) {
|
|
19
19
|
throw new Error(
|
|
20
20
|
'Please provide a repo to this changelog generator like this:\n"changelog": ["@icebreakers/changelog-github", { "repo": "org/repo" }]'
|
|
21
21
|
);
|
|
@@ -34,7 +34,7 @@ async function collectDependencyReferences(changesets, repo) {
|
|
|
34
34
|
return links.commit;
|
|
35
35
|
})
|
|
36
36
|
);
|
|
37
|
-
return references.filter((link) => Boolean(link));
|
|
37
|
+
return [...new Set(references.filter((link) => Boolean(link)))];
|
|
38
38
|
}
|
|
39
39
|
function formatDependencyLine(references, dependenciesUpdated) {
|
|
40
40
|
const count = dependenciesUpdated.length;
|
|
@@ -42,16 +42,53 @@ function formatDependencyLine(references, dependenciesUpdated) {
|
|
|
42
42
|
if (count === 0) {
|
|
43
43
|
return firstCommit ? `- \u{1F4E6} **Dependencies** ${firstCommit}` : "- \u{1F4E6} **Dependencies**";
|
|
44
44
|
}
|
|
45
|
+
const dependencySummaries = dependenciesUpdated.map(
|
|
46
|
+
(dependency) => `\`${dependency.name}@${dependency.newVersion}\``
|
|
47
|
+
);
|
|
45
48
|
if (count <= 3) {
|
|
46
|
-
const
|
|
47
|
-
(dependency) => `\`${dependency.name}@${dependency.newVersion}\``
|
|
48
|
-
);
|
|
49
|
-
const header = firstCommit ? `- \u{1F4E6} **Dependencies** ${firstCommit}` : "- \u{1F4E6} **Dependencies**";
|
|
49
|
+
const header2 = firstCommit ? `- \u{1F4E6} **Dependencies** ${firstCommit}` : "- \u{1F4E6} **Dependencies**";
|
|
50
50
|
const details = ` \u2192 ${dependencySummaries.join(", ")}`;
|
|
51
|
-
return `${
|
|
51
|
+
return `${header2}
|
|
52
52
|
${details}`;
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
const header = firstCommit ? `- \u{1F4E6} Updated ${count} dependencies ${firstCommit}` : `- \u{1F4E6} Updated ${count} dependencies`;
|
|
55
|
+
const detailBlock = [
|
|
56
|
+
" <details><summary>Details</summary>",
|
|
57
|
+
"",
|
|
58
|
+
` ${dependencySummaries.join(", ")}`,
|
|
59
|
+
"",
|
|
60
|
+
" </details>"
|
|
61
|
+
].join("\n");
|
|
62
|
+
return `${header}
|
|
63
|
+
${detailBlock}`;
|
|
64
|
+
}
|
|
65
|
+
function parseConventionalHeadline(raw) {
|
|
66
|
+
const match = raw.match(
|
|
67
|
+
/^(\w+)(?:\(([^)]*)\))?(!?):\s(.+)$/
|
|
68
|
+
);
|
|
69
|
+
if (!match) {
|
|
70
|
+
return { breaking: false, description: raw };
|
|
71
|
+
}
|
|
72
|
+
const type = match[1];
|
|
73
|
+
const scope = match[2] || void 0;
|
|
74
|
+
const description = (_nullishCoalesce(match[4], () => ( raw))).trim();
|
|
75
|
+
return {
|
|
76
|
+
type,
|
|
77
|
+
scope,
|
|
78
|
+
breaking: match[3] === "!",
|
|
79
|
+
description
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function formatHeadline(raw) {
|
|
83
|
+
const parsed = parseConventionalHeadline(raw);
|
|
84
|
+
if (!parsed.type) {
|
|
85
|
+
return { text: raw, breaking: parsed.breaking };
|
|
86
|
+
}
|
|
87
|
+
const scopeTag = parsed.scope ? `${parsed.scope}: ` : "";
|
|
88
|
+
return {
|
|
89
|
+
text: `${scopeTag}${parsed.description}`,
|
|
90
|
+
breaking: parsed.breaking
|
|
91
|
+
};
|
|
55
92
|
}
|
|
56
93
|
function normalizeUserMentions(users) {
|
|
57
94
|
const normalized = users.map((user) => user.trim()).filter(Boolean).map((user) => user.startsWith("@") ? user : `@${user}`);
|
|
@@ -59,16 +96,17 @@ function normalizeUserMentions(users) {
|
|
|
59
96
|
return "";
|
|
60
97
|
}
|
|
61
98
|
if (normalized.length === 1) {
|
|
62
|
-
return normalized[0];
|
|
99
|
+
return _nullishCoalesce(normalized[0], () => ( ""));
|
|
63
100
|
}
|
|
64
101
|
if (normalized.length === 2) {
|
|
65
|
-
return `${normalized[0]} and ${normalized[1]}`;
|
|
102
|
+
return `${_nullishCoalesce(normalized[0], () => ( ""))} and ${_nullishCoalesce(normalized[1], () => ( ""))}`;
|
|
66
103
|
}
|
|
67
|
-
return `${normalized.slice(0, -1).join(", ")}, and ${normalized.at(-1)}`;
|
|
104
|
+
return `${normalized.slice(0, -1).join(", ")}, and ${_nullishCoalesce(normalized.at(-1), () => ( ""))}`;
|
|
68
105
|
}
|
|
69
106
|
function extractSummaryMeta(summary) {
|
|
70
107
|
let prNumber;
|
|
71
108
|
let commitRef;
|
|
109
|
+
let breaking = false;
|
|
72
110
|
const users = [];
|
|
73
111
|
const contentLines = summary.split(/\r?\n/).filter((line) => {
|
|
74
112
|
const trimmed = line.trim();
|
|
@@ -77,7 +115,7 @@ function extractSummaryMeta(summary) {
|
|
|
77
115
|
/^(?:pr|pull|pull\s*request):\s*#?(\d+)\s*$/i
|
|
78
116
|
);
|
|
79
117
|
if (prMatch) {
|
|
80
|
-
const num = Number(prMatch[1]);
|
|
118
|
+
const num = Number(_nullishCoalesce(prMatch[1], () => ( Number.NaN)));
|
|
81
119
|
if (!Number.isNaN(num)) {
|
|
82
120
|
prNumber = num;
|
|
83
121
|
}
|
|
@@ -90,16 +128,23 @@ function extractSummaryMeta(summary) {
|
|
|
90
128
|
}
|
|
91
129
|
const userMatch = withoutListMarker.match(/^(?:author|user):\s*(\S+)\s*$/i);
|
|
92
130
|
if (userMatch) {
|
|
93
|
-
|
|
131
|
+
const user = userMatch[1];
|
|
132
|
+
if (user) {
|
|
133
|
+
users.push(user.replace(/^@/, ""));
|
|
134
|
+
}
|
|
94
135
|
return false;
|
|
95
136
|
}
|
|
137
|
+
if (/^BREAKING[\s-]CHANGE:/i.test(withoutListMarker)) {
|
|
138
|
+
breaking = true;
|
|
139
|
+
}
|
|
96
140
|
return true;
|
|
97
|
-
}).map((line) => line.
|
|
141
|
+
}).map((line) => line.trimEnd());
|
|
98
142
|
return {
|
|
99
|
-
prNumber,
|
|
100
|
-
commitRef,
|
|
143
|
+
...prNumber !== void 0 ? { prNumber } : {},
|
|
144
|
+
...commitRef !== void 0 ? { commitRef } : {},
|
|
101
145
|
users,
|
|
102
|
-
contentLines
|
|
146
|
+
contentLines,
|
|
147
|
+
breaking
|
|
103
148
|
};
|
|
104
149
|
}
|
|
105
150
|
function parseSummary(summary) {
|
|
@@ -107,29 +152,34 @@ function parseSummary(summary) {
|
|
|
107
152
|
prNumber,
|
|
108
153
|
commitRef,
|
|
109
154
|
users,
|
|
110
|
-
contentLines
|
|
155
|
+
contentLines,
|
|
156
|
+
breaking: bodyBreaking
|
|
111
157
|
} = extractSummaryMeta(summary);
|
|
112
158
|
const nonEmptyIndex = contentLines.findIndex((line) => line.trim().length > 0);
|
|
113
159
|
if (nonEmptyIndex === -1) {
|
|
114
160
|
return {
|
|
115
161
|
headline: "",
|
|
116
162
|
detailLines: [],
|
|
117
|
-
prNumber,
|
|
118
|
-
commitRef,
|
|
119
|
-
users
|
|
163
|
+
...prNumber !== void 0 ? { prNumber } : {},
|
|
164
|
+
...commitRef !== void 0 ? { commitRef } : {},
|
|
165
|
+
users,
|
|
166
|
+
breaking: bodyBreaking
|
|
120
167
|
};
|
|
121
168
|
}
|
|
122
|
-
const firstContentLine = contentLines[nonEmptyIndex].trim();
|
|
169
|
+
const firstContentLine = _nullishCoalesce(_optionalChain([contentLines, 'access', _ => _[nonEmptyIndex], 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]), () => ( ""));
|
|
123
170
|
const startsWithList = /^(?:[-*+]\s+|\d+[.)]\s+)/.test(firstContentLine);
|
|
124
171
|
const headline = startsWithList ? "" : firstContentLine;
|
|
125
172
|
const restLines = startsWithList ? contentLines.slice(nonEmptyIndex) : contentLines.slice(nonEmptyIndex + 1);
|
|
126
173
|
const detailLines = restLines;
|
|
174
|
+
const headlineParsed = headline ? parseConventionalHeadline(headline) : null;
|
|
175
|
+
const breaking = bodyBreaking || (_nullishCoalesce(_optionalChain([headlineParsed, 'optionalAccess', _4 => _4.breaking]), () => ( false)));
|
|
127
176
|
return {
|
|
128
177
|
headline,
|
|
129
178
|
detailLines,
|
|
130
|
-
prNumber,
|
|
131
|
-
commitRef,
|
|
132
|
-
users
|
|
179
|
+
...prNumber !== void 0 ? { prNumber } : {},
|
|
180
|
+
...commitRef !== void 0 ? { commitRef } : {},
|
|
181
|
+
users,
|
|
182
|
+
breaking
|
|
133
183
|
};
|
|
134
184
|
}
|
|
135
185
|
async function resolveLinks(repo, parsed, changesetCommit) {
|
|
@@ -164,7 +214,8 @@ function buildUserMentions(users, fallbackUser) {
|
|
|
164
214
|
}
|
|
165
215
|
if (fallbackUser) {
|
|
166
216
|
const match = fallbackUser.match(/@([^\]]+)/);
|
|
167
|
-
|
|
217
|
+
const matchedUser = _optionalChain([match, 'optionalAccess', _5 => _5[1]]);
|
|
218
|
+
return matchedUser ? normalizeUserMentions([matchedUser]) : "";
|
|
168
219
|
}
|
|
169
220
|
return "";
|
|
170
221
|
}
|
|
@@ -178,7 +229,7 @@ function indentMarkdownBlock(lines, spaces) {
|
|
|
178
229
|
}).join("\n");
|
|
179
230
|
}
|
|
180
231
|
function formatDetailBlock(detailLines) {
|
|
181
|
-
const trimmed = detailLines.join("\n").trim().split("\n").map((line) => line.
|
|
232
|
+
const trimmed = detailLines.join("\n").trim().split("\n").map((line) => line.trimEnd());
|
|
182
233
|
const hasFence = trimmed.some((line) => /^\s*```/.test(line));
|
|
183
234
|
const isListLike = trimmed.some((line) => /^\s*(?:[-*+]\s+|\d+[.)]\s+)/.test(line));
|
|
184
235
|
if (trimmed.length === 0) {
|
|
@@ -187,13 +238,16 @@ function formatDetailBlock(detailLines) {
|
|
|
187
238
|
if (hasFence || isListLike) {
|
|
188
239
|
return indentMarkdownBlock(trimmed, 2);
|
|
189
240
|
}
|
|
190
|
-
const paragraphs = trimmed.join("\n").split(/\n\s*\n/).
|
|
191
|
-
|
|
241
|
+
const paragraphs = trimmed.join("\n").split(/\n\s*\n/).filter((chunk) => chunk.trim().length > 0);
|
|
242
|
+
const lines = paragraphs.flatMap(
|
|
243
|
+
(chunk) => chunk.split("\n").map((line) => line.trim()).filter(Boolean)
|
|
244
|
+
);
|
|
245
|
+
return lines.map((text) => ` - ${text}`).join("\n");
|
|
192
246
|
}
|
|
193
247
|
var changelogFunctions = {
|
|
194
248
|
async getDependencyReleaseLine(changesets, dependenciesUpdated, options) {
|
|
195
249
|
assertRepo(options);
|
|
196
|
-
const
|
|
250
|
+
const repo = options.repo;
|
|
197
251
|
if (dependenciesUpdated.length === 0) {
|
|
198
252
|
return "";
|
|
199
253
|
}
|
|
@@ -205,7 +259,7 @@ var changelogFunctions = {
|
|
|
205
259
|
},
|
|
206
260
|
async getReleaseLine(changeset, type, options) {
|
|
207
261
|
assertRepo(options);
|
|
208
|
-
const
|
|
262
|
+
const repo = options.repo;
|
|
209
263
|
const parsedSummary = parseSummary(changeset.summary);
|
|
210
264
|
const resolvedType = resolveReleaseType(type);
|
|
211
265
|
const links = await resolveLinks(
|
|
@@ -217,10 +271,13 @@ var changelogFunctions = {
|
|
|
217
271
|
parsedSummary.users,
|
|
218
272
|
links.user
|
|
219
273
|
);
|
|
220
|
-
const headlineText = parsedSummary.headline
|
|
274
|
+
const { text: headlineText, breaking: headlineBreaking } = parsedSummary.headline ? formatHeadline(parsedSummary.headline) : { text: "Miscellaneous improvements", breaking: false };
|
|
275
|
+
const isBreaking = parsedSummary.breaking || headlineBreaking;
|
|
276
|
+
const breakingPrefix = isBreaking ? "\u26A0\uFE0F " : "";
|
|
277
|
+
const icon = isBreaking ? "\u{1F4A5}" : releaseTypeMap[resolvedType].icon;
|
|
221
278
|
const mainLineParts = [
|
|
222
|
-
`- ${
|
|
223
|
-
|
|
279
|
+
`- ${icon}`,
|
|
280
|
+
`${breakingPrefix}**${headlineText}**`
|
|
224
281
|
];
|
|
225
282
|
if (links.pull) {
|
|
226
283
|
mainLineParts.push(links.pull);
|
|
@@ -249,4 +306,6 @@ var { getDependencyReleaseLine, getReleaseLine } = changelogFunctions;
|
|
|
249
306
|
|
|
250
307
|
|
|
251
308
|
|
|
252
|
-
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
exports.default = index_default; exports.formatHeadline = formatHeadline; exports.getDependencyReleaseLine = getDependencyReleaseLine; exports.getReleaseLine = getReleaseLine; exports.parseConventionalHeadline = parseConventionalHeadline;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import * as _changesets_types from '@changesets/types';
|
|
2
2
|
import { ChangelogFunctions } from '@changesets/types';
|
|
3
3
|
|
|
4
|
+
interface ConventionalHeadline {
|
|
5
|
+
type?: string | undefined;
|
|
6
|
+
scope?: string | undefined;
|
|
7
|
+
breaking: boolean;
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
declare function parseConventionalHeadline(raw: string): ConventionalHeadline;
|
|
11
|
+
declare function formatHeadline(raw: string): {
|
|
12
|
+
text: string;
|
|
13
|
+
breaking: boolean;
|
|
14
|
+
};
|
|
4
15
|
declare const changelogFunctions: ChangelogFunctions;
|
|
5
16
|
|
|
6
17
|
declare const getDependencyReleaseLine: _changesets_types.GetDependencyReleaseLine;
|
|
@@ -8,4 +19,4 @@ declare const getReleaseLine: _changesets_types.GetReleaseLine;
|
|
|
8
19
|
|
|
9
20
|
// @ts-ignore
|
|
10
21
|
export = changelogFunctions;
|
|
11
|
-
export { getDependencyReleaseLine, getReleaseLine };
|
|
22
|
+
export { formatHeadline, getDependencyReleaseLine, getReleaseLine, parseConventionalHeadline };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import * as _changesets_types from '@changesets/types';
|
|
2
2
|
import { ChangelogFunctions } from '@changesets/types';
|
|
3
3
|
|
|
4
|
+
interface ConventionalHeadline {
|
|
5
|
+
type?: string | undefined;
|
|
6
|
+
scope?: string | undefined;
|
|
7
|
+
breaking: boolean;
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
declare function parseConventionalHeadline(raw: string): ConventionalHeadline;
|
|
11
|
+
declare function formatHeadline(raw: string): {
|
|
12
|
+
text: string;
|
|
13
|
+
breaking: boolean;
|
|
14
|
+
};
|
|
4
15
|
declare const changelogFunctions: ChangelogFunctions;
|
|
5
16
|
|
|
6
17
|
declare const getDependencyReleaseLine: _changesets_types.GetDependencyReleaseLine;
|
|
7
18
|
declare const getReleaseLine: _changesets_types.GetReleaseLine;
|
|
8
19
|
|
|
9
|
-
export { changelogFunctions as default, getDependencyReleaseLine, getReleaseLine };
|
|
20
|
+
export { changelogFunctions as default, formatHeadline, getDependencyReleaseLine, getReleaseLine, parseConventionalHeadline };
|
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ function resolveReleaseType(type) {
|
|
|
15
15
|
return "none";
|
|
16
16
|
}
|
|
17
17
|
function assertRepo(options) {
|
|
18
|
-
if (!options ||
|
|
18
|
+
if (!options || typeof options["repo"] !== "string" || options["repo"].trim().length === 0) {
|
|
19
19
|
throw new Error(
|
|
20
20
|
'Please provide a repo to this changelog generator like this:\n"changelog": ["@icebreakers/changelog-github", { "repo": "org/repo" }]'
|
|
21
21
|
);
|
|
@@ -34,7 +34,7 @@ async function collectDependencyReferences(changesets, repo) {
|
|
|
34
34
|
return links.commit;
|
|
35
35
|
})
|
|
36
36
|
);
|
|
37
|
-
return references.filter((link) => Boolean(link));
|
|
37
|
+
return [...new Set(references.filter((link) => Boolean(link)))];
|
|
38
38
|
}
|
|
39
39
|
function formatDependencyLine(references, dependenciesUpdated) {
|
|
40
40
|
const count = dependenciesUpdated.length;
|
|
@@ -42,16 +42,53 @@ function formatDependencyLine(references, dependenciesUpdated) {
|
|
|
42
42
|
if (count === 0) {
|
|
43
43
|
return firstCommit ? `- \u{1F4E6} **Dependencies** ${firstCommit}` : "- \u{1F4E6} **Dependencies**";
|
|
44
44
|
}
|
|
45
|
+
const dependencySummaries = dependenciesUpdated.map(
|
|
46
|
+
(dependency) => `\`${dependency.name}@${dependency.newVersion}\``
|
|
47
|
+
);
|
|
45
48
|
if (count <= 3) {
|
|
46
|
-
const
|
|
47
|
-
(dependency) => `\`${dependency.name}@${dependency.newVersion}\``
|
|
48
|
-
);
|
|
49
|
-
const header = firstCommit ? `- \u{1F4E6} **Dependencies** ${firstCommit}` : "- \u{1F4E6} **Dependencies**";
|
|
49
|
+
const header2 = firstCommit ? `- \u{1F4E6} **Dependencies** ${firstCommit}` : "- \u{1F4E6} **Dependencies**";
|
|
50
50
|
const details = ` \u2192 ${dependencySummaries.join(", ")}`;
|
|
51
|
-
return `${
|
|
51
|
+
return `${header2}
|
|
52
52
|
${details}`;
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
const header = firstCommit ? `- \u{1F4E6} Updated ${count} dependencies ${firstCommit}` : `- \u{1F4E6} Updated ${count} dependencies`;
|
|
55
|
+
const detailBlock = [
|
|
56
|
+
" <details><summary>Details</summary>",
|
|
57
|
+
"",
|
|
58
|
+
` ${dependencySummaries.join(", ")}`,
|
|
59
|
+
"",
|
|
60
|
+
" </details>"
|
|
61
|
+
].join("\n");
|
|
62
|
+
return `${header}
|
|
63
|
+
${detailBlock}`;
|
|
64
|
+
}
|
|
65
|
+
function parseConventionalHeadline(raw) {
|
|
66
|
+
const match = raw.match(
|
|
67
|
+
/^(\w+)(?:\(([^)]*)\))?(!?):\s(.+)$/
|
|
68
|
+
);
|
|
69
|
+
if (!match) {
|
|
70
|
+
return { breaking: false, description: raw };
|
|
71
|
+
}
|
|
72
|
+
const type = match[1];
|
|
73
|
+
const scope = match[2] || void 0;
|
|
74
|
+
const description = (match[4] ?? raw).trim();
|
|
75
|
+
return {
|
|
76
|
+
type,
|
|
77
|
+
scope,
|
|
78
|
+
breaking: match[3] === "!",
|
|
79
|
+
description
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function formatHeadline(raw) {
|
|
83
|
+
const parsed = parseConventionalHeadline(raw);
|
|
84
|
+
if (!parsed.type) {
|
|
85
|
+
return { text: raw, breaking: parsed.breaking };
|
|
86
|
+
}
|
|
87
|
+
const scopeTag = parsed.scope ? `${parsed.scope}: ` : "";
|
|
88
|
+
return {
|
|
89
|
+
text: `${scopeTag}${parsed.description}`,
|
|
90
|
+
breaking: parsed.breaking
|
|
91
|
+
};
|
|
55
92
|
}
|
|
56
93
|
function normalizeUserMentions(users) {
|
|
57
94
|
const normalized = users.map((user) => user.trim()).filter(Boolean).map((user) => user.startsWith("@") ? user : `@${user}`);
|
|
@@ -59,16 +96,17 @@ function normalizeUserMentions(users) {
|
|
|
59
96
|
return "";
|
|
60
97
|
}
|
|
61
98
|
if (normalized.length === 1) {
|
|
62
|
-
return normalized[0];
|
|
99
|
+
return normalized[0] ?? "";
|
|
63
100
|
}
|
|
64
101
|
if (normalized.length === 2) {
|
|
65
|
-
return `${normalized[0]} and ${normalized[1]}`;
|
|
102
|
+
return `${normalized[0] ?? ""} and ${normalized[1] ?? ""}`;
|
|
66
103
|
}
|
|
67
|
-
return `${normalized.slice(0, -1).join(", ")}, and ${normalized.at(-1)}`;
|
|
104
|
+
return `${normalized.slice(0, -1).join(", ")}, and ${normalized.at(-1) ?? ""}`;
|
|
68
105
|
}
|
|
69
106
|
function extractSummaryMeta(summary) {
|
|
70
107
|
let prNumber;
|
|
71
108
|
let commitRef;
|
|
109
|
+
let breaking = false;
|
|
72
110
|
const users = [];
|
|
73
111
|
const contentLines = summary.split(/\r?\n/).filter((line) => {
|
|
74
112
|
const trimmed = line.trim();
|
|
@@ -77,7 +115,7 @@ function extractSummaryMeta(summary) {
|
|
|
77
115
|
/^(?:pr|pull|pull\s*request):\s*#?(\d+)\s*$/i
|
|
78
116
|
);
|
|
79
117
|
if (prMatch) {
|
|
80
|
-
const num = Number(prMatch[1]);
|
|
118
|
+
const num = Number(prMatch[1] ?? Number.NaN);
|
|
81
119
|
if (!Number.isNaN(num)) {
|
|
82
120
|
prNumber = num;
|
|
83
121
|
}
|
|
@@ -90,16 +128,23 @@ function extractSummaryMeta(summary) {
|
|
|
90
128
|
}
|
|
91
129
|
const userMatch = withoutListMarker.match(/^(?:author|user):\s*(\S+)\s*$/i);
|
|
92
130
|
if (userMatch) {
|
|
93
|
-
|
|
131
|
+
const user = userMatch[1];
|
|
132
|
+
if (user) {
|
|
133
|
+
users.push(user.replace(/^@/, ""));
|
|
134
|
+
}
|
|
94
135
|
return false;
|
|
95
136
|
}
|
|
137
|
+
if (/^BREAKING[\s-]CHANGE:/i.test(withoutListMarker)) {
|
|
138
|
+
breaking = true;
|
|
139
|
+
}
|
|
96
140
|
return true;
|
|
97
|
-
}).map((line) => line.
|
|
141
|
+
}).map((line) => line.trimEnd());
|
|
98
142
|
return {
|
|
99
|
-
prNumber,
|
|
100
|
-
commitRef,
|
|
143
|
+
...prNumber !== void 0 ? { prNumber } : {},
|
|
144
|
+
...commitRef !== void 0 ? { commitRef } : {},
|
|
101
145
|
users,
|
|
102
|
-
contentLines
|
|
146
|
+
contentLines,
|
|
147
|
+
breaking
|
|
103
148
|
};
|
|
104
149
|
}
|
|
105
150
|
function parseSummary(summary) {
|
|
@@ -107,29 +152,34 @@ function parseSummary(summary) {
|
|
|
107
152
|
prNumber,
|
|
108
153
|
commitRef,
|
|
109
154
|
users,
|
|
110
|
-
contentLines
|
|
155
|
+
contentLines,
|
|
156
|
+
breaking: bodyBreaking
|
|
111
157
|
} = extractSummaryMeta(summary);
|
|
112
158
|
const nonEmptyIndex = contentLines.findIndex((line) => line.trim().length > 0);
|
|
113
159
|
if (nonEmptyIndex === -1) {
|
|
114
160
|
return {
|
|
115
161
|
headline: "",
|
|
116
162
|
detailLines: [],
|
|
117
|
-
prNumber,
|
|
118
|
-
commitRef,
|
|
119
|
-
users
|
|
163
|
+
...prNumber !== void 0 ? { prNumber } : {},
|
|
164
|
+
...commitRef !== void 0 ? { commitRef } : {},
|
|
165
|
+
users,
|
|
166
|
+
breaking: bodyBreaking
|
|
120
167
|
};
|
|
121
168
|
}
|
|
122
|
-
const firstContentLine = contentLines[nonEmptyIndex]
|
|
169
|
+
const firstContentLine = contentLines[nonEmptyIndex]?.trim() ?? "";
|
|
123
170
|
const startsWithList = /^(?:[-*+]\s+|\d+[.)]\s+)/.test(firstContentLine);
|
|
124
171
|
const headline = startsWithList ? "" : firstContentLine;
|
|
125
172
|
const restLines = startsWithList ? contentLines.slice(nonEmptyIndex) : contentLines.slice(nonEmptyIndex + 1);
|
|
126
173
|
const detailLines = restLines;
|
|
174
|
+
const headlineParsed = headline ? parseConventionalHeadline(headline) : null;
|
|
175
|
+
const breaking = bodyBreaking || (headlineParsed?.breaking ?? false);
|
|
127
176
|
return {
|
|
128
177
|
headline,
|
|
129
178
|
detailLines,
|
|
130
|
-
prNumber,
|
|
131
|
-
commitRef,
|
|
132
|
-
users
|
|
179
|
+
...prNumber !== void 0 ? { prNumber } : {},
|
|
180
|
+
...commitRef !== void 0 ? { commitRef } : {},
|
|
181
|
+
users,
|
|
182
|
+
breaking
|
|
133
183
|
};
|
|
134
184
|
}
|
|
135
185
|
async function resolveLinks(repo, parsed, changesetCommit) {
|
|
@@ -164,7 +214,8 @@ function buildUserMentions(users, fallbackUser) {
|
|
|
164
214
|
}
|
|
165
215
|
if (fallbackUser) {
|
|
166
216
|
const match = fallbackUser.match(/@([^\]]+)/);
|
|
167
|
-
|
|
217
|
+
const matchedUser = match?.[1];
|
|
218
|
+
return matchedUser ? normalizeUserMentions([matchedUser]) : "";
|
|
168
219
|
}
|
|
169
220
|
return "";
|
|
170
221
|
}
|
|
@@ -178,7 +229,7 @@ function indentMarkdownBlock(lines, spaces) {
|
|
|
178
229
|
}).join("\n");
|
|
179
230
|
}
|
|
180
231
|
function formatDetailBlock(detailLines) {
|
|
181
|
-
const trimmed = detailLines.join("\n").trim().split("\n").map((line) => line.
|
|
232
|
+
const trimmed = detailLines.join("\n").trim().split("\n").map((line) => line.trimEnd());
|
|
182
233
|
const hasFence = trimmed.some((line) => /^\s*```/.test(line));
|
|
183
234
|
const isListLike = trimmed.some((line) => /^\s*(?:[-*+]\s+|\d+[.)]\s+)/.test(line));
|
|
184
235
|
if (trimmed.length === 0) {
|
|
@@ -187,13 +238,16 @@ function formatDetailBlock(detailLines) {
|
|
|
187
238
|
if (hasFence || isListLike) {
|
|
188
239
|
return indentMarkdownBlock(trimmed, 2);
|
|
189
240
|
}
|
|
190
|
-
const paragraphs = trimmed.join("\n").split(/\n\s*\n/).
|
|
191
|
-
|
|
241
|
+
const paragraphs = trimmed.join("\n").split(/\n\s*\n/).filter((chunk) => chunk.trim().length > 0);
|
|
242
|
+
const lines = paragraphs.flatMap(
|
|
243
|
+
(chunk) => chunk.split("\n").map((line) => line.trim()).filter(Boolean)
|
|
244
|
+
);
|
|
245
|
+
return lines.map((text) => ` - ${text}`).join("\n");
|
|
192
246
|
}
|
|
193
247
|
var changelogFunctions = {
|
|
194
248
|
async getDependencyReleaseLine(changesets, dependenciesUpdated, options) {
|
|
195
249
|
assertRepo(options);
|
|
196
|
-
const
|
|
250
|
+
const repo = options.repo;
|
|
197
251
|
if (dependenciesUpdated.length === 0) {
|
|
198
252
|
return "";
|
|
199
253
|
}
|
|
@@ -205,7 +259,7 @@ var changelogFunctions = {
|
|
|
205
259
|
},
|
|
206
260
|
async getReleaseLine(changeset, type, options) {
|
|
207
261
|
assertRepo(options);
|
|
208
|
-
const
|
|
262
|
+
const repo = options.repo;
|
|
209
263
|
const parsedSummary = parseSummary(changeset.summary);
|
|
210
264
|
const resolvedType = resolveReleaseType(type);
|
|
211
265
|
const links = await resolveLinks(
|
|
@@ -217,10 +271,13 @@ var changelogFunctions = {
|
|
|
217
271
|
parsedSummary.users,
|
|
218
272
|
links.user
|
|
219
273
|
);
|
|
220
|
-
const headlineText = parsedSummary.headline
|
|
274
|
+
const { text: headlineText, breaking: headlineBreaking } = parsedSummary.headline ? formatHeadline(parsedSummary.headline) : { text: "Miscellaneous improvements", breaking: false };
|
|
275
|
+
const isBreaking = parsedSummary.breaking || headlineBreaking;
|
|
276
|
+
const breakingPrefix = isBreaking ? "\u26A0\uFE0F " : "";
|
|
277
|
+
const icon = isBreaking ? "\u{1F4A5}" : releaseTypeMap[resolvedType].icon;
|
|
221
278
|
const mainLineParts = [
|
|
222
|
-
`- ${
|
|
223
|
-
|
|
279
|
+
`- ${icon}`,
|
|
280
|
+
`${breakingPrefix}**${headlineText}**`
|
|
224
281
|
];
|
|
225
282
|
if (links.pull) {
|
|
226
283
|
mainLineParts.push(links.pull);
|
|
@@ -247,6 +304,8 @@ var index_default = changelogFunctions;
|
|
|
247
304
|
var { getDependencyReleaseLine, getReleaseLine } = changelogFunctions;
|
|
248
305
|
export {
|
|
249
306
|
index_default as default,
|
|
307
|
+
formatHeadline,
|
|
250
308
|
getDependencyReleaseLine,
|
|
251
|
-
getReleaseLine
|
|
309
|
+
getReleaseLine,
|
|
310
|
+
parseConventionalHeadline
|
|
252
311
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icebreakers/changelog-github",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Changesets GitHub changelog formatter for Icebreaker's dev-configs",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"dist"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@changesets/get-github-info": "^0.
|
|
37
|
+
"@changesets/get-github-info": "^0.8.0",
|
|
38
38
|
"@changesets/types": "^6.1.0",
|
|
39
|
-
"dotenv": "^17.
|
|
39
|
+
"dotenv": "^17.3.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@changesets/parse": "^0.4.
|
|
42
|
+
"@changesets/parse": "^0.4.3"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"stub": "unbuild --stub",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"test:dev": "vitest",
|
|
50
50
|
"release": "pnpm publish",
|
|
51
51
|
"lint": "eslint .",
|
|
52
|
-
"lint:fix": "eslint . --fix"
|
|
52
|
+
"lint:fix": "eslint . --fix",
|
|
53
|
+
"typecheck": "tsc --noEmit"
|
|
53
54
|
}
|
|
54
55
|
}
|