@savvy-web/changesets 0.4.2 → 0.5.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/esm/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BREAKING_CHANGES, PERFORMANCE, fromHeading, allHeadings, resolveCommitType, CI, TESTS, DEPENDENCIES, OTHER, CATEGORIES, FEATURES, BUG_FIXES, REVERTS, DOCUMENTATION, isValidHeading, BUILD_SYSTEM, REFACTORING, MAINTENANCE } from "./60.js";
2
- import { default as changelog, NonEmptyString } from "./160.js";
3
- import { Context, Schema } from "./795.js";
2
+ import { default as changelog } from "./160.js";
3
+ import { parseDependencyTable, serializeDependencyTable, collapseDependencyRows, serializeDependencyTableToMarkdown, NonEmptyString, sortDependencyRows } from "./891.js";
4
+ import { Context, Schema } from "./855.js";
4
5
  class Categories {
5
6
  static BREAKING_CHANGES = BREAKING_CHANGES;
6
7
  static FEATURES = FEATURES;
@@ -37,6 +38,26 @@ class Changelog {
37
38
  return changelog.getDependencyReleaseLine(changesets, dependenciesUpdated, options);
38
39
  }
39
40
  }
41
+ class DependencyTable {
42
+ static parse(tableNode) {
43
+ return parseDependencyTable(tableNode);
44
+ }
45
+ static serialize(rows) {
46
+ return serializeDependencyTable(rows);
47
+ }
48
+ static toMarkdown(rows) {
49
+ return serializeDependencyTableToMarkdown(rows);
50
+ }
51
+ static collapse(rows) {
52
+ return collapseDependencyRows(rows);
53
+ }
54
+ static sort(rows) {
55
+ return sortDependencyRows(rows);
56
+ }
57
+ static aggregate(rows) {
58
+ return sortDependencyRows(collapseDependencyRows(rows));
59
+ }
60
+ }
40
61
  const _tag = Context.Tag("ChangelogService");
41
62
  const ChangelogServiceBase = _tag();
42
63
  class ChangelogService extends ChangelogServiceBase {
@@ -71,6 +92,7 @@ const DependencyUpdateSchema = Schema.Struct({
71
92
  newVersion: Schema.String
72
93
  });
73
94
  export { ChangelogTransformer, ChangesetLinter } from "./273.js";
74
- export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, NonEmptyString, PositiveInteger, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest } from "./160.js";
75
- export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema } from "./795.js";
76
- export { Categories, Changelog, ChangelogService, ChangelogServiceBase, ChangesetSchema, ChangesetSummarySchema, CommitHashSchema, DependencyTypeSchema, DependencyUpdateSchema, SectionCategorySchema, VersionTypeSchema };
95
+ export { ChangesetOptionsSchema, GitHubInfoSchema, GitHubLive, GitHubService, GitHubServiceBase, IssueNumberSchema, MarkdownLive, MarkdownService, MarkdownServiceBase, RepoSchema, UrlOrMarkdownLinkSchema, UsernameSchema, makeGitHubTest } from "./160.js";
96
+ export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema } from "./725.js";
97
+ export { DependencyActionSchema, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, NonEmptyString, PositiveInteger, VersionOrEmptySchema } from "./891.js";
98
+ export { Categories, Changelog, ChangelogService, ChangelogServiceBase, ChangesetSchema, ChangesetSummarySchema, CommitHashSchema, DependencyTable, DependencyTypeSchema, DependencyUpdateSchema, SectionCategorySchema, VersionTypeSchema };
@@ -1,14 +1,24 @@
1
1
  /**
2
+ * \@savvy-web/changesets/markdownlint
3
+ *
2
4
  * markdownlint custom rules for validating changeset file structure.
3
5
  *
4
6
  * Provides the same validation as the remark-lint rules but using
5
7
  * markdownlint's micromark token API for integration with
6
8
  * markdownlint-cli2 and the VS Code markdownlint extension.
7
9
  *
8
- * - `changeset-heading-hierarchy` (CSH001): Enforce h2 start, no h1, no depth skips
9
- * - `changeset-required-sections` (CSH002): Validate section headings match known categories
10
- * - `changeset-content-structure` (CSH003): Content quality validation
11
- * - `changeset-uncategorized-content` (CSH004): Reject content before first h2 heading
10
+ * Rules included:
11
+ * - {@link HeadingHierarchyRule | changeset-heading-hierarchy} (CSH001): Enforce h2 start, no h1, no depth skips
12
+ * - {@link RequiredSectionsRule | changeset-required-sections} (CSH002): Validate section headings match known categories
13
+ * - {@link ContentStructureRule | changeset-content-structure} (CSH003): Content quality validation
14
+ * - {@link UncategorizedContentRule | changeset-uncategorized-content} (CSH004): Reject content before first h2 heading
15
+ * - {@link DependencyTableFormatRule | changeset-dependency-table-format} (CSH005): Validate dependency table structure
16
+ *
17
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH001.md | CSH001 docs}
18
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH002.md | CSH002 docs}
19
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH003.md | CSH003 docs}
20
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH004.md | CSH004 docs}
21
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH005.md | CSH005 docs}
12
22
  *
13
23
  * @packageDocumentation
14
24
  */
