@reforgium/presentia 1.2.0 → 1.4.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.
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ // eslint-disable-next-line no-undef
6
+ const args = process.argv.slice(2);
7
+ const getArg = (name, fallback) => {
8
+ const idx = args.indexOf(name);
9
+ return idx >= 0 && args[idx + 1] ? args[idx + 1] : fallback;
10
+ };
11
+
12
+ // eslint-disable-next-line no-undef
13
+ const cwd = process.cwd();
14
+ const localesDir = path.resolve(cwd, getArg('--locales', 'src/assets/locales'));
15
+ const outputFile = path.resolve(cwd, getArg('--out', 'src/types/presentia-lang-keys.d.ts'));
16
+ const moduleName = getArg('--module', '@reforgium/presentia');
17
+
18
+ const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
19
+
20
+ const collectJsonFiles = (dir) => {
21
+ const out = [];
22
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
23
+
24
+ for (const entry of entries) {
25
+ const full = path.join(dir, entry.name);
26
+ if (entry.isDirectory()) {
27
+ out.push(...collectJsonFiles(full));
28
+ continue;
29
+ }
30
+ if (entry.isFile() && entry.name.endsWith('.json')) {
31
+ out.push(full);
32
+ }
33
+ }
34
+
35
+ return out;
36
+ };
37
+
38
+ const namespaceFromFile = (filePath) => {
39
+ const base = path.basename(filePath);
40
+ const parts = base.split('.');
41
+
42
+ if (parts.length >= 3) {
43
+ return parts.slice(0, -2).join('.');
44
+ }
45
+
46
+ return parts.slice(0, -1).join('.');
47
+ };
48
+
49
+ const flattenKeys = (value, prefix = '') => {
50
+ if (!isObject(value)) {
51
+ return [];
52
+ }
53
+
54
+ const out = [];
55
+
56
+ for (const [key, nested] of Object.entries(value)) {
57
+ const next = prefix ? `${prefix}.${key}` : key;
58
+ if (isObject(nested)) {
59
+ out.push(...flattenKeys(nested, next));
60
+ } else {
61
+ out.push(next);
62
+ }
63
+ }
64
+
65
+ return out;
66
+ };
67
+
68
+ if (!fs.existsSync(localesDir)) {
69
+ // eslint-disable-next-line no-undef
70
+ console.error(`[presentia-gen-lang-keys] locales directory not found: ${localesDir}`);
71
+ // eslint-disable-next-line no-undef
72
+ process.exit(1);
73
+ }
74
+
75
+ const files = collectJsonFiles(localesDir);
76
+ const keySet = new Set();
77
+
78
+ for (const file of files) {
79
+ const ns = namespaceFromFile(file);
80
+ if (!ns) {
81
+ continue;
82
+ }
83
+
84
+ const raw = fs.readFileSync(file, 'utf8');
85
+ const json = JSON.parse(raw);
86
+ const keys = flattenKeys(json);
87
+
88
+ for (const key of keys) {
89
+ keySet.add(`${ns}.${key}`);
90
+ }
91
+ }
92
+
93
+ const keys = [...keySet].sort();
94
+ const union = keys.length ? keys.map((key) => ` | '${key}'`).join('\n') : ` | string`;
95
+
96
+ const content = `/* auto-generated by presentia-gen-lang-keys */
97
+ declare module '${moduleName}' {
98
+ interface LangKeyRegistry {
99
+ keys:
100
+ ${union};
101
+ }
102
+ }
103
+
104
+ export {};
105
+ `;
106
+
107
+ fs.mkdirSync(path.dirname(outputFile), { recursive: true });
108
+ fs.writeFileSync(outputFile, content, 'utf8');
109
+
110
+ // eslint-disable-next-line no-undef
111
+ console.log(`[presentia-gen-lang-keys] Generated ${keys.length} keys -> ${outputFile}`);