@savvy-web/changesets 0.5.0 → 0.5.2

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/cjs/index.d.cts CHANGED
@@ -14,7 +14,6 @@
14
14
 
15
15
  import { Context } from 'effect';
16
16
  import { Effect } from 'effect';
17
- import { Equals } from 'effect/Types';
18
17
  import { Layer } from 'effect';
19
18
  import { ModCompWithPackage } from '@changesets/types';
20
19
  import { NewChangesetWithCommit } from '@changesets/types';
@@ -22,6 +21,7 @@ import type { Root } from 'mdast';
22
21
  import { Schema } from 'effect';
23
22
  import type { Table } from 'mdast';
24
23
  import { VersionType as VersionType_2 } from '@changesets/types';
24
+ import { VoidIfEmpty } from 'effect/Types';
25
25
  import { YieldableError } from 'effect/Cause';
26
26
 
27
27
  /**
@@ -889,7 +889,7 @@ export declare class ChangesetValidationError extends ChangesetValidationErrorBa
889
889
  *
890
890
  * @internal
891
891
  */
892
- export declare const ChangesetValidationErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
892
+ export declare const ChangesetValidationErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
893
893
  readonly _tag: "ChangesetValidationError";
894
894
  } & Readonly<A>;
895
895
 
@@ -974,7 +974,7 @@ export declare class ConfigurationError extends ConfigurationErrorBase<{
974
974
  *
975
975
  * @internal
976
976
  */
977
- export declare const ConfigurationErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
977
+ export declare const ConfigurationErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
978
978
  readonly _tag: "ConfigurationError";
979
979
  } & Readonly<A>;
980
980
 
@@ -1445,7 +1445,7 @@ export declare class GitHubApiError extends GitHubApiErrorBase<{
1445
1445
  *
1446
1446
  * @internal
1447
1447
  */
1448
- export declare const GitHubApiErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
1448
+ export declare const GitHubApiErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
1449
1449
  readonly _tag: "GitHubApiError";
1450
1450
  } & Readonly<A>;
1451
1451
 
@@ -1936,7 +1936,7 @@ export declare class MarkdownParseError extends MarkdownParseErrorBase<{
1936
1936
  *
1937
1937
  * @internal
1938
1938
  */
1939
- export declare const MarkdownParseErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
1939
+ export declare const MarkdownParseErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
1940
1940
  readonly _tag: "MarkdownParseError";
1941
1941
  } & Readonly<A>;
1942
1942
 
@@ -2320,7 +2320,7 @@ export declare class VersionFileError extends VersionFileErrorBase<{
2320
2320
  *
2321
2321
  * @internal
2322
2322
  */
2323
- export declare const VersionFileErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
2323
+ export declare const VersionFileErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
2324
2324
  readonly _tag: "VersionFileError";
2325
2325
  } & Readonly<A>;
2326
2326
 
@@ -1,8 +1,10 @@
1
- import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
2
- import { join, relative, resolve } from "node:path";
3
- import { remark_parse } from "./725.js";
4
- import { unified, remark_stringify, remark_gfm } from "./855.js";
5
- import { UncategorizedContentRule, MergeSectionsPlugin, DeduplicateItemsPlugin, IssueLinkRefsPlugin, ContentStructureRule, HeadingHierarchyRule, NormalizeFormatPlugin, ReorderSectionsPlugin, ContributorFootnotesPlugin, RequiredSectionsRule } from "./622.js";
1
+ import { readFileSync, readdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import remark_parse from "remark-parse";
4
+ import remark_stringify from "remark-stringify";
5
+ import { unified } from "unified";
6
+ import remark_gfm from "remark-gfm";
7
+ import { UncategorizedContentRule, MergeSectionsPlugin, DeduplicateItemsPlugin, IssueLinkRefsPlugin, ContentStructureRule, HeadingHierarchyRule, NormalizeFormatPlugin, ReorderSectionsPlugin, ContributorFootnotesPlugin, RequiredSectionsRule } from "./448.js";
6
8
  function stripFrontmatter(content) {
7
9
  return content.replace(/^---\n[\s\S]*?\n---\n?/, "");
8
10
  }
@@ -39,4 +41,4 @@ class ChangelogTransformer {
39
41
  writeFileSync(filePath, result, "utf-8");
40
42
  }
41
43
  }
42
- export { ChangelogTransformer, ChangesetLinter, existsSync, join, mkdirSync, readFileSync, relative, resolve, writeFileSync };
44
+ export { ChangelogTransformer, ChangesetLinter };
@@ -1,4 +1,8 @@
1
- import { external_mdast_util_to_string_toString, unified, Schema, remark_gfm, remark_stringify } from "./855.js";
1
+ import { Schema } from "effect";
2
+ import { toString as external_mdast_util_to_string_toString } from "mdast-util-to-string";
3
+ import remark_gfm from "remark-gfm";
4
+ import remark_stringify from "remark-stringify";
5
+ import { unified } from "unified";
2
6
  const NonEmptyString = Schema.String.pipe(Schema.minLength(1));
3
7
  const PositiveInteger = Schema.Number.pipe(Schema.int(), Schema.positive());
4
8
  const DependencyActionSchema = Schema.Literal("added", "updated", "removed");
@@ -1,8 +1,8 @@
1
+ import { toString as external_mdast_util_to_string_toString } from "mdast-util-to-string";
1
2
  import { lintRule } from "unified-lint-rule";
2
3
  import { SKIP, visit } from "unist-util-visit";
