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.
- package/LICENSE +1 -1
- package/README.md +141 -1191
- package/main/i18ntk-analyze.js +65 -84
- package/main/i18ntk-backup-class.js +420 -0
- package/main/i18ntk-backup.js +3 -3
- package/main/i18ntk-complete.js +90 -65
- package/main/i18ntk-doctor.js +123 -103
- package/main/i18ntk-fixer.js +61 -725
- package/main/i18ntk-go.js +14 -15
- package/main/i18ntk-init.js +77 -26
- package/main/i18ntk-java.js +27 -32
- package/main/i18ntk-js.js +70 -68
- package/main/i18ntk-manage.js +129 -30
- package/main/i18ntk-php.js +75 -75
- package/main/i18ntk-py.js +55 -56
- package/main/i18ntk-scanner.js +59 -57
- package/main/i18ntk-setup.js +9 -404
- package/main/i18ntk-sizing.js +6 -6
- package/main/i18ntk-summary.js +21 -18
- package/main/i18ntk-ui.js +11 -10
- package/main/i18ntk-usage.js +54 -18
- package/main/i18ntk-validate.js +13 -13
- package/main/manage/commands/AnalyzeCommand.js +1124 -0
- package/main/manage/commands/BackupCommand.js +62 -0
- package/main/manage/commands/CommandRouter.js +295 -0
- package/main/manage/commands/CompleteCommand.js +61 -0
- package/main/manage/commands/DoctorCommand.js +60 -0
- package/main/manage/commands/FixerCommand.js +624 -0
- package/main/manage/commands/InitCommand.js +62 -0
- package/main/manage/commands/ScannerCommand.js +654 -0
- package/main/manage/commands/SizingCommand.js +60 -0
- package/main/manage/commands/SummaryCommand.js +61 -0
- package/main/manage/commands/UsageCommand.js +60 -0
- package/main/manage/commands/ValidateCommand.js +978 -0
- package/main/manage/index-fixed.js +1447 -0
- package/main/manage/index.js +1462 -0
- package/main/manage/managers/DebugMenu.js +140 -0
- package/main/manage/managers/InteractiveMenu.js +177 -0
- package/main/manage/managers/LanguageMenu.js +62 -0
- package/main/manage/managers/SettingsMenu.js +53 -0
- package/main/manage/services/AuthenticationService.js +263 -0
- package/main/manage/services/ConfigurationService-fixed.js +449 -0
- package/main/manage/services/ConfigurationService.js +449 -0
- package/main/manage/services/FileManagementService.js +368 -0
- package/main/manage/services/FrameworkDetectionService.js +458 -0
- package/main/manage/services/InitService.js +1051 -0
- package/main/manage/services/SetupService.js +462 -0
- package/main/manage/services/SummaryService.js +450 -0
- package/main/manage/services/UsageService.js +1502 -0
- package/package.json +32 -29
- package/runtime/enhanced.d.ts +221 -221
- package/runtime/index.d.ts +29 -29
- package/runtime/index.full.d.ts +331 -331
- package/runtime/index.js +7 -6
- package/scripts/build-lite.js +17 -17
- package/scripts/deprecate-versions.js +23 -6
- package/scripts/export-translations.js +5 -5
- package/scripts/fix-all-i18n.js +3 -3
- package/scripts/fix-and-purify-i18n.js +3 -2
- package/scripts/fix-locale-control-chars.js +110 -0
- package/scripts/lint-locales.js +80 -0
- package/scripts/locale-optimizer.js +8 -8
- package/scripts/prepublish.js +21 -21
- package/scripts/security-check.js +117 -117
- package/scripts/sync-translations.js +4 -4
- package/scripts/sync-ui-locales.js +9 -8
- package/scripts/validate-all-translations.js +8 -7
- package/scripts/verify-deprecations.js +157 -161
- package/scripts/verify-translations.js +6 -5
- package/settings/i18ntk-config.json +282 -282
- package/settings/language-config.json +5 -5
- package/settings/settings-cli.js +9 -9
- package/settings/settings-manager.js +18 -18
- package/ui-locales/de.json +2417 -2348
- package/ui-locales/en.json +2415 -2352
- package/ui-locales/es.json +2425 -2353
- package/ui-locales/fr.json +2418 -2348
- package/ui-locales/ja.json +2463 -2361
- package/ui-locales/ru.json +2463 -2359
- package/ui-locales/zh.json +2418 -2351
- package/utils/admin-auth.js +2 -2
- package/utils/admin-cli.js +297 -297
- package/utils/admin-pin.js +9 -9
- package/utils/cli-helper.js +9 -9
- package/utils/config-helper.js +73 -104
- package/utils/config-manager.js +204 -171
- package/utils/config.js +5 -4
- package/utils/env-manager.js +249 -263
- package/utils/framework-detector.js +27 -24
- package/utils/i18n-helper.js +85 -41
- package/utils/init-helper.js +152 -94
- package/utils/json-output.js +98 -98
- package/utils/mini-commander.js +179 -0
- package/utils/missing-key-validator.js +5 -5
- package/utils/plugin-loader.js +40 -29
- package/utils/prompt.js +14 -44
- package/utils/safe-json.js +40 -0
- package/utils/secure-errors.js +3 -3
- package/utils/security-check-improved.js +390 -0
- package/utils/security-config.js +5 -5
- package/utils/security-fixed.js +607 -0
- package/utils/security.js +652 -602
- package/utils/setup-enforcer.js +136 -44
- package/utils/setup-validator.js +33 -32
- package/utils/ultra-performance-optimizer.js +11 -9
- package/utils/watch-locales.js +2 -1
- package/utils/prompt-fixed.js +0 -55
- package/utils/security-check.js +0 -454
package/utils/setup-enforcer.js
CHANGED
|
@@ -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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
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
|
-
//
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
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
|
|
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
|
|
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;
|
package/utils/setup-validator.js
CHANGED
|
@@ -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 (
|
|
67
|
+
if (SecurityUtils.safeExistsSync(configPath)) {
|
|
67
68
|
try {
|
|
68
|
-
this.config = JSON.parse(
|
|
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 (
|
|
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 (!
|
|
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: ['
|
|
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 (
|
|
262
|
+
if (SecurityUtils.safeExistsSync(packageJsonPath)) {
|
|
262
263
|
try {
|
|
263
|
-
const packageJson = JSON.parse(
|
|
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 (
|
|
301
|
-
const requirements =
|
|
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 (
|
|
328
|
-
const goMod =
|
|
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 (
|
|
355
|
-
const pom =
|
|
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 (
|
|
381
|
+
if (SecurityUtils.safeExistsSync(composerPath)) {
|
|
381
382
|
try {
|
|
382
|
-
const composer = JSON.parse(
|
|
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 &&
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
293
|
-
const results = await this.processFiles(filePaths);
|
|
294
|
-
const end =
|
|
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
|
+
}
|
package/utils/watch-locales.js
CHANGED
|
@@ -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 (!
|
|
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));
|
package/utils/prompt-fixed.js
DELETED
|
@@ -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;
|