@savvy-web/silk-effects 0.6.0 → 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.
Files changed (155) hide show
  1. package/README.md +48 -17
  2. package/_virtual/_rolldown/runtime.js +18 -0
  3. package/changesets/api/categories.js +247 -0
  4. package/changesets/api/changelog.js +134 -0
  5. package/changesets/api/dependency-table.js +163 -0
  6. package/changesets/api/linter.js +168 -0
  7. package/changesets/api/transformer.js +140 -0
  8. package/changesets/categories/index.js +299 -0
  9. package/changesets/categories/types.js +66 -0
  10. package/changesets/changelog/formatting.js +119 -0
  11. package/changesets/changelog/getDependencyReleaseLine.js +114 -0
  12. package/changesets/changelog/getReleaseLine.js +122 -0
  13. package/changesets/changelog/index.js +99 -0
  14. package/changesets/constants.js +43 -0
  15. package/changesets/errors.js +305 -0
  16. package/changesets/index.js +146 -0
  17. package/changesets/markdownlint/index.js +29 -0
  18. package/changesets/markdownlint/rules/content-structure.js +98 -0
  19. package/changesets/markdownlint/rules/dependency-table-format.js +170 -0
  20. package/changesets/markdownlint/rules/heading-hierarchy.js +61 -0
  21. package/changesets/markdownlint/rules/required-sections.js +54 -0
  22. package/changesets/markdownlint/rules/uncategorized-content.js +54 -0
  23. package/changesets/markdownlint/rules/utils.js +30 -0
  24. package/changesets/remark/plugins/aggregate-dependency-tables.js +47 -0
  25. package/changesets/remark/plugins/contributor-footnotes.js +123 -0
  26. package/changesets/remark/plugins/deduplicate-items.js +30 -0
  27. package/changesets/remark/plugins/issue-link-refs.js +58 -0
  28. package/changesets/remark/plugins/merge-sections.js +43 -0
  29. package/changesets/remark/plugins/normalize-format.js +47 -0
  30. package/changesets/remark/plugins/reorder-sections.js +34 -0
  31. package/changesets/remark/presets.js +119 -0
  32. package/changesets/remark/rules/content-structure.js +22 -0
  33. package/changesets/remark/rules/dependency-table-format.js +40 -0
  34. package/changesets/remark/rules/heading-hierarchy.js +19 -0
  35. package/changesets/remark/rules/required-sections.js +17 -0
  36. package/changesets/remark/rules/uncategorized-content.js +31 -0
  37. package/changesets/schemas/changeset.js +146 -0
  38. package/changesets/schemas/dependency-table.js +189 -0
  39. package/changesets/schemas/git.js +69 -0
  40. package/changesets/schemas/github.js +175 -0
  41. package/changesets/schemas/options.js +182 -0
  42. package/changesets/schemas/package-scope.js +128 -0
  43. package/changesets/schemas/primitives.js +72 -0
  44. package/changesets/schemas/version-files.js +151 -0
  45. package/changesets/services/branch-analyzer.js +278 -0
  46. package/changesets/services/changelog.js +50 -0
  47. package/changesets/services/config-inspector.js +390 -0
  48. package/changesets/services/github.js +178 -0
  49. package/changesets/services/markdown.js +106 -0
  50. package/changesets/services/workspace-snapshot.js +182 -0
  51. package/changesets/utils/commit-parser.js +80 -0
  52. package/changesets/utils/dep-diff.js +77 -0
  53. package/changesets/utils/dependency-table.js +347 -0
  54. package/changesets/utils/issue-refs.js +101 -0
  55. package/changesets/utils/jsonpath.js +175 -0
  56. package/changesets/utils/logger.js +50 -0
  57. package/changesets/utils/markdown-link.js +57 -0
  58. package/changesets/utils/publishability.js +39 -0
  59. package/changesets/utils/remark-pipeline.js +79 -0
  60. package/changesets/utils/section-parser.js +94 -0
  61. package/changesets/utils/strip-frontmatter.js +46 -0
  62. package/changesets/utils/version-blocks.js +108 -0
  63. package/changesets/utils/version-files.js +336 -0
  64. package/changesets/utils/worktree-snapshot.js +142 -0
  65. package/changesets/vendor/github-info.js +55 -0
  66. package/commitlint/config/factory.js +69 -0
  67. package/commitlint/config/plugins.js +227 -0
  68. package/commitlint/config/rules.js +155 -0
  69. package/commitlint/config/schema.js +46 -0
  70. package/commitlint/detection/dco.js +53 -0
  71. package/commitlint/detection/scopes.js +45 -0
  72. package/commitlint/formatter/format.js +85 -0
  73. package/commitlint/formatter/messages.js +79 -0
  74. package/commitlint/hook/diagnostics/branch.js +36 -0
  75. package/commitlint/hook/diagnostics/cache.js +37 -0
  76. package/commitlint/hook/diagnostics/commitlint-config.js +36 -0
  77. package/commitlint/hook/diagnostics/open-issues.js +56 -0
  78. package/commitlint/hook/diagnostics/package-manager.js +51 -0
  79. package/commitlint/hook/diagnostics/signing.js +107 -0
  80. package/commitlint/hook/envelope.js +46 -0
  81. package/commitlint/hook/output.js +45 -0
  82. package/commitlint/hook/parse-bash-command.js +105 -0
  83. package/commitlint/hook/rules/closes-trailer.js +31 -0
  84. package/commitlint/hook/rules/forbidden-content.js +32 -0
  85. package/commitlint/hook/rules/plan-leakage.js +36 -0
  86. package/commitlint/hook/rules/signing-flag-conflict.js +25 -0
  87. package/commitlint/hook/rules/soft-wrap.js +37 -0
  88. package/commitlint/hook/rules/types.js +14 -0
  89. package/commitlint/hook/rules/verbosity.js +31 -0
  90. package/commitlint/hook/silence-logger.js +39 -0
  91. package/commitlint/index.js +146 -0
  92. package/commitlint/prompt/config.js +91 -0
  93. package/commitlint/prompt/emojis.js +74 -0
  94. package/commitlint/prompt/prompter.js +135 -0
  95. package/commitlint/static.js +73 -0
  96. package/errors/BiomeSyncError.js +21 -0
  97. package/errors/ChangesetConfigError.js +20 -0
  98. package/errors/ConfigNotFoundError.js +21 -0
  99. package/errors/SectionParseError.js +16 -0
  100. package/errors/SectionValidationError.js +16 -0
  101. package/errors/SectionWriteError.js +16 -0
  102. package/errors/TagFormatError.js +20 -0
  103. package/errors/ToolNotFoundError.js +11 -0
  104. package/errors/ToolResolutionError.js +11 -0
  105. package/errors/ToolVersionMismatchError.js +11 -0
  106. package/errors/VersioningDetectionError.js +20 -0
  107. package/errors/WorkspaceAnalysisError.js +21 -0
  108. package/index.d.ts +9743 -8380
  109. package/index.js +36 -6657
  110. package/lint/Handler.js +39 -0
  111. package/lint/cli/sections.js +65 -0
  112. package/lint/cli/templates/markdownlint.gen.js +183 -0
  113. package/lint/config/Preset.js +152 -0
  114. package/lint/config/createConfig.js +89 -0
  115. package/lint/handlers/Biome.js +179 -0
  116. package/lint/handlers/Markdown.js +139 -0
  117. package/lint/handlers/PackageJson.js +130 -0
  118. package/lint/handlers/PnpmWorkspace.js +141 -0
  119. package/lint/handlers/ShellScripts.js +58 -0
  120. package/lint/handlers/TypeScript.js +134 -0
  121. package/lint/handlers/Yaml.js +167 -0
  122. package/lint/index.js +52 -0
  123. package/lint/utils/Command.js +285 -0
  124. package/lint/utils/Filter.js +100 -0
  125. package/lint/utils/Workspace.js +86 -0
  126. package/package.json +52 -63
  127. package/schemas/CommentStyle.js +16 -0
  128. package/schemas/ResolvedTool.js +63 -0
  129. package/schemas/SavvySections.js +113 -0
  130. package/schemas/SectionBlock.js +70 -0
  131. package/schemas/SectionDefinition.js +121 -0
  132. package/schemas/SectionResults.js +12 -0
  133. package/schemas/TagStrategySchemas.js +18 -0
  134. package/schemas/ToolDefinition.js +39 -0
  135. package/schemas/ToolResults.js +14 -0
  136. package/schemas/VersioningSchemas.js +95 -0
  137. package/schemas/WorkspaceAnalysisSchemas.js +190 -0
  138. package/services/BiomeSchemaSync.js +133 -0
  139. package/services/ChangesetConfig.js +78 -0
  140. package/services/ChangesetConfigReader.js +106 -0
  141. package/services/ConfigDiscovery.js +71 -0
  142. package/services/ManagedSection.js +288 -0
  143. package/services/SilkPublishability.js +193 -0
  144. package/services/SilkWorkspaceAnalyzer.js +213 -0
  145. package/services/TagStrategy.js +54 -0
  146. package/services/ToolDiscovery.js +229 -0
  147. package/services/VersioningStrategy.js +67 -0
  148. package/tsdoc-metadata.json +11 -11
  149. package/turbo/digest.js +127 -0
  150. package/turbo/errors.js +48 -0
  151. package/turbo/index.js +32 -0
  152. package/turbo/schemas/DryRun.js +57 -0
  153. package/turbo/schemas/results.js +61 -0
  154. package/turbo/services/TurboInspector.js +100 -0
  155. package/utils/ToolCommand.js +40 -0
