@vue-skuilder/cli 0.1.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.
- package/README.md +163 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +70 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +35 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/prompts.d.ts +5 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +185 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/template.d.ts +26 -0
- package/dist/utils/template.d.ts.map +1 -0
- package/dist/utils/template.js +170 -0
- package/dist/utils/template.js.map +1 -0
- package/eslint.config.mjs +21 -0
- package/package.json +52 -0
- package/src/cli.ts +42 -0
- package/src/commands/init.ts +83 -0
- package/src/types.ts +72 -0
- package/src/utils/prompts.ts +204 -0
- package/src/utils/template.ts +215 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { ProjectConfig, SkuilderConfig } from '../types.js';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Find the standalone-ui package in node_modules
|
|
13
|
+
*/
|
|
14
|
+
export async function findStandaloneUiPath(): Promise<string> {
|
|
15
|
+
// Start from CLI package root and work upward
|
|
16
|
+
let currentDir = path.join(__dirname, '..', '..');
|
|
17
|
+
|
|
18
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
19
|
+
const nodeModulesPath = path.join(currentDir, 'node_modules', '@vue-skuilder', 'standalone-ui');
|
|
20
|
+
if (existsSync(nodeModulesPath)) {
|
|
21
|
+
return nodeModulesPath;
|
|
22
|
+
}
|
|
23
|
+
currentDir = path.dirname(currentDir);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
throw new Error('Could not find @vue-skuilder/standalone-ui package. Please ensure it is installed.');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Copy directory recursively, excluding certain files/directories
|
|
31
|
+
*/
|
|
32
|
+
export async function copyDirectory(
|
|
33
|
+
source: string,
|
|
34
|
+
destination: string,
|
|
35
|
+
excludePatterns: string[] = ['node_modules', 'dist', '.git', 'cypress']
|
|
36
|
+
): Promise<void> {
|
|
37
|
+
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
38
|
+
|
|
39
|
+
await fs.mkdir(destination, { recursive: true });
|
|
40
|
+
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const sourcePath = path.join(source, entry.name);
|
|
43
|
+
const destPath = path.join(destination, entry.name);
|
|
44
|
+
|
|
45
|
+
// Skip excluded patterns
|
|
46
|
+
if (excludePatterns.some(pattern => entry.name.includes(pattern))) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (entry.isDirectory()) {
|
|
51
|
+
await copyDirectory(sourcePath, destPath, excludePatterns);
|
|
52
|
+
} else {
|
|
53
|
+
await fs.copyFile(sourcePath, destPath);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Transform package.json to use published dependencies instead of workspace references
|
|
60
|
+
*/
|
|
61
|
+
export async function transformPackageJson(
|
|
62
|
+
packageJsonPath: string,
|
|
63
|
+
projectName: string,
|
|
64
|
+
cliVersion: string
|
|
65
|
+
): Promise<void> {
|
|
66
|
+
const content = await fs.readFile(packageJsonPath, 'utf-8');
|
|
67
|
+
const packageJson = JSON.parse(content);
|
|
68
|
+
|
|
69
|
+
// Update basic project info
|
|
70
|
+
packageJson.name = projectName;
|
|
71
|
+
packageJson.description = `Skuilder course application: ${projectName}`;
|
|
72
|
+
packageJson.version = '1.0.0';
|
|
73
|
+
|
|
74
|
+
// Transform workspace dependencies to published versions
|
|
75
|
+
if (packageJson.dependencies) {
|
|
76
|
+
for (const [depName, version] of Object.entries(packageJson.dependencies)) {
|
|
77
|
+
if (typeof version === 'string' && version.startsWith('workspace:')) {
|
|
78
|
+
// Replace workspace references with CLI's version
|
|
79
|
+
packageJson.dependencies[depName] = `^${cliVersion}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Remove CLI-specific fields that don't belong in generated projects
|
|
85
|
+
delete packageJson.publishConfig;
|
|
86
|
+
|
|
87
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Generate skuilder.config.json based on project configuration
|
|
92
|
+
*/
|
|
93
|
+
export async function generateSkuilderConfig(
|
|
94
|
+
configPath: string,
|
|
95
|
+
config: ProjectConfig
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
const skuilderConfig: SkuilderConfig = {
|
|
98
|
+
title: config.title,
|
|
99
|
+
dataLayerType: config.dataLayerType
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (config.course) {
|
|
103
|
+
skuilderConfig.course = config.course;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (config.couchdbUrl) {
|
|
107
|
+
skuilderConfig.couchdbUrl = config.couchdbUrl;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (config.theme) {
|
|
111
|
+
skuilderConfig.theme = config.theme;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await fs.writeFile(configPath, JSON.stringify(skuilderConfig, null, 2));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Generate project README.md
|
|
119
|
+
*/
|
|
120
|
+
export async function generateReadme(
|
|
121
|
+
readmePath: string,
|
|
122
|
+
config: ProjectConfig
|
|
123
|
+
): Promise<void> {
|
|
124
|
+
const dataLayerInfo = config.dataLayerType === 'static'
|
|
125
|
+
? 'This project uses a static data layer with JSON files.'
|
|
126
|
+
: `This project connects to CouchDB at: ${config.couchdbUrl || '[URL not specified]'}`;
|
|
127
|
+
|
|
128
|
+
const readme = `# ${config.title}
|
|
129
|
+
|
|
130
|
+
A Skuilder course application built with Vue 3, Vuetify, and Pinia.
|
|
131
|
+
|
|
132
|
+
## Data Layer
|
|
133
|
+
|
|
134
|
+
${dataLayerInfo}
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
Install dependencies:
|
|
139
|
+
\`\`\`bash
|
|
140
|
+
npm install
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
Start the development server:
|
|
144
|
+
\`\`\`bash
|
|
145
|
+
npm run dev
|
|
146
|
+
\`\`\`
|
|
147
|
+
|
|
148
|
+
Build for production:
|
|
149
|
+
\`\`\`bash
|
|
150
|
+
npm run build
|
|
151
|
+
\`\`\`
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
Course configuration is managed in \`skuilder.config.json\`. You can modify:
|
|
156
|
+
- Course title
|
|
157
|
+
- Data layer settings
|
|
158
|
+
- Theme customization
|
|
159
|
+
- Database connection details (for dynamic data layer)
|
|
160
|
+
|
|
161
|
+
## Theme
|
|
162
|
+
|
|
163
|
+
Current theme: **${config.theme.name}**
|
|
164
|
+
- Primary: ${config.theme.colors.primary}
|
|
165
|
+
- Secondary: ${config.theme.colors.secondary}
|
|
166
|
+
- Accent: ${config.theme.colors.accent}
|
|
167
|
+
|
|
168
|
+
## Testing
|
|
169
|
+
|
|
170
|
+
Run end-to-end tests:
|
|
171
|
+
\`\`\`bash
|
|
172
|
+
npm run test:e2e
|
|
173
|
+
\`\`\`
|
|
174
|
+
|
|
175
|
+
Run tests in headless mode:
|
|
176
|
+
\`\`\`bash
|
|
177
|
+
npm run test:e2e:headless
|
|
178
|
+
\`\`\`
|
|
179
|
+
|
|
180
|
+
## Learn More
|
|
181
|
+
|
|
182
|
+
Visit the [Skuilder documentation](https://github.com/NiloCK/vue-skuilder) for more information about building course applications.
|
|
183
|
+
`;
|
|
184
|
+
|
|
185
|
+
await fs.writeFile(readmePath, readme);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Copy and transform the standalone-ui template to create a new project
|
|
190
|
+
*/
|
|
191
|
+
export async function processTemplate(
|
|
192
|
+
projectPath: string,
|
|
193
|
+
config: ProjectConfig,
|
|
194
|
+
cliVersion: string
|
|
195
|
+
): Promise<void> {
|
|
196
|
+
console.log(chalk.blue('📦 Locating standalone-ui template...'));
|
|
197
|
+
const templatePath = await findStandaloneUiPath();
|
|
198
|
+
|
|
199
|
+
console.log(chalk.blue('📂 Copying project files...'));
|
|
200
|
+
await copyDirectory(templatePath, projectPath);
|
|
201
|
+
|
|
202
|
+
console.log(chalk.blue('⚙️ Configuring package.json...'));
|
|
203
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
204
|
+
await transformPackageJson(packageJsonPath, config.projectName, cliVersion);
|
|
205
|
+
|
|
206
|
+
console.log(chalk.blue('🔧 Generating configuration...'));
|
|
207
|
+
const configPath = path.join(projectPath, 'skuilder.config.json');
|
|
208
|
+
await generateSkuilderConfig(configPath, config);
|
|
209
|
+
|
|
210
|
+
console.log(chalk.blue('📝 Creating README...'));
|
|
211
|
+
const readmePath = path.join(projectPath, 'README.md');
|
|
212
|
+
await generateReadme(readmePath, config);
|
|
213
|
+
|
|
214
|
+
console.log(chalk.green('✅ Template processing complete!'));
|
|
215
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"resolveJsonModule": true,
|
|
9
|
+
"allowImportingTsExtensions": false
|
|
10
|
+
},
|
|
11
|
+
"include": [
|
|
12
|
+
"src/**/*"
|
|
13
|
+
],
|
|
14
|
+
"exclude": [
|
|
15
|
+
"node_modules",
|
|
16
|
+
"dist"
|
|
17
|
+
]
|
|
18
|
+
}
|