@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/README.md +16 -0
- package/cjs/changelog.cjs +131 -36
- package/cjs/changelog.d.cts +52 -3
- package/cjs/index.cjs +262 -42
- package/cjs/index.d.cts +1726 -175
- package/cjs/markdownlint.cjs +156 -2
- package/cjs/markdownlint.d.cts +127 -21
- package/cjs/remark.cjs +225 -9
- package/cjs/remark.d.cts +106 -37
- package/esm/160.js +45 -39
- package/esm/260.js +2 -1
- package/esm/273.js +2 -1
- package/esm/622.js +2 -2
- package/esm/{795.js → 725.js} +2 -5
- package/esm/855.js +5 -0
- package/esm/891.js +147 -0
- package/esm/bin/savvy-changesets.js +5 -3
- package/esm/changelog.d.ts +52 -3
- package/esm/index.d.ts +1726 -175
- package/esm/index.js +27 -5
- package/esm/markdownlint.d.ts +127 -21
- package/esm/markdownlint.js +152 -2
- package/esm/remark.d.ts +106 -37
- package/esm/remark.js +76 -3
- package/package.json +1 -1
- package/esm/689.js +0 -1
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
|
|
3
|
-
import {
|
|
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,
|
|
75
|
-
export { ChangesetValidationError, ChangesetValidationErrorBase, ConfigurationError, ConfigurationErrorBase, GitHubApiError, GitHubApiErrorBase, JsonPathSchema, MarkdownParseError, MarkdownParseErrorBase, VersionFileConfigSchema, VersionFileError, VersionFileErrorBase, VersionFilesSchema } from "./
|
|
76
|
-
export {
|
|
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 };
|
package/esm/markdownlint.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
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
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
66
|
-
*
|
|
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
|
|
package/esm/markdownlint.js
CHANGED
|
@@ -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
|
-
*
|
|
2
|
+
* \@savvy-web/changesets/remark
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
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
|
|