package/README.md CHANGED
@@ -13,6 +13,7 @@ Shared [Effect](https://effect.website/) library providing Silk Suite convention
13
13
  - Discover and resolve CLI tools globally or locally with version enforcement and caching
14
14
  - Detect versioning strategy and format git tags from changeset configuration
15
15
  - Locate config files and keep Biome schema URLs in sync across workspaces
16
+ - Inspect a Turborepo read-only — diagnose per-package cache hits, derive the task graph and compute affected packages, all over `turbo --dry`
16
17
 
17
18
  ## Install
18
19
 
@@ -36,17 +37,21 @@ import {
36
37
  } from "@savvy-web/silk-effects";
37
38
  ```
38
39
 
39
- `SilkPublishability.detect` is a pure static — no layers, no Effect runtime. Pass a package name and the raw `package.json` and get back the publish targets the silk rules resolve:
40
+ `SilkPublishability.detect` is a pure static — no layers, no Effect runtime. Pass a package name, the raw `package.json` and the bundler's resolved target binding (or `null` before the prod build has run) and get back the publish targets the silk rules resolve:
40
41
 
41
42
  ```typescript
42
43
  import { SilkPublishability } from "@savvy-web/silk-effects";
43
44
 
44
- const targets = SilkPublishability.detect("@my-org/my-package", {
45
- private: true,
46
- publishConfig: { access: "public", targets: ["npm", "github"] },
47
- });
48
- // => [PublishTarget { name: "@my-org/my-package", registry: "https://registry.npmjs.org/", ... },
49
- // PublishTarget { name: "@my-org/my-package", registry: "https://npm.pkg.github.com/", ... }]
45
+ const targets = SilkPublishability.detect(
46
+ "@my-org/my-package",
47
+ {
48
+ private: true,
49
+ publishConfig: { access: "public", targets: { npm: true, github: true } },
50
+ },
51
+ null, // pre-build: one count-accurate placeholder per declared target key
52
+ );
53
+ // => [PublishTarget { name: "@my-org/my-package", registry: "https://registry.npmjs.org", ... },
54
+ // PublishTarget { name: "@my-org/my-package", registry: "https://npm.pkg.github.com", ... }]
50
55
  ```
51
56
 
52
57
  ## Services
@@ -61,23 +66,27 @@ These services are pure logic — no filesystem or shell access needed.
61
66
 
62
67
  #### SilkPublishability
63
68
 
64
- Apply silk publishability rules to a raw `package.json` and resolve its publish targets. Targets are `PublishTarget` records from `workspaces-effect` with `name`, `registry`, `directory`, `access` and `provenance` fields. The static `detect`, `expandShorthand` and `resolveTargetAccess` helpers are pure; `resolveTargets` and `listPublishable` are Effects that read from disk (see below).
69
+ Apply silk publishability rules to a raw `package.json` and the bundler's resolved target binding, and resolve the publish targets. Targets are `PublishTarget` records from `workspaces-effect` with `name`, `registry`, `directory`, `access` and `provenance` fields. The static `detect` helper is pure; `resolveTargets` and `listPublishable` are Effects that read from disk (see below), and `readTargetsBinding` reads the binding `detect` consumes.
65
70
 
66
- In silk mode `private: true` is the norm on workspace `package.json` files. Publishability is derived from `publishConfig`, with the `private` flag consulted only as a last-resort default.
71
+ In silk mode `private: true` is the norm on workspace `package.json` files. Publishability is derived from `publishConfig`, with the `private` flag consulted only as a last-resort default. Publish targets are declared as the bundler's keyed `publishConfig.targets` map; the legacy array form is no longer supported.
67
72
 
68
73
  ```typescript
69
74
  import { SilkPublishability } from "@savvy-web/silk-effects";
70
75
 
71
- // Targets-first: one PublishTarget per surviving publishConfig.targets entry
72
- const targets = SilkPublishability.detect("@my-org/pkg", {
73
- private: true,
74
- publishConfig: { access: "public", targets: ["npm", "github"] },
75
- });
76
- // => [PublishTarget { registry: "https://registry.npmjs.org/", access: "public", ... },
77
- // PublishTarget { registry: "https://npm.pkg.github.com/", access: "public", ... }]
76
+ // Targets-first: one PublishTarget per declared publishConfig.targets key
77
+ const targets = SilkPublishability.detect(
78
+ "@my-org/pkg",
79
+ {
80
+ private: true,
81
+ publishConfig: { access: "public", targets: { npm: true, github: true } },
82
+ },
83
+ null, // pre-build placeholder; pass the dist/prod/targets.json binding post-build
84
+ );
85
+ // => [PublishTarget { registry: "https://registry.npmjs.org", access: "public", ... },
86
+ // PublishTarget { registry: "https://npm.pkg.github.com", access: "public", ... }]
78
87
 
79
88
  // Not publishable -> empty array
80
- const none = SilkPublishability.detect("@my-org/internal", { private: true });
89
+ const none = SilkPublishability.detect("@my-org/internal", { private: true }, null);
81
90
  // => []
82
91
  ```
83
92
 
@@ -379,6 +388,28 @@ const biome = yield* td.require(
379
388
  );
380
389
  ```
381
390
 
391
+ #### TurboInspector
392
+
393
+ Read-only Turborepo inspection. Every method shells out to `turbo` with `--dry=json`, so no task ever runs. `diagnoseCache(task, cwd)` reports a per-package cache HIT/MISS breakdown for a task, `taskGraph(cwd, task?)` derives the task graph and its critical path and `affected(cwd, base?)` lists the packages affected relative to `base` (default `main`). It resolves the `turbo` binary through `ToolDiscovery` and fails with a tagged error when `turbo` is missing or the directory is not a Turborepo. The service tag and its layer are exported under the `Turbo` namespace.
394
+
395
+ ```typescript
396
+ import { Effect } from "effect";
397
+ import { NodeContext } from "@effect/platform-node";
398
+ import { Turbo, ToolDiscoveryLive } from "@savvy-web/silk-effects";
399
+
400
+ const diagnosis = await Effect.runPromise(
401
+ Effect.gen(function* () {
402
+ const turbo = yield* Turbo.TurboInspector;
403
+ return yield* turbo.diagnoseCache("build:dev", process.cwd());
404
+ }).pipe(
405
+ Effect.provide(Turbo.TurboInspectorLive),
406
+ Effect.provide(ToolDiscoveryLive),
407
+ Effect.provide(NodeContext.layer),
408
+ ),
409
+ );
410
+ // => CacheDiagnosis: per-package HIT/MISS breakdown for the task
411
+ ```
412
+
382
413
  ## Documentation
383
414
 
384
415
  - [Overview](./docs/overview.md) — what the library is, its design philosophy and platform-layer model
@@ -0,0 +1,18 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (!no_symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ export { __exportAll };
@@ -0,0 +1,247 @@
1
+ import { BREAKING_CHANGES, BUG_FIXES, BUILD_SYSTEM, CATEGORIES, CI, DEPENDENCIES, DOCUMENTATION, FEATURES, MAINTENANCE, OTHER, PERFORMANCE, REFACTORING, REVERTS, TESTS, allHeadings, fromHeading, isValidHeading, resolveCommitType } from "../categories/index.js";
2
+
3
+ //#region src/changesets/api/categories.ts
4
+ /**
5
+ * Class-based API wrapper for section categories.
6
+ *
7
+ * Provides a static class interface that bridges to the underlying
8
+ * Effect-native category functions for higher-level consumers.
9
+ *
10
+ * @internal
11
+ */
12
+ /**
13
+ * Static class wrapper for section category operations.
14
+ *
15
+ * Provides methods for resolving conventional commit types to changelog
16
+ * section categories, validating section headings, and accessing the
17
+ * canonical set of 13 section categories used throughout the pipeline.
18
+ *
19
+ * @remarks
20
+ * This class wraps the pure functions and constants from the internal
21
+ * `categories/` module. Each {@link SectionCategory} is defined by the
22
+ * {@link SectionCategorySchema} Effect Schema, which provides runtime
23
+ * validation at system boundaries. The class itself is stateless; all
24
+ * methods and properties are `static`.
25
+ *
26
+ * Categories control how changelog entries are grouped and ordered.
27
+ * Lower priority numbers appear first in the output. The 13 built-in
28
+ * categories cover all conventional commit types plus special cases
29
+ * like dependency updates and breaking changes.
30
+ *
31
+ * @example Looking up categories from commit metadata
32
+ * ```typescript
33
+ * import { Categories } from "\@savvy-web/changesets";
34
+ * import type { SectionCategory } from "\@savvy-web/changesets";
35
+ *
36
+ * // Resolve a conventional commit type to its category
37
+ * const feature: SectionCategory = Categories.fromCommitType("feat");
38
+ * // feature.heading === "Features"
39
+ * // feature.priority === 2
40
+ *
41
+ * // Breaking changes always win regardless of commit type
42
+ * const breaking: SectionCategory = Categories.fromCommitType("fix", undefined, true);
43
+ * // breaking.heading === "Breaking Changes"
44
+ * // breaking.priority === 1
45
+ *
46
+ * // The special scope "deps" on "chore" maps to Dependencies
47
+ * const deps: SectionCategory = Categories.fromCommitType("chore", "deps");
48
+ * // deps.heading === "Dependencies"
49
+ * ```
50
+ *
51
+ * @example Validating section headings
52
+ * ```typescript
53
+ * import { Categories } from "\@savvy-web/changesets";
54
+ *
55
+ * const headings: readonly string[] = Categories.allHeadings();
56
+ * // ["Breaking Changes", "Features", "Bug Fixes", ...]
57
+ *
58
+ * const valid: boolean = Categories.isValidHeading("Bug Fixes");
59
+ * // true
60
+ *
61
+ * const unknown: boolean = Categories.isValidHeading("Miscellaneous");
62
+ * // false
63
+ * ```
64
+ *
65
+ * @example Reverse-lookup from heading text
66
+ * ```typescript
67
+ * import { Categories } from "\@savvy-web/changesets";
68
+ * import type { SectionCategory } from "\@savvy-web/changesets";
69
+ *
70
+ * const category: SectionCategory | undefined = Categories.fromHeading("Features");
71
+ * if (category) {
72
+ * const commitTypes: readonly string[] = category.commitTypes;
73
+ * // ["feat"]
74
+ * }
75
+ * ```
76
+ *
77
+ * @see {@link SectionCategory} for the category shape (heading, priority, commitTypes, description)
78
+ * @see {@link SectionCategorySchema} for the Effect Schema that validates category data
79
+ *
80
+ * @public
81
+ */
82
+ var Categories = class {
83
+ constructor() {}
84
+ /**
85
+ * Breaking changes -- backward-incompatible changes (priority 1).
86
+ *
87
+ * @remarks
88
+ * Mapped from any commit type when the `breaking` flag is `true`.
89
+ * Always appears first in changelog output.
90
+ */
91
+ static BREAKING_CHANGES = BREAKING_CHANGES;
92
+ /**
93
+ * Features -- new functionality (priority 2).
94
+ *
95
+ * @remarks
96
+ * Mapped from the `feat` commit type.
97
+ */
98
+ static FEATURES = FEATURES;
99
+ /**
100
+ * Bug Fixes -- bug corrections (priority 3).
101
+ *
102
+ * @remarks
103
+ * Mapped from the `fix` commit type.
104
+ */
105
+ static BUG_FIXES = BUG_FIXES;
106
+ /**
107
+ * Performance -- performance improvements (priority 4).
108
+ *
109
+ * @remarks
110
+ * Mapped from the `perf` commit type.
111
+ */
112
+ static PERFORMANCE = PERFORMANCE;
113
+ /**
114
+ * Documentation -- documentation changes (priority 5).
115
+ *
116
+ * @remarks
117
+ * Mapped from the `docs` commit type.
118
+ */
119
+ static DOCUMENTATION = DOCUMENTATION;
120
+ /**
121
+ * Refactoring -- code restructuring (priority 6).
122
+ *
123
+ * @remarks
124
+ * Mapped from the `refactor` commit type.
125
+ */
126
+ static REFACTORING = REFACTORING;
127
+ /**
128
+ * Tests -- test additions or modifications (priority 7).
129
+ *
130
+ * @remarks
131
+ * Mapped from the `test` commit type.
132
+ */
133
+ static TESTS = TESTS;
134
+ /**
135
+ * Build System -- build configuration changes (priority 8).
136
+ *
137
+ * @remarks
138
+ * Mapped from the `build` commit type.
139
+ */
140
+ static BUILD_SYSTEM = BUILD_SYSTEM;
141
+ /**
142
+ * CI -- continuous integration changes (priority 9).
143
+ *
144
+ * @remarks
145
+ * Mapped from the `ci` commit type.
146
+ */
147
+ static CI = CI;
148
+ /**
149
+ * Dependencies -- dependency updates (priority 10).
150
+ *
151
+ * @remarks
152
+ * Mapped from `chore(deps)` and similar dependency-scoped commits.
153
+ */
154
+ static DEPENDENCIES = DEPENDENCIES;
155
+ /**
156
+ * Maintenance -- general maintenance (priority 11).
157
+ *
158
+ * @remarks
159
+ * Mapped from the `chore` commit type (without the `deps` scope).
160
+ */
161
+ static MAINTENANCE = MAINTENANCE;
162
+ /**
163
+ * Reverts -- reverted changes (priority 12).
164
+ *
165
+ * @remarks
166
+ * Mapped from the `revert` commit type.
167
+ */
168
+ static REVERTS = REVERTS;
169
+ /**
170
+ * Other -- uncategorized changes (priority 13).
171
+ *
172
+ * @remarks
173
+ * Fallback category for unrecognized commit types. Always appears
174
+ * last in changelog output.
175
+ */
176
+ static OTHER = OTHER;
177
+ /**
178
+ * All 13 categories ordered by priority (ascending, 1-13).
179
+ *
180
+ * @remarks
181
+ * This array is frozen and sorted from highest priority (Breaking Changes)
182
+ * to lowest (Other). Useful for iterating over categories in display order.
183
+ */
184
+ static ALL = CATEGORIES;
185
+ /**
186
+ * Resolve a conventional commit type to its section category.
187
+ *
188
+ * @remarks
189
+ * Resolution follows a precedence chain:
190
+ *
191
+ * 1. If `breaking` is `true`, always returns {@link Categories.BREAKING_CHANGES}
192
+ * 2. If `type` is `"chore"` and `scope` is `"deps"`, returns {@link Categories.DEPENDENCIES}
193
+ * 3. Otherwise, looks up `type` in the `commitTypes` arrays of all categories
194
+ * 4. Falls back to {@link Categories.OTHER} for unrecognized types
195
+ *
196
+ * @param type - The conventional commit type (e.g., `"feat"`, `"fix"`, `"chore"`)
197
+ * @param scope - Optional commit scope (e.g., `"deps"` from `chore(deps):`)
198
+ * @param breaking - Whether the commit includes a breaking change indicator (`!`)
199
+ * @returns The resolved {@link SectionCategory}
200
+ */
201
+ static fromCommitType(type, scope, breaking) {
202
+ return resolveCommitType(type, scope, breaking);
203
+ }
204
+ /**
205
+ * Look up a category by its section heading text.
206
+ *
207
+ * @remarks
208
+ * Comparison is case-insensitive. For example, both `"Bug Fixes"` and
209
+ * `"bug fixes"` will match {@link Categories.BUG_FIXES}.
210
+ *
211
+ * @param heading - The heading text (e.g., `"Features"`, `"Bug Fixes"`)
212
+ * @returns The matching {@link SectionCategory}, or `undefined` if the heading
213
+ * does not correspond to any known category
214
+ */
215
+ static fromHeading(heading) {
216
+ return fromHeading(heading);
217
+ }
218
+ /**
219
+ * Get all valid section heading strings in priority order.
220
+ *
221
+ * @remarks
222
+ * Returns the `heading` field from each category in {@link Categories.ALL},
223
+ * preserving priority order. Useful for building validation sets or
224
+ * rendering category pickers.
225
+ *
226
+ * @returns Readonly array of heading strings (e.g., `["Breaking Changes", "Features", ...]`)
227
+ */
228
+ static allHeadings() {
229
+ return allHeadings();
230
+ }
231
+ /**
232
+ * Check whether a heading string matches a known category.
233
+ *
234
+ * @remarks
235
+ * Comparison is case-insensitive. Equivalent to
236
+ * `Categories.fromHeading(heading) !== undefined`.
237
+ *
238
+ * @param heading - The heading text to validate
239
+ * @returns `true` if the heading matches a known category, `false` otherwise
240
+ */
241
+ static isValidHeading(heading) {
242
+ return isValidHeading(heading);
243
+ }
244
+ };
245
+
246
+ //#endregion
247
+ export { Categories };
@@ -0,0 +1,134 @@
1
+ import changelogFunctions from "../changelog/index.js";
2
+
3
+ //#region src/changesets/api/changelog.ts
4
+ /**
5
+ * Class-based API wrapper for changelog formatting.
6
+ *
7
+ * Provides a static class interface that delegates to the underlying
8
+ * Changesets API-compatible default export.
9
+ *
10
+ * @internal
11
+ */
12
+ /**
13
+ * Static class wrapper for changelog formatting operations.
14
+ *
15
+ * Delegates to the Changesets-compatible `getReleaseLine` and
16
+ * `getDependencyReleaseLine` functions. Internally, these use the
17
+ * {@link ChangelogService} Effect service layer, which coordinates
18
+ * the {@link GitHubService} (for commit/PR metadata) and
19
+ * {@link MarkdownService} (for AST manipulation) to produce
20
+ * structured changelog entries.
21
+ *
22
+ * @remarks
23
+ * This class provides the same formatting capabilities as the
24
+ * `\@savvy-web/changesets/changelog` subpath export, but through a
25
+ * class-based API rather than the Changesets default-export convention.
26
+ * The underlying formatter parses conventional commit prefixes from the
27
+ * changeset summary to determine the section category (via
28
+ * {@link Categories}), resolves GitHub metadata (authors, PR links,
29
+ * commit hashes), and produces markdown output grouped by category.
30
+ *
31
+ * The `options` parameter must include a `repo` field in `"owner/repo"`
32
+ * format (e.g., `"savvy-web/changesets"`) so that GitHub links can be
33
+ * constructed. Additional options are defined by {@link ChangesetOptionsSchema}.
34
+ *
35
+ * @example Formatting a single changeset release line
36
+ * ```typescript
37
+ * import { Changelog } from "\@savvy-web/changesets";
38
+ *
39
+ * const changeset = {
40
+ * id: "brave-pandas-learn",
41
+ * summary: "feat: add token refresh endpoint",
42
+ * releases: [{ name: "\@savvy-web/auth", type: "minor" as const }],
43
+ * commit: "abc1234567890abcdef1234567890abcdef123456",
44
+ * };
45
+ *
46
+ * const line: string = await Changelog.formatReleaseLine(changeset, "minor", {
47
+ * repo: "savvy-web/auth",
48
+ * });
49
+ * // line contains a markdown bullet under the "Features" section heading
50
+ * ```
51
+ *
52
+ * @example Formatting dependency update lines
53
+ * ```typescript
54
+ * import { Changelog } from "\@savvy-web/changesets";
55
+ *
56
+ * const changesets = [
57
+ * {
58
+ * id: "cool-dogs-fly",
59
+ * summary: "chore(deps): update effect to 3.20.0",
60
+ * releases: [{ name: "\@savvy-web/core", type: "patch" as const }],
61
+ * commit: "def4567890abcdef1234567890abcdef456789ab",
62
+ * },
63
+ * ];
64
+ *
65
+ * const dependenciesUpdated = [
66
+ * {
67
+ * name: "\@savvy-web/utils",
68
+ * type: "patch" as const,
69
+ * oldVersion: "1.2.0",
70
+ * newVersion: "1.2.1",
71
+ * changesets: ["cool-dogs-fly"],
72
+ * packageJson: { name: "\@savvy-web/utils", version: "1.2.1" },
73
+ * },
74
+ * ];
75
+ *
76
+ * const depLines: string = await Changelog.formatDependencyReleaseLine(
77
+ * changesets,
78
+ * dependenciesUpdated,
79
+ * { repo: "savvy-web/core" },
80
+ * );
81
+ * // depLines contains a markdown table of dependency changes
82
+ * ```
83
+ *
84
+ * @see {@link ChangelogService} for the underlying Effect service
85
+ * @see {@link Categories} for how commit types map to section headings
86
+ * @see {@link ChangesetOptionsSchema} for the full options schema
87
+ *
88
+ * @public
89
+ */
90
+ var Changelog = class {
91
+ /* v8 ignore next -- private constructor prevents direct instantiation */
92
+ constructor() {}
93
+ /**
94
+ * Format a single changeset into a changelog release line.
95
+ *
96
+ * @remarks
97
+ * Parses the changeset summary for a conventional commit prefix
98
+ * (e.g., `"feat: ..."`, `"fix!: ..."`), resolves the corresponding
99
+ * {@link SectionCategory}, and produces a markdown bullet item with
100
+ * optional GitHub metadata (author, PR link, commit hash).
101
+ *
102
+ * @param changeset - The changeset to format, including its `id`, `summary`,
103
+ * `releases` array, and optional `commit` hash
104
+ * @param versionType - The semantic version bump type (`"major"`, `"minor"`, or `"patch"`)
105
+ * @param options - Configuration object; must include `repo` in `"owner/repo"` format.
106
+ * Pass `null` to use defaults (no GitHub link resolution).
107
+ * @returns A promise resolving to the formatted markdown string
108
+ */
109
+ static formatReleaseLine(changeset, versionType, options) {
110
+ return changelogFunctions.getReleaseLine(changeset, versionType, options);
111
+ }
112
+ /**
113
+ * Format dependency update release lines into a markdown table.
114
+ *
115
+ * @remarks
116
+ * Generates a structured dependency table showing package names,
117
+ * version transitions, and dependency types. The table is placed
118
+ * under the "Dependencies" section heading in the changelog.
119
+ *
120
+ * @param changesets - The changesets that triggered the dependency updates
121
+ * @param dependenciesUpdated - Array of updated dependencies with their
122
+ * old/new versions and package metadata
123
+ * @param options - Configuration object; must include `repo` in `"owner/repo"` format.
124
+ * Pass `null` to use defaults.
125
+ * @returns A promise resolving to the formatted markdown string containing
126
+ * the dependency update table
127
+ */
128
+ static formatDependencyReleaseLine(changesets, dependenciesUpdated, options) {
129
+ return changelogFunctions.getDependencyReleaseLine(changesets, dependenciesUpdated, options);
130
+ }
131
+ };
132
+
133
+ //#endregion
134
+ export { Changelog };
@@ -0,0 +1,163 @@
1
+ import { collapseDependencyRows, parseDependencyTable, serializeDependencyTable, serializeDependencyTableToMarkdown, sortDependencyRows } from "../utils/dependency-table.js";
2
+
3
+ //#region src/changesets/api/dependency-table.ts
4
+ /**
5
+ * Static class for dependency table manipulation.
6
+ *
7
+ * Wraps the internal utility functions that operate on dependency tables --
8
+ * the structured markdown tables that appear in the "Dependencies" section
9
+ * of changelogs. Each row in a dependency table represents a single package
10
+ * change with its name, type, action, and version transition.
11
+ *
12
+ * @remarks
13
+ * The typical workflow for processing dependency tables is:
14
+ *
15
+ * 1. **Parse** an mdast `Table` node into typed {@link DependencyTableRow} objects
16
+ * 2. **Collapse** duplicate rows (same package updated multiple times) into single entries
17
+ * 3. **Sort** rows by dependency type, then alphabetically by package name
18
+ * 4. **Serialize** back to an mdast `Table` node or directly to a markdown string
19
+ *
20
+ * The {@link DependencyTable.aggregate} method combines the collapse and sort
21
+ * steps into a single call, which is the most common usage pattern.
22
+ *
23
+ * Each {@link DependencyTableRow} is validated by the {@link DependencyTableRowSchema}
24
+ * Effect Schema at system boundaries, ensuring that dependency names, types,
25
+ * actions, and version strings conform to expected formats.
26
+ *
27
+ * @example Parse, aggregate, and serialize a dependency table
28
+ * ```typescript
29
+ * import { DependencyTable } from "\@savvy-web/changesets";
30
+ * import type { DependencyTableRow } from "\@savvy-web/changesets";
31
+ * import type { Table } from "mdast";
32
+ *
33
+ * // Given an mdast Table node from a parsed CHANGELOG
34
+ * declare const tableNode: Table;
35
+ *
36
+ * // Parse into typed rows
37
+ * const rows: DependencyTableRow[] = DependencyTable.parse(tableNode);
38
+ *
39
+ * // Collapse duplicates and sort by type, then name
40
+ * const aggregated: DependencyTableRow[] = DependencyTable.aggregate(rows);
41
+ *
42
+ * // Serialize back to an mdast Table node for further AST manipulation
43
+ * const outputNode: Table = DependencyTable.serialize(aggregated);
44
+ *
45
+ * // Or serialize directly to a markdown string
46
+ * const markdown: string = DependencyTable.toMarkdown(aggregated);
47
+ * ```
48
+ *
49
+ * @example Step-by-step collapse and sort
50
+ * ```typescript
51
+ * import { DependencyTable } from "\@savvy-web/changesets";
52
+ * import type { DependencyTableRow } from "\@savvy-web/changesets";
53
+ *
54
+ * declare const rows: DependencyTableRow[];
55
+ *
56
+ * // Collapse duplicate entries (same package appears multiple times)
57
+ * const collapsed: DependencyTableRow[] = DependencyTable.collapse(rows);
58
+ *
59
+ * // Sort by dependency type, then alphabetically by name
60
+ * const sorted: DependencyTableRow[] = DependencyTable.sort(collapsed);
61
+ * ```
62
+ *
63
+ * @see {@link DependencyTableRow} for the row shape (dependency, type, action, from, to)
64
+ * @see {@link DependencyTableRowSchema} for the Effect Schema that validates row data
65
+ * @see {@link DependencyTableSchema} for the non-empty array schema
66
+ *
67
+ * @public
68
+ */
69
+ var DependencyTable = class {
70
+ /* v8 ignore next -- private constructor prevents direct instantiation */
71
+ constructor() {}
72
+ /**
73
+ * Parse an mdast `Table` node into typed dependency table rows.
74
+ *
75
+ * @remarks
76
+ * Extracts the text content from each table cell and maps it to the
77
+ * corresponding {@link DependencyTableRow} fields. The first row is
78
+ * treated as the header and skipped. Rows that do not have the expected
79
+ * number of columns are ignored.
80
+ *
81
+ * @param tableNode - An mdast `Table` node from a parsed markdown AST
82
+ * @returns Array of {@link DependencyTableRow} objects, one per data row
83
+ */
84
+ static parse(tableNode) {
85
+ return parseDependencyTable(tableNode);
86
+ }
87
+ /**
88
+ * Serialize typed dependency table rows into an mdast `Table` node.
89
+ *
90
+ * @remarks
91
+ * Produces a well-formed mdast `Table` with a header row
92
+ * (`Dependency | Type | Action | From | To`) followed by one data row
93
+ * per input entry. The resulting node can be inserted into a remark AST
94
+ * for further processing or stringification.
95
+ *
96
+ * @param rows - Array of {@link DependencyTableRow} objects to serialize
97
+ * @returns An mdast `Table` node ready for AST insertion
98
+ */
99
+ static serialize(rows) {
100
+ return serializeDependencyTable(rows);
101
+ }
102
+ /**
103
+ * Serialize typed dependency table rows directly to a markdown string.
104
+ *
105
+ * @remarks
106
+ * Convenience method that combines {@link DependencyTable.serialize} with
107
+ * remark stringification. Produces a GFM-compatible markdown table string.
108
+ *
109
+ * @param rows - Array of {@link DependencyTableRow} objects to render
110
+ * @returns A markdown string containing the formatted table
111
+ */
112
+ static toMarkdown(rows) {
113
+ return serializeDependencyTableToMarkdown(rows);
114
+ }
115
+ /**
116
+ * Collapse duplicate dependency rows into single entries.
117
+ *
118
+ * @remarks
119
+ * When a package appears in multiple rows (e.g., updated in separate
120
+ * changesets), this method merges them by keeping the earliest `from`
121
+ * version and the latest `to` version, producing a single row that
122
+ * represents the net change.
123
+ *
124
+ * @param rows - Array of {@link DependencyTableRow} objects, possibly with duplicates
125
+ * @returns A new array with duplicate packages collapsed into single rows
126
+ */
127
+ static collapse(rows) {
128
+ return collapseDependencyRows(rows);
129
+ }
130
+ /**
131
+ * Sort dependency rows by action, type, and package name.
132
+ *
133
+ * @remarks
134
+ * Applies a three-level stable sort:
135
+ * 1. **Action** — `removed` first, then `updated`, then `added`
136
+ * 2. **Type** — alphabetically (e.g., `config` before `dependency`)
137
+ * 3. **Dependency name** — alphabetically within each action+type group
138
+ *
139
+ * @param rows - Array of {@link DependencyTableRow} objects to sort
140
+ * @returns A new array sorted by action, type, then name
141
+ */
142
+ static sort(rows) {
143
+ return sortDependencyRows(rows);
144
+ }
145
+ /**
146
+ * Collapse duplicate rows and then sort the result.
147
+ *
148
+ * @remarks
149
+ * Equivalent to calling {@link DependencyTable.collapse} followed by
150
+ * {@link DependencyTable.sort}. This is the recommended method for
151
+ * preparing dependency table data for final output, as it produces
152
+ * a clean, deduplicated, and consistently ordered table.
153
+ *
154
+ * @param rows - Array of {@link DependencyTableRow} objects to aggregate
155
+ * @returns A new array with duplicates collapsed and rows sorted
156
+ */
157
+ static aggregate(rows) {
158
+ return sortDependencyRows(collapseDependencyRows(rows));
159
+ }
160
+ };
161
+
162
+ //#endregion
163
+ export { DependencyTable };