@savvy-web/silk-effects 0.6.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -17
- package/_virtual/_rolldown/runtime.js +18 -0
- package/changesets/api/categories.js +247 -0
- package/changesets/api/changelog.js +134 -0
- package/changesets/api/dependency-table.js +163 -0
- package/changesets/api/linter.js +168 -0
- package/changesets/api/transformer.js +140 -0
- package/changesets/categories/index.js +299 -0
- package/changesets/categories/types.js +66 -0
- package/changesets/changelog/formatting.js +119 -0
- package/changesets/changelog/getDependencyReleaseLine.js +114 -0
- package/changesets/changelog/getReleaseLine.js +122 -0
- package/changesets/changelog/index.js +99 -0
- package/changesets/constants.js +43 -0
- package/changesets/errors.js +305 -0
- package/changesets/index.js +146 -0
- package/changesets/markdownlint/index.js +29 -0
- package/changesets/markdownlint/rules/content-structure.js +98 -0
- package/changesets/markdownlint/rules/dependency-table-format.js +170 -0
- package/changesets/markdownlint/rules/heading-hierarchy.js +61 -0
- package/changesets/markdownlint/rules/required-sections.js +54 -0
- package/changesets/markdownlint/rules/uncategorized-content.js +54 -0
- package/changesets/markdownlint/rules/utils.js +30 -0
- package/changesets/remark/plugins/aggregate-dependency-tables.js +47 -0
- package/changesets/remark/plugins/contributor-footnotes.js +123 -0
- package/changesets/remark/plugins/deduplicate-items.js +30 -0
- package/changesets/remark/plugins/issue-link-refs.js +58 -0
- package/changesets/remark/plugins/merge-sections.js +43 -0
- package/changesets/remark/plugins/normalize-format.js +47 -0
- package/changesets/remark/plugins/reorder-sections.js +34 -0
- package/changesets/remark/presets.js +119 -0
- package/changesets/remark/rules/content-structure.js +22 -0
- package/changesets/remark/rules/dependency-table-format.js +40 -0
- package/changesets/remark/rules/heading-hierarchy.js +19 -0
- package/changesets/remark/rules/required-sections.js +17 -0
- package/changesets/remark/rules/uncategorized-content.js +31 -0
- package/changesets/schemas/changeset.js +146 -0
- package/changesets/schemas/dependency-table.js +189 -0
- package/changesets/schemas/git.js +69 -0
- package/changesets/schemas/github.js +175 -0
- package/changesets/schemas/options.js +182 -0
- package/changesets/schemas/package-scope.js +128 -0
- package/changesets/schemas/primitives.js +72 -0
- package/changesets/schemas/version-files.js +151 -0
- package/changesets/services/branch-analyzer.js +278 -0
- package/changesets/services/changelog.js +50 -0
- package/changesets/services/config-inspector.js +390 -0
- package/changesets/services/github.js +178 -0
- package/changesets/services/markdown.js +106 -0
- package/changesets/services/workspace-snapshot.js +182 -0
- package/changesets/utils/commit-parser.js +80 -0
- package/changesets/utils/dep-diff.js +77 -0
- package/changesets/utils/dependency-table.js +347 -0
- package/changesets/utils/issue-refs.js +101 -0
- package/changesets/utils/jsonpath.js +175 -0
- package/changesets/utils/logger.js +50 -0
- package/changesets/utils/markdown-link.js +57 -0
- package/changesets/utils/publishability.js +39 -0
- package/changesets/utils/remark-pipeline.js +79 -0
- package/changesets/utils/section-parser.js +94 -0
- package/changesets/utils/strip-frontmatter.js +46 -0
- package/changesets/utils/version-blocks.js +108 -0
- package/changesets/utils/version-files.js +336 -0
- package/changesets/utils/worktree-snapshot.js +142 -0
- package/changesets/vendor/github-info.js +55 -0
- package/commitlint/config/factory.js +69 -0
- package/commitlint/config/plugins.js +227 -0
- package/commitlint/config/rules.js +155 -0
- package/commitlint/config/schema.js +46 -0
- package/commitlint/detection/dco.js +53 -0
- package/commitlint/detection/scopes.js +45 -0
- package/commitlint/formatter/format.js +85 -0
- package/commitlint/formatter/messages.js +79 -0
- package/commitlint/hook/diagnostics/branch.js +36 -0
- package/commitlint/hook/diagnostics/cache.js +37 -0
- package/commitlint/hook/diagnostics/commitlint-config.js +36 -0
- package/commitlint/hook/diagnostics/open-issues.js +56 -0
- package/commitlint/hook/diagnostics/package-manager.js +51 -0
- package/commitlint/hook/diagnostics/signing.js +107 -0
- package/commitlint/hook/envelope.js +46 -0
- package/commitlint/hook/output.js +45 -0
- package/commitlint/hook/parse-bash-command.js +105 -0
- package/commitlint/hook/rules/closes-trailer.js +31 -0
- package/commitlint/hook/rules/forbidden-content.js +32 -0
- package/commitlint/hook/rules/plan-leakage.js +36 -0
- package/commitlint/hook/rules/signing-flag-conflict.js +25 -0
- package/commitlint/hook/rules/soft-wrap.js +37 -0
- package/commitlint/hook/rules/types.js +14 -0
- package/commitlint/hook/rules/verbosity.js +31 -0
- package/commitlint/hook/silence-logger.js +39 -0
- package/commitlint/index.js +146 -0
- package/commitlint/prompt/config.js +91 -0
- package/commitlint/prompt/emojis.js +74 -0
- package/commitlint/prompt/prompter.js +135 -0
- package/commitlint/static.js +73 -0
- package/errors/BiomeSyncError.js +21 -0
- package/errors/ChangesetConfigError.js +20 -0
- package/errors/ConfigNotFoundError.js +21 -0
- package/errors/SectionParseError.js +16 -0
- package/errors/SectionValidationError.js +16 -0
- package/errors/SectionWriteError.js +16 -0
- package/errors/TagFormatError.js +20 -0
- package/errors/ToolNotFoundError.js +11 -0
- package/errors/ToolResolutionError.js +11 -0
- package/errors/ToolVersionMismatchError.js +11 -0
- package/errors/VersioningDetectionError.js +20 -0
- package/errors/WorkspaceAnalysisError.js +21 -0
- package/index.d.ts +9743 -8380
- package/index.js +36 -6657
- package/lint/Handler.js +39 -0
- package/lint/cli/sections.js +65 -0
- package/lint/cli/templates/markdownlint.gen.js +183 -0
- package/lint/config/Preset.js +152 -0
- package/lint/config/createConfig.js +89 -0
- package/lint/handlers/Biome.js +179 -0
- package/lint/handlers/Markdown.js +139 -0
- package/lint/handlers/PackageJson.js +130 -0
- package/lint/handlers/PnpmWorkspace.js +141 -0
- package/lint/handlers/ShellScripts.js +58 -0
- package/lint/handlers/TypeScript.js +134 -0
- package/lint/handlers/Yaml.js +167 -0
- package/lint/index.js +52 -0
- package/lint/utils/Command.js +285 -0
- package/lint/utils/Filter.js +100 -0
- package/lint/utils/Workspace.js +86 -0
- package/package.json +52 -63
- package/schemas/CommentStyle.js +16 -0
- package/schemas/ResolvedTool.js +63 -0
- package/schemas/SavvySections.js +113 -0
- package/schemas/SectionBlock.js +70 -0
- package/schemas/SectionDefinition.js +121 -0
- package/schemas/SectionResults.js +12 -0
- package/schemas/TagStrategySchemas.js +18 -0
- package/schemas/ToolDefinition.js +39 -0
- package/schemas/ToolResults.js +14 -0
- package/schemas/VersioningSchemas.js +95 -0
- package/schemas/WorkspaceAnalysisSchemas.js +190 -0
- package/services/BiomeSchemaSync.js +133 -0
- package/services/ChangesetConfig.js +78 -0
- package/services/ChangesetConfigReader.js +106 -0
- package/services/ConfigDiscovery.js +71 -0
- package/services/ManagedSection.js +288 -0
- package/services/SilkPublishability.js +193 -0
- package/services/SilkWorkspaceAnalyzer.js +213 -0
- package/services/TagStrategy.js +54 -0
- package/services/ToolDiscovery.js +229 -0
- package/services/VersioningStrategy.js +67 -0
- package/tsdoc-metadata.json +11 -11
- package/turbo/digest.js +127 -0
- package/turbo/errors.js +48 -0
- package/turbo/index.js +32 -0
- package/turbo/schemas/DryRun.js +57 -0
- package/turbo/schemas/results.js +61 -0
- package/turbo/services/TurboInspector.js +100 -0
- package/utils/ToolCommand.js +40 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { extractUrlFromMarkdown } from "../utils/markdown-link.js";
|
|
2
|
+
|
|
3
|
+
//#region src/changesets/changelog/formatting.ts
|
|
4
|
+
/**
|
|
5
|
+
* Issue reference categories and their display labels.
|
|
6
|
+
*
|
|
7
|
+
* Used by {@link formatChangelogEntry} to render issue links grouped
|
|
8
|
+
* by their relationship to the change (Closes, Fixes, Refs).
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
const ISSUE_CATEGORIES = [
|
|
13
|
+
{
|
|
14
|
+
key: "closes",
|
|
15
|
+
label: "Closes"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
key: "fixes",
|
|
19
|
+
label: "Fixes"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: "refs",
|
|
23
|
+
label: "Refs"
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Format a changelog entry into a markdown string with GitHub links.
|
|
28
|
+
*
|
|
29
|
+
* Produces a commit-link prefix (shortened to 7 characters) followed by the
|
|
30
|
+
* summary text and any issue references, each rendered as GitHub links.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* The output does **not** include a leading `- ` list marker — the caller
|
|
34
|
+
* is responsible for wrapping the result in a markdown list item. Issue
|
|
35
|
+
* references are appended on a new paragraph (double newline) when present,
|
|
36
|
+
* grouped by category: "Closes", "Fixes", "Refs".
|
|
37
|
+
*
|
|
38
|
+
* Output format examples:
|
|
39
|
+
*
|
|
40
|
+
* With commit: `[short-hash](commit-url) Summary text`
|
|
41
|
+
*
|
|
42
|
+
* With issues: `Summary text` followed by `Closes: [#1](issue-url)`
|
|
43
|
+
*
|
|
44
|
+
* With both: `[short-hash](commit-url) Summary text` followed by `Fixes: [#2](issue-url)`
|
|
45
|
+
*
|
|
46
|
+
* @param entry - The changelog entry containing commit, summary, and issue data
|
|
47
|
+
* @param options - Must include `repo` in `owner/repo` format for link generation
|
|
48
|
+
* @returns Formatted markdown string (without leading `- `)
|
|
49
|
+
*
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
function formatChangelogEntry(entry, options) {
|
|
53
|
+
const parts = [];
|
|
54
|
+
if (entry.commit) {
|
|
55
|
+
const shortHash = entry.commit.substring(0, 7);
|
|
56
|
+
parts.push(`[\`${shortHash}\`](https://github.com/${options.repo}/commit/${entry.commit})`);
|
|
57
|
+
}
|
|
58
|
+
parts.push(entry.summary.trim());
|
|
59
|
+
const issueLinks = [];
|
|
60
|
+
for (const { key, label } of ISSUE_CATEGORIES) {
|
|
61
|
+
const numbers = entry.issues[key];
|
|
62
|
+
if (numbers.length > 0) {
|
|
63
|
+
const links = numbers.map((num) => `[#${num}](https://github.com/${options.repo}/issues/${num})`);
|
|
64
|
+
issueLinks.push(`${label}: ${links.join(", ")}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (issueLinks.length > 0) parts.push(`\n\n${issueLinks.join(". ")}`);
|
|
68
|
+
return parts.join(" ");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Format pull-request reference and user attribution for a changelog entry.
|
|
72
|
+
*
|
|
73
|
+
* Appends a PR link and/or a "Thanks \@user!" attribution suffix to a
|
|
74
|
+
* changelog line. The output includes a leading space when non-empty, so it
|
|
75
|
+
* can be directly concatenated after the main entry text.
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* The `links` parameter may contain either plain URLs or markdown-formatted
|
|
79
|
+
* links (e.g., `[#42](https://...)`). This function handles both formats
|
|
80
|
+
* via {@link extractUrlFromMarkdown}, which strips the markdown link syntax
|
|
81
|
+
* and extracts the raw URL.
|
|
82
|
+
*
|
|
83
|
+
* Output format examples:
|
|
84
|
+
*
|
|
85
|
+
* PR only: `[#42](pr-url)`
|
|
86
|
+
*
|
|
87
|
+
* PR without link: `(#42)`
|
|
88
|
+
*
|
|
89
|
+
* User only: `Thanks user!`
|
|
90
|
+
*
|
|
91
|
+
* Both: `[#42](pr-url) Thanks [user](profile-url)!`
|
|
92
|
+
*
|
|
93
|
+
* Neither: empty string
|
|
94
|
+
*
|
|
95
|
+
* @param pr - Pull request number (omit if no PR is associated)
|
|
96
|
+
* @param user - GitHub username of the contributor (omit if unknown)
|
|
97
|
+
* @param links - Optional pre-formatted links for the PR and user from the GitHub API
|
|
98
|
+
* @returns Formatted attribution string (with leading space) or empty string
|
|
99
|
+
*
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
function formatPRAndUserAttribution(pr, user, links) {
|
|
103
|
+
let prReference = "";
|
|
104
|
+
if (pr) if (links?.pull) {
|
|
105
|
+
const pullUrl = extractUrlFromMarkdown(links.pull);
|
|
106
|
+
prReference = ` [#${String(pr)}](${pullUrl})`;
|
|
107
|
+
} else prReference = ` (#${String(pr)})`;
|
|
108
|
+
if (user) {
|
|
109
|
+
if (links?.user) {
|
|
110
|
+
const userUrl = extractUrlFromMarkdown(links.user);
|
|
111
|
+
return `${prReference} Thanks [@${user}](${userUrl})!`;
|
|
112
|
+
}
|
|
113
|
+
return `${prReference} Thanks @${user}!`;
|
|
114
|
+
}
|
|
115
|
+
return prReference;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
export { formatChangelogEntry, formatPRAndUserAttribution };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { GitHubService } from "../services/github.js";
|
|
2
|
+
import { serializeDependencyTableToMarkdown } from "../utils/dependency-table.js";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/changesets/changelog/getDependencyReleaseLine.ts
|
|
6
|
+
/**
|
|
7
|
+
* Core formatter: getDependencyReleaseLine.
|
|
8
|
+
*
|
|
9
|
+
* Formats dependency update entries as a structured markdown table showing
|
|
10
|
+
* each updated dependency's name, type, action, and version range.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* This formatter is the companion to {@link getReleaseLine}. While
|
|
14
|
+
* `getReleaseLine` handles individual changeset entries, this module
|
|
15
|
+
* handles the "Updated dependencies" section that Changesets appends
|
|
16
|
+
* when a package's dependencies are bumped as part of a release.
|
|
17
|
+
*
|
|
18
|
+
* The output is a GFM (GitHub Flavored Markdown) table with columns:
|
|
19
|
+
* `Dependency`, `Type`, `Action`, `From`, `To`. The dependency type
|
|
20
|
+
* is inferred from the consuming package's `package.json` fields
|
|
21
|
+
* (`dependencies`, `devDependencies`, `peerDependencies`,
|
|
22
|
+
* `optionalDependencies`) via the {@link inferDependencyType} helper.
|
|
23
|
+
*
|
|
24
|
+
* ### Dependency type inference
|
|
25
|
+
*
|
|
26
|
+
* The {@link FIELD_MAP} constant defines the precedence order for
|
|
27
|
+
* inferring the dependency type. The first matching field wins:
|
|
28
|
+
*
|
|
29
|
+
* 1. `dependencies` maps to `"dependency"`
|
|
30
|
+
* 2. `devDependencies` maps to `"devDependency"`
|
|
31
|
+
* 3. `peerDependencies` maps to `"peerDependency"`
|
|
32
|
+
* 4. `optionalDependencies` maps to `"optionalDependency"`
|
|
33
|
+
*
|
|
34
|
+
* If the dependency is not found in any field, it defaults to `"dependency"`.
|
|
35
|
+
*
|
|
36
|
+
* @see {@link getReleaseLine} for the companion individual changeset formatter
|
|
37
|
+
* @see {@link serializeDependencyTableToMarkdown} for the table serialization utility
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* Field-to-type mapping for inferring dependency type from `package.json`.
|
|
43
|
+
*
|
|
44
|
+
* Maps `package.json` dependency fields to their corresponding
|
|
45
|
+
* `DependencyTableType` values. The order defines precedence when a
|
|
46
|
+
* dependency name appears in multiple fields (first match wins).
|
|
47
|
+
*
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
const FIELD_MAP = [
|
|
51
|
+
["dependencies", "dependency"],
|
|
52
|
+
["devDependencies", "devDependency"],
|
|
53
|
+
["peerDependencies", "peerDependency"],
|
|
54
|
+
["optionalDependencies", "optionalDependency"]
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Infer the dependency table type from a package's `package.json`.
|
|
58
|
+
*
|
|
59
|
+
* Inspects the consuming package's `package.json` to determine which
|
|
60
|
+
* dependency field contains the given dependency name. Returns the
|
|
61
|
+
* corresponding `DependencyTableType` value, or `"dependency"` as a
|
|
62
|
+
* fallback when the dependency is not found in any standard field.
|
|
63
|
+
*
|
|
64
|
+
* @param dep - The dependency update with its associated `packageJson`
|
|
65
|
+
* @returns The inferred dependency type for display in the table
|
|
66
|
+
*
|
|
67
|
+
* @internal
|
|
68
|
+
*/
|
|
69
|
+
function inferDependencyType(dep) {
|
|
70
|
+
const pkg = dep.packageJson;
|
|
71
|
+
for (const [field, type] of FIELD_MAP) {
|
|
72
|
+
const section = pkg[field];
|
|
73
|
+
if (typeof section === "object" && section !== null && dep.name in section) return type;
|
|
74
|
+
}
|
|
75
|
+
return "dependency";
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Format dependency release lines as a structured markdown table.
|
|
79
|
+
*
|
|
80
|
+
* This is the core Effect program that implements the `getDependencyReleaseLine`
|
|
81
|
+
* contract from the Changesets API. It requires {@link GitHubService} in its
|
|
82
|
+
* environment (currently unused but kept for API contract stability).
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* The function maps each `ModCompWithPackage` entry to a `DependencyTableRow`,
|
|
86
|
+
* inferring the dependency type from the consuming package's `package.json`,
|
|
87
|
+
* then delegates to `serializeDependencyTableToMarkdown` for GFM table
|
|
88
|
+
* rendering. Returns an empty string when no dependencies were updated.
|
|
89
|
+
*
|
|
90
|
+
* The `_changesets` and `_options` parameters are part of the Changesets API
|
|
91
|
+
* contract but are not used in the table format. They are retained for
|
|
92
|
+
* interface compatibility.
|
|
93
|
+
*
|
|
94
|
+
* @param _changesets - Changesets that caused the dependency updates (unused in table format)
|
|
95
|
+
* @param dependenciesUpdated - The list of dependencies that were updated, including old/new versions
|
|
96
|
+
* @param _options - Validated configuration options (unused in table format)
|
|
97
|
+
* @returns An `Effect` that resolves to a formatted markdown table string, or empty string if no dependencies were updated
|
|
98
|
+
*/
|
|
99
|
+
function getDependencyReleaseLine(_changesets, dependenciesUpdated, _options) {
|
|
100
|
+
return Effect.gen(function* () {
|
|
101
|
+
if (dependenciesUpdated.length === 0) return "";
|
|
102
|
+
yield* GitHubService;
|
|
103
|
+
return serializeDependencyTableToMarkdown(dependenciesUpdated.map((dep) => ({
|
|
104
|
+
dependency: dep.name,
|
|
105
|
+
type: inferDependencyType(dep),
|
|
106
|
+
action: "updated",
|
|
107
|
+
from: dep.oldVersion,
|
|
108
|
+
to: dep.newVersion
|
|
109
|
+
})));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
export { getDependencyReleaseLine };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { resolveCommitType } from "../categories/index.js";
|
|
2
|
+
import { GitHubService } from "../services/github.js";
|
|
3
|
+
import { GitHubInfoSchema } from "../schemas/github.js";
|
|
4
|
+
import { parseCommitMessage } from "../utils/commit-parser.js";
|
|
5
|
+
import { parseIssueReferences } from "../utils/issue-refs.js";
|
|
6
|
+
import { logWarning } from "../utils/logger.js";
|
|
7
|
+
import { parseChangesetSections } from "../utils/section-parser.js";
|
|
8
|
+
import { formatChangelogEntry, formatPRAndUserAttribution } from "./formatting.js";
|
|
9
|
+
import { Effect, Schema } from "effect";
|
|
10
|
+
|
|
11
|
+
//#region src/changesets/changelog/getReleaseLine.ts
|
|
12
|
+
/**
|
|
13
|
+
* Core formatter: getReleaseLine.
|
|
14
|
+
*
|
|
15
|
+
* Formats a single changeset into a changelog entry. This is the primary
|
|
16
|
+
* formatting function in the changelog pipeline, responsible for transforming
|
|
17
|
+
* a `NewChangesetWithCommit` into structured markdown output.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* The formatter supports two distinct input modes:
|
|
21
|
+
*
|
|
22
|
+
* 1. **Section-aware changesets** — When the changeset summary contains h2
|
|
23
|
+
* headings (e.g., `## Features`, `## Bug Fixes`), each section is rendered
|
|
24
|
+
* as an h3 heading with commit-linked list items beneath it. This mode
|
|
25
|
+
* produces multi-line output suitable for rich changelogs.
|
|
26
|
+
*
|
|
27
|
+
* 2. **Flat-text changesets** — When the summary is plain text without section
|
|
28
|
+
* headings, the formatter falls back to backward-compatible single-line
|
|
29
|
+
* output. The conventional commit type is resolved via `resolveCommitType`
|
|
30
|
+
* to determine the changelog category.
|
|
31
|
+
*
|
|
32
|
+
* In both modes, the formatter:
|
|
33
|
+
* - Fetches GitHub metadata (PR number, author) via {@link GitHubService}
|
|
34
|
+
* - Generates shortened commit hash links (`[abc1234](...)`)
|
|
35
|
+
* - Extracts and renders issue references (Closes, Fixes, Refs)
|
|
36
|
+
* - Appends PR and user attribution when available
|
|
37
|
+
*
|
|
38
|
+
* @see {@link formatChangelogEntry} for the low-level entry formatting
|
|
39
|
+
* @see {@link formatPRAndUserAttribution} for attribution suffix generation
|
|
40
|
+
* @see {@link getDependencyReleaseLine} for the companion dependency formatter
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Format a single changeset into a markdown release line.
|
|
46
|
+
*
|
|
47
|
+
* This is the core Effect program that implements the `getReleaseLine` contract
|
|
48
|
+
* from the Changesets API. It requires {@link GitHubService} in its environment
|
|
49
|
+
* for resolving commit metadata.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* The formatting pipeline proceeds in seven steps:
|
|
53
|
+
*
|
|
54
|
+
* 1. **Fetch GitHub info** — If the changeset has a commit hash, query
|
|
55
|
+
* the {@link GitHubService} for PR number, author, and links. Failures
|
|
56
|
+
* are caught and logged as warnings (attribution is simply omitted).
|
|
57
|
+
* 2. **Parse sections** — Attempt to split the summary into h2-delimited
|
|
58
|
+
* sections using `parseChangesetSections`.
|
|
59
|
+
* 3. **Parse conventional commit** — Extract the commit type, scope, and
|
|
60
|
+
* breaking flag from the first line of the summary.
|
|
61
|
+
* 4. **Extract issue references** — Parse the body for `Closes #N`,
|
|
62
|
+
* `Fixes #N`, and `Refs #N` patterns.
|
|
63
|
+
* 5. **Build attribution** — Format PR link and user credit from GitHub info.
|
|
64
|
+
* 6. **Section-aware output** — If sections were found, render each as an
|
|
65
|
+
* h3 heading with commit-linked list items.
|
|
66
|
+
* 7. **Flat-text fallback** — Otherwise, produce a single `- entry` line
|
|
67
|
+
* with the resolved category heading.
|
|
68
|
+
*
|
|
69
|
+
* @param changeset - The changeset to format, including commit hash and summary text
|
|
70
|
+
* @param versionType - The semantic version bump type (`major`, `minor`, or `patch`),
|
|
71
|
+
* used as fallback when no conventional commit type is detected
|
|
72
|
+
* @param options - Validated configuration options (must include `repo` in `owner/repo` format)
|
|
73
|
+
* @returns An `Effect` that resolves to a formatted markdown string
|
|
74
|
+
*/
|
|
75
|
+
function getReleaseLine(changeset, versionType, options) {
|
|
76
|
+
return Effect.gen(function* () {
|
|
77
|
+
let commitInfo = null;
|
|
78
|
+
if (changeset.commit) commitInfo = yield* (yield* GitHubService).getInfo({
|
|
79
|
+
commit: changeset.commit,
|
|
80
|
+
repo: options.repo
|
|
81
|
+
}).pipe(Effect.flatMap((raw) => Schema.decodeUnknown(GitHubInfoSchema)(raw).pipe(Effect.map(() => raw), Effect.catchAll(() => Effect.succeed(raw)))), Effect.catchAll((error) => {
|
|
82
|
+
logWarning("Could not fetch GitHub info for commit:", changeset.commit ?? "", String(error));
|
|
83
|
+
return Effect.succeed(null);
|
|
84
|
+
}));
|
|
85
|
+
const parsed = parseChangesetSections(changeset.summary);
|
|
86
|
+
const firstLine = changeset.summary.split("\n")[0];
|
|
87
|
+
const commitMsg = parseCommitMessage(firstLine);
|
|
88
|
+
const issueRefs = parseIssueReferences(changeset.summary.split("\n").slice(1).join("\n"));
|
|
89
|
+
const attribution = commitInfo ? formatPRAndUserAttribution(commitInfo.pull ?? void 0, commitInfo.user ?? void 0, commitInfo.links) : "";
|
|
90
|
+
if (parsed.sections.length > 0) {
|
|
91
|
+
const lines = [];
|
|
92
|
+
if (parsed.preamble) {
|
|
93
|
+
lines.push(parsed.preamble);
|
|
94
|
+
lines.push("");
|
|
95
|
+
}
|
|
96
|
+
for (const section of parsed.sections) {
|
|
97
|
+
lines.push(`### ${section.category.heading}`);
|
|
98
|
+
lines.push("");
|
|
99
|
+
const commitPrefix = changeset.commit ? `[\`${changeset.commit.substring(0, 7)}\`](https://github.com/${options.repo}/commit/${changeset.commit}) ` : "";
|
|
100
|
+
if (section.content) {
|
|
101
|
+
const contentLines = section.content.split("\n");
|
|
102
|
+
const firstContentLine = contentLines[0];
|
|
103
|
+
if (firstContentLine.startsWith("- ") || firstContentLine.startsWith("* ")) {
|
|
104
|
+
lines.push(`${firstContentLine.substring(0, 2)}${commitPrefix}${firstContentLine.substring(2)}`);
|
|
105
|
+
lines.push(...contentLines.slice(1));
|
|
106
|
+
} else lines.push(`- ${commitPrefix}${section.content}`);
|
|
107
|
+
}
|
|
108
|
+
lines.push("");
|
|
109
|
+
}
|
|
110
|
+
return `${lines.join("\n").trimEnd()}${attribution}`;
|
|
111
|
+
}
|
|
112
|
+
return `- ${formatChangelogEntry({
|
|
113
|
+
type: resolveCommitType(commitMsg.type ?? versionType, commitMsg.scope, commitMsg.breaking).heading,
|
|
114
|
+
summary: changeset.summary,
|
|
115
|
+
issues: issueRefs,
|
|
116
|
+
...changeset.commit ? { commit: changeset.commit } : {}
|
|
117
|
+
}, { repo: options.repo })}${attribution}`;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
export { getReleaseLine };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { validateChangesetOptions } from "../schemas/options.js";
|
|
2
|
+
import { GitHubLive } from "../services/github.js";
|
|
3
|
+
import { MarkdownLive } from "../services/markdown.js";
|
|
4
|
+
import { getDependencyReleaseLine } from "./getDependencyReleaseLine.js";
|
|
5
|
+
import { getReleaseLine } from "./getReleaseLine.js";
|
|
6
|
+
import { Effect, Layer } from "effect";
|
|
7
|
+
|
|
8
|
+
//#region src/changesets/changelog/index.ts
|
|
9
|
+
/**
|
|
10
|
+
* Changesets API changelog formatter — `\@savvy-web/changesets/changelog`
|
|
11
|
+
*
|
|
12
|
+
* This module is the default export consumed by the Changesets CLI via the
|
|
13
|
+
* `changelog` field in `.changeset/config.json`. It implements the
|
|
14
|
+
* `ChangelogFunctions` interface from `\@changesets/types`, wiring the
|
|
15
|
+
* Effect-based formatting pipeline into the async API that Changesets expects.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* The module composes two Effect programs — {@link getReleaseLine} and
|
|
19
|
+
* {@link getDependencyReleaseLine} — and runs each through
|
|
20
|
+
* `Effect.runPromise` with a merged layer of {@link GitHubLive} (for commit
|
|
21
|
+
* metadata) and {@link MarkdownLive} (for mdast parsing). Options are
|
|
22
|
+
* validated at the boundary via `validateChangesetOptions` before being
|
|
23
|
+
* passed to the formatters.
|
|
24
|
+
*
|
|
25
|
+
* ### Configuration
|
|
26
|
+
*
|
|
27
|
+
* Add the following to your `.changeset/config.json`:
|
|
28
|
+
*
|
|
29
|
+
* ```json
|
|
30
|
+
* {
|
|
31
|
+
* "changelog": ["\@savvy-web/changesets/changelog", { "repo": "savvy-web/package-name" }]
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* The `repo` option is **required** and must be in `owner/repo` format.
|
|
36
|
+
*
|
|
37
|
+
* ### Pipeline
|
|
38
|
+
*
|
|
39
|
+
* 1. **Options validation** — the raw `options` object from the Changesets
|
|
40
|
+
* config is decoded through `ChangesetOptionsSchema`.
|
|
41
|
+
* 2. **Release line formatting** — each changeset is formatted by
|
|
42
|
+
* `getReleaseLine`, which resolves GitHub metadata, parses sections,
|
|
43
|
+
* and produces structured markdown with commit links and attribution.
|
|
44
|
+
* 3. **Dependency table formatting** — bulk dependency updates are
|
|
45
|
+
* formatted by `getDependencyReleaseLine` into a markdown table.
|
|
46
|
+
*
|
|
47
|
+
* @example Configuring in `.changeset/config.json`
|
|
48
|
+
* ```json
|
|
49
|
+
* {
|
|
50
|
+
* "$schema": "https://unpkg.com/\@changesets/config\@3.1.1/schema.json",
|
|
51
|
+
* "changelog": ["\@savvy-web/changesets/changelog", { "repo": "savvy-web/my-package" }],
|
|
52
|
+
* "commit": false,
|
|
53
|
+
* "access": "public"
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @see {@link getReleaseLine} in `./getReleaseLine.ts` for individual changeset formatting
|
|
58
|
+
* @see {@link getDependencyReleaseLine} in `./getDependencyReleaseLine.ts` for dependency table formatting
|
|
59
|
+
*
|
|
60
|
+
* @packageDocumentation
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* Combined layer providing all services needed by the formatters.
|
|
64
|
+
*
|
|
65
|
+
* Merges {@link GitHubLive} and {@link MarkdownLive} into a single layer
|
|
66
|
+
* that satisfies the environment requirements of both `getReleaseLine`
|
|
67
|
+
* (which needs `GitHubService` and `MarkdownService`) and
|
|
68
|
+
* `getDependencyReleaseLine` (which needs `GitHubService`).
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
const MainLayer = Layer.mergeAll(GitHubLive, MarkdownLive);
|
|
73
|
+
/**
|
|
74
|
+
* Changesets API `ChangelogFunctions` implementation.
|
|
75
|
+
*
|
|
76
|
+
* This object satisfies the `ChangelogFunctions` contract from
|
|
77
|
+
* `\@changesets/types`. Each method validates options, runs the
|
|
78
|
+
* corresponding Effect program with the merged service layer, and
|
|
79
|
+
* returns a `Promise<string>`.
|
|
80
|
+
*
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
const changelogFunctions = {
|
|
84
|
+
getReleaseLine: async (changeset, versionType, options) => {
|
|
85
|
+
const program = Effect.gen(function* () {
|
|
86
|
+
return yield* getReleaseLine(changeset, versionType, yield* validateChangesetOptions(options));
|
|
87
|
+
});
|
|
88
|
+
return Effect.runPromise(program.pipe(Effect.provide(MainLayer)));
|
|
89
|
+
},
|
|
90
|
+
getDependencyReleaseLine: async (changesets, dependenciesUpdated, options) => {
|
|
91
|
+
const program = Effect.gen(function* () {
|
|
92
|
+
return yield* getDependencyReleaseLine(changesets, dependenciesUpdated, yield* validateChangesetOptions(options));
|
|
93
|
+
});
|
|
94
|
+
return Effect.runPromise(program.pipe(Effect.provide(MainLayer)));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
export { changelogFunctions as default };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/changesets/constants.ts
|
|
2
|
+
/**
|
|
3
|
+
* Constants for changeset lint rule documentation URLs.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Each lint rule in the \@savvy-web/changesets remark-lint plugin has a
|
|
7
|
+
* corresponding documentation page hosted on GitHub. These URLs are
|
|
8
|
+
* referenced in lint diagnostic messages to help users understand and
|
|
9
|
+
* resolve validation errors.
|
|
10
|
+
*
|
|
11
|
+
* Rule codes follow the `CSH` prefix convention:
|
|
12
|
+
* - `CSH001` -- Changeset heading validation
|
|
13
|
+
* - `CSH002` -- Changeset summary validation
|
|
14
|
+
* - `CSH003` -- Dependency table structure validation
|
|
15
|
+
* - `CSH004` -- Changeset body content validation
|
|
16
|
+
* - `CSH005` -- Frontmatter validation
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
/** Base URL for rule documentation on GitHub. */
|
|
22
|
+
const DOCS_BASE = "https://github.com/savvy-web/changesets/blob/main/docs/rules";
|
|
23
|
+
/**
|
|
24
|
+
* Documentation URLs for each changeset lint rule.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* Keyed by rule code (`CSH001`--`CSH005`). Each value is a full URL
|
|
28
|
+
* pointing to the rule's documentation page on GitHub. Used by the
|
|
29
|
+
* remark-lint plugins to attach documentation links to diagnostic
|
|
30
|
+
* messages.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
const RULE_DOCS = {
|
|
35
|
+
CSH001: `${DOCS_BASE}/CSH001.md`,
|
|
36
|
+
CSH002: `${DOCS_BASE}/CSH002.md`,
|
|
37
|
+
CSH003: `${DOCS_BASE}/CSH003.md`,
|
|
38
|
+
CSH004: `${DOCS_BASE}/CSH004.md`,
|
|
39
|
+
CSH005: `${DOCS_BASE}/CSH005.md`
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { RULE_DOCS };
|