@vue-skuilder/cli 0.1.4 → 0.1.6
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/CLAUDE.md +84 -0
- package/dist/cli.js +7 -11
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +87 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pack.d.ts +3 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +141 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/types.d.ts +29 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +192 -16
- package/dist/types.js.map +1 -1
- package/dist/utils/pack-courses.d.ts +13 -0
- package/dist/utils/pack-courses.d.ts.map +1 -0
- package/dist/utils/pack-courses.js +54 -0
- package/dist/utils/pack-courses.js.map +1 -0
- package/dist/utils/prompts.d.ts +5 -2
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +272 -72
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/template.d.ts +4 -0
- package/dist/utils/template.d.ts.map +1 -1
- package/dist/utils/template.js +93 -11
- package/dist/utils/template.js.map +1 -1
- package/package.json +5 -3
- package/src/cli.ts +8 -12
- package/src/commands/init.ts +128 -22
- package/src/commands/pack.ts +186 -0
- package/src/types.ts +230 -18
- package/src/utils/pack-courses.ts +77 -0
- package/src/utils/prompts.ts +321 -81
- package/src/utils/template.ts +129 -41
package/src/utils/template.ts
CHANGED
|
@@ -13,7 +13,7 @@ const __dirname = path.dirname(__filename);
|
|
|
13
13
|
export async function findStandaloneUiPath(): Promise<string> {
|
|
14
14
|
// Start from CLI package root and work upward
|
|
15
15
|
let currentDir = path.join(__dirname, '..', '..');
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
while (currentDir !== path.dirname(currentDir)) {
|
|
18
18
|
const nodeModulesPath = path.join(currentDir, 'node_modules', '@vue-skuilder', 'standalone-ui');
|
|
19
19
|
if (existsSync(nodeModulesPath)) {
|
|
@@ -21,8 +21,10 @@ export async function findStandaloneUiPath(): Promise<string> {
|
|
|
21
21
|
}
|
|
22
22
|
currentDir = path.dirname(currentDir);
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
throw new Error(
|
|
24
|
+
|
|
25
|
+
throw new Error(
|
|
26
|
+
'Could not find @vue-skuilder/standalone-ui package. Please ensure it is installed.'
|
|
27
|
+
);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -34,18 +36,18 @@ export async function copyDirectory(
|
|
|
34
36
|
excludePatterns: string[] = ['node_modules', 'dist', '.git', 'cypress']
|
|
35
37
|
): Promise<void> {
|
|
36
38
|
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
37
|
-
|
|
39
|
+
|
|
38
40
|
await fs.mkdir(destination, { recursive: true });
|
|
39
|
-
|
|
41
|
+
|
|
40
42
|
for (const entry of entries) {
|
|
41
43
|
const sourcePath = path.join(source, entry.name);
|
|
42
44
|
const destPath = path.join(destination, entry.name);
|
|
43
|
-
|
|
45
|
+
|
|
44
46
|
// Skip excluded patterns
|
|
45
|
-
if (excludePatterns.some(pattern => entry.name.includes(pattern))) {
|
|
47
|
+
if (excludePatterns.some((pattern) => entry.name.includes(pattern))) {
|
|
46
48
|
continue;
|
|
47
49
|
}
|
|
48
|
-
|
|
50
|
+
|
|
49
51
|
if (entry.isDirectory()) {
|
|
50
52
|
await copyDirectory(sourcePath, destPath, excludePatterns);
|
|
51
53
|
} else {
|
|
@@ -64,12 +66,12 @@ export async function transformPackageJson(
|
|
|
64
66
|
): Promise<void> {
|
|
65
67
|
const content = await fs.readFile(packageJsonPath, 'utf-8');
|
|
66
68
|
const packageJson = JSON.parse(content);
|
|
67
|
-
|
|
69
|
+
|
|
68
70
|
// Update basic project info
|
|
69
71
|
packageJson.name = projectName;
|
|
70
72
|
packageJson.description = `Skuilder course application: ${projectName}`;
|
|
71
73
|
packageJson.version = '1.0.0';
|
|
72
|
-
|
|
74
|
+
|
|
73
75
|
// Transform workspace dependencies to published versions
|
|
74
76
|
if (packageJson.dependencies) {
|
|
75
77
|
for (const [depName, version] of Object.entries(packageJson.dependencies)) {
|
|
@@ -79,21 +81,21 @@ export async function transformPackageJson(
|
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
|
-
|
|
84
|
+
|
|
83
85
|
// Add missing terser devDependency for build minification
|
|
84
86
|
if (packageJson.devDependencies && !packageJson.devDependencies['terser']) {
|
|
85
87
|
packageJson.devDependencies['terser'] = '^5.39.0';
|
|
86
88
|
}
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
// Remove CLI-specific fields that don't belong in generated projects
|
|
89
91
|
delete packageJson.publishConfig;
|
|
90
|
-
|
|
92
|
+
|
|
91
93
|
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
/**
|
|
95
97
|
* Create a vite.config.ts to work with published packages instead of workspace sources
|
|
96
|
-
*
|
|
98
|
+
*
|
|
97
99
|
* // [ ] This should be revised so that it works from the existing vite.config.ts in standalone-ui. As is, it recreates 95% of the same config.
|
|
98
100
|
*/
|
|
99
101
|
export async function createViteConfig(viteConfigPath: string): Promise<void> {
|
|
@@ -109,7 +111,7 @@ export default defineConfig({
|
|
|
109
111
|
alias: {
|
|
110
112
|
// Alias for internal src paths
|
|
111
113
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
112
|
-
|
|
114
|
+
|
|
113
115
|
// Add events alias if needed (often required by dependencies)
|
|
114
116
|
events: 'events',
|
|
115
117
|
},
|
|
@@ -156,7 +158,7 @@ export default defineConfig({
|
|
|
156
158
|
},
|
|
157
159
|
});
|
|
158
160
|
`;
|
|
159
|
-
|
|
161
|
+
|
|
160
162
|
await fs.writeFile(viteConfigPath, transformedContent);
|
|
161
163
|
}
|
|
162
164
|
|
|
@@ -169,24 +171,66 @@ export async function generateSkuilderConfig(
|
|
|
169
171
|
): Promise<void> {
|
|
170
172
|
const skuilderConfig: SkuilderConfig = {
|
|
171
173
|
title: config.title,
|
|
172
|
-
dataLayerType: config.dataLayerType
|
|
174
|
+
dataLayerType: config.dataLayerType,
|
|
173
175
|
};
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
|
|
177
|
+
// For dynamic data layer, use the specified course ID
|
|
178
|
+
if (config.dataLayerType === 'couch' && config.course) {
|
|
176
179
|
skuilderConfig.course = config.course;
|
|
177
180
|
}
|
|
178
|
-
|
|
181
|
+
|
|
182
|
+
// For static data layer with imported courses, use the first course as primary
|
|
183
|
+
if (config.dataLayerType === 'static' && config.importCourseIds && config.importCourseIds.length > 0) {
|
|
184
|
+
skuilderConfig.course = config.importCourseIds[0];
|
|
185
|
+
}
|
|
186
|
+
|
|
179
187
|
if (config.couchdbUrl) {
|
|
180
188
|
skuilderConfig.couchdbUrl = config.couchdbUrl;
|
|
181
189
|
}
|
|
182
|
-
|
|
190
|
+
|
|
183
191
|
if (config.theme) {
|
|
184
192
|
skuilderConfig.theme = config.theme;
|
|
185
193
|
}
|
|
186
|
-
|
|
194
|
+
|
|
187
195
|
await fs.writeFile(configPath, JSON.stringify(skuilderConfig, null, 2));
|
|
188
196
|
}
|
|
189
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Transform tsconfig.json to be standalone (remove base config reference)
|
|
200
|
+
*/
|
|
201
|
+
export async function transformTsConfig(tsconfigPath: string): Promise<void> {
|
|
202
|
+
const content = await fs.readFile(tsconfigPath, 'utf-8');
|
|
203
|
+
const tsconfig = JSON.parse(content);
|
|
204
|
+
|
|
205
|
+
// Remove the extends reference to the monorepo base config
|
|
206
|
+
delete tsconfig.extends;
|
|
207
|
+
|
|
208
|
+
// Merge in the essential settings from the base config that scaffolded apps need
|
|
209
|
+
tsconfig.compilerOptions = {
|
|
210
|
+
...tsconfig.compilerOptions,
|
|
211
|
+
// Essential TypeScript settings from base config
|
|
212
|
+
strict: true,
|
|
213
|
+
skipLibCheck: true,
|
|
214
|
+
forceConsistentCasingInFileNames: true,
|
|
215
|
+
esModuleInterop: true,
|
|
216
|
+
allowSyntheticDefaultImports: true,
|
|
217
|
+
// Keep existing Vue/Vite-specific settings
|
|
218
|
+
target: tsconfig.compilerOptions.target || 'ESNext',
|
|
219
|
+
useDefineForClassFields: tsconfig.compilerOptions.useDefineForClassFields,
|
|
220
|
+
module: tsconfig.compilerOptions.module || 'ESNext',
|
|
221
|
+
moduleResolution: tsconfig.compilerOptions.moduleResolution || 'bundler',
|
|
222
|
+
jsx: tsconfig.compilerOptions.jsx || 'preserve',
|
|
223
|
+
resolveJsonModule: tsconfig.compilerOptions.resolveJsonModule,
|
|
224
|
+
isolatedModules: tsconfig.compilerOptions.isolatedModules,
|
|
225
|
+
lib: tsconfig.compilerOptions.lib || ['ESNext', 'DOM'],
|
|
226
|
+
noEmit: tsconfig.compilerOptions.noEmit,
|
|
227
|
+
baseUrl: tsconfig.compilerOptions.baseUrl || '.',
|
|
228
|
+
types: tsconfig.compilerOptions.types || ['vite/client'],
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await fs.writeFile(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
232
|
+
}
|
|
233
|
+
|
|
190
234
|
/**
|
|
191
235
|
* Generate .gitignore file for the project
|
|
192
236
|
*/
|
|
@@ -313,14 +357,20 @@ Thumbs.db
|
|
|
313
357
|
/**
|
|
314
358
|
* Generate project README.md
|
|
315
359
|
*/
|
|
316
|
-
export async function generateReadme(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
)
|
|
320
|
-
|
|
321
|
-
? 'This project uses a static data layer with JSON files.'
|
|
322
|
-
: `This project connects to CouchDB at: ${config.couchdbUrl || '[URL not specified]'}`;
|
|
360
|
+
export async function generateReadme(readmePath: string, config: ProjectConfig): Promise<void> {
|
|
361
|
+
let dataLayerInfo = '';
|
|
362
|
+
|
|
363
|
+
if (config.dataLayerType === 'static') {
|
|
364
|
+
dataLayerInfo = 'This project uses a static data layer with JSON files.';
|
|
323
365
|
|
|
366
|
+
if (config.importCourseIds && config.importCourseIds.length > 0) {
|
|
367
|
+
const courseList = config.importCourseIds.map(id => `- ${id}`).join('\n');
|
|
368
|
+
dataLayerInfo += `\n\n**Imported Courses:**\n${courseList}\n\nCourse data is stored in \`public/static-courses/\` and loaded automatically.`;
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
dataLayerInfo = `This project connects to CouchDB at: ${config.couchdbUrl || '[URL not specified]'}`;
|
|
372
|
+
}
|
|
373
|
+
|
|
324
374
|
const readme = `# ${config.title}
|
|
325
375
|
|
|
326
376
|
A Skuilder course application built with Vue 3, Vuetify, and Pinia.
|
|
@@ -356,10 +406,42 @@ Course configuration is managed in \`skuilder.config.json\`. You can modify:
|
|
|
356
406
|
|
|
357
407
|
## Theme
|
|
358
408
|
|
|
359
|
-
Current theme: **${config.theme.name}**
|
|
360
|
-
- Primary: ${config.theme.colors.primary}
|
|
361
|
-
- Secondary: ${config.theme.colors.secondary}
|
|
362
|
-
- Accent: ${config.theme.colors.accent}
|
|
409
|
+
Current theme: **${config.theme.name}** (${config.theme.defaultMode} mode)
|
|
410
|
+
- Primary: ${config.theme.light.colors.primary}
|
|
411
|
+
- Secondary: ${config.theme.light.colors.secondary}
|
|
412
|
+
- Accent: ${config.theme.light.colors.accent}
|
|
413
|
+
|
|
414
|
+
This theme includes both light and dark variants. The application will use the ${config.theme.defaultMode} theme by default, but users can toggle between light and dark modes in their settings.
|
|
415
|
+
|
|
416
|
+
### Theme Customization
|
|
417
|
+
|
|
418
|
+
To customize the theme colors, edit the \`theme\` section in \`skuilder.config.json\`:
|
|
419
|
+
|
|
420
|
+
\`\`\`json
|
|
421
|
+
{
|
|
422
|
+
"theme": {
|
|
423
|
+
"name": "custom",
|
|
424
|
+
"defaultMode": "light",
|
|
425
|
+
"light": {
|
|
426
|
+
"dark": false,
|
|
427
|
+
"colors": {
|
|
428
|
+
"primary": "#your-color",
|
|
429
|
+
"secondary": "#your-color",
|
|
430
|
+
"accent": "#your-color"
|
|
431
|
+
// ... other semantic colors
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
"dark": {
|
|
435
|
+
"dark": true,
|
|
436
|
+
"colors": {
|
|
437
|
+
// ... dark variant colors
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
\`\`\`
|
|
443
|
+
|
|
444
|
+
The theme system supports all Vuetify semantic colors including error, success, warning, info, background, surface, and text colors. Changes to the configuration file are applied automatically on restart.
|
|
363
445
|
|
|
364
446
|
## Testing
|
|
365
447
|
|
|
@@ -391,31 +473,37 @@ export async function processTemplate(
|
|
|
391
473
|
): Promise<void> {
|
|
392
474
|
console.log(chalk.blue('📦 Locating standalone-ui template...'));
|
|
393
475
|
const templatePath = await findStandaloneUiPath();
|
|
394
|
-
|
|
476
|
+
|
|
395
477
|
console.log(chalk.blue('📂 Copying project files...'));
|
|
396
478
|
await copyDirectory(templatePath, projectPath);
|
|
397
|
-
|
|
479
|
+
|
|
398
480
|
console.log(chalk.blue('⚙️ Configuring package.json...'));
|
|
399
481
|
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
400
482
|
await transformPackageJson(packageJsonPath, config.projectName, cliVersion);
|
|
401
|
-
|
|
483
|
+
|
|
402
484
|
console.log(chalk.blue('🔧 Creating vite.config.ts...'));
|
|
403
485
|
const viteConfigPath = path.join(projectPath, 'vite.config.ts');
|
|
404
486
|
if (existsSync(viteConfigPath)) {
|
|
405
487
|
await createViteConfig(viteConfigPath);
|
|
406
488
|
}
|
|
407
|
-
|
|
489
|
+
|
|
490
|
+
console.log(chalk.blue('🔧 Transforming tsconfig.json...'));
|
|
491
|
+
const tsconfigPath = path.join(projectPath, 'tsconfig.json');
|
|
492
|
+
if (existsSync(tsconfigPath)) {
|
|
493
|
+
await transformTsConfig(tsconfigPath);
|
|
494
|
+
}
|
|
495
|
+
|
|
408
496
|
console.log(chalk.blue('🔧 Generating configuration...'));
|
|
409
497
|
const configPath = path.join(projectPath, 'skuilder.config.json');
|
|
410
498
|
await generateSkuilderConfig(configPath, config);
|
|
411
|
-
|
|
499
|
+
|
|
412
500
|
console.log(chalk.blue('📝 Creating README...'));
|
|
413
501
|
const readmePath = path.join(projectPath, 'README.md');
|
|
414
502
|
await generateReadme(readmePath, config);
|
|
415
|
-
|
|
503
|
+
|
|
416
504
|
console.log(chalk.blue('📄 Generating .gitignore...'));
|
|
417
505
|
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
418
506
|
await generateGitignore(gitignorePath);
|
|
419
|
-
|
|
507
|
+
|
|
420
508
|
console.log(chalk.green('✅ Template processing complete!'));
|
|
421
|
-
}
|
|
509
|
+
}
|