@translation-cms/sync 1.2.9 → 1.2.12
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/README.md +304 -151
- package/dist/api.d.ts +79 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +151 -0
- package/dist/api.js.map +1 -0
- package/dist/bin.js +51 -17
- package/dist/bin.js.map +1 -1
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +18 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pull.d.ts +7 -0
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +15 -2
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +16 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +10 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +23 -4
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/watch.d.ts +14 -0
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +23 -3
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/config-internals/args.d.ts +11 -0
- package/dist/config/config-internals/args.d.ts.map +1 -0
- package/dist/config/config-internals/args.js +22 -0
- package/dist/config/config-internals/args.js.map +1 -0
- package/dist/config/config-internals/env.d.ts +10 -0
- package/dist/config/config-internals/env.d.ts.map +1 -0
- package/dist/config/config-internals/env.js +35 -0
- package/dist/config/config-internals/env.js.map +1 -0
- package/dist/config/config-internals/file.d.ts +11 -0
- package/dist/config/config-internals/file.d.ts.map +1 -0
- package/dist/config/config-internals/file.js +28 -0
- package/dist/config/config-internals/file.js.map +1 -0
- package/dist/config/config-internals/resolve.d.ts +21 -0
- package/dist/config/config-internals/resolve.d.ts.map +1 -0
- package/dist/config/config-internals/resolve.js +73 -0
- package/dist/config/config-internals/resolve.js.map +1 -0
- package/dist/config/config-internals/root.d.ts +9 -0
- package/dist/config/config-internals/root.d.ts.map +1 -0
- package/dist/config/config-internals/root.js +22 -0
- package/dist/config/config-internals/root.js.map +1 -0
- package/dist/config/config-internals/types.d.ts +83 -0
- package/dist/config/config-internals/types.d.ts.map +1 -0
- package/dist/config/config-internals/types.js +9 -0
- package/dist/config/config-internals/types.js.map +1 -0
- package/dist/config/resolve-config.d.ts +9 -90
- package/dist/config/resolve-config.d.ts.map +1 -1
- package/dist/config/resolve-config.js +7 -123
- package/dist/config/resolve-config.js.map +1 -1
- package/dist/core/api-internals/pull.d.ts +9 -1
- package/dist/core/api-internals/pull.d.ts.map +1 -1
- package/dist/core/api-internals/pull.js +41 -28
- package/dist/core/api-internals/pull.js.map +1 -1
- package/dist/core/api-internals/sync.d.ts +9 -2
- package/dist/core/api-internals/sync.d.ts.map +1 -1
- package/dist/core/api-internals/sync.js +18 -2
- package/dist/core/api-internals/sync.js.map +1 -1
- package/dist/core/cache-internals/format.d.ts +16 -0
- package/dist/core/cache-internals/format.d.ts.map +1 -1
- package/dist/core/cache-internals/format.js +17 -0
- package/dist/core/cache-internals/format.js.map +1 -1
- package/dist/core/cache-internals/params.d.ts.map +1 -1
- package/dist/core/cache-internals/params.js +24 -24
- package/dist/core/cache-internals/params.js.map +1 -1
- package/dist/core/cache-internals/pull.d.ts +12 -0
- package/dist/core/cache-internals/pull.d.ts.map +1 -1
- package/dist/core/cache-internals/pull.js +13 -0
- package/dist/core/cache-internals/pull.js.map +1 -1
- package/dist/core/cache-internals/sync.d.ts +23 -0
- package/dist/core/cache-internals/sync.d.ts.map +1 -1
- package/dist/core/cache-internals/sync.js +33 -0
- package/dist/core/cache-internals/sync.js.map +1 -1
- package/dist/core/cache-internals/types.d.ts +20 -0
- package/dist/core/cache-internals/types.d.ts.map +1 -1
- package/dist/core/scanner-internals/ast.d.ts +23 -5
- package/dist/core/scanner-internals/ast.d.ts.map +1 -1
- package/dist/core/scanner-internals/ast.js +25 -5
- package/dist/core/scanner-internals/ast.js.map +1 -1
- package/dist/core/scanner-internals/file-walker.d.ts +3 -2
- package/dist/core/scanner-internals/file-walker.d.ts.map +1 -1
- package/dist/core/scanner-internals/file-walker.js +10 -12
- package/dist/core/scanner-internals/file-walker.js.map +1 -1
- package/dist/core/scanner-internals/import-resolver.d.ts +9 -1
- package/dist/core/scanner-internals/import-resolver.d.ts.map +1 -1
- package/dist/core/scanner-internals/import-resolver.js +58 -63
- package/dist/core/scanner-internals/import-resolver.js.map +1 -1
- package/dist/core/scanner-internals/key-extractor.d.ts +12 -8
- package/dist/core/scanner-internals/key-extractor.d.ts.map +1 -1
- package/dist/core/scanner-internals/key-extractor.js +125 -97
- package/dist/core/scanner-internals/key-extractor.js.map +1 -1
- package/dist/core/scanner-internals/route-detector.d.ts +16 -8
- package/dist/core/scanner-internals/route-detector.d.ts.map +1 -1
- package/dist/core/scanner-internals/route-detector.js +37 -33
- package/dist/core/scanner-internals/route-detector.js.map +1 -1
- package/dist/core/scanner.d.ts.map +1 -1
- package/dist/core/scanner.js +25 -8
- package/dist/core/scanner.js.map +1 -1
- package/dist/next.d.ts +28 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +65 -0
- package/dist/next.js.map +1 -0
- package/dist/preview/internals/highlight.d.ts +16 -7
- package/dist/preview/internals/highlight.d.ts.map +1 -1
- package/dist/preview/internals/highlight.js +71 -60
- package/dist/preview/internals/highlight.js.map +1 -1
- package/dist/scaffold/intenrals/scaffold.d.ts +17 -0
- package/dist/scaffold/intenrals/scaffold.d.ts.map +1 -1
- package/dist/scaffold/intenrals/scaffold.js +19 -0
- package/dist/scaffold/intenrals/scaffold.js.map +1 -1
- package/package.json +16 -3
package/dist/commands/status.js
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import { scanProject } from '../core/scanner.js';
|
|
2
2
|
import { serializeNamespaces, loadSyncCache, computeDiff, formatPreviewRoutes, } from '../core/cache.js';
|
|
3
|
+
/**
|
|
4
|
+
* `status` command — scans the project for translation keys and compares
|
|
5
|
+
* the result against the last sync cache (.cms-sync-cache.json).
|
|
6
|
+
*
|
|
7
|
+
* Outputs a human-readable diff showing:
|
|
8
|
+
* + keys that are new since the last sync
|
|
9
|
+
* - keys that have been removed
|
|
10
|
+
* ~ keys whose preview routes have changed
|
|
11
|
+
* = keys that are unchanged
|
|
12
|
+
*
|
|
13
|
+
* Does not write anything — safe to run at any time.
|
|
14
|
+
*/
|
|
3
15
|
export function runStatus(root, scanOpts) {
|
|
4
16
|
console.log(`Scanning project: ${root}`);
|
|
5
17
|
const namespaces = scanProject(root, scanOpts);
|
|
18
|
+
// Flatten the NamespaceMap into a plain serializable object and get the total key count
|
|
6
19
|
const { serialized, totalKeys } = serializeNamespaces(namespaces);
|
|
7
20
|
const namespaceCount = Object.keys(serialized).length;
|
|
8
21
|
console.log(`\nFound ${totalKeys} key(s) across ${namespaceCount} namespace(s): ${Object.keys(serialized).join(', ')}`);
|
|
22
|
+
// Load the baseline written by the last successful sync
|
|
9
23
|
const cached = loadSyncCache(root);
|
|
10
24
|
if (!cached) {
|
|
11
25
|
console.log('\nNo sync cache found (.cms-sync-cache.json). Run sync first to establish a baseline.');
|
|
12
26
|
return;
|
|
13
27
|
}
|
|
28
|
+
// Diff current scan against the cached snapshot
|
|
14
29
|
const diff = computeDiff(serialized, cached);
|
|
15
30
|
console.log('\nStatus vs last sync:');
|
|
16
31
|
console.log(` + ${diff.added.length} new key(s)`);
|
|
@@ -35,6 +50,7 @@ export function runStatus(root, scanOpts) {
|
|
|
35
50
|
console.log(` ~ ${namespace}:${key} [${formatPreviewRoutes(before)}] -> [${formatPreviewRoutes(after)}]`);
|
|
36
51
|
}
|
|
37
52
|
}
|
|
53
|
+
// Only prompt to sync if there are actual changes
|
|
38
54
|
const total = diff.added.length + diff.removed.length + diff.routesChanged.length;
|
|
39
55
|
if (total > 0) {
|
|
40
56
|
console.log('\nRun "sync-translations sync" to push these changes.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EACH,mBAAmB,EACnB,aAAa,EACb,WAAW,EACX,mBAAmB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,QAAqB;IACzD,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/sync.d.ts
CHANGED
|
@@ -10,5 +10,15 @@ export interface SyncCommandOptions {
|
|
|
10
10
|
/** User-configured route params from config file (merged into mock data). */
|
|
11
11
|
userRouteParams?: Record<string, Record<string, string>>;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* `sync` command — the main push/pull cycle:
|
|
15
|
+
*
|
|
16
|
+
* 1. Scan the project for translation keys and their preview routes.
|
|
17
|
+
* 2. Auto-generate mock route params for any dynamic routes (e.g. /[slug]).
|
|
18
|
+
* If a mockDataPath is configured, write a TS file with the merged params
|
|
19
|
+
* so the CMS can render live previews.
|
|
20
|
+
* 3. POST the discovered keys to the CMS (dry-run: report only, no writes).
|
|
21
|
+
* 4. Pull the latest published translations back to disk (skipped on dry-run).
|
|
22
|
+
*/
|
|
13
23
|
export declare function runSync(root: string, config: Config, scanOpts: ScanOptions, opts: SyncCommandOptions): Promise<void>;
|
|
14
24
|
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAY,MAAM,oBAAoB,CAAC;AAQ7E,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,wBAAsB,OAAO,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAY,MAAM,oBAAoB,CAAC;AAQ7E,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAsDf"}
|
package/dist/commands/sync.js
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import { scanProject, routeKey } from '../core/scanner.js';
|
|
2
2
|
import { postToSync, pullTranslations } from '../core/api.js';
|
|
3
3
|
import { generateRouteParams, saveRouteParamsCache, writeMockDataFile, } from '../core/cache.js';
|
|
4
|
+
/**
|
|
5
|
+
* `sync` command — the main push/pull cycle:
|
|
6
|
+
*
|
|
7
|
+
* 1. Scan the project for translation keys and their preview routes.
|
|
8
|
+
* 2. Auto-generate mock route params for any dynamic routes (e.g. /[slug]).
|
|
9
|
+
* If a mockDataPath is configured, write a TS file with the merged params
|
|
10
|
+
* so the CMS can render live previews.
|
|
11
|
+
* 3. POST the discovered keys to the CMS (dry-run: report only, no writes).
|
|
12
|
+
* 4. Pull the latest published translations back to disk (skipped on dry-run).
|
|
13
|
+
*/
|
|
4
14
|
export async function runSync(root, config, scanOpts, opts) {
|
|
5
15
|
console.log(`Scanning project: ${root}`);
|
|
6
16
|
const namespaces = scanProject(root, scanOpts);
|
|
7
|
-
//
|
|
17
|
+
// Collect every unique route string found across all keys so we can
|
|
18
|
+
// generate placeholder params for dynamic segments (e.g. [slug], [id]).
|
|
8
19
|
const detectedRoutes = new Set();
|
|
9
20
|
for (const keyMap of Object.values(namespaces)) {
|
|
10
21
|
for (const routes of keyMap.values()) {
|
|
11
22
|
for (const route of routes) {
|
|
23
|
+
// routeKey normalises PreviewRoute objects to plain strings
|
|
12
24
|
const routeStr = routeKey(route);
|
|
13
25
|
detectedRoutes.add(routeStr);
|
|
14
26
|
}
|
|
@@ -17,22 +29,29 @@ export async function runSync(root, config, scanOpts, opts) {
|
|
|
17
29
|
if (detectedRoutes.size > 0) {
|
|
18
30
|
const autoParams = generateRouteParams(Array.from(detectedRoutes));
|
|
19
31
|
if (Object.keys(autoParams).length > 0) {
|
|
32
|
+
// Persist the auto-generated params to cache so subsequent scans
|
|
33
|
+
// can reuse them without re-deriving them from scratch
|
|
20
34
|
saveRouteParamsCache(root, autoParams);
|
|
21
35
|
console.log(`[route-params] Auto-generated params for ${Object.keys(autoParams).length} dynamic routes`);
|
|
22
36
|
if (opts.mockDataPath) {
|
|
23
|
-
// Merge auto-generated with user-configured params (user wins)
|
|
24
|
-
const merged = {
|
|
37
|
+
// Merge auto-generated with user-configured params (user wins on conflict)
|
|
38
|
+
const merged = {
|
|
39
|
+
...autoParams,
|
|
40
|
+
...(opts.userRouteParams ?? {}),
|
|
41
|
+
};
|
|
25
42
|
writeMockDataFile(root, merged, opts.mockDataPath);
|
|
26
43
|
}
|
|
27
44
|
}
|
|
28
45
|
}
|
|
46
|
+
// Push discovered keys to the CMS; dry-run mode only prints a report
|
|
29
47
|
await postToSync(config, namespaces, {
|
|
30
48
|
root,
|
|
31
49
|
force: opts.force,
|
|
32
50
|
dryRun: opts.dryRun,
|
|
33
51
|
reportPath: opts.reportPath,
|
|
34
52
|
});
|
|
35
|
-
//
|
|
53
|
+
// Pull translations back to disk after a successful push.
|
|
54
|
+
// Skip when dry-running — there's nothing new to pull yet.
|
|
36
55
|
if (!opts.dryRun) {
|
|
37
56
|
await pullTranslations(config, {
|
|
38
57
|
outputDir: opts.outputDir,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAoB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EACH,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,GACpB,MAAM,kBAAkB,CAAC;AAa1B,MAAM,CAAC,KAAK,UAAU,OAAO,CACzB,IAAY,EACZ,MAAc,EACd,QAAqB,EACrB,IAAwB;IAExB,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE/C,
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAoB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EACH,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,GACpB,MAAM,kBAAkB,CAAC;AAa1B;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CACzB,IAAY,EACZ,MAAc,EACd,QAAqB,EACrB,IAAwB;IAExB,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE/C,oEAAoE;IACpE,wEAAwE;IACxE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IACzC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBACzB,4DAA4D;gBAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACjC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACjC,CAAC;QACL,CAAC;IACL,CAAC;IAED,IAAI,cAAc,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;QACnE,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,iEAAiE;YACjE,uDAAuD;YACvD,oBAAoB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CACP,4CAA4C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,iBAAiB,CAC9F,CAAC;YAEF,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,2EAA2E;gBAC3E,MAAM,MAAM,GAAG;oBACX,GAAG,UAAU;oBACb,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC;iBAClC,CAAC;gBACF,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YACvD,CAAC;QACL,CAAC;IACL,CAAC;IAED,qEAAqE;IACrE,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE;QACjC,IAAI;QACJ,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAI,CAAC,UAAU;KAC9B,CAAC,CAAC;IAEH,0DAA0D;IAC1D,2DAA2D;IAC3D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;SACpB,CAAC,CAAC;IACP,CAAC;AACL,CAAC"}
|
package/dist/commands/watch.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import type { Config } from '../config/resolve-config.js';
|
|
2
2
|
import { type ScanOptions } from '../core/scanner.js';
|
|
3
|
+
/**
|
|
4
|
+
* `watch` command — runs a full sync on startup, then re-syncs automatically
|
|
5
|
+
* whenever a source file changes.
|
|
6
|
+
*
|
|
7
|
+
* Flow on each change:
|
|
8
|
+
* 1. Debounce 500 ms to coalesce rapid saves (e.g. editor auto-format).
|
|
9
|
+
* 2. Scan the project for translation keys.
|
|
10
|
+
* 3. POST discovered keys to the CMS (force — bypass TTL cache).
|
|
11
|
+
* 4. Pull the latest translations back to disk (force).
|
|
12
|
+
*
|
|
13
|
+
* Concurrent syncs are prevented by the `running` guard — if a sync is
|
|
14
|
+
* already in progress when a new change fires, the new event is dropped.
|
|
15
|
+
* Ctrl+C closes the watcher cleanly before exiting.
|
|
16
|
+
*/
|
|
3
17
|
export declare function runWatch(root: string, config: Config, outputDir: string, scanOpts: ScanOptions): Promise<void>;
|
|
4
18
|
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGnE,wBAAsB,QAAQ,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,WAAW,GACtB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGnE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,WAAW,GACtB,OAAO,CAAC,IAAI,CAAC,CA0Df"}
|
package/dist/commands/watch.js
CHANGED
|
@@ -2,11 +2,27 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import { scanProject } from '../core/scanner.js';
|
|
4
4
|
import { postToSync, pullTranslations } from '../core/api.js';
|
|
5
|
+
/**
|
|
6
|
+
* `watch` command — runs a full sync on startup, then re-syncs automatically
|
|
7
|
+
* whenever a source file changes.
|
|
8
|
+
*
|
|
9
|
+
* Flow on each change:
|
|
10
|
+
* 1. Debounce 500 ms to coalesce rapid saves (e.g. editor auto-format).
|
|
11
|
+
* 2. Scan the project for translation keys.
|
|
12
|
+
* 3. POST discovered keys to the CMS (force — bypass TTL cache).
|
|
13
|
+
* 4. Pull the latest translations back to disk (force).
|
|
14
|
+
*
|
|
15
|
+
* Concurrent syncs are prevented by the `running` guard — if a sync is
|
|
16
|
+
* already in progress when a new change fires, the new event is dropped.
|
|
17
|
+
* Ctrl+C closes the watcher cleanly before exiting.
|
|
18
|
+
*/
|
|
5
19
|
export async function runWatch(root, config, outputDir, scanOpts) {
|
|
6
20
|
console.log(`[watch] Watching ${root} for changes...`);
|
|
7
21
|
console.log('[watch] Press Ctrl+C to stop.\n');
|
|
22
|
+
// Only react to source files — ignore CSS, JSON, lock files, etc.
|
|
8
23
|
const sourceExtensions = new Set(scanOpts.sourceExtensions ?? ['.ts', '.tsx', '.js', '.jsx']);
|
|
9
24
|
let debounce = null;
|
|
25
|
+
// Prevents overlapping syncs if a change fires while a sync is still running
|
|
10
26
|
let running = false;
|
|
11
27
|
const runSync = async () => {
|
|
12
28
|
if (running)
|
|
@@ -14,25 +30,28 @@ export async function runWatch(root, config, outputDir, scanOpts) {
|
|
|
14
30
|
running = true;
|
|
15
31
|
try {
|
|
16
32
|
const namespaces = scanProject(root, scanOpts);
|
|
33
|
+
// force: true bypasses the TTL cache so changes are always pushed/pulled
|
|
17
34
|
await postToSync(config, namespaces, { root, force: true });
|
|
18
35
|
await pullTranslations(config, { outputDir, force: true });
|
|
19
36
|
}
|
|
20
37
|
catch (err) {
|
|
38
|
+
// Log errors without crashing the watcher process
|
|
21
39
|
console.error('[watch] Sync error:', err instanceof Error ? err.message : String(err));
|
|
22
40
|
}
|
|
23
41
|
finally {
|
|
24
42
|
running = false;
|
|
25
43
|
}
|
|
26
44
|
};
|
|
27
|
-
//
|
|
45
|
+
// Run an initial sync so the local dictionaries are up-to-date before watching
|
|
28
46
|
await runSync();
|
|
29
|
-
//
|
|
47
|
+
// fs.watch with recursive:true covers the entire tree in one watcher instance
|
|
30
48
|
const watcher = fs.watch(root, { recursive: true }, (_evt, filename) => {
|
|
31
49
|
if (!filename)
|
|
32
50
|
return;
|
|
33
51
|
const ext = path.extname(filename);
|
|
34
52
|
if (!sourceExtensions.has(ext))
|
|
35
53
|
return;
|
|
54
|
+
// Coalesce rapid saves within 500 ms into a single sync run
|
|
36
55
|
if (debounce)
|
|
37
56
|
clearTimeout(debounce);
|
|
38
57
|
debounce = setTimeout(() => {
|
|
@@ -40,12 +59,13 @@ export async function runWatch(root, config, outputDir, scanOpts) {
|
|
|
40
59
|
void runSync();
|
|
41
60
|
}, 500);
|
|
42
61
|
});
|
|
62
|
+
// Clean up the watcher before exiting on Ctrl+C
|
|
43
63
|
process.on('SIGINT', () => {
|
|
44
64
|
watcher.close();
|
|
45
65
|
console.log('\n[watch] Stopped.');
|
|
46
66
|
process.exit(0);
|
|
47
67
|
});
|
|
48
|
-
//
|
|
68
|
+
// Hold the event loop open indefinitely — the watcher keeps us alive until SIGINT
|
|
49
69
|
await new Promise(() => undefined);
|
|
50
70
|
}
|
|
51
71
|
//# sourceMappingURL=watch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE9D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC1B,IAAY,EACZ,MAAc,EACd,SAAiB,EACjB,QAAqB;IAErB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,iBAAiB,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAC5B,QAAQ,CAAC,gBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAC9D,CAAC;IAEF,IAAI,QAAQ,GAAyC,IAAI,CAAC;IAC1D,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACtC,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC;YACD,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC/C,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,gBAAgB,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CACT,qBAAqB,EACrB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACnD,CAAC;QACN,CAAC;gBAAS,CAAC;YACP,OAAO,GAAG,KAAK,CAAC;QACpB,CAAC;IACL,CAAC,CAAC;IAEF
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE9D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC1B,IAAY,EACZ,MAAc,EACd,SAAiB,EACjB,QAAqB;IAErB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,iBAAiB,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,kEAAkE;IAClE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAC5B,QAAQ,CAAC,gBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAC9D,CAAC;IAEF,IAAI,QAAQ,GAAyC,IAAI,CAAC;IAC1D,6EAA6E;IAC7E,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACtC,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC;YACD,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC/C,yEAAyE;YACzE,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,gBAAgB,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,kDAAkD;YAClD,OAAO,CAAC,KAAK,CACT,qBAAqB,EACrB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACnD,CAAC;QACN,CAAC;gBAAS,CAAC;YACP,OAAO,GAAG,KAAK,CAAC;QACpB,CAAC;IACL,CAAC,CAAC;IAEF,+EAA+E;IAC/E,MAAM,OAAO,EAAE,CAAC;IAEhB,8EAA8E;IAC9E,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;QACnE,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAEvC,4DAA4D;QAC5D,IAAI,QAAQ;YAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;QACrC,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE;YACvB,OAAO,CAAC,GAAG,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;YACpD,KAAK,OAAO,EAAE,CAAC;QACnB,CAAC,EAAE,GAAG,CAAC,CAAC;IACZ,CAAC,CAAC,CAAC;IAEH,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACtB,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,kFAAkF;IAClF,MAAM,IAAI,OAAO,CAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses CLI arguments that override resolved config values.
|
|
3
|
+
*/
|
|
4
|
+
import type { Config } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Scan process.argv for --project-id, --api-key, and --cms-url flags.
|
|
7
|
+
* Returns only the fields that were explicitly provided — missing flags are
|
|
8
|
+
* omitted so they can be overridden by lower-priority sources (env vars, file).
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseArgs(): Partial<Config>;
|
|
11
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../../src/config/config-internals/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAU3C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses CLI arguments that override resolved config values.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Scan process.argv for --project-id, --api-key, and --cms-url flags.
|
|
6
|
+
* Returns only the fields that were explicitly provided — missing flags are
|
|
7
|
+
* omitted so they can be overridden by lower-priority sources (env vars, file).
|
|
8
|
+
*/
|
|
9
|
+
export function parseArgs() {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const result = {};
|
|
12
|
+
for (let i = 0; i < args.length; i++) {
|
|
13
|
+
if (args[i] === '--project-id' && args[i + 1])
|
|
14
|
+
result.projectId = args[++i];
|
|
15
|
+
if (args[i] === '--api-key' && args[i + 1])
|
|
16
|
+
result.apiKey = args[++i];
|
|
17
|
+
if (args[i] === '--cms-url' && args[i + 1])
|
|
18
|
+
result.cmsUrl = args[++i];
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../../src/config/config-internals/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,MAAM,UAAU,SAAS;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACzC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACtE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads .env.local files and parses them into a key/value map.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Parse a .env.local file at the given root into a plain key/value map.
|
|
6
|
+
* Skips blank lines and comments. Strips surrounding quotes from values.
|
|
7
|
+
* Returns an empty object when the file does not exist — never throws.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadEnvLocal(root: string): Record<string, string>;
|
|
10
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/config/config-internals/env.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBjE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads .env.local files and parses them into a key/value map.
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
/**
|
|
7
|
+
* Parse a .env.local file at the given root into a plain key/value map.
|
|
8
|
+
* Skips blank lines and comments. Strips surrounding quotes from values.
|
|
9
|
+
* Returns an empty object when the file does not exist — never throws.
|
|
10
|
+
*/
|
|
11
|
+
export function loadEnvLocal(root) {
|
|
12
|
+
const envPath = path.join(root, '.env.local');
|
|
13
|
+
if (!fs.existsSync(envPath))
|
|
14
|
+
return {};
|
|
15
|
+
const vars = {};
|
|
16
|
+
const lines = fs.readFileSync(envPath, 'utf-8').split('\n');
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
// Skip blank lines and comments
|
|
20
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
21
|
+
continue;
|
|
22
|
+
const eq = trimmed.indexOf('=');
|
|
23
|
+
if (eq === -1)
|
|
24
|
+
continue;
|
|
25
|
+
const key = trimmed.slice(0, eq).trim();
|
|
26
|
+
// Strip surrounding single or double quotes from the value
|
|
27
|
+
const value = trimmed
|
|
28
|
+
.slice(eq + 1)
|
|
29
|
+
.trim()
|
|
30
|
+
.replace(/^["']|["']$/g, '');
|
|
31
|
+
vars[key] = value;
|
|
32
|
+
}
|
|
33
|
+
return vars;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/config/config-internals/env.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvC,MAAM,IAAI,GAA2B,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,gCAAgC;QAChC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClD,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,2DAA2D;QAC3D,MAAM,KAAK,GAAG,OAAO;aAChB,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;aACb,IAAI,EAAE;aACN,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the project-level config file (.translationsrc.json / translations.config.json).
|
|
3
|
+
*/
|
|
4
|
+
import { type TranslationsConfig } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Load project-level config from .translationsrc.json or translations.config.json.
|
|
7
|
+
* Searches the given root directory and returns the first file found.
|
|
8
|
+
* Returns an empty object when no config file is found — never throws.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadConfigFile(root: string): TranslationsConfig;
|
|
11
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../../src/config/config-internals/file.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAqB/D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the project-level config file (.translationsrc.json / translations.config.json).
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { CONFIG_FILENAMES } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Load project-level config from .translationsrc.json or translations.config.json.
|
|
9
|
+
* Searches the given root directory and returns the first file found.
|
|
10
|
+
* Returns an empty object when no config file is found — never throws.
|
|
11
|
+
*/
|
|
12
|
+
export function loadConfigFile(root) {
|
|
13
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
14
|
+
const filePath = path.join(root, filename);
|
|
15
|
+
if (!fs.existsSync(filePath))
|
|
16
|
+
continue;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
19
|
+
console.log(`[config] Loaded config from ${filename}`);
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
console.warn(`[config] Failed to parse ${filename}: ${err instanceof Error ? err.message : String(err)}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../../src/config/config-internals/file.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAA2B,MAAM,YAAY,CAAC;AAEvE;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,KAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEvC,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACrB,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CACf,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;YACvD,OAAO,MAAM,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CACR,4BAA4B,QAAQ,KAChC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACnD,EAAE,CACL,CAAC;QACN,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the final runtime Config and route params by merging all sources.
|
|
3
|
+
*
|
|
4
|
+
* Priority order (highest → lowest):
|
|
5
|
+
* CLI args > env vars > config file
|
|
6
|
+
*/
|
|
7
|
+
import type { Config, TranslationsConfig } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the runtime Config from CLI args, env vars, and the file-based config.
|
|
10
|
+
* Reads both root .env.local and apps/web/.env.local (for monorepo setups where
|
|
11
|
+
* NEXT_PUBLIC_* vars are defined next to the Next.js app).
|
|
12
|
+
* Exits the process with an error message if any required value is missing.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveConfig(cwd?: string, fileConfig?: TranslationsConfig): Config;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve route params for the scanner by merging auto-generated params
|
|
17
|
+
* (from the cache written by the last sync) with user-configured params.
|
|
18
|
+
* User config takes precedence on conflict.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveRouteParams(cwd?: string, fileConfig?: TranslationsConfig): Record<string, Record<string, string>>;
|
|
21
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/config/config-internals/resolve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,aAAa,CACzB,GAAG,CAAC,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,kBAAkB,GAChC,MAAM,CA8CR;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAC9B,GAAG,CAAC,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,kBAAkB,GAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAWxC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the final runtime Config and route params by merging all sources.
|
|
3
|
+
*
|
|
4
|
+
* Priority order (highest → lowest):
|
|
5
|
+
* CLI args > env vars > config file
|
|
6
|
+
*/
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { loadRouteParamsCache } from '../../core/cache.js';
|
|
9
|
+
import { loadEnvLocal } from './env.js';
|
|
10
|
+
import { parseArgs } from './args.js';
|
|
11
|
+
import { findProjectRoot } from './root.js';
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the runtime Config from CLI args, env vars, and the file-based config.
|
|
14
|
+
* Reads both root .env.local and apps/web/.env.local (for monorepo setups where
|
|
15
|
+
* NEXT_PUBLIC_* vars are defined next to the Next.js app).
|
|
16
|
+
* Exits the process with an error message if any required value is missing.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveConfig(cwd, fileConfig) {
|
|
19
|
+
const root = cwd ?? findProjectRoot();
|
|
20
|
+
// Load root .env.local first, then apps/web/.env.local as fallback
|
|
21
|
+
// for NEXT_PUBLIC_* vars already configured there (monorepo support).
|
|
22
|
+
const rootEnv = loadEnvLocal(root);
|
|
23
|
+
const webEnv = loadEnvLocal(path.join(root, 'apps', 'web'));
|
|
24
|
+
const cliArgs = parseArgs();
|
|
25
|
+
const projectId = cliArgs.projectId ??
|
|
26
|
+
rootEnv['NEXT_PUBLIC_CMS_PROJECT_ID'] ??
|
|
27
|
+
webEnv['NEXT_PUBLIC_CMS_PROJECT_ID'] ??
|
|
28
|
+
fileConfig?.projectId ??
|
|
29
|
+
'';
|
|
30
|
+
// CMS_SYNC_API_KEY is preferred over the public anon key for CLI use
|
|
31
|
+
const apiKey = cliArgs.apiKey ??
|
|
32
|
+
rootEnv['CMS_SYNC_API_KEY'] ??
|
|
33
|
+
rootEnv['NEXT_PUBLIC_CMS_ANON_KEY'] ??
|
|
34
|
+
webEnv['CMS_SYNC_API_KEY'] ??
|
|
35
|
+
webEnv['NEXT_PUBLIC_CMS_ANON_KEY'] ??
|
|
36
|
+
fileConfig?.apiKey ??
|
|
37
|
+
'';
|
|
38
|
+
const cmsUrl = cliArgs.cmsUrl ??
|
|
39
|
+
rootEnv['NEXT_PUBLIC_CMS_URL'] ??
|
|
40
|
+
webEnv['NEXT_PUBLIC_CMS_URL'] ??
|
|
41
|
+
fileConfig?.cmsUrl ??
|
|
42
|
+
'';
|
|
43
|
+
// Collect all missing required values and fail with a clear error message
|
|
44
|
+
const missing = [];
|
|
45
|
+
if (!projectId)
|
|
46
|
+
missing.push('--project-id / NEXT_PUBLIC_CMS_PROJECT_ID');
|
|
47
|
+
if (!apiKey)
|
|
48
|
+
missing.push('--api-key / NEXT_PUBLIC_CMS_ANON_KEY');
|
|
49
|
+
if (!cmsUrl)
|
|
50
|
+
missing.push('--cms-url / NEXT_PUBLIC_CMS_URL');
|
|
51
|
+
if (missing.length > 0) {
|
|
52
|
+
console.error('Missing required config:');
|
|
53
|
+
for (const m of missing)
|
|
54
|
+
console.error(` ${m}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
return { projectId, apiKey, cmsUrl };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolve route params for the scanner by merging auto-generated params
|
|
61
|
+
* (from the cache written by the last sync) with user-configured params.
|
|
62
|
+
* User config takes precedence on conflict.
|
|
63
|
+
*/
|
|
64
|
+
export function resolveRouteParams(cwd, fileConfig) {
|
|
65
|
+
const root = cwd ?? findProjectRoot();
|
|
66
|
+
// Auto-generated params are written to cache by the sync command
|
|
67
|
+
const cached = loadRouteParamsCache(root);
|
|
68
|
+
const autoParams = cached?.generated ?? {};
|
|
69
|
+
// User's manual config overrides auto-generated values
|
|
70
|
+
const userParams = fileConfig?.routeParams ?? {};
|
|
71
|
+
return { ...autoParams, ...userParams };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/config/config-internals/resolve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CACzB,GAAY,EACZ,UAA+B;IAE/B,MAAM,IAAI,GAAG,GAAG,IAAI,eAAe,EAAE,CAAC;IAEtC,mEAAmE;IACnE,sEAAsE;IACtE,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAE5B,MAAM,SAAS,GACX,OAAO,CAAC,SAAS;QACjB,OAAO,CAAC,4BAA4B,CAAC;QACrC,MAAM,CAAC,4BAA4B,CAAC;QACpC,UAAU,EAAE,SAAS;QACrB,EAAE,CAAC;IAEP,qEAAqE;IACrE,MAAM,MAAM,GACR,OAAO,CAAC,MAAM;QACd,OAAO,CAAC,kBAAkB,CAAC;QAC3B,OAAO,CAAC,0BAA0B,CAAC;QACnC,MAAM,CAAC,kBAAkB,CAAC;QAC1B,MAAM,CAAC,0BAA0B,CAAC;QAClC,UAAU,EAAE,MAAM;QAClB,EAAE,CAAC;IAEP,MAAM,MAAM,GACR,OAAO,CAAC,MAAM;QACd,OAAO,CAAC,qBAAqB,CAAC;QAC9B,MAAM,CAAC,qBAAqB,CAAC;QAC7B,UAAU,EAAE,MAAM;QAClB,EAAE,CAAC;IAEP,0EAA0E;IAC1E,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC1E,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAE7D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAC9B,GAAY,EACZ,UAA+B;IAE/B,MAAM,IAAI,GAAG,GAAG,IAAI,eAAe,EAAE,CAAC;IAEtC,iEAAiE;IACjE,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC;IAE3C,uDAAuD;IACvD,MAAM,UAAU,GAAG,UAAU,EAAE,WAAW,IAAI,EAAE,CAAC;IAEjD,OAAO,EAAE,GAAG,UAAU,EAAE,GAAG,UAAU,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locates the project root by walking up the directory tree.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Walk up from cwd until a directory containing package.json, src/, or .git is found.
|
|
6
|
+
* Falls back to cwd when no such directory exists (e.g. in isolated test environments).
|
|
7
|
+
*/
|
|
8
|
+
export declare function findProjectRoot(): string;
|
|
9
|
+
//# sourceMappingURL=root.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../src/config/config-internals/root.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAaxC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locates the project root by walking up the directory tree.
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
/**
|
|
7
|
+
* Walk up from cwd until a directory containing package.json, src/, or .git is found.
|
|
8
|
+
* Falls back to cwd when no such directory exists (e.g. in isolated test environments).
|
|
9
|
+
*/
|
|
10
|
+
export function findProjectRoot() {
|
|
11
|
+
let current = process.cwd();
|
|
12
|
+
while (current !== '/') {
|
|
13
|
+
if (fs.existsSync(path.join(current, 'package.json')) ||
|
|
14
|
+
fs.existsSync(path.join(current, 'src')) ||
|
|
15
|
+
fs.existsSync(path.join(current, '.git'))) {
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
current = path.dirname(current);
|
|
19
|
+
}
|
|
20
|
+
return process.cwd();
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../../src/config/config-internals/root.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC3B,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC5B,OAAO,OAAO,KAAK,GAAG,EAAE,CAAC;QACrB,IACI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YACjD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACxC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,EAC3C,CAAC;YACC,OAAO,OAAO,CAAC;QACnB,CAAC;QACD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;AACzB,CAAC"}
|