@@ -16,31 +26,103 @@
16
26
  import type { Rule } from 'markdownlint';
17
27
 
18
28
  /**
19
- * markdownlint rule: changeset-content-structure (CSH003)
29
+ * markdownlint rule: `changeset-content-structure` (CSH003).
30
+ *
31
+ * Validates content quality inside changeset markdown files by inspecting
32
+ * micromark tokens for three categories of structural problems:
33
+ *
34
+ * 1. **Empty sections** -- an `atxHeading` (h2) followed immediately by another
35
+ * h2 or the end of the token stream with no intervening content tokens.
36
+ * 2. **Code blocks without a language identifier** -- a `codeFenced` token whose
37
+ * opening fence child lacks a `codeFencedFenceInfo` token.
38
+ * 3. **Empty list items** -- a `listItemPrefix` token with no subsequent
39
+ * `content` token before the next prefix or end of list.
20
40
  *
21
- * Validates content quality in changeset files:
22
- * - Sections must not be empty (h2 followed immediately by another h2 or EOF)
23
- * - Code blocks must have a language identifier
24
- * - List items should have meaningful content (not empty)
41
+ * @remarks
42
+ * This rule mirrors the remark-lint rule `remarkLintContentStructure` but uses
43
+ * markdownlint's micromark token API so it can run inside markdownlint-cli2 and
44
+ * the VS Code markdownlint extension.
45
+ *
46
+ * @example
47
+ * ```json
48
+ * {
49
+ * "changeset-content-structure": true
50
+ * }
51
+ * ```
52
+ *
53
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH003.md | CSH003 rule documentation}
54
+ * @see `src/remark/rules/content-structure.ts` for the corresponding remark-lint rule
55
+ *
56
+ * @public
25
57
  */
26
58
  export declare const ContentStructureRule: Rule;
27
59
 
28
60
  /**
29
- * markdownlint rule: changeset-heading-hierarchy (CSH001)
61
+ * The markdownlint `Rule` object for CSH005 (`changeset-dependency-table-format`).
62
+ *
63
+ * @public
64
+ */
65
+ export declare const DependencyTableFormatRule: Rule;
66
+
67
+ /**
68
+ * markdownlint rule: `changeset-heading-hierarchy` (CSH001).
69
+ *
70
+ * Validates heading structure in changeset markdown files by inspecting
71
+ * `atxHeading` micromark tokens for three constraints:
72
+ *
73
+ * 1. **No h1 headings** -- h1 is reserved for the version title generated by
74
+ * the changelog formatter.
75
+ * 2. **Start at h2** -- the first heading in a changeset must be h2.
76
+ * 3. **No depth skips** -- heading levels must increase sequentially
77
+ * (h2 then h3, not h2 then h4).
78
+ *
79
+ * @remarks
80
+ * This rule mirrors the remark-lint rule `remarkLintHeadingHierarchy` but uses
81
+ * markdownlint's micromark token API so it can run inside markdownlint-cli2 and
82
+ * the VS Code markdownlint extension.
83
+ *
84
+ * @example
85
+ * ```json
86
+ * {
87
+ * "changeset-heading-hierarchy": true
88
+ * }
89
+ * ```
90
+ *
91
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH001.md | CSH001 rule documentation}
92
+ * @see `src/remark/rules/heading-hierarchy.ts` for the corresponding remark-lint rule
30
93
  *
31
- * Validates heading structure in changeset files:
32
- * - No h1 headings allowed
33
- * - Headings must start at h2
34
- * - No depth skips (e.g., h2 ... h4 is invalid)
94
+ * @public
35
95
  */