3
- import { external_mdast_util_to_string_toString } from "./855.js";
4
- import { RULE_DOCS } from "./260.js";
5
- import { isValidHeading, fromHeading, allHeadings } from "./60.js";
4
+ import { RULE_DOCS } from "./486.js";
5
+ import { isValidHeading, fromHeading, allHeadings } from "./286.js";
6
6
  const ContentStructureRule = lintRule("remark-lint:changeset-content-structure", (tree, file)=>{
7
7
  visit(tree, "heading", (node, index, parent)=>{
8
8
  if (2 !== node.depth || null == parent || null == index) return;
@@ -348,4 +348,4 @@ const ReorderSectionsPlugin = ()=>(tree)=>{
348
348
  tree.children.splice(block.startIndex, blockLength, ...newChildren);
349
349
  }
350
350
  };
351
- export { ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, HeadingHierarchyRule, IssueLinkRefsPlugin, MergeSectionsPlugin, NormalizeFormatPlugin, ReorderSectionsPlugin, RequiredSectionsRule, UncategorizedContentRule, getBlockSections, getHeadingText, getVersionBlocks, lintRule, visit };
351
+ export { ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, HeadingHierarchyRule, IssueLinkRefsPlugin, MergeSectionsPlugin, NormalizeFormatPlugin, ReorderSectionsPlugin, RequiredSectionsRule, UncategorizedContentRule, getBlockSections, getHeadingText, getVersionBlocks };
@@ -1,4 +1,4 @@
1
- import { Data, Schema } from "./855.js";
1
+ import { Data, Schema } from "effect";
2
2
  const ChangesetValidationErrorBase = Data.TaggedError("ChangesetValidationError");
3
3
  class ChangesetValidationError extends ChangesetValidationErrorBase {
4
4
  get message() {
@@ -49,5 +49,4 @@ const VersionFileConfigSchema = Schema.Struct({
49
49
  paths: Schema.optional(Schema.Array(JsonPathSchema))
50
50
  });
51
51
  const VersionFilesSchema = Schema.Array(VersionFileConfigSchema);
52
- export { default as remark_parse } from "remark-parse";
53
52
  export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema };
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { Args, Command, Options } from "@effect/cli";
3
3
  import { NodeContext, NodeRuntime } from "@effect/platform-node";
4
+ import { Data, Effect, Schema } from "effect";
5
+ import { join, relative, resolve } from "node:path";
4
6
  import { execSync } from "node:child_process";
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
8
  import { applyEdits, modify, parse } from "jsonc-parser";
6
9
  import { findProjectRoot, getWorkspaceInfos } from "workspace-tools";
7
10
  import { globSync } from "tinyglobby";
8
- import { readFileSync, ChangelogTransformer, ChangesetLinter, resolve, existsSync, relative, mkdirSync, writeFileSync, join } from "../273.js";
9
- import { Effect, Schema, Data } from "../855.js";
10
- import { VersionFileError, VersionFilesSchema } from "../725.js";
11
+ import { ChangesetLinter, ChangelogTransformer } from "../245.js";
12
+ import { VersionFileError, VersionFilesSchema } from "../514.js";
11
13
  const dirArg = Args.directory({
12
14
  name: "dir"
13
15
  }).pipe(Args.withDefault(".changeset"));
@@ -787,7 +789,7 @@ const rootCommand = Command.make("savvy-changesets").pipe(Command.withSubcommand
787
789
  ]));
788
790
  const cli = Command.run(rootCommand, {
789
791
  name: "savvy-changesets",
790
- version: "0.5.0"
792
+ version: "0.5.2"
791
793
  });
792
794
  function runCli() {
793
795
  const main = Effect.suspend(()=>cli(process.argv)).pipe(Effect.provide(NodeContext.layer));
package/esm/changelog.js CHANGED
@@ -1 +1,382 @@
1
- export { default } from "./160.js";
1
+ import { Context, Effect, Layer, Schema } from "effect";
2
+ import { getInfo } from "@changesets/get-github-info";
3
+ import remark_gfm from "remark-gfm";
4
+ import remark_parse from "remark-parse";
5
+ import remark_stringify from "remark-stringify";
6
+ import { unified } from "unified";
7
+ import { toString as external_mdast_util_to_string_toString } from "mdast-util-to-string";
8
+ import { GitHubApiError, ConfigurationError, VersionFilesSchema } from "./514.js";
9
+ import { PositiveInteger, serializeDependencyTableToMarkdown } from "./345.js";
10
+ import { resolveCommitType, fromHeading } from "./286.js";
11
+ const REPO_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/;
12
+ const RepoSchema = Schema.String.pipe(Schema.pattern(REPO_PATTERN, {
13
+ message: ()=>'Repository must be in format "owner/repository" (e.g., "microsoft/vscode")'
14
+ }));
15
+ const ChangesetOptionsSchema = Schema.Struct({
16
+ repo: RepoSchema,
17
+ commitLinks: Schema.optional(Schema.Boolean),
18
+ prLinks: Schema.optional(Schema.Boolean),
19
+ issueLinks: Schema.optional(Schema.Boolean),
20
+ issuePrefixes: Schema.optional(Schema.Array(Schema.String)),
21
+ versionFiles: Schema.optional(VersionFilesSchema)
22
+ });
23
+ function validateChangesetOptions(input) {
24
+ if (null == input) return Effect.fail(new ConfigurationError({
25
+ field: "options",
26
+ reason: 'Configuration is required. Add options to your changesets config:\n"changelog": ["@savvy-web/changesets", { "repo": "owner/repository" }]'
27
+ }));
28
+ if ("object" != typeof input) return Effect.fail(new ConfigurationError({
29
+ field: "options",
30
+ reason: "Configuration must be an object"
31
+ }));
32
+ const obj = input;
33
+ if (!("repo" in obj) || void 0 === obj.repo) return Effect.fail(new ConfigurationError({
34
+ field: "repo",
35
+ reason: 'Repository name is required. Add the "repo" option to your changesets config:\n"changelog": ["@savvy-web/changesets", { "repo": "owner/repository" }]'
36
+ }));
37
+ if ("string" == typeof obj.repo && !REPO_PATTERN.test(obj.repo)) return Effect.fail(new ConfigurationError({
38
+ field: "repo",
39
+ reason: `Invalid repository format: "${obj.repo}". Expected format is "owner/repository" (e.g., "microsoft/vscode")`
40
+ }));
41
+ return Schema.decodeUnknown(ChangesetOptionsSchema)(input).pipe(Effect.mapError((parseError)=>new ConfigurationError({
42
+ field: "options",
43
+ reason: String(parseError)
44
+ })));
45
+ }
46
+ function getGitHubInfo(params) {
47
+ return Effect.tryPromise({
48
+ try: ()=>getInfo({
49
+ commit: params.commit,
50
+ repo: params.repo
51
+ }),
52
+ catch: (error)=>new GitHubApiError({
53
+ operation: "getInfo",
54
+ reason: error instanceof Error ? error.message : String(error)
55
+ })
56
+ });
57
+ }
58
+ const _tag = Context.Tag("GitHubService");
59
+ const GitHubServiceBase = _tag();
60
+ class GitHubService extends GitHubServiceBase {
61
+ }
62
+ const GitHubLive = Layer.succeed(GitHubService, {
63
+ getInfo: getGitHubInfo
64
+ });
65
+ function makeGitHubTest(responses) {
66
+ return Layer.succeed(GitHubService, {
67
+ getInfo: (params)=>{
68
+ const info = responses.get(params.commit);
69
+ if (info) return Effect.succeed(info);
70
+ return Effect.fail(new GitHubApiError({
71
+ operation: "getInfo",
72
+ reason: `No mock response for commit ${params.commit}`
73
+ }));
74
+ }
75
+ });
76
+ }
77
+ function createRemarkProcessor() {
78
+ return unified().use(remark_parse).use(remark_gfm).use(remark_stringify);
79
+ }
80
+ function parseMarkdown(content) {
81
+ const processor = createRemarkProcessor();
82
+ return processor.parse(content);
83
+ }
84
+ function stringifyMarkdown(tree) {
85
+ const processor = createRemarkProcessor();
86
+ return processor.stringify(tree);
87
+ }
88
+ const markdown_tag = Context.Tag("MarkdownService");
89
+ const MarkdownServiceBase = markdown_tag();
90
+ class MarkdownService extends MarkdownServiceBase {
91
+ }
92
+ const MarkdownLive = Layer.succeed(MarkdownService, {
93
+ parse: (content)=>Effect.sync(()=>parseMarkdown(content)),
94
+ stringify: (tree)=>Effect.sync(()=>stringifyMarkdown(tree))
95
+ });
96
+ const FIELD_MAP = [
97
+ [
98
+ "dependencies",
99
+ "dependency"
100
+ ],
101
+ [
102
+ "devDependencies",
103
+ "devDependency"
104
+ ],
105
+ [
106
+ "peerDependencies",
107
+ "peerDependency"
108
+ ],
109
+ [
110
+ "optionalDependencies",
111
+ "optionalDependency"
112
+ ]
113
+ ];
114
+ function inferDependencyType(dep) {
115
+ const pkg = dep.packageJson;
116
+ for (const [field, type] of FIELD_MAP){
117
+ const section = pkg[field];
118
+ if ("object" == typeof section && null !== section && dep.name in section) return type;
119
+ }
120
+ return "dependency";
121
+ }
122
+ function getDependencyReleaseLine(_changesets, dependenciesUpdated, _options) {
123
+ return Effect.gen(function*() {
124
+ if (0 === dependenciesUpdated.length) return "";
125
+ yield* GitHubService;
126
+ const rows = dependenciesUpdated.map((dep)=>({
127
+ dependency: dep.name,
128
+ type: inferDependencyType(dep),
129
+ action: "updated",
130
+ from: dep.oldVersion,
131
+ to: dep.newVersion
132
+ }));
133
+ return serializeDependencyTableToMarkdown(rows);
134
+ });
135
+ }
136
+ const MARKDOWN_LINK_PATTERN = /\[([^\]]+)\]\(([^)]+)\)/;
137
+ function extractUrlFromMarkdown(linkOrUrl) {
138
+ const match = MARKDOWN_LINK_PATTERN.exec(linkOrUrl);
139
+ return match ? match[2] : linkOrUrl;
140
+ }
141
+ function isValidUrl(value) {
142
+ try {
143
+ new URL(value);
144
+ return true;
145
+ } catch {
146
+ return false;
147
+ }
148
+ }
149
+ const UsernameSchema = Schema.String.pipe(Schema.pattern(/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/, {
150
+ message: ()=>'Invalid GitHub username format. Usernames must contain only alphanumeric characters and hyphens, and cannot start or end with a hyphen. Example: "octocat" or "my-user-123"'
151
+ }));
152
+ const IssueNumberSchema = PositiveInteger.annotations({
153
+ title: "IssueNumber",
154
+ description: "GitHub issue or pull request number"
155
+ });
156
+ const UrlOrMarkdownLinkSchema = Schema.String.pipe(Schema.filter((value)=>{
157
+ if (isValidUrl(value)) return true;
158
+ const match = MARKDOWN_LINK_PATTERN.exec(value);
159
+ return match?.[2] ? isValidUrl(match[2]) : false;
160
+ }, {
161
+ message: ()=>'Value must be a valid URL or a markdown link. Expected a plain URL (e.g., "https://github.com/owner/repo/pull/42") or a markdown link (e.g., "[#42](https://github.com/owner/repo/pull/42)")'
162
+ }));
163
+ const GitHubInfoSchema = Schema.Struct({
164
+ user: Schema.optional(UsernameSchema),
165
+ pull: Schema.optional(IssueNumberSchema),
166
+ links: Schema.Struct({
167
+ commit: UrlOrMarkdownLinkSchema,
168
+ pull: Schema.optional(UrlOrMarkdownLinkSchema),
169
+ user: Schema.optional(UrlOrMarkdownLinkSchema)
170
+ })
171
+ });
172
+ const CONVENTIONAL_COMMIT_PATTERN = /^(\w+)(?:\(([^)]+)\))?(!)?\s*:\s*(.+)/;
173
+ function parseCommitMessage(message) {
174
+ const match = CONVENTIONAL_COMMIT_PATTERN.exec(message);
175
+ if (match) {
176
+ const [, type, scope, bang, description] = match;
177
+ const lines = message.split("\n");
178
+ const body = lines.slice(1).join("\n").trim();
179
+ const result = {
180
+ type,
181
+ description: description.trim()
182
+ };
183
+ if (scope) result.scope = scope;
184
+ if ("!" === bang) result.breaking = true;
185
+ if (body) result.body = body;
186
+ return result;
187
+ }
188
+ return {
189
+ description: message
190
+ };
191
+ }
192
+ const CLOSES_ISSUE_PATTERN = /closes?:?\s*#?(\d+(?:, *#?\d+)*)/i;
193
+ const FIXES_ISSUE_PATTERN = /fix(?:es)?:?\s*#?(\d+(?:, *#?\d+)*)/i;
194
+ const REFS_ISSUE_PATTERN = /refs?:?\s*#?(\d+(?:, *#?\d+)*)/i;
195
+ const ISSUE_NUMBER_SPLIT_PATTERN = /, */;
196
+ function extractIssueNumbers(pattern, message) {
197
+ const safeMessage = message.slice(0, 10000);
198
+ const match = pattern.exec(safeMessage);
199
+ if (!match?.[1]) return [];
200
+ return match[1].split(ISSUE_NUMBER_SPLIT_PATTERN).map((num)=>num.replace("#", "").trim());
201
+ }
202
+ function parseIssueReferences(commitMessage) {
203
+ return {
204
+ closes: extractIssueNumbers(CLOSES_ISSUE_PATTERN, commitMessage),
205
+ fixes: extractIssueNumbers(FIXES_ISSUE_PATTERN, commitMessage),
206
+ refs: extractIssueNumbers(REFS_ISSUE_PATTERN, commitMessage)
207
+ };
208
+ }
209
+ function logWarning(message, ...args) {
210
+ if ("u" > typeof process && process.env.VITEST) return;
211
+ if ("u" > typeof process && "true" === process.env.GITHUB_ACTIONS) {
212
+ const text = args.length > 0 ? `${message} ${args.join(" ")}` : message;
213
+ console.warn(`::warning::${text}`);
214
+ } else console.warn(message, ...args);
215
+ }
216
+ function parseChangesetSections(summary) {
217
+ const tree = parseMarkdown(summary);
218
+ const h2Indices = [];
219
+ for(let i = 0; i < tree.children.length; i++){
220
+ const node = tree.children[i];
221
+ if ("heading" === node.type && 2 === node.depth) h2Indices.push(i);
222
+ }
223
+ if (0 === h2Indices.length) return {
224
+ preamble: summary.trim(),
225
+ sections: []
226
+ };
227
+ const result = {
228
+ sections: []
229
+ };
230
+ if (h2Indices[0] > 0) {
231
+ const preambleNodes = tree.children.slice(0, h2Indices[0]);
232
+ result.preamble = stringifyAstSlice(preambleNodes);
233
+ }
234
+ for(let i = 0; i < h2Indices.length; i++){
235
+ const headingIndex = h2Indices[i];
236
+ const headingNode = tree.children[headingIndex];
237
+ const headingText = external_mdast_util_to_string_toString(headingNode);
238
+ const nextIndex = i + 1 < h2Indices.length ? h2Indices[i + 1] : tree.children.length;
239
+ const contentNodes = tree.children.slice(headingIndex + 1, nextIndex);
240
+ const content = stringifyAstSlice(contentNodes);
241
+ const category = fromHeading(headingText);
242
+ if (category) result.sections.push({
243
+ category,
244
+ heading: headingText,
245
+ content
246
+ });
247
+ }
248
+ return result;
249
+ }
250
+ function stringifyAstSlice(nodes) {
251
+ if (0 === nodes.length) return "";
252
+ const root = {
253
+ type: "root",
254
+ children: nodes
255
+ };
256
+ return stringifyMarkdown(root).trim();
257
+ }
258
+ const ISSUE_CATEGORIES = [
259
+ {
260
+ key: "closes",
261
+ label: "Closes"
262
+ },
263
+ {
264
+ key: "fixes",
265
+ label: "Fixes"
266
+ },
267
+ {
268
+ key: "refs",
269
+ label: "Refs"
270
+ }
271
+ ];
272
+ function formatChangelogEntry(entry, options) {
273
+ const parts = [];
274
+ if (entry.commit) {
275
+ const shortHash = entry.commit.substring(0, 7);
276
+ parts.push(`[\`${shortHash}\`](https://github.com/${options.repo}/commit/${entry.commit})`);
277
+ }
278
+ parts.push(entry.summary.trim());
279
+ const issueLinks = [];
280
+ for (const { key, label } of ISSUE_CATEGORIES){
281
+ const numbers = entry.issues[key];
282
+ if (numbers.length > 0) {
283
+ const links = numbers.map((num)=>`[#${num}](https://github.com/${options.repo}/issues/${num})`);
284
+ issueLinks.push(`${label}: ${links.join(", ")}`);
285
+ }
286
+ }
287
+ if (issueLinks.length > 0) parts.push(`\n\n${issueLinks.join(". ")}`);
288
+ return parts.join(" ");
289
+ }
290
+ function formatPRAndUserAttribution(pr, user, links) {
291
+ let prReference = "";
292
+ if (pr) if (links?.pull) {
293
+ const pullUrl = extractUrlFromMarkdown(links.pull);
294
+ prReference = ` [#${String(pr)}](${pullUrl})`;
295
+ } else prReference = ` (#${String(pr)})`;
296
+ if (user) {
297
+ if (links?.user) {
298
+ const userUrl = extractUrlFromMarkdown(links.user);
299
+ return `${prReference} Thanks [@${user}](${userUrl})!`;
300
+ }
301
+ return `${prReference} Thanks @${user}!`;
302
+ }
303
+ return prReference;
304
+ }
305
+ function getReleaseLine(changeset, versionType, options) {
306
+ return Effect.gen(function*() {
307
+ let commitInfo = null;
308
+ if (changeset.commit) {
309
+ const github = yield* GitHubService;
310
+ commitInfo = yield* github.getInfo({
311
+ commit: changeset.commit,
312
+ repo: options.repo
313
+ }).pipe(Effect.flatMap((raw)=>Schema.decodeUnknown(GitHubInfoSchema)(raw).pipe(Effect.map(()=>raw), Effect.catchAll(()=>Effect.succeed(raw)))), Effect.catchAll((error)=>{
314
+ logWarning("Could not fetch GitHub info for commit:", changeset.commit ?? "", String(error));
315
+ return Effect.succeed(null);
316
+ }));
317
+ }
318
+ const parsed = parseChangesetSections(changeset.summary);
319
+ const firstLine = changeset.summary.split("\n")[0];
320
+ const commitMsg = parseCommitMessage(firstLine);
321
+ const bodyText = changeset.summary.split("\n").slice(1).join("\n");
322
+ const issueRefs = parseIssueReferences(bodyText);
323
+ const attribution = commitInfo ? formatPRAndUserAttribution(commitInfo.pull ?? void 0, commitInfo.user ?? void 0, commitInfo.links) : "";
324
+ if (parsed.sections.length > 0) {
325
+ const lines = [];
326
+ if (parsed.preamble) {
327
+ lines.push(parsed.preamble);
328
+ lines.push("");
329
+ }
330
+ for (const section of parsed.sections){
331
+ lines.push(`### ${section.category.heading}`);
332
+ lines.push("");
333
+ const commitPrefix = changeset.commit ? `[\`${changeset.commit.substring(0, 7)}\`](https://github.com/${options.repo}/commit/${changeset.commit}) ` : "";
334
+ if (section.content) {
335
+ const contentLines = section.content.split("\n");
336
+ const firstContentLine = contentLines[0];
337
+ if (firstContentLine.startsWith("- ") || firstContentLine.startsWith("* ")) {
338
+ lines.push(`${firstContentLine.substring(0, 2)}${commitPrefix}${firstContentLine.substring(2)}`);
339
+ lines.push(...contentLines.slice(1));
340
+ } else lines.push(`- ${commitPrefix}${section.content}`);
341
+ }
342
+ lines.push("");
343
+ }
344
+ const result = lines.join("\n").trimEnd();
345
+ return `${result}${attribution}`;
346
+ }
347
+ const commitType = commitMsg.type ?? versionType;
348
+ const category = resolveCommitType(commitType, commitMsg.scope, commitMsg.breaking);
349
+ const entryInput = {
350
+ type: category.heading,
351
+ summary: changeset.summary,
352
+ issues: issueRefs,
353
+ ...changeset.commit ? {
354
+ commit: changeset.commit
355
+ } : {}
356
+ };
357
+ const entry = formatChangelogEntry(entryInput, {
358
+ repo: options.repo
359
+ });
360
+ return `- ${entry}${attribution}`;
361
+ });
362
+ }
363
+ const MainLayer = Layer.mergeAll(GitHubLive, MarkdownLive);
364
+ const changelogFunctions = {
365
+ getReleaseLine: async (changeset, versionType, options)=>{
366
+ const program = Effect.gen(function*() {
367
+ const opts = yield* validateChangesetOptions(options);
368
+ return yield* getReleaseLine(changeset, versionType, opts);
369
+ });
370
+ return Effect.runPromise(program.pipe(Effect.provide(MainLayer)));
371
+ },
372
+ getDependencyReleaseLine: async (changesets, dependenciesUpdated, options)=>{
373
+ const program = Effect.gen(function*() {
374
+ const opts = yield* validateChangesetOptions(options);
375
+ return yield* getDependencyReleaseLine(changesets, dependenciesUpdated, opts);
376
+ });
377
+ return Effect.runPromise(program.pipe(Effect.provide(MainLayer)));
378
+ }
379
+ };
380
+ const changelog = changelogFunctions;
381
+ export default changelog;
382
+ export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest };
package/esm/index.d.ts CHANGED
@@ -14,7 +14,6 @@
14
14
 
