voidui-cli 0.1.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 +1 -0
- package/dist/commands/add.d.ts +28 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +104 -0
- package/dist/commands/augment.d.ts +2 -0
- package/dist/commands/augment.d.ts.map +1 -0
- package/dist/commands/augment.js +97 -0
- package/dist/commands/diff.d.ts +19 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +233 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +2 -0
- package/dist/commands/snapshot.d.ts +2 -0
- package/dist/commands/snapshot.d.ts.map +1 -0
- package/dist/commands/snapshot.js +99 -0
- package/dist/commands/update.d.ts +28 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +203 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/types/changelog.d.ts +17 -0
- package/dist/types/changelog.d.ts.map +1 -0
- package/dist/types/changelog.js +1 -0
- package/dist/types/lock-file.d.ts +41 -0
- package/dist/types/lock-file.d.ts.map +1 -0
- package/dist/types/lock-file.js +4 -0
- package/dist/types/registry.d.ts +84 -0
- package/dist/types/registry.d.ts.map +1 -0
- package/dist/types/registry.js +4 -0
- package/dist/utils/checksum.d.ts +27 -0
- package/dist/utils/checksum.d.ts.map +1 -0
- package/dist/utils/checksum.js +50 -0
- package/dist/utils/component-locator.d.ts +23 -0
- package/dist/utils/component-locator.d.ts.map +1 -0
- package/dist/utils/component-locator.js +59 -0
- package/dist/utils/diff-formatter.d.ts +47 -0
- package/dist/utils/diff-formatter.d.ts.map +1 -0
- package/dist/utils/diff-formatter.js +186 -0
- package/dist/utils/file-operations.d.ts +7 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +37 -0
- package/dist/utils/lock-file.d.ts +60 -0
- package/dist/utils/lock-file.d.ts.map +1 -0
- package/dist/utils/lock-file.js +110 -0
- package/dist/utils/merge.d.ts +54 -0
- package/dist/utils/merge.d.ts.map +1 -0
- package/dist/utils/merge.js +84 -0
- package/dist/utils/prompts.d.ts +8 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +49 -0
- package/dist/utils/registry.d.ts +32 -0
- package/dist/utils/registry.d.ts.map +1 -0
- package/dist/utils/registry.js +139 -0
- package/dist/utils/shadcn.d.ts +30 -0
- package/dist/utils/shadcn.d.ts.map +1 -0
- package/dist/utils/shadcn.js +67 -0
- package/dist/validators/changelog.d.ts +50 -0
- package/dist/validators/changelog.d.ts.map +1 -0
- package/dist/validators/changelog.js +31 -0
- package/dist/validators/lock-file.d.ts +32 -0
- package/dist/validators/lock-file.d.ts.map +1 -0
- package/dist/validators/lock-file.js +39 -0
- package/package.json +56 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for formatting diffs and changelogs for terminal output
|
|
3
|
+
*/
|
|
4
|
+
import type { ChangelogEntry } from "../types/changelog.js";
|
|
5
|
+
export interface DiffOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Number of context lines to show around changes
|
|
8
|
+
* @default 3
|
|
9
|
+
*/
|
|
10
|
+
contextLines?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate and format a unified diff between two code strings
|
|
14
|
+
*
|
|
15
|
+
* @param oldContent - Original content
|
|
16
|
+
* @param newContent - New content
|
|
17
|
+
* @param oldLabel - Label for old version (e.g., "separator@1.0.0")
|
|
18
|
+
* @param newLabel - Label for new version (e.g., "separator@1.1.0")
|
|
19
|
+
* @param options - Diff options
|
|
20
|
+
* @returns Formatted diff string with syntax highlighting
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatDiff(oldContent: string, newContent: string, oldLabel: string, newLabel: string, options?: DiffOptions): string;
|
|
23
|
+
/**
|
|
24
|
+
* Apply syntax highlighting to a unified diff
|
|
25
|
+
* Uses chalk for terminal colors
|
|
26
|
+
*
|
|
27
|
+
* @param diffString - Raw unified diff string
|
|
28
|
+
* @returns Colored diff string
|
|
29
|
+
*/
|
|
30
|
+
export declare function highlightDiff(diffString: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Format changelog entries between two versions
|
|
33
|
+
*
|
|
34
|
+
* @param entries - All changelog entries
|
|
35
|
+
* @param fromVersion - Starting version (older)
|
|
36
|
+
* @param toVersion - Ending version (newer)
|
|
37
|
+
* @returns Formatted changelog string
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatChangelog(entries: ChangelogEntry[], fromVersion: string, toVersion: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Format a single changelog entry summary (for compact display)
|
|
42
|
+
*
|
|
43
|
+
* @param entry - Changelog entry
|
|
44
|
+
* @returns Formatted summary string
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatChangelogSummary(entry: ChangelogEntry): string;
|
|
47
|
+
//# sourceMappingURL=diff-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-formatter.d.ts","sourceRoot":"","sources":["../../src/utils/diff-formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,MAAM,CAeR;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwBxD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,cAAc,EAAE,EACzB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CA0CR;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAWpE"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for formatting diffs and changelogs for terminal output
|
|
3
|
+
*/
|
|
4
|
+
import { createPatch } from "diff";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
/**
|
|
7
|
+
* Generate and format a unified diff between two code strings
|
|
8
|
+
*
|
|
9
|
+
* @param oldContent - Original content
|
|
10
|
+
* @param newContent - New content
|
|
11
|
+
* @param oldLabel - Label for old version (e.g., "separator@1.0.0")
|
|
12
|
+
* @param newLabel - Label for new version (e.g., "separator@1.1.0")
|
|
13
|
+
* @param options - Diff options
|
|
14
|
+
* @returns Formatted diff string with syntax highlighting
|
|
15
|
+
*/
|
|
16
|
+
export function formatDiff(oldContent, newContent, oldLabel, newLabel, options = {}) {
|
|
17
|
+
const contextLines = options.contextLines ?? 3;
|
|
18
|
+
// Generate unified diff
|
|
19
|
+
const patch = createPatch(oldLabel, oldContent, newContent, oldLabel, newLabel, { context: contextLines });
|
|
20
|
+
// Apply syntax highlighting
|
|
21
|
+
return highlightDiff(patch);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Apply syntax highlighting to a unified diff
|
|
25
|
+
* Uses chalk for terminal colors
|
|
26
|
+
*
|
|
27
|
+
* @param diffString - Raw unified diff string
|
|
28
|
+
* @returns Colored diff string
|
|
29
|
+
*/
|
|
30
|
+
export function highlightDiff(diffString) {
|
|
31
|
+
const lines = diffString.split("\n");
|
|
32
|
+
const coloredLines = [];
|
|
33
|
+
for (const line of lines) {
|
|
34
|
+
if (line.startsWith("---") || line.startsWith("+++")) {
|
|
35
|
+
// File headers
|
|
36
|
+
coloredLines.push(chalk.bold(line));
|
|
37
|
+
}
|
|
38
|
+
else if (line.startsWith("@@")) {
|
|
39
|
+
// Hunk headers (line numbers)
|
|
40
|
+
coloredLines.push(chalk.cyan(line));
|
|
41
|
+
}
|
|
42
|
+
else if (line.startsWith("+")) {
|
|
43
|
+
// Additions
|
|
44
|
+
coloredLines.push(chalk.green(line));
|
|
45
|
+
}
|
|
46
|
+
else if (line.startsWith("-")) {
|
|
47
|
+
// Deletions
|
|
48
|
+
coloredLines.push(chalk.red(line));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Context lines
|
|
52
|
+
coloredLines.push(chalk.gray(line));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return coloredLines.join("\n");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format changelog entries between two versions
|
|
59
|
+
*
|
|
60
|
+
* @param entries - All changelog entries
|
|
61
|
+
* @param fromVersion - Starting version (older)
|
|
62
|
+
* @param toVersion - Ending version (newer)
|
|
63
|
+
* @returns Formatted changelog string
|
|
64
|
+
*/
|
|
65
|
+
export function formatChangelog(entries, fromVersion, toVersion) {
|
|
66
|
+
// Filter entries between versions
|
|
67
|
+
const relevantEntries = filterEntriesBetweenVersions(entries, fromVersion, toVersion);
|
|
68
|
+
if (relevantEntries.length === 0) {
|
|
69
|
+
return chalk.gray("No changes found between these versions.");
|
|
70
|
+
}
|
|
71
|
+
const output = [];
|
|
72
|
+
for (const entry of relevantEntries) {
|
|
73
|
+
// Version header
|
|
74
|
+
const date = new Date(entry.date).toLocaleDateString("en-US", {
|
|
75
|
+
year: "numeric",
|
|
76
|
+
month: "short",
|
|
77
|
+
day: "numeric",
|
|
78
|
+
});
|
|
79
|
+
let versionLine = chalk.bold(`Version ${entry.version}`) + chalk.gray(` (${date})`);
|
|
80
|
+
if (entry.breaking) {
|
|
81
|
+
versionLine += " " + chalk.red.bold("BREAKING");
|
|
82
|
+
}
|
|
83
|
+
output.push(versionLine);
|
|
84
|
+
// Changes
|
|
85
|
+
for (const change of entry.changes) {
|
|
86
|
+
const icon = getChangeIcon(change.type);
|
|
87
|
+
const color = getChangeColor(change.type);
|
|
88
|
+
output.push(` ${icon} ${color(change.description)}`);
|
|
89
|
+
}
|
|
90
|
+
output.push(""); // Empty line between versions
|
|
91
|
+
}
|
|
92
|
+
return output.join("\n");
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Format a single changelog entry summary (for compact display)
|
|
96
|
+
*
|
|
97
|
+
* @param entry - Changelog entry
|
|
98
|
+
* @returns Formatted summary string
|
|
99
|
+
*/
|
|
100
|
+
export function formatChangelogSummary(entry) {
|
|
101
|
+
const lines = [];
|
|
102
|
+
for (const change of entry.changes) {
|
|
103
|
+
const icon = getChangeIcon(change.type);
|
|
104
|
+
const label = getChangeLabel(change.type);
|
|
105
|
+
const color = getChangeColor(change.type);
|
|
106
|
+
lines.push(` ${icon} ${color(`${label}: ${change.description}`)}`);
|
|
107
|
+
}
|
|
108
|
+
return lines.join("\n");
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Filter changelog entries between two versions
|
|
112
|
+
*/
|
|
113
|
+
function filterEntriesBetweenVersions(entries, fromVersion, toVersion) {
|
|
114
|
+
const fromIndex = entries.findIndex((e) => e.version === fromVersion);
|
|
115
|
+
const toIndex = entries.findIndex((e) => e.version === toVersion);
|
|
116
|
+
if (fromIndex === -1 || toIndex === -1) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
// Entries are typically sorted newest first, so we need the range between indices
|
|
120
|
+
const start = Math.min(fromIndex, toIndex);
|
|
121
|
+
const end = Math.max(fromIndex, toIndex);
|
|
122
|
+
return entries.slice(start, end + 1).reverse(); // Reverse to show oldest first
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get icon for change type
|
|
126
|
+
*/
|
|
127
|
+
function getChangeIcon(type) {
|
|
128
|
+
switch (type) {
|
|
129
|
+
case "added":
|
|
130
|
+
return "+";
|
|
131
|
+
case "changed":
|
|
132
|
+
return "~";
|
|
133
|
+
case "deprecated":
|
|
134
|
+
return "!";
|
|
135
|
+
case "removed":
|
|
136
|
+
return "-";
|
|
137
|
+
case "fixed":
|
|
138
|
+
return "*";
|
|
139
|
+
case "security":
|
|
140
|
+
return "!";
|
|
141
|
+
default:
|
|
142
|
+
return "•";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get label for change type
|
|
147
|
+
*/
|
|
148
|
+
function getChangeLabel(type) {
|
|
149
|
+
switch (type) {
|
|
150
|
+
case "added":
|
|
151
|
+
return "Added";
|
|
152
|
+
case "changed":
|
|
153
|
+
return "Changed";
|
|
154
|
+
case "deprecated":
|
|
155
|
+
return "Deprecated";
|
|
156
|
+
case "removed":
|
|
157
|
+
return "Removed";
|
|
158
|
+
case "fixed":
|
|
159
|
+
return "Fixed";
|
|
160
|
+
case "security":
|
|
161
|
+
return "Security";
|
|
162
|
+
default:
|
|
163
|
+
return "Changed";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get color function for change type
|
|
168
|
+
*/
|
|
169
|
+
function getChangeColor(type) {
|
|
170
|
+
switch (type) {
|
|
171
|
+
case "added":
|
|
172
|
+
return chalk.green;
|
|
173
|
+
case "changed":
|
|
174
|
+
return chalk.blue;
|
|
175
|
+
case "deprecated":
|
|
176
|
+
return chalk.yellow;
|
|
177
|
+
case "removed":
|
|
178
|
+
return chalk.red;
|
|
179
|
+
case "fixed":
|
|
180
|
+
return chalk.cyan;
|
|
181
|
+
case "security":
|
|
182
|
+
return chalk.magenta;
|
|
183
|
+
default:
|
|
184
|
+
return chalk.white;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function fileExists(filePath: string): Promise<boolean>;
|
|
2
|
+
export declare function readJsonFile<T>(filePath: string): Promise<T | null>;
|
|
3
|
+
export declare function writeJsonFile(filePath: string, data: unknown): Promise<void>;
|
|
4
|
+
export declare function copyFile(source: string, destination: string): Promise<void>;
|
|
5
|
+
export declare function ensureDir(dirPath: string): Promise<void>;
|
|
6
|
+
export declare function readDir(dirPath: string): Promise<string[]>;
|
|
7
|
+
//# sourceMappingURL=file-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-operations.d.ts","sourceRoot":"","sources":["../../src/utils/file-operations.ts"],"names":[],"mappings":"AAEA,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAOzE;AAED,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMhE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
export async function fileExists(filePath) {
|
|
3
|
+
try {
|
|
4
|
+
await fs.access(filePath);
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export async function readJsonFile(filePath) {
|
|
12
|
+
try {
|
|
13
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
14
|
+
return JSON.parse(content);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function writeJsonFile(filePath, data) {
|
|
21
|
+
const content = JSON.stringify(data, null, 2);
|
|
22
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
23
|
+
}
|
|
24
|
+
export async function copyFile(source, destination) {
|
|
25
|
+
await fs.copyFile(source, destination);
|
|
26
|
+
}
|
|
27
|
+
export async function ensureDir(dirPath) {
|
|
28
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
export async function readDir(dirPath) {
|
|
31
|
+
try {
|
|
32
|
+
return await fs.readdir(dirPath);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lock file management utilities
|
|
3
|
+
* Handles reading, writing, and updating voidui.lock.json
|
|
4
|
+
*/
|
|
5
|
+
import type { LockFile, ComponentLockEntry } from "../types/lock-file.js";
|
|
6
|
+
/**
|
|
7
|
+
* Read existing lock file or return null if not found
|
|
8
|
+
*
|
|
9
|
+
* @param cwd - Current working directory
|
|
10
|
+
* @returns Lock file or null
|
|
11
|
+
*/
|
|
12
|
+
export declare function readLockFile(cwd: string): Promise<LockFile | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Read lock file or create a new empty one if it doesn't exist
|
|
15
|
+
*
|
|
16
|
+
* @param cwd - Current working directory
|
|
17
|
+
* @returns Lock file
|
|
18
|
+
*/
|
|
19
|
+
export declare function readOrCreateLockFile(cwd: string): Promise<LockFile>;
|
|
20
|
+
/**
|
|
21
|
+
* Write lock file to disk
|
|
22
|
+
*
|
|
23
|
+
* @param cwd - Current working directory
|
|
24
|
+
* @param lockFile - Lock file to write
|
|
25
|
+
*/
|
|
26
|
+
export declare function writeLockFile(cwd: string, lockFile: LockFile): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Update a component entry in the lock file
|
|
29
|
+
*
|
|
30
|
+
* @param lockFile - Lock file to update
|
|
31
|
+
* @param componentName - Component name
|
|
32
|
+
* @param entry - Component entry data
|
|
33
|
+
* @returns Updated lock file
|
|
34
|
+
*/
|
|
35
|
+
export declare function updateComponentEntry(lockFile: LockFile, componentName: string, entry: ComponentLockEntry): LockFile;
|
|
36
|
+
/**
|
|
37
|
+
* Remove a component entry from the lock file
|
|
38
|
+
*
|
|
39
|
+
* @param lockFile - Lock file to update
|
|
40
|
+
* @param componentName - Component name to remove
|
|
41
|
+
* @returns Updated lock file
|
|
42
|
+
*/
|
|
43
|
+
export declare function removeComponentEntry(lockFile: LockFile, componentName: string): LockFile;
|
|
44
|
+
/**
|
|
45
|
+
* Check if a component is tracked in the lock file
|
|
46
|
+
*
|
|
47
|
+
* @param lockFile - Lock file
|
|
48
|
+
* @param componentName - Component name
|
|
49
|
+
* @returns True if component is tracked
|
|
50
|
+
*/
|
|
51
|
+
export declare function isComponentTracked(lockFile: LockFile, componentName: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Get component entry from lock file
|
|
54
|
+
*
|
|
55
|
+
* @param lockFile - Lock file
|
|
56
|
+
* @param componentName - Component name
|
|
57
|
+
* @returns Component entry or null
|
|
58
|
+
*/
|
|
59
|
+
export declare function getComponentEntry(lockFile: LockFile, componentName: string): ComponentLockEntry | null;
|
|
60
|
+
//# sourceMappingURL=lock-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock-file.d.ts","sourceRoot":"","sources":["../../src/utils/lock-file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAM1E;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqBxE;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAYzE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,kBAAkB,GACxB,QAAQ,CAQV;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,GACpB,QAAQ,CAOV;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAET;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,GACpB,kBAAkB,GAAG,IAAI,CAE3B"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lock file management utilities
|
|
3
|
+
* Handles reading, writing, and updating voidui.lock.json
|
|
4
|
+
*/
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { lockFileSchema } from "../validators/lock-file.js";
|
|
7
|
+
import { fileExists, readJsonFile, writeJsonFile } from "./file-operations.js";
|
|
8
|
+
const LOCK_FILE_NAME = "voidui.lock.json";
|
|
9
|
+
const LOCK_FILE_VERSION = "1.0";
|
|
10
|
+
/**
|
|
11
|
+
* Read existing lock file or return null if not found
|
|
12
|
+
*
|
|
13
|
+
* @param cwd - Current working directory
|
|
14
|
+
* @returns Lock file or null
|
|
15
|
+
*/
|
|
16
|
+
export async function readLockFile(cwd) {
|
|
17
|
+
const lockFilePath = path.join(cwd, LOCK_FILE_NAME);
|
|
18
|
+
if (!(await fileExists(lockFilePath))) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const rawLockFile = await readJsonFile(lockFilePath);
|
|
22
|
+
if (!rawLockFile) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const lockFile = lockFileSchema.parse(rawLockFile);
|
|
27
|
+
return lockFile;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`Lock file is corrupted. Please delete ${LOCK_FILE_NAME} and re-install components.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read lock file or create a new empty one if it doesn't exist
|
|
35
|
+
*
|
|
36
|
+
* @param cwd - Current working directory
|
|
37
|
+
* @returns Lock file
|
|
38
|
+
*/
|
|
39
|
+
export async function readOrCreateLockFile(cwd) {
|
|
40
|
+
const existing = await readLockFile(cwd);
|
|
41
|
+
if (existing) {
|
|
42
|
+
return existing;
|
|
43
|
+
}
|
|
44
|
+
// Create new lock file structure
|
|
45
|
+
return {
|
|
46
|
+
version: LOCK_FILE_VERSION,
|
|
47
|
+
components: {},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Write lock file to disk
|
|
52
|
+
*
|
|
53
|
+
* @param cwd - Current working directory
|
|
54
|
+
* @param lockFile - Lock file to write
|
|
55
|
+
*/
|
|
56
|
+
export async function writeLockFile(cwd, lockFile) {
|
|
57
|
+
const lockFilePath = path.join(cwd, LOCK_FILE_NAME);
|
|
58
|
+
await writeJsonFile(lockFilePath, lockFile);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Update a component entry in the lock file
|
|
62
|
+
*
|
|
63
|
+
* @param lockFile - Lock file to update
|
|
64
|
+
* @param componentName - Component name
|
|
65
|
+
* @param entry - Component entry data
|
|
66
|
+
* @returns Updated lock file
|
|
67
|
+
*/
|
|
68
|
+
export function updateComponentEntry(lockFile, componentName, entry) {
|
|
69
|
+
return {
|
|
70
|
+
...lockFile,
|
|
71
|
+
components: {
|
|
72
|
+
...lockFile.components,
|
|
73
|
+
[componentName]: entry,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Remove a component entry from the lock file
|
|
79
|
+
*
|
|
80
|
+
* @param lockFile - Lock file to update
|
|
81
|
+
* @param componentName - Component name to remove
|
|
82
|
+
* @returns Updated lock file
|
|
83
|
+
*/
|
|
84
|
+
export function removeComponentEntry(lockFile, componentName) {
|
|
85
|
+
const { [componentName]: _, ...remainingComponents } = lockFile.components;
|
|
86
|
+
return {
|
|
87
|
+
...lockFile,
|
|
88
|
+
components: remainingComponents,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if a component is tracked in the lock file
|
|
93
|
+
*
|
|
94
|
+
* @param lockFile - Lock file
|
|
95
|
+
* @param componentName - Component name
|
|
96
|
+
* @returns True if component is tracked
|
|
97
|
+
*/
|
|
98
|
+
export function isComponentTracked(lockFile, componentName) {
|
|
99
|
+
return componentName in lockFile.components;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get component entry from lock file
|
|
103
|
+
*
|
|
104
|
+
* @param lockFile - Lock file
|
|
105
|
+
* @param componentName - Component name
|
|
106
|
+
* @returns Component entry or null
|
|
107
|
+
*/
|
|
108
|
+
export function getComponentEntry(lockFile, componentName) {
|
|
109
|
+
return lockFile.components[componentName] || null;
|
|
110
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3-way merge utilities for component updates
|
|
3
|
+
* Handles merging local changes with upstream updates
|
|
4
|
+
*/
|
|
5
|
+
export interface MergeResult {
|
|
6
|
+
/**
|
|
7
|
+
* Whether the merge was successful (no conflicts)
|
|
8
|
+
*/
|
|
9
|
+
success: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Merged content (may contain conflict markers if !success)
|
|
12
|
+
*/
|
|
13
|
+
content: string;
|
|
14
|
+
/**
|
|
15
|
+
* Number of conflicts found
|
|
16
|
+
*/
|
|
17
|
+
conflictCount: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Perform a 3-way merge of component files
|
|
21
|
+
*
|
|
22
|
+
* @param base - Original version (what was installed)
|
|
23
|
+
* @param ours - Current local version (potentially modified)
|
|
24
|
+
* @param theirs - New version from registry
|
|
25
|
+
* @param labels - Optional labels for conflict markers
|
|
26
|
+
* @returns Merge result
|
|
27
|
+
*/
|
|
28
|
+
export declare function threeWayMerge(base: string, ours: string, theirs: string, labels?: {
|
|
29
|
+
ours?: string;
|
|
30
|
+
theirs?: string;
|
|
31
|
+
}): MergeResult;
|
|
32
|
+
/**
|
|
33
|
+
* Check if content contains merge conflict markers
|
|
34
|
+
*
|
|
35
|
+
* @param content - File content to check
|
|
36
|
+
* @returns True if conflict markers are present
|
|
37
|
+
*/
|
|
38
|
+
export declare function hasConflictMarkers(content: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Count the number of conflict regions in content
|
|
41
|
+
*
|
|
42
|
+
* @param content - File content
|
|
43
|
+
* @returns Number of conflict regions
|
|
44
|
+
*/
|
|
45
|
+
export declare function countConflicts(content: string): number;
|
|
46
|
+
/**
|
|
47
|
+
* Generate a user-friendly message for merge results
|
|
48
|
+
*
|
|
49
|
+
* @param result - Merge result
|
|
50
|
+
* @param componentPath - Path to component file
|
|
51
|
+
* @returns Formatted message
|
|
52
|
+
*/
|
|
53
|
+
export declare function formatMergeMessage(result: MergeResult, componentPath: string): string;
|
|
54
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/utils/merge.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,WAAW,CAoCb;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAM3D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,aAAa,EAAE,MAAM,GACpB,MAAM,CAeR"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3-way merge utilities for component updates
|
|
3
|
+
* Handles merging local changes with upstream updates
|
|
4
|
+
*/
|
|
5
|
+
import { diff3Merge } from "node-diff3";
|
|
6
|
+
/**
|
|
7
|
+
* Perform a 3-way merge of component files
|
|
8
|
+
*
|
|
9
|
+
* @param base - Original version (what was installed)
|
|
10
|
+
* @param ours - Current local version (potentially modified)
|
|
11
|
+
* @param theirs - New version from registry
|
|
12
|
+
* @param labels - Optional labels for conflict markers
|
|
13
|
+
* @returns Merge result
|
|
14
|
+
*/
|
|
15
|
+
export function threeWayMerge(base, ours, theirs, labels) {
|
|
16
|
+
// Split content into lines for diff3
|
|
17
|
+
const baseLines = base.split("\n");
|
|
18
|
+
const oursLines = ours.split("\n");
|
|
19
|
+
const theirsLines = theirs.split("\n");
|
|
20
|
+
// Perform 3-way merge
|
|
21
|
+
const mergeResults = diff3Merge(oursLines, baseLines, theirsLines);
|
|
22
|
+
let conflictCount = 0;
|
|
23
|
+
const mergedLines = [];
|
|
24
|
+
for (const result of mergeResults) {
|
|
25
|
+
if (result.ok) {
|
|
26
|
+
// No conflict, use the merged result
|
|
27
|
+
mergedLines.push(...result.ok);
|
|
28
|
+
}
|
|
29
|
+
else if (result.conflict) {
|
|
30
|
+
// Conflict detected
|
|
31
|
+
conflictCount++;
|
|
32
|
+
// Add conflict markers
|
|
33
|
+
mergedLines.push(`<<<<<<< ${labels?.ours || "ours (your changes)"}`, ...result.conflict.a, "=======", ...result.conflict.b, `>>>>>>> ${labels?.theirs || "theirs (upstream)"}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
success: conflictCount === 0,
|
|
38
|
+
content: mergedLines.join("\n"),
|
|
39
|
+
conflictCount,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if content contains merge conflict markers
|
|
44
|
+
*
|
|
45
|
+
* @param content - File content to check
|
|
46
|
+
* @returns True if conflict markers are present
|
|
47
|
+
*/
|
|
48
|
+
export function hasConflictMarkers(content) {
|
|
49
|
+
return (content.includes("<<<<<<<") &&
|
|
50
|
+
content.includes("=======") &&
|
|
51
|
+
content.includes(">>>>>>>"));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Count the number of conflict regions in content
|
|
55
|
+
*
|
|
56
|
+
* @param content - File content
|
|
57
|
+
* @returns Number of conflict regions
|
|
58
|
+
*/
|
|
59
|
+
export function countConflicts(content) {
|
|
60
|
+
const matches = content.match(/<<<<<<</g);
|
|
61
|
+
return matches ? matches.length : 0;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Generate a user-friendly message for merge results
|
|
65
|
+
*
|
|
66
|
+
* @param result - Merge result
|
|
67
|
+
* @param componentPath - Path to component file
|
|
68
|
+
* @returns Formatted message
|
|
69
|
+
*/
|
|
70
|
+
export function formatMergeMessage(result, componentPath) {
|
|
71
|
+
if (result.success) {
|
|
72
|
+
return `✓ Successfully merged your changes with the latest version`;
|
|
73
|
+
}
|
|
74
|
+
return `⚠️ Merge completed with ${result.conflictCount} conflict${result.conflictCount > 1 ? "s" : ""}
|
|
75
|
+
|
|
76
|
+
Conflict markers have been added to: ${componentPath}
|
|
77
|
+
|
|
78
|
+
To resolve:
|
|
79
|
+
1. Open the file and search for "<<<<<<<"
|
|
80
|
+
2. Edit each conflict region to keep the code you want
|
|
81
|
+
3. Remove the conflict markers (<<<<<<<, =======, >>>>>>>)
|
|
82
|
+
4. Save the file
|
|
83
|
+
5. Run: voidui add ${componentPath.split("/").pop()?.replace(".tsx", "")} --force`;
|
|
84
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ChangeType } from "../types/changelog.js";
|
|
2
|
+
export declare function promptForChange(): Promise<{
|
|
3
|
+
type: ChangeType;
|
|
4
|
+
description: string;
|
|
5
|
+
} | null>;
|
|
6
|
+
export declare function promptForMore(message: string): Promise<boolean>;
|
|
7
|
+
export declare function promptForBreaking(): Promise<boolean>;
|
|
8
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,IAAI,CAAC,CAgCR;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASrE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS1D"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
export async function promptForChange() {
|
|
3
|
+
const response = await prompts([
|
|
4
|
+
{
|
|
5
|
+
type: "select",
|
|
6
|
+
name: "type",
|
|
7
|
+
message: "Change type:",
|
|
8
|
+
choices: [
|
|
9
|
+
{ title: "✨ Added", value: "added" },
|
|
10
|
+
{ title: "🔄 Changed", value: "changed" },
|
|
11
|
+
{ title: "⚠️ Deprecated", value: "deprecated" },
|
|
12
|
+
{ title: "🗑️ Removed", value: "removed" },
|
|
13
|
+
{ title: "🐛 Fixed", value: "fixed" },
|
|
14
|
+
{ title: "🔒 Security", value: "security" },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
name: "description",
|
|
20
|
+
message: "Change description:",
|
|
21
|
+
validate: (value) => value.length > 0 ? true : "Description cannot be empty",
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
if (!response.type || !response.description) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
type: response.type,
|
|
29
|
+
description: response.description,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function promptForMore(message) {
|
|
33
|
+
const response = await prompts({
|
|
34
|
+
type: "confirm",
|
|
35
|
+
name: "more",
|
|
36
|
+
message,
|
|
37
|
+
initial: false,
|
|
38
|
+
});
|
|
39
|
+
return response.more ?? false;
|
|
40
|
+
}
|
|
41
|
+
export async function promptForBreaking() {
|
|
42
|
+
const response = await prompts({
|
|
43
|
+
type: "confirm",
|
|
44
|
+
name: "breaking",
|
|
45
|
+
message: "Is this a breaking change?",
|
|
46
|
+
initial: false,
|
|
47
|
+
});
|
|
48
|
+
return response.breaking ?? false;
|
|
49
|
+
}
|