@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,168 @@
|
|
|
1
|
+
import { ContentStructureRule } from "../remark/rules/content-structure.js";
|
|
2
|
+
import { HeadingHierarchyRule } from "../remark/rules/heading-hierarchy.js";
|
|
3
|
+
import { RequiredSectionsRule } from "../remark/rules/required-sections.js";
|
|
4
|
+
import { UncategorizedContentRule } from "../remark/rules/uncategorized-content.js";
|
|
5
|
+
import { stripFrontmatter } from "../utils/strip-frontmatter.js";
|
|
6
|
+
import remarkParse from "remark-parse";
|
|
7
|
+
import remarkStringify from "remark-stringify";
|
|
8
|
+
import { unified } from "unified";
|
|
9
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
//#region src/changesets/api/linter.ts
|
|
13
|
+
/**
|
|
14
|
+
* Class-based API wrapper for changeset linting.
|
|
15
|
+
*
|
|
16
|
+
* Provides a static class interface that runs all remark-lint rules
|
|
17
|
+
* against changeset markdown files and returns structured diagnostics.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Static class for linting changeset markdown files.
|
|
23
|
+
*
|
|
24
|
+
* Runs the four remark-lint rules (heading-hierarchy, required-sections,
|
|
25
|
+
* content-structure, uncategorized-content) against changeset markdown
|
|
26
|
+
* and returns structured {@link LintMessage} diagnostics.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* This class implements the pre-validation layer of the three-layer
|
|
30
|
+
* pipeline. It validates that changeset markdown conforms to the
|
|
31
|
+
* expected structure before the changelog formatter processes it.
|
|
32
|
+
*
|
|
33
|
+
* YAML frontmatter (the `---` delimited block at the top of changeset
|
|
34
|
+
* files containing package bump declarations) is automatically stripped
|
|
35
|
+
* before validation, since frontmatter is managed by Changesets itself
|
|
36
|
+
* and is not part of the markdown structure being validated.
|
|
37
|
+
*
|
|
38
|
+
* The class provides three granularity levels:
|
|
39
|
+
*
|
|
40
|
+
* - {@link ChangesetLinter.validateContent} -- validate a markdown string directly
|
|
41
|
+
* - {@link ChangesetLinter.validateFile} -- validate a single file by path
|
|
42
|
+
* - {@link ChangesetLinter.validate} -- validate all changeset files in a directory
|
|
43
|
+
*
|
|
44
|
+
* @example Validate a single file and report errors
|
|
45
|
+
* ```typescript
|
|
46
|
+
* import { ChangesetLinter } from "\@savvy-web/changesets";
|
|
47
|
+
* import type { LintMessage } from "\@savvy-web/changesets";
|
|
48
|
+
*
|
|
49
|
+
* const messages: LintMessage[] = ChangesetLinter.validateFile(
|
|
50
|
+
* ".changeset/brave-pandas-learn.md",
|
|
51
|
+
* );
|
|
52
|
+
*
|
|
53
|
+
* if (messages.length > 0) {
|
|
54
|
+
* for (const msg of messages) {
|
|
55
|
+
* console.error(`${msg.file}:${msg.line}:${msg.column} [${msg.rule}] ${msg.message}`);
|
|
56
|
+
* }
|
|
57
|
+
* process.exitCode = 1;
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example Validate all changesets in a directory
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { ChangesetLinter } from "\@savvy-web/changesets";
|
|
64
|
+
* import type { LintMessage } from "\@savvy-web/changesets";
|
|
65
|
+
*
|
|
66
|
+
* const allMessages: LintMessage[] = ChangesetLinter.validate(".changeset");
|
|
67
|
+
*
|
|
68
|
+
* const errorsByFile = new Map<string, LintMessage[]>();
|
|
69
|
+
* for (const msg of allMessages) {
|
|
70
|
+
* const existing = errorsByFile.get(msg.file) ?? [];
|
|
71
|
+
* existing.push(msg);
|
|
72
|
+
* errorsByFile.set(msg.file, existing);
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* for (const [file, msgs] of errorsByFile) {
|
|
76
|
+
* console.error(`${file}: ${msgs.length} issue(s)`);
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @example Validate markdown content directly (useful in tests)
|
|
81
|
+
* ```typescript
|
|
82
|
+
* import { ChangesetLinter } from "\@savvy-web/changesets";
|
|
83
|
+
* import type { LintMessage } from "\@savvy-web/changesets";
|
|
84
|
+
*
|
|
85
|
+
* const content = [
|
|
86
|
+
* "---",
|
|
87
|
+
* '"\@savvy-web/core": patch',
|
|
88
|
+
* "---",
|
|
89
|
+
* "",
|
|
90
|
+
* "## Bug Fixes",
|
|
91
|
+
* "",
|
|
92
|
+
* "Fixed an edge case in token validation.",
|
|
93
|
+
* ].join("\n");
|
|
94
|
+
*
|
|
95
|
+
* const messages: LintMessage[] = ChangesetLinter.validateContent(content);
|
|
96
|
+
* // messages.length === 0 (valid changeset)
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @see {@link LintMessage} for the diagnostic message shape
|
|
100
|
+
* @see {@link Categories} for the valid section headings checked by the rules
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
var ChangesetLinter = class ChangesetLinter {
|
|
105
|
+
/* v8 ignore next -- private constructor prevents direct instantiation */
|
|
106
|
+
constructor() {}
|
|
107
|
+
/**
|
|
108
|
+
* Validate a single changeset file by path.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* Reads the file synchronously, strips YAML frontmatter, and runs all
|
|
112
|
+
* four lint rules. The file path is preserved in each returned
|
|
113
|
+
* {@link LintMessage} for error reporting.
|
|
114
|
+
*
|
|
115
|
+
* @param filePath - Absolute or relative path to the changeset `.md` file
|
|
116
|
+
* @returns Array of {@link LintMessage} diagnostics (empty if the file is valid)
|
|
117
|
+
*/
|
|
118
|
+
static validateFile(filePath) {
|
|
119
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
120
|
+
return ChangesetLinter.validateContent(raw, filePath);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Validate a markdown string directly.
|
|
124
|
+
*
|
|
125
|
+
* @remarks
|
|
126
|
+
* Strips YAML frontmatter (if present) and runs all four lint rules
|
|
127
|
+
* against the remaining content. This method is useful for validating
|
|
128
|
+
* changeset content that is already in memory, such as in test suites
|
|
129
|
+
* or editor integrations.
|
|
130
|
+
*
|
|
131
|
+
* @param content - Raw markdown content (may include YAML frontmatter)
|
|
132
|
+
* @param filePath - File path for error reporting; defaults to `"<input>"`
|
|
133
|
+
* when validating in-memory content
|
|
134
|
+
* @returns Array of {@link LintMessage} diagnostics (empty if the content is valid)
|
|
135
|
+
*/
|
|
136
|
+
static validateContent(content, filePath = "<input>") {
|
|
137
|
+
const body = stripFrontmatter(content);
|
|
138
|
+
return unified().use(remarkParse).use(remarkStringify).use(HeadingHierarchyRule).use(RequiredSectionsRule).use(ContentStructureRule).use(UncategorizedContentRule).processSync(body).messages.map((msg) => ({
|
|
139
|
+
file: filePath,
|
|
140
|
+
/* v8 ignore next 3 -- ruleId/line/column fallbacks; remark-lint always provides these */
|
|
141
|
+
rule: msg.ruleId ?? msg.source ?? "unknown",
|
|
142
|
+
line: msg.line ?? 1,
|
|
143
|
+
column: msg.column ?? 1,
|
|
144
|
+
message: msg.message
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validate all changeset `.md` files in a directory.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Scans the directory for `*.md` files (excluding `README.md`) and runs
|
|
152
|
+
* {@link ChangesetLinter.validateFile} on each. Results are aggregated
|
|
153
|
+
* into a single array. The directory is read synchronously.
|
|
154
|
+
*
|
|
155
|
+
* This is the method used by the Effect CLI's `lint` and `check`
|
|
156
|
+
* subcommands to validate the `.changeset/` directory.
|
|
157
|
+
*
|
|
158
|
+
* @param dir - Path to the directory containing changeset files
|
|
159
|
+
* (typically `.changeset/`)
|
|
160
|
+
* @returns Aggregated array of {@link LintMessage} diagnostics from all files
|
|
161
|
+
*/
|
|
162
|
+
static validate(dir) {
|
|
163
|
+
return readdirSync(dir).filter((f) => f.endsWith(".md") && f !== "README.md").flatMap((filename) => ChangesetLinter.validateFile(join(dir, filename)));
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
export { ChangesetLinter };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ContributorFootnotesPlugin } from "../remark/plugins/contributor-footnotes.js";
|
|
2
|
+
import { DeduplicateItemsPlugin } from "../remark/plugins/deduplicate-items.js";
|
|
3
|
+
import { IssueLinkRefsPlugin } from "../remark/plugins/issue-link-refs.js";
|
|
4
|
+
import { MergeSectionsPlugin } from "../remark/plugins/merge-sections.js";
|
|
5
|
+
import { NormalizeFormatPlugin } from "../remark/plugins/normalize-format.js";
|
|
6
|
+
import { ReorderSectionsPlugin } from "../remark/plugins/reorder-sections.js";
|
|
7
|
+
import remarkGfm from "remark-gfm";
|
|
8
|
+
import remarkParse from "remark-parse";
|
|
9
|
+
import remarkStringify from "remark-stringify";
|
|
10
|
+
import { unified } from "unified";
|
|
11
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
12
|
+
|
|
13
|
+
//#region src/changesets/api/transformer.ts
|
|
14
|
+
/**
|
|
15
|
+
* Class-based API wrapper for changelog transformation.
|
|
16
|
+
*
|
|
17
|
+
* Provides a static class interface that runs all remark transform
|
|
18
|
+
* plugins against CHANGELOG markdown content as the post-processing
|
|
19
|
+
* layer of the three-layer pipeline.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Static class for post-processing CHANGELOG.md files.
|
|
25
|
+
*
|
|
26
|
+
* Implements the third layer of the three-layer pipeline by running
|
|
27
|
+
* six remark transform plugins in a fixed order to clean up, normalize,
|
|
28
|
+
* and enhance changelog output produced by the formatter layer.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* The six plugins run in this order:
|
|
32
|
+
*
|
|
33
|
+
* 1. **MergeSectionsPlugin** -- merges duplicate section headings (e.g., two
|
|
34
|
+
* "Features" sections from separate changesets are combined into one)
|
|
35
|
+
* 2. **ReorderSectionsPlugin** -- reorders sections by category priority
|
|
36
|
+
* (Breaking Changes first, Other last) using the {@link Categories} priority values
|
|
37
|
+
* 3. **DeduplicateItemsPlugin** -- removes duplicate list items within a section
|
|
38
|
+
* 4. **ContributorFootnotesPlugin** -- converts inline contributor mentions
|
|
39
|
+
* into footnote references for cleaner formatting
|
|
40
|
+
* 5. **IssueLinkRefsPlugin** -- converts inline issue/PR links into markdown
|
|
41
|
+
* reference-style links collected at the bottom of the document
|
|
42
|
+
* 6. **NormalizeFormatPlugin** -- applies consistent formatting (spacing,
|
|
43
|
+
* trailing newlines, heading levels)
|
|
44
|
+
*
|
|
45
|
+
* The transformer operates on the full CHANGELOG.md content (all versions),
|
|
46
|
+
* not just the latest release block. It is idempotent -- running it multiple
|
|
47
|
+
* times produces the same output.
|
|
48
|
+
*
|
|
49
|
+
* @example Transform changelog content in memory
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { ChangelogTransformer } from "\@savvy-web/changesets";
|
|
52
|
+
*
|
|
53
|
+
* const rawChangelog = [
|
|
54
|
+
* "# Changelog",
|
|
55
|
+
* "",
|
|
56
|
+
* "## 1.2.0",
|
|
57
|
+
* "",
|
|
58
|
+
* "### Features",
|
|
59
|
+
* "",
|
|
60
|
+
* "- Added new auth endpoint",
|
|
61
|
+
* "",
|
|
62
|
+
* "### Features",
|
|
63
|
+
* "",
|
|
64
|
+
* "- Added rate limiting",
|
|
65
|
+
* ].join("\n");
|
|
66
|
+
*
|
|
67
|
+
* const cleaned: string = ChangelogTransformer.transformContent(rawChangelog);
|
|
68
|
+
* // Duplicate "Features" sections are merged into one
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example Transform a CHANGELOG.md file in-place
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import { ChangelogTransformer } from "\@savvy-web/changesets";
|
|
74
|
+
*
|
|
75
|
+
* // Reads, transforms, and writes back to the same path
|
|
76
|
+
* ChangelogTransformer.transformFile("CHANGELOG.md");
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @example Check for changes without writing (dry-run pattern)
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import { readFileSync } from "node:fs";
|
|
82
|
+
* import { ChangelogTransformer } from "\@savvy-web/changesets";
|
|
83
|
+
*
|
|
84
|
+
* const original: string = readFileSync("CHANGELOG.md", "utf-8");
|
|
85
|
+
* const transformed: string = ChangelogTransformer.transformContent(original);
|
|
86
|
+
*
|
|
87
|
+
* if (original !== transformed) {
|
|
88
|
+
* console.error("CHANGELOG.md needs transformation");
|
|
89
|
+
* process.exitCode = 1;
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see {@link Categories} for the priority order used by ReorderSectionsPlugin
|
|
94
|
+
* @see {@link ChangesetLinter} for the pre-validation layer (layer 1)
|
|
95
|
+
* @see {@link Changelog} for the formatter layer (layer 2)
|
|
96
|
+
*
|
|
97
|
+
* @public
|
|
98
|
+
*/
|
|
99
|
+
var ChangelogTransformer = class ChangelogTransformer {
|
|
100
|
+
/* v8 ignore next -- private constructor prevents direct instantiation */
|
|
101
|
+
constructor() {}
|
|
102
|
+
/**
|
|
103
|
+
* Transform CHANGELOG markdown content by running all six transform plugins.
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* The input is parsed with `remark-parse` and `remark-gfm` (for table
|
|
107
|
+
* support), processed through all six plugins in order, and stringified
|
|
108
|
+
* back to markdown. The operation is synchronous and idempotent.
|
|
109
|
+
*
|
|
110
|
+
* @param content - Raw CHANGELOG markdown string (may contain multiple
|
|
111
|
+
* version blocks, GFM tables, footnotes, and reference links)
|
|
112
|
+
* @returns The transformed markdown string with sections merged, reordered,
|
|
113
|
+
* deduplicated, and normalized
|
|
114
|
+
*/
|
|
115
|
+
static transformContent(content) {
|
|
116
|
+
const file = unified().use(remarkParse).use(remarkGfm).use(MergeSectionsPlugin).use(ReorderSectionsPlugin).use(DeduplicateItemsPlugin).use(ContributorFootnotesPlugin).use(IssueLinkRefsPlugin).use(NormalizeFormatPlugin).use(remarkStringify).processSync(content);
|
|
117
|
+
return String(file);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Transform a CHANGELOG file in-place.
|
|
121
|
+
*
|
|
122
|
+
* @remarks
|
|
123
|
+
* Reads the file synchronously, runs all transform plugins via
|
|
124
|
+
* {@link ChangelogTransformer.transformContent}, and writes the result
|
|
125
|
+
* back to the same path. The file is overwritten atomically (single
|
|
126
|
+
* `writeFileSync` call).
|
|
127
|
+
*
|
|
128
|
+
* This is the method used by the Effect CLI's `transform` subcommand
|
|
129
|
+
* when invoked without the `--dry-run` or `--check` flags.
|
|
130
|
+
*
|
|
131
|
+
* @param filePath - Absolute or relative path to the CHANGELOG.md file
|
|
132
|
+
*/
|
|
133
|
+
static transformFile(filePath) {
|
|
134
|
+
const content = readFileSync(filePath, "utf-8");
|
|
135
|
+
writeFileSync(filePath, ChangelogTransformer.transformContent(content), "utf-8");
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
export { ChangelogTransformer };
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
//#region src/changesets/categories/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Breaking changes -- backward-incompatible changes.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Priority 1 (highest). This category has no associated commit types;
|
|
7
|
+
* it is resolved by the `!` suffix on any conventional commit type
|
|
8
|
+
* (e.g., `feat!:`, `fix!:`). Use {@link resolveCommitType} with
|
|
9
|
+
* `breaking: true` to map to this category.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
const BREAKING_CHANGES = {
|
|
14
|
+
heading: "Breaking Changes",
|
|
15
|
+
priority: 1,
|
|
16
|
+
commitTypes: [],
|
|
17
|
+
description: "Backward-incompatible changes"
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Features -- new functionality.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Priority 2. Maps from the `feat` conventional commit type.
|
|
24
|
+
*
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
const FEATURES = {
|
|
28
|
+
heading: "Features",
|
|
29
|
+
priority: 2,
|
|
30
|
+
commitTypes: ["feat"],
|
|
31
|
+
description: "New functionality"
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Bug Fixes -- bug corrections.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* Priority 3. Maps from the `fix` conventional commit type.
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
const BUG_FIXES = {
|
|
42
|
+
heading: "Bug Fixes",
|
|
43
|
+
priority: 3,
|
|
44
|
+
commitTypes: ["fix"],
|
|
45
|
+
description: "Bug corrections"
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Performance -- performance improvements.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* Priority 4. Maps from the `perf` conventional commit type.
|
|
52
|
+
*
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
const PERFORMANCE = {
|
|
56
|
+
heading: "Performance",
|
|
57
|
+
priority: 4,
|
|
58
|
+
commitTypes: ["perf"],
|
|
59
|
+
description: "Performance improvements"
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Documentation -- documentation changes.
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* Priority 5. Maps from the `docs` conventional commit type.
|
|
66
|
+
*
|
|
67
|
+
* @internal
|
|
68
|
+
*/
|
|
69
|
+
const DOCUMENTATION = {
|
|
70
|
+
heading: "Documentation",
|
|
71
|
+
priority: 5,
|
|
72
|
+
commitTypes: ["docs"],
|
|
73
|
+
description: "Documentation changes"
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Refactoring -- code restructuring without behavior change.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* Priority 6. Maps from the `refactor` conventional commit type.
|
|
80
|
+
*
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
const REFACTORING = {
|
|
84
|
+
heading: "Refactoring",
|
|
85
|
+
priority: 6,
|
|
86
|
+
commitTypes: ["refactor"],
|
|
87
|
+
description: "Code restructuring"
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Tests -- test additions or modifications.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* Priority 7. Maps from the `test` conventional commit type.
|
|
94
|
+
*
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
const TESTS = {
|
|
98
|
+
heading: "Tests",
|
|
99
|
+
priority: 7,
|
|
100
|
+
commitTypes: ["test"],
|
|
101
|
+
description: "Test additions or modifications"
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Build System -- build configuration changes.
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* Priority 8. Maps from the `build` conventional commit type.
|
|
108
|
+
*
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
const BUILD_SYSTEM = {
|
|
112
|
+
heading: "Build System",
|
|
113
|
+
priority: 8,
|
|
114
|
+
commitTypes: ["build"],
|
|
115
|
+
description: "Build configuration changes"
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* CI -- continuous integration changes.
|
|
119
|
+
*
|
|
120
|
+
* @remarks
|
|
121
|
+
* Priority 9. Maps from the `ci` conventional commit type.
|
|
122
|
+
*
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
const CI = {
|
|
126
|
+
heading: "CI",
|
|
127
|
+
priority: 9,
|
|
128
|
+
commitTypes: ["ci"],
|
|
129
|
+
description: "Continuous integration changes"
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Dependencies -- dependency updates.
|
|
133
|
+
*
|
|
134
|
+
* @remarks
|
|
135
|
+
* Priority 10. Maps from the `deps` conventional commit type and also
|
|
136
|
+
* from `chore(deps)` via the {@link resolveCommitType} function.
|
|
137
|
+
*
|
|
138
|
+
* @internal
|
|
139
|
+
*/
|
|
140
|
+
const DEPENDENCIES = {
|
|
141
|
+
heading: "Dependencies",
|
|
142
|
+
priority: 10,
|
|
143
|
+
commitTypes: ["deps"],
|
|
144
|
+
description: "Dependency updates"
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Maintenance -- general maintenance tasks.
|
|
148
|
+
*
|
|
149
|
+
* @remarks
|
|
150
|
+
* Priority 11. Maps from the `chore` and `style` conventional commit types.
|
|
151
|
+
* Note that `chore(deps)` is redirected to {@link DEPENDENCIES} by
|
|
152
|
+
* {@link resolveCommitType}.
|
|
153
|
+
*
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
const MAINTENANCE = {
|
|
157
|
+
heading: "Maintenance",
|
|
158
|
+
priority: 11,
|
|
159
|
+
commitTypes: ["chore", "style"],
|
|
160
|
+
description: "General maintenance"
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Reverts -- reverted changes.
|
|
164
|
+
*
|
|
165
|
+
* @remarks
|
|
166
|
+
* Priority 12. Maps from the `revert` conventional commit type.
|
|
167
|
+
*
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
170
|
+
const REVERTS = {
|
|
171
|
+
heading: "Reverts",
|
|
172
|
+
priority: 12,
|
|
173
|
+
commitTypes: ["revert"],
|
|
174
|
+
description: "Reverted changes"
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Other -- uncategorized changes.
|
|
178
|
+
*
|
|
179
|
+
* @remarks
|
|
180
|
+
* Priority 13 (lowest). This category has no associated commit types;
|
|
181
|
+
* it serves as the fallback for any commit type not recognized by the
|
|
182
|
+
* category system. Resolved by {@link resolveCommitType} when no other
|
|
183
|
+
* category matches.
|
|
184
|
+
*
|
|
185
|
+
* @internal
|
|
186
|
+
*/
|
|
187
|
+
const OTHER = {
|
|
188
|
+
heading: "Other",
|
|
189
|
+
priority: 13,
|
|
190
|
+
commitTypes: [],
|
|
191
|
+
description: "Uncategorized changes"
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* All 13 categories ordered by priority (ascending).
|
|
195
|
+
*
|
|
196
|
+
* @remarks
|
|
197
|
+
* This array provides the canonical ordering for section headings in
|
|
198
|
+
* CHANGELOG output. Breaking Changes appear first, Other appears last.
|
|
199
|
+
* The array is frozen (`as const`) to prevent accidental mutation.
|
|
200
|
+
*
|
|
201
|
+
* @internal
|
|
202
|
+
*/
|
|
203
|
+
const CATEGORIES = [
|
|
204
|
+
BREAKING_CHANGES,
|
|
205
|
+
FEATURES,
|
|
206
|
+
BUG_FIXES,
|
|
207
|
+
PERFORMANCE,
|
|
208
|
+
DOCUMENTATION,
|
|
209
|
+
REFACTORING,
|
|
210
|
+
TESTS,
|
|
211
|
+
BUILD_SYSTEM,
|
|
212
|
+
CI,
|
|
213
|
+
DEPENDENCIES,
|
|
214
|
+
MAINTENANCE,
|
|
215
|
+
REVERTS,
|
|
216
|
+
OTHER
|
|
217
|
+
];
|
|
218
|
+
/**
|
|
219
|
+
* Set of all valid section heading strings (case-insensitive lookup).
|
|
220
|
+
* Used by Layer 1 (remark-lint) to validate changeset headings.
|
|
221
|
+
*/
|
|
222
|
+
const headingToCategory = new Map(CATEGORIES.map((cat) => [cat.heading.toLowerCase(), cat]));
|
|
223
|
+
/**
|
|
224
|
+
* Map from commit type string to its category.
|
|
225
|
+
* Handles standard commit types. For `chore(deps)` and breaking `!` suffix,
|
|
226
|
+
* use {@link resolveCommitType} instead.
|
|
227
|
+
*/
|
|
228
|
+
const commitTypeToCategory = /* @__PURE__ */ new Map();
|
|
229
|
+
for (const cat of CATEGORIES) for (const commitType of cat.commitTypes) commitTypeToCategory.set(commitType, cat);
|
|
230
|
+
/**
|
|
231
|
+
* Resolve a conventional commit type (with optional scope and `!` suffix) to a category.
|
|
232
|
+
*
|
|
233
|
+
* @remarks
|
|
234
|
+
* This function implements the full commit-type-to-category mapping logic,
|
|
235
|
+
* including special cases:
|
|
236
|
+
* - Any commit with `breaking: true` maps to {@link BREAKING_CHANGES}
|
|
237
|
+
* - `chore` with scope `deps` maps to {@link DEPENDENCIES} (not Maintenance)
|
|
238
|
+
* - Unrecognized types fall through to {@link OTHER}
|
|
239
|
+
*
|
|
240
|
+
* @param type - The commit type (e.g., `"feat"`, `"fix"`, `"chore"`)
|
|
241
|
+
* @param scope - Optional scope (e.g., `"deps"` in `chore(deps):`)
|
|
242
|
+
* @param breaking - Whether the commit has a `!` suffix indicating a breaking change
|
|
243
|
+
* @returns The resolved section category
|
|
244
|
+
*
|
|
245
|
+
* @internal
|
|
246
|
+
*/
|
|
247
|
+
function resolveCommitType(type, scope, breaking) {
|
|
248
|
+
if (breaking) return BREAKING_CHANGES;
|
|
249
|
+
if (type === "chore" && scope === "deps") return DEPENDENCIES;
|
|
250
|
+
return commitTypeToCategory.get(type) ?? OTHER;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Look up a category by its section heading text.
|
|
254
|
+
*
|
|
255
|
+
* @remarks
|
|
256
|
+
* Comparison is case-insensitive: `"features"`, `"Features"`, and
|
|
257
|
+
* `"FEATURES"` all match the Features category.
|
|
258
|
+
*
|
|
259
|
+
* @param heading - The heading text (e.g., `"Features"`, `"Bug Fixes"`)
|
|
260
|
+
* @returns The matching category, or `undefined` if not recognized
|
|
261
|
+
*
|
|
262
|
+
* @internal
|
|
263
|
+
*/
|
|
264
|
+
function fromHeading(heading) {
|
|
265
|
+
return headingToCategory.get(heading.toLowerCase());
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Check whether a heading string matches a known category.
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* Comparison is case-insensitive. Useful for validating that a markdown
|
|
272
|
+
* heading in a changeset file corresponds to a recognized section.
|
|
273
|
+
*
|
|
274
|
+
* @param heading - The heading text to check
|
|
275
|
+
* @returns `true` if the heading matches a known category
|
|
276
|
+
*
|
|
277
|
+
* @internal
|
|
278
|
+
*/
|
|
279
|
+
function isValidHeading(heading) {
|
|
280
|
+
return headingToCategory.has(heading.toLowerCase());
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get all valid section heading strings.
|
|
284
|
+
*
|
|
285
|
+
* @remarks
|
|
286
|
+
* Returns the headings in priority order, matching the order of {@link CATEGORIES}.
|
|
287
|
+
* Useful for generating help text or validation error messages that list
|
|
288
|
+
* accepted headings.
|
|
289
|
+
*
|
|
290
|
+
* @returns Array of heading strings (e.g., `["Breaking Changes", "Features", ...]`)
|
|
291
|
+
*
|
|
292
|
+
* @internal
|
|
293
|
+
*/
|
|
294
|
+
function allHeadings() {
|
|
295
|
+
return CATEGORIES.map((cat) => cat.heading);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
//#endregion
|
|
299
|
+
export { BREAKING_CHANGES, BUG_FIXES, BUILD_SYSTEM, CATEGORIES, CI, DEPENDENCIES, DOCUMENTATION, FEATURES, MAINTENANCE, OTHER, PERFORMANCE, REFACTORING, REVERTS, TESTS, allHeadings, fromHeading, isValidHeading, resolveCommitType };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/changesets/categories/types.ts
|
|
4
|
+
/**
|
|
5
|
+
* Section category schema and type definitions.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Section categories define how changes are grouped and ordered in release
|
|
9
|
+
* notes and CHANGELOGs. Each category maps conventional commit types to a
|
|
10
|
+
* display heading with a priority for ordering. Categories are used across
|
|
11
|
+
* all three processing layers: remark-lint pre-validation (Layer 1),
|
|
12
|
+
* changelog formatting (Layer 2), and remark-transform post-processing
|
|
13
|
+
* (Layer 3).
|
|
14
|
+
*
|
|
15
|
+
* @see {@link CATEGORIES} for the predefined list of 13 section categories
|
|
16
|
+
* @see {@link resolveCommitType} for mapping commit types to categories
|
|
17
|
+
* @see {@link https://effect.website/docs/schema/introduction | Effect Schema documentation}
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Schema for a section category that defines how changes are grouped in release notes.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* A section category has four fields:
|
|
26
|
+
* - `heading` -- the display heading used in CHANGELOG output (e.g., `"Features"`, `"Bug Fixes"`)
|
|
27
|
+
* - `priority` -- an integer controlling display order (lower = higher priority)
|
|
28
|
+
* - `commitTypes` -- conventional commit type prefixes that map to this category (e.g., `["feat"]`)
|
|
29
|
+
* - `description` -- a brief human-readable description for documentation
|
|
30
|
+
*
|
|
31
|
+
* Categories with an empty `commitTypes` array are resolved through other means:
|
|
32
|
+
* `BREAKING_CHANGES` is resolved via the `!` suffix on any commit type, and
|
|
33
|
+
* `OTHER` is the fallback for unrecognized types.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { Schema } from "effect";
|
|
38
|
+
* import { SectionCategorySchema } from "@savvy-web/changesets";
|
|
39
|
+
* import type { SectionCategory } from "@savvy-web/changesets";
|
|
40
|
+
*
|
|
41
|
+
* const category: SectionCategory = Schema.decodeUnknownSync(SectionCategorySchema)({
|
|
42
|
+
* heading: "Features",
|
|
43
|
+
* priority: 2,
|
|
44
|
+
* commitTypes: ["feat"],
|
|
45
|
+
* description: "New functionality",
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @see {@link SectionCategory} for the inferred TypeScript type
|
|
50
|
+
* @see {@link CATEGORIES} for all predefined categories
|
|
51
|
+
*
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
const SectionCategorySchema = Schema.Struct({
|
|
55
|
+
/** Display heading used in CHANGELOG output. */
|
|
56
|
+
heading: Schema.String,
|
|
57
|
+
/** Priority for ordering (lower = higher priority). */
|
|
58
|
+
priority: Schema.Number,
|
|
59
|
+
/** Conventional commit types that map to this category. */
|
|
60
|
+
commitTypes: Schema.Array(Schema.String),
|
|
61
|
+
/** Brief description for documentation. */
|
|
62
|
+
description: Schema.String
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
export { SectionCategorySchema };
|