15
15
  import { Context } from 'effect';
16
16
  import { Effect } from 'effect';
17
- import { Equals } from 'effect/Types';
18
17
  import { Layer } from 'effect';
19
18
  import { ModCompWithPackage } from '@changesets/types';
20
19
  import { NewChangesetWithCommit } from '@changesets/types';
@@ -22,6 +21,7 @@ import type { Root } from 'mdast';
22
21
  import { Schema } from 'effect';
23
22
  import type { Table } from 'mdast';
24
23
  import { VersionType as VersionType_2 } from '@changesets/types';
24
+ import { VoidIfEmpty } from 'effect/Types';
25
25
  import { YieldableError } from 'effect/Cause';
26
26
 
27
27
  /**
@@ -889,7 +889,7 @@ export declare class ChangesetValidationError extends ChangesetValidationErrorBa
889
889
  *
890
890
  * @internal
891
891
  */
892
- export declare const ChangesetValidationErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
892
+ export declare const ChangesetValidationErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
893
893
  readonly _tag: "ChangesetValidationError";
894
894
  } & Readonly<A>;
895
895
 
@@ -974,7 +974,7 @@ export declare class ConfigurationError extends ConfigurationErrorBase<{
974
974
  *
975
975
  * @internal
976
976
  */
977
- export declare const ConfigurationErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
977
+ export declare const ConfigurationErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
978
978
  readonly _tag: "ConfigurationError";
979
979
  } & Readonly<A>;