36
96
  export declare const HeadingHierarchyRule: Rule;
37
97
 
38
98
  /**
39
- * markdownlint rule: changeset-required-sections (CSH002)
99
+ * markdownlint rule: `changeset-required-sections` (CSH002).
100
+ *
101
+ * Validates that every h2 (`atxHeading` with depth 2) in a changeset markdown
102
+ * file matches a known category heading from the category system. When an
103
+ * unrecognized heading is found, the error detail lists all valid headings.
104
+ *
105
+ * @remarks
106
+ * Heading comparison is case-insensitive. The set of valid headings is provided
107
+ * by `allHeadings()` and `isValidHeading()` from the category system
108
+ * (`src/categories/index.ts`). This rule inspects `atxHeading` micromark
109
+ * tokens and extracts their text via the {@link getHeadingText} utility.
110
+ *
111
+ * This rule mirrors the remark-lint rule `remarkLintRequiredSections` but uses
112
+ * markdownlint's micromark token API so it can run inside markdownlint-cli2 and
113
+ * the VS Code markdownlint extension.
114
+ *
115
+ * @example
116
+ * ```json
117
+ * {
118
+ * "changeset-required-sections": true
119
+ * }
120
+ * ```
121
+ *
122
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH002.md | CSH002 rule documentation}
123
+ * @see `src/remark/rules/required-sections.ts` for the corresponding remark-lint rule
40
124
  *
41
- * Validates that all h2 headings in changeset files match a known
42
- * category heading from the category system. Reports unrecognized
43
- * headings with the list of valid options.
125
+ * @public
44
126
  */
45
127
  export declare const RequiredSectionsRule: Rule;
46
128
 
@@ -60,10 +142,34 @@ declare const SilkChangesetsRules: Rule[];
60
142
  export default SilkChangesetsRules;
61
143
 
62
144
  /**
63
- * markdownlint rule: changeset-uncategorized-content (CSH004)
145
+ * markdownlint rule: `changeset-uncategorized-content` (CSH004).
146
+ *
147
+ * Detects content that appears before the first h2 heading in a changeset
148
+ * markdown file. All substantive content must be placed under a categorized
149
+ * section (`## heading`).
64
150
  *
65
- * Detects content that appears before the first h2 heading in a changeset file.
66
- * All content must be placed under a categorized section (## heading).
151
+ * @remarks
152
+ * The rule iterates over the top-level micromark token stream and stops at the
153
+ * first `atxHeading` with depth 2. Any token encountered before that heading
154
+ * that is not a `lineEnding`, `lineEndingBlank`, or `htmlFlow` (HTML comments)
155
+ * triggers an error. This ensures that changeset content is always grouped
156
+ * under a recognized category heading.
157
+ *
158
+ * This rule mirrors the remark-lint rule `remarkLintUncategorizedContent` but
159
+ * uses markdownlint's micromark token API so it can run inside
160
+ * markdownlint-cli2 and the VS Code markdownlint extension.
161
+ *
162
+ * @example
163
+ * ```json
164
+ * {
165
+ * "changeset-uncategorized-content": true
166
+ * }
167
+ * ```
168
+ *
169
+ * @see {@link https://github.com/savvy-web/changesets/blob/main/docs/rules/CSH004.md | CSH004 rule documentation}
170
+ * @see `src/remark/rules/uncategorized-content.ts` for the corresponding remark-lint rule
171
+ *
172
+ * @public
67
173
  */
68
174
  export declare const UncategorizedContentRule: Rule;
69
175
 
@@ -67,6 +67,155 @@ const ContentStructureRule = {
67
67
  }
68
68
  }
69
69
  };
