skuilder 0.1.2 → 0.1.4

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 (90) hide show
  1. package/README.md +162 -2
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +35 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +70 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/types.d.ts +35 -0
  11. package/dist/types.d.ts.map +1 -0
  12. package/dist/types.js +35 -0
  13. package/dist/types.js.map +1 -0
  14. package/dist/utils/prompts.d.ts +5 -0
  15. package/dist/utils/prompts.d.ts.map +1 -0
  16. package/dist/utils/prompts.js +185 -0
  17. package/dist/utils/prompts.js.map +1 -0
  18. package/dist/utils/template.d.ts +36 -0
  19. package/dist/utils/template.d.ts.map +1 -0
  20. package/dist/utils/template.js +369 -0
  21. package/dist/utils/template.js.map +1 -0
  22. package/eslint.config.mjs +21 -0
  23. package/package.json +41 -36
  24. package/src/cli.ts +42 -0
  25. package/src/commands/init.ts +83 -0
  26. package/src/types.ts +72 -0
  27. package/src/utils/prompts.ts +204 -0
  28. package/src/utils/template.ts +421 -0
  29. package/tsconfig.json +12 -21
  30. package/.npmignore +0 -56
  31. package/android/app/BUCK +0 -65
  32. package/android/app/build.gradle +0 -139
  33. package/android/app/proguard-rules.pro +0 -66
  34. package/android/app/src/main/AndroidManifest.xml +0 -32
  35. package/android/app/src/main/java/com/rxphelloworld/MainActivity.java +0 -15
  36. package/android/app/src/main/java/com/rxphelloworld/MainApplication.java +0 -40
  37. package/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  38. package/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  39. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  40. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  41. package/android/app/src/main/res/values/strings.xml +0 -3
  42. package/android/app/src/main/res/values/styles.xml +0 -8
  43. package/android/build.gradle +0 -24
  44. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  45. package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  46. package/android/gradle.properties +0 -20
  47. package/android/gradlew +0 -164
  48. package/android/gradlew.bat +0 -90
  49. package/android/keystores/BUCK +0 -8
  50. package/android/keystores/debug.keystore.properties +0 -4
  51. package/android/settings.gradle +0 -3
  52. package/img/fingerCounter/1.PNG +0 -0
  53. package/img/fingerCounter/10.PNG +0 -0
  54. package/img/fingerCounter/2.PNG +0 -0
  55. package/img/fingerCounter/3.PNG +0 -0
  56. package/img/fingerCounter/4.PNG +0 -0
  57. package/img/fingerCounter/5.PNG +0 -0
  58. package/img/fingerCounter/6.PNG +0 -0
  59. package/img/fingerCounter/7.PNG +0 -0
  60. package/img/fingerCounter/8.PNG +0 -0
  61. package/img/fingerCounter/9.PNG +0 -0
  62. package/index.android.js +0 -1
  63. package/index.html +0 -30
  64. package/index.ios.js +0 -1
  65. package/ios/RXPHelloWorld/AppDelegate.h +0 -16
  66. package/ios/RXPHelloWorld/AppDelegate.m +0 -37
  67. package/ios/RXPHelloWorld/Base.lproj/LaunchScreen.xib +0 -42
  68. package/ios/RXPHelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json +0 -38
  69. package/ios/RXPHelloWorld/Info.plist +0 -56
  70. package/ios/RXPHelloWorld/main.m +0 -18
  71. package/ios/RXPHelloWorld.xcodeproj/project.pbxproj +0 -1251
  72. package/ios/RXPHelloWorld.xcodeproj/xcshareddata/xcschemes/RXPHelloWorld-tvOS.xcscheme +0 -129
  73. package/ios/RXPHelloWorld.xcodeproj/xcshareddata/xcschemes/RXPHelloWorld.xcscheme +0 -129
  74. package/ios/RXPHelloWorldTests/Info.plist +0 -24
  75. package/ios/RXPHelloWorldTests/RXPHelloWorldTests.m +0 -70
  76. package/src/App.tsx +0 -206
  77. package/src/appUtilities/Grader.ts +0 -72
  78. package/src/appUtilities/Keybinder.ts +0 -28
  79. package/src/appUtilities/Recorder.ts +0 -73
  80. package/src/cloudantFiles/_users._design._auth.validate_doc_update.js +0 -136
  81. package/src/components/ProgressChart.tsx +0 -155
  82. package/src/components/fingerCounter/fingerCounter.tsx +0 -38
  83. package/src/components/fingerCounter/resources/hands.svg +0 -512
  84. package/src/components/numpad.tsx +0 -146
  85. package/src/components/sessionReport.tsx +0 -87
  86. package/src/index.tsx +0 -8
  87. package/src/styles/answerStyles.css +0 -22
  88. package/src/typings/react.d.ts +0 -964
  89. package/webpack.config.ts +0 -26
  90. package/yarn.lock +0 -6208
