i18ntk 1.10.2 → 2.0.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.
Files changed (108) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +141 -1191
  3. package/main/i18ntk-analyze.js +65 -84
  4. package/main/i18ntk-backup-class.js +420 -0
  5. package/main/i18ntk-backup.js +3 -3
  6. package/main/i18ntk-complete.js +90 -65
  7. package/main/i18ntk-doctor.js +123 -103
  8. package/main/i18ntk-fixer.js +61 -725
  9. package/main/i18ntk-go.js +14 -15
  10. package/main/i18ntk-init.js +77 -26
  11. package/main/i18ntk-java.js +27 -32
  12. package/main/i18ntk-js.js +70 -68
  13. package/main/i18ntk-manage.js +129 -30
  14. package/main/i18ntk-php.js +75 -75
  15. package/main/i18ntk-py.js +55 -56
  16. package/main/i18ntk-scanner.js +59 -57
  17. package/main/i18ntk-setup.js +9 -404
  18. package/main/i18ntk-sizing.js +6 -6
  19. package/main/i18ntk-summary.js +21 -18
  20. package/main/i18ntk-ui.js +11 -10
  21. package/main/i18ntk-usage.js +54 -18
  22. package/main/i18ntk-validate.js +13 -13
  23. package/main/manage/commands/AnalyzeCommand.js +1124 -0
  24. package/main/manage/commands/BackupCommand.js +62 -0
  25. package/main/manage/commands/CommandRouter.js +295 -0
  26. package/main/manage/commands/CompleteCommand.js +61 -0
  27. package/main/manage/commands/DoctorCommand.js +60 -0
  28. package/main/manage/commands/FixerCommand.js +624 -0
  29. package/main/manage/commands/InitCommand.js +62 -0
  30. package/main/manage/commands/ScannerCommand.js +654 -0
  31. package/main/manage/commands/SizingCommand.js +60 -0
  32. package/main/manage/commands/SummaryCommand.js +61 -0
  33. package/main/manage/commands/UsageCommand.js +60 -0
  34. package/main/manage/commands/ValidateCommand.js +978 -0
  35. package/main/manage/index-fixed.js +1447 -0
  36. package/main/manage/index.js +1462 -0
  37. package/main/manage/managers/DebugMenu.js +140 -0
  38. package/main/manage/managers/InteractiveMenu.js +177 -0
  39. package/main/manage/managers/LanguageMenu.js +62 -0
  40. package/main/manage/managers/SettingsMenu.js +53 -0
  41. package/main/manage/services/AuthenticationService.js +263 -0
  42. package/main/manage/services/ConfigurationService-fixed.js +449 -0
  43. package/main/manage/services/ConfigurationService.js +449 -0
  44. package/main/manage/services/FileManagementService.js +368 -0
  45. package/main/manage/services/FrameworkDetectionService.js +458 -0
  46. package/main/manage/services/InitService.js +1051 -0
  47. package/main/manage/services/SetupService.js +462 -0
  48. package/main/manage/services/SummaryService.js +450 -0
  49. package/main/manage/services/UsageService.js +1502 -0
  50. package/package.json +32 -29
  51. package/runtime/enhanced.d.ts +221 -221
  52. package/runtime/index.d.ts +29 -29
  53. package/runtime/index.full.d.ts +331 -331
  54. package/runtime/index.js +7 -6
  55. package/scripts/build-lite.js +17 -17
  56. package/scripts/deprecate-versions.js +23 -6
  57. package/scripts/export-translations.js +5 -5
  58. package/scripts/fix-all-i18n.js +3 -3
  59. package/scripts/fix-and-purify-i18n.js +3 -2
  60. package/scripts/fix-locale-control-chars.js +110 -0
  61. package/scripts/lint-locales.js +80 -0
  62. package/scripts/locale-optimizer.js +8 -8
  63. package/scripts/prepublish.js +21 -21
  64. package/scripts/security-check.js +117 -117
  65. package/scripts/sync-translations.js +4 -4
  66. package/scripts/sync-ui-locales.js +9 -8
  67. package/scripts/validate-all-translations.js +8 -7
  68. package/scripts/verify-deprecations.js +157 -161
  69. package/scripts/verify-translations.js +6 -5
  70. package/settings/i18ntk-config.json +282 -282
  71. package/settings/language-config.json +5 -5
  72. package/settings/settings-cli.js +9 -9
  73. package/settings/settings-manager.js +18 -18
  74. package/ui-locales/de.json +2417 -2348
  75. package/ui-locales/en.json +2415 -2352
  76. package/ui-locales/es.json +2425 -2353
  77. package/ui-locales/fr.json +2418 -2348
  78. package/ui-locales/ja.json +2463 -2361
  79. package/ui-locales/ru.json +2463 -2359
  80. package/ui-locales/zh.json +2418 -2351
  81. package/utils/admin-auth.js +2 -2
  82. package/utils/admin-cli.js +297 -297
  83. package/utils/admin-pin.js +9 -9
  84. package/utils/cli-helper.js +9 -9
  85. package/utils/config-helper.js +73 -104
  86. package/utils/config-manager.js +204 -171
  87. package/utils/config.js +5 -4
  88. package/utils/env-manager.js +249 -263
  89. package/utils/framework-detector.js +27 -24
  90. package/utils/i18n-helper.js +85 -41
  91. package/utils/init-helper.js +152 -94
  92. package/utils/json-output.js +98 -98
  93. package/utils/mini-commander.js +179 -0
  94. package/utils/missing-key-validator.js +5 -5
  95. package/utils/plugin-loader.js +40 -29
  96. package/utils/prompt.js +14 -44
  97. package/utils/safe-json.js +40 -0
  98. package/utils/secure-errors.js +3 -3
  99. package/utils/security-check-improved.js +390 -0
  100. package/utils/security-config.js +5 -5
  101. package/utils/security-fixed.js +607 -0
  102. package/utils/security.js +652 -602
  103. package/utils/setup-enforcer.js +136 -44
  104. package/utils/setup-validator.js +33 -32
  105. package/utils/ultra-performance-optimizer.js +11 -9
  106. package/utils/watch-locales.js +2 -1
  107. package/utils/prompt-fixed.js +0 -55
  108. package/utils/security-check.js +0 -454
