@chipmobilesdk/rn-i18n-tooling 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +65 -3
- package/bin/chip-i18n.mjs +17 -0
- package/lib/cli.d.ts +5 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +91 -0
- package/lib/cli.js.map +1 -0
- package/lib/generateKeys.d.ts +14 -0
- package/lib/generateKeys.d.ts.map +1 -0
- package/lib/generateKeys.js +51 -0
- package/lib/generateKeys.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -0
- package/lib/report.d.ts +10 -0
- package/lib/report.d.ts.map +1 -0
- package/lib/report.js +89 -0
- package/lib/report.js.map +1 -0
- package/lib/runner.d.ts +21 -0
- package/lib/runner.d.ts.map +1 -0
- package/lib/runner.js +88 -0
- package/lib/runner.js.map +1 -0
- package/lib/scan.d.ts +22 -0
- package/lib/scan.d.ts.map +1 -0
- package/lib/scan.js +227 -0
- package/lib/scan.js.map +1 -0
- package/lib/sync.d.ts +18 -0
- package/lib/sync.d.ts.map +1 -0
- package/lib/sync.js +173 -0
- package/lib/sync.js.map +1 -0
- package/lib/types.d.ts +123 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/package.json +38 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @chipmobilesdk/rn-i18n-tooling
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- The extraction CLI is a package of its own, and it runs from npm. ([#21](https://github.com/operationd8979/chip-mobile-sdk/pull/21))
|
|
8
|
+
|
|
9
|
+
`@chipmobilesdk/rn-i18n-tooling` is new: it builds to JavaScript, declares the Node it
|
|
10
|
+
needs (`>=22.13.0`) and exposes a `chip-i18n` binary.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm i -D @chipmobilesdk/rn-i18n-tooling
|
|
14
|
+
npx chip-i18n sync # was: node --experimental-strip-types \
|
|
15
|
+
# node_modules/@chipmobilesdk/rn-i18n/src/tooling/cli.ts
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The tooling used to ship inside the runtime tarball as TypeScript source behind a
|
|
19
|
+
`./tooling` subpath, so the command the README documented worked in this monorepo and
|
|
20
|
+
nowhere else — a consumer had no `bin`, and `node` could not execute the `.ts`
|
|
21
|
+
(I18N-01, DEP-02). A test now installs the package into a throwaway app's
|
|
22
|
+
`node_modules` from exactly what `files` lists and runs the binary there, so "works
|
|
23
|
+
when published" is checked rather than asserted.
|
|
24
|
+
|
|
25
|
+
`@chipmobilesdk/rn-i18n` therefore has one entrypoint and no subpaths, and its tarball
|
|
26
|
+
no longer carries `src/tooling`. **Migration:** an app that imported
|
|
27
|
+
`@chipmobilesdk/rn-i18n/tooling` for the programmatic API installs the new package and
|
|
28
|
+
imports `@chipmobilesdk/rn-i18n-tooling` instead; the members are unchanged
|
|
29
|
+
(`runSync`, `scanSource`, `syncLocaleFiles`, `buildReport`, `renderReport`,
|
|
30
|
+
`generateKeysFile`, `renderKeysModule`, `validateSyncConfig`, `listSourceFiles`,
|
|
31
|
+
`globToRegExp`). An app that only ran the CLI replaces its script with `chip-i18n sync`.
|
|
32
|
+
|
|
33
|
+
Three things the move fixed while the code was in hand:
|
|
34
|
+
|
|
35
|
+
- **The scan starts where the glob does.** `listSourceFiles` walked the project root and
|
|
36
|
+
threw away almost everything it read; it now walks each glob's own base directory
|
|
37
|
+
(`src/screens/**/*.tsx` → `src/screens`), one walk per distinct base.
|
|
38
|
+
- **A match offset becomes a line number by binary search** over the file's line
|
|
39
|
+
starts, computed once. Counting newlines per match made a file with many keys
|
|
40
|
+
quadratic in its own length, and the ambiguous-usage snippet re-split the whole file
|
|
41
|
+
for every hit.
|
|
42
|
+
- **A sync with nothing to do writes nothing.** Each locale file and the generated keys
|
|
43
|
+
file are compared with what would be written — with line endings normalised, so a
|
|
44
|
+
Windows checkout's CRLF is not "a change" — and left alone when they match. Rewriting
|
|
45
|
+
identical bytes churned every mtime, which woke watchers and showed work in
|
|
46
|
+
`git status` that had not happened. The report says `Locale files: unchanged, nothing
|
|
47
|
+
written`.
|
|
48
|
+
|
|
49
|
+
`chip-i18n` also takes a command rather than only flags: `sync` is the one command,
|
|
50
|
+
`--help` prints usage, an unknown command exits 2, and a bare invocation still means
|
|
51
|
+
`sync` for a script that predates the name.
|
|
52
|
+
|
package/README.md
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# @chipmobilesdk/rn-i18n-tooling
|
|
2
|
+
|
|
3
|
+
The `chip-i18n` CLI: it scans a React Native app's source for translation keys and
|
|
4
|
+
synchronises the app's locale JSON files against what it finds.
|
|
5
|
+
|
|
6
|
+
- **Node, not React Native.** Nothing here runs on a device, and the package is a
|
|
7
|
+
`devDependency` of the app. The runtime library is
|
|
8
|
+
[`@chipmobilesdk/rn-i18n`](../rn-i18n/README.md).
|
|
9
|
+
- **Ships JavaScript.** The tarball carries `lib/` built from TypeScript plus the
|
|
10
|
+
`bin/chip-i18n.mjs` entry. This package exists because the tooling used to ship as
|
|
11
|
+
`.ts` source inside the runtime tarball, where the documented command — `node
|
|
12
|
+
--experimental-strip-types node_modules/@chipmobilesdk/rn-i18n/src/tooling/cli.ts` —
|
|
13
|
+
worked in this monorepo and nowhere else (I18N-01, DEP-02).
|
|
14
|
+
- **Public package.** Published under the `@chipmobilesdk` npm organization. The
|
|
15
|
+
license is `UNLICENSED`: the code is readable on npm, but
|
|
16
|
+
no open-source license is granted.
|
|
17
|
+
- **Version**: see [CHANGELOG](CHANGELOG.md)
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm i -D @chipmobilesdk/rn-i18n-tooling
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Node `>=22.13.0`.
|
|
26
|
+
|
|
27
|
+
## Use
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npx chip-i18n sync # i18n-sync.config.json
|
|
31
|
+
npx chip-i18n sync --config other.config.json
|
|
32
|
+
npx chip-i18n --help
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The configuration file, the key patterns, the runtime-only key policy and the generated
|
|
36
|
+
typed-key contract are documented in the runtime package's README, under
|
|
37
|
+
`## Extraction & synchronization CLI` — the CLI reads the same config it always did.
|
|
38
|
+
|
|
39
|
+
Exit codes: `0` success or warnings, `1` blocking findings (a key with two different
|
|
40
|
+
default texts, a malformed locale file), `2` invalid configuration or usage.
|
|
41
|
+
|
|
42
|
+
A run that finds nothing to change **writes no file**: each locale file is compared
|
|
43
|
+
with what would be written and left alone when it matches. That makes the command safe
|
|
44
|
+
in a watch loop or a pre-commit hook, where rewriting identical bytes used to churn
|
|
45
|
+
mtimes and show work in `git status` that had not happened.
|
|
46
|
+
|
|
47
|
+
## Programmatic use
|
|
48
|
+
|
|
49
|
+
The same functions are importable, for a repository that wants to drive extraction from
|
|
50
|
+
its own script:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { runSync, renderReport, scanSource } from '@chipmobilesdk/rn-i18n-tooling';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`runSync(rootDir, config)` returns the report and whether the generated keys file
|
|
57
|
+
changed; `scanSource` is the scanner on its own. Both are the ones the CLI uses.
|
|
58
|
+
|
|
59
|
+
## Repository layout
|
|
60
|
+
|
|
61
|
+
| | |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `src/` | TypeScript sources; `cli.ts` is the command |
|
|
64
|
+
| `lib/` | build output (`npm run build`), git-ignored, published |
|
|
65
|
+
| `bin/chip-i18n.mjs` | the published binary, a wrapper over `lib/cli.js` |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The published entry point for `npx chip-i18n`. It is a hand-written wrapper
|
|
3
|
+
// rather than the built `lib/cli.js` directly: a shebang in a TypeScript source
|
|
4
|
+
// file is at the mercy of the emitter, and this file is also where the error for
|
|
5
|
+
// "installed but never built" belongs.
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const cli = new URL('../lib/cli.js', import.meta.url);
|
|
10
|
+
if (!existsSync(fileURLToPath(cli))) {
|
|
11
|
+
console.error(
|
|
12
|
+
'[chip-i18n] This package was installed without its build output. Reinstall it from npm, or run `npm run build` in packages/rn-i18n-tooling.',
|
|
13
|
+
);
|
|
14
|
+
process.exitCode = 2;
|
|
15
|
+
} else {
|
|
16
|
+
await import(cli.href);
|
|
17
|
+
}
|
package/lib/cli.d.ts
ADDED
package/lib/cli.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAuBA,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAiB1F"}
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `chip-i18n` CLI: extracts translation keys from an app's source and
|
|
3
|
+
* synchronises its locale files.
|
|
4
|
+
*
|
|
5
|
+
* npx chip-i18n sync # i18n-sync.config.json
|
|
6
|
+
* npx chip-i18n sync --config other.config.json
|
|
7
|
+
*
|
|
8
|
+
* Exit codes: 0 success or warnings, 1 blocking findings (conflicts or
|
|
9
|
+
* malformed locale files), 2 invalid configuration, bad usage or internal error.
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import process from 'node:process';
|
|
14
|
+
import { renderReport } from "./report.js";
|
|
15
|
+
import { SyncConfigError, runSync } from "./runner.js";
|
|
16
|
+
const USAGE = `Usage: chip-i18n sync [--config <path>]
|
|
17
|
+
|
|
18
|
+
sync Scan the configured source globs, update the locale files and report.
|
|
19
|
+
--config defaults to i18n-sync.config.json, resolved from the current
|
|
20
|
+
working directory.`;
|
|
21
|
+
export function parseArgs(argv) {
|
|
22
|
+
let configPath = 'i18n-sync.config.json';
|
|
23
|
+
// No command at all means `sync`: that is what the one command was before this
|
|
24
|
+
// CLI had a name, and an app's npm script may still invoke it that way.
|
|
25
|
+
let command = 'sync';
|
|
26
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
27
|
+
const argument = argv[index];
|
|
28
|
+
if (argument === '--config' && argv[index + 1]) {
|
|
29
|
+
configPath = argv[index + 1];
|
|
30
|
+
index += 1;
|
|
31
|
+
}
|
|
32
|
+
else if (argument === '--help' || argument === '-h') {
|
|
33
|
+
command = 'help';
|
|
34
|
+
}
|
|
35
|
+
else if (index === 0 && !argument.startsWith('-')) {
|
|
36
|
+
command = argument;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { command, configPath };
|
|
40
|
+
}
|
|
41
|
+
async function main() {
|
|
42
|
+
const rootDir = process.cwd();
|
|
43
|
+
const { command, configPath } = parseArgs(process.argv.slice(2));
|
|
44
|
+
if (command === 'help') {
|
|
45
|
+
console.log(USAGE);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
if (command !== 'sync') {
|
|
49
|
+
console.error(`[chip-i18n] Unknown command: ${command}\n\n${USAGE}`);
|
|
50
|
+
return 2;
|
|
51
|
+
}
|
|
52
|
+
const absoluteConfigPath = path.resolve(rootDir, configPath);
|
|
53
|
+
if (!fs.existsSync(absoluteConfigPath)) {
|
|
54
|
+
console.error(`[chip-i18n] Sync configuration not found: ${configPath}`);
|
|
55
|
+
return 2;
|
|
56
|
+
}
|
|
57
|
+
let config;
|
|
58
|
+
try {
|
|
59
|
+
config = JSON.parse(fs.readFileSync(absoluteConfigPath, 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error(`[chip-i18n] Sync configuration is not valid JSON: ${String(error)}`);
|
|
63
|
+
return 2;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const { report, generatedKeysChanged } = await runSync(rootDir, config);
|
|
67
|
+
console.log(renderReport(report));
|
|
68
|
+
if (config.generateKeysFile) {
|
|
69
|
+
console.log(generatedKeysChanged
|
|
70
|
+
? `Typed keys regenerated: ${config.generateKeysFile}`
|
|
71
|
+
: `Typed keys unchanged: ${config.generateKeysFile}`);
|
|
72
|
+
}
|
|
73
|
+
return report.outcome === 'failed' ? 1 : 0;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error instanceof SyncConfigError) {
|
|
77
|
+
console.error(`[chip-i18n] ${error.message}`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.error(`[chip-i18n] Sync failed: ${String(error)}`);
|
|
81
|
+
}
|
|
82
|
+
return 2;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
main().then(code => {
|
|
86
|
+
process.exitCode = code;
|
|
87
|
+
}, error => {
|
|
88
|
+
console.error(`[chip-i18n] Unexpected failure: ${String(error)}`);
|
|
89
|
+
process.exitCode = 2;
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=cli.js.map
|
package/lib/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RuntimeEntryConfig, TranslationTemplate } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Renders the typed key contract: the union of scanned template keys and
|
|
4
|
+
* declared runtime-only keys (FR-041). Apps bind lookups to the generated
|
|
5
|
+
* type so `tsc --noEmit` reports invalid or stale key usage before release.
|
|
6
|
+
*/
|
|
7
|
+
export declare function renderKeysModule(template: TranslationTemplate, runtimeEntries: readonly RuntimeEntryConfig[], typeName?: string): string;
|
|
8
|
+
export interface GenerateKeysResult {
|
|
9
|
+
filePath: string;
|
|
10
|
+
changed: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Writes the typed key artifact and reports whether it changed (staleness). */
|
|
13
|
+
export declare function generateKeysFile(rootDir: string, relativePath: string, template: TranslationTemplate, runtimeEntries: readonly RuntimeEntryConfig[], typeName?: string): GenerateKeysResult;
|
|
14
|
+
//# sourceMappingURL=generateKeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateKeys.d.ts","sourceRoot":"","sources":["../src/generateKeys.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,mBAAmB,EAC7B,cAAc,EAAE,SAAS,kBAAkB,EAAE,EAC7C,QAAQ,SAAe,GACrB,MAAM,CA4BR;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,mBAAmB,EAC7B,cAAc,EAAE,SAAS,kBAAkB,EAAE,EAC7C,QAAQ,CAAC,EAAE,MAAM,GACf,kBAAkB,CAepB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Renders the typed key contract: the union of scanned template keys and
|
|
5
|
+
* declared runtime-only keys (FR-041). Apps bind lookups to the generated
|
|
6
|
+
* type so `tsc --noEmit` reports invalid or stale key usage before release.
|
|
7
|
+
*/
|
|
8
|
+
export function renderKeysModule(template, runtimeEntries, typeName = 'AppI18nKey') {
|
|
9
|
+
const templateKeys = template.keys.map(key => key.key).sort((a, b) => a.localeCompare(b, 'en'));
|
|
10
|
+
const runtimeKeys = runtimeEntries
|
|
11
|
+
.map(entry => entry.key)
|
|
12
|
+
.sort((a, b) => a.localeCompare(b, 'en'));
|
|
13
|
+
// Escaped, not interpolated: a key holding an apostrophe or a backslash wrote
|
|
14
|
+
// a file that did not parse, and `tsc` then failed for the whole app (I18N-20).
|
|
15
|
+
const literal = (key) => `'${key.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
16
|
+
const renderList = (keys) => keys.length === 0 ? '[]' : `[\n${keys.map(key => `\t${literal(key)},`).join('\n')}\n]`;
|
|
17
|
+
return [
|
|
18
|
+
'// AUTO-GENERATED by @chipmobilesdk/rn-i18n tooling. Do not edit by hand.',
|
|
19
|
+
'// Regenerate with: npm run i18n:sync',
|
|
20
|
+
'',
|
|
21
|
+
`export const I18N_TEMPLATE_KEYS = ${renderList(templateKeys)} as const;`,
|
|
22
|
+
'',
|
|
23
|
+
`export const I18N_RUNTIME_ONLY_KEYS = ${renderList(runtimeKeys)} as const;`,
|
|
24
|
+
'',
|
|
25
|
+
'export const I18N_KEYS = [',
|
|
26
|
+
'\t...I18N_TEMPLATE_KEYS,',
|
|
27
|
+
'\t...I18N_RUNTIME_ONLY_KEYS,',
|
|
28
|
+
'] as const;',
|
|
29
|
+
'',
|
|
30
|
+
`export type ${typeName} = (typeof I18N_KEYS)[number];`,
|
|
31
|
+
'',
|
|
32
|
+
].join('\n');
|
|
33
|
+
}
|
|
34
|
+
/** Writes the typed key artifact and reports whether it changed (staleness). */
|
|
35
|
+
export function generateKeysFile(rootDir, relativePath, template, runtimeEntries, typeName) {
|
|
36
|
+
const filePath = path.join(rootDir, relativePath);
|
|
37
|
+
const content = renderKeysModule(template, runtimeEntries, typeName);
|
|
38
|
+
// Line endings normalised before comparing, which is how git sees the file: a
|
|
39
|
+
// Windows checkout materialises CRLF, and rewriting it in LF to "fix" that is
|
|
40
|
+
// churn, not work. The file keeps its endings while the content matches.
|
|
41
|
+
const previous = fs.existsSync(filePath)
|
|
42
|
+
? fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n')
|
|
43
|
+
: undefined;
|
|
44
|
+
const changed = previous !== content;
|
|
45
|
+
if (changed) {
|
|
46
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
47
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
48
|
+
}
|
|
49
|
+
return { filePath, changed };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=generateKeys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateKeys.js","sourceRoot":"","sources":["../src/generateKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC/B,QAA6B,EAC7B,cAA6C,EAC7C,QAAQ,GAAG,YAAY;IAEvB,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAChG,MAAM,WAAW,GAAG,cAAc;SAChC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;SACvB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAE3C,8EAA8E;IAC9E,gFAAgF;IAChF,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;IACxF,MAAM,UAAU,GAAG,CAAC,IAAuB,EAAE,EAAE,CAC9C,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAExF,OAAO;QACN,2EAA2E;QAC3E,uCAAuC;QACvC,EAAE;QACF,qCAAqC,UAAU,CAAC,YAAY,CAAC,YAAY;QACzE,EAAE;QACF,yCAAyC,UAAU,CAAC,WAAW,CAAC,YAAY;QAC5E,EAAE;QACF,4BAA4B;QAC5B,0BAA0B;QAC1B,8BAA8B;QAC9B,aAAa;QACb,EAAE;QACF,eAAe,QAAQ,gCAAgC;QACvD,EAAE;KACF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAOD,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAC/B,OAAe,EACf,YAAoB,EACpB,QAA6B,EAC7B,cAA6C,EAC7C,QAAiB;IAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;IACrE,8EAA8E;IAC9E,8EAA8E;IAC9E,yEAAyE;IACzE,MAAM,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QACvC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;QAC1D,CAAC,CAAC,SAAS,CAAC;IACb,MAAM,OAAO,GAAG,QAAQ,KAAK,OAAO,CAAC;IACrC,IAAI,OAAO,EAAE,CAAC;QACb,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic surface of `@chipmobilesdk/rn-i18n-tooling`: the extraction and
|
|
3
|
+
* synchronization the `chip-i18n` command performs, for a repository that drives
|
|
4
|
+
* it from its own script. Node only — nothing here may be imported from React
|
|
5
|
+
* Native code, which is why it is a package of its own rather than a subpath of
|
|
6
|
+
* the runtime library (LIB-003, WS4-03).
|
|
7
|
+
*/
|
|
8
|
+
export { globToRegExp, listSourceFiles, scanSource } from './scan.ts';
|
|
9
|
+
export { flattenTranslations, nestTranslations, syncLocaleFiles } from './sync.ts';
|
|
10
|
+
export { buildReport, renderReport } from './report.ts';
|
|
11
|
+
export { generateKeysFile, renderKeysModule } from './generateKeys.ts';
|
|
12
|
+
export type { GenerateKeysResult } from './generateKeys.ts';
|
|
13
|
+
export { SyncConfigError, loadRuntimeEntries, runSync, validateSyncConfig } from './runner.ts';
|
|
14
|
+
export type { SyncRunResult } from './runner.ts';
|
|
15
|
+
export type { AmbiguousUsage, ExtractionReport, KeyConflict, LocaleSyncResult, PatternConfig, ReportOutcome, RuntimeEntryConfig, SourceLocation, SyncConfig, TemplateKey, TranslationTemplate, } from './types.ts';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC/F,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EACX,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,WAAW,EACX,mBAAmB,GACnB,MAAM,YAAY,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic surface of `@chipmobilesdk/rn-i18n-tooling`: the extraction and
|
|
3
|
+
* synchronization the `chip-i18n` command performs, for a repository that drives
|
|
4
|
+
* it from its own script. Node only — nothing here may be imported from React
|
|
5
|
+
* Native code, which is why it is a package of its own rather than a subpath of
|
|
6
|
+
* the runtime library (LIB-003, WS4-03).
|
|
7
|
+
*/
|
|
8
|
+
export { globToRegExp, listSourceFiles, scanSource } from "./scan.js";
|
|
9
|
+
export { flattenTranslations, nestTranslations, syncLocaleFiles } from "./sync.js";
|
|
10
|
+
export { buildReport, renderReport } from "./report.js";
|
|
11
|
+
export { generateKeysFile, renderKeysModule } from "./generateKeys.js";
|
|
12
|
+
export { SyncConfigError, loadRuntimeEntries, runSync, validateSyncConfig } from "./runner.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|
package/lib/report.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ExtractionReport, LocaleSyncResult, RuntimeEntryConfig, TranslationTemplate } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Assembles the extraction/synchronization report distinguishing scanned
|
|
4
|
+
* template keys, runtime-only keys, stale removals, ambiguous usages, and
|
|
5
|
+
* conflicts (FR-026, FR-036).
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildReport(template: TranslationTemplate, syncResults: readonly LocaleSyncResult[], runtimeEntries: readonly RuntimeEntryConfig[]): ExtractionReport;
|
|
8
|
+
/** Renders the report as readable text for CLI output. */
|
|
9
|
+
export declare function renderReport(report: ExtractionReport): string;
|
|
10
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAEhB,kBAAkB,EAClB,mBAAmB,EACnB,MAAM,YAAY,CAAC;AAapB;;;;GAIG;AACH,wBAAgB,WAAW,CAC1B,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,SAAS,gBAAgB,EAAE,EACxC,cAAc,EAAE,SAAS,kBAAkB,EAAE,GAC3C,gBAAgB,CA2ClB;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAwC7D"}
|
package/lib/report.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
function perLocale(results, select) {
|
|
2
|
+
const record = {};
|
|
3
|
+
for (const result of results) {
|
|
4
|
+
record[result.locale] = select(result);
|
|
5
|
+
}
|
|
6
|
+
return record;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Assembles the extraction/synchronization report distinguishing scanned
|
|
10
|
+
* template keys, runtime-only keys, stale removals, ambiguous usages, and
|
|
11
|
+
* conflicts (FR-026, FR-036).
|
|
12
|
+
*/
|
|
13
|
+
export function buildReport(template, syncResults, runtimeEntries) {
|
|
14
|
+
const errors = syncResults.filter(result => result.error).map(result => result.error);
|
|
15
|
+
let outcome = 'success';
|
|
16
|
+
if (template.ambiguous.length > 0 ||
|
|
17
|
+
syncResults.some(result => result.addedKeys.length > 0 || result.runtimeReported.length > 0)) {
|
|
18
|
+
outcome = 'completedWithWarnings';
|
|
19
|
+
}
|
|
20
|
+
if (errors.length > 0 || template.conflicts.length > 0) {
|
|
21
|
+
outcome = 'failed';
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
outcome,
|
|
25
|
+
discovered: template.keys.map(key => ({
|
|
26
|
+
key: key.key,
|
|
27
|
+
defaultText: key.defaultText,
|
|
28
|
+
locations: key.locations.map(location => `${location.file}:${location.line}`),
|
|
29
|
+
})),
|
|
30
|
+
createdLocaleFiles: syncResults
|
|
31
|
+
.filter(result => result.created && !result.error)
|
|
32
|
+
.map(result => ({ locale: result.locale, filePath: result.filePath })),
|
|
33
|
+
writtenLocaleFiles: syncResults.filter(result => result.written).map(result => result.locale),
|
|
34
|
+
addedKeys: perLocale(syncResults, result => result.addedKeys),
|
|
35
|
+
preservedKeys: perLocale(syncResults, result => result.preservedKeys),
|
|
36
|
+
removedStaleKeys: perLocale(syncResults, result => result.removedKeys),
|
|
37
|
+
missingPerLocale: perLocale(syncResults, result => [...result.addedKeys, ...result.runtimeAdded, ...result.runtimeReported].sort((a, b) => a.localeCompare(b, 'en'))),
|
|
38
|
+
runtimeOnly: {
|
|
39
|
+
declared: runtimeEntries.map(entry => entry.key),
|
|
40
|
+
preserved: perLocale(syncResults, result => result.runtimePreserved),
|
|
41
|
+
added: perLocale(syncResults, result => result.runtimeAdded),
|
|
42
|
+
reported: perLocale(syncResults, result => result.runtimeReported),
|
|
43
|
+
},
|
|
44
|
+
ambiguous: template.ambiguous,
|
|
45
|
+
conflicts: template.conflicts,
|
|
46
|
+
errors,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Renders the report as readable text for CLI output. */
|
|
50
|
+
export function renderReport(report) {
|
|
51
|
+
const lines = [];
|
|
52
|
+
lines.push(`i18n sync outcome: ${report.outcome}`);
|
|
53
|
+
lines.push(`Discovered keys: ${report.discovered.length}`);
|
|
54
|
+
lines.push(report.writtenLocaleFiles.length === 0
|
|
55
|
+
? 'Locale files: unchanged, nothing written'
|
|
56
|
+
: `Locale files written: ${report.writtenLocaleFiles.join(', ')}`);
|
|
57
|
+
for (const created of report.createdLocaleFiles) {
|
|
58
|
+
lines.push(`Created locale file: ${created.locale} -> ${created.filePath}`);
|
|
59
|
+
}
|
|
60
|
+
for (const [locale, keys] of Object.entries(report.addedKeys)) {
|
|
61
|
+
if (keys.length > 0) {
|
|
62
|
+
lines.push(`Added [${locale}]: ${keys.join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const [locale, keys] of Object.entries(report.removedStaleKeys)) {
|
|
66
|
+
if (keys.length > 0) {
|
|
67
|
+
lines.push(`Removed stale [${locale}]: ${keys.join(', ')}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
for (const [locale, keys] of Object.entries(report.runtimeOnly.reported)) {
|
|
71
|
+
if (keys.length > 0) {
|
|
72
|
+
lines.push(`Runtime-only missing [${locale}]: ${keys.join(', ')}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const usage of report.ambiguous) {
|
|
76
|
+
lines.push(`Ambiguous usage at ${usage.file}:${usage.line}: ${usage.snippet}`);
|
|
77
|
+
}
|
|
78
|
+
for (const conflict of report.conflicts) {
|
|
79
|
+
const sources = conflict.values
|
|
80
|
+
.map(value => `"${value.text}" (${value.location.file}:${value.location.line})`)
|
|
81
|
+
.join(' vs ');
|
|
82
|
+
lines.push(`Conflict for key "${conflict.key}": ${sources}`);
|
|
83
|
+
}
|
|
84
|
+
for (const error of report.errors) {
|
|
85
|
+
lines.push(`Error: ${error}`);
|
|
86
|
+
}
|
|
87
|
+
return lines.join('\n');
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
|
package/lib/runner.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ExtractionReport, RuntimeEntryConfig, SyncConfig } from './types.ts';
|
|
2
|
+
export declare class SyncConfigError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function validateSyncConfig(config: SyncConfig): void;
|
|
6
|
+
/**
|
|
7
|
+
* Loads declared runtime-only entries from the configured module. Accepts a
|
|
8
|
+
* default export or a named `runtimeEntries` export. The module must use
|
|
9
|
+
* type-only imports so it can run under Node's TypeScript type stripping.
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadRuntimeEntries(rootDir: string, runtimeEntriesFile: string | undefined): Promise<RuntimeEntryConfig[]>;
|
|
12
|
+
export interface SyncRunResult {
|
|
13
|
+
report: ExtractionReport;
|
|
14
|
+
generatedKeysChanged: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Full pipeline: scan the source tree, synchronize every locale JSON file,
|
|
18
|
+
* regenerate the typed key artifact, and assemble the report.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runSync(rootDir: string, config: SyncConfig, runtimeEntriesOverride?: readonly RuntimeEntryConfig[]): Promise<SyncRunResult>;
|
|
21
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEnF,qBAAa,eAAgB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI3B;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAuB3D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,MAAM,EACf,kBAAkB,EAAE,MAAM,GAAG,SAAS,GACpC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAmB/B;AAED,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,EAClB,sBAAsB,CAAC,EAAE,SAAS,kBAAkB,EAAE,GACpD,OAAO,CAAC,aAAa,CAAC,CA2BxB"}
|
package/lib/runner.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { scanSource } from "./scan.js";
|
|
13
|
+
import { syncLocaleFiles } from "./sync.js";
|
|
14
|
+
import { buildReport } from "./report.js";
|
|
15
|
+
import { generateKeysFile } from "./generateKeys.js";
|
|
16
|
+
export class SyncConfigError extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'SyncConfigError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function validateSyncConfig(config) {
|
|
23
|
+
const issues = [];
|
|
24
|
+
if (!Array.isArray(config.sourceGlobs) || config.sourceGlobs.length === 0) {
|
|
25
|
+
issues.push('`sourceGlobs` must list at least one glob.');
|
|
26
|
+
}
|
|
27
|
+
if (!Array.isArray(config.patterns) || config.patterns.length === 0) {
|
|
28
|
+
issues.push('`patterns` must list at least one regex pattern.');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
for (const pattern of config.patterns) {
|
|
32
|
+
if (!pattern.regex?.includes('(?<key>')) {
|
|
33
|
+
issues.push(`Pattern "${pattern.regex}" must contain a named (?<key>...) capture group.`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!config.localesDir) {
|
|
38
|
+
issues.push('`localesDir` is required.');
|
|
39
|
+
}
|
|
40
|
+
if (!Array.isArray(config.locales) || config.locales.length === 0) {
|
|
41
|
+
issues.push('`locales` must list every supported locale.');
|
|
42
|
+
}
|
|
43
|
+
if (issues.length > 0) {
|
|
44
|
+
throw new SyncConfigError(`Invalid i18n sync configuration:\n- ${issues.join('\n- ')}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loads declared runtime-only entries from the configured module. Accepts a
|
|
49
|
+
* default export or a named `runtimeEntries` export. The module must use
|
|
50
|
+
* type-only imports so it can run under Node's TypeScript type stripping.
|
|
51
|
+
*/
|
|
52
|
+
export async function loadRuntimeEntries(rootDir, runtimeEntriesFile) {
|
|
53
|
+
if (!runtimeEntriesFile) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const absolutePath = path.resolve(rootDir, runtimeEntriesFile);
|
|
57
|
+
if (!fs.existsSync(absolutePath)) {
|
|
58
|
+
throw new SyncConfigError(`Runtime entries file not found: ${runtimeEntriesFile}`);
|
|
59
|
+
}
|
|
60
|
+
const module = (await import(__rewriteRelativeImportExtension(pathToFileURL(absolutePath).href)));
|
|
61
|
+
const entries = module.default ?? module.runtimeEntries;
|
|
62
|
+
if (!Array.isArray(entries)) {
|
|
63
|
+
throw new SyncConfigError(`Runtime entries file must export an entry array (default or \`runtimeEntries\`): ${runtimeEntriesFile}`);
|
|
64
|
+
}
|
|
65
|
+
return entries;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Full pipeline: scan the source tree, synchronize every locale JSON file,
|
|
69
|
+
* regenerate the typed key artifact, and assemble the report.
|
|
70
|
+
*/
|
|
71
|
+
export async function runSync(rootDir, config, runtimeEntriesOverride) {
|
|
72
|
+
validateSyncConfig(config);
|
|
73
|
+
const runtimeEntries = runtimeEntriesOverride ?? (await loadRuntimeEntries(rootDir, config.runtimeEntriesFile));
|
|
74
|
+
const template = scanSource(rootDir, config.sourceGlobs, config.patterns);
|
|
75
|
+
const syncResults = syncLocaleFiles(rootDir, config, template, runtimeEntries);
|
|
76
|
+
const report = buildReport(template, syncResults, runtimeEntries);
|
|
77
|
+
let generatedKeysChanged = false;
|
|
78
|
+
if (config.generateKeysFile) {
|
|
79
|
+
generatedKeysChanged = generateKeysFile(rootDir, config.generateKeysFile, template, runtimeEntries, config.keysTypeName).changed;
|
|
80
|
+
}
|
|
81
|
+
if (config.reportPath) {
|
|
82
|
+
const reportPath = path.resolve(rootDir, config.reportPath);
|
|
83
|
+
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
|
|
84
|
+
fs.writeFileSync(reportPath, `${JSON.stringify(report, null, '\t')}\n`, 'utf8');
|
|
85
|
+
}
|
|
86
|
+
return { report, generatedKeysChanged };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/lib/scan.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PatternConfig, TranslationTemplate } from './types.ts';
|
|
2
|
+
/** Converts a glob (`**`, `*`, `?`, `{a,b}`) to an anchored RegExp. */
|
|
3
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
4
|
+
/**
|
|
5
|
+
* The deepest directory a glob can only match inside: everything before its
|
|
6
|
+
* first wildcard, truncated to a directory boundary. `src/screens/**\/*.tsx`
|
|
7
|
+
* gives `src/screens`, so the walk never leaves it — scanning started at the
|
|
8
|
+
* project root and threw away almost everything it read, which on a React
|
|
9
|
+
* Native checkout means `android/`, `ios/` and every build directory inside
|
|
10
|
+
* them (I18N-15).
|
|
11
|
+
*/
|
|
12
|
+
export declare function globBaseDir(glob: string): string;
|
|
13
|
+
/** Lists project-relative source files matching the configured globs. */
|
|
14
|
+
export declare function listSourceFiles(rootDir: string, sourceGlobs: readonly string[]): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Scans the source tree with the app-configured i18n usage regex patterns and
|
|
17
|
+
* builds the source-of-truth translation template: discovered keys with
|
|
18
|
+
* default text and `file:line` locations, ambiguous dynamic usages, and
|
|
19
|
+
* conflicting duplicate keys (FR-024…FR-026, FR-031).
|
|
20
|
+
*/
|
|
21
|
+
export declare function scanSource(rootDir: string, sourceGlobs: readonly string[], patterns: readonly PatternConfig[]): TranslationTemplate;
|
|
22
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGX,aAAa,EAGb,mBAAmB,EACnB,MAAM,YAAY,CAAC;AAIpB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsCjD;AAgBD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAqBzF;AAuDD;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,QAAQ,EAAE,SAAS,aAAa,EAAE,GAChC,mBAAmB,CAgFrB"}
|