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.
Files changed (121) hide show
  1. package/README.md +295 -306
  2. package/dist/__tests__/context.test.d.ts +5 -0
  3. package/dist/__tests__/context.test.d.ts.map +1 -0
  4. package/dist/__tests__/context.test.js +86 -0
  5. package/dist/__tests__/context.test.js.map +1 -0
  6. package/dist/__tests__/generator.test.d.ts +5 -0
  7. package/dist/__tests__/generator.test.d.ts.map +1 -0
  8. package/dist/__tests__/generator.test.js +83 -0
  9. package/dist/__tests__/generator.test.js.map +1 -0
  10. package/dist/__tests__/validation.test.d.ts +5 -0
  11. package/dist/__tests__/validation.test.d.ts.map +1 -0
  12. package/dist/__tests__/validation.test.js +81 -0
  13. package/dist/__tests__/validation.test.js.map +1 -0
  14. package/dist/cli/commands/create.d.ts +10 -0
  15. package/dist/cli/commands/create.d.ts.map +1 -0
  16. package/dist/cli/commands/create.js +203 -0
  17. package/dist/cli/commands/create.js.map +1 -0
  18. package/dist/cli/commands/info.d.ts +13 -0
  19. package/dist/cli/commands/info.d.ts.map +1 -0
  20. package/dist/cli/commands/info.js +153 -0
  21. package/dist/cli/commands/info.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +15 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +141 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/commands/list.d.ts +18 -0
  27. package/dist/cli/commands/list.d.ts.map +1 -0
  28. package/dist/cli/commands/list.js +122 -0
  29. package/dist/cli/commands/list.js.map +1 -0
  30. package/dist/cli/commands/new.d.ts +22 -0
  31. package/dist/cli/commands/new.d.ts.map +1 -0
  32. package/dist/cli/commands/new.js +245 -0
  33. package/dist/cli/commands/new.js.map +1 -0
  34. package/dist/cli/index.d.ts +5 -0
  35. package/dist/cli/index.d.ts.map +1 -0
  36. package/dist/cli/index.js +99 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/core/config.d.ts +89 -0
  39. package/dist/core/config.d.ts.map +1 -0
  40. package/dist/core/config.js +151 -0
  41. package/dist/core/config.js.map +1 -0
  42. package/dist/core/context.d.ts +47 -0
  43. package/dist/core/context.d.ts.map +1 -0
  44. package/dist/core/context.js +175 -0
  45. package/dist/core/context.js.map +1 -0
  46. package/dist/core/generator.d.ts +44 -0
  47. package/dist/core/generator.d.ts.map +1 -0
  48. package/{src/core/generator.ts → dist/core/generator.js} +394 -484
  49. package/dist/core/generator.js.map +1 -0
  50. package/dist/core/types.d.ts +125 -0
  51. package/dist/core/types.d.ts.map +1 -0
  52. package/dist/core/types.js +22 -0
  53. package/dist/core/types.js.map +1 -0
  54. package/dist/templates/index.d.ts +36 -0
  55. package/dist/templates/index.d.ts.map +1 -0
  56. package/dist/templates/index.js +141 -0
  57. package/dist/templates/index.js.map +1 -0
  58. package/dist/ui/colors.d.ts +40 -0
  59. package/dist/ui/colors.d.ts.map +1 -0
  60. package/dist/ui/colors.js +117 -0
  61. package/dist/ui/colors.js.map +1 -0
  62. package/dist/ui/output.d.ts +69 -0
  63. package/dist/ui/output.d.ts.map +1 -0
  64. package/dist/ui/output.js +199 -0
  65. package/dist/ui/output.js.map +1 -0
  66. package/dist/ui/prompts.d.ts +20 -0
  67. package/dist/ui/prompts.d.ts.map +1 -0
  68. package/dist/ui/prompts.js +118 -0
  69. package/dist/ui/prompts.js.map +1 -0
  70. package/dist/ui/spinners.d.ts +30 -0
  71. package/dist/ui/spinners.d.ts.map +1 -0
  72. package/dist/ui/spinners.js +74 -0
  73. package/dist/ui/spinners.js.map +1 -0
  74. package/dist/ui/types.d.ts +35 -0
  75. package/dist/ui/types.d.ts.map +1 -0
  76. package/dist/ui/types.js +5 -0
  77. package/dist/ui/types.js.map +1 -0
  78. package/dist/utils/filesystem.d.ts +38 -0
  79. package/dist/utils/filesystem.d.ts.map +1 -0
  80. package/dist/utils/filesystem.js +181 -0
  81. package/dist/utils/filesystem.js.map +1 -0
  82. package/dist/utils/logger.d.ts +27 -0
  83. package/dist/utils/logger.d.ts.map +1 -0
  84. package/dist/utils/logger.js +52 -0
  85. package/dist/utils/logger.js.map +1 -0
  86. package/dist/utils/object.d.ts +140 -0
  87. package/dist/utils/object.d.ts.map +1 -0
  88. package/dist/utils/object.js +385 -0
  89. package/dist/utils/object.js.map +1 -0
  90. package/dist/utils/validation.d.ts +35 -0
  91. package/dist/utils/validation.d.ts.map +1 -0
  92. package/dist/utils/validation.js +270 -0
  93. package/dist/utils/validation.js.map +1 -0
  94. package/package.json +10 -21
  95. package/CHANGELOG.md +0 -70
  96. package/CONTRIBUTING.md +0 -132
  97. package/sc.png +0 -0
  98. package/src/__tests__/context.test.ts +0 -133
  99. package/src/__tests__/generator.test.ts +0 -107
  100. package/src/__tests__/validation.test.ts +0 -105
  101. package/src/cli/commands/create.ts +0 -252
  102. package/src/cli/commands/info.ts +0 -178
  103. package/src/cli/commands/init.ts +0 -186
  104. package/src/cli/commands/list.ts +0 -156
  105. package/src/cli/commands/new.ts +0 -316
  106. package/src/cli/index.ts +0 -116
  107. package/src/core/config.ts +0 -172
  108. package/src/core/context.ts +0 -212
  109. package/src/core/types.ts +0 -184
  110. package/src/templates/index.ts +0 -162
  111. package/src/types/gradient-string.d.ts +0 -25
  112. package/src/ui/colors.ts +0 -139
  113. package/src/ui/output.ts +0 -230
  114. package/src/ui/prompts.ts +0 -170
  115. package/src/ui/spinners.ts +0 -95
  116. package/src/ui/types.ts +0 -41
  117. package/src/utils/filesystem.ts +0 -222
  118. package/src/utils/logger.ts +0 -67
  119. package/src/utils/object.ts +0 -456
  120. package/src/utils/validation.ts +0 -345
  121. package/tsconfig.json +0 -25
