@versatiles/release-tool 2.6.0 → 2.7.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 +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/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 +154 -29
- 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 +10 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes for categorizing different types of errors in the release tool.
|
|
3
|
+
*/
|
|
4
|
+
export type VrtErrorCode = 'VALIDATION_ERROR' | 'MARKDOWN_ERROR' | 'GIT_ERROR' | 'RELEASE_ERROR' | 'NOT_IMPLEMENTED';
|
|
5
|
+
/**
|
|
6
|
+
* Custom error class for the VersaTiles Release Tool.
|
|
7
|
+
* Provides consistent error handling with categorization via error codes.
|
|
8
|
+
*/
|
|
9
|
+
export declare class VrtError extends Error {
|
|
10
|
+
readonly code: VrtErrorCode;
|
|
11
|
+
constructor(message: string, code?: VrtErrorCode);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Helper function to create a validation error.
|
|
15
|
+
*/
|
|
16
|
+
export declare function validationError(message: string): VrtError;
|
|
17
|
+
/**
|
|
18
|
+
* Helper function to create a markdown processing error.
|
|
19
|
+
*/
|
|
20
|
+
export declare function markdownError(message: string): VrtError;
|
|
21
|
+
/**
|
|
22
|
+
* Helper function to create a git operation error.
|
|
23
|
+
*/
|
|
24
|
+
export declare function gitError(message: string): VrtError;
|
|
25
|
+
/**
|
|
26
|
+
* Helper function to create a release process error.
|
|
27
|
+
*/
|
|
28
|
+
export declare function releaseError(message: string): VrtError;
|
|
29
|
+
/**
|
|
30
|
+
* Helper function to create a not implemented error.
|
|
31
|
+
*/
|
|
32
|
+
export declare function notImplementedError(feature: string): VrtError;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for the VersaTiles Release Tool.
|
|
3
|
+
* Provides consistent error handling with categorization via error codes.
|
|
4
|
+
*/
|
|
5
|
+
export class VrtError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(message, code = 'VALIDATION_ERROR') {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'VrtError';
|
|
10
|
+
this.code = code;
|
|
11
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
12
|
+
if (Error.captureStackTrace) {
|
|
13
|
+
Error.captureStackTrace(this, VrtError);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Helper function to create a validation error.
|
|
19
|
+
*/
|
|
20
|
+
export function validationError(message) {
|
|
21
|
+
return new VrtError(message, 'VALIDATION_ERROR');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Helper function to create a markdown processing error.
|
|
25
|
+
*/
|
|
26
|
+
export function markdownError(message) {
|
|
27
|
+
return new VrtError(message, 'MARKDOWN_ERROR');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Helper function to create a git operation error.
|
|
31
|
+
*/
|
|
32
|
+
export function gitError(message) {
|
|
33
|
+
return new VrtError(message, 'GIT_ERROR');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Helper function to create a release process error.
|
|
37
|
+
*/
|
|
38
|
+
export function releaseError(message) {
|
|
39
|
+
return new VrtError(message, 'RELEASE_ERROR');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Helper function to create a not implemented error.
|
|
43
|
+
*/
|
|
44
|
+
export function notImplementedError(feature) {
|
|
45
|
+
return new VrtError(`Not implemented yet: "${feature}"`, 'NOT_IMPLEMENTED');
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=errors.js.map
|
package/dist/lib/git.d.ts
CHANGED
|
@@ -1,14 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a Git commit with its SHA, message, and optional tag.
|
|
3
|
+
*/
|
|
1
4
|
export interface Commit {
|
|
5
|
+
/** The full SHA hash of the commit. */
|
|
2
6
|
sha: string;
|
|
7
|
+
/** The commit message (first line / subject). */
|
|
3
8
|
message: string;
|
|
9
|
+
/** The tag associated with this commit, if any. */
|
|
4
10
|
tag?: string;
|
|
5
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Conventional commit types and their display labels
|
|
14
|
+
*/
|
|
15
|
+
export declare const COMMIT_TYPES: {
|
|
16
|
+
readonly feat: "Features";
|
|
17
|
+
readonly fix: "Bug Fixes";
|
|
18
|
+
readonly docs: "Documentation";
|
|
19
|
+
readonly style: "Styles";
|
|
20
|
+
readonly refactor: "Code Refactoring";
|
|
21
|
+
readonly perf: "Performance Improvements";
|
|
22
|
+
readonly test: "Tests";
|
|
23
|
+
readonly build: "Build System";
|
|
24
|
+
readonly ci: "CI/CD";
|
|
25
|
+
readonly chore: "Chores";
|
|
26
|
+
readonly revert: "Reverts";
|
|
27
|
+
};
|
|
28
|
+
export type CommitType = keyof typeof COMMIT_TYPES;
|
|
29
|
+
/**
|
|
30
|
+
* Represents a parsed conventional commit
|
|
31
|
+
*/
|
|
32
|
+
export interface ParsedCommit extends Commit {
|
|
33
|
+
/** The conventional commit type (feat, fix, etc.) */
|
|
34
|
+
type?: CommitType;
|
|
35
|
+
/** The scope of the change (e.g., "api" in "feat(api): add endpoint") */
|
|
36
|
+
scope?: string;
|
|
37
|
+
/** The commit description without the type/scope prefix */
|
|
38
|
+
description: string;
|
|
39
|
+
/** Whether this is a breaking change */
|
|
40
|
+
breaking: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parses a commit message according to the Conventional Commits specification.
|
|
44
|
+
* @see https://www.conventionalcommits.org/
|
|
45
|
+
*
|
|
46
|
+
* @param commit - The commit to parse
|
|
47
|
+
* @returns A ParsedCommit with type, scope, description, and breaking change info
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseConventionalCommit(commit: Commit): ParsedCommit;
|
|
50
|
+
/**
|
|
51
|
+
* Determines the suggested semver bump based on parsed commits.
|
|
52
|
+
* - Breaking changes -> major
|
|
53
|
+
* - Features -> minor
|
|
54
|
+
* - Everything else -> patch
|
|
55
|
+
*
|
|
56
|
+
* @param commits - Array of parsed commits
|
|
57
|
+
* @returns The suggested bump type: 'major', 'minor', or 'patch'
|
|
58
|
+
*/
|
|
59
|
+
export declare function getSuggestedBump(commits: ParsedCommit[]): 'major' | 'minor' | 'patch';
|
|
60
|
+
/**
|
|
61
|
+
* Groups parsed commits by their type for release notes.
|
|
62
|
+
*
|
|
63
|
+
* @param commits - Array of parsed commits
|
|
64
|
+
* @returns A Map of commit type to array of commits, plus 'other' for non-conventional commits
|
|
65
|
+
*/
|
|
66
|
+
export declare function groupCommitsByType(commits: ParsedCommit[]): Map<string, ParsedCommit[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Interface for Git operations used by the release tool.
|
|
69
|
+
*/
|
|
6
70
|
export interface Git {
|
|
71
|
+
/**
|
|
72
|
+
* Gets the most recent semver tag from the repository.
|
|
73
|
+
* @returns The SHA and version string of the last tag, or undefined if no semver tags exist.
|
|
74
|
+
*/
|
|
7
75
|
getLastGitHubTag: () => Promise<{
|
|
8
76
|
sha: string;
|
|
9
77
|
version: string;
|
|
10
78
|
} | undefined>;
|
|
79
|
+
/**
|
|
80
|
+
* Gets the current (most recent) commit.
|
|
81
|
+
* @returns The current commit object.
|
|
82
|
+
*/
|
|
11
83
|
getCurrentGitHubCommit: () => Promise<Commit>;
|
|
84
|
+
/**
|
|
85
|
+
* Gets all commits between two commit SHAs.
|
|
86
|
+
* @param shaLast - The older commit SHA (exclusive).
|
|
87
|
+
* @param shaCurrent - The newer commit SHA (inclusive).
|
|
88
|
+
* @returns Array of commits between the two SHAs.
|
|
89
|
+
*/
|
|
12
90
|
getCommitsBetween: (shaLast?: string, shaCurrent?: string) => Promise<Commit[]>;
|
|
13
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Creates a Git interface for the specified directory.
|
|
94
|
+
* Provides methods to query commit history and tags.
|
|
95
|
+
*
|
|
96
|
+
* @param cwd - The working directory of the Git repository.
|
|
97
|
+
* @returns An object with methods to interact with the Git repository.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* const git = getGit('/path/to/repo');
|
|
102
|
+
* const lastTag = await git.getLastGitHubTag();
|
|
103
|
+
* const commits = await git.getCommitsBetween(lastTag?.sha, 'HEAD');
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
14
106
|
export declare function getGit(cwd: string): Git;
|
package/dist/lib/git.js
CHANGED
|
@@ -1,4 +1,100 @@
|
|
|
1
1
|
import { Shell } from './shell.js';
|
|
2
|
+
/**
|
|
3
|
+
* Conventional commit types and their display labels
|
|
4
|
+
*/
|
|
5
|
+
export const COMMIT_TYPES = {
|
|
6
|
+
feat: 'Features',
|
|
7
|
+
fix: 'Bug Fixes',
|
|
8
|
+
docs: 'Documentation',
|
|
9
|
+
style: 'Styles',
|
|
10
|
+
refactor: 'Code Refactoring',
|
|
11
|
+
perf: 'Performance Improvements',
|
|
12
|
+
test: 'Tests',
|
|
13
|
+
build: 'Build System',
|
|
14
|
+
ci: 'CI/CD',
|
|
15
|
+
chore: 'Chores',
|
|
16
|
+
revert: 'Reverts',
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Parses a commit message according to the Conventional Commits specification.
|
|
20
|
+
* @see https://www.conventionalcommits.org/
|
|
21
|
+
*
|
|
22
|
+
* @param commit - The commit to parse
|
|
23
|
+
* @returns A ParsedCommit with type, scope, description, and breaking change info
|
|
24
|
+
*/
|
|
25
|
+
export function parseConventionalCommit(commit) {
|
|
26
|
+
const message = commit.message.trim();
|
|
27
|
+
// Pattern: type(scope)!: description OR type!: description OR type(scope): description OR type: description
|
|
28
|
+
// Note: No space allowed before colon per Conventional Commits spec
|
|
29
|
+
const conventionalPattern = /^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
|
|
30
|
+
const match = message.match(conventionalPattern);
|
|
31
|
+
if (!match) {
|
|
32
|
+
// Not a conventional commit - return with original message as description
|
|
33
|
+
return {
|
|
34
|
+
...commit,
|
|
35
|
+
description: message,
|
|
36
|
+
breaking: message.toUpperCase().includes('BREAKING CHANGE'),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const [, typeStr, scope, breakingMark, description] = match;
|
|
40
|
+
const type = typeStr.toLowerCase();
|
|
41
|
+
const isKnownType = type in COMMIT_TYPES;
|
|
42
|
+
return {
|
|
43
|
+
...commit,
|
|
44
|
+
type: isKnownType ? type : undefined,
|
|
45
|
+
scope: scope || undefined,
|
|
46
|
+
description: description.trim(),
|
|
47
|
+
breaking: breakingMark === '!' || message.toUpperCase().includes('BREAKING CHANGE'),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Determines the suggested semver bump based on parsed commits.
|
|
52
|
+
* - Breaking changes -> major
|
|
53
|
+
* - Features -> minor
|
|
54
|
+
* - Everything else -> patch
|
|
55
|
+
*
|
|
56
|
+
* @param commits - Array of parsed commits
|
|
57
|
+
* @returns The suggested bump type: 'major', 'minor', or 'patch'
|
|
58
|
+
*/
|
|
59
|
+
export function getSuggestedBump(commits) {
|
|
60
|
+
const hasBreaking = commits.some((c) => c.breaking);
|
|
61
|
+
if (hasBreaking)
|
|
62
|
+
return 'major';
|
|
63
|
+
const hasFeature = commits.some((c) => c.type === 'feat');
|
|
64
|
+
if (hasFeature)
|
|
65
|
+
return 'minor';
|
|
66
|
+
return 'patch';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Groups parsed commits by their type for release notes.
|
|
70
|
+
*
|
|
71
|
+
* @param commits - Array of parsed commits
|
|
72
|
+
* @returns A Map of commit type to array of commits, plus 'other' for non-conventional commits
|
|
73
|
+
*/
|
|
74
|
+
export function groupCommitsByType(commits) {
|
|
75
|
+
const groups = new Map();
|
|
76
|
+
for (const commit of commits) {
|
|
77
|
+
const key = commit.type ?? 'other';
|
|
78
|
+
const existing = groups.get(key) ?? [];
|
|
79
|
+
existing.push(commit);
|
|
80
|
+
groups.set(key, existing);
|
|
81
|
+
}
|
|
82
|
+
return groups;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a Git interface for the specified directory.
|
|
86
|
+
* Provides methods to query commit history and tags.
|
|
87
|
+
*
|
|
88
|
+
* @param cwd - The working directory of the Git repository.
|
|
89
|
+
* @returns An object with methods to interact with the Git repository.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const git = getGit('/path/to/repo');
|
|
94
|
+
* const lastTag = await git.getLastGitHubTag();
|
|
95
|
+
* const commits = await git.getCommitsBetween(lastTag?.sha, 'HEAD');
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
2
98
|
export function getGit(cwd) {
|
|
3
99
|
const shell = new Shell(cwd);
|
|
4
100
|
return {
|
|
@@ -6,6 +102,10 @@ export function getGit(cwd) {
|
|
|
6
102
|
getCurrentGitHubCommit,
|
|
7
103
|
getCommitsBetween,
|
|
8
104
|
};
|
|
105
|
+
/**
|
|
106
|
+
* Finds the most recent commit tagged with a semver version (vX.Y.Z format).
|
|
107
|
+
* Supports pre-release and build metadata suffixes.
|
|
108
|
+
*/
|
|
9
109
|
async function getLastGitHubTag() {
|
|
10
110
|
const commits = await getAllCommits();
|
|
11
111
|
const result = commits
|
|
@@ -16,6 +116,10 @@ export function getGit(cwd) {
|
|
|
16
116
|
.find((r) => r.version);
|
|
17
117
|
return result;
|
|
18
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Retrieves all commits from the repository's history.
|
|
121
|
+
* Parses the git log output to extract SHA, message, and tag information.
|
|
122
|
+
*/
|
|
19
123
|
async function getAllCommits() {
|
|
20
124
|
const result = await shell.stdout("git log --pretty=format:'⍃%H⍄%s⍄%D⍄'");
|
|
21
125
|
return result
|
|
@@ -30,9 +134,17 @@ export function getGit(cwd) {
|
|
|
30
134
|
};
|
|
31
135
|
});
|
|
32
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Returns the most recent commit in the repository.
|
|
139
|
+
*/
|
|
33
140
|
async function getCurrentGitHubCommit() {
|
|
34
141
|
return (await getAllCommits())[0];
|
|
35
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Gets commits between two SHA hashes.
|
|
145
|
+
* If shaCurrent is provided, starts from that commit.
|
|
146
|
+
* If shaLast is provided, stops before that commit.
|
|
147
|
+
*/
|
|
36
148
|
async function getCommitsBetween(shaLast, shaCurrent) {
|
|
37
149
|
let commits = await getAllCommits();
|
|
38
150
|
const start = commits.findIndex((commit) => commit.sha === shaCurrent);
|
package/dist/lib/log.d.ts
CHANGED
|
@@ -1,8 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enables or disables verbose logging mode.
|
|
3
|
+
* When enabled, debug messages will be printed to stderr.
|
|
4
|
+
*
|
|
5
|
+
* @param enabled - Whether to enable verbose mode.
|
|
6
|
+
*/
|
|
1
7
|
export declare function setVerbose(enabled: boolean): void;
|
|
8
|
+
/**
|
|
9
|
+
* Checks if verbose mode is currently enabled.
|
|
10
|
+
*
|
|
11
|
+
* @returns `true` if verbose mode is enabled, `false` otherwise.
|
|
12
|
+
*/
|
|
2
13
|
export declare function isVerbose(): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Logs a fatal error message and terminates the process.
|
|
16
|
+
* The message is displayed in bold red text.
|
|
17
|
+
*
|
|
18
|
+
* @param text - The error message to display.
|
|
19
|
+
* @returns Never returns as the process is terminated.
|
|
20
|
+
*/
|
|
3
21
|
export declare function panic(text: string): never;
|
|
22
|
+
/**
|
|
23
|
+
* Logs a warning message to stderr.
|
|
24
|
+
* The message is displayed in bold yellow text.
|
|
25
|
+
*
|
|
26
|
+
* @param text - The warning message to display.
|
|
27
|
+
*/
|
|
4
28
|
export declare function warn(text: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Logs an informational message to stderr.
|
|
31
|
+
*
|
|
32
|
+
* @param text - The informational message to display.
|
|
33
|
+
*/
|
|
5
34
|
export declare function info(text: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Logs a debug message to stderr if verbose mode is enabled.
|
|
37
|
+
* The message is displayed in gray text.
|
|
38
|
+
*
|
|
39
|
+
* @param text - The debug message to display.
|
|
40
|
+
*/
|
|
6
41
|
export declare function debug(text: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Logs an abort message and terminates the process with exit code 1.
|
|
44
|
+
*
|
|
45
|
+
* @returns Never returns as the process is terminated.
|
|
46
|
+
*/
|
|
7
47
|
export declare function abort(): never;
|
|
48
|
+
/**
|
|
49
|
+
* Executes an async operation with progress indication.
|
|
50
|
+
* Displays a spinner-like message while the operation is in progress,
|
|
51
|
+
* then shows a success checkmark or failure X based on the result.
|
|
52
|
+
*
|
|
53
|
+
* @typeParam T - The return type of the promise.
|
|
54
|
+
* @param message - The message to display while the operation is running.
|
|
55
|
+
* @param promise - The promise to await, or a function that returns a promise.
|
|
56
|
+
* @returns The resolved value of the promise.
|
|
57
|
+
* @throws Calls `panic()` if the promise rejects, terminating the process.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const result = await check('Fetching data', fetchData());
|
|
62
|
+
* const result = await check('Processing', async () => processData());
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
8
65
|
export declare function check<T>(message: string, promise: Promise<T> | (() => Promise<T>)): Promise<T>;
|
package/dist/lib/log.js
CHANGED
|
@@ -1,29 +1,88 @@
|
|
|
1
|
+
import { VrtError } from './errors.js';
|
|
2
|
+
/** Internal flag to track verbose mode state. */
|
|
1
3
|
let verboseMode = false;
|
|
4
|
+
/**
|
|
5
|
+
* Enables or disables verbose logging mode.
|
|
6
|
+
* When enabled, debug messages will be printed to stderr.
|
|
7
|
+
*
|
|
8
|
+
* @param enabled - Whether to enable verbose mode.
|
|
9
|
+
*/
|
|
2
10
|
export function setVerbose(enabled) {
|
|
3
11
|
verboseMode = enabled;
|
|
4
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Checks if verbose mode is currently enabled.
|
|
15
|
+
*
|
|
16
|
+
* @returns `true` if verbose mode is enabled, `false` otherwise.
|
|
17
|
+
*/
|
|
5
18
|
export function isVerbose() {
|
|
6
19
|
return verboseMode;
|
|
7
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Logs a fatal error message and terminates the process.
|
|
23
|
+
* The message is displayed in bold red text.
|
|
24
|
+
*
|
|
25
|
+
* @param text - The error message to display.
|
|
26
|
+
* @returns Never returns as the process is terminated.
|
|
27
|
+
*/
|
|
8
28
|
export function panic(text) {
|
|
9
29
|
process.stderr.write(`\x1b[1;31m! ERROR: ${text}\x1b[0m\n`);
|
|
10
30
|
abort();
|
|
11
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Logs a warning message to stderr.
|
|
34
|
+
* The message is displayed in bold yellow text.
|
|
35
|
+
*
|
|
36
|
+
* @param text - The warning message to display.
|
|
37
|
+
*/
|
|
12
38
|
export function warn(text) {
|
|
13
39
|
process.stderr.write(`\x1b[1;33m! warning: ${text}\x1b[0m\n`);
|
|
14
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Logs an informational message to stderr.
|
|
43
|
+
*
|
|
44
|
+
* @param text - The informational message to display.
|
|
45
|
+
*/
|
|
15
46
|
export function info(text) {
|
|
16
47
|
process.stderr.write(`\x1b[0mi ${text}\n`);
|
|
17
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Logs a debug message to stderr if verbose mode is enabled.
|
|
51
|
+
* The message is displayed in gray text.
|
|
52
|
+
*
|
|
53
|
+
* @param text - The debug message to display.
|
|
54
|
+
*/
|
|
18
55
|
export function debug(text) {
|
|
19
56
|
if (verboseMode) {
|
|
20
57
|
process.stderr.write(`\x1b[0;90m ${text}\x1b[0m\n`);
|
|
21
58
|
}
|
|
22
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Logs an abort message and terminates the process with exit code 1.
|
|
62
|
+
*
|
|
63
|
+
* @returns Never returns as the process is terminated.
|
|
64
|
+
*/
|
|
23
65
|
export function abort() {
|
|
24
66
|
info('abort');
|
|
25
67
|
process.exit(1);
|
|
26
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Executes an async operation with progress indication.
|
|
71
|
+
* Displays a spinner-like message while the operation is in progress,
|
|
72
|
+
* then shows a success checkmark or failure X based on the result.
|
|
73
|
+
*
|
|
74
|
+
* @typeParam T - The return type of the promise.
|
|
75
|
+
* @param message - The message to display while the operation is running.
|
|
76
|
+
* @param promise - The promise to await, or a function that returns a promise.
|
|
77
|
+
* @returns The resolved value of the promise.
|
|
78
|
+
* @throws Calls `panic()` if the promise rejects, terminating the process.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const result = await check('Fetching data', fetchData());
|
|
83
|
+
* const result = await check('Processing', async () => processData());
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
27
86
|
export async function check(message, promise) {
|
|
28
87
|
process.stderr.write(`\x1b[0;90m\u2B95 ${message}\x1b[0m`);
|
|
29
88
|
try {
|
|
@@ -33,7 +92,10 @@ export async function check(message, promise) {
|
|
|
33
92
|
}
|
|
34
93
|
catch (error) {
|
|
35
94
|
process.stderr.write(`\r\x1b[0;91m\u2718 ${message}\x1b[0m\n`);
|
|
36
|
-
|
|
95
|
+
if (error instanceof VrtError) {
|
|
96
|
+
panic(`[${error.code}] ${error.message}`);
|
|
97
|
+
}
|
|
98
|
+
panic(error.message ?? String(error));
|
|
37
99
|
}
|
|
38
100
|
}
|
|
39
101
|
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for retry behavior
|
|
3
|
+
*/
|
|
4
|
+
export interface RetryOptions {
|
|
5
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
6
|
+
maxRetries?: number;
|
|
7
|
+
/** Initial delay in milliseconds before first retry (default: 1000) */
|
|
8
|
+
initialDelayMs?: number;
|
|
9
|
+
/** Multiplier for exponential backoff (default: 2) */
|
|
10
|
+
backoffMultiplier?: number;
|
|
11
|
+
/** Maximum delay in milliseconds (default: 30000) */
|
|
12
|
+
maxDelayMs?: number;
|
|
13
|
+
/** Optional callback called before each retry */
|
|
14
|
+
onRetry?: (attempt: number, error: Error, nextDelayMs: number) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Executes an async function with retry logic and exponential backoff.
|
|
18
|
+
*
|
|
19
|
+
* @param fn - The async function to execute
|
|
20
|
+
* @param options - Retry configuration options
|
|
21
|
+
* @returns The result of the function if successful
|
|
22
|
+
* @throws The last error encountered after all retries are exhausted
|
|
23
|
+
*/
|
|
24
|
+
export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const DEFAULT_OPTIONS = {
|
|
2
|
+
maxRetries: 3,
|
|
3
|
+
initialDelayMs: 1000,
|
|
4
|
+
backoffMultiplier: 2,
|
|
5
|
+
maxDelayMs: 30000,
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Executes an async function with retry logic and exponential backoff.
|
|
9
|
+
*
|
|
10
|
+
* @param fn - The async function to execute
|
|
11
|
+
* @param options - Retry configuration options
|
|
12
|
+
* @returns The result of the function if successful
|
|
13
|
+
* @throws The last error encountered after all retries are exhausted
|
|
14
|
+
*/
|
|
15
|
+
export async function withRetry(fn, options = {}) {
|
|
16
|
+
const { maxRetries, initialDelayMs, backoffMultiplier, maxDelayMs } = { ...DEFAULT_OPTIONS, ...options };
|
|
17
|
+
const { onRetry } = options;
|
|
18
|
+
let lastError;
|
|
19
|
+
let currentDelay = initialDelayMs;
|
|
20
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
21
|
+
try {
|
|
22
|
+
return await fn();
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
26
|
+
if (attempt < maxRetries) {
|
|
27
|
+
const nextDelay = Math.min(currentDelay, maxDelayMs);
|
|
28
|
+
if (onRetry) {
|
|
29
|
+
onRetry(attempt + 1, lastError, nextDelay);
|
|
30
|
+
}
|
|
31
|
+
await sleep(nextDelay);
|
|
32
|
+
currentDelay *= backoffMultiplier;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw lastError;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Sleep for a specified number of milliseconds
|
|
40
|
+
*/
|
|
41
|
+
function sleep(ms) {
|
|
42
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=retry.js.map
|