@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 +6 -6
- package/esm/{273.js → 245.js} +8 -6
- package/esm/{891.js → 345.js} +5 -1
- package/esm/{622.js → 448.js} +4 -4
- package/esm/{725.js → 514.js} +1 -2
- package/esm/bin/savvy-changesets.js +6 -4
- package/esm/changelog.js +382 -1
- package/esm/index.d.ts +6 -6
- package/esm/index.js +8 -8
- package/esm/markdownlint.js +2 -2
- package/esm/remark.js +7 -5
- package/package.json +1 -4
- package/tsdoc-metadata.json +1 -1
- package/esm/160.js +0 -377
- package/esm/855.js +0 -5
- /package/esm/{60.js → 286.js} +0 -0
- /package/esm/{260.js → 486.js} +0 -0
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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/{273.js → 245.js}
RENAMED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
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
|
|
44
|
+
export { ChangelogTransformer, ChangesetLinter };
|
package/esm/{891.js → 345.js}
RENAMED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
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");
|
package/esm/{622.js → 448.js}
RENAMED
|
@@ -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 {
|
|
4
|
-
import {
|
|
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
|
|
351
|
+
export { ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, HeadingHierarchyRule, IssueLinkRefsPlugin, MergeSectionsPlugin, NormalizeFormatPlugin, ReorderSectionsPlugin, RequiredSectionsRule, UncategorizedContentRule, getBlockSections, getHeadingText, getVersionBlocks };
|
package/esm/{725.js → 514.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Data, Schema } from "
|
|
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 {
|
|
9
|
-
import {
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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 "./
|
|
95
|
-
export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest } from "./
|
|
96
|
-
export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema } from "./
|
|
97
|
-
export { DependencyActionSchema, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, NonEmptyString, PositiveInteger, VersionOrEmptySchema } from "./
|
|
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 };
|
package/esm/markdownlint.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RULE_DOCS } from "./
|
|
2
|
-
import { isValidHeading, allHeadings } from "./
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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 "./
|
|
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.
|
|
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",
|
package/tsdoc-metadata.json
CHANGED
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";
|
/package/esm/{60.js → 286.js}
RENAMED
|
File without changes
|
/package/esm/{260.js → 486.js}
RENAMED
|
File without changes
|