70
+ const EM_DASH = "\u2014";
71
+ const VALID_TYPES = new Set([
72
+ "dependency",
73
+ "devDependency",
74
+ "peerDependency",
75
+ "optionalDependency",
76
+ "workspace",
77
+ "config"
78
+ ]);
79
+ const VALID_ACTIONS = new Set([
80
+ "added",
81
+ "updated",
82
+ "removed"
83
+ ]);
84
+ const EXPECTED_HEADERS = [
85
+ "dependency",
86
+ "type",
87
+ "action",
88
+ "from",
89
+ "to"
90
+ ];
91
+ const VERSION_RE = /^(\u2014|[~^]?\d+\.\d+\.\d+(?:[-+.][\w.+-]*)?)$/;
92
+ function getCellText(cell) {
93
+ const content = cell.children.find((c)=>"tableContent" === c.type);
94
+ return content ? content.text.trim() : "";
95
+ }
96
+ function getRowCells(row) {
97
+ return row.children.filter((c)=>"tableHeader" === c.type || "tableData" === c.type).map(getCellText);
98
+ }
99
+ const DependencyTableFormatRule = {
100
+ names: [
101
+ "changeset-dependency-table-format",
102
+ "CSH005"
103
+ ],
104
+ description: "Dependencies section must contain a valid dependency table",
105
+ tags: [
106
+ "changeset"
107
+ ],
108
+ parser: "micromark",
109
+ function: function(params, onError) {
110
+ const tokens = params.parsers.micromark.tokens;
111
+ for(let i = 0; i < tokens.length; i++){
112
+ const token = tokens[i];
113
+ if ("atxHeading" !== token.type) continue;
114
+ if (2 !== getHeadingLevel(token)) continue;
115
+ if ("dependencies" !== getHeadingText(token).toLowerCase()) continue;
116
+ const headingLine = token.startLine;
117
+ let tableToken = null;
118
+ for(let j = i + 1; j < tokens.length; j++){
119
+ const next = tokens[j];
120
+ if ("lineEnding" !== next.type && "lineEndingBlank" !== next.type) {
121
+ if ("atxHeading" === next.type) break;
122
+ if ("table" === next.type) tableToken = next;
123
+ break;
124
+ }
125
+ }
126
+ if (null === tableToken) {
127
+ onError({
128
+ lineNumber: headingLine,
129
+ detail: `Dependencies section must contain a table, not a list or paragraph. See: ${RULE_DOCS.CSH005}`
130
+ });
131
+ continue;
132
+ }
133
+ const tableHead = tableToken.children.find((c)=>"tableHead" === c.type);
134
+ if (!tableHead) {
135
+ onError({
136
+ lineNumber: tableToken.startLine,
137
+ detail: `Dependencies table is missing a header row. See: ${RULE_DOCS.CSH005}`
138
+ });
139
+ continue;
140
+ }
141
+ const headerRow = tableHead.children.find((c)=>"tableRow" === c.type);
142
+ if (!headerRow) {
143
+ onError({
144
+ lineNumber: tableToken.startLine,
145
+ detail: `Dependencies table is missing a header row. See: ${RULE_DOCS.CSH005}`
146
+ });
147
+ continue;
148
+ }
149
+ const headers = getRowCells(headerRow).map((h)=>h.toLowerCase());
150
+ if (headers.length !== EXPECTED_HEADERS.length || !headers.every((h, idx)=>h === EXPECTED_HEADERS[idx])) {
151
+ onError({
152
+ lineNumber: headerRow.startLine,
153
+ detail: `Dependencies table must have columns: Dependency, Type, Action, From, To. Got: ${headers.join(", ")}. See: ${RULE_DOCS.CSH005}`
154
+ });
155
+ continue;
156
+ }
157
+ const tableBody = tableToken.children.find((c)=>"tableBody" === c.type);
158
+ if (!tableBody) {
159
+ onError({
160
+ lineNumber: tableToken.startLine,
161
+ detail: `Dependencies table must have at least one data row. See: ${RULE_DOCS.CSH005}`
162
+ });
163
+ continue;
164
+ }
165
+ const dataRows = tableBody.children.filter((c)=>"tableRow" === c.type);
166
+ if (0 === dataRows.length) {
167
+ onError({
168
+ lineNumber: tableToken.startLine,
169
+ detail: `Dependencies table must have at least one data row. See: ${RULE_DOCS.CSH005}`
170
+ });
171
+ continue;
172
+ }
173
+ for (const row of dataRows){
174
+ const cells = getRowCells(row);
175
+ if (cells.length < 5) {
176
+ onError({
177
+ lineNumber: row.startLine,
178
+ detail: `Dependencies table row has too few columns (expected 5, got ${cells.length}). See: ${RULE_DOCS.CSH005}`
179
+ });
180
+ continue;
181
+ }
182
+ const [dependency, type, action, from, to] = cells;
183
+ if (!dependency) onError({
184
+ lineNumber: row.startLine,
185
+ detail: `Dependencies table row has an empty 'Dependency' cell. See: ${RULE_DOCS.CSH005}`
186
+ });
187
+ if (!VALID_TYPES.has(type)) onError({
188
+ lineNumber: row.startLine,
189
+ detail: `Invalid dependency type '${type}'. Valid types are: ${[
190
+ ...VALID_TYPES
191
+ ].join(", ")}. See: ${RULE_DOCS.CSH005}`
192
+ });
193
+ if (!VALID_ACTIONS.has(action)) onError({
194
+ lineNumber: row.startLine,
195
+ detail: `Invalid dependency action '${action}'. Valid actions are: ${[
196
+ ...VALID_ACTIONS
197
+ ].join(", ")}. See: ${RULE_DOCS.CSH005}`
198
+ });
199
+ if (from && !VERSION_RE.test(from)) onError({
200
+ lineNumber: row.startLine,
201
+ detail: `Invalid 'from' value '${from}'. Must be a semver string or em dash (\u2014). See: ${RULE_DOCS.CSH005}`
202
+ });
203
+ if (to && !VERSION_RE.test(to)) onError({
204
+ lineNumber: row.startLine,
205
+ detail: `Invalid 'to' value '${to}'. Must be a semver string or em dash (\u2014). See: ${RULE_DOCS.CSH005}`
206
+ });
207
+ if ("added" === action && from !== EM_DASH) onError({
208
+ lineNumber: row.startLine,
209
+ detail: `'from' must be '\u2014' when action is 'added' (got '${from}'). See: ${RULE_DOCS.CSH005}`
210
+ });
211
+ if ("removed" === action && to !== EM_DASH) onError({
212
+ lineNumber: row.startLine,
213
+ detail: `'to' must be '\u2014' when action is 'removed' (got '${to}'). See: ${RULE_DOCS.CSH005}`
214
+ });
215
+ }
216
+ }
217
+ }
218
+ };
70
219
  const HeadingHierarchyRule = {
71
220
  names: [
72
221
  "changeset-heading-hierarchy",
@@ -146,8 +295,9 @@ const SilkChangesetsRules = [
146
295
  HeadingHierarchyRule,
147
296
  RequiredSectionsRule,
148
297
  ContentStructureRule,
149
- UncategorizedContentRule
298
+ UncategorizedContentRule,
299
+ DependencyTableFormatRule
150
300
  ];
151
301
  const markdownlint = SilkChangesetsRules;
152
302
  export default markdownlint;
153
- export { ContentStructureRule, HeadingHierarchyRule, RequiredSectionsRule, UncategorizedContentRule };
303
+ export { ContentStructureRule, DependencyTableFormatRule, HeadingHierarchyRule, RequiredSectionsRule, UncategorizedContentRule };
package/esm/remark.d.ts CHANGED
@@ -1,7 +1,54 @@
1
1
  /**
2
- * Consolidated remark plugins for changeset validation and CHANGELOG transformation.
2
+ * \@savvy-web/changesets/remark
3
3
  *
4
- * Re-exports all lint rules and transform plugins from a single entry point.
4
+ * Remark plugins for changeset validation and CHANGELOG transformation.
5
+ *
6
+ * This entry point re-exports all lint rules, transform plugins, and presets
7
+ * from a single import path. The exports are organized into three groups:
8
+ *
9
+ * **Lint rules** validate changeset markdown structure before changelog generation:
10
+ * - {@link HeadingHierarchyRule} (CSH001) -- heading depth and ordering
11
+ * - {@link RequiredSectionsRule} (CSH002) -- recognized section headings
12
+ * - {@link ContentStructureRule} (CSH003) -- non-empty sections, code fences, list items
13
+ * - {@link UncategorizedContentRule} (CSH004) -- content before the first heading
14
+ * - {@link DependencyTableFormatRule} (CSH005) -- dependency table schema compliance
15
+ *
16
+ * **Transform plugins** normalize and clean up generated CHANGELOG markdown:
17
+ * - {@link AggregateDependencyTablesPlugin} -- merge duplicate dependency sections
18
+ * - {@link MergeSectionsPlugin} -- merge duplicate h3 section headings
19
+ * - {@link ReorderSectionsPlugin} -- sort sections by category priority
20
+ * - {@link DeduplicateItemsPlugin} -- remove duplicate list items
21
+ * - {@link ContributorFootnotesPlugin} -- aggregate contributor attributions
22
+ * - {@link IssueLinkRefsPlugin} -- convert inline issue links to reference-style
23
+ * - {@link NormalizeFormatPlugin} -- remove empty sections and lists
24
+ *
25
+ * **Presets** bundle related rules or plugins for convenient consumption:
26
+ * - {@link SilkChangesetPreset} -- all five lint rules
27
+ * - {@link SilkChangesetTransformPreset} -- all seven transform plugins in execution order
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * import {
32
+ * SilkChangesetPreset,
33
+ * SilkChangesetTransformPreset,
34
+ * } from "\@savvy-web/changesets/remark";
35
+ * import remarkParse from "remark-parse";
36
+ * import remarkStringify from "remark-stringify";
37
+ * import { unified } from "unified";
38
+ *
39
+ * // Lint a changeset file
40
+ * const linter = unified().use(remarkParse);
41
+ * for (const rule of SilkChangesetPreset) {
42
+ * linter.use(rule);
43
+ * }
44
+ *
45
+ * // Transform a CHANGELOG
46
+ * const transformer = unified().use(remarkParse);
47
+ * for (const plugin of SilkChangesetTransformPreset) {
48
+ * transformer.use(plugin);
49
+ * }
50
+ * transformer.use(remarkStringify);
51
+ * ```
5
52
  *
6
53
  * @packageDocumentation
7
54
  */
@@ -10,46 +57,24 @@ import { Plugin } from 'unified';
10
57
  import { Plugin as Plugin_2 } from 'unified-lint-rule';
11
58
  import { Root } from 'mdast';
12
59
 
60
+ export declare const AggregateDependencyTablesPlugin: Plugin<[], Root>;
61
+
13
62
  export declare const ContentStructureRule: Plugin_2<Root, unknown>;
14
63
 
15
- /**
16
- * Extract inline contributor attributions and aggregate them into
17
- * a summary paragraph at the end of each version block.
18
- */
19
64
  export declare const ContributorFootnotesPlugin: Plugin<[], Root>;
20
65
 
21
- /**
22
- * Remove duplicate list items within each h3 section.
23
- *
24
- * Items are compared by their plain text content. If a list becomes
25
- * empty after deduplication, it is removed from the tree.
26
- */
27
66
  export declare const DeduplicateItemsPlugin: Plugin<[], Root>;
28
67
 
68
+ export declare const DependencyTableFormatRule: Plugin_2<Root, unknown>;
69
+
29
70
  export declare const HeadingHierarchyRule: Plugin_2<Root, unknown>;
30
71
 
31
- /**
32
- * Convert inline issue links to reference-style links with definitions
33
- * at the end of each version block.
34
- */
35
72
  export declare const IssueLinkRefsPlugin: Plugin<[], Root>;
36
73
 
37
- /**
38
- * Merge duplicate h3 sections within each version block.
39
- *
40
- * Groups sections by heading text (case-insensitive via `fromHeading`),
41
- * keeps the first occurrence, and splices content from duplicates into it.
42
- */
43
74
  export declare const MergeSectionsPlugin: Plugin<[], Root>;
44
75
 
45
- /**
46
- * Remove empty sections and empty lists from the document.
47
- */
48
76
  export declare const NormalizeFormatPlugin: Plugin<[], Root>;
49
77
 
50
- /**
51
- * Reorder h3 sections within each version block by category priority.
52
- */
53
78
  export declare const ReorderSectionsPlugin: Plugin<[], Root>;
54
79
 
55
80
  export declare const RequiredSectionsRule: Plugin_2<Root, unknown>;
@@ -57,37 +82,81 @@ export declare const RequiredSectionsRule: Plugin_2<Root, unknown>;
57
82
  /**
58
83
  * Preset combining all changeset lint rules for convenient consumption.
59
84
  *
85
+ * @remarks
86
+ * Includes the following rules in order:
87
+ *
88
+ * 1. {@link HeadingHierarchyRule} (CSH001) -- no h1, no depth skips
89
+ * 2. {@link RequiredSectionsRule} (CSH002) -- h2 headings must match a known category
90
+ * 3. {@link ContentStructureRule} (CSH003) -- non-empty sections, code fence languages, non-empty list items
91
+ * 4. {@link UncategorizedContentRule} (CSH004) -- no content before the first h2 heading
92
+ * 5. {@link DependencyTableFormatRule} (CSH005) -- dependency table column/value validation
93
+ *
94
+ * Rule execution order is not significant for lint rules; all rules run
95
+ * independently over the same AST and report warnings to the virtual file.
96
+ *
60
97
  * @example
61
98
  * ```typescript
62
99
  * import { SilkChangesetPreset } from "\@savvy-web/changesets/remark";
63
100
  * import remarkParse from "remark-parse";
64
101
  * import { unified } from "unified";
102
+ * import { read } from "to-vfile";
65
103
  *
66
104
  * const processor = unified().use(remarkParse);
67
105
  * for (const rule of SilkChangesetPreset) {
68
106
  * processor.use(rule);
69
107
  * }
108
+ *
109
+ * const file = await read("changeset.md");
110
+ * const result = await processor.process(file);
111
+ * console.log(result.messages); // lint warnings
70
112
  * ```
71
113
  *
114
+ * @see {@link SilkChangesetTransformPreset} for the corresponding transform preset
115
+ *
72
116
  * @public
73
117
  */
74
- export declare const SilkChangesetPreset: readonly [Plugin_2<Root, unknown>, Plugin_2<Root, unknown>, Plugin_2<Root, unknown>, Plugin_2<Root, unknown>];
118
+ export declare const SilkChangesetPreset: readonly [Plugin_2<Root, unknown>, Plugin_2<Root, unknown>, Plugin_2<Root, unknown>, Plugin_2<Root, unknown>, Plugin_2<Root, unknown>];
75
119
 
76
120
  /**
77
121
  * Ordered array of all transform plugins in the correct execution order.
78
122
  *
79
123
  * @remarks
80
- * Plugin ordering is significant:
81
- * 1. `MergeSectionsPlugin` -- merge duplicate h3 headings (must run before reorder)
82
- * 2. `ReorderSectionsPlugin` -- sort sections by category priority
83
- * 3. `DeduplicateItemsPlugin` -- remove duplicate list items
84
- * 4. `ContributorFootnotesPlugin` -- aggregate contributor attributions
85
- * 5. `IssueLinkRefsPlugin` -- convert inline issue links to reference-style
86
- * 6. `NormalizeFormatPlugin` -- final cleanup (remove empty sections/lists)
124
+ * Plugin ordering is significant -- each plugin may depend on the output of
125
+ * earlier plugins in the pipeline:
126
+ *
127
+ * 1. {@link AggregateDependencyTablesPlugin} -- merge duplicate dependency sections (must run first so downstream plugins see a single Dependencies section)
128
+ * 2. {@link MergeSectionsPlugin} -- merge duplicate h3 headings (must run before reorder so that priority is computed on consolidated sections)
129
+ * 3. {@link ReorderSectionsPlugin} -- sort sections by category priority (Breaking Changes first, Other last)
130
+ * 4. {@link DeduplicateItemsPlugin} -- remove duplicate list items within each section
131
+ * 5. {@link ContributorFootnotesPlugin} -- extract inline `Thanks \@user!` attributions and aggregate them into a summary paragraph per version block
132
+ * 6. {@link IssueLinkRefsPlugin} -- convert inline `[#N](url)` links to reference-style `[#N]` with definitions at the end of each version block
133
+ * 7. {@link NormalizeFormatPlugin} -- final cleanup removing empty sections and empty lists
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * import { SilkChangesetTransformPreset } from "\@savvy-web/changesets/remark";
138
+ * import remarkGfm from "remark-gfm";
139
+ * import remarkParse from "remark-parse";
140
+ * import remarkStringify from "remark-stringify";
141
+ * import { unified } from "unified";
142
+ * import { read } from "to-vfile";
143
+ *
144
+ * const processor = unified().use(remarkParse).use(remarkGfm);
145
+ * for (const plugin of SilkChangesetTransformPreset) {
146
+ * processor.use(plugin);
147
+ * }
148
+ * processor.use(remarkStringify);
149
+ *
150
+ * const file = await read("CHANGELOG.md");
151
+ * const result = await processor.process(file);
152
+ * console.log(String(result));
153
+ * ```
154
+ *
155
+ * @see {@link SilkChangesetPreset} for the corresponding lint preset
87
156
  *
88
157
  * @public
89
158
  */
90
- export declare const SilkChangesetTransformPreset: readonly [Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>];
159
+ export declare const SilkChangesetTransformPreset: readonly [Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>, Plugin<[], Root>];
91
160
 
92
161
  export declare const UncategorizedContentRule: Plugin_2<Root, unknown>;
93
162