i18ntk 2.3.8 → 2.5.0

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.
@@ -1,717 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * setup-validator.js - Comprehensive Setup Validation
5
- *
6
- * Validates the foundational setup, identifies potential issues,
7
- * and provides actionable recommendations for improvement.
8
- */
9
-
10
- const fs = require('fs');
11
- const path = require('path');
12
- const SecurityUtils = require('./security');
13
-
14
-
15
- class SetupValidator {
16
- constructor() {
17
- this.results = {
18
- timestamp: new Date().toISOString(),
19
- status: 'pending',
20
- checks: [],
21
- warnings: [],
22
- errors: [],
23
- recommendations: [],
24
- performance: {},
25
- security: {},
26
- compatibility: {}
27
- };
28
- this.config = null;
29
- }
30
-
31
- async validate() {
32
- console.log('šŸ” Validating i18n Toolkit Setup...');
33
- console.log('====================================');
34
-
35
- try {
36
- await this.loadConfiguration();
37
- await this.validateFrameworkDetection();
38
- await this.validateDirectoryStructure();
39
- await this.validateDependencies();
40
- await this.validatePerformanceSettings();
41
- await this.validateSecuritySettings();
42
- await this.validateCompatibility();
43
- await this.generateValidationReport();
44
-
45
- this.results.status = this.results.errors.length === 0 ? 'passed' : 'failed';
46
-
47
- console.log(`\nšŸ“Š Validation Complete: ${this.results.status.toUpperCase()}`);
48
- console.log(` āœ… Passed: ${this.results.checks.filter(c => c.status === 'passed').length}`);
49
- console.log(` āš ļø Warnings: ${this.results.warnings.length}`);
50
- console.log(` āŒ Errors: ${this.results.errors.length}`);
51
-
52
- return this.results;
53
- } catch (error) {
54
- this.results.errors.push({
55
- category: 'validation',
56
- message: `Validation failed: ${error.message}`,
57
- severity: 'critical',
58
- fix: 'Check system configuration and permissions'
59
- });
60
- return this.results;
61
- }
62
- }
63
-
64
- async loadConfiguration() {
65
- const configPath = path.join(process.cwd(), 'i18ntk-config.json');
66
-
67
- if (SecurityUtils.safeExistsSync(configPath)) {
68
- try {
69
- this.config = JSON.parse(SecurityUtils.safeReadFileSync(configPath, path.dirname(configPath), 'utf8'));
70
- this.results.checks.push({
71
- category: 'configuration',
72
- message: 'Configuration file found and valid',
73
- status: 'passed',
74
- details: { path: configPath }
75
- });
76
- } catch (error) {
77
- this.results.errors.push({
78
- category: 'configuration',
79
- message: 'Invalid configuration file',
80
- severity: 'high',
81
- fix: 'Run setup script to regenerate configuration',
82
- details: { error: error.message }
83
- });
84
- }
85
- } else {
86
- this.results.errors.push({
87
- category: 'configuration',
88
- message: 'Configuration file not found',
89
- severity: 'critical',
90
- fix: 'Run i18ntk-setup.js to create configuration',
91
- action: 'node main/i18ntk-setup.js'
92
- });
93
- }
94
- }
95
-
96
- async validateFrameworkDetection() {
97
- if (!this.config) return;
98
-
99
- const detectedLanguage = this.config.detectedLanguage;
100
- const detectedFramework = this.config.detectedFramework;
101
-
102
- // Check if detection is valid
103
- const validLanguages = ['javascript', 'typescript', 'python', 'java', 'go', 'php'];
104
- const validFrameworks = {
105
- javascript: ['react', 'vue', 'angular', 'nextjs', 'nuxt', 'svelte', 'generic'],
106
- typescript: ['react', 'vue', 'angular', 'nextjs', 'nuxt', 'generic'],
107
- python: ['django', 'flask', 'fastapi', 'generic'],
108
- java: ['spring', 'spring-boot', 'quarkus', 'generic'],
109
- go: ['gin', 'echo', 'fiber', 'generic'],
110
- php: ['laravel', 'symfony', 'wordpress', 'generic']
111
- };
112
-
113
- if (validLanguages.includes(detectedLanguage)) {
114
- this.results.checks.push({
115
- category: 'framework',
116
- message: `Language detected: ${detectedLanguage}`,
117
- status: 'passed',
118
- details: { detected: detectedLanguage }
119
- });
120
- } else {
121
- this.results.warnings.push({
122
- category: 'framework',
123
- message: 'Language detection may be inaccurate',
124
- severity: 'medium',
125
- fix: 'Manually specify language if needed',
126
- action: 'node main/i18ntk-setup.js --language [javascript|python|go|java|php]'
127
- });
128
- }
129
-
130
- if (detectedFramework && validFrameworks[detectedLanguage]?.includes(detectedFramework)) {
131
- this.results.checks.push({
132
- category: 'framework',
133
- message: `Framework detected: ${detectedFramework}`,
134
- status: 'passed',
135
- details: { detected: detectedFramework }
136
- });
137
- } else {
138
- this.results.warnings.push({
139
- category: 'framework',
140
- message: 'Framework detection uncertain',
141
- severity: 'low',
142
- fix: 'Verify framework detection or specify manually',
143
- action: 'node main/i18ntk-setup.js --framework [framework-name]'
144
- });
145
- }
146
- }
147
-
148
- async validateDirectoryStructure() {
149
- if (!this.config) return;
150
-
151
- const sourceDir = this.config.sourceDir;
152
- const outputDir = this.config.outputDir;
153
-
154
- // Check source directory
155
- if (SecurityUtils.safeExistsSync(sourceDir)) {
156
- const stats = fs.statSync(sourceDir);
157
- if (stats.isDirectory()) {
158
- const files = fs.readdirSync(sourceDir);
159
- const localeFiles = files.filter(f => f.endsWith('.json') || f.endsWith('.yml') || f.endsWith('.yaml'));
160
-
161
- this.results.checks.push({
162
- category: 'directories',
163
- message: 'Source directory exists',
164
- status: 'passed',
165
- details: { path: sourceDir, files: files.length, localeFiles: localeFiles.length }
166
- });
167
-
168
- if (localeFiles.length === 0) {
169
- this.results.warnings.push({
170
- category: 'directories',
171
- message: 'No locale files found in source directory',
172
- severity: 'medium',
173
- fix: 'Add locale files or run initialization',
174
- action: 'node main/i18ntk-init.js'
175
- });
176
- }
177
- } else {
178
- this.results.errors.push({
179
- category: 'directories',
180
- message: 'Source path is not a directory',
181
- severity: 'high',
182
- fix: 'Check source directory configuration',
183
- details: { path: sourceDir }
184
- });
185
- }
186
- } else {
187
- this.results.errors.push({
188
- category: 'directories',
189
- message: 'Source directory does not exist',
190
- severity: 'high',
191
- fix: 'Create source directory or run setup',
192
- action: 'node main/i18ntk-setup.js'
193
- });
194
- }
195
-
196
- // Check output directory
197
- if (!SecurityUtils.safeExistsSync(outputDir)) {
198
- fs.mkdirSync(outputDir, { recursive: true });
199
- this.results.checks.push({
200
- category: 'directories',
201
- message: 'Output directory created',
202
- status: 'passed',
203
- details: { path: outputDir }
204
- });
205
- } else {
206
- this.results.checks.push({
207
- category: 'directories',
208
- message: 'Output directory exists',
209
- status: 'passed',
210
- details: { path: outputDir }
211
- });
212
- }
213
- }
214
-
215
- async validateDependencies() {
216
- if (!this.config) return;
217
-
218
- const language = this.config.detectedLanguage;
219
- const framework = this.config.detectedFramework;
220
-
221
- // Check for language-specific dependencies
222
- const dependencies = {
223
- javascript: {
224
- required: [],
225
- recommended: ['i18next', 'react-i18next', 'vue-i18n', '@angular/localize'],
226
- dev: ['@types/i18next']
227
- },
228
- python: {
229
- required: [],
230
- recommended: ['django', 'flask-babel', 'babel'],
231
- dev: ['pytest']
232
- },
233
- go: {
234
- required: [],
235
- recommended: ['go-i18n'],
236
- dev: []
237
- },
238
- java: {
239
- required: [],
240
- recommended: ['spring-boot-starter-web', 'spring-context'],
241
- dev: ['spring-boot-starter-test']
242
- },
243
- php: {
244
- required: [],
245
- recommended: ['gettext', 'symfony/translation'],
246
- dev: ['phpunit/phpunit']
247
- }
248
- };
249
-
250
- const packageJsonPath = path.join(process.cwd(), 'package.json');
251
- const requirementsPath = path.join(process.cwd(), 'requirements.txt');
252
- const goModPath = path.join(process.cwd(), 'go.mod');
253
- const pomPath = path.join(process.cwd(), 'pom.xml');
254
- const composerPath = path.join(process.cwd(), 'composer.json');
255
-
256
- let hasDependencies = false;
257
- let hasRecommended = false;
258
-
259
- switch (language) {
260
- case 'javascript':
261
- case 'typescript':
262
- if (SecurityUtils.safeExistsSync(packageJsonPath)) {
263
- try {
264
- const packageJson = JSON.parse(SecurityUtils.safeReadFileSync(packageJsonPath, path.dirname(packageJsonPath), 'utf8'));
265
- const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
266
-
267
- const recommended = dependencies[language].recommended;
268
- const found = recommended.filter(dep => allDeps[dep]);
269
-
270
- if (found.length > 0) {
271
- hasDependencies = true;
272
- hasRecommended = true;
273
- this.results.checks.push({
274
- category: 'dependencies',
275
- message: 'i18n dependencies found',
276
- status: 'passed',
277
- details: { found: found }
278
- });
279
- } else {
280
- this.results.warnings.push({
281
- category: 'dependencies',
282
- message: 'No i18n dependencies found',
283
- severity: 'medium',
284
- fix: 'Install recommended dependencies',
285
- action: `npm install ${recommended.join(' ')}`
286
- });
287
- }
288
- } catch (error) {
289
- this.results.errors.push({
290
- category: 'dependencies',
291
- message: 'Cannot parse package.json',
292
- severity: 'medium',
293
- fix: 'Check package.json syntax',
294
- details: { error: error.message }
295
- });
296
- }
297
- }
298
- break;
299
-
300
- case 'python':
301
- if (SecurityUtils.safeExistsSync(requirementsPath)) {
302
- const requirements = SecurityUtils.safeReadFileSync(requirementsPath, path.dirname(requirementsPath), 'utf8');
303
- const recommended = dependencies[language].recommended;
304
- const found = recommended.filter(dep => requirements.includes(dep));
305
-
306
- if (found.length > 0) {
307
- hasDependencies = true;
308
- hasRecommended = true;
309
- this.results.checks.push({
310
- category: 'dependencies',
311
- message: 'i18n dependencies found',
312
- status: 'passed',
313
- details: { found: found }
314
- });
315
- } else {
316
- this.results.warnings.push({
317
- category: 'dependencies',
318
- message: 'No i18n dependencies found',
319
- severity: 'medium',
320
- fix: 'Install recommended dependencies',
321
- action: `pip install ${recommended.join(' ')}`
322
- });
323
- }
324
- }
325
- break;
326
-
327
- case 'go':
328
- if (SecurityUtils.safeExistsSync(goModPath)) {
329
- const goMod = SecurityUtils.safeReadFileSync(goModPath, path.dirname(goModPath), 'utf8');
330
- const recommended = dependencies[language].recommended;
331
- const found = recommended.filter(dep => goMod.includes(dep));
332
-
333
- if (found.length > 0) {
334
- hasDependencies = true;
335
- hasRecommended = true;
336
- this.results.checks.push({
337
- category: 'dependencies',
338
- message: 'i18n dependencies found',
339
- status: 'passed',
340
- details: { found: found }
341
- });
342
- } else {
343
- this.results.warnings.push({
344
- category: 'dependencies',
345
- message: 'No i18n dependencies found',
346
- severity: 'medium',
347
- fix: 'Install recommended dependencies',
348
- action: `go get ${recommended.join(' ')}`
349
- });
350
- }
351
- }
352
- break;
353
-
354
- case 'java':
355
- if (SecurityUtils.safeExistsSync(pomPath)) {
356
- const pom = SecurityUtils.safeReadFileSync(pomPath, path.dirname(pomPath), 'utf8');
357
- const recommended = dependencies[language].recommended;
358
- const found = recommended.filter(dep => pom.includes(dep));
359
-
360
- if (found.length > 0) {
361
- hasDependencies = true;
362
- hasRecommended = true;
363
- this.results.checks.push({
364
- category: 'dependencies',
365
- message: 'i18n dependencies found',
366
- status: 'passed',
367
- details: { found: found }
368
- });
369
- } else {
370
- this.results.warnings.push({
371
- category: 'dependencies',
372
- message: 'No i18n dependencies found',
373
- severity: 'medium',
374
- fix: 'Add recommended dependencies to pom.xml'
375
- });
376
- }
377
- }
378
- break;
379
-
380
- case 'php':
381
- if (SecurityUtils.safeExistsSync(composerPath)) {
382
- try {
383
- const composer = JSON.parse(SecurityUtils.safeReadFileSync(composerPath, path.dirname(composerPath), 'utf8'));
384
- const allDeps = { ...composer.require, ...composer['require-dev'] };
385
-
386
- const recommended = dependencies[language].recommended;
387
- const found = recommended.filter(dep => allDeps[dep]);
388
-
389
- if (found.length > 0) {
390
- hasDependencies = true;
391
- hasRecommended = true;
392
- this.results.checks.push({
393
- category: 'dependencies',
394
- message: 'i18n dependencies found',
395
- status: 'passed',
396
- details: { found: found }
397
- });
398
- } else {
399
- this.results.warnings.push({
400
- category: 'dependencies',
401
- message: 'No i18n dependencies found',
402
- severity: 'medium',
403
- fix: 'Install recommended dependencies',
404
- action: `composer require ${recommended.join(' ')}`
405
- });
406
- }
407
- } catch (error) {
408
- this.results.errors.push({
409
- category: 'dependencies',
410
- message: 'Cannot parse composer.json',
411
- severity: 'medium',
412
- fix: 'Check composer.json syntax',
413
- details: { error: error.message }
414
- });
415
- }
416
- }
417
- break;
418
- }
419
- }
420
-
421
- estimatePerformance(mode) {
422
- const performanceMap = {
423
- extreme: { improvement: 87, time: '38.90ms' },
424
- ultra: { improvement: 78, time: '336.8ms' },
425
- optimized: { improvement: 45, time: '847.9ms' }
426
- };
427
- return performanceMap[mode] || { improvement: 0, time: 'unknown' };
428
- }
429
-
430
- async validatePerformanceSettings() {
431
- if (!this.config) return;
432
-
433
- const optimization = this.config.optimization;
434
-
435
- // Validate performance mode
436
- const validModes = ['extreme', 'ultra', 'optimized'];
437
- if (validModes.includes(optimization.mode)) {
438
- this.results.checks.push({
439
- category: 'performance',
440
- message: `Performance mode set to: ${optimization.mode}`,
441
- status: 'passed',
442
- details: { mode: optimization.mode }
443
- });
444
- } else {
445
- this.results.warnings.push({
446
- category: 'performance',
447
- message: 'Invalid performance mode',
448
- severity: 'low',
449
- fix: 'Update performance mode',
450
- action: 'node main/i18ntk-setup.js --optimize'
451
- });
452
- }
453
-
454
- // Validate batch size
455
- const batchSize = optimization.batchSize;
456
- if (batchSize >= 100 && batchSize <= 10000) {
457
- this.results.checks.push({
458
- category: 'performance',
459
- message: 'Batch size within optimal range',
460
- status: 'passed',
461
- details: { batchSize: batchSize }
462
- });
463
- } else {
464
- this.results.warnings.push({
465
- category: 'performance',
466
- message: 'Batch size may impact performance',
467
- severity: 'low',
468
- fix: 'Adjust batch size',
469
- details: { current: batchSize, recommended: '100-10000' }
470
- });
471
- }
472
-
473
- // Check cache settings
474
- if (optimization.cacheEnabled) {
475
- this.results.checks.push({
476
- category: 'performance',
477
- message: 'Caching enabled',
478
- status: 'passed',
479
- details: { cacheEnabled: true }
480
- });
481
- } else {
482
- this.results.warnings.push({
483
- category: 'performance',
484
- message: 'Caching disabled may impact performance',
485
- severity: 'low',
486
- fix: 'Enable caching for better performance',
487
- action: 'node main/i18ntk-setup.js --cache-enabled'
488
- });
489
- }
490
-
491
- this.results.performance = {
492
- mode: optimization.mode,
493
- batchSize: batchSize,
494
- cacheEnabled: optimization.cacheEnabled,
495
- estimatedPerformance: this.estimatePerformance(optimization.mode)
496
- };
497
- }
498
-
499
- async validateSecuritySettings() {
500
- const security = this.config?.security || {};
501
-
502
- // Check admin PIN
503
- if (security.adminPinEnabled) {
504
- this.results.checks.push({
505
- category: 'security',
506
- message: 'Admin PIN protection enabled',
507
- status: 'passed',
508
- details: { adminPinEnabled: true }
509
- });
510
- } else {
511
- this.results.warnings.push({
512
- category: 'security',
513
- message: 'Admin PIN protection disabled',
514
- severity: 'medium',
515
- fix: 'Enable admin PIN for sensitive operations',
516
- action: 'node main/i18ntk-setup.js --security-enable'
517
- });
518
- }
519
-
520
- // Check session timeout
521
- const timeout = security.sessionTimeout;
522
- if (timeout >= 300000 && timeout <= 3600000) { // 5 minutes to 1 hour
523
- this.results.checks.push({
524
- category: 'security',
525
- message: 'Session timeout within secure range',
526
- status: 'passed',
527
- details: { timeout: timeout }
528
- });
529
- } else {
530
- this.results.warnings.push({
531
- category: 'security',
532
- message: 'Session timeout may be insecure',
533
- severity: 'medium',
534
- fix: 'Set session timeout between 5-60 minutes',
535
- action: 'node main/i18ntk-setup.js --session-timeout 1800000'
536
- });
537
- }
538
-
539
- // Check for sensitive data in locale files
540
- const sourceDir = this.config?.sourceDir;
541
- if (sourceDir && SecurityUtils.safeExistsSync(sourceDir)) {
542
- const sensitivePatterns = [
543
- /password/i,
544
- /secret/i,
545
- /api[_-]?key/i,
546
- /token/i,
547
- /private[_-]?key/i
548
- ];
549
-
550
- const files = fs.readdirSync(sourceDir);
551
- let sensitiveFound = false;
552
-
553
- for (const file of files) {
554
- const filePath = path.join(sourceDir, file);
555
- if (fs.statSync(filePath).isFile()) {
556
- const content = SecurityUtils.safeReadFileSync(filePath, path.dirname(filePath), 'utf8');
557
-
558
- for (const pattern of sensitivePatterns) {
559
- if (pattern.test(content)) {
560
- sensitiveFound = true;
561
- this.results.warnings.push({
562
- category: 'security',
563
- message: `Sensitive data detected in ${file}`,
564
- severity: 'high',
565
- fix: 'Remove sensitive data from locale files',
566
- details: { file: file, pattern: pattern.source }
567
- });
568
- }
569
- }
570
- }
571
- }
572
-
573
- if (!sensitiveFound) {
574
- this.results.checks.push({
575
- category: 'security',
576
- message: 'No sensitive data found in locale files',
577
- status: 'passed'
578
- });
579
- }
580
- }
581
-
582
- this.results.security = {
583
- adminPinEnabled: security.adminPinEnabled,
584
- sessionTimeout: security.sessionTimeout,
585
- sensitiveDataFound: sensitiveFound || false
586
- };
587
- }
588
-
589
- async validateCompatibility() {
590
- const nodeVersion = process.version;
591
- const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
592
-
593
- if (majorVersion >= 16) {
594
- this.results.checks.push({
595
- category: 'compatibility',
596
- message: 'Node.js version compatible',
597
- status: 'passed',
598
- details: { version: nodeVersion, required: '>=16' }
599
- });
600
- } else {
601
- this.results.errors.push({
602
- category: 'compatibility',
603
- message: 'Node.js version incompatible',
604
- severity: 'critical',
605
- fix: 'Upgrade Node.js to version 16 or higher',
606
- details: { current: nodeVersion, required: '>=16' }
607
- });
608
- }
609
-
610
- // Check for common compatibility issues
611
- const checks = [
612
- { name: 'fs', test: () => require('fs') },
613
- { name: 'path', test: () => require('path') },
614
- { name: 'child_process', test: () => require('child_process') }
615
- ];
616
-
617
- for (const check of checks) {
618
- try {
619
- check.test();
620
- this.results.checks.push({
621
- category: 'compatibility',
622
- message: `${check.name} module available`,
623
- status: 'passed'
624
- });
625
- } catch (error) {
626
- this.results.errors.push({
627
- category: 'compatibility',
628
- message: `${check.name} module not available`,
629
- severity: 'critical',
630
- fix: 'Check Node.js installation'
631
- });
632
- }
633
- }
634
-
635
- this.results.compatibility = {
636
- nodeVersion: nodeVersion,
637
- compatible: majorVersion >= 16,
638
- modules: checks.map(c => c.name)
639
- };
640
- }
641
-
642
- async generateValidationReport() {
643
- const reportPath = path.join(process.cwd(), 'i18ntk-validation-report.json');
644
-
645
- const report = {
646
- ...this.results,
647
- summary: {
648
- totalChecks: this.results.checks.length,
649
- totalWarnings: this.results.warnings.length,
650
- totalErrors: this.results.errors.length,
651
- status: this.results.status,
652
- nextSteps: this.generateNextSteps()
653
- }
654
- };
655
-
656
- SecurityUtils.safeWriteFileSync(reportPath, JSON.stringify(report, null, 2));
657
- console.log(`\nšŸ“‹ Validation report saved: ${reportPath}`);
658
-
659
- // Print summary
660
- console.log('\nšŸ“Š Validation Summary:');
661
- console.log('====================');
662
-
663
- if (this.results.errors.length > 0) {
664
- console.log('\nāŒ Critical Issues:');
665
- this.results.errors.forEach(error => {
666
- console.log(` - ${error.message}`);
667
- if (error.action) {
668
- console.log(` Fix: ${error.action}`);
669
- }
670
- });
671
- }
672
-
673
- if (this.results.warnings.length > 0) {
674
- console.log('\nāš ļø Warnings:');
675
- this.results.warnings.forEach(warning => {
676
- console.log(` - ${warning.message}`);
677
- if (warning.action) {
678
- console.log(` Fix: ${warning.action}`);
679
- }
680
- });
681
- }
682
-
683
- console.log('\nāœ… Passed Checks:');
684
- this.results.checks.forEach(check => {
685
- console.log(` - ${check.message}`);
686
- });
687
- }
688
-
689
- generateNextSteps() {
690
- const steps = [];
691
-
692
- if (this.results.errors.length > 0) {
693
- steps.push('Fix critical errors before proceeding');
694
- steps.push('Run setup script: node main/i18ntk-setup.js');
695
- }
696
-
697
- if (this.results.warnings.length > 0) {
698
- steps.push('Review and address warnings');
699
- steps.push('Run validation: node utils/setup-validator.js');
700
- }
701
-
702
- if (this.results.status === 'passed') {
703
- steps.push('Setup is ready! Proceed with initialization');
704
- steps.push('Run: node main/i18ntk-init.js');
705
- }
706
-
707
- return steps;
708
- }
709
- }
710
-
711
- // CLI interface
712
- if (require.main === module) {
713
- const validator = new SetupValidator();
714
- validator.validate().catch(console.error);
715
- }
716
-
717
- module.exports = SetupValidator;