@@ -0,0 +1,204 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import { CliOptions, ProjectConfig, PREDEFINED_THEMES, ThemeConfig } from '../types.js';
4
+
5
+ export async function gatherProjectConfig(
6
+ projectName: string,
7
+ options: CliOptions
8
+ ): Promise<ProjectConfig> {
9
+ console.log(chalk.cyan('\n🚀 Creating a new Skuilder course application\n'));
10
+
11
+ let config: Partial<ProjectConfig> = {
12
+ projectName
13
+ };
14
+
15
+ if (options.interactive) {
16
+ const answers = await inquirer.prompt([
17
+ {
18
+ type: 'input',
19
+ name: 'title',
20
+ message: 'Course title:',
21
+ default: formatProjectName(projectName),
22
+ validate: (input: string) => input.trim().length > 0 || 'Course title is required'
23
+ },
24
+ {
25
+ type: 'list',
26
+ name: 'dataLayerType',
27
+ message: 'Data layer type:',
28
+ choices: [
29
+ {
30
+ name: 'Dynamic (Connect to CouchDB server)',
31
+ value: 'couch'
32
+ },
33
+ {
34
+ name: 'Static (Self-contained JSON files)',
35
+ value: 'static'
36
+ }
37
+ ],
38
+ default: options.dataLayer === 'dynamic' ? 'couch' : 'static'
39
+ },
40
+ {
41
+ type: 'input',
42
+ name: 'couchdbUrl',
43
+ message: 'CouchDB server URL:',
44
+ default: 'http://localhost:5984',
45
+ when: (answers) => answers.dataLayerType === 'couch',
46
+ validate: (input: string) => {
47
+ if (!input.trim()) return 'CouchDB URL is required for dynamic data layer';
48
+ try {
49
+ new URL(input);
50
+ return true;
51
+ } catch {
52
+ return 'Please enter a valid URL';
53
+ }
54
+ }
55
+ },
56
+ {
57
+ type: 'input',
58
+ name: 'courseId',
59
+ message: 'Course ID to import (optional):',
60
+ when: (answers) => answers.dataLayerType === 'couch'
61
+ },
62
+ {
63
+ type: 'list',
64
+ name: 'themeName',
65
+ message: 'Select theme:',
66
+ choices: [
67
+ {
68
+ name: 'Default (Material Blue)',
69
+ value: 'default'
70
+ },
71
+ {
72
+ name: 'Medical (Healthcare Green)',
73
+ value: 'medical'
74
+ },
75
+ {
76
+ name: 'Educational (Academic Orange)',
77
+ value: 'educational'
78
+ },
79
+ {
80
+ name: 'Corporate (Professional Gray)',
81
+ value: 'corporate'
82
+ }
83
+ ],
84
+ default: options.theme
85
+ }
86
+ ]);
87
+
88
+ config = {
89
+ ...config,
90
+ title: answers.title,
91
+ dataLayerType: answers.dataLayerType,
92
+ couchdbUrl: answers.couchdbUrl,
93
+ course: answers.courseId,
94
+ theme: PREDEFINED_THEMES[answers.themeName]
95
+ };
96
+ } else {
97
+ // Non-interactive mode: use provided options
98
+ config = {
99
+ projectName,
100
+ title: formatProjectName(projectName),
101
+ dataLayerType: options.dataLayer === 'dynamic' ? 'couch' : 'static',
102
+ couchdbUrl: options.couchdbUrl,
103
+ course: options.courseId,
104
+ theme: PREDEFINED_THEMES[options.theme]
105
+ };
106
+
107
+ // Validate required fields for non-interactive mode
108
+ if (config.dataLayerType === 'couch' && !config.couchdbUrl) {
109
+ throw new Error('CouchDB URL is required when using dynamic data layer. Use --couchdb-url option.');
110
+ }
111
+ }
112
+
113
+ return config as ProjectConfig;
114
+ }
115
+
116
+ export async function confirmProjectCreation(
117
+ config: ProjectConfig,
118
+ projectPath: string
119
+ ): Promise<boolean> {
120
+ console.log(chalk.yellow('\n📋 Project Configuration Summary:'));
121
+ console.log(` Project Name: ${chalk.white(config.projectName)}`);
122
+ console.log(` Course Title: ${chalk.white(config.title)}`);
123
+ console.log(` Data Layer: ${chalk.white(config.dataLayerType)}`);
124
+
125
+ if (config.couchdbUrl) {
126
+ console.log(` CouchDB URL: ${chalk.white(config.couchdbUrl)}`);
127
+ }
128
+
129
+ if (config.course) {
130
+ console.log(` Course ID: ${chalk.white(config.course)}`);
131
+ }
132
+
133
+ console.log(` Theme: ${chalk.white(config.theme.name)}`);
134
+ console.log(` Directory: ${chalk.white(projectPath)}`);
135
+
136
+ const { confirmed } = await inquirer.prompt([
137
+ {
138
+ type: 'confirm',
139
+ name: 'confirmed',
140
+ message: 'Create project with these settings?',
141
+ default: true
142
+ }
143
+ ]);
144
+
145
+ return confirmed;
146
+ }
147
+
148
+ export async function promptForCustomTheme(): Promise<ThemeConfig> {
149
+ console.log(chalk.cyan('\n🎨 Custom Theme Configuration\n'));
150
+
151
+ const answers = await inquirer.prompt([
152
+ {
153
+ type: 'input',
154
+ name: 'name',
155
+ message: 'Theme name:',
156
+ validate: (input: string) => input.trim().length > 0 || 'Theme name is required'
157
+ },
158
+ {
159
+ type: 'input',
160
+ name: 'primary',
161
+ message: 'Primary color (hex):',
162
+ default: '#1976D2',
163
+ validate: validateHexColor
164
+ },
165
+ {
166
+ type: 'input',
167
+ name: 'secondary',
168
+ message: 'Secondary color (hex):',
169
+ default: '#424242',
170
+ validate: validateHexColor
171
+ },
172
+ {
173
+ type: 'input',
174
+ name: 'accent',
175
+ message: 'Accent color (hex):',
176
+ default: '#82B1FF',
177
+ validate: validateHexColor
178
+ }
179
+ ]);
180
+
181
+ return {
182
+ name: answers.name,
183
+ colors: {
184
+ primary: answers.primary,
185
+ secondary: answers.secondary,
186
+ accent: answers.accent
187
+ }
188
+ };
189
+ }
190
+
191
+ function formatProjectName(projectName: string): string {
192
+ return projectName
193
+ .split(/[-_\s]+/)
194
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
195
+ .join(' ');
196
+ }
197
+
198
+ function validateHexColor(input: string): boolean | string {
199
+ const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
200
+ if (!hexColorRegex.test(input)) {
201
+ return 'Please enter a valid hex color (e.g., #1976D2)';
202
+ }
203
+ return true;
204
+ }
@@ -0,0 +1,421 @@
1
+ import { promises as fs, existsSync } from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+ import { ProjectConfig, SkuilderConfig } from '../types.js';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ /**
11
+ * Find the standalone-ui package in node_modules
12
+ */
13
+ export async function findStandaloneUiPath(): Promise<string> {
14
+ // Start from CLI package root and work upward
15
+ let currentDir = path.join(__dirname, '..', '..');
16
+
17
+ while (currentDir !== path.dirname(currentDir)) {
18
+ const nodeModulesPath = path.join(currentDir, 'node_modules', '@vue-skuilder', 'standalone-ui');
19
+ if (existsSync(nodeModulesPath)) {
20
+ return nodeModulesPath;
21
+ }
22
+ currentDir = path.dirname(currentDir);
23
+ }
24
+
25
+ throw new Error('Could not find @vue-skuilder/standalone-ui package. Please ensure it is installed.');
26
+ }
27
+
28
+ /**
29
+ * Copy directory recursively, excluding certain files/directories
30
+ */
31
+ export async function copyDirectory(
32
+ source: string,
33
+ destination: string,
34
+ excludePatterns: string[] = ['node_modules', 'dist', '.git', 'cypress']
35
+ ): Promise<void> {
36
+ const entries = await fs.readdir(source, { withFileTypes: true });
37
+
38
+ await fs.mkdir(destination, { recursive: true });
39
+
40
+ for (const entry of entries) {
41
+ const sourcePath = path.join(source, entry.name);
42
+ const destPath = path.join(destination, entry.name);
43
+
44
+ // Skip excluded patterns
45
+ if (excludePatterns.some(pattern => entry.name.includes(pattern))) {
46
+ continue;
47
+ }
48
+
49
+ if (entry.isDirectory()) {
50
+ await copyDirectory(sourcePath, destPath, excludePatterns);
51
+ } else {
52
+ await fs.copyFile(sourcePath, destPath);
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Transform package.json to use published dependencies instead of workspace references
59
+ */
60
+ export async function transformPackageJson(
61
+ packageJsonPath: string,
62
+ projectName: string,
63
+ cliVersion: string
64
+ ): Promise<void> {
65
+ const content = await fs.readFile(packageJsonPath, 'utf-8');
66
+ const packageJson = JSON.parse(content);
67
+
68
+ // Update basic project info
69
+ packageJson.name = projectName;
70
+ packageJson.description = `Skuilder course application: ${projectName}`;
71
+ packageJson.version = '1.0.0';
72
+
73
+ // Transform workspace dependencies to published versions
74
+ if (packageJson.dependencies) {
75
+ for (const [depName, version] of Object.entries(packageJson.dependencies)) {
76
+ if (typeof version === 'string' && version.startsWith('workspace:')) {
77
+ // Replace workspace references with CLI's version
78
+ packageJson.dependencies[depName] = `^${cliVersion}`;
79
+ }
80
+ }
81
+ }
82
+
83
+ // Add missing terser devDependency for build minification
84
+ if (packageJson.devDependencies && !packageJson.devDependencies['terser']) {
85
+ packageJson.devDependencies['terser'] = '^5.39.0';
86
+ }
87
+
88
+ // Remove CLI-specific fields that don't belong in generated projects
89
+ delete packageJson.publishConfig;
90
+
91
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
92
+ }
93
+
94
+ /**
95
+ * Create a vite.config.ts to work with published packages instead of workspace sources
96
+ *
97
+ * // [ ] 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
+ */
99
+ export async function createViteConfig(viteConfigPath: string): Promise<void> {
100
+ // Create a clean vite config for standalone projects
101
+ const transformedContent = `// packages/standalone-ui/vite.config.ts
102
+ import { defineConfig } from 'vite';
103
+ import vue from '@vitejs/plugin-vue';
104
+ import { fileURLToPath, URL } from 'node:url';
105
+
106
+ export default defineConfig({
107
+ plugins: [vue()],
108
+ resolve: {
109
+ alias: {
110
+ // Alias for internal src paths
111
+ '@': fileURLToPath(new URL('./src', import.meta.url)),
112
+
113
+ // Add events alias if needed (often required by dependencies)
114
+ events: 'events',
115
+ },
116
+ extensions: ['.js', '.ts', '.json', '.vue'],
117
+ dedupe: [
118
+ // Ensure single instances of core libs and published packages
119
+ 'vue',
120
+ 'vuetify',
121
+ 'pinia',
122
+ 'vue-router',
123
+ '@vue-skuilder/db',
124
+ '@vue-skuilder/common',
125
+ '@vue-skuilder/common-ui',
126
+ '@vue-skuilder/courses',
127
+ ],
128
+ },
129
+ // --- Dependencies optimization ---
130
+ optimizeDeps: {
131
+ // Help Vite pre-bundle dependencies from published packages
132
+ include: [
133
+ '@vue-skuilder/common-ui',
134
+ '@vue-skuilder/db',
135
+ '@vue-skuilder/common',
136
+ '@vue-skuilder/courses',
137
+ ],
138
+ },
139
+ server: {
140
+ port: 5173, // Use standard Vite port for standalone projects
141
+ },
142
+ build: {
143
+ sourcemap: true,
144
+ target: 'es2020',
145
+ minify: 'terser',
146
+ terserOptions: {
147
+ keep_classnames: true,
148
+ },
149
+ },
150
+ // Add define block for process polyfills
151
+ define: {
152
+ global: 'window',
153
+ 'process.env': process.env,
154
+ 'process.browser': true,
155
+ 'process.version': JSON.stringify(process.version),
156
+ },
157
+ });
158
+ `;
159
+
160
+ await fs.writeFile(viteConfigPath, transformedContent);
161
+ }
162
+
163
+ /**
164
+ * Generate skuilder.config.json based on project configuration
165
+ */
166
+ export async function generateSkuilderConfig(
167
+ configPath: string,
168
+ config: ProjectConfig
169
+ ): Promise<void> {
170
+ const skuilderConfig: SkuilderConfig = {
171
+ title: config.title,
172
+ dataLayerType: config.dataLayerType
173
+ };
174
+
175
+ if (config.course) {
176
+ skuilderConfig.course = config.course;
177
+ }
178
+
179
+ if (config.couchdbUrl) {
180
+ skuilderConfig.couchdbUrl = config.couchdbUrl;
181
+ }
182
+
183
+ if (config.theme) {
184
+ skuilderConfig.theme = config.theme;
185
+ }
186
+
187
+ await fs.writeFile(configPath, JSON.stringify(skuilderConfig, null, 2));
188
+ }
189
+
190
+ /**
191
+ * Generate .gitignore file for the project
192
+ */
193
+ export async function generateGitignore(gitignorePath: string): Promise<void> {
194
+ const gitignoreContent = `# Dependencies
195
+ node_modules/
196
+ /.pnp
197
+ .pnp.js
198
+
199
+ # Production builds
200
+ /dist
201
+ /build
202
+
203
+ # Local env files
204
+ .env
205
+ .env.local
206
+ .env.development.local
207
+ .env.test.local
208
+ .env.production.local
209
+
210
+ # Log files
211
+ npm-debug.log*
212
+ yarn-debug.log*
213
+ yarn-error.log*
214
+ pnpm-debug.log*
215
+ lerna-debug.log*
216
+
217
+ # Runtime data
218
+ pids
219
+ *.pid
220
+ *.seed
221
+ *.pid.lock
222
+
223
+ # Coverage directory used by tools like istanbul
224
+ coverage/
225
+ *.lcov
226
+
227
+ # nyc test coverage
228
+ .nyc_output
229
+
230
+ # Dependency directories
231
+ jspm_packages/
232
+
233
+ # TypeScript cache
234
+ *.tsbuildinfo
235
+
236
+ # Optional npm cache directory
237
+ .npm
238
+
239
+ # Optional eslint cache
240
+ .eslintcache
241
+
242
+ # Microbundle cache
243
+ .rpt2_cache/
244
+ .rts2_cache_cjs/
245
+ .rts2_cache_es/
246
+ .rts2_cache_umd/
247
+
248
+ # Optional REPL history
249
+ .node_repl_history
250
+
251
+ # Output of 'npm pack'
252
+ *.tgz
253
+
254
+ # Yarn Integrity file
255
+ .yarn-integrity
256
+
257
+ # parcel-bundler cache (https://parceljs.org/)
258
+ .cache
259
+ .parcel-cache
260
+
261
+ # Next.js build output
262
+ .next
263
+
264
+ # Nuxt.js build / generate output
265
+ .nuxt
266
+ dist
267
+
268
+ # Gatsby files
269
+ .cache/
270
+ public
271
+
272
+ # Storybook build outputs
273
+ .out
274
+ .storybook-out
275
+
276
+ # Temporary folders
277
+ tmp/
278
+ temp/
279
+
280
+ # Editor directories and files
281
+ .vscode/
282
+ .idea
283
+ .DS_Store
284
+ *.suo
285
+ *.ntvs*
286
+ *.njsproj
287
+ *.sln
288
+ *.sw?
289
+
290
+ # OS generated files
291
+ Thumbs.db
292
+
293
+ # Cypress
294
+ /cypress/videos/
295
+ /cypress/screenshots/
296
+
297
+ # Local development
298
+ .env.development
299
+ .env.production
300
+
301
+ # Package manager lockfiles (uncomment if you want to ignore them)
302
+ # package-lock.json
303
+ # yarn.lock
304
+ # pnpm-lock.yaml
305
+
306
+ # Skuilder specific
307
+ /src/data/local-*.json
308
+ `;
309
+
310
+ await fs.writeFile(gitignorePath, gitignoreContent);
311
+ }
312
+
313
+ /**
314
+ * Generate project README.md
315
+ */
316
+ export async function generateReadme(
317
+ readmePath: string,
318
+ config: ProjectConfig
319
+ ): Promise<void> {
320
+ const dataLayerInfo = config.dataLayerType === 'static'
321
+ ? 'This project uses a static data layer with JSON files.'
322
+ : `This project connects to CouchDB at: ${config.couchdbUrl || '[URL not specified]'}`;
323
+
324
+ const readme = `# ${config.title}
325
+
326
+ A Skuilder course application built with Vue 3, Vuetify, and Pinia.
327
+
328
+ ## Data Layer
329
+
330
+ ${dataLayerInfo}
331
+
332
+ ## Development
333
+
334
+ Install dependencies:
335
+ \`\`\`bash
336
+ npm install
337
+ \`\`\`
338
+
339
+ Start the development server:
340
+ \`\`\`bash
341
+ npm run dev
342
+ \`\`\`
343
+
344
+ Build for production:
345
+ \`\`\`bash
346
+ npm run build
347
+ \`\`\`
348
+
349
+ ## Configuration
350
+
351
+ Course configuration is managed in \`skuilder.config.json\`. You can modify:
352
+ - Course title
353
+ - Data layer settings
354
+ - Theme customization
355
+ - Database connection details (for dynamic data layer)
356
+
357
+ ## Theme
358
+
359
+ Current theme: **${config.theme.name}**
360
+ - Primary: ${config.theme.colors.primary}
361
+ - Secondary: ${config.theme.colors.secondary}
362
+ - Accent: ${config.theme.colors.accent}
363
+
364
+ ## Testing
365
+
366
+ Run end-to-end tests:
367
+ \`\`\`bash
368
+ npm run test:e2e
369
+ \`\`\`
370
+
371
+ Run tests in headless mode:
372
+ \`\`\`bash
373
+ npm run test:e2e:headless
374
+ \`\`\`
375
+
376
+ ## Learn More
377
+
378
+ Visit the [Skuilder documentation](https://github.com/NiloCK/vue-skuilder) for more information about building course applications.
379
+ `;
380
+
381
+ await fs.writeFile(readmePath, readme);
382
+ }
383
+
384
+ /**
385
+ * Copy and transform the standalone-ui template to create a new project
386
+ */
387
+ export async function processTemplate(
388
+ projectPath: string,
389
+ config: ProjectConfig,
390
+ cliVersion: string
391
+ ): Promise<void> {
392
+ console.log(chalk.blue('📦 Locating standalone-ui template...'));
393
+ const templatePath = await findStandaloneUiPath();
394
+
395
+ console.log(chalk.blue('📂 Copying project files...'));
396
+ await copyDirectory(templatePath, projectPath);
397
+
398
+ console.log(chalk.blue('⚙️ Configuring package.json...'));
399
+ const packageJsonPath = path.join(projectPath, 'package.json');
400
+ await transformPackageJson(packageJsonPath, config.projectName, cliVersion);
401
+
402
+ console.log(chalk.blue('🔧 Creating vite.config.ts...'));
403
+ const viteConfigPath = path.join(projectPath, 'vite.config.ts');
404
+ if (existsSync(viteConfigPath)) {
405
+ await createViteConfig(viteConfigPath);
406
+ }
407
+
408
+ console.log(chalk.blue('🔧 Generating configuration...'));
409
+ const configPath = path.join(projectPath, 'skuilder.config.json');
410
+ await generateSkuilderConfig(configPath, config);
411
+
412
+ console.log(chalk.blue('📝 Creating README...'));
413
+ const readmePath = path.join(projectPath, 'README.md');
414
+ await generateReadme(readmePath, config);
415
+
416
+ console.log(chalk.blue('📄 Generating .gitignore...'));
417
+ const gitignorePath = path.join(projectPath, '.gitignore');
418
+ await generateGitignore(gitignorePath);
419
+
420
+ console.log(chalk.green('✅ Template processing complete!'));
421
+ }
package/tsconfig.json CHANGED
@@ -1,27 +1,18 @@
1
1
  {
2
- "exclude": [
3
- "node_modules"
4
- ],
2
+ "extends": "../../tsconfig.base.json",
5
3
  "compilerOptions": {
6
- "declaration": false,
7
- "noResolve": false,
8
- "jsx": "react",
9
- "reactNamespace": "RX",
10
- "module": "commonjs",
11
- "target": "es5",
12
- "experimentalDecorators": true,
13
- "sourceMap": true,
14
- "noImplicitAny": true,
15
- "noImplicitReturns": true,
16
- "outDir": "./dist/",
17
- "types": [
18
- "node"
19
- ]
20
- },
21
- "typeAcquisition": {
22
- "enable": true
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "resolveJsonModule": true,
9
+ "allowImportingTsExtensions": false
23
10
  },
24
11
  "include": [
25
- "./src/**/*"
12
+ "src/**/*"
13
+ ],
14
+ "exclude": [
15
+ "node_modules",
16
+ "dist"
26
17
  ]
27
18
  }
package/.npmignore DELETED
@@ -1,56 +0,0 @@
1
- # OSX
2
- #
3
- .DS_Store
4
-
5
- # Xcode
6
- #
7
- build/
8
- *.pbxuser
9
- !default.pbxuser
10
- *.mode1v3
11
- !default.mode1v3
12
- *.mode2v3
13
- !default.mode2v3
14
- *.perspectivev3
15
- !default.perspectivev3
16
- xcuserdata
17
- *.xccheckout
18
- *.moved-aside
19
- DerivedData
20
- *.hmap
21
- *.ipa
22
- *.xcuserstate
23
- project.xcworkspace
24
-
25
- # Android/IntelliJ
26
- #
27
- build/
28
- .idea
29
- .gradle
30
- local.properties
31
- *.iml
32
-
33
- # node.js
34
- #
35
- node_modules/
36
- npm-debug.log
37
- yarn-error.log
38
-
39
- # BUCK
40
- buck-out/
41
- \.buckd/
42
- *.keystore
43
-
44
- # fastlane
45
- #
46
- # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47
- # screenshots whenever they are needed.
48
- # For more information about the recommended setup visit:
49
- # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
50
-
51
- fastlane/report.xml
52
- fastlane/Preview.html
53
- fastlane/screenshots
54
-
55
- .vscode
56
- dist/