andrud 1.0.1 → 1.0.2
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 +295 -306
- package/dist/__tests__/context.test.d.ts +5 -0
- package/dist/__tests__/context.test.d.ts.map +1 -0
- package/dist/__tests__/context.test.js +86 -0
- package/dist/__tests__/context.test.js.map +1 -0
- package/dist/__tests__/generator.test.d.ts +5 -0
- package/dist/__tests__/generator.test.d.ts.map +1 -0
- package/dist/__tests__/generator.test.js +83 -0
- package/dist/__tests__/generator.test.js.map +1 -0
- package/dist/__tests__/validation.test.d.ts +5 -0
- package/dist/__tests__/validation.test.d.ts.map +1 -0
- package/dist/__tests__/validation.test.js +81 -0
- package/dist/__tests__/validation.test.js.map +1 -0
- package/dist/cli/commands/create.d.ts +10 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +203 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/info.d.ts +13 -0
- package/dist/cli/commands/info.d.ts.map +1 -0
- package/dist/cli/commands/info.js +153 -0
- package/dist/cli/commands/info.js.map +1 -0
- package/dist/cli/commands/init.d.ts +15 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +141 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +18 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +122 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/new.d.ts +22 -0
- package/dist/cli/commands/new.d.ts.map +1 -0
- package/dist/cli/commands/new.js +245 -0
- package/dist/cli/commands/new.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/config.d.ts +89 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +151 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +47 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +175 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/generator.d.ts +44 -0
- package/dist/core/generator.d.ts.map +1 -0
- package/{src/core/generator.ts → dist/core/generator.js} +394 -484
- package/dist/core/generator.js.map +1 -0
- package/dist/core/types.d.ts +125 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +22 -0
- package/dist/core/types.js.map +1 -0
- package/dist/templates/index.d.ts +36 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +141 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/ui/colors.d.ts +40 -0
- package/dist/ui/colors.d.ts.map +1 -0
- package/dist/ui/colors.js +117 -0
- package/dist/ui/colors.js.map +1 -0
- package/dist/ui/output.d.ts +69 -0
- package/dist/ui/output.d.ts.map +1 -0
- package/dist/ui/output.js +199 -0
- package/dist/ui/output.js.map +1 -0
- package/dist/ui/prompts.d.ts +20 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +118 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/spinners.d.ts +30 -0
- package/dist/ui/spinners.d.ts.map +1 -0
- package/dist/ui/spinners.js +74 -0
- package/dist/ui/spinners.js.map +1 -0
- package/dist/ui/types.d.ts +35 -0
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +5 -0
- package/dist/ui/types.js.map +1 -0
- package/dist/utils/filesystem.d.ts +38 -0
- package/dist/utils/filesystem.d.ts.map +1 -0
- package/dist/utils/filesystem.js +181 -0
- package/dist/utils/filesystem.js.map +1 -0
- package/dist/utils/logger.d.ts +27 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/object.d.ts +140 -0
- package/dist/utils/object.d.ts.map +1 -0
- package/dist/utils/object.js +385 -0
- package/dist/utils/object.js.map +1 -0
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +270 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +10 -21
- package/CHANGELOG.md +0 -70
- package/CONTRIBUTING.md +0 -132
- package/sc.png +0 -0
- package/src/__tests__/context.test.ts +0 -133
- package/src/__tests__/generator.test.ts +0 -107
- package/src/__tests__/validation.test.ts +0 -105
- package/src/cli/commands/create.ts +0 -252
- package/src/cli/commands/info.ts +0 -178
- package/src/cli/commands/init.ts +0 -186
- package/src/cli/commands/list.ts +0 -156
- package/src/cli/commands/new.ts +0 -316
- package/src/cli/index.ts +0 -116
- package/src/core/config.ts +0 -172
- package/src/core/context.ts +0 -212
- package/src/core/types.ts +0 -184
- package/src/templates/index.ts +0 -162
- package/src/types/gradient-string.d.ts +0 -25
- package/src/ui/colors.ts +0 -139
- package/src/ui/output.ts +0 -230
- package/src/ui/prompts.ts +0 -170
- package/src/ui/spinners.ts +0 -95
- package/src/ui/types.ts +0 -41
- package/src/utils/filesystem.ts +0 -222
- package/src/utils/logger.ts +0 -67
- package/src/utils/object.ts +0 -456
- package/src/utils/validation.ts +0 -345
- package/tsconfig.json +0 -25
package/src/ui/prompts.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wrapper around @clack/prompts with proper TypeScript types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
select,
|
|
7
|
-
text,
|
|
8
|
-
multiselect,
|
|
9
|
-
confirm,
|
|
10
|
-
isCancel,
|
|
11
|
-
cancel,
|
|
12
|
-
type SelectOptions,
|
|
13
|
-
type TextOptions,
|
|
14
|
-
type MultiSelectOptions,
|
|
15
|
-
type ConfirmOptions
|
|
16
|
-
} from '@clack/prompts';
|
|
17
|
-
|
|
18
|
-
// Re-export core functions
|
|
19
|
-
export {
|
|
20
|
-
select,
|
|
21
|
-
text,
|
|
22
|
-
multiselect,
|
|
23
|
-
confirm,
|
|
24
|
-
isCancel,
|
|
25
|
-
cancel,
|
|
26
|
-
type SelectOptions,
|
|
27
|
-
type TextOptions,
|
|
28
|
-
type MultiSelectOptions,
|
|
29
|
-
type ConfirmOptions
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// Helper function to ask for app name
|
|
33
|
-
export async function askAppName(defaultValue?: string): Promise<string> {
|
|
34
|
-
const value = await text({
|
|
35
|
-
message: '? What is the app name?',
|
|
36
|
-
placeholder: 'MyAwesomeApp',
|
|
37
|
-
defaultValue: defaultValue ?? 'MyAwesomeApp',
|
|
38
|
-
validate: (value: string) => {
|
|
39
|
-
if (!value || value.trim().length === 0) {
|
|
40
|
-
return 'App name cannot be empty';
|
|
41
|
-
}
|
|
42
|
-
if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(value)) {
|
|
43
|
-
return 'App name must start with a letter and contain only letters, numbers, and underscores';
|
|
44
|
-
}
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
if (isCancel(value)) {
|
|
50
|
-
cancel();
|
|
51
|
-
process.exit(0);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return value as string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Helper function to ask for package name
|
|
58
|
-
export async function askPackageName(defaultValue?: string): Promise<string> {
|
|
59
|
-
const value = await text({
|
|
60
|
-
message: '? What is the package name?',
|
|
61
|
-
placeholder: 'com.example.myapp',
|
|
62
|
-
defaultValue: defaultValue ?? 'com.example.myapp',
|
|
63
|
-
validate: (value: string) => {
|
|
64
|
-
if (!value || value.trim().length === 0) {
|
|
65
|
-
return 'Package name cannot be empty';
|
|
66
|
-
}
|
|
67
|
-
if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(value)) {
|
|
68
|
-
return 'Package name must be a valid domain structure (e.g., com.example.myapp)';
|
|
69
|
-
}
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
if (isCancel(value)) {
|
|
75
|
-
cancel();
|
|
76
|
-
process.exit(0);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return value as string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Helper function to ask for project directory
|
|
83
|
-
export async function askDirectory(defaultValue?: string): Promise<string> {
|
|
84
|
-
const value = await text({
|
|
85
|
-
message: '? In which directory should the project be created?',
|
|
86
|
-
placeholder: './my-app',
|
|
87
|
-
defaultValue: defaultValue ?? './my-app',
|
|
88
|
-
validate: (value: string) => {
|
|
89
|
-
if (!value || value.trim().length === 0) {
|
|
90
|
-
return 'Directory path cannot be empty';
|
|
91
|
-
}
|
|
92
|
-
if (value.includes('..')) {
|
|
93
|
-
return 'Directory path cannot contain ".." to prevent directory traversal';
|
|
94
|
-
}
|
|
95
|
-
return undefined;
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (isCancel(value)) {
|
|
100
|
-
cancel();
|
|
101
|
-
process.exit(0);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return value as string;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Template selection helper
|
|
108
|
-
export async function selectTemplate<T extends string>(
|
|
109
|
-
templates: Array<{ label: string; value: T; hint?: string }>
|
|
110
|
-
): Promise<T> {
|
|
111
|
-
const options = templates.map(t => ({
|
|
112
|
-
label: t.label + (t.hint ? ` ${t.hint}` : ''),
|
|
113
|
-
value: t.value
|
|
114
|
-
}));
|
|
115
|
-
|
|
116
|
-
const value = await select({
|
|
117
|
-
message: '? Select a project template',
|
|
118
|
-
options
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (isCancel(value)) {
|
|
122
|
-
cancel();
|
|
123
|
-
process.exit(0);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return value as T;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Multi-select helper
|
|
130
|
-
export async function askMultiSelect<T>(
|
|
131
|
-
options: Array<{ label: string; value: T; hint?: string }>,
|
|
132
|
-
message: string = '? Select options',
|
|
133
|
-
min?: number
|
|
134
|
-
): Promise<T[]> {
|
|
135
|
-
const formattedOptions = options.map(o => ({
|
|
136
|
-
label: o.label + (o.hint ? ` (${o.hint})` : ''),
|
|
137
|
-
value: o.value
|
|
138
|
-
}));
|
|
139
|
-
|
|
140
|
-
const value = await multiselect({
|
|
141
|
-
message,
|
|
142
|
-
options: formattedOptions,
|
|
143
|
-
...(min !== undefined ? { min } : {})
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
if (isCancel(value)) {
|
|
147
|
-
cancel();
|
|
148
|
-
process.exit(0);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return value as T[];
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Confirmation helper
|
|
155
|
-
export async function askConfirmation(
|
|
156
|
-
message: string,
|
|
157
|
-
initialValue: boolean = false
|
|
158
|
-
): Promise<boolean> {
|
|
159
|
-
const value = await confirm({
|
|
160
|
-
message: `? ${message}`,
|
|
161
|
-
initialValue
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (isCancel(value)) {
|
|
165
|
-
cancel();
|
|
166
|
-
process.exit(0);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return value as boolean;
|
|
170
|
-
}
|
package/src/ui/spinners.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spinner utilities using ora
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import ora, { type Ora } from 'ora';
|
|
6
|
-
|
|
7
|
-
export class AsyncSpinner {
|
|
8
|
-
private spinner: Ora | null = null;
|
|
9
|
-
private startTime: number = 0;
|
|
10
|
-
|
|
11
|
-
start(text?: string): void {
|
|
12
|
-
this.startTime = Date.now();
|
|
13
|
-
this.spinner = ora({
|
|
14
|
-
text: text ?? 'Loading...',
|
|
15
|
-
spinner: 'dots'
|
|
16
|
-
}).start();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
update(text: string): void {
|
|
20
|
-
if (this.spinner) {
|
|
21
|
-
this.spinner.text = text;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
succeed(text?: string): void {
|
|
26
|
-
if (this.spinner) {
|
|
27
|
-
const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(1);
|
|
28
|
-
this.spinner.succeed(text ? `${text} (${elapsed}s)` : undefined);
|
|
29
|
-
this.spinner = null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
fail(text?: string): void {
|
|
34
|
-
if (this.spinner) {
|
|
35
|
-
const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(1);
|
|
36
|
-
this.spinner.fail(text ? `${text} (${elapsed}s)` : undefined);
|
|
37
|
-
this.spinner = null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
warn(text?: string): void {
|
|
42
|
-
if (this.spinner) {
|
|
43
|
-
this.spinner.warn(text);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
stop(): void {
|
|
48
|
-
if (this.spinner) {
|
|
49
|
-
this.spinner.stop();
|
|
50
|
-
this.spinner = null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
isSpinning(): boolean {
|
|
55
|
-
return this.spinner?.isSpinning ?? false;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface WithSpinnerOptions {
|
|
60
|
-
text?: string;
|
|
61
|
-
successText?: string;
|
|
62
|
-
failText?: string;
|
|
63
|
-
warnText?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Executes an async function with a spinner
|
|
68
|
-
*/
|
|
69
|
-
export async function withSpinner<T>(
|
|
70
|
-
text: string,
|
|
71
|
-
fn: () => Promise<T>,
|
|
72
|
-
options?: WithSpinnerOptions
|
|
73
|
-
): Promise<T> {
|
|
74
|
-
const spinner = new AsyncSpinner();
|
|
75
|
-
spinner.start(text);
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
const result = await fn();
|
|
79
|
-
spinner.succeed(options?.successText);
|
|
80
|
-
return result;
|
|
81
|
-
} catch (error) {
|
|
82
|
-
spinner.fail(options?.failText ?? (error instanceof Error ? error.message : 'An error occurred'));
|
|
83
|
-
throw error;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Creates a simple loading indicator
|
|
89
|
-
*/
|
|
90
|
-
export function createSpinner(text?: string): Ora {
|
|
91
|
-
return ora({
|
|
92
|
-
text,
|
|
93
|
-
spinner: 'dots'
|
|
94
|
-
});
|
|
95
|
-
}
|
package/src/ui/types.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for UI components and utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export type StyleType = 'primary' | 'success' | 'warning' | 'error' | 'info' | 'muted';
|
|
6
|
-
|
|
7
|
-
export interface SpinnerOptions {
|
|
8
|
-
text?: string;
|
|
9
|
-
color?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface TableColumn<T> {
|
|
13
|
-
header: string;
|
|
14
|
-
accessor: (row: T) => string;
|
|
15
|
-
width?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface ConfirmationOptions {
|
|
19
|
-
message: string;
|
|
20
|
-
initialValue?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface SelectOption<T> {
|
|
24
|
-
label: string;
|
|
25
|
-
value: T;
|
|
26
|
-
hint?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface TextInputOptions {
|
|
30
|
-
message: string;
|
|
31
|
-
placeholder?: string;
|
|
32
|
-
defaultValue?: string;
|
|
33
|
-
validate?: (value: string) => string | null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface MultiSelectOptions<T> {
|
|
37
|
-
message: string;
|
|
38
|
-
options: SelectOption<T>[];
|
|
39
|
-
min?: number;
|
|
40
|
-
max?: number;
|
|
41
|
-
}
|
package/src/utils/filesystem.ts
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File system utilities using fs-extra
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import fse from 'fs-extra';
|
|
6
|
-
import { resolve, join, dirname, basename, extname, relative, normalize, isAbsolute } from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
|
|
9
|
-
// Check if path exists
|
|
10
|
-
export async function exists(path: string): Promise<boolean> {
|
|
11
|
-
try {
|
|
12
|
-
await fse.access(path);
|
|
13
|
-
return true;
|
|
14
|
-
} catch {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Check if path is a directory
|
|
20
|
-
export async function isDirectory(path: string): Promise<boolean> {
|
|
21
|
-
try {
|
|
22
|
-
const stats = await fse.stat(path);
|
|
23
|
-
return stats.isDirectory();
|
|
24
|
-
} catch {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Check if path is a file
|
|
30
|
-
export async function isFile(path: string): Promise<boolean> {
|
|
31
|
-
try {
|
|
32
|
-
const stats = await fse.stat(path);
|
|
33
|
-
return stats.isFile();
|
|
34
|
-
} catch {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Read file content
|
|
40
|
-
export async function readFile(path: string): Promise<string> {
|
|
41
|
-
return fse.readFile(path, 'utf-8');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Write file content
|
|
45
|
-
export async function writeFile(path: string, content: string): Promise<void> {
|
|
46
|
-
await fse.writeFile(path, content, 'utf-8');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Read JSON file
|
|
50
|
-
export async function readJson<T = unknown>(path: string): Promise<T> {
|
|
51
|
-
return fse.readJson(path) as Promise<T>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Write JSON file
|
|
55
|
-
export async function writeJson(path: string, data: unknown, spaces: number = 2): Promise<void> {
|
|
56
|
-
await fse.writeJson(path, data, { spaces });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Copy file
|
|
60
|
-
export async function copyFile(source: string, destination: string): Promise<void> {
|
|
61
|
-
await fse.copy(source, destination);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Move file
|
|
65
|
-
export async function moveFile(source: string, destination: string): Promise<void> {
|
|
66
|
-
await fse.move(source, destination);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Remove file
|
|
70
|
-
export async function removeFile(path: string): Promise<void> {
|
|
71
|
-
try {
|
|
72
|
-
await fse.remove(path);
|
|
73
|
-
} catch {
|
|
74
|
-
// Ignore errors if file doesn't exist
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Create directory
|
|
79
|
-
export async function createDirectory(path: string): Promise<void> {
|
|
80
|
-
await fse.mkdir(path, { recursive: true });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Remove directory
|
|
84
|
-
export async function removeDirectory(path: string): Promise<void> {
|
|
85
|
-
try {
|
|
86
|
-
await fse.remove(path);
|
|
87
|
-
} catch {
|
|
88
|
-
// Ignore errors if directory doesn't exist
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Copy directory
|
|
93
|
-
export async function copyDirectory(source: string, destination: string): Promise<void> {
|
|
94
|
-
await fse.copy(source, destination);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Ensure directory exists
|
|
98
|
-
export async function ensureDirectory(path: string): Promise<void> {
|
|
99
|
-
await fse.ensureDir(path);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Ensure file exists (creates empty file if it doesn't)
|
|
103
|
-
export async function ensureFile(path: string): Promise<void> {
|
|
104
|
-
await fse.ensureFile(path);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Get absolute path
|
|
108
|
-
export function getAbsolutePath(path: string): string {
|
|
109
|
-
if (isAbsolute(path)) {
|
|
110
|
-
return normalize(path);
|
|
111
|
-
}
|
|
112
|
-
return resolve(getCurrentWorkingDirectory(), path);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Normalize path
|
|
116
|
-
export function normalizePath(path: string): string {
|
|
117
|
-
return normalize(path);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Join path segments
|
|
121
|
-
export function joinPath(...paths: string[]): string {
|
|
122
|
-
return join(...paths);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Get directory name
|
|
126
|
-
export function dirnamePath(path: string): string {
|
|
127
|
-
return dirname(path);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Get base name
|
|
131
|
-
export function basenamePath(path: string, ext?: string): string {
|
|
132
|
-
return basename(path, ext);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Get extension
|
|
136
|
-
export function extnamePath(path: string): string {
|
|
137
|
-
return extname(path);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Get relative path
|
|
141
|
-
export function relativePath(from: string, to: string): string {
|
|
142
|
-
return relative(from, to);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Get current working directory
|
|
146
|
-
export function getCurrentWorkingDirectory(): string {
|
|
147
|
-
return process.cwd();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Get package root directory
|
|
151
|
-
export function getPackageRoot(): string {
|
|
152
|
-
const currentFile = import.meta.url;
|
|
153
|
-
if (currentFile.startsWith('file://')) {
|
|
154
|
-
const currentDir = fileURLToPath(new URL('.', currentFile));
|
|
155
|
-
return resolve(currentDir, '..');
|
|
156
|
-
}
|
|
157
|
-
return getCurrentWorkingDirectory();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// List files in directory
|
|
161
|
-
export async function listFiles(directory: string, extensions?: string[]): Promise<string[]> {
|
|
162
|
-
const files: string[] = [];
|
|
163
|
-
|
|
164
|
-
async function walk(dir: string): Promise<void> {
|
|
165
|
-
const entries = await fse.readdir(dir, { withFileTypes: true });
|
|
166
|
-
for (const entry of entries) {
|
|
167
|
-
const fullPath = join(dir, entry.name);
|
|
168
|
-
if (entry.isDirectory()) {
|
|
169
|
-
await walk(fullPath);
|
|
170
|
-
} else if (entry.isFile()) {
|
|
171
|
-
if (!extensions || extensions.some(ext => entry.name.endsWith(ext))) {
|
|
172
|
-
files.push(fullPath);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
await walk(directory);
|
|
179
|
-
return files;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Read directory contents
|
|
183
|
-
export async function readDirectory(directory: string): Promise<string[]> {
|
|
184
|
-
return fse.readdir(directory);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Write file with timeout protection
|
|
189
|
-
*/
|
|
190
|
-
export async function writeFileWithTimeout(
|
|
191
|
-
path: string,
|
|
192
|
-
content: string,
|
|
193
|
-
timeoutMs: number = 5000
|
|
194
|
-
): Promise<void> {
|
|
195
|
-
return Promise.race([
|
|
196
|
-
writeFile(path, content),
|
|
197
|
-
new Promise<void>((_, reject) =>
|
|
198
|
-
setTimeout(
|
|
199
|
-
() => reject(new Error(`Write operation timeout after ${timeoutMs}ms`)),
|
|
200
|
-
timeoutMs
|
|
201
|
-
)
|
|
202
|
-
)
|
|
203
|
-
]);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Create directory with timeout protection
|
|
208
|
-
*/
|
|
209
|
-
export async function createDirectoryWithTimeout(
|
|
210
|
-
path: string,
|
|
211
|
-
timeoutMs: number = 5000
|
|
212
|
-
): Promise<void> {
|
|
213
|
-
return Promise.race([
|
|
214
|
-
createDirectory(path),
|
|
215
|
-
new Promise<void>((_, reject) =>
|
|
216
|
-
setTimeout(
|
|
217
|
-
() => reject(new Error(`Create directory operation timeout after ${timeoutMs}ms`)),
|
|
218
|
-
timeoutMs
|
|
219
|
-
)
|
|
220
|
-
)
|
|
221
|
-
]);
|
|
222
|
-
}
|
package/src/utils/logger.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logging utilities with structured logging levels
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import pc from 'picocolors';
|
|
6
|
-
|
|
7
|
-
export enum LogLevel {
|
|
8
|
-
DEBUG = 0,
|
|
9
|
-
INFO = 1,
|
|
10
|
-
WARN = 2,
|
|
11
|
-
ERROR = 3
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface LoggerOptions {
|
|
15
|
-
level?: LogLevel;
|
|
16
|
-
verbose?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class Logger {
|
|
20
|
-
private level: LogLevel;
|
|
21
|
-
private verbose: boolean;
|
|
22
|
-
|
|
23
|
-
constructor(options: LoggerOptions = {}) {
|
|
24
|
-
this.level = options.level ?? LogLevel.INFO;
|
|
25
|
-
this.verbose = options.verbose ?? false;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
debug(message: string, data?: unknown): void {
|
|
29
|
-
if (this.level <= LogLevel.DEBUG) {
|
|
30
|
-
console.log(pc.gray(`[DEBUG] ${message}`), data ?? '');
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
info(message: string, data?: unknown): void {
|
|
35
|
-
if (this.level <= LogLevel.INFO) {
|
|
36
|
-
console.log(pc.blue(`[INFO] ${message}`), data ?? '');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
warn(message: string, data?: unknown): void {
|
|
41
|
-
if (this.level <= LogLevel.WARN) {
|
|
42
|
-
console.log(pc.yellow(`[WARN] ${message}`), data ?? '');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
error(message: string, error?: Error | string): void {
|
|
47
|
-
console.error(pc.red(`[ERROR] ${message}`), error ?? '');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
success(message: string): void {
|
|
51
|
-
console.log(pc.green(`[SUCCESS] ${message}`));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
setLevel(level: LogLevel): void {
|
|
55
|
-
this.level = level;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
setVerbose(verbose: boolean): void {
|
|
59
|
-
this.verbose = verbose;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Create default logger instance
|
|
64
|
-
export const defaultLogger = new Logger({
|
|
65
|
-
level: process.env.DEBUG ? LogLevel.DEBUG : LogLevel.INFO,
|
|
66
|
-
verbose: process.env.VERBOSE === 'true'
|
|
67
|
-
});
|