@@ -1,162 +0,0 @@
1
- /**
2
- * Template registry and metadata
3
- */
4
-
5
- import type { TemplateType } from '../core/types.js';
6
-
7
- interface TemplateMetadata {
8
- id: TemplateType;
9
- name: string;
10
- description: string;
11
- keywords: string[];
12
- features: string[];
13
- language: 'kotlin' | 'java';
14
- uiFramework: 'xml' | 'compose';
15
- }
16
-
17
- export type { TemplateMetadata };
18
-
19
- export const TEMPLATE_REGISTRY: TemplateMetadata[] = [
20
- {
21
- id: 'kotlin-xml',
22
- name: 'Kotlin with XML Layouts',
23
- description: 'Traditional Android Views with Kotlin. Best for developers who prefer XML layouts and ViewBinding.',
24
- keywords: ['kotlin', 'xml', 'views', 'viewbinding', 'material'],
25
- features: ['Material Design 3', 'ViewBinding', 'Kotlin Coroutines', 'RecyclerView', 'ConstraintLayout'],
26
- language: 'kotlin',
27
- uiFramework: 'xml'
28
- },
29
- {
30
- id: 'kotlin-compose',
31
- name: 'Kotlin with Jetpack Compose',
32
- description: 'Modern declarative UI with Kotlin and Jetpack Compose. Latest Android UI toolkit with Material 3 support.',
33
- keywords: ['kotlin', 'compose', 'declarative', 'material3', 'modern'],
34
- features: ['Material Design 3', 'Compose Navigation', 'Kotlin Coroutines', 'ViewModel', 'Hilt'],
35
- language: 'kotlin',
36
- uiFramework: 'compose'
37
- },
38
- {
39
- id: 'java-xml',
40
- name: 'Java with XML Layouts',
41
- description: 'Traditional Android Views with Java. Ideal for teams maintaining Java codebases or preferring Java syntax.',
42
- keywords: ['java', 'xml', 'views', 'viewbinding', 'legacy'],
43
- features: ['Material Design 3', 'ViewBinding', 'Java 17', 'RecyclerView', 'ConstraintLayout'],
44
- language: 'java',
45
- uiFramework: 'xml'
46
- },
47
- {
48
- id: 'native-cpp',
49
- name: 'Kotlin with Native C++/NDK',
50
- description: 'Native C++ development with JNI integration. For high-performance code, game engines, or system-level programming.',
51
- keywords: ['kotlin', 'native', 'cpp', 'ndk', 'jni', 'cmake'],
52
- features: ['CMake Integration', 'JNI Bridge', 'Native Development', 'Multi-ABI Support', 'STL'],
53
- language: 'kotlin',
54
- uiFramework: 'xml'
55
- }
56
- ];
57
-
58
- /**
59
- * Get template metadata by ID
60
- */
61
- export function getTemplateMetadata(id: TemplateType): TemplateMetadata | undefined {
62
- return TEMPLATE_REGISTRY.find((t) => t.id === id);
63
- }
64
-
65
- /**
66
- * Get all available templates
67
- */
68
- export function getAllTemplates(): TemplateMetadata[] {
69
- return [...TEMPLATE_REGISTRY];
70
- }
71
-
72
- /**
73
- * Search templates by query
74
- */
75
- export function searchTemplates(query: string): TemplateMetadata[] {
76
- const lowerQuery = query.toLowerCase();
77
-
78
- return TEMPLATE_REGISTRY.filter((template) => {
79
- if (template.name.toLowerCase().includes(lowerQuery)) {
80
- return true;
81
- }
82
- if (template.description.toLowerCase().includes(lowerQuery)) {
83
- return true;
84
- }
85
- if (template.keywords.some((k) => k.toLowerCase().includes(lowerQuery))) {
86
- return true;
87
- }
88
- if (template.id.toLowerCase().includes(lowerQuery)) {
89
- return true;
90
- }
91
- return false;
92
- });
93
- }
94
-
95
- /**
96
- * Get templates by category
97
- */
98
- export function getTemplatesByCategory(category: 'kotlin' | 'java' | 'native'): TemplateMetadata[] {
99
- return TEMPLATE_REGISTRY.filter((t) => {
100
- switch (category) {
101
- case 'kotlin':
102
- return t.id === 'kotlin-xml' || t.id === 'kotlin-compose' || t.id === 'native-cpp';
103
- case 'java':
104
- return t.id === 'java-xml';
105
- case 'native':
106
- return t.id === 'native-cpp';
107
- default:
108
- return false;
109
- }
110
- });
111
- }
112
-
113
- /**
114
- * Get template preview code
115
- */
116
- export function getTemplatePreview(id: TemplateType): string | undefined {
117
- const previews: Record<string, string> = {
118
- 'kotlin-compose': `// MainActivity.kt
119
- @Composable
120
- fun MainScreen() {
121
- var count by remember { mutableIntStateOf(0) }
122
-
123
- Column(
124
- modifier = Modifier
125
- .fillMaxSize()
126
- .padding(16.dp),
127
- horizontalAlignment = Alignment.CenterHorizontally
128
- ) {
129
- Text(
130
- text = "Count: $count",
131
- style = MaterialTheme.typography.headlineMedium
132
- )
133
- }
134
- }`,
135
- 'kotlin-xml': `// MainActivity.kt
136
- class MainActivity : AppCompatActivity() {
137
- override fun onCreate(savedInstanceState: Bundle?) {
138
- super.onCreate(savedInstanceState)
139
- setContentView(R.layout.activity_main)
140
- }
141
- }`,
142
- 'java-xml': `// MainActivity.java
143
- public class MainActivity extends AppCompatActivity {
144
- @Override
145
- protected void onCreate(Bundle savedInstanceState) {
146
- super.onCreate(savedInstanceState);
147
- setContentView(R.layout.activity_main);
148
- }
149
- }`,
150
- 'native-cpp': `// native-lib.cpp
151
- #include <jni.h>
152
- #include <string>
153
-
154
- extern "C" JNIEXPORT jstring JNICALL
155
- Java_com_example_app_NativeLib_stringFromJNI(
156
- JNIEnv* env, jobject /* this */) {
157
- return env->NewStringUTF("Hello from C++");
158
- }`
159
- };
160
-
161
- return previews[id];
162
- }
@@ -1,25 +0,0 @@
1
- declare module 'gradient-string' {
2
- interface Gradient {
3
- (text: string): string;
4
- rainbow(text: string): string;
5
- pastel(text: string): string;
6
- ice(text: string): string;
7
- }
8
-
9
- interface GradientStatic {
10
- (color1: string, color2: string): Gradient;
11
- rainbow: Gradient;
12
- pastel: Gradient;
13
- teen: Gradient;
14
- mind: Gradient;
15
- summer: Gradient;
16
- winter: Gradient;
17
- autumn: Gradient;
18
- spring: Gradient;
19
- forest: Gradient;
20
- }
21
-
22
- const gradient: GradientStatic;
23
- export default gradient;
24
- export { Gradient, GradientStatic };
25
- }
package/src/ui/colors.ts DELETED
@@ -1,139 +0,0 @@
1
- /**
2
- * Color and text formatting utilities using picocolors and gradient-string
3
- */
4
-
5
- import pc from 'picocolors';
6
- import gradient from 'gradient-string';
7
-
8
- // Style function to apply color based on type
9
- export function style(text: string, type: 'primary' | 'success' | 'warning' | 'error' | 'info' | 'muted'): string {
10
- switch (type) {
11
- case 'primary':
12
- return pc.cyan(text);
13
- case 'success':
14
- return pc.green(text);
15
- case 'warning':
16
- return pc.yellow(text);
17
- case 'error':
18
- return pc.red(text);
19
- case 'info':
20
- return pc.blue(text);
21
- case 'muted':
22
- return pc.gray(text);
23
- default:
24
- return text;
25
- }
26
- }
27
-
28
- // Text formatting functions
29
- export const bold = (text: string): string => pc.bold(text);
30
- export const dim = (text: string): string => pc.dim(text);
31
- export const underline = (text: string): string => pc.underline(text);
32
- export const inverse = (text: string): string => pc.inverse(text);
33
- export const italic = (text: string): string => pc.italic(text);
34
-
35
- // Color functions
36
- export const primary = (text: string): string => pc.cyan(text);
37
- export const success = (text: string): string => pc.green(text);
38
- export const warning = (text: string): string => pc.yellow(text);
39
- export const error = (text: string): string => pc.red(text);
40
- export const info = (text: string): string => pc.blue(text);
41
- export const muted = (text: string): string => pc.gray(text);
42
-
43
- // Aliases for backward compatibility
44
- export const cyan = (text: string): string => pc.cyan(text);
45
- export const green = (text: string): string => pc.green(text);
46
- export const yellow = (text: string): string => pc.yellow(text);
47
- export const red = (text: string): string => pc.red(text);
48
- export const blue = (text: string): string => pc.blue(text);
49
- export const gray = (text: string): string => pc.gray(text);
50
-
51
- // Gradient functions using gradient-string
52
- export function gradientTeen(text: string): string {
53
- const g = gradient('#00C9FF', '#92FE9D');
54
- return g(text);
55
- }
56
-
57
- export function gradientRainbow(text: string): string {
58
- return gradient.rainbow(text);
59
- }
60
-
61
- export function gradientCool(text: string): string {
62
- const g = gradient('#667eea', '#764ba2');
63
- return g(text);
64
- }
65
-
66
- export function gradientPassion(text: string): string {
67
- const g = gradient('#ee0979', '#ff6a00');
68
- return g(text);
69
- }
70
-
71
- // Section formatting
72
- export const header = (text: string): string => {
73
- return bold(pc.cyan(pc.bold(`\n${text}\n`)));
74
- };
75
-
76
- export const section = (text: string): string => {
77
- return bold(pc.white(text));
78
- };
79
-
80
- export const subsection = (text: string): string => {
81
- return pc.dim(text);
82
- };
83
-
84
- // Symbol functions for visual elements
85
- export const checkmark = (text?: string): string => {
86
- const symbol = pc.green('✓');
87
- return text ? `${symbol} ${text}` : symbol;
88
- };
89
-
90
- export const crossmark = (text?: string): string => {
91
- const symbol = pc.red('✗');
92
- return text ? `${symbol} ${text}` : symbol;
93
- };
94
-
95
- // Arrow and bullet functions
96
- export const bullet = (text: string): string => {
97
- return `${pc.gray('•')} ${text}`;
98
- };
99
-
100
- export const numbered = (num: number, text: string): string => {
101
- return `${pc.gray(`${num}.`)} ${text}`;
102
- };
103
-
104
- export const arrow = (text: string): string => {
105
- return `${pc.gray('→')} ${text}`;
106
- };
107
-
108
- export const rightArrow = (from: string, to: string): string => {
109
- return `${from} ${pc.gray('→')} ${to}`;
110
- };
111
-
112
- // Progress bar
113
- export function progressBar(current: number, total: number, width: number = 20): string {
114
- const percentage = Math.min(Math.max(current / total, 0), 1);
115
- const filled = Math.round(percentage * width);
116
- const empty = width - filled;
117
- const filledBar = pc.green('█'.repeat(filled));
118
- const emptyBar = pc.gray('░'.repeat(empty));
119
- const percentText = pc.cyan(`${Math.round(percentage * 100)}%`);
120
- return `${filledBar}${emptyBar} ${percentText}`;
121
- }
122
-
123
- // Separator line
124
- export function printSeparator(char: string = '─', length: number = 60): string {
125
- return pc.gray(char.repeat(length));
126
- }
127
-
128
- // Terminal control functions
129
- export function clearLine(): void {
130
- process.stdout.write('\r\x1B[K');
131
- }
132
-
133
- export function cursorHide(): void {
134
- process.stdout.write('\x1B[?25l');
135
- }
136
-
137
- export function cursorShow(): void {
138
- process.stdout.write('\x1B[?25h');
139
- }
package/src/ui/output.ts DELETED
@@ -1,230 +0,0 @@
1
- /**
2
- * Output formatting utilities
3
- */
4
-
5
- import pc from 'picocolors';
6
- import { style, bold, dim, muted, primary, success, error, warning, info, section, printSeparator } from './colors.js';
7
- import gradient from 'gradient-string';
8
-
9
- export interface Logger {
10
- log: (message: string, ...args: unknown[]) => void;
11
- info: (message: string, ...args: unknown[]) => void;
12
- success: (message: string, ...args: unknown[]) => void;
13
- warn: (message: string, ...args: unknown[]) => void;
14
- error: (message: string, ...args: unknown[]) => void;
15
- debug: (message: string, ...args: unknown[]) => void;
16
- verbose: (message: string, ...args: unknown[]) => void;
17
- }
18
-
19
- const logger: Logger = {
20
- log: (message: string, ...args: unknown[]) => {
21
- console.log(message, ...args);
22
- },
23
- info: (message: string, ...args: unknown[]) => {
24
- console.log(pc.blue('INFO: ') + message, ...args);
25
- },
26
- success: (message: string, ...args: unknown[]) => {
27
- console.log(pc.green('SUCCESS: ') + message, ...args);
28
- },
29
- warn: (message: string, ...args: unknown[]) => {
30
- console.log(pc.yellow('WARN: ') + message, ...args);
31
- },
32
- error: (message: string, ...args: unknown[]) => {
33
- console.error(pc.red('ERROR: ') + message, ...args);
34
- },
35
- debug: (message: string, ...args: unknown[]) => {
36
- if (process.env.DEBUG || process.env.VERBOSE) {
37
- console.log(pc.gray('DEBUG: ') + message, ...args);
38
- }
39
- },
40
- verbose: (message: string, ...args: unknown[]) => {
41
- if (process.env.VERBOSE) {
42
- console.log(pc.gray('VERBOSE: ') + message, ...args);
43
- }
44
- }
45
- };
46
-
47
- export { logger };
48
-
49
- /**
50
- * Creates a gradient from cyan to green (singleton pattern to prevent memory leak)
51
- */
52
- const teenGradient = gradient('#00C9FF', '#92FE9D');
53
-
54
- /**
55
- * Prints the welcome banner
56
- */
57
- export function printWelcome(): void {
58
- console.log('');
59
- console.log(pc.cyan(`
60
- ╔═══════════════════════════════════════════════════════════╗
61
- ║ ║
62
- ║ ██╗ ██╗ █████╗ ██████╗ ███████╗███╗ ██╗ ║
63
- ║ ██║ ██║██╔══██╗██╔══██╗ ██╔════╝████╗ ██║ ║
64
- ║ ██║ █╗ ██║███████║██████╔╝ █████╗ ██╔██╗ ██║ ║
65
- ║ ██║███╗██║██╔══██║██╔══██╗ ██╔══╝ ██║╚██╗██║ ║
66
- ║ ╚███╔███╔╝██║ ██║██║ ██║ ███████╗██║ ╚████║ ║
67
- ║ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ║
68
- ║ ║
69
- ║ Android Project Generator v1.0.0 ║
70
- ║ Modern Android Development CLI ║
71
- ║ ║
72
- ╚═══════════════════════════════════════════════════════════╝
73
- `));
74
- console.log('');
75
- }
76
-
77
- /**
78
- * Prints the goodbye message
79
- */
80
- export function printGoodbye(success: boolean = true): void {
81
- // Uses module-level teenGradient constant
82
- if (success) {
83
- console.log('');
84
- console.log(teenGradient(`
85
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
86
-
87
- Thanks for using andrud! Happy coding! 🚀
88
-
89
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
90
- `));
91
- } else {
92
- console.log('');
93
- console.log(pc.red(`
94
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
95
-
96
- Operation failed. Please check the error above.
97
-
98
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
99
- `));
100
- }
101
- }
102
-
103
- /**
104
- * Prints a success message
105
- */
106
- export function printSuccess(message: string, details?: string): void {
107
- console.log(pc.green(' ✓ ') + pc.white(message));
108
- if (details) {
109
- console.log(pc.gray(` ${details}`));
110
- }
111
- }
112
-
113
- /**
114
- * Prints an error message
115
- */
116
- export function printError(message: string, details?: string): void {
117
- console.error(pc.red(' ✗ ') + pc.white(message));
118
- if (details) {
119
- console.error(pc.gray(` ${details}`));
120
- }
121
- }
122
-
123
- /**
124
- * Prints a section header
125
- */
126
- export function printSection(text: string): void {
127
- console.log('');
128
- console.log(section(text));
129
- console.log(dim(printSeparator('─', 50)));
130
- }
131
-
132
- /**
133
- * Prints key-value pairs
134
- */
135
- export function printKeyValue(items: Array<{ key: string; value: string }>): void {
136
- const maxKeyLength = Math.max(...items.map(item => item.key.length));
137
- items.forEach(item => {
138
- const padding = ' '.repeat(maxKeyLength - item.key.length);
139
- console.log(` ${pc.cyan(item.key)}${padding} ${item.value}`);
140
- });
141
- }
142
-
143
- /**
144
- * Prints a separator line
145
- */
146
- export function printSeparatorLine(char: string = '─', length: number = 60): void {
147
- console.log(dim(char.repeat(length)));
148
- }
149
-
150
- /**
151
- * Prints a banner with text
152
- */
153
- export function printBanner(text: string, color: 'primary' | 'success' | 'warning' | 'error' = 'primary'): void {
154
- const padding = 4;
155
- const line = ' '.repeat(padding);
156
- const border = '━'.repeat(text.length + padding * 2);
157
-
158
- console.log('');
159
- console.log(pc.cyan(' ' + border));
160
- console.log(pc.cyan(' ║') + ' '.repeat(padding) + text + ' '.repeat(padding) + pc.cyan('║'));
161
- console.log(pc.cyan(' ' + border));
162
- console.log('');
163
- }
164
-
165
- /**
166
- * Prints an ASCII box with content
167
- */
168
- export function printAsciiBox(lines: string[], options: { border?: string; padding?: number } = {}): void {
169
- const border = options.border ?? '─';
170
- const padding = options.padding ?? 2;
171
- const maxLength = Math.max(...lines.map(l => l.length));
172
- const width = maxLength + padding * 2;
173
-
174
- console.log(pc.gray(' ┌' + border.repeat(width) + '┐'));
175
-
176
- if (lines.length === 0) {
177
- console.log(pc.gray(' │' + ' '.repeat(width) + '│'));
178
- } else {
179
- lines.forEach(line => {
180
- const padded = line + ' '.repeat(maxLength - line.length);
181
- console.log(pc.gray(' │') + ' '.repeat(padding) + padded + ' '.repeat(padding) + pc.gray('│'));
182
- });
183
- }
184
-
185
- console.log(pc.gray(' └' + border.repeat(width) + '┘'));
186
- }
187
-
188
- /**
189
- * Prints a table with columns
190
- */
191
- export function printTable<T>(
192
- columns: Array<{ header: string; accessor: (row: T) => string; width?: number }>,
193
- rows: T[]
194
- ): void {
195
- const colWidths = columns.map(col => {
196
- const headerWidth = col.header.length;
197
- const dataWidths = rows.map(row => col.accessor(row).length);
198
- return col.width ?? Math.max(headerWidth, ...dataWidths);
199
- });
200
-
201
- // Print header
202
- const headerRow = columns.map((_col, i) => {
203
- const width = colWidths[i] ?? 10;
204
- return _col.header.substring(0, width).padEnd(width);
205
- });
206
- console.log(bold(headerRow.join(' ')));
207
- console.log(pc.gray(colWidths.map(w => '─'.repeat(w)).join(' ')));
208
-
209
- // Print rows
210
- rows.forEach(row => {
211
- const dataRow = columns.map((col, i) => {
212
- const width = colWidths[i] ?? 10;
213
- const value = col.accessor(row);
214
- return value.substring(0, width).padEnd(width);
215
- });
216
- console.log(dataRow.join(' '));
217
- });
218
- }
219
-
220
- /**
221
- * Prints numbered steps
222
- */
223
- export function printSteps(steps: string[]): void {
224
- console.log('');
225
- steps.forEach((step, index) => {
226
- const num = pc.cyan(`${index + 1}.`);
227
- console.log(` ${num} ${step}`);
228
- });
229
- console.log('');
230
- }