@versatiles/release-tool 2.6.0 → 2.7.1
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 +37 -27
- package/dist/commands/check.d.ts +24 -0
- package/dist/commands/check.js +25 -1
- package/dist/commands/deps-graph.d.ts +22 -0
- package/dist/commands/deps-graph.js +23 -1
- package/dist/commands/deps-upgrade.js +1 -1
- package/dist/commands/doc-typescript.d.ts +39 -3
- package/dist/commands/doc-typescript.js +24 -0
- package/dist/commands/markdown.d.ts +9 -1
- package/dist/commands/markdown.js +141 -28
- package/dist/commands/release-npm.d.ts +43 -0
- package/dist/commands/release-npm.js +156 -31
- package/dist/lib/benchmark.d.ts +119 -0
- package/dist/lib/benchmark.js +148 -0
- package/dist/lib/changelog.d.ts +23 -0
- package/dist/lib/changelog.js +117 -0
- package/dist/lib/errors.d.ts +32 -0
- package/dist/lib/errors.js +47 -0
- package/dist/lib/git.d.ts +92 -0
- package/dist/lib/git.js +112 -0
- package/dist/lib/log.d.ts +57 -0
- package/dist/lib/log.js +63 -1
- package/dist/lib/retry.d.ts +24 -0
- package/dist/lib/retry.js +44 -0
- package/dist/lib/shell.d.ts +131 -16
- package/dist/lib/shell.js +106 -2
- package/dist/lib/utils.d.ts +29 -0
- package/dist/lib/utils.js +29 -0
- package/package.json +15 -8
package/README.md
CHANGED
|
@@ -203,41 +203,51 @@ flowchart TB
|
|
|
203
203
|
subgraph 0["src"]
|
|
204
204
|
subgraph 1["commands"]
|
|
205
205
|
2["check.ts"]
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
6["deps-graph.ts"]
|
|
207
|
+
7["deps-upgrade.ts"]
|
|
208
|
+
9["doc-command.ts"]
|
|
209
|
+
B["doc-typescript.ts"]
|
|
210
|
+
C["markdown.ts"]
|
|
211
|
+
D["release-npm.ts"]
|
|
212
212
|
end
|
|
213
213
|
subgraph 3["lib"]
|
|
214
214
|
4["log.ts"]
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
5["errors.ts"]
|
|
216
|
+
8["shell.ts"]
|
|
217
|
+
A["utils.ts"]
|
|
218
|
+
E["changelog.ts"]
|
|
219
|
+
F["git.ts"]
|
|
220
|
+
G["retry.ts"]
|
|
221
|
+
I["benchmark.ts"]
|
|
218
222
|
end
|
|
219
|
-
|
|
223
|
+
H["index.ts"]
|
|
220
224
|
end
|
|
221
225
|
2-->4
|
|
222
|
-
5
|
|
226
|
+
4-->5
|
|
223
227
|
6-->4
|
|
224
|
-
6-->7
|
|
225
228
|
7-->4
|
|
226
|
-
8
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
C-->
|
|
231
|
-
C-->
|
|
232
|
-
D-->
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
E-->
|
|
239
|
-
|
|
240
|
-
|
|
229
|
+
7-->8
|
|
230
|
+
8-->4
|
|
231
|
+
9-->A
|
|
232
|
+
B-->4
|
|
233
|
+
C-->5
|
|
234
|
+
C-->A
|
|
235
|
+
D-->E
|
|
236
|
+
D-->5
|
|
237
|
+
D-->F
|
|
238
|
+
D-->4
|
|
239
|
+
D-->G
|
|
240
|
+
D-->8
|
|
241
|
+
E-->F
|
|
242
|
+
F-->8
|
|
243
|
+
H-->2
|
|
244
|
+
H-->6
|
|
245
|
+
H-->7
|
|
246
|
+
H-->9
|
|
247
|
+
H-->B
|
|
248
|
+
H-->C
|
|
249
|
+
H-->D
|
|
250
|
+
H-->4
|
|
241
251
|
|
|
242
252
|
class 0,1,3 subgraphs;
|
|
243
253
|
classDef subgraphs fill-opacity:0.1, fill:#888, color:#888, stroke:#888;
|
package/dist/commands/check.d.ts
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs all project checks including package.json and workflow validation.
|
|
3
|
+
*
|
|
4
|
+
* @param directory - The project directory to check
|
|
5
|
+
*/
|
|
1
6
|
export declare function check(directory: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Validates package.json configuration for VersaTiles projects.
|
|
9
|
+
*
|
|
10
|
+
* Checks for:
|
|
11
|
+
* - Required scripts (build, check, prepack, release)
|
|
12
|
+
* - Recommended scripts (test, doc, upgrade, doc-graph)
|
|
13
|
+
* - Script configurations following best practices
|
|
14
|
+
* - Unnecessary dependencies
|
|
15
|
+
*
|
|
16
|
+
* @param directory - The project directory containing package.json
|
|
17
|
+
* @throws {VrtError} If package.json is missing required scripts
|
|
18
|
+
*/
|
|
2
19
|
export declare function checkPackage(directory: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Validates GitHub Actions workflow configuration.
|
|
22
|
+
*
|
|
23
|
+
* Checks for the presence of expected workflow files.
|
|
24
|
+
*
|
|
25
|
+
* @param directory - The project directory to check
|
|
26
|
+
*/
|
|
3
27
|
export declare function checkWorkflow(directory: string): void;
|
package/dist/commands/check.js
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
|
-
import { panic, info, warn } from '../lib/log.js';
|
|
3
2
|
import { resolve } from 'path';
|
|
3
|
+
import { info, panic, warn } from '../lib/log.js';
|
|
4
|
+
/**
|
|
5
|
+
* Runs all project checks including package.json and workflow validation.
|
|
6
|
+
*
|
|
7
|
+
* @param directory - The project directory to check
|
|
8
|
+
*/
|
|
4
9
|
export function check(directory) {
|
|
5
10
|
checkPackage(directory);
|
|
6
11
|
checkWorkflow(directory);
|
|
7
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Validates package.json configuration for VersaTiles projects.
|
|
15
|
+
*
|
|
16
|
+
* Checks for:
|
|
17
|
+
* - Required scripts (build, check, prepack, release)
|
|
18
|
+
* - Recommended scripts (test, doc, upgrade, doc-graph)
|
|
19
|
+
* - Script configurations following best practices
|
|
20
|
+
* - Unnecessary dependencies
|
|
21
|
+
*
|
|
22
|
+
* @param directory - The project directory containing package.json
|
|
23
|
+
* @throws {VrtError} If package.json is missing required scripts
|
|
24
|
+
*/
|
|
8
25
|
export function checkPackage(directory) {
|
|
9
26
|
const pack = JSON.parse(readFileSync(resolve(directory, 'package.json'), 'utf8'));
|
|
10
27
|
const { scripts } = pack;
|
|
@@ -60,6 +77,13 @@ export function checkPackage(directory) {
|
|
|
60
77
|
}
|
|
61
78
|
});
|
|
62
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Validates GitHub Actions workflow configuration.
|
|
82
|
+
*
|
|
83
|
+
* Checks for the presence of expected workflow files.
|
|
84
|
+
*
|
|
85
|
+
* @param directory - The project directory to check
|
|
86
|
+
*/
|
|
63
87
|
export function checkWorkflow(directory) {
|
|
64
88
|
if (!existsSync(resolve(directory, '.github/workflows/pages.yml'))) {
|
|
65
89
|
info('GitHub Pages workflow not found');
|
|
@@ -1 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a Mermaid dependency graph for the project's source files.
|
|
3
|
+
*
|
|
4
|
+
* Uses dependency-cruiser to analyze imports and outputs a Mermaid flowchart
|
|
5
|
+
* diagram to stdout. The output is wrapped in markdown code blocks for
|
|
6
|
+
* easy inclusion in documentation.
|
|
7
|
+
*
|
|
8
|
+
* Configuration:
|
|
9
|
+
* - Only includes files from `src/` directory
|
|
10
|
+
* - Excludes test files, declaration files, and mocks
|
|
11
|
+
* - Uses ELK layout for better graph rendering
|
|
12
|
+
*
|
|
13
|
+
* @param directory - The project directory to analyze
|
|
14
|
+
* @throws {VrtError} If dependency analysis fails
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* // Generate graph and pipe to doc-insert
|
|
19
|
+
* await generateDependencyGraph('./');
|
|
20
|
+
* // Output: ```mermaid\nflowchart TB\n...\n```
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
1
23
|
export declare function generateDependencyGraph(directory: string): Promise<void>;
|
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
import { cruise } from 'dependency-cruiser';
|
|
2
2
|
import { panic } from '../lib/log.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates a Mermaid dependency graph for the project's source files.
|
|
5
|
+
*
|
|
6
|
+
* Uses dependency-cruiser to analyze imports and outputs a Mermaid flowchart
|
|
7
|
+
* diagram to stdout. The output is wrapped in markdown code blocks for
|
|
8
|
+
* easy inclusion in documentation.
|
|
9
|
+
*
|
|
10
|
+
* Configuration:
|
|
11
|
+
* - Only includes files from `src/` directory
|
|
12
|
+
* - Excludes test files, declaration files, and mocks
|
|
13
|
+
* - Uses ELK layout for better graph rendering
|
|
14
|
+
*
|
|
15
|
+
* @param directory - The project directory to analyze
|
|
16
|
+
* @throws {VrtError} If dependency analysis fails
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Generate graph and pipe to doc-insert
|
|
21
|
+
* await generateDependencyGraph('./');
|
|
22
|
+
* // Output: ```mermaid\nflowchart TB\n...\n```
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
3
25
|
export async function generateDependencyGraph(directory) {
|
|
4
26
|
let cruiseResult;
|
|
5
27
|
try {
|
|
6
28
|
cruiseResult = await cruise([directory], {
|
|
7
29
|
includeOnly: '^src',
|
|
8
30
|
outputType: 'mermaid',
|
|
9
|
-
exclude: ['\\.(test|d)\\.ts$', 'node_modules', '__mocks__/'],
|
|
31
|
+
exclude: ['\\.(test|d|mock)\\.ts$', 'node_modules', '__mocks__/'],
|
|
10
32
|
});
|
|
11
33
|
}
|
|
12
34
|
catch (pError) {
|
|
@@ -24,7 +24,7 @@ export async function upgradeDependencies(directory) {
|
|
|
24
24
|
});
|
|
25
25
|
});
|
|
26
26
|
const shell = new Shell(directory);
|
|
27
|
-
await
|
|
27
|
+
await shell.run('rm -f package-lock.json && rm -rf node_modules', false);
|
|
28
28
|
await check('Reinstall all dependencies', shell.stdout('npm i'));
|
|
29
29
|
// Final log message
|
|
30
30
|
info('All dependencies are up to date');
|
|
@@ -1,6 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Output format for generated TypeScript documentation.
|
|
3
|
+
*/
|
|
4
|
+
export type DocFormat = 'markdown' | 'wiki' | 'html';
|
|
5
|
+
/**
|
|
6
|
+
* Options for generating TypeScript documentation.
|
|
7
|
+
*/
|
|
8
|
+
export interface TypescriptDocOptions {
|
|
9
|
+
/** Path to the entry point file (default: './src/index.ts') */
|
|
2
10
|
entryPoint?: string;
|
|
11
|
+
/** Output directory for generated docs (default: './docs') */
|
|
3
12
|
outputPath?: string;
|
|
4
|
-
format
|
|
13
|
+
/** Documentation format: 'markdown', 'wiki', or 'html' (default: 'markdown') */
|
|
14
|
+
format?: DocFormat;
|
|
15
|
+
/** Suppress info-level logging (default: false) */
|
|
5
16
|
quiet?: boolean;
|
|
6
|
-
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generates TypeScript documentation using TypeDoc.
|
|
20
|
+
*
|
|
21
|
+
* Supports multiple output formats:
|
|
22
|
+
* - `markdown`: Standard Markdown files using typedoc-plugin-markdown
|
|
23
|
+
* - `wiki`: GitHub Wiki compatible Markdown using typedoc-github-wiki-theme
|
|
24
|
+
* - `html`: HTML documentation using typedoc-github-theme
|
|
25
|
+
*
|
|
26
|
+
* @param options - Configuration options for documentation generation
|
|
27
|
+
* @throws {VrtError} If project conversion fails or validation errors occur
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* // Generate markdown docs from default entry point
|
|
32
|
+
* await generateTypescriptDocs({ format: 'markdown' });
|
|
33
|
+
*
|
|
34
|
+
* // Generate HTML docs to custom directory
|
|
35
|
+
* await generateTypescriptDocs({
|
|
36
|
+
* entryPoint: './src/main.ts',
|
|
37
|
+
* outputPath: './api-docs',
|
|
38
|
+
* format: 'html'
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateTypescriptDocs(options: TypescriptDocOptions): Promise<void>;
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import * as td from 'typedoc';
|
|
2
2
|
import { panic, warn } from '../lib/log.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates TypeScript documentation using TypeDoc.
|
|
5
|
+
*
|
|
6
|
+
* Supports multiple output formats:
|
|
7
|
+
* - `markdown`: Standard Markdown files using typedoc-plugin-markdown
|
|
8
|
+
* - `wiki`: GitHub Wiki compatible Markdown using typedoc-github-wiki-theme
|
|
9
|
+
* - `html`: HTML documentation using typedoc-github-theme
|
|
10
|
+
*
|
|
11
|
+
* @param options - Configuration options for documentation generation
|
|
12
|
+
* @throws {VrtError} If project conversion fails or validation errors occur
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Generate markdown docs from default entry point
|
|
17
|
+
* await generateTypescriptDocs({ format: 'markdown' });
|
|
18
|
+
*
|
|
19
|
+
* // Generate HTML docs to custom directory
|
|
20
|
+
* await generateTypescriptDocs({
|
|
21
|
+
* entryPoint: './src/main.ts',
|
|
22
|
+
* outputPath: './api-docs',
|
|
23
|
+
* format: 'html'
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
3
27
|
export async function generateTypescriptDocs(options) {
|
|
4
28
|
const { entryPoint, outputPath, quiet } = options;
|
|
5
29
|
const format = options.format ?? 'markdown';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PhrasingContent, Root } from 'mdast';
|
|
2
2
|
/**
|
|
3
3
|
* Injects a Markdown segment under a specified heading in a Markdown document.
|
|
4
4
|
* Optionally, the injected segment can be made foldable for better readability.
|
|
@@ -17,5 +17,13 @@ export declare function injectMarkdown(document: string, segment: string, headin
|
|
|
17
17
|
* @returns The Markdown document with an updated TOC.
|
|
18
18
|
*/
|
|
19
19
|
export declare function updateTOC(main: string, heading: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Converts a PhrasingContent node to its HTML representation.
|
|
22
|
+
* Handles all PhrasingContent types defined in mdast.
|
|
23
|
+
*
|
|
24
|
+
* @param node The phrasing content node to convert.
|
|
25
|
+
* @returns The HTML string representation.
|
|
26
|
+
* @throws {VrtError} For reference types that require resolution (footnote, image, link references).
|
|
27
|
+
*/
|
|
20
28
|
export declare function nodeToHtml(node: PhrasingContent): string;
|
|
21
29
|
export declare function parseMarkdown(document: string): Root;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { remark } from 'remark';
|
|
2
2
|
import remarkGfm from 'remark-gfm';
|
|
3
3
|
import remarkStringify from 'remark-stringify';
|
|
4
|
+
import { markdownError, notImplementedError } from '../lib/errors.js';
|
|
4
5
|
import { getErrorMessage } from '../lib/utils.js';
|
|
5
6
|
// Custom blockquote handler that preserves GitHub alert syntax
|
|
6
7
|
function blockquoteHandler(node, _parent, state, info) {
|
|
@@ -36,7 +37,7 @@ export function injectMarkdown(document, segment, heading, foldable) {
|
|
|
36
37
|
}
|
|
37
38
|
catch (error) {
|
|
38
39
|
// Handle errors during the search for the start index.
|
|
39
|
-
throw
|
|
40
|
+
throw markdownError(`Error while searching for segment "${heading}": ${getErrorMessage(error)}`);
|
|
40
41
|
}
|
|
41
42
|
// Get the depth of the specified heading to maintain the structure.
|
|
42
43
|
const depth = getHeadingDepth(documentAst, startIndex);
|
|
@@ -102,9 +103,9 @@ export function updateTOC(main, heading) {
|
|
|
102
103
|
function findSegmentStartIndex(mainAst, headingAst) {
|
|
103
104
|
// Verify the structure of the headingAst.
|
|
104
105
|
if (headingAst.children.length !== 1)
|
|
105
|
-
throw
|
|
106
|
+
throw markdownError('headingAst.children.length !== 1');
|
|
106
107
|
if (headingAst.children[0].type !== 'heading')
|
|
107
|
-
throw
|
|
108
|
+
throw markdownError("headingAst.children[0].type !== 'heading'");
|
|
108
109
|
const sectionDepth = headingAst.children[0].depth;
|
|
109
110
|
const sectionText = extractTextFromMDAsHTML(headingAst);
|
|
110
111
|
// Search for the index of the heading in the main document AST.
|
|
@@ -116,9 +117,9 @@ function findSegmentStartIndex(mainAst, headingAst) {
|
|
|
116
117
|
});
|
|
117
118
|
// Handle the cases of no match or multiple matches.
|
|
118
119
|
if (indexes.length < 1)
|
|
119
|
-
throw
|
|
120
|
+
throw markdownError('section not found');
|
|
120
121
|
if (indexes.length > 1)
|
|
121
|
-
throw
|
|
122
|
+
throw markdownError('too many sections found');
|
|
122
123
|
return indexes[0];
|
|
123
124
|
}
|
|
124
125
|
/**
|
|
@@ -148,7 +149,7 @@ function findNextHeadingIndex(mainAst, startIndex, depth) {
|
|
|
148
149
|
function getHeadingDepth(mainAst, index) {
|
|
149
150
|
const node = mainAst.children[index];
|
|
150
151
|
if (node.type !== 'heading')
|
|
151
|
-
throw
|
|
152
|
+
throw markdownError("node.type !== 'heading'");
|
|
152
153
|
return node.depth;
|
|
153
154
|
}
|
|
154
155
|
/**
|
|
@@ -174,47 +175,108 @@ function mergeSegments(mainAst, segmentAst, startIndex, endIndex) {
|
|
|
174
175
|
}
|
|
175
176
|
/**
|
|
176
177
|
* Extracts the textual content from a node in the AST.
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* @
|
|
178
|
+
* Recursively processes nodes with children and extracts text values.
|
|
179
|
+
*
|
|
180
|
+
* @param node The AST node (Root or any RootContent type).
|
|
181
|
+
* @returns The extracted text content as HTML-escaped string.
|
|
180
182
|
*/
|
|
181
183
|
function extractTextFromMDAsHTML(node) {
|
|
182
184
|
switch (node.type) {
|
|
185
|
+
// Nodes with direct text value
|
|
183
186
|
case 'inlineCode':
|
|
184
187
|
case 'text':
|
|
185
188
|
return textToHtml(node.value);
|
|
189
|
+
// Nodes with children to recurse into
|
|
186
190
|
case 'heading':
|
|
187
191
|
case 'root':
|
|
188
|
-
|
|
192
|
+
case 'paragraph':
|
|
193
|
+
case 'blockquote':
|
|
194
|
+
case 'listItem':
|
|
195
|
+
case 'tableCell':
|
|
196
|
+
case 'tableRow':
|
|
197
|
+
case 'link':
|
|
198
|
+
case 'emphasis':
|
|
199
|
+
case 'strong':
|
|
200
|
+
case 'delete':
|
|
201
|
+
return node.children.map((child) => extractTextFromMDAsHTML(child)).join('');
|
|
202
|
+
// Nodes with children but need special handling
|
|
203
|
+
case 'list':
|
|
204
|
+
return node.children.map((child) => extractTextFromMDAsHTML(child)).join('');
|
|
205
|
+
case 'table':
|
|
206
|
+
return node.children.map((child) => extractTextFromMDAsHTML(child)).join('');
|
|
207
|
+
// Nodes with alt text
|
|
208
|
+
case 'image':
|
|
209
|
+
return node.alt ? textToHtml(node.alt) : '';
|
|
210
|
+
// Nodes that don't contribute text content
|
|
189
211
|
case 'html':
|
|
212
|
+
case 'code':
|
|
213
|
+
case 'thematicBreak':
|
|
214
|
+
case 'break':
|
|
215
|
+
case 'definition':
|
|
216
|
+
case 'footnoteDefinition':
|
|
217
|
+
case 'footnoteReference':
|
|
218
|
+
case 'imageReference':
|
|
219
|
+
case 'linkReference':
|
|
220
|
+
case 'yaml':
|
|
190
221
|
return '';
|
|
191
|
-
default:
|
|
192
|
-
|
|
222
|
+
default: {
|
|
223
|
+
// TypeScript exhaustive check - this ensures we handle all types
|
|
224
|
+
const _exhaustiveCheck = node;
|
|
225
|
+
throw markdownError(`unhandled node type: ${node.type}`);
|
|
226
|
+
}
|
|
193
227
|
}
|
|
194
228
|
}
|
|
195
229
|
/**
|
|
196
230
|
* Generates an anchor ID for a Markdown heading based on its text content.
|
|
231
|
+
* Handles all PhrasingContent types that can appear in a heading.
|
|
232
|
+
*
|
|
197
233
|
* @param node The heading node.
|
|
198
|
-
* @returns The generated anchor ID.
|
|
199
|
-
* @throws Error if the child node type is unknown.
|
|
234
|
+
* @returns The generated anchor ID, formatted for use in URLs.
|
|
200
235
|
*/
|
|
201
236
|
function getMDAnchor(node) {
|
|
202
237
|
let text = '';
|
|
203
238
|
for (const c of node.children) {
|
|
204
239
|
// Handle different types of child nodes to construct the anchor text.
|
|
205
240
|
switch (c.type) {
|
|
241
|
+
// Check for explicit ID in HTML
|
|
206
242
|
case 'html': {
|
|
207
243
|
const match = /<a\s.*id\s*=\s*['"]([^'"]+)/i.exec(c.value);
|
|
208
244
|
if (match)
|
|
209
245
|
return match[1];
|
|
210
246
|
break;
|
|
211
247
|
}
|
|
248
|
+
// Nodes with direct text value
|
|
212
249
|
case 'text':
|
|
213
250
|
case 'inlineCode':
|
|
214
251
|
text += c.value;
|
|
215
252
|
break;
|
|
216
|
-
|
|
217
|
-
|
|
253
|
+
// Nodes with children - recurse to extract text
|
|
254
|
+
case 'emphasis':
|
|
255
|
+
case 'strong':
|
|
256
|
+
case 'delete':
|
|
257
|
+
case 'link':
|
|
258
|
+
for (const child of c.children) {
|
|
259
|
+
if (child.type === 'text' || child.type === 'inlineCode') {
|
|
260
|
+
text += child.value;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
// Image - use alt text
|
|
265
|
+
case 'image':
|
|
266
|
+
if (c.alt)
|
|
267
|
+
text += c.alt;
|
|
268
|
+
break;
|
|
269
|
+
// Nodes that don't contribute to anchor text
|
|
270
|
+
case 'break':
|
|
271
|
+
case 'footnoteReference':
|
|
272
|
+
case 'imageReference':
|
|
273
|
+
case 'linkReference':
|
|
274
|
+
break;
|
|
275
|
+
default: {
|
|
276
|
+
// TypeScript exhaustive check
|
|
277
|
+
const _exhaustiveCheck = c;
|
|
278
|
+
throw markdownError(`unhandled phrasing content type: ${c.type}`);
|
|
279
|
+
}
|
|
218
280
|
}
|
|
219
281
|
}
|
|
220
282
|
// Format the text to create a suitable anchor ID.
|
|
@@ -227,6 +289,8 @@ function getMDAnchor(node) {
|
|
|
227
289
|
}
|
|
228
290
|
/**
|
|
229
291
|
* Converts a segment of the AST into a foldable HTML element.
|
|
292
|
+
* Headings become collapsible `<details>` sections.
|
|
293
|
+
*
|
|
230
294
|
* @param ast The AST of the segment to be converted.
|
|
231
295
|
*/
|
|
232
296
|
function convertToFoldable(ast) {
|
|
@@ -234,19 +298,56 @@ function convertToFoldable(ast) {
|
|
|
234
298
|
const children = [];
|
|
235
299
|
ast.children.forEach((c) => {
|
|
236
300
|
switch (c.type) {
|
|
237
|
-
|
|
238
|
-
case 'list':
|
|
239
|
-
case 'paragraph':
|
|
240
|
-
children.push(c);
|
|
241
|
-
break;
|
|
301
|
+
// Headings start new foldable sections
|
|
242
302
|
case 'heading':
|
|
243
303
|
closeDetails(c.depth);
|
|
244
304
|
children.push({ type: 'html', value: '<details>' });
|
|
245
305
|
children.push({ type: 'html', value: `<summary>${lineToHtml(c)}</summary>` });
|
|
246
306
|
openDetails.unshift(c.depth);
|
|
247
307
|
break;
|
|
248
|
-
|
|
249
|
-
|
|
308
|
+
// Block content that gets included in sections
|
|
309
|
+
case 'html':
|
|
310
|
+
case 'list':
|
|
311
|
+
case 'paragraph':
|
|
312
|
+
case 'blockquote':
|
|
313
|
+
case 'code':
|
|
314
|
+
case 'table':
|
|
315
|
+
case 'thematicBreak':
|
|
316
|
+
children.push(c);
|
|
317
|
+
break;
|
|
318
|
+
// Definition content - include as-is
|
|
319
|
+
case 'definition':
|
|
320
|
+
case 'footnoteDefinition':
|
|
321
|
+
children.push(c);
|
|
322
|
+
break;
|
|
323
|
+
// YAML frontmatter - include as-is
|
|
324
|
+
case 'yaml':
|
|
325
|
+
children.push(c);
|
|
326
|
+
break;
|
|
327
|
+
// Inline/phrasing content that shouldn't appear at root level
|
|
328
|
+
// but handle gracefully if present
|
|
329
|
+
case 'text':
|
|
330
|
+
case 'inlineCode':
|
|
331
|
+
case 'emphasis':
|
|
332
|
+
case 'strong':
|
|
333
|
+
case 'delete':
|
|
334
|
+
case 'link':
|
|
335
|
+
case 'image':
|
|
336
|
+
case 'break':
|
|
337
|
+
case 'footnoteReference':
|
|
338
|
+
case 'imageReference':
|
|
339
|
+
case 'linkReference':
|
|
340
|
+
case 'listItem':
|
|
341
|
+
case 'tableCell':
|
|
342
|
+
case 'tableRow':
|
|
343
|
+
// These shouldn't normally appear at root level, but pass through
|
|
344
|
+
children.push(c);
|
|
345
|
+
break;
|
|
346
|
+
default: {
|
|
347
|
+
// TypeScript exhaustive check
|
|
348
|
+
const _exhaustiveCheck = c;
|
|
349
|
+
throw markdownError(`unhandled root content type: ${c.type}`);
|
|
350
|
+
}
|
|
250
351
|
}
|
|
251
352
|
});
|
|
252
353
|
closeDetails(0);
|
|
@@ -261,6 +362,14 @@ function convertToFoldable(ast) {
|
|
|
261
362
|
function lineToHtml(heading) {
|
|
262
363
|
return `<h${heading.depth}>${nodesToHtml(heading.children)}</h${heading.depth}>`;
|
|
263
364
|
}
|
|
365
|
+
/**
|
|
366
|
+
* Converts a PhrasingContent node to its HTML representation.
|
|
367
|
+
* Handles all PhrasingContent types defined in mdast.
|
|
368
|
+
*
|
|
369
|
+
* @param node The phrasing content node to convert.
|
|
370
|
+
* @returns The HTML string representation.
|
|
371
|
+
* @throws {VrtError} For reference types that require resolution (footnote, image, link references).
|
|
372
|
+
*/
|
|
264
373
|
export function nodeToHtml(node) {
|
|
265
374
|
switch (node.type) {
|
|
266
375
|
case 'html':
|
|
@@ -287,14 +396,18 @@ export function nodeToHtml(node) {
|
|
|
287
396
|
attributes.push(`title="${node.title}"`);
|
|
288
397
|
return `<img ${attributes.join(' ')} />`;
|
|
289
398
|
}
|
|
399
|
+
// Reference types require definition resolution which is not supported
|
|
290
400
|
case 'footnoteReference':
|
|
291
|
-
throw
|
|
401
|
+
throw notImplementedError('footnoteReference - requires definition resolution');
|
|
292
402
|
case 'imageReference':
|
|
293
|
-
throw
|
|
403
|
+
throw notImplementedError('imageReference - requires definition resolution');
|
|
294
404
|
case 'linkReference':
|
|
295
|
-
throw
|
|
296
|
-
default:
|
|
297
|
-
|
|
405
|
+
throw notImplementedError('linkReference - requires definition resolution');
|
|
406
|
+
default: {
|
|
407
|
+
// TypeScript exhaustive check
|
|
408
|
+
const _exhaustiveCheck = node;
|
|
409
|
+
throw markdownError(`unhandled phrasing content type: ${node.type}`);
|
|
410
|
+
}
|
|
298
411
|
}
|
|
299
412
|
}
|
|
300
413
|
function nodesToHtml(children) {
|
|
@@ -1,2 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* Options for the release process.
|
|
4
|
+
*/
|
|
5
|
+
export interface ReleaseOptions {
|
|
6
|
+
/** The project directory containing package.json (default: current directory) */
|
|
7
|
+
directory?: string;
|
|
8
|
+
/** The git branch to release from (default: 'main') */
|
|
9
|
+
branch?: string;
|
|
10
|
+
/** If true, simulate the release without making changes (default: false) */
|
|
11
|
+
dryRun?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Executes the npm release process.
|
|
15
|
+
*
|
|
16
|
+
* This function performs a complete release workflow:
|
|
17
|
+
* 1. Validates git state (correct branch, no uncommitted changes)
|
|
18
|
+
* 2. Pulls latest changes from remote
|
|
19
|
+
* 3. Verifies npm authentication
|
|
20
|
+
* 4. Prompts for new version (with suggestion based on conventional commits)
|
|
21
|
+
* 5. Runs project checks
|
|
22
|
+
* 6. Updates package.json version
|
|
23
|
+
* 7. Updates CHANGELOG.md
|
|
24
|
+
* 8. Publishes to npm (if not private)
|
|
25
|
+
* 9. Creates git commit and tag
|
|
26
|
+
* 10. Pushes to remote and creates GitHub release
|
|
27
|
+
*
|
|
28
|
+
* @param directory - The project directory containing package.json
|
|
29
|
+
* @param branch - The git branch to release from (default: 'main')
|
|
30
|
+
* @param dryRun - If true, simulate the release without making changes
|
|
31
|
+
* @throws {VrtError} If any step in the release process fails
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // Standard release from main branch
|
|
36
|
+
* await release('/path/to/project');
|
|
37
|
+
*
|
|
38
|
+
* // Dry run to preview release
|
|
39
|
+
* await release('/path/to/project', 'main', true);
|
|
40
|
+
*
|
|
41
|
+
* // Release from a different branch
|
|
42
|
+
* await release('/path/to/project', 'release');
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
2
45
|
export declare function release(directory: string, branch?: string, dryRun?: boolean): Promise<void>;
|