@@ -11,22 +11,43 @@ const { getIcon } = require('./terminal-icons');
11
11
  const fs = require('fs');
12
12
  const path = require('path');
13
13
  const { blue, yellow, gray, cyan, green, red } = require('./colors-new');
14
+ const SecurityUtils = require('./security');
14
15
 
15
16
  class SetupEnforcer {
16
17
  static _setupCheckInProgress = false;
17
18
  static _setupCheckPromise = null;
18
19
 
19
- static checkSetupComplete() {
20
- const configManager = require('./config-manager');
21
- const configPath = configManager.CONFIG_PATH;
22
-
23
- if (!fs.existsSync(configPath)) {
24
- this.handleMissingSetup();
25
- return;
20
+ /**
21
+ * Detect if running in non-interactive environment
22
+ * @returns {boolean} - True if non-interactive
23
+ */
24
+ static isNonInteractive() {
25
+ return !process.stdout.isTTY ||
26
+ !process.stdin.isTTY ||
27
+ process.env.CI === 'true' ||
28
+ process.env.CONTINUOUS_INTEGRATION === 'true' ||
29
+ process.env.NODE_ENV === 'test' ||
30
+ process.env.npm_lifecycle_event === 'test' ||
31
+ Boolean(process.env.NO_INTERACTIVE);
32
+ }
33
+
34
+ static checkSetupComplete() {
35
+ // Avoid circular dependency - use direct path resolution
36
+ const path = require('path');
37
+ const configPath = path.join(process.cwd(), '.i18ntk-config');
38
+ const exists = SecurityUtils.safeExistsSync(configPath);
39
+ if (!exists) {
40
+ this.handleMissingSetup();
41
+ return;
26
42
  }
27
43
 
28
44
  try {
29
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
45
+ const configRaw = SecurityUtils.safeReadFileSync(configPath, path.dirname(configPath), 'utf8');
46
+ const config = SecurityUtils.safeParseJSON(configRaw);
47
+ if (!config || typeof config !== 'object') {
48
+ this.handleInvalidConfig();
49
+ return;
50
+ }
30
51
 
31
52
  // Check if setup has been explicitly marked as completed
32
53
  if (config.setup && config.setup.completed === true) {
@@ -34,7 +55,7 @@ class SetupEnforcer {
34
55
  }
35
56
 
36
57
  // Fallback: check if config has required fields (for backward compatibility)
37
- if (!config.version || !config.sourceDir || !config.detectedFramework) {
58
+ if (!config.version || !config.sourceDir || (!config.detectedFramework && !(config.framework && config.framework.detected !== false))) {
38
59
  this.handleIncompleteSetup();
39
60
  return;
40
61
  }
@@ -51,29 +72,47 @@ class SetupEnforcer {
51
72
  console.log(yellow('Welcome to i18n Toolkit! This appears to be your first time running the toolkit.'));
52
73
  console.log(gray('Setup is required to configure your project for internationalization management.'));
53
74
  console.log('');
54
-
55
- // Use readline for interactive prompt
75
+
76
+ // Check if running in non-interactive environment
77
+ if (SetupEnforcer.isNonInteractive()) {
78
+ console.log(yellow('āš ļø Non-interactive environment detected.'));
79
+ console.log(gray('Please run setup manually:'));
80
+ console.log(cyan(' npm run i18ntk-setup'));
81
+ console.log(gray('Or set NO_INTERACTIVE=false to force interactive mode.'));
82
+ process.exit(1);
83
+ }
84
+
85
+ // Use readline for interactive prompt with timeout
56
86
  const readline = require('readline');
57
87
  const rl = readline.createInterface({
58
88
  input: process.stdin,
59
89
  output: process.stdout
60
90
  });
61
-
91
+
62
92
  return new Promise((resolve, reject) => {
93
+ // Set timeout for user input (30 seconds)
94
+ const timeout = setTimeout(() => {
95
+ console.log(yellow('\nā° Timeout reached - no response received.'));
96
+ console.log(gray('Setup cancelled. Run "npm run i18ntk-setup" when you\'re ready.'));
97
+ rl.close();
98
+ process.exit(1);
99
+ }, 30000); // 30 second timeout
100
+
63
101
  rl.question(cyan('Would you like to run setup now? (Y/n): '), async (answer) => {
102
+ clearTimeout(timeout);
64
103
  rl.close();
65
-
104
+
66
105
  if (answer.toLowerCase() === 'n' || answer.toLowerCase() === 'no') {
67
106
  console.log(gray('Setup cancelled. Run "npm run i18ntk-setup" when you\'re ready.'));
68
107
  process.exit(0);
69
108
  }
70
-
109
+
71
110
  console.log(green(`${getIcon('rocket')} Running setup...`));
72
-
111
+
73
112
  try {
74
113
  // Import and run setup directly
75
114
  const setupPath = path.join(__dirname, '..', 'main', 'i18ntk-setup.js');
76
- if (fs.existsSync(setupPath)) {
115
+ if (SecurityUtils.safeExistsSync(setupPath)) {
77
116
  try {
78
117
  const setup = require(setupPath);
79
118
  // Use the run function which properly instantiates the class
@@ -112,27 +151,45 @@ static async handleIncompleteSetup() {
112
151
  console.log(yellow('Your setup appears to be incomplete or outdated.'));
113
152
  console.log(gray('This might happen after updating to a new version.'));
114
153
  console.log('');
115
-
154
+
155
+ // Check if running in non-interactive environment
156
+ if (SetupEnforcer.isNonInteractive()) {
157
+ console.log(yellow('āš ļø Non-interactive environment detected.'));
158
+ console.log(gray('Please run setup manually:'));
159
+ console.log(cyan(' npm run i18ntk-setup'));
160
+ console.log(gray('Or set NO_INTERACTIVE=false to force interactive mode.'));
161
+ process.exit(1);
162
+ }
163
+
116
164
  const readline = require('readline');
117
165
  const rl = readline.createInterface({
118
166
  input: process.stdin,
119
167
  output: process.stdout
120
168
  });
121
-
169
+
122
170
  return new Promise((resolve, reject) => {
171
+ // Set timeout for user input (30 seconds)
172
+ const timeout = setTimeout(() => {
173
+ console.log(yellow('\nā° Timeout reached - no response received.'));
174
+ console.log(gray('Setup cancelled. Run "npm run i18ntk-setup" when you\'re ready.'));
175
+ rl.close();
176
+ process.exit(1);
177
+ }, 30000); // 30 second timeout
178
+
123
179
  rl.question(cyan('Would you like to re-run setup? (Y/n): '), async (answer) => {
180
+ clearTimeout(timeout);
124
181
  rl.close();
125
-
182
+
126
183
  if (answer.toLowerCase() === 'n' || answer.toLowerCase() === 'no') {
127
184
  console.log(gray('Operation cancelled.'));
128
185
  process.exit(0);
129
186
  }
130
-
187
+
131
188
  console.log(green(`${getIcon('rocket')} Running setup...`));
132
-
189
+
133
190
  try {
134
191
  const setupPath = path.join(__dirname, '..', 'main', 'i18ntk-setup.js');
135
- if (fs.existsSync(setupPath)) {
192
+ if (SecurityUtils.safeExistsSync(setupPath)) {
136
193
  try {
137
194
  const setup = require(setupPath);
138
195
  // Use the run function which properly instantiates the class
@@ -169,27 +226,45 @@ static async handleInvalidConfig() {
169
226
  console.log(yellow('Your configuration file appears to be corrupted or invalid.'));
170
227
  console.log(gray('This might happen due to file corruption or manual editing.'));
171
228
  console.log('');
172
-
229
+
230
+ // Check if running in non-interactive environment
231
+ if (SetupEnforcer.isNonInteractive()) {
232
+ console.log(yellow('āš ļø Non-interactive environment detected.'));
233
+ console.log(gray('Please run setup manually:'));
234
+ console.log(cyan(' npm run i18ntk-setup'));
235
+ console.log(gray('Or set NO_INTERACTIVE=false to force interactive mode.'));
236
+ process.exit(1);
237
+ }
238
+
173
239
  const readline = require('readline');
174
240
  const rl = readline.createInterface({
175
241
  input: process.stdin,
176
242
  output: process.stdout
177
243
  });
178
-
244
+
179
245
  return new Promise((resolve, reject) => {
246
+ // Set timeout for user input (30 seconds)
247
+ const timeout = setTimeout(() => {
248
+ console.log(yellow('\nā° Timeout reached - no response received.'));
249
+ console.log(gray('Setup cancelled. Run "npm run i18ntk-setup" when you\'re ready.'));
250
+ rl.close();
251
+ process.exit(1);
252
+ }, 30000); // 30 second timeout
253
+
180
254
  rl.question(cyan('Would you like to re-run setup to fix this? (Y/n): '), async (answer) => {
255
+ clearTimeout(timeout);
181
256
  rl.close();
182
-
257
+
183
258
  if (answer.toLowerCase() === 'n' || answer.toLowerCase() === 'no') {
184
259
  console.log(gray('Operation cancelled.'));
185
260
  process.exit(0);
186
261
  }
187
-
262
+
188
263
  console.log(green(`${getIcon('rocket')} Running setup...`));
189
-
264
+
190
265
  try {
191
266
  const setupPath = path.join(__dirname, '..', 'main', 'i18ntk-setup.js');
192
- if (fs.existsSync(setupPath)) {
267
+ if (SecurityUtils.safeExistsSync(setupPath)) {
193
268
  try {
194
269
  const setup = require(setupPath);
195
270
  // Use the run function which properly instantiates the class
@@ -223,6 +298,7 @@ static async handleInvalidConfig() {
223
298
 
224
299
  static checkSetupCompleteAsync() {
225
300
  // Return existing promise if already in progress
301
+ // Add debugging for setup check
226
302
  if (SetupEnforcer._setupCheckInProgress && SetupEnforcer._setupCheckPromise) {
227
303
  return SetupEnforcer._setupCheckPromise;
228
304
  }
@@ -230,22 +306,30 @@ static async handleInvalidConfig() {
230
306
  // Create new promise and store it
231
307
  SetupEnforcer._setupCheckInProgress = true;
232
308
  SetupEnforcer._setupCheckPromise = new Promise(async (resolve, reject) => {
233
- try {
234
- const configPath = path.join(process.cwd(), 'settings', 'i18ntk-config.json');
235
-
236
- if (!fs.existsSync(configPath)) {
237
- await SetupEnforcer.handleMissingSetup();
238
- // After setup is done, re-check the config
239
- if (fs.existsSync(configPath)) {
240
- resolve(true);
241
- } else {
309
+ try {
310
+ // Avoid circular dependency - use direct path resolution
311
+ const path = require('path');
312
+ const configPath = path.join(process.cwd(), '.i18ntk-config');
313
+ const exists = SecurityUtils.safeExistsSync(configPath);
314
+ if (!exists) {
315
+ await SetupEnforcer.handleMissingSetup();
316
+ // After setup is done, re-check the config
317
+ const existsAfter = SecurityUtils.safeExistsSync(configPath);
318
+ if (existsAfter) {
319
+ resolve(true);
320
+ } else {
242
321
  process.exit(0);
243
322
  }
244
323
  return;
245
324
  }
246
325
 
247
326
  try {
248
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
327
+ const configRaw = SecurityUtils.safeReadFileSync(configPath, path.dirname(configPath), 'utf8');
328
+ const config = SecurityUtils.safeParseJSON(configRaw);
329
+ if (!config || typeof config !== 'object') {
330
+ await SetupEnforcer.handleInvalidConfig();
331
+ process.exit(0);
332
+ }
249
333
 
250
334
  // Check if setup has been explicitly marked as completed
251
335
  if (config.setup && config.setup.completed === true) {
@@ -254,13 +338,17 @@ static async handleInvalidConfig() {
254
338
  }
255
339
 
256
340
  // Fallback: check if config has required fields (for backward compatibility)
257
- if (!config.version || !config.sourceDir || !config.detectedFramework) {
341
+ if (!config.version || !config.sourceDir || (!config.detectedFramework && !(config.framework && config.framework.detected !== false))) {
258
342
  await SetupEnforcer.handleIncompleteSetup();
259
343
  // After setup is done, re-check the config
260
- const newConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
344
+ const newConfigRaw = SecurityUtils.safeReadFileSync(configPath, path.dirname(configPath), 'utf8');
345
+ const newConfig = SecurityUtils.safeParseJSON(newConfigRaw);
346
+ if (!newConfig || typeof newConfig !== 'object') {
347
+ process.exit(0);
348
+ }
261
349
  if (newConfig.setup && newConfig.setup.completed === true) {
262
350
  resolve(true);
263
- } else if (newConfig.version && newConfig.sourceDir && newConfig.detectedFramework) {
351
+ } else if (newConfig.version && newConfig.sourceDir && (newConfig.detectedFramework || (newConfig.framework && newConfig.framework.detected !== false))) {
264
352
  resolve(true);
265
353
  } else {
266
354
  process.exit(0);
@@ -273,10 +361,14 @@ static async handleInvalidConfig() {
273
361
  await SetupEnforcer.handleInvalidConfig();
274
362
  // After setup is done, re-check the config
275
363
  try {
276
- const newConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
364
+ const newConfigRaw = SecurityUtils.safeReadFileSync(configPath, path.dirname(configPath), 'utf8');
365
+ const newConfig = SecurityUtils.safeParseJSON(newConfigRaw);
366
+ if (!newConfig || typeof newConfig !== 'object') {
367
+ process.exit(0);
368
+ }
277
369
  if (newConfig.setup && newConfig.setup.completed === true) {
278
370
  resolve(true);
279
- } else if (newConfig.version && newConfig.sourceDir && newConfig.detectedFramework) {
371
+ } else if (newConfig.version && newConfig.sourceDir && (newConfig.detectedFramework || (newConfig.framework && newConfig.framework.detected !== false))) {
280
372
  resolve(true);
281
373
  } else {
282
374
  process.exit(0);
@@ -296,4 +388,4 @@ static async handleInvalidConfig() {
296
388
  }
297
389
  }
298
390
 
299
- module.exports = SetupEnforcer;
391
+ module.exports = SetupEnforcer;
@@ -9,6 +9,7 @@
9
9
 
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
+ const SecurityUtils = require('./security');
12
13
 
13
14
 
14
15
  class SetupValidator {
@@ -63,9 +64,9 @@ class SetupValidator {
63
64
  async loadConfiguration() {
64
65
  const configPath = path.join(process.cwd(), 'i18ntk-config.json');
65
66
 
66
- if (fs.existsSync(configPath)) {
67
+ if (SecurityUtils.safeExistsSync(configPath)) {
67
68
  try {
68
- this.config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
69
+ this.config = JSON.parse(SecurityUtils.safeReadFileSync(configPath, path.dirname(configPath), 'utf8'));
69
70
  this.results.checks.push({
70
71
  category: 'configuration',
71
72
  message: 'Configuration file found and valid',
@@ -151,7 +152,7 @@ class SetupValidator {
151
152
  const outputDir = this.config.outputDir;
152
153
 
153
154
  // Check source directory
154
- if (fs.existsSync(sourceDir)) {
155
+ if (SecurityUtils.safeExistsSync(sourceDir)) {
155
156
  const stats = fs.statSync(sourceDir);
156
157
  if (stats.isDirectory()) {
157
158
  const files = fs.readdirSync(sourceDir);
@@ -193,7 +194,7 @@ class SetupValidator {
193
194
  }
194
195
 
195
196
  // Check output directory
196
- if (!fs.existsSync(outputDir)) {
197
+ if (!SecurityUtils.safeExistsSync(outputDir)) {
197
198
  fs.mkdirSync(outputDir, { recursive: true });
198
199
  this.results.checks.push({
199
200
  category: 'directories',
@@ -229,11 +230,11 @@ class SetupValidator {
229
230
  recommended: ['django', 'flask-babel', 'babel'],
230
231
  dev: ['pytest']
231
232
  },
232
- go: {
233
- required: [],
234
- recommended: ['github.com/nicksnyder/go-i18n/v2/i18n'],
235
- dev: []
236
- },
233
+ go: {
234
+ required: [],
235
+ recommended: ['go-i18n'],
236
+ dev: []
237
+ },
237
238
  java: {
238
239
  required: [],
239
240
  recommended: ['spring-boot-starter-web', 'spring-context'],
@@ -258,9 +259,9 @@ class SetupValidator {
258
259
  switch (language) {
259
260
  case 'javascript':
260
261
  case 'typescript':
261
- if (fs.existsSync(packageJsonPath)) {
262
+ if (SecurityUtils.safeExistsSync(packageJsonPath)) {
262
263
  try {
263
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
264
+ const packageJson = JSON.parse(SecurityUtils.safeReadFileSync(packageJsonPath, path.dirname(packageJsonPath), 'utf8'));
264
265
  const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
265
266
 
266
267
  const recommended = dependencies[language].recommended;
@@ -297,8 +298,8 @@ class SetupValidator {
297
298
  break;
298
299
 
299
300
  case 'python':
300
- if (fs.existsSync(requirementsPath)) {
301
- const requirements = fs.readFileSync(requirementsPath, 'utf8');
301
+ if (SecurityUtils.safeExistsSync(requirementsPath)) {
302
+ const requirements = SecurityUtils.safeReadFileSync(requirementsPath, path.dirname(requirementsPath), 'utf8');
302
303
  const recommended = dependencies[language].recommended;
303
304
  const found = recommended.filter(dep => requirements.includes(dep));
304
305
 
@@ -324,8 +325,8 @@ class SetupValidator {
324
325
  break;
325
326
 
326
327
  case 'go':
327
- if (fs.existsSync(goModPath)) {
328
- const goMod = fs.readFileSync(goModPath, 'utf8');
328
+ if (SecurityUtils.safeExistsSync(goModPath)) {
329
+ const goMod = SecurityUtils.safeReadFileSync(goModPath, path.dirname(goModPath), 'utf8');
329
330
  const recommended = dependencies[language].recommended;
330
331
  const found = recommended.filter(dep => goMod.includes(dep));
331
332
 
@@ -351,8 +352,8 @@ class SetupValidator {
351
352
  break;
352
353
 
353
354
  case 'java':
354
- if (fs.existsSync(pomPath)) {
355
- const pom = fs.readFileSync(pomPath, 'utf8');
355
+ if (SecurityUtils.safeExistsSync(pomPath)) {
356
+ const pom = SecurityUtils.safeReadFileSync(pomPath, path.dirname(pomPath), 'utf8');
356
357
  const recommended = dependencies[language].recommended;
357
358
  const found = recommended.filter(dep => pom.includes(dep));
358
359
 
@@ -377,9 +378,9 @@ class SetupValidator {
377
378
  break;
378
379
 
379
380
  case 'php':
380
- if (fs.existsSync(composerPath)) {
381
+ if (SecurityUtils.safeExistsSync(composerPath)) {
381
382
  try {
382
- const composer = JSON.parse(fs.readFileSync(composerPath, 'utf8'));
383
+ const composer = JSON.parse(SecurityUtils.safeReadFileSync(composerPath, path.dirname(composerPath), 'utf8'));
383
384
  const allDeps = { ...composer.require, ...composer['require-dev'] };
384
385
 
385
386
  const recommended = dependencies[language].recommended;
@@ -417,6 +418,15 @@ class SetupValidator {
417
418
  }
418
419
  }
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
+
420
430
  async validatePerformanceSettings() {
421
431
  if (!this.config) return;
422
432
 
@@ -486,15 +496,6 @@ class SetupValidator {
486
496
  };
487
497
  }
488
498
 
489
- estimatePerformance(mode) {
490
- const performanceMap = {
491
- extreme: { improvement: 87, time: '38.90ms' },
492
- ultra: { improvement: 78, time: '336.8ms' },
493
- optimized: { improvement: 45, time: '847.9ms' }
494
- };
495
- return performanceMap[mode] || { improvement: 0, time: 'unknown' };
496
- }
497
-
498
499
  async validateSecuritySettings() {
499
500
  const security = this.config?.security || {};
500
501
 
@@ -537,7 +538,7 @@ class SetupValidator {
537
538
 
538
539
  // Check for sensitive data in locale files
539
540
  const sourceDir = this.config?.sourceDir;
540
- if (sourceDir && fs.existsSync(sourceDir)) {
541
+ if (sourceDir && SecurityUtils.safeExistsSync(sourceDir)) {
541
542
  const sensitivePatterns = [
542
543
  /password/i,
543
544
  /secret/i,
@@ -552,7 +553,7 @@ class SetupValidator {
552
553
  for (const file of files) {
553
554
  const filePath = path.join(sourceDir, file);
554
555
  if (fs.statSync(filePath).isFile()) {
555
- const content = fs.readFileSync(filePath, 'utf8');
556
+ const content = SecurityUtils.safeReadFileSync(filePath, path.dirname(filePath), 'utf8');
556
557
 
557
558
  for (const pattern of sensitivePatterns) {
558
559
  if (pattern.test(content)) {
@@ -652,7 +653,7 @@ class SetupValidator {
652
653
  }
653
654
  };
654
655
 
655
- fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
656
+ SecurityUtils.safeWriteFileSync(reportPath, JSON.stringify(report, null, 2));
656
657
  console.log(`\nšŸ“‹ Validation report saved: ${reportPath}`);
657
658
 
658
659
  // Print summary
@@ -713,4 +714,4 @@ if (require.main === module) {
713
714
  validator.validate().catch(console.error);
714
715
  }
715
716
 
716
- module.exports = SetupValidator;
717
+ module.exports = SetupValidator;
@@ -4,9 +4,11 @@
4
4
  * Targets: 35ms processing for 200k keys with <10MB memory
5
5
  */
6
6
 
7
- const fs = require('fs').promises;
8
- const path = require('path');
9
- const { performance } = require('perf_hooks');
7
+ const fs = require('fs').promises;
8
+ const path = require('path');
9
+ const perf = (globalThis.performance && typeof globalThis.performance.now === 'function')
10
+ ? globalThis.performance
11
+ : { now: () => Date.now() };
10
12
 
11
13
  class UltraPerformanceOptimizer {
12
14
  constructor(options = {}) {
@@ -42,7 +44,7 @@ class UltraPerformanceOptimizer {
42
44
  * Initialize ultra-optimization
43
45
  */
44
46
  async initialize() {
45
- this.stats.startTime = performance.now();
47
+ this.stats.startTime = perf.now();
46
48
  this.stats.memoryStart = process.memoryUsage();
47
49
 
48
50
  // Force garbage collection if available
@@ -265,7 +267,7 @@ class UltraPerformanceOptimizer {
265
267
  * Get performance statistics
266
268
  */
267
269
  getStats() {
268
- this.stats.endTime = performance.now();
270
+ this.stats.endTime = perf.now();
269
271
  this.stats.memoryEnd = process.memoryUsage();
270
272
 
271
273
  const processingTime = this.stats.endTime - this.stats.startTime;
@@ -289,9 +291,9 @@ class UltraPerformanceOptimizer {
289
291
  async runUltraBenchmark(filePaths) {
290
292
  console.log('šŸš€ Starting Ultra-Extreme Performance Benchmark...');
291
293
 
292
- const start = performance.now();
293
- const results = await this.processFiles(filePaths);
294
- const end = performance.now();
294
+ const start = perf.now();
295
+ const results = await this.processFiles(filePaths);
296
+ const end = perf.now();
295
297
 
296
298
  const stats = this.getStats();
297
299
 
@@ -347,4 +349,4 @@ if (require.main === module) {
347
349
  console.error('āŒ Benchmark failed:', error);
348
350
  process.exit(1);
349
351
  });
350
- }
352
+ }
@@ -1,8 +1,9 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const SecurityUtils = require('./security');
3
4
 
4
5
  function watchDirectory(dir, callback, watchers) {
5
- if (!fs.existsSync(dir)) return;
6
+ if (!SecurityUtils.safeExistsSync(dir)) return;
6
7
  const watcher = fs.watch(dir, (event, filename) => {
7
8
  if (filename && filename.endsWith('.json')) {
8
9
  callback(path.join(dir, filename));
@@ -1,55 +0,0 @@
1
- const readline = require('readline');
2
- const { logger } = require('./logger');
3
-
4
- class Prompt {
5
- constructor() {
6
- this.rl = readline.createInterface({
7
- input: process.stdin,
8
- output: process.stdout
9
- });
10
- }
11
-
12
- close() {
13
- this.rl.close();
14
- }
15
-
16
- async question(questionText) {
17
- return new Promise((resolve) => {
18
- this.rl.question(questionText, (answer) => {
19
- resolve(answer.trim());
20
- });
21
- });
22
- }
23
-
24
- async confirm(questionText, defaultValue = false) {
25
- const answer = await this.question(`${questionText} (${defaultValue ? 'Y/n' : 'y/N'}) `);
26
- if (answer === '') return defaultValue;
27
- return /^y|yes$/i.test(answer);
28
- }
29
-
30
- async select(questionText, choices, defaultIndex = 0) {
31
- logger.log(`\n${questionText}:`);
32
- choices.forEach((choice, index) => {
33
- logger.log(` ${index + 1}. ${choice}`);
34
- });
35
-
36
- while (true) {
37
- const answer = await this.question(`\nSelect an option (1-${choices.length}): `);
38
- const selected = parseInt(answer, 10) - 1;
39
- if (!isNaN(selected) && selected >= 0 && selected < choices.length) {
40
- return selected;
41
- }
42
- logger.log('Invalid selection. Please try again.');
43
- }
44
- }
45
-
46
- async input(questionText, defaultValue = '') {
47
- const answer = await this.question(`${questionText}${defaultValue ? ` [${defaultValue}]` : ''}: `);
48
- return answer || defaultValue;
49
- }
50
- }
51
-
52
- const prompt = new Prompt();
53
- process.on('exit', () => prompt.close());
54
-
55
- module.exports = prompt;