ai-localize-cli 1.0.0 → 1.0.2
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/dist/cli.js +78 -77
- package/package.json +10 -10
- package/src/cli.ts +1 -1
- package/src/commands/cleanup.ts +3 -3
- package/src/commands/extract.ts +3 -3
- package/src/commands/full-migrate.ts +6 -6
- package/src/commands/init.ts +2 -2
- package/src/commands/migrate-cdn.ts +3 -3
- package/src/commands/replace-cdn.ts +5 -5
- package/src/commands/report.ts +4 -4
- package/src/commands/scan.ts +3 -3
- package/src/commands/upload-assets.ts +3 -3
- package/src/commands/validate.ts +2 -2
- package/tsup.config.ts +11 -0
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -25,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
26
|
// src/cli.ts
|
|
26
27
|
var import_commander11 = require("commander");
|
|
27
28
|
var import_chalk12 = __toESM(require("chalk"));
|
|
28
|
-
var
|
|
29
|
+
var import_ai_localize_shared5 = require("ai-localize-shared");
|
|
29
30
|
|
|
30
31
|
// src/commands/init.ts
|
|
31
32
|
var import_commander = require("commander");
|
|
@@ -50,8 +51,8 @@ function createSpinner(text) {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// src/commands/init.ts
|
|
53
|
-
var
|
|
54
|
-
var
|
|
54
|
+
var import_ai_localize_config = require("ai-localize-config");
|
|
55
|
+
var import_ai_localize_framework_detectors = require("ai-localize-framework-detectors");
|
|
55
56
|
function initCommand() {
|
|
56
57
|
return new import_commander.Command("init").description("Initialize ai-localize configuration in the current project").option("-f, --framework <type>", "Override framework detection").option("--cwd <path>", "Working directory", process.cwd()).action(async (opts) => {
|
|
57
58
|
logger.header("ai-localize init");
|
|
@@ -60,12 +61,12 @@ function initCommand() {
|
|
|
60
61
|
const cwd = opts.cwd;
|
|
61
62
|
let framework = opts.framework;
|
|
62
63
|
if (!framework) {
|
|
63
|
-
framework = (0,
|
|
64
|
+
framework = (0, import_ai_localize_framework_detectors.detectFramework)(cwd);
|
|
64
65
|
spinner.succeed("Detected framework: " + import_chalk2.default.cyan(framework));
|
|
65
66
|
} else {
|
|
66
67
|
spinner.succeed("Using framework: " + import_chalk2.default.cyan(framework));
|
|
67
68
|
}
|
|
68
|
-
const configPath = (0,
|
|
69
|
+
const configPath = (0, import_ai_localize_config.writeDefaultConfig)(cwd, framework);
|
|
69
70
|
logger.success("Config created: " + import_chalk2.default.cyan(configPath));
|
|
70
71
|
} catch (err) {
|
|
71
72
|
spinner.fail("Initialization failed");
|
|
@@ -79,25 +80,25 @@ function initCommand() {
|
|
|
79
80
|
var import_commander2 = require("commander");
|
|
80
81
|
var import_chalk3 = __toESM(require("chalk"));
|
|
81
82
|
var path = __toESM(require("path"));
|
|
82
|
-
var
|
|
83
|
-
var
|
|
84
|
-
var
|
|
83
|
+
var import_ai_localize_config2 = require("ai-localize-config");
|
|
84
|
+
var import_ai_localize_scanner = require("ai-localize-scanner");
|
|
85
|
+
var import_ai_localize_shared = require("ai-localize-shared");
|
|
85
86
|
function scanCommand() {
|
|
86
87
|
return new import_commander2.Command("scan").description("Scan project for hardcoded texts and asset references").option("--incremental", "Scan only changed files based on git diff").option("--staged", "Scan only git staged files").option("--cwd <path>", "Working directory", process.cwd()).option("--output <path>", "Output JSON file path").action(async (opts) => {
|
|
87
88
|
logger.header("ai-localize scan");
|
|
88
89
|
const spinner = createSpinner("Loading configuration...").start();
|
|
89
90
|
try {
|
|
90
91
|
const cwd = opts.cwd;
|
|
91
|
-
const { config } = await (0,
|
|
92
|
+
const { config } = await (0, import_ai_localize_config2.loadConfig)(cwd);
|
|
92
93
|
spinner.succeed("Configuration loaded");
|
|
93
94
|
let files;
|
|
94
95
|
if (opts.staged || opts.incremental) {
|
|
95
|
-
const git = new
|
|
96
|
+
const git = new import_ai_localize_scanner.GitScanner(cwd);
|
|
96
97
|
files = opts.staged ? git.getStagedFiles() : git.getChangedFiles();
|
|
97
98
|
logger.info("Changed files: " + import_chalk3.default.cyan(String(files.length)));
|
|
98
99
|
}
|
|
99
100
|
const scanSpinner = createSpinner("Scanning files...").start();
|
|
100
|
-
const scanner = new
|
|
101
|
+
const scanner = new import_ai_localize_scanner.ProjectScanner(config);
|
|
101
102
|
const result = await scanner.scan({ files });
|
|
102
103
|
scanSpinner.succeed("Scanned " + import_chalk3.default.cyan(String(result.scannedFiles)) + " files in " + import_chalk3.default.cyan(result.duration + "ms"));
|
|
103
104
|
logger.info("Hardcoded texts: " + import_chalk3.default.yellow(String(result.detectedTexts.length)));
|
|
@@ -105,7 +106,7 @@ function scanCommand() {
|
|
|
105
106
|
logger.info("Legacy CDN URLs: " + import_chalk3.default.red(String(result.legacyCdnUrls.length)));
|
|
106
107
|
if (opts.output) {
|
|
107
108
|
const outPath = path.resolve(cwd, opts.output);
|
|
108
|
-
(0,
|
|
109
|
+
(0, import_ai_localize_shared.writeJson)(outPath, result);
|
|
109
110
|
logger.success("Results saved to " + import_chalk3.default.cyan(outPath));
|
|
110
111
|
}
|
|
111
112
|
} catch (err) {
|
|
@@ -120,24 +121,24 @@ function scanCommand() {
|
|
|
120
121
|
var import_commander3 = require("commander");
|
|
121
122
|
var import_chalk4 = __toESM(require("chalk"));
|
|
122
123
|
var path2 = __toESM(require("path"));
|
|
123
|
-
var
|
|
124
|
-
var
|
|
125
|
-
var
|
|
124
|
+
var import_ai_localize_config3 = require("ai-localize-config");
|
|
125
|
+
var import_ai_localize_scanner2 = require("ai-localize-scanner");
|
|
126
|
+
var import_ai_localize_locale_engine = require("ai-localize-locale-engine");
|
|
126
127
|
function extractCommand() {
|
|
127
128
|
return new import_commander3.Command("extract").description("Extract hardcoded text to locale JSON files").option("--cwd <path>", "Working directory", process.cwd()).option("--dry-run", "Preview changes without modifying files").option("--no-merge", "Overwrite existing keys").action(async (opts) => {
|
|
128
129
|
logger.header("ai-localize extract");
|
|
129
130
|
const cwd = opts.cwd;
|
|
130
131
|
const spinner = createSpinner("Loading configuration...").start();
|
|
131
132
|
try {
|
|
132
|
-
const { config } = await (0,
|
|
133
|
+
const { config } = await (0, import_ai_localize_config3.loadConfig)(cwd);
|
|
133
134
|
spinner.succeed("Configuration loaded");
|
|
134
135
|
const ss = createSpinner("Scanning for hardcoded text...").start();
|
|
135
|
-
const scanner = new
|
|
136
|
+
const scanner = new import_ai_localize_scanner2.ProjectScanner(config);
|
|
136
137
|
const scanResult = await scanner.scan();
|
|
137
138
|
ss.succeed("Found " + import_chalk4.default.cyan(String(scanResult.detectedTexts.length)) + " texts in " + scanResult.scannedFiles + " files");
|
|
138
|
-
const uniqueTexts = (0,
|
|
139
|
+
const uniqueTexts = (0, import_ai_localize_locale_engine.deduplicateTexts)(scanResult.detectedTexts);
|
|
139
140
|
logger.info("Unique texts: " + import_chalk4.default.cyan(String(uniqueTexts.length)));
|
|
140
|
-
const extractor = new
|
|
141
|
+
const extractor = new import_ai_localize_locale_engine.LocaleExtractor({
|
|
141
142
|
defaultLanguage: config.defaultLanguage,
|
|
142
143
|
targetLanguages: config.targetLanguages,
|
|
143
144
|
namespaceSplitting: true
|
|
@@ -147,7 +148,7 @@ function extractCommand() {
|
|
|
147
148
|
logger.info("Namespaces: " + import_chalk4.default.cyan(namespaces.join(", ")));
|
|
148
149
|
if (!opts.dryRun) {
|
|
149
150
|
const localesDir = path2.resolve(cwd, config.localesDir);
|
|
150
|
-
const writer = new
|
|
151
|
+
const writer = new import_ai_localize_locale_engine.LocaleWriter({ localesDir, merge: opts.merge !== false });
|
|
151
152
|
const { written, created, merged } = writer.write(localeFiles);
|
|
152
153
|
logger.success("Wrote " + written.length + " locale files (" + created.length + " new, " + merged.length + " merged)");
|
|
153
154
|
} else {
|
|
@@ -165,18 +166,18 @@ function extractCommand() {
|
|
|
165
166
|
var import_commander4 = require("commander");
|
|
166
167
|
var import_chalk5 = __toESM(require("chalk"));
|
|
167
168
|
var path3 = __toESM(require("path"));
|
|
168
|
-
var
|
|
169
|
-
var
|
|
169
|
+
var import_ai_localize_config4 = require("ai-localize-config");
|
|
170
|
+
var import_ai_localize_validators = require("ai-localize-validators");
|
|
170
171
|
function validateCommand() {
|
|
171
172
|
return new import_commander4.Command("validate").description("Validate locale files for missing/duplicate/unused keys").option("--cwd <path>", "Working directory", process.cwd()).option("--no-unused", "Skip unused key check").option("--no-duplicates", "Skip duplicate key check").option("--no-placeholders", "Skip placeholder check").option("--fail-on-warning", "Exit with error if warnings exist").action(async (opts) => {
|
|
172
173
|
logger.header("ai-localize validate");
|
|
173
174
|
const spinner = createSpinner("Loading configuration...").start();
|
|
174
175
|
try {
|
|
175
176
|
const cwd = opts.cwd;
|
|
176
|
-
const { config } = await (0,
|
|
177
|
+
const { config } = await (0, import_ai_localize_config4.loadConfig)(cwd);
|
|
177
178
|
spinner.succeed("Configuration loaded");
|
|
178
179
|
const vs = createSpinner("Validating locale files...").start();
|
|
179
|
-
const validator = new
|
|
180
|
+
const validator = new import_ai_localize_validators.LocaleValidator({
|
|
180
181
|
localesDir: path3.resolve(cwd, config.localesDir),
|
|
181
182
|
sourceDir: path3.resolve(cwd, config.sourceDir),
|
|
182
183
|
defaultLanguage: config.defaultLanguage,
|
|
@@ -209,19 +210,19 @@ var import_commander5 = require("commander");
|
|
|
209
210
|
var import_chalk6 = __toESM(require("chalk"));
|
|
210
211
|
var path4 = __toESM(require("path"));
|
|
211
212
|
var fs = __toESM(require("fs"));
|
|
212
|
-
var
|
|
213
|
-
var
|
|
214
|
-
var
|
|
213
|
+
var import_ai_localize_config5 = require("ai-localize-config");
|
|
214
|
+
var import_ai_localize_validators2 = require("ai-localize-validators");
|
|
215
|
+
var import_ai_localize_shared2 = require("ai-localize-shared");
|
|
215
216
|
function cleanupCommand() {
|
|
216
217
|
return new import_commander5.Command("cleanup").description("Remove unused locale keys from translation files").option("--cwd <path>", "Working directory", process.cwd()).option("--dry-run", "Preview changes without modifying files").action(async (opts) => {
|
|
217
218
|
logger.header("ai-localize cleanup");
|
|
218
219
|
const spinner = createSpinner("Validating keys...").start();
|
|
219
220
|
try {
|
|
220
221
|
const cwd = opts.cwd;
|
|
221
|
-
const { config } = await (0,
|
|
222
|
+
const { config } = await (0, import_ai_localize_config5.loadConfig)(cwd);
|
|
222
223
|
const localesDir = path4.resolve(cwd, config.localesDir);
|
|
223
224
|
const sourceDir = path4.resolve(cwd, config.sourceDir);
|
|
224
|
-
const validator = new
|
|
225
|
+
const validator = new import_ai_localize_validators2.UnusedKeyValidator(localesDir, sourceDir, config.defaultLanguage);
|
|
225
226
|
const { unusedKeys } = validator.validate();
|
|
226
227
|
spinner.succeed("Found " + import_chalk6.default.yellow(String(unusedKeys.length)) + " unused keys");
|
|
227
228
|
if (unusedKeys.length === 0) {
|
|
@@ -236,7 +237,7 @@ function cleanupCommand() {
|
|
|
236
237
|
for (const nsFile of nsFiles) {
|
|
237
238
|
const ns = nsFile.replace(".json", "");
|
|
238
239
|
const fp = path4.join(defaultDir, nsFile);
|
|
239
|
-
const entries = (0,
|
|
240
|
+
const entries = (0, import_ai_localize_shared2.readJsonSafe)(fp) || {};
|
|
240
241
|
for (const key of unusedKeys) {
|
|
241
242
|
const lk = key.startsWith(ns + ".") ? key.slice(ns.length + 1) : null;
|
|
242
243
|
if (lk && lk in entries) {
|
|
@@ -244,7 +245,7 @@ function cleanupCommand() {
|
|
|
244
245
|
removed++;
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
|
-
(0,
|
|
248
|
+
(0, import_ai_localize_shared2.writeJson)(fp, entries);
|
|
248
249
|
}
|
|
249
250
|
logger.success("Removed " + removed + " unused keys");
|
|
250
251
|
} else {
|
|
@@ -262,16 +263,16 @@ function cleanupCommand() {
|
|
|
262
263
|
var import_commander6 = require("commander");
|
|
263
264
|
var import_chalk7 = __toESM(require("chalk"));
|
|
264
265
|
var path5 = __toESM(require("path"));
|
|
265
|
-
var
|
|
266
|
-
var
|
|
267
|
-
var
|
|
266
|
+
var import_ai_localize_config6 = require("ai-localize-config");
|
|
267
|
+
var import_ai_localize_scanner3 = require("ai-localize-scanner");
|
|
268
|
+
var import_ai_localize_aws_cloudfront = require("ai-localize-aws-cloudfront");
|
|
268
269
|
function migrateCdnCommand() {
|
|
269
270
|
return new import_commander6.Command("migrate-cdn").description("Migrate legacy CDN URLs to CloudFront").option("--cwd <path>", "Working directory", process.cwd()).option("--assets-dir <path>", "Local assets directory to upload").option("--dry-run", "Preview changes without executing").option("--invalidate", "Invalidate CloudFront cache after upload").action(async (opts) => {
|
|
270
271
|
logger.header("ai-localize migrate-cdn");
|
|
271
272
|
const spinner = createSpinner("Loading configuration...").start();
|
|
272
273
|
try {
|
|
273
274
|
const cwd = opts.cwd;
|
|
274
|
-
const { config } = await (0,
|
|
275
|
+
const { config } = await (0, import_ai_localize_config6.loadConfig)(cwd);
|
|
275
276
|
if (!config.aws?.bucket) {
|
|
276
277
|
spinner.fail("AWS configuration missing");
|
|
277
278
|
logger.error("Set aws.bucket and aws.distributionId in ai-localize.config.json");
|
|
@@ -279,14 +280,14 @@ function migrateCdnCommand() {
|
|
|
279
280
|
}
|
|
280
281
|
spinner.succeed("Configuration loaded");
|
|
281
282
|
const ss = createSpinner("Scanning for legacy CDN URLs...").start();
|
|
282
|
-
const scanner = new
|
|
283
|
+
const scanner = new import_ai_localize_scanner3.ProjectScanner(config);
|
|
283
284
|
const scanResult = await scanner.scan();
|
|
284
285
|
ss.succeed("Found " + import_chalk7.default.yellow(String(scanResult.legacyCdnUrls.length)) + " legacy CDN URLs");
|
|
285
286
|
if (scanResult.legacyCdnUrls.length === 0) {
|
|
286
287
|
logger.success("No legacy CDN URLs found!");
|
|
287
288
|
return;
|
|
288
289
|
}
|
|
289
|
-
const migrator = new
|
|
290
|
+
const migrator = new import_ai_localize_aws_cloudfront.CdnMigrator(config.aws);
|
|
290
291
|
const result = await migrator.migrate({
|
|
291
292
|
sourceDir: path5.resolve(cwd, config.sourceDir),
|
|
292
293
|
assetsDir: path5.resolve(cwd, opts.assetsDir),
|
|
@@ -311,22 +312,22 @@ function migrateCdnCommand() {
|
|
|
311
312
|
var import_commander7 = require("commander");
|
|
312
313
|
var import_chalk8 = __toESM(require("chalk"));
|
|
313
314
|
var path6 = __toESM(require("path"));
|
|
314
|
-
var
|
|
315
|
-
var
|
|
316
|
-
var
|
|
315
|
+
var import_ai_localize_config7 = require("ai-localize-config");
|
|
316
|
+
var import_ai_localize_aws_cloudfront2 = require("ai-localize-aws-cloudfront");
|
|
317
|
+
var import_ai_localize_shared3 = require("ai-localize-shared");
|
|
317
318
|
function uploadAssetsCommand() {
|
|
318
319
|
return new import_commander7.Command("upload-assets").description("Upload local assets to AWS S3").option("--cwd <path>", "Working directory", process.cwd()).option("--assets-dir <path>", "Directory containing assets to upload").option("--force", "Force upload even if file already exists with same hash").option("--output <path>", "Output manifest JSON path").action(async (opts) => {
|
|
319
320
|
logger.header("ai-localize upload-assets");
|
|
320
321
|
const spinner = createSpinner("Loading configuration...").start();
|
|
321
322
|
try {
|
|
322
323
|
const cwd = opts.cwd;
|
|
323
|
-
const { config } = await (0,
|
|
324
|
+
const { config } = await (0, import_ai_localize_config7.loadConfig)(cwd);
|
|
324
325
|
if (!config.aws?.bucket) {
|
|
325
326
|
spinner.fail("AWS configuration missing");
|
|
326
327
|
process.exit(1);
|
|
327
328
|
}
|
|
328
329
|
spinner.succeed("Configuration loaded");
|
|
329
|
-
const uploader = new
|
|
330
|
+
const uploader = new import_ai_localize_aws_cloudfront2.S3Uploader(config.aws);
|
|
330
331
|
const assetsDir = path6.resolve(cwd, opts.assetsDir);
|
|
331
332
|
const uploadSpinner = createSpinner("Uploading assets...").start();
|
|
332
333
|
const result = await uploader.uploadDirectory({
|
|
@@ -339,7 +340,7 @@ function uploadAssetsCommand() {
|
|
|
339
340
|
uploadSpinner.succeed("Uploaded " + import_chalk8.default.green(String(result.uploaded.length)) + " (" + result.skipped.length + " skipped)");
|
|
340
341
|
if (opts.output) {
|
|
341
342
|
const outPath = path6.resolve(cwd, opts.output);
|
|
342
|
-
(0,
|
|
343
|
+
(0, import_ai_localize_shared3.writeJson)(outPath, [...result.uploaded, ...result.skipped]);
|
|
343
344
|
logger.success("Manifest saved to " + import_chalk8.default.cyan(outPath));
|
|
344
345
|
}
|
|
345
346
|
} catch (err) {
|
|
@@ -354,24 +355,24 @@ function uploadAssetsCommand() {
|
|
|
354
355
|
var import_commander8 = require("commander");
|
|
355
356
|
var import_chalk9 = __toESM(require("chalk"));
|
|
356
357
|
var path7 = __toESM(require("path"));
|
|
357
|
-
var
|
|
358
|
-
var
|
|
359
|
-
var
|
|
360
|
-
var
|
|
358
|
+
var import_ai_localize_config8 = require("ai-localize-config");
|
|
359
|
+
var import_ai_localize_scanner4 = require("ai-localize-scanner");
|
|
360
|
+
var import_ai_localize_shared4 = require("ai-localize-shared");
|
|
361
|
+
var import_ai_localize_codemods = require("ai-localize-codemods");
|
|
361
362
|
function replaceCdnCommand() {
|
|
362
363
|
return new import_commander8.Command("replace-cdn").description("Replace legacy CDN URLs with CloudFront URLs in source files").option("--cwd <path>", "Working directory", process.cwd()).option("--manifest <path>", "Path to upload manifest JSON").option("--dry-run", "Preview changes without executing").action(async (opts) => {
|
|
363
364
|
logger.header("ai-localize replace-cdn");
|
|
364
365
|
const spinner = createSpinner("Loading configuration...").start();
|
|
365
366
|
try {
|
|
366
367
|
const cwd = opts.cwd;
|
|
367
|
-
const { config } = await (0,
|
|
368
|
+
const { config } = await (0, import_ai_localize_config8.loadConfig)(cwd);
|
|
368
369
|
spinner.succeed("Configuration loaded");
|
|
369
370
|
let assets = [];
|
|
370
371
|
if (opts.manifest) {
|
|
371
|
-
assets = (0,
|
|
372
|
+
assets = (0, import_ai_localize_shared4.readJsonSafe)(path7.resolve(cwd, opts.manifest)) || [];
|
|
372
373
|
}
|
|
373
374
|
const ss = createSpinner("Scanning for legacy CDN URLs...").start();
|
|
374
|
-
const scanner = new
|
|
375
|
+
const scanner = new import_ai_localize_scanner4.ProjectScanner(config);
|
|
375
376
|
const scanResult = await scanner.scan();
|
|
376
377
|
ss.succeed("Found " + import_chalk9.default.yellow(String(scanResult.legacyCdnUrls.length)) + " legacy CDN URLs");
|
|
377
378
|
if (scanResult.legacyCdnUrls.length === 0) {
|
|
@@ -380,7 +381,7 @@ function replaceCdnCommand() {
|
|
|
380
381
|
}
|
|
381
382
|
if (!opts.dryRun) {
|
|
382
383
|
const rs = createSpinner("Replacing URLs...").start();
|
|
383
|
-
const replacedCount = await (0,
|
|
384
|
+
const replacedCount = await (0, import_ai_localize_codemods.batchReplaceCdnUrls)(
|
|
384
385
|
path7.resolve(cwd, config.sourceDir),
|
|
385
386
|
scanResult.legacyCdnUrls,
|
|
386
387
|
assets
|
|
@@ -401,24 +402,24 @@ function replaceCdnCommand() {
|
|
|
401
402
|
var import_commander9 = require("commander");
|
|
402
403
|
var import_chalk10 = __toESM(require("chalk"));
|
|
403
404
|
var path8 = __toESM(require("path"));
|
|
404
|
-
var
|
|
405
|
-
var
|
|
406
|
-
var
|
|
407
|
-
var
|
|
405
|
+
var import_ai_localize_config9 = require("ai-localize-config");
|
|
406
|
+
var import_ai_localize_scanner5 = require("ai-localize-scanner");
|
|
407
|
+
var import_ai_localize_validators3 = require("ai-localize-validators");
|
|
408
|
+
var import_ai_localize_reporting = require("ai-localize-reporting");
|
|
408
409
|
function reportCommand() {
|
|
409
410
|
return new import_commander9.Command("report").description("Generate JSON and HTML localization reports").option("--cwd <path>", "Working directory", process.cwd()).option("--output-dir <path>", "Output directory for reports", ".ai-localize-reports").option("--no-html", "Skip HTML report generation").action(async (opts) => {
|
|
410
411
|
logger.header("ai-localize report");
|
|
411
412
|
const spinner = createSpinner("Loading configuration...").start();
|
|
412
413
|
try {
|
|
413
414
|
const cwd = opts.cwd;
|
|
414
|
-
const { config } = await (0,
|
|
415
|
+
const { config } = await (0, import_ai_localize_config9.loadConfig)(cwd);
|
|
415
416
|
spinner.succeed("Configuration loaded");
|
|
416
417
|
const ss = createSpinner("Scanning project...").start();
|
|
417
|
-
const scanner = new
|
|
418
|
+
const scanner = new import_ai_localize_scanner5.ProjectScanner(config);
|
|
418
419
|
const scanResult = await scanner.scan();
|
|
419
420
|
ss.succeed("Scanned " + scanResult.scannedFiles + " files");
|
|
420
421
|
const vs = createSpinner("Validating locale files...").start();
|
|
421
|
-
const validator = new
|
|
422
|
+
const validator = new import_ai_localize_validators3.LocaleValidator({
|
|
422
423
|
localesDir: path8.resolve(cwd, config.localesDir),
|
|
423
424
|
sourceDir: path8.resolve(cwd, config.sourceDir),
|
|
424
425
|
defaultLanguage: config.defaultLanguage,
|
|
@@ -428,12 +429,12 @@ function reportCommand() {
|
|
|
428
429
|
vs.succeed("Validation complete");
|
|
429
430
|
const outDir = path8.resolve(cwd, opts.outputDir);
|
|
430
431
|
const rs = createSpinner("Building report...").start();
|
|
431
|
-
const report = (0,
|
|
432
|
+
const report = (0, import_ai_localize_reporting.buildReport)({ scanResult, validationResult });
|
|
432
433
|
if (opts.html !== false) {
|
|
433
|
-
(0,
|
|
434
|
+
(0, import_ai_localize_reporting.generateHtmlReport)(report, outDir);
|
|
434
435
|
}
|
|
435
436
|
rs.succeed("Report generated at " + import_chalk10.default.cyan(outDir));
|
|
436
|
-
(0,
|
|
437
|
+
(0, import_ai_localize_reporting.printCliSummary)(report);
|
|
437
438
|
} catch (err) {
|
|
438
439
|
spinner.fail("Report generation failed");
|
|
439
440
|
logger.error(String(err));
|
|
@@ -446,12 +447,12 @@ function reportCommand() {
|
|
|
446
447
|
var import_commander10 = require("commander");
|
|
447
448
|
var import_chalk11 = __toESM(require("chalk"));
|
|
448
449
|
var path9 = __toESM(require("path"));
|
|
449
|
-
var
|
|
450
|
-
var
|
|
451
|
-
var
|
|
452
|
-
var
|
|
453
|
-
var
|
|
454
|
-
var
|
|
450
|
+
var import_ai_localize_config10 = require("ai-localize-config");
|
|
451
|
+
var import_ai_localize_scanner6 = require("ai-localize-scanner");
|
|
452
|
+
var import_ai_localize_locale_engine2 = require("ai-localize-locale-engine");
|
|
453
|
+
var import_ai_localize_codemods2 = require("ai-localize-codemods");
|
|
454
|
+
var import_ai_localize_validators4 = require("ai-localize-validators");
|
|
455
|
+
var import_ai_localize_reporting2 = require("ai-localize-reporting");
|
|
455
456
|
function fullMigrateCommand() {
|
|
456
457
|
return new import_commander10.Command("full-migrate").description("Run full localization pipeline: scan -> extract -> codemod -> validate -> report").option("--cwd <path>", "Working directory", process.cwd()).option("--dry-run", "Preview changes without modifying files").option("--no-codemods", "Skip codemod phase").option("--no-report", "Skip report generation").action(async (opts) => {
|
|
457
458
|
logger.header("ai-localize full-migrate");
|
|
@@ -459,15 +460,15 @@ function fullMigrateCommand() {
|
|
|
459
460
|
const dryRun = opts.dryRun;
|
|
460
461
|
try {
|
|
461
462
|
const cs = createSpinner("Loading configuration...").start();
|
|
462
|
-
const { config } = await (0,
|
|
463
|
+
const { config } = await (0, import_ai_localize_config10.loadConfig)(cwd);
|
|
463
464
|
cs.succeed("Configuration loaded");
|
|
464
465
|
const ss = createSpinner("Scanning for hardcoded text...").start();
|
|
465
|
-
const scanner = new
|
|
466
|
+
const scanner = new import_ai_localize_scanner6.ProjectScanner(config);
|
|
466
467
|
const scanResult = await scanner.scan();
|
|
467
468
|
ss.succeed("Found " + import_chalk11.default.cyan(String(scanResult.detectedTexts.length)) + " texts in " + scanResult.scannedFiles + " files");
|
|
468
469
|
const es = createSpinner("Extracting locale keys...").start();
|
|
469
|
-
const uniqueTexts = (0,
|
|
470
|
-
const extractor = new
|
|
470
|
+
const uniqueTexts = (0, import_ai_localize_locale_engine2.deduplicateTexts)(scanResult.detectedTexts);
|
|
471
|
+
const extractor = new import_ai_localize_locale_engine2.LocaleExtractor({
|
|
471
472
|
defaultLanguage: config.defaultLanguage,
|
|
472
473
|
targetLanguages: config.targetLanguages,
|
|
473
474
|
namespaceSplitting: true
|
|
@@ -475,17 +476,17 @@ function fullMigrateCommand() {
|
|
|
475
476
|
const { localeFiles, keyCount } = extractor.extract(uniqueTexts);
|
|
476
477
|
es.succeed("Generated " + import_chalk11.default.green(String(keyCount)) + " locale keys");
|
|
477
478
|
if (!dryRun) {
|
|
478
|
-
const writer = new
|
|
479
|
+
const writer = new import_ai_localize_locale_engine2.LocaleWriter({ localesDir: path9.resolve(cwd, config.localesDir), merge: true });
|
|
479
480
|
writer.write(localeFiles);
|
|
480
481
|
}
|
|
481
482
|
if (opts.codemods !== false) {
|
|
482
483
|
const ms = createSpinner("Applying i18n codemods...").start();
|
|
483
|
-
const runner = new
|
|
484
|
+
const runner = new import_ai_localize_codemods2.CodemodRunner(config);
|
|
484
485
|
const codemodResult = await runner.run(uniqueTexts, { dryRun });
|
|
485
486
|
ms.succeed("Codemods: " + import_chalk11.default.green(String(codemodResult.totalReplacements)) + " replacements in " + codemodResult.changedFiles + " files");
|
|
486
487
|
}
|
|
487
488
|
const vs = createSpinner("Validating locale files...").start();
|
|
488
|
-
const validator = new
|
|
489
|
+
const validator = new import_ai_localize_validators4.LocaleValidator({
|
|
489
490
|
localesDir: path9.resolve(cwd, config.localesDir),
|
|
490
491
|
sourceDir: path9.resolve(cwd, config.sourceDir),
|
|
491
492
|
defaultLanguage: config.defaultLanguage,
|
|
@@ -494,8 +495,8 @@ function fullMigrateCommand() {
|
|
|
494
495
|
const validationResult = validator.validate();
|
|
495
496
|
vs.succeed(validationResult.valid ? import_chalk11.default.green("Locale files valid!") : import_chalk11.default.yellow(validationResult.errors.length + " errors, " + validationResult.warnings.length + " warnings"));
|
|
496
497
|
if (opts.report !== false) {
|
|
497
|
-
const report = (0,
|
|
498
|
-
(0,
|
|
498
|
+
const report = (0, import_ai_localize_reporting2.buildReport)({ scanResult, validationResult });
|
|
499
|
+
(0, import_ai_localize_reporting2.printCliSummary)(report);
|
|
499
500
|
}
|
|
500
501
|
logger.success("Full migration complete!");
|
|
501
502
|
} catch (err) {
|
|
@@ -507,7 +508,7 @@ function fullMigrateCommand() {
|
|
|
507
508
|
|
|
508
509
|
// src/cli.ts
|
|
509
510
|
var program = new import_commander11.Command();
|
|
510
|
-
program.name("ai-localize").description(import_chalk12.default.cyan("ai-localize-core") + " \u2014 Deterministic localization + CloudFront migration platform").version(
|
|
511
|
+
program.name("ai-localize").description(import_chalk12.default.cyan("ai-localize-core") + " \u2014 Deterministic localization + CloudFront migration platform").version(import_ai_localize_shared5.PLATFORM_VERSION, "-v, --version");
|
|
511
512
|
program.addCommand(initCommand());
|
|
512
513
|
program.addCommand(scanCommand());
|
|
513
514
|
program.addCommand(extractCommand());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-localize-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "CLI for ai-localize-core: scan, extract, validate, migrate CDN",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-localize": "./dist/cli.js"
|
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
"chalk": "^5.3.0",
|
|
12
12
|
"ora": "^8.0.1",
|
|
13
13
|
"inquirer": "^9.2.12",
|
|
14
|
-
"ai-localize-
|
|
15
|
-
"ai-localize-shared": "1.0.
|
|
16
|
-
"ai-localize-
|
|
17
|
-
"ai-localize-
|
|
18
|
-
"ai-localize-scanner": "1.0.
|
|
19
|
-
"ai-localize-
|
|
20
|
-
"ai-localize-
|
|
21
|
-
"ai-localize-
|
|
22
|
-
"ai-localize-locale-engine": "1.0.
|
|
14
|
+
"ai-localize-config": "1.0.1",
|
|
15
|
+
"ai-localize-shared": "1.0.1",
|
|
16
|
+
"ai-localize-framework-detectors": "1.0.1",
|
|
17
|
+
"ai-localize-codemods": "1.0.1",
|
|
18
|
+
"ai-localize-scanner": "1.0.1",
|
|
19
|
+
"ai-localize-validators": "1.0.1",
|
|
20
|
+
"ai-localize-aws-cloudfront": "1.0.1",
|
|
21
|
+
"ai-localize-reporting": "1.0.1",
|
|
22
|
+
"ai-localize-locale-engine": "1.0.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/inquirer": "^9.0.7",
|
package/src/cli.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { PLATFORM_VERSION } from '
|
|
3
|
+
import { PLATFORM_VERSION } from 'ai-localize-shared';
|
|
4
4
|
import { initCommand } from './commands/init.js';
|
|
5
5
|
import { scanCommand } from './commands/scan.js';
|
|
6
6
|
import { extractCommand } from './commands/extract.js';
|
package/src/commands/cleanup.ts
CHANGED
|
@@ -4,9 +4,9 @@ import * as path from 'path';
|
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import { logger } from '../utils/logger.js';
|
|
6
6
|
import { createSpinner } from '../utils/spinner.js';
|
|
7
|
-
import { loadConfig } from '
|
|
8
|
-
import { UnusedKeyValidator } from '
|
|
9
|
-
import { readJsonSafe, writeJson } from '
|
|
7
|
+
import { loadConfig } from 'ai-localize-config';
|
|
8
|
+
import { UnusedKeyValidator } from 'ai-localize-validators';
|
|
9
|
+
import { readJsonSafe, writeJson } from 'ai-localize-shared';
|
|
10
10
|
|
|
11
11
|
export function cleanupCommand(): Command {
|
|
12
12
|
return new Command('cleanup')
|
package/src/commands/extract.ts
CHANGED
|
@@ -3,9 +3,9 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { ProjectScanner } from '
|
|
8
|
-
import { deduplicateTexts, LocaleExtractor, LocaleWriter } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { ProjectScanner } from 'ai-localize-scanner';
|
|
8
|
+
import { deduplicateTexts, LocaleExtractor, LocaleWriter } from 'ai-localize-locale-engine';
|
|
9
9
|
|
|
10
10
|
export function extractCommand(): Command {
|
|
11
11
|
return new Command('extract')
|
|
@@ -3,12 +3,12 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { ProjectScanner } from '
|
|
8
|
-
import { deduplicateTexts, LocaleExtractor, LocaleWriter } from '
|
|
9
|
-
import { CodemodRunner } from '
|
|
10
|
-
import { LocaleValidator } from '
|
|
11
|
-
import { buildReport, generateHtmlReport, printCliSummary } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { ProjectScanner } from 'ai-localize-scanner';
|
|
8
|
+
import { deduplicateTexts, LocaleExtractor, LocaleWriter } from 'ai-localize-locale-engine';
|
|
9
|
+
import { CodemodRunner } from 'ai-localize-codemods';
|
|
10
|
+
import { LocaleValidator } from 'ai-localize-validators';
|
|
11
|
+
import { buildReport, generateHtmlReport, printCliSummary } from 'ai-localize-reporting';
|
|
12
12
|
|
|
13
13
|
export function fullMigrateCommand(): Command {
|
|
14
14
|
return new Command('full-migrate')
|
package/src/commands/init.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { Command } from 'commander';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { logger } from '../utils/logger.js';
|
|
4
4
|
import { createSpinner } from '../utils/spinner.js';
|
|
5
|
-
import { writeDefaultConfig } from '
|
|
6
|
-
import { detectFramework } from '
|
|
5
|
+
import { writeDefaultConfig } from 'ai-localize-config';
|
|
6
|
+
import { detectFramework } from 'ai-localize-framework-detectors';
|
|
7
7
|
|
|
8
8
|
export function initCommand(): Command {
|
|
9
9
|
return new Command('init')
|
|
@@ -3,9 +3,9 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { ProjectScanner } from '
|
|
8
|
-
import { CdnMigrator } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { ProjectScanner } from 'ai-localize-scanner';
|
|
8
|
+
import { CdnMigrator } from 'ai-localize-aws-cloudfront';
|
|
9
9
|
|
|
10
10
|
export function migrateCdnCommand(): Command {
|
|
11
11
|
return new Command('migrate-cdn')
|
|
@@ -3,11 +3,11 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { ProjectScanner } from '
|
|
8
|
-
import { readJsonSafe } from '
|
|
9
|
-
import type { CloudFrontAsset } from '
|
|
10
|
-
import { batchReplaceCdnUrls } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { ProjectScanner } from 'ai-localize-scanner';
|
|
8
|
+
import { readJsonSafe } from 'ai-localize-shared';
|
|
9
|
+
import type { CloudFrontAsset } from 'ai-localize-shared';
|
|
10
|
+
import { batchReplaceCdnUrls } from 'ai-localize-codemods';
|
|
11
11
|
|
|
12
12
|
export function replaceCdnCommand(): Command {
|
|
13
13
|
return new Command('replace-cdn')
|
package/src/commands/report.ts
CHANGED
|
@@ -3,10 +3,10 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { ProjectScanner } from '
|
|
8
|
-
import { LocaleValidator } from '
|
|
9
|
-
import { buildReport, generateHtmlReport, printCliSummary } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { ProjectScanner } from 'ai-localize-scanner';
|
|
8
|
+
import { LocaleValidator } from 'ai-localize-validators';
|
|
9
|
+
import { buildReport, generateHtmlReport, printCliSummary } from 'ai-localize-reporting';
|
|
10
10
|
|
|
11
11
|
export function reportCommand(): Command {
|
|
12
12
|
return new Command('report')
|
package/src/commands/scan.ts
CHANGED
|
@@ -3,9 +3,9 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { ProjectScanner, GitScanner } from '
|
|
8
|
-
import { writeJson } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { ProjectScanner, GitScanner } from 'ai-localize-scanner';
|
|
8
|
+
import { writeJson } from 'ai-localize-shared';
|
|
9
9
|
|
|
10
10
|
export function scanCommand(): Command {
|
|
11
11
|
return new Command('scan')
|
|
@@ -3,9 +3,9 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { S3Uploader } from '
|
|
8
|
-
import { writeJson } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { S3Uploader } from 'ai-localize-aws-cloudfront';
|
|
8
|
+
import { writeJson } from 'ai-localize-shared';
|
|
9
9
|
|
|
10
10
|
export function uploadAssetsCommand(): Command {
|
|
11
11
|
return new Command('upload-assets')
|
package/src/commands/validate.ts
CHANGED
|
@@ -3,8 +3,8 @@ import chalk from 'chalk';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { createSpinner } from '../utils/spinner.js';
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { LocaleValidator } from '
|
|
6
|
+
import { loadConfig } from 'ai-localize-config';
|
|
7
|
+
import { LocaleValidator } from 'ai-localize-validators';
|
|
8
8
|
|
|
9
9
|
export function validateCommand(): Command {
|
|
10
10
|
return new Command('validate')
|