@lang-tag/cli 0.12.4 → 0.13.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/README.md +1 -0
- package/algorithms/config-generation/path-based-config-generator.d.ts +28 -1
- package/algorithms/index.cjs +62 -1
- package/algorithms/index.js +62 -1
- package/index.cjs +14 -1
- package/index.js +14 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Lang-tag CLI
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
A professional solution for managing translations in modern JavaScript/TypeScript projects, especially those using component-based architectures. `lang-tag` simplifies internationalization by allowing you to define translation keys directly within the components where they are used. Translations become local, callable function objects with full TypeScript support, IntelliSense, and compile-time safety.
|
|
4
5
|
|
|
5
6
|
## Key Benefits
|
|
@@ -47,16 +47,43 @@ export interface PathBasedConfigGeneratorOptions {
|
|
|
47
47
|
/**
|
|
48
48
|
* Hierarchical structure for ignoring specific directory patterns.
|
|
49
49
|
* Keys represent path segments to match, values indicate what to ignore at that level.
|
|
50
|
+
* Supports special key `_` when set to `true` to ignore current segment but continue hierarchy.
|
|
50
51
|
*
|
|
51
52
|
* @example
|
|
52
53
|
* {
|
|
53
54
|
* 'src': {
|
|
54
55
|
* 'app': true, // ignore 'app' when under 'src'
|
|
55
|
-
* 'features': ['auth', 'admin'] // ignore 'auth' and 'admin' under 'src/features'
|
|
56
|
+
* 'features': ['auth', 'admin'], // ignore 'auth' and 'admin' under 'src/features'
|
|
57
|
+
* 'dashboard': {
|
|
58
|
+
* _: true, // ignore 'dashboard' but continue with nested rules
|
|
59
|
+
* modules: true // also ignore 'modules' under 'dashboard'
|
|
60
|
+
* }
|
|
56
61
|
* }
|
|
57
62
|
* }
|
|
58
63
|
*/
|
|
59
64
|
ignoreStructured?: Record<string, any>;
|
|
65
|
+
/**
|
|
66
|
+
* Advanced hierarchical rules for transforming path segments.
|
|
67
|
+
* Supports ignoring and renaming segments with special keys:
|
|
68
|
+
* - `_`: when `false`, ignores the current segment but continues hierarchy
|
|
69
|
+
* - `>`: renames the current segment to the specified value
|
|
70
|
+
* - Regular keys: nested rules or boolean/string for child segments
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* {
|
|
74
|
+
* app: {
|
|
75
|
+
* dashboard: {
|
|
76
|
+
* _: false, // ignore "dashboard" segment
|
|
77
|
+
* modules: false // ignore "modules" when under "dashboard"
|
|
78
|
+
* },
|
|
79
|
+
* admin: {
|
|
80
|
+
* '>': 'management', // rename "admin" to "management"
|
|
81
|
+
* users: true // keep "users" as is (does nothing)
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
*/
|
|
86
|
+
pathRules?: Record<string, any>;
|
|
60
87
|
/**
|
|
61
88
|
* Convert the final namespace to lowercase.
|
|
62
89
|
* @default false
|
package/algorithms/index.cjs
CHANGED
|
@@ -27,12 +27,20 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
27
27
|
ignoreDirectories = [],
|
|
28
28
|
ignoreIncludesRootDirectories = false,
|
|
29
29
|
ignoreStructured = {},
|
|
30
|
+
pathRules = {},
|
|
30
31
|
lowercaseNamespace = false,
|
|
31
32
|
namespaceCase,
|
|
32
33
|
pathCase,
|
|
33
34
|
fallbackNamespace,
|
|
34
35
|
clearOnDefaultNamespace = true
|
|
35
36
|
} = options;
|
|
37
|
+
const hasPathRules = Object.keys(pathRules).length > 0;
|
|
38
|
+
const hasIgnoreStructured = Object.keys(ignoreStructured).length > 0;
|
|
39
|
+
if (hasPathRules && hasIgnoreStructured) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
'pathBasedConfigGenerator: Cannot use both "pathRules" and "ignoreStructured" options simultaneously. Please use "pathRules" (recommended) or "ignoreStructured" (legacy), but not both.'
|
|
42
|
+
);
|
|
43
|
+
}
|
|
36
44
|
return async (event) => {
|
|
37
45
|
const { relativePath, langTagConfig } = event;
|
|
38
46
|
const actualFallbackNamespace = fallbackNamespace ?? langTagConfig.collect?.defaultNamespace;
|
|
@@ -54,7 +62,11 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
54
62
|
}
|
|
55
63
|
return segment;
|
|
56
64
|
}).filter((seg) => seg !== null);
|
|
57
|
-
|
|
65
|
+
if (hasPathRules) {
|
|
66
|
+
pathSegments = applyPathRules(pathSegments, pathRules);
|
|
67
|
+
} else {
|
|
68
|
+
pathSegments = applyStructuredIgnore(pathSegments, ignoreStructured);
|
|
69
|
+
}
|
|
58
70
|
if (ignoreIncludesRootDirectories && langTagConfig.includes && pathSegments.length > 0) {
|
|
59
71
|
const extractedDirectories = extractRootDirectoriesFromIncludes(langTagConfig.includes);
|
|
60
72
|
if (extractedDirectories.includes(pathSegments[0])) {
|
|
@@ -135,7 +147,56 @@ function applyStructuredIgnore(segments, structure) {
|
|
|
135
147
|
currentStructure = structure;
|
|
136
148
|
continue;
|
|
137
149
|
} else if (typeof rule === "object" && rule !== null) {
|
|
150
|
+
const ignoreSelf = rule["_"] === true;
|
|
151
|
+
if (ignoreSelf) {
|
|
152
|
+
currentStructure = rule;
|
|
153
|
+
continue;
|
|
154
|
+
} else {
|
|
155
|
+
result.push(segment);
|
|
156
|
+
currentStructure = rule;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
result.push(segment);
|
|
162
|
+
currentStructure = structure;
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
function applyPathRules(segments, structure) {
|
|
167
|
+
const result = [];
|
|
168
|
+
let currentStructure = structure;
|
|
169
|
+
for (let i = 0; i < segments.length; i++) {
|
|
170
|
+
const segment = segments[i];
|
|
171
|
+
if (segment in currentStructure) {
|
|
172
|
+
const rule = currentStructure[segment];
|
|
173
|
+
if (rule === true) {
|
|
174
|
+
currentStructure = structure;
|
|
175
|
+
continue;
|
|
176
|
+
} else if (rule === false) {
|
|
177
|
+
currentStructure = structure;
|
|
178
|
+
continue;
|
|
179
|
+
} else if (typeof rule === "string") {
|
|
180
|
+
result.push(rule);
|
|
181
|
+
currentStructure = structure;
|
|
182
|
+
continue;
|
|
183
|
+
} else if (Array.isArray(rule)) {
|
|
138
184
|
result.push(segment);
|
|
185
|
+
if (i + 1 < segments.length && rule.includes(segments[i + 1])) {
|
|
186
|
+
i++;
|
|
187
|
+
}
|
|
188
|
+
currentStructure = structure;
|
|
189
|
+
continue;
|
|
190
|
+
} else if (typeof rule === "object" && rule !== null) {
|
|
191
|
+
const ignoreSelf = rule["_"] === false;
|
|
192
|
+
const renameTo = rule[">"];
|
|
193
|
+
if (!ignoreSelf) {
|
|
194
|
+
if (typeof renameTo === "string") {
|
|
195
|
+
result.push(renameTo);
|
|
196
|
+
} else {
|
|
197
|
+
result.push(segment);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
139
200
|
currentStructure = rule;
|
|
140
201
|
continue;
|
|
141
202
|
}
|
package/algorithms/index.js
CHANGED
|
@@ -8,12 +8,20 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
8
8
|
ignoreDirectories = [],
|
|
9
9
|
ignoreIncludesRootDirectories = false,
|
|
10
10
|
ignoreStructured = {},
|
|
11
|
+
pathRules = {},
|
|
11
12
|
lowercaseNamespace = false,
|
|
12
13
|
namespaceCase,
|
|
13
14
|
pathCase,
|
|
14
15
|
fallbackNamespace,
|
|
15
16
|
clearOnDefaultNamespace = true
|
|
16
17
|
} = options;
|
|
18
|
+
const hasPathRules = Object.keys(pathRules).length > 0;
|
|
19
|
+
const hasIgnoreStructured = Object.keys(ignoreStructured).length > 0;
|
|
20
|
+
if (hasPathRules && hasIgnoreStructured) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'pathBasedConfigGenerator: Cannot use both "pathRules" and "ignoreStructured" options simultaneously. Please use "pathRules" (recommended) or "ignoreStructured" (legacy), but not both.'
|
|
23
|
+
);
|
|
24
|
+
}
|
|
17
25
|
return async (event) => {
|
|
18
26
|
const { relativePath, langTagConfig } = event;
|
|
19
27
|
const actualFallbackNamespace = fallbackNamespace ?? langTagConfig.collect?.defaultNamespace;
|
|
@@ -35,7 +43,11 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
35
43
|
}
|
|
36
44
|
return segment;
|
|
37
45
|
}).filter((seg) => seg !== null);
|
|
38
|
-
|
|
46
|
+
if (hasPathRules) {
|
|
47
|
+
pathSegments = applyPathRules(pathSegments, pathRules);
|
|
48
|
+
} else {
|
|
49
|
+
pathSegments = applyStructuredIgnore(pathSegments, ignoreStructured);
|
|
50
|
+
}
|
|
39
51
|
if (ignoreIncludesRootDirectories && langTagConfig.includes && pathSegments.length > 0) {
|
|
40
52
|
const extractedDirectories = extractRootDirectoriesFromIncludes(langTagConfig.includes);
|
|
41
53
|
if (extractedDirectories.includes(pathSegments[0])) {
|
|
@@ -116,7 +128,56 @@ function applyStructuredIgnore(segments, structure) {
|
|
|
116
128
|
currentStructure = structure;
|
|
117
129
|
continue;
|
|
118
130
|
} else if (typeof rule === "object" && rule !== null) {
|
|
131
|
+
const ignoreSelf = rule["_"] === true;
|
|
132
|
+
if (ignoreSelf) {
|
|
133
|
+
currentStructure = rule;
|
|
134
|
+
continue;
|
|
135
|
+
} else {
|
|
136
|
+
result.push(segment);
|
|
137
|
+
currentStructure = rule;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
result.push(segment);
|
|
143
|
+
currentStructure = structure;
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
function applyPathRules(segments, structure) {
|
|
148
|
+
const result = [];
|
|
149
|
+
let currentStructure = structure;
|
|
150
|
+
for (let i = 0; i < segments.length; i++) {
|
|
151
|
+
const segment = segments[i];
|
|
152
|
+
if (segment in currentStructure) {
|
|
153
|
+
const rule = currentStructure[segment];
|
|
154
|
+
if (rule === true) {
|
|
155
|
+
currentStructure = structure;
|
|
156
|
+
continue;
|
|
157
|
+
} else if (rule === false) {
|
|
158
|
+
currentStructure = structure;
|
|
159
|
+
continue;
|
|
160
|
+
} else if (typeof rule === "string") {
|
|
161
|
+
result.push(rule);
|
|
162
|
+
currentStructure = structure;
|
|
163
|
+
continue;
|
|
164
|
+
} else if (Array.isArray(rule)) {
|
|
119
165
|
result.push(segment);
|
|
166
|
+
if (i + 1 < segments.length && rule.includes(segments[i + 1])) {
|
|
167
|
+
i++;
|
|
168
|
+
}
|
|
169
|
+
currentStructure = structure;
|
|
170
|
+
continue;
|
|
171
|
+
} else if (typeof rule === "object" && rule !== null) {
|
|
172
|
+
const ignoreSelf = rule["_"] === false;
|
|
173
|
+
const renameTo = rule[">"];
|
|
174
|
+
if (!ignoreSelf) {
|
|
175
|
+
if (typeof renameTo === "string") {
|
|
176
|
+
result.push(renameTo);
|
|
177
|
+
} else {
|
|
178
|
+
result.push(segment);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
120
181
|
currentStructure = rule;
|
|
121
182
|
continue;
|
|
122
183
|
}
|
package/index.cjs
CHANGED
|
@@ -1454,7 +1454,20 @@ const generationAlgorithm = pathBasedConfigGenerator({
|
|
|
1454
1454
|
namespaceCase: 'kebab',
|
|
1455
1455
|
pathCase: 'camel',
|
|
1456
1456
|
clearOnDefaultNamespace: true,
|
|
1457
|
-
ignoreDirectories: ['core', 'utils', 'helpers']
|
|
1457
|
+
ignoreDirectories: ['core', 'utils', 'helpers'],
|
|
1458
|
+
// Advanced: Use pathRules for hierarchical transformations with ignore and rename
|
|
1459
|
+
// pathRules: {
|
|
1460
|
+
// app: {
|
|
1461
|
+
// dashboard: {
|
|
1462
|
+
// _: false, // ignore "dashboard" but continue with nested rules
|
|
1463
|
+
// modules: false // also ignore "modules"
|
|
1464
|
+
// },
|
|
1465
|
+
// admin: {
|
|
1466
|
+
// '>': 'management', // rename "admin" to "management"
|
|
1467
|
+
// users: false // ignore "users"
|
|
1468
|
+
// }
|
|
1469
|
+
// }
|
|
1470
|
+
// }
|
|
1458
1471
|
});
|
|
1459
1472
|
const keeper = configKeeper();
|
|
1460
1473
|
|
package/index.js
CHANGED
|
@@ -1434,7 +1434,20 @@ const generationAlgorithm = pathBasedConfigGenerator({
|
|
|
1434
1434
|
namespaceCase: 'kebab',
|
|
1435
1435
|
pathCase: 'camel',
|
|
1436
1436
|
clearOnDefaultNamespace: true,
|
|
1437
|
-
ignoreDirectories: ['core', 'utils', 'helpers']
|
|
1437
|
+
ignoreDirectories: ['core', 'utils', 'helpers'],
|
|
1438
|
+
// Advanced: Use pathRules for hierarchical transformations with ignore and rename
|
|
1439
|
+
// pathRules: {
|
|
1440
|
+
// app: {
|
|
1441
|
+
// dashboard: {
|
|
1442
|
+
// _: false, // ignore "dashboard" but continue with nested rules
|
|
1443
|
+
// modules: false // also ignore "modules"
|
|
1444
|
+
// },
|
|
1445
|
+
// admin: {
|
|
1446
|
+
// '>': 'management', // rename "admin" to "management"
|
|
1447
|
+
// users: false // ignore "users"
|
|
1448
|
+
// }
|
|
1449
|
+
// }
|
|
1450
|
+
// }
|
|
1438
1451
|
});
|
|
1439
1452
|
const keeper = configKeeper();
|
|
1440
1453
|
|