980
980
 
@@ -1445,7 +1445,7 @@ export declare class GitHubApiError extends GitHubApiErrorBase<{
1445
1445
  *
1446
1446
  * @internal
1447
1447
  */
1448
- export declare const GitHubApiErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
1448
+ export declare const GitHubApiErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
1449
1449
  readonly _tag: "GitHubApiError";
1450
1450
  } & Readonly<A>;
1451
1451
 
@@ -1936,7 +1936,7 @@ export declare class MarkdownParseError extends MarkdownParseErrorBase<{
1936
1936
  *
1937
1937
  * @internal
1938
1938
  */
1939
- export declare const MarkdownParseErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
1939
+ export declare const MarkdownParseErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
1940
1940
  readonly _tag: "MarkdownParseError";
1941
1941
  } & Readonly<A>;
1942
1942
 
@@ -2320,7 +2320,7 @@ export declare class VersionFileError extends VersionFileErrorBase<{
2320
2320
  *
2321
2321
  * @internal
2322
2322
  */
2323
- export declare const VersionFileErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
2323
+ export declare const VersionFileErrorBase: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
2324
2324
  readonly _tag: "VersionFileError";
2325
2325
  } & Readonly<A>;
2326
2326
 
package/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { BREAKING_CHANGES, PERFORMANCE, fromHeading, allHeadings, resolveCommitType, CI, TESTS, DEPENDENCIES, OTHER, CATEGORIES, FEATURES, BUG_FIXES, REVERTS, DOCUMENTATION, isValidHeading, BUILD_SYSTEM, REFACTORING, MAINTENANCE } from "./60.js";
2
- import { default as changelog } from "./160.js";
3
- import { parseDependencyTable, serializeDependencyTable, collapseDependencyRows, serializeDependencyTableToMarkdown, NonEmptyString, sortDependencyRows } from "./891.js";
4
- import { Context, Schema } from "./855.js";
1
+ import { Context, Schema } from "effect";
2
+ import { BREAKING_CHANGES, PERFORMANCE, fromHeading, allHeadings, resolveCommitType, CI, TESTS, DEPENDENCIES, OTHER, CATEGORIES, FEATURES, BUG_FIXES, REVERTS, DOCUMENTATION, isValidHeading, BUILD_SYSTEM, REFACTORING, MAINTENANCE } from "./286.js";
3
+ import { default as changelog } from "./changelog.js";
4
+ import { parseDependencyTable, serializeDependencyTable, collapseDependencyRows, serializeDependencyTableToMarkdown, NonEmptyString, sortDependencyRows } from "./345.js";
5
5
  class Categories {
6
6
  static BREAKING_CHANGES = BREAKING_CHANGES;
7
7
  static FEATURES = FEATURES;
@@ -91,8 +91,8 @@ const DependencyUpdateSchema = Schema.Struct({
91
91
  oldVersion: Schema.String,
92
92
  newVersion: Schema.String
93
93
  });
94
- export { ChangelogTransformer, ChangesetLinter } from "./273.js";
95
- export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest } from "./160.js";
96
- export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema } from "./725.js";
97
- export { DependencyActionSchema, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, NonEmptyString, PositiveInteger, VersionOrEmptySchema } from "./891.js";
94
+ export { ChangelogTransformer, ChangesetLinter } from "./245.js";
95
+ export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest } from "./changelog.js";
96
+ export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema } from "./514.js";
97
+ export { DependencyActionSchema, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, NonEmptyString, PositiveInteger, VersionOrEmptySchema } from "./345.js";
98
98
  export { Categories, Changelog, ChangelogService, ChangelogServiceBase, ChangesetSchema, ChangesetSummarySchema, CommitHashSchema, DependencyTable, DependencyTypeSchema, DependencyUpdateSchema, SectionCategorySchema, VersionTypeSchema };
