@xbg.solutions/create-frontend 1.1.1

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.
@@ -0,0 +1,341 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Validates the project setup and configuration
5
+ *
6
+ * Checks:
7
+ * - Environment variables
8
+ * - Firebase configuration
9
+ * - Dependencies
10
+ * - Build configuration
11
+ * - Test setup
12
+ *
13
+ * Usage: npm run validate
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const { execSync } = require('child_process');
19
+
20
+ // ANSI colors
21
+ const colors = {
22
+ reset: '\x1b[0m',
23
+ green: '\x1b[32m',
24
+ red: '\x1b[31m',
25
+ yellow: '\x1b[33m',
26
+ cyan: '\x1b[36m',
27
+ bright: '\x1b[1m'
28
+ };
29
+
30
+ const log = {
31
+ success: (msg) => console.log(`${colors.green}โœ“${colors.reset} ${msg}`),
32
+ error: (msg) => console.log(`${colors.red}โœ—${colors.reset} ${msg}`),
33
+ warn: (msg) => console.log(`${colors.yellow}โš ${colors.reset} ${msg}`),
34
+ info: (msg) => console.log(`${colors.cyan}โ„น${colors.reset} ${msg}`),
35
+ title: (msg) => console.log(`\n${colors.bright}${msg}${colors.reset}`)
36
+ };
37
+
38
+ let errorCount = 0;
39
+ let warningCount = 0;
40
+
41
+ function checkFile(filePath, description) {
42
+ if (fs.existsSync(filePath)) {
43
+ log.success(`${description} exists`);
44
+ return true;
45
+ } else {
46
+ log.error(`${description} missing: ${filePath}`);
47
+ errorCount++;
48
+ return false;
49
+ }
50
+ }
51
+
52
+ function checkEnvVar(varName, description, isRequired = true) {
53
+ // Read .env file
54
+ if (!fs.existsSync('.env')) {
55
+ if (isRequired) {
56
+ log.error(`.env file not found - run 'npm run setup'`);
57
+ errorCount++;
58
+ }
59
+ return false;
60
+ }
61
+
62
+ const envContent = fs.readFileSync('.env', 'utf8');
63
+ const match = envContent.match(new RegExp(`${varName}=(.+)`));
64
+
65
+ if (match && match[1] && match[1].trim() !== '') {
66
+ const value = match[1].trim().replace(/"/g, '');
67
+
68
+ // Check if it's still a placeholder
69
+ if (value.includes('your-') || value.includes('FIXME') || value === 'localhost') {
70
+ if (isRequired) {
71
+ log.warn(`${description} is set to placeholder value: ${value}`);
72
+ warningCount++;
73
+ }
74
+ return false;
75
+ }
76
+
77
+ log.success(`${description} configured`);
78
+ return true;
79
+ } else {
80
+ if (isRequired) {
81
+ log.error(`${description} missing (${varName})`);
82
+ errorCount++;
83
+ } else {
84
+ log.warn(`${description} not set (${varName})`);
85
+ warningCount++;
86
+ }
87
+ return false;
88
+ }
89
+ }
90
+
91
+ function validatePackageJson() {
92
+ log.title('๐Ÿ“ฆ Package.json Validation');
93
+
94
+ if (!checkFile('package.json', 'package.json')) return;
95
+
96
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
97
+
98
+ // Check required scripts
99
+ const requiredScripts = ['dev', 'build', 'test', 'lint'];
100
+ requiredScripts.forEach(script => {
101
+ if (pkg.scripts && pkg.scripts[script]) {
102
+ log.success(`Script '${script}' defined`);
103
+ } else {
104
+ log.error(`Script '${script}' missing`);
105
+ errorCount++;
106
+ }
107
+ });
108
+
109
+ // Check required dependencies
110
+ const requiredDeps = ['svelte', 'firebase', 'tailwindcss'];
111
+ requiredDeps.forEach(dep => {
112
+ if (pkg.dependencies && pkg.dependencies[dep]) {
113
+ log.success(`Dependency '${dep}' installed`);
114
+ } else if (pkg.devDependencies && pkg.devDependencies[dep]) {
115
+ log.success(`Dev dependency '${dep}' installed`);
116
+ } else {
117
+ log.error(`Required dependency '${dep}' missing`);
118
+ errorCount++;
119
+ }
120
+ });
121
+ }
122
+
123
+ function validateFiles() {
124
+ log.title('๐Ÿ“ File Structure Validation');
125
+
126
+ const requiredFiles = [
127
+ { path: 'src/app.html', desc: 'App HTML template' },
128
+ { path: 'src/routes/+page.svelte', desc: 'Home page' },
129
+ { path: 'src/lib/config/app.config.ts', desc: 'App configuration' },
130
+ { path: 'svelte.config.js', desc: 'Svelte config' },
131
+ { path: 'vite.config.ts', desc: 'Vite config' },
132
+ { path: 'tailwind.config.js', desc: 'Tailwind config' },
133
+ { path: 'tsconfig.json', desc: 'TypeScript config' }
134
+ ];
135
+
136
+ requiredFiles.forEach(({ path, desc }) => checkFile(path, desc));
137
+
138
+ // Check component library
139
+ if (fs.existsSync('src/lib/components/ui')) {
140
+ const uiComponents = fs.readdirSync('src/lib/components/ui');
141
+ log.success(`UI component library (${uiComponents.length} components)`);
142
+ } else {
143
+ log.error('UI component library missing');
144
+ errorCount++;
145
+ }
146
+ }
147
+
148
+ function validateEnvironment() {
149
+ log.title('๐ŸŒ Environment Configuration Validation');
150
+
151
+ // Check .env file
152
+ checkFile('.env', 'Environment file (.env)');
153
+ checkFile('.env.example', 'Environment template (.env.example)');
154
+
155
+ // Check required environment variables
156
+ checkEnvVar('VITE_APP_NAME', 'App name', true);
157
+ checkEnvVar('VITE_APP_DOMAIN', 'App domain', true);
158
+ checkEnvVar('VITE_FIREBASE_PROJECT_ID', 'Firebase Project ID', true);
159
+ checkEnvVar('VITE_FIREBASE_API_KEY', 'Firebase API Key', true);
160
+ checkEnvVar('VITE_FIREBASE_AUTH_DOMAIN', 'Firebase Auth Domain', true);
161
+
162
+ // Optional but recommended
163
+ checkEnvVar('VITE_API_BASE_URL_DEV', 'Development API URL', false);
164
+ checkEnvVar('VITE_API_BASE_URL_PROD', 'Production API URL', false);
165
+ }
166
+
167
+ function validateFirebase() {
168
+ log.title('๐Ÿ”ฅ Firebase Configuration Validation');
169
+
170
+ // Check firebase.json
171
+ if (checkFile('firebase.json', 'Firebase config (firebase.json)')) {
172
+ try {
173
+ const firebaseConfig = JSON.parse(fs.readFileSync('firebase.json', 'utf8'));
174
+
175
+ if (firebaseConfig.hosting) {
176
+ log.success('Firebase Hosting configured');
177
+ } else {
178
+ log.warn('Firebase Hosting not configured');
179
+ warningCount++;
180
+ }
181
+
182
+ if (firebaseConfig.emulators) {
183
+ log.success('Firebase Emulators configured');
184
+ } else {
185
+ log.info('Firebase Emulators not configured (optional)');
186
+ }
187
+ } catch (e) {
188
+ log.error(`Invalid firebase.json: ${e.message}`);
189
+ errorCount++;
190
+ }
191
+ }
192
+
193
+ // Check if Firebase CLI is installed
194
+ try {
195
+ execSync('firebase --version', { stdio: 'ignore' });
196
+ log.success('Firebase CLI installed');
197
+ } catch (e) {
198
+ log.warn('Firebase CLI not found - install: npm install -g firebase-tools');
199
+ warningCount++;
200
+ }
201
+ }
202
+
203
+ function validateBuild() {
204
+ log.title('๐Ÿ—๏ธ Build Configuration Validation');
205
+
206
+ // Check if node_modules exists
207
+ if (fs.existsSync('node_modules')) {
208
+ log.success('Dependencies installed');
209
+ } else {
210
+ log.error('Dependencies not installed - run: npm install');
211
+ errorCount++;
212
+ return;
213
+ }
214
+
215
+ // Try a build (optional - can be slow)
216
+ const quickBuild = process.argv.includes('--quick');
217
+ if (!quickBuild) {
218
+ log.info('Testing build process (use --quick to skip)...');
219
+ try {
220
+ execSync('npm run build', { stdio: 'ignore', timeout: 60000 });
221
+ log.success('Build successful');
222
+ } catch (e) {
223
+ log.error('Build failed - check build output for errors');
224
+ errorCount++;
225
+ }
226
+ }
227
+ }
228
+
229
+ function validateTests() {
230
+ log.title('๐Ÿงช Test Setup Validation');
231
+
232
+ // Check test configuration
233
+ if (checkFile('vitest.config.ts', 'Vitest config')) {
234
+ // Try running tests
235
+ log.info('Running tests (use --quick to skip)...');
236
+ const quickTest = process.argv.includes('--quick');
237
+ if (!quickTest) {
238
+ try {
239
+ const testOutput = execSync('npm test', { encoding: 'utf8', timeout: 30000 });
240
+
241
+ // Parse test results
242
+ const passMatch = testOutput.match(/(\d+) passed/);
243
+ if (passMatch) {
244
+ log.success(`Tests passing: ${passMatch[1]} tests`);
245
+ } else {
246
+ log.success('Tests completed');
247
+ }
248
+ } catch (e) {
249
+ log.error('Tests failed - check test output for errors');
250
+ errorCount++;
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ function validateAppConfig() {
257
+ log.title('โš™๏ธ App Configuration Validation');
258
+
259
+ const configPath = 'src/lib/config/app.config.ts';
260
+ if (!fs.existsSync(configPath)) {
261
+ log.error('app.config.ts not found');
262
+ errorCount++;
263
+ return;
264
+ }
265
+
266
+ const configContent = fs.readFileSync(configPath, 'utf8');
267
+
268
+ // Check for FIXME comments
269
+ const fixmeMatches = configContent.match(/\/\/ FIXME:/g);
270
+ if (fixmeMatches && fixmeMatches.length > 0) {
271
+ log.warn(`Found ${fixmeMatches.length} FIXME comments in app.config.ts`);
272
+ log.info(' Review and update these configuration items');
273
+ warningCount++;
274
+ } else {
275
+ log.success('No FIXME comments in app.config.ts');
276
+ }
277
+
278
+ // Check for placeholder values
279
+ const placeholders = [
280
+ 'your-project-id',
281
+ 'your-api-key',
282
+ 'your-app-id',
283
+ 'your-domain.com'
284
+ ];
285
+
286
+ let placeholderCount = 0;
287
+ placeholders.forEach(placeholder => {
288
+ if (configContent.includes(placeholder)) {
289
+ placeholderCount++;
290
+ }
291
+ });
292
+
293
+ if (placeholderCount > 0) {
294
+ log.warn(`Found ${placeholderCount} placeholder values in app.config.ts`);
295
+ log.info(' Run `npm run setup` to configure automatically');
296
+ warningCount++;
297
+ } else {
298
+ log.success('No placeholder values in app.config.ts');
299
+ }
300
+ }
301
+
302
+ function displaySummary() {
303
+ log.title('๐Ÿ“Š Validation Summary');
304
+
305
+ console.log(`\nResults:`);
306
+ console.log(` ${colors.green}โœ“ Checks passed${colors.reset}`);
307
+ console.log(` ${colors.red}โœ— Errors: ${errorCount}${colors.reset}`);
308
+ console.log(` ${colors.yellow}โš  Warnings: ${warningCount}${colors.reset}\n`);
309
+
310
+ if (errorCount === 0 && warningCount === 0) {
311
+ console.log(`${colors.green}${colors.bright}๐ŸŽ‰ Your project is fully configured and ready!${colors.reset}\n`);
312
+ console.log(`Next steps:`);
313
+ console.log(` ${colors.cyan}npm run dev${colors.reset} - Start development server`);
314
+ console.log(` ${colors.cyan}npm test${colors.reset} - Run tests`);
315
+ console.log(` ${colors.cyan}npm run build${colors.reset} - Build for production\n`);
316
+ } else if (errorCount === 0) {
317
+ console.log(`${colors.yellow}โš  Project is mostly configured with ${warningCount} warnings${colors.reset}\n`);
318
+ console.log(`Consider addressing the warnings above for best results.\n`);
319
+ } else {
320
+ console.log(`${colors.red}โŒ Project has ${errorCount} errors that need to be fixed${colors.reset}\n`);
321
+ console.log(`Fix the errors above before continuing.\n`);
322
+ console.log(`Quick fixes:`);
323
+ console.log(` ${colors.cyan}npm run setup${colors.reset} - Run interactive setup wizard`);
324
+ console.log(` ${colors.cyan}npm install${colors.reset} - Install missing dependencies\n`);
325
+ }
326
+
327
+ process.exit(errorCount > 0 ? 1 : 0);
328
+ }
329
+
330
+ // Main validation
331
+ console.clear();
332
+ console.log(`${colors.bright}${colors.cyan}๐Ÿ” SvelteKit Boilerplate - Setup Validation${colors.reset}\n`);
333
+
334
+ validatePackageJson();
335
+ validateFiles();
336
+ validateEnvironment();
337
+ validateFirebase();
338
+ validateAppConfig();
339
+ validateBuild();
340
+ validateTests();
341
+ displaySummary();
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true,
9
+ "outDir": "lib",
10
+ "rootDir": "src",
11
+ "strict": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "resolveJsonModule": true,
16
+ "isolatedModules": true
17
+ },
18
+ "include": ["src/**/*.ts"],
19
+ "exclude": ["node_modules", "lib"]
20
+ }