andrud 1.0.1 → 1.0.3

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 +157 -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,345 +0,0 @@
1
- /**
2
- * Validation utilities for app names, package names, and paths
3
- */
4
-
5
- export interface ValidationResult {
6
- valid: boolean;
7
- errors: string[];
8
- warnings: string[];
9
- }
10
-
11
- export interface AppNameValidation extends ValidationResult {
12
- normalized?: string;
13
- }
14
-
15
- export interface PackageNameValidation extends ValidationResult {
16
- suggestions?: string[];
17
- }
18
-
19
- export interface DirectoryPathValidation extends ValidationResult {
20
- normalized?: string;
21
- }
22
-
23
- // Validate app name
24
- export function validateAppName(name: string): AppNameValidation {
25
- const errors: string[] = [];
26
- const warnings: string[] = [];
27
-
28
- if (!name || name.trim().length === 0) {
29
- errors.push('App name cannot be empty');
30
- return { valid: false, errors, warnings };
31
- }
32
-
33
- const trimmed = name.trim();
34
-
35
- // Check for invalid characters
36
- if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(trimmed)) {
37
- if (trimmed.includes('-')) {
38
- errors.push('App name cannot contain hyphens. Use underscores instead (e.g., My_Awesome_App)');
39
- } else if (trimmed.includes(' ')) {
40
- errors.push('App name cannot contain spaces. Use underscores instead (e.g., My_Awesome_App)');
41
- } else if (/^[0-9]/.test(trimmed)) {
42
- errors.push('App name must start with a letter');
43
- } else {
44
- errors.push('App name can only contain letters, numbers, and underscores');
45
- }
46
- return { valid: false, errors, warnings };
47
- }
48
-
49
- // Warnings for reserved words
50
- const reservedWords = ['android', 'app', 'application', 'com', 'org', 'net', 'io', 'java', 'kotlin'];
51
- if (reservedWords.includes(trimmed.toLowerCase())) {
52
- warnings.push(`"${trimmed}" is a common word. Consider a more unique app name.`);
53
- }
54
-
55
- // Check length
56
- if (trimmed.length < 3) {
57
- warnings.push('App name is very short. Consider using a more descriptive name.');
58
- }
59
- if (trimmed.length > 50) {
60
- errors.push('App name cannot exceed 50 characters');
61
- return { valid: false, errors, warnings };
62
- }
63
-
64
- // Normalize (capitalize first letter)
65
- const normalized = trimmed.charAt(0).toUpperCase() + trimmed.slice(1);
66
-
67
- return { valid: true, errors, warnings, normalized };
68
- }
69
-
70
- // Validate package name input
71
- export function validatePackageNameInput(name: string): PackageNameValidation {
72
- const errors: string[] = [];
73
- const warnings: string[] = [];
74
- const suggestions: string[] = [];
75
-
76
- if (!name || name.trim().length === 0) {
77
- errors.push('Package name cannot be empty');
78
- return { valid: false, errors, warnings, suggestions };
79
- }
80
-
81
- const trimmed = name.trim().toLowerCase();
82
-
83
- // Check basic format
84
- if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(trimmed)) {
85
- errors.push('Package name must follow domain structure (e.g., com.example.myapp)');
86
- errors.push('Each segment must start with a letter and contain only lowercase letters, numbers, and underscores');
87
-
88
- // Generate suggestions
89
- if (!trimmed.startsWith('com.') && !trimmed.startsWith('org.') && !trimmed.startsWith('io.') && !trimmed.startsWith('net.')) {
90
- suggestions.push('com.' + trimmed);
91
- }
92
- if (trimmed.split('.').length < 2) {
93
- suggestions.push(trimmed + '.app');
94
- suggestions.push(trimmed + '.myapp');
95
- }
96
-
97
- return { valid: false, errors, warnings, suggestions };
98
- }
99
-
100
- // Minimum 2 segments
101
- const segments = trimmed.split('.');
102
- if (segments.length < 2) {
103
- errors.push('Package name must have at least 2 segments (e.g., com.app)');
104
- return { valid: false, errors, warnings, suggestions };
105
- }
106
-
107
- // Maximum segment length
108
- for (const segment of segments) {
109
- if (segment.length < 1) {
110
- errors.push('Package segments cannot be empty');
111
- return { valid: false, errors, warnings, suggestions };
112
- }
113
- if (segment.length > 50) {
114
- errors.push(`Package segment "${segment}" exceeds 50 character limit`);
115
- return { valid: false, errors, warnings, suggestions };
116
- }
117
- }
118
-
119
- // Check for reserved prefixes
120
- const reservedPrefixes = ['java', 'android', 'kotlin', 'javax', 'androidx', 'com.android'];
121
- if (reservedPrefixes.some(p => trimmed.startsWith(p + '.'))) {
122
- const prefix = reservedPrefixes.find(p => trimmed.startsWith(p + '.'));
123
- errors.push(`Package name cannot start with reserved prefix: ${prefix}`);
124
- return { valid: false, errors, warnings, suggestions };
125
- }
126
-
127
- // Warnings
128
- if (segments[0] === 'com' && (segments[1] === 'example' || segments[1] === 'test' || segments[1] === 'app')) {
129
- warnings.push('Using generic "com.example" prefix. Consider using your own domain.');
130
- }
131
-
132
- return { valid: true, errors, warnings };
133
- }
134
-
135
- // Validate package structure (similar to input but for verification)
136
- export function validatePackageStructure(name: string): ValidationResult {
137
- return validatePackageNameInput(name);
138
- }
139
-
140
- // Validate directory path
141
- export function validateDirectoryPath(path: string): DirectoryPathValidation {
142
- const errors: string[] = [];
143
- const warnings: string[] = [];
144
-
145
- if (!path || path.trim().length === 0) {
146
- errors.push('Directory path cannot be empty');
147
- return { valid: false, errors, warnings };
148
- }
149
-
150
- const trimmed = path.trim();
151
-
152
- // Check for directory traversal
153
- if (trimmed.includes('..')) {
154
- errors.push('Directory path cannot contain ".." to prevent directory traversal');
155
- return { valid: false, errors, warnings };
156
- }
157
-
158
- // Allow normal path characters including Windows backslashes
159
- // Just check for truly invalid characters
160
- if (/[<>:"|?*]/.test(trimmed)) {
161
- errors.push('Directory path contains invalid characters');
162
- return { valid: false, errors, warnings };
163
- }
164
-
165
- // Check for absolute path
166
- const isAbsolutePath = /^[A-Za-z]:\\|\//.test(trimmed) || trimmed.startsWith('/');
167
-
168
- // Warn about potential issues
169
- if (trimmed.includes(' ')) {
170
- warnings.push('Path contains spaces. This may cause issues with some build tools.');
171
- }
172
-
173
- if (isAbsolutePath && (trimmed.includes('$') || trimmed.includes('`'))) {
174
- warnings.push('Path contains special characters that may be interpreted as variables.');
175
- }
176
-
177
- return { valid: true, errors, warnings, normalized: trimmed };
178
- }
179
-
180
- // Validate email
181
- export function validateEmail(email: string): ValidationResult {
182
- const errors: string[] = [];
183
- const warnings: string[] = [];
184
-
185
- if (!email || email.trim().length === 0) {
186
- errors.push('Email cannot be empty');
187
- return { valid: false, errors, warnings };
188
- }
189
-
190
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
191
- if (!emailRegex.test(email.trim())) {
192
- errors.push('Invalid email format');
193
- return { valid: false, errors, warnings };
194
- }
195
-
196
- return { valid: true, errors, warnings };
197
- }
198
-
199
- // Validate URL
200
- export function validateUrl(url: string): ValidationResult {
201
- const errors: string[] = [];
202
- const warnings: string[] = [];
203
-
204
- if (!url || url.trim().length === 0) {
205
- errors.push('URL cannot be empty');
206
- return { valid: false, errors, warnings };
207
- }
208
-
209
- try {
210
- new URL(url);
211
- } catch {
212
- errors.push('Invalid URL format');
213
- return { valid: false, errors, warnings };
214
- }
215
-
216
- return { valid: true, errors, warnings };
217
- }
218
-
219
- // Validate version string
220
- export function validateVersion(version: string): ValidationResult {
221
- const errors: string[] = [];
222
- const warnings: string[] = [];
223
-
224
- if (!version || version.trim().length === 0) {
225
- errors.push('Version cannot be empty');
226
- return { valid: false, errors, warnings };
227
- }
228
-
229
- // Semantic versioning format
230
- const versionRegex = /^\d+\.\d+(\.\d+)?(-[a-zA-Z0-9.-]+)?$/;
231
- if (!versionRegex.test(version.trim())) {
232
- errors.push('Version must follow semantic versioning (e.g., 1.0.0 or 1.0.0-beta)');
233
- return { valid: false, errors, warnings };
234
- }
235
-
236
- return { valid: true, errors, warnings };
237
- }
238
-
239
- // Validate Android min SDK
240
- export function validateAndroidMinSdk(sdk: number | string): ValidationResult {
241
- const errors: string[] = [];
242
- const warnings: string[] = [];
243
-
244
- const sdkNum = typeof sdk === 'string' ? parseInt(sdk, 10) : sdk;
245
-
246
- if (isNaN(sdkNum)) {
247
- errors.push('Min SDK must be a number');
248
- return { valid: false, errors, warnings };
249
- }
250
-
251
- if (sdkNum < 16) {
252
- errors.push('Min SDK must be at least 16 (Android 4.1)');
253
- return { valid: false, errors, warnings };
254
- }
255
-
256
- if (sdkNum > 35) {
257
- warnings.push('Min SDK is very high. This excludes older devices.');
258
- }
259
-
260
- return { valid: true, errors, warnings };
261
- }
262
-
263
- // Validate Android target SDK
264
- export function validateAndroidTargetSdk(sdk: number | string): ValidationResult {
265
- const errors: string[] = [];
266
- const warnings: string[] = [];
267
-
268
- const sdkNum = typeof sdk === 'string' ? parseInt(sdk, 10) : sdk;
269
-
270
- if (isNaN(sdkNum)) {
271
- errors.push('Target SDK must be a number');
272
- return { valid: false, errors, warnings };
273
- }
274
-
275
- if (sdkNum < 21) {
276
- errors.push('Target SDK must be at least 21');
277
- return { valid: false, errors, warnings };
278
- }
279
-
280
- if (sdkNum > 35) {
281
- warnings.push('Target SDK exceeds latest stable (35). This might require unstable dependencies.');
282
- }
283
-
284
- return { valid: true, errors, warnings };
285
- }
286
-
287
- // Sanitize file name
288
- export function sanitizeFileName(name: string): string {
289
- return name
290
- .replace(/[<>:"/\\|?*]/g, '_')
291
- .replace(/\s+/g, '_')
292
- .replace(/_{2,}/g, '_')
293
- .trim();
294
- }
295
-
296
- // Sanitize package name
297
- export function sanitizePackageName(name: string): string {
298
- return name
299
- .toLowerCase()
300
- .replace(/[^a-z0-9.]/g, '_')
301
- .replace(/_{2,}/g, '.')
302
- .replace(/^\.|\.$/g, '')
303
- .trim();
304
- }
305
-
306
- // String transformation utilities
307
- export function capitalizeFirstLetter(str: string): string {
308
- if (!str) return '';
309
- return str.charAt(0).toUpperCase() + str.slice(1);
310
- }
311
-
312
- export function camelCase(str: string): string {
313
- return str
314
- .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) =>
315
- index === 0 ? word.toLowerCase() : word.toUpperCase()
316
- )
317
- .replace(/\s+|_+/g, '');
318
- }
319
-
320
- export function pascalCase(str: string): string {
321
- return str
322
- .replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => word.toUpperCase())
323
- .replace(/\s+|_+/g, '');
324
- }
325
-
326
- export function kebabCase(str: string): string {
327
- return str
328
- .replace(/([a-z])([A-Z])/g, '$1-$2')
329
- .replace(/\s+|_+/g, '-')
330
- .toLowerCase();
331
- }
332
-
333
- export function snakeCase(str: string): string {
334
- return str
335
- .replace(/([a-z])([A-Z])/g, '$1_$2')
336
- .replace(/\s+|-+/g, '_')
337
- .toLowerCase();
338
- }
339
-
340
- export function dotCase(str: string): string {
341
- return str
342
- .replace(/([a-z])([A-Z])/g, '$1.$2')
343
- .replace(/\s+|-+|_+/g, '.')
344
- .toLowerCase();
345
- }
package/tsconfig.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022"],
7
- "declaration": true,
8
- "declarationMap": true,
9
- "sourceMap": true,
10
- "outDir": "./dist",
11
- "rootDir": "./src",
12
- "strict": true,
13
- "esModuleInterop": true,
14
- "skipLibCheck": true,
15
- "forceConsistentCasingInFileNames": true,
16
- "resolveJsonModule": true,
17
- "allowSyntheticDefaultImports": true,
18
- "noImplicitReturns": true,
19
- "noFallthroughCasesInSwitch": true,
20
- "noImplicitOverride": true,
21
- "noUncheckedIndexedAccess": true
22
- },
23
- "include": ["src/**/*"],
24
- "exclude": ["node_modules", "dist"]
25
- }