@@ -1,5 +1,5 @@
1
- import { RULE_DOCS } from "./260.js";
2
- import { isValidHeading, allHeadings } from "./60.js";
1
+ import { RULE_DOCS } from "./486.js";
2
+ import { isValidHeading, allHeadings } from "./286.js";
3
3
  function getHeadingLevel(heading) {
4
4
  const sequence = heading.children.find((c)=>"atxHeadingSequence" === c.type);
5
5
  return sequence ? sequence.text.length : 0;
package/esm/remark.js CHANGED
@@ -1,7 +1,9 @@
1
- import { parseDependencyTable, serializeDependencyTable, collapseDependencyRows, sortDependencyRows } from "./891.js";
2
- import { getHeadingText, NormalizeFormatPlugin, ContentStructureRule, HeadingHierarchyRule, ReorderSectionsPlugin, getVersionBlocks, getBlockSections, visit, UncategorizedContentRule, MergeSectionsPlugin, DeduplicateItemsPlugin, IssueLinkRefsPlugin, lintRule, ContributorFootnotesPlugin, RequiredSectionsRule } from "./622.js";
3
- import { external_mdast_util_to_string_toString } from "./855.js";
4
- import { RULE_DOCS } from "./260.js";
1
+ import { toString as external_mdast_util_to_string_toString } from "mdast-util-to-string";
2
+ import { lintRule } from "unified-lint-rule";
3
+ import { visit } from "unist-util-visit";
4
+ import { parseDependencyTable, serializeDependencyTable, collapseDependencyRows, sortDependencyRows } from "./345.js";
5
+ import { HeadingHierarchyRule, RequiredSectionsRule, UncategorizedContentRule, MergeSectionsPlugin, DeduplicateItemsPlugin, IssueLinkRefsPlugin, getHeadingText, NormalizeFormatPlugin, ReorderSectionsPlugin, ContentStructureRule, ContributorFootnotesPlugin, getVersionBlocks, getBlockSections } from "./448.js";
6
+ import { RULE_DOCS } from "./486.js";
5
7
  const AggregateDependencyTablesPlugin = ()=>(tree)=>{
6
8
  const blocks = getVersionBlocks(tree);
7
9
  for(let b = blocks.length - 1; b >= 0; b--){
@@ -86,5 +88,5 @@ const SilkChangesetTransformPreset = [
86
88
  IssueLinkRefsPlugin,
87
89
  NormalizeFormatPlugin
88
90
  ];
89
- export { ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, HeadingHierarchyRule, IssueLinkRefsPlugin, MergeSectionsPlugin, NormalizeFormatPlugin, ReorderSectionsPlugin, RequiredSectionsRule, UncategorizedContentRule } from "./622.js";
91
+ export { ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, HeadingHierarchyRule, IssueLinkRefsPlugin, MergeSectionsPlugin, NormalizeFormatPlugin, ReorderSectionsPlugin, RequiredSectionsRule, UncategorizedContentRule } from "./448.js";
90
92
  export { AggregateDependencyTablesPlugin, DependencyTableFormatRule, SilkChangesetPreset, SilkChangesetTransformPreset };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/changesets",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "private": false,
5
5
  "description": "Custom changelog formatter and markdown processing pipeline for the Silk Suite. Provides structured changeset sections, remark-based validation and transformation, and an Effect CLI.",
6
6
  "keywords": [
@@ -81,9 +81,6 @@
81
81
  "engines": {
82
82
  "node": ">=24.0.0"
83
83
  },
84
- "scripts": {
85
- "postinstall": "savvy-changesets init --check"
86
- },
87
84
  "files": [
88
85
  "!changesets.api.json",
89
86
  "!tsconfig.json",
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.57.6"
8
+ "packageVersion": "7.57.7"
9
9
  }
10
10
  ]
11
11
  }
package/esm/160.js DELETED
@@ -1,377 +0,0 @@
1
- import { getInfo } from "@changesets/get-github-info";
2
- import { Layer, unified, Schema, external_mdast_util_to_string_toString, remark_stringify, Effect, remark_gfm, Context } from "./855.js";
3
- import { GitHubApiError, VersionFilesSchema, ConfigurationError, remark_parse } from "./725.js";
4
- import { PositiveInteger, serializeDependencyTableToMarkdown } from "./891.js";
5
- import { resolveCommitType, fromHeading } from "./60.js";
6
- const REPO_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/;
7
- const RepoSchema = Schema.String.pipe(Schema.pattern(REPO_PATTERN, {
8
- message: ()=>'Repository must be in format "owner/repository" (e.g., "microsoft/vscode")'
9
- }));
10
- const ChangesetOptionsSchema = Schema.Struct({
11
- repo: RepoSchema,
12
- commitLinks: Schema.optional(Schema.Boolean),
13
- prLinks: Schema.optional(Schema.Boolean),
14
- issueLinks: Schema.optional(Schema.Boolean),
15
- issuePrefixes: Schema.optional(Schema.Array(Schema.String)),
16
- versionFiles: Schema.optional(VersionFilesSchema)
17
- });
18
- function validateChangesetOptions(input) {
19
- if (null == input) return Effect.fail(new ConfigurationError({
20
- field: "options",
21
- reason: 'Configuration is required. Add options to your changesets config:\n"changelog": ["@savvy-web/changesets", { "repo": "owner/repository" }]'
22
- }));
23
- if ("object" != typeof input) return Effect.fail(new ConfigurationError({
24
- field: "options",
25
- reason: "Configuration must be an object"
26
- }));
27
- const obj = input;
28
- if (!("repo" in obj) || void 0 === obj.repo) return Effect.fail(new ConfigurationError({
29
- field: "repo",
30
- reason: 'Repository name is required. Add the "repo" option to your changesets config:\n"changelog": ["@savvy-web/changesets", { "repo": "owner/repository" }]'
31
- }));
32
- if ("string" == typeof obj.repo && !REPO_PATTERN.test(obj.repo)) return Effect.fail(new ConfigurationError({
33
- field: "repo",
34
- reason: `Invalid repository format: "${obj.repo}". Expected format is "owner/repository" (e.g., "microsoft/vscode")`
35
- }));
36
- return Schema.decodeUnknown(ChangesetOptionsSchema)(input).pipe(Effect.mapError((parseError)=>new ConfigurationError({
37
- field: "options",
38
- reason: String(parseError)
39
- })));
40
- }
41
- function getGitHubInfo(params) {
42
- return Effect.tryPromise({
43
- try: ()=>getInfo({
44
- commit: params.commit,
45
- repo: params.repo
46
- }),
47
- catch: (error)=>new GitHubApiError({
48
- operation: "getInfo",
49
- reason: error instanceof Error ? error.message : String(error)
50
- })
51
- });
52
- }
53
- const _tag = Context.Tag("GitHubService");
54
- const GitHubServiceBase = _tag();
55
- class GitHubService extends GitHubServiceBase {
56
- }
57
- const GitHubLive = Layer.succeed(GitHubService, {
58
- getInfo: getGitHubInfo
59
- });
60
- function makeGitHubTest(responses) {
61
- return Layer.succeed(GitHubService, {
62
- getInfo: (params)=>{
63
- const info = responses.get(params.commit);
64
- if (info) return Effect.succeed(info);
65
- return Effect.fail(new GitHubApiError({
66
- operation: "getInfo",
67
- reason: `No mock response for commit ${params.commit}`
68
- }));
69
- }
70
- });
71
- }
72
- function createRemarkProcessor() {
73
- return unified().use(remark_parse).use(remark_gfm).use(remark_stringify);
74
- }
75
- function parseMarkdown(content) {
76
- const processor = createRemarkProcessor();
77
- return processor.parse(content);
78
- }
79
- function stringifyMarkdown(tree) {
80
- const processor = createRemarkProcessor();
81
- return processor.stringify(tree);
82
- }
83
- const markdown_tag = Context.Tag("MarkdownService");
84
- const MarkdownServiceBase = markdown_tag();
85
- class MarkdownService extends MarkdownServiceBase {
86
- }
87
- const MarkdownLive = Layer.succeed(MarkdownService, {
88
- parse: (content)=>Effect.sync(()=>parseMarkdown(content)),
89
- stringify: (tree)=>Effect.sync(()=>stringifyMarkdown(tree))
90
- });
91
- const FIELD_MAP = [
92
- [
93
- "dependencies",
94
- "dependency"
95
- ],
96
- [
97
- "devDependencies",
98
- "devDependency"
99
- ],
100
- [
101
- "peerDependencies",
102
- "peerDependency"
103
- ],
104
- [
105
- "optionalDependencies",
106
- "optionalDependency"
107
- ]
108
- ];
109
- function inferDependencyType(dep) {
110
- const pkg = dep.packageJson;
111
- for (const [field, type] of FIELD_MAP){
112
- const section = pkg[field];
113
- if ("object" == typeof section && null !== section && dep.name in section) return type;
114
- }
115
- return "dependency";
116
- }
117
- function getDependencyReleaseLine(_changesets, dependenciesUpdated, _options) {
118
- return Effect.gen(function*() {
119
- if (0 === dependenciesUpdated.length) return "";
120
- yield* GitHubService;
121
- const rows = dependenciesUpdated.map((dep)=>({
122
- dependency: dep.name,
123
- type: inferDependencyType(dep),
124
- action: "updated",
125
- from: dep.oldVersion,
126
- to: dep.newVersion
127
- }));
128
- return serializeDependencyTableToMarkdown(rows);
129
- });
130
- }
131
- const MARKDOWN_LINK_PATTERN = /\[([^\]]+)\]\(([^)]+)\)/;
132
- function extractUrlFromMarkdown(linkOrUrl) {
133
- const match = MARKDOWN_LINK_PATTERN.exec(linkOrUrl);
134
- return match ? match[2] : linkOrUrl;
135
- }
136
- function isValidUrl(value) {
137
- try {
138
- new URL(value);
139
- return true;
140
- } catch {
141
- return false;
142
- }
143
- }
144
- const UsernameSchema = Schema.String.pipe(Schema.pattern(/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/, {
145
- message: ()=>'Invalid GitHub username format. Usernames must contain only alphanumeric characters and hyphens, and cannot start or end with a hyphen. Example: "octocat" or "my-user-123"'
146
- }));
147
- const IssueNumberSchema = PositiveInteger.annotations({
148
- title: "IssueNumber",
149
- description: "GitHub issue or pull request number"
150
- });
151
- const UrlOrMarkdownLinkSchema = Schema.String.pipe(Schema.filter((value)=>{
152
- if (isValidUrl(value)) return true;
153
- const match = MARKDOWN_LINK_PATTERN.exec(value);
154
- return match?.[2] ? isValidUrl(match[2]) : false;
155
- }, {
156
- message: ()=>'Value must be a valid URL or a markdown link. Expected a plain URL (e.g., "https://github.com/owner/repo/pull/42") or a markdown link (e.g., "[#42](https://github.com/owner/repo/pull/42)")'
157
- }));
158
- const GitHubInfoSchema = Schema.Struct({
159
- user: Schema.optional(UsernameSchema),
160
- pull: Schema.optional(IssueNumberSchema),
161
- links: Schema.Struct({
162
- commit: UrlOrMarkdownLinkSchema,
163
- pull: Schema.optional(UrlOrMarkdownLinkSchema),
164
- user: Schema.optional(UrlOrMarkdownLinkSchema)
165
- })
166
- });
167
- const CONVENTIONAL_COMMIT_PATTERN = /^(\w+)(?:\(([^)]+)\))?(!)?\s*:\s*(.+)/;
168
- function parseCommitMessage(message) {
169
- const match = CONVENTIONAL_COMMIT_PATTERN.exec(message);
170
- if (match) {
171
- const [, type, scope, bang, description] = match;
172
- const lines = message.split("\n");
173
- const body = lines.slice(1).join("\n").trim();
174
- const result = {
175
- type,
176
- description: description.trim()
177
- };
178
- if (scope) result.scope = scope;
179
- if ("!" === bang) result.breaking = true;
180
- if (body) result.body = body;
181
- return result;
182
- }
183
- return {
184
- description: message
185
- };
186
- }
187
- const CLOSES_ISSUE_PATTERN = /closes?:?\s*#?(\d+(?:, *#?\d+)*)/i;
188
- const FIXES_ISSUE_PATTERN = /fix(?:es)?:?\s*#?(\d+(?:, *#?\d+)*)/i;
189
- const REFS_ISSUE_PATTERN = /refs?:?\s*#?(\d+(?:, *#?\d+)*)/i;
190
- const ISSUE_NUMBER_SPLIT_PATTERN = /, */;
191
- function extractIssueNumbers(pattern, message) {
192
- const safeMessage = message.slice(0, 10000);
193
- const match = pattern.exec(safeMessage);
194
- if (!match?.[1]) return [];
195
- return match[1].split(ISSUE_NUMBER_SPLIT_PATTERN).map((num)=>num.replace("#", "").trim());
196
- }
197
- function parseIssueReferences(commitMessage) {
198
- return {
199
- closes: extractIssueNumbers(CLOSES_ISSUE_PATTERN, commitMessage),
200
- fixes: extractIssueNumbers(FIXES_ISSUE_PATTERN, commitMessage),
201
- refs: extractIssueNumbers(REFS_ISSUE_PATTERN, commitMessage)
202
- };
203
- }
204
- function logWarning(message, ...args) {
205
- if ("u" > typeof process && process.env.VITEST) return;
206
- if ("u" > typeof process && "true" === process.env.GITHUB_ACTIONS) {
207
- const text = args.length > 0 ? `${message} ${args.join(" ")}` : message;
208
- console.warn(`::warning::${text}`);
209
- } else console.warn(message, ...args);
210
- }
211
- function parseChangesetSections(summary) {
212
- const tree = parseMarkdown(summary);
213
- const h2Indices = [];
214
- for(let i = 0; i < tree.children.length; i++){
215
- const node = tree.children[i];
216
- if ("heading" === node.type && 2 === node.depth) h2Indices.push(i);
217
- }
218
- if (0 === h2Indices.length) return {
219
- preamble: summary.trim(),
220
- sections: []
221
- };
222
- const result = {
223
- sections: []
224
- };
225
- if (h2Indices[0] > 0) {
226
- const preambleNodes = tree.children.slice(0, h2Indices[0]);
227
- result.preamble = stringifyAstSlice(preambleNodes);
228
- }
229
- for(let i = 0; i < h2Indices.length; i++){
230
- const headingIndex = h2Indices[i];
231
- const headingNode = tree.children[headingIndex];
232
- const headingText = external_mdast_util_to_string_toString(headingNode);
233
- const nextIndex = i + 1 < h2Indices.length ? h2Indices[i + 1] : tree.children.length;
234
- const contentNodes = tree.children.slice(headingIndex + 1, nextIndex);
235
- const content = stringifyAstSlice(contentNodes);
236
- const category = fromHeading(headingText);
237
- if (category) result.sections.push({
238
- category,
239
- heading: headingText,
240
- content
241
- });
242
- }
243
- return result;
244
- }
245
- function stringifyAstSlice(nodes) {
246
- if (0 === nodes.length) return "";
247
- const root = {
248
- type: "root",
249
- children: nodes
250
- };
251
- return stringifyMarkdown(root).trim();
252
- }
253
- const ISSUE_CATEGORIES = [
254
- {
255
- key: "closes",
256
- label: "Closes"
257
- },
258
- {
259
- key: "fixes",
260
- label: "Fixes"
261
- },
262
- {
263
- key: "refs",
264
- label: "Refs"
265
- }
266
- ];
267
- function formatChangelogEntry(entry, options) {
268
- const parts = [];
269
- if (entry.commit) {
270
- const shortHash = entry.commit.substring(0, 7);
271
- parts.push(`[\`${shortHash}\`](https://github.com/${options.repo}/commit/${entry.commit})`);
272
- }
273
- parts.push(entry.summary.trim());
274
- const issueLinks = [];
275
- for (const { key, label } of ISSUE_CATEGORIES){
276
- const numbers = entry.issues[key];
277
- if (numbers.length > 0) {
278
- const links = numbers.map((num)=>`[#${num}](https://github.com/${options.repo}/issues/${num})`);
279
- issueLinks.push(`${label}: ${links.join(", ")}`);
280
- }
281
- }
282
- if (issueLinks.length > 0) parts.push(`\n\n${issueLinks.join(". ")}`);
283
- return parts.join(" ");
284
- }
285
- function formatPRAndUserAttribution(pr, user, links) {
286
- let prReference = "";
287
- if (pr) if (links?.pull) {
288
- const pullUrl = extractUrlFromMarkdown(links.pull);
289
- prReference = ` [#${String(pr)}](${pullUrl})`;
290
- } else prReference = ` (#${String(pr)})`;
291
- if (user) {
292
- if (links?.user) {
293
- const userUrl = extractUrlFromMarkdown(links.user);
294
- return `${prReference} Thanks [@${user}](${userUrl})!`;
295
- }
296
- return `${prReference} Thanks @${user}!`;
297
- }
298
- return prReference;
299
- }
300
- function getReleaseLine(changeset, versionType, options) {
301
- return Effect.gen(function*() {
302
- let commitInfo = null;
303
- if (changeset.commit) {
304
- const github = yield* GitHubService;
305
- commitInfo = yield* github.getInfo({
306
- commit: changeset.commit,
307
- repo: options.repo
308
- }).pipe(Effect.flatMap((raw)=>Schema.decodeUnknown(GitHubInfoSchema)(raw).pipe(Effect.map(()=>raw), Effect.catchAll(()=>Effect.succeed(raw)))), Effect.catchAll((error)=>{
309
- logWarning("Could not fetch GitHub info for commit:", changeset.commit ?? "", String(error));
310
- return Effect.succeed(null);
311
- }));
312
- }
313
- const parsed = parseChangesetSections(changeset.summary);
314
- const firstLine = changeset.summary.split("\n")[0];
315
- const commitMsg = parseCommitMessage(firstLine);
316
- const bodyText = changeset.summary.split("\n").slice(1).join("\n");
317
- const issueRefs = parseIssueReferences(bodyText);
318
- const attribution = commitInfo ? formatPRAndUserAttribution(commitInfo.pull ?? void 0, commitInfo.user ?? void 0, commitInfo.links) : "";
319
- if (parsed.sections.length > 0) {
320
- const lines = [];
321
- if (parsed.preamble) {
322
- lines.push(parsed.preamble);
323
- lines.push("");
324
- }
325
- for (const section of parsed.sections){
326
- lines.push(`### ${section.category.heading}`);
327
- lines.push("");
328
- const commitPrefix = changeset.commit ? `[\`${changeset.commit.substring(0, 7)}\`](https://github.com/${options.repo}/commit/${changeset.commit}) ` : "";
329
- if (section.content) {
330
- const contentLines = section.content.split("\n");
331
- const firstContentLine = contentLines[0];
332
- if (firstContentLine.startsWith("- ") || firstContentLine.startsWith("* ")) {
333
- lines.push(`${firstContentLine.substring(0, 2)}${commitPrefix}${firstContentLine.substring(2)}`);
334
- lines.push(...contentLines.slice(1));
335
- } else lines.push(`- ${commitPrefix}${section.content}`);
336
- }
337
- lines.push("");
338
- }
339
- const result = lines.join("\n").trimEnd();
340
- return `${result}${attribution}`;
341
- }
342
- const commitType = commitMsg.type ?? versionType;
343
- const category = resolveCommitType(commitType, commitMsg.scope, commitMsg.breaking);
344
- const entryInput = {
345
- type: category.heading,
346
- summary: changeset.summary,
347
- issues: issueRefs,
348
- ...changeset.commit ? {
349
- commit: changeset.commit
350
- } : {}
351
- };
352
- const entry = formatChangelogEntry(entryInput, {
353
- repo: options.repo
354
- });
355
- return `- ${entry}${attribution}`;
356
- });
357
- }
358
- const MainLayer = Layer.mergeAll(GitHubLive, MarkdownLive);
359
- const changelogFunctions = {
360
- getReleaseLine: async (changeset, versionType, options)=>{
361
- const program = Effect.gen(function*() {
362
- const opts = yield* validateChangesetOptions(options);
363
- return yield* getReleaseLine(changeset, versionType, opts);
364
- });
365
- return Effect.runPromise(program.pipe(Effect.provide(MainLayer)));
366
- },
367
- getDependencyReleaseLine: async (changesets, dependenciesUpdated, options)=>{
368
- const program = Effect.gen(function*() {
369
- const opts = yield* validateChangesetOptions(options);
370
- return yield* getDependencyReleaseLine(changesets, dependenciesUpdated, opts);
371
- });
372
- return Effect.runPromise(program.pipe(Effect.provide(MainLayer)));
373
- }
374
- };
375
- const changelog = changelogFunctions;
376
- export default changelog;
377
- export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest };
package/esm/855.js DELETED
@@ -1,5 +0,0 @@
1
- export { Context, Data, Effect, Layer, Schema } from "effect";
2
- export { default as remark_gfm } from "remark-gfm";
3
- export { default as remark_stringify } from "remark-stringify";
4
- export { unified } from "unified";
5
- export { toString as external_mdast_util_to_string_toString } from "mdast-util-to-string";
File without changes
File without changes