@windrun-huaiin/dev-scripts 6.8.2 → 6.9.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/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +137 -1410
- package/dist/cli.mjs +145 -432
- package/dist/commands/check-translations.d.ts +3 -0
- package/dist/commands/check-translations.d.ts.map +1 -0
- package/dist/commands/check-translations.js +132 -0
- package/dist/commands/check-translations.mjs +130 -0
- package/dist/commands/clean-translations.d.ts +3 -0
- package/dist/commands/clean-translations.d.ts.map +1 -0
- package/dist/commands/clean-translations.js +148 -0
- package/dist/commands/clean-translations.mjs +146 -0
- package/dist/commands/create-diaomao-app.d.ts +2 -0
- package/dist/commands/create-diaomao-app.d.ts.map +1 -0
- package/dist/commands/create-diaomao-app.js +151 -0
- package/dist/commands/create-diaomao-app.mjs +149 -0
- package/dist/commands/deep-clean.d.ts +3 -0
- package/dist/commands/deep-clean.d.ts.map +1 -0
- package/dist/commands/deep-clean.js +119 -0
- package/dist/commands/deep-clean.mjs +117 -0
- package/dist/commands/easy-changeset.d.ts +2 -0
- package/dist/commands/easy-changeset.d.ts.map +1 -0
- package/dist/commands/easy-changeset.js +39 -0
- package/dist/commands/easy-changeset.mjs +37 -0
- package/dist/commands/generate-blog-index.d.ts +3 -0
- package/dist/commands/generate-blog-index.d.ts.map +1 -0
- package/dist/commands/generate-blog-index.js +302 -0
- package/dist/commands/generate-blog-index.mjs +300 -0
- package/dist/commands/generate-nextjs-architecture.d.ts +3 -0
- package/dist/commands/generate-nextjs-architecture.d.ts.map +1 -0
- package/dist/commands/generate-nextjs-architecture.js +84 -0
- package/dist/commands/generate-nextjs-architecture.mjs +82 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +173 -0
- package/dist/config/index.mjs +170 -0
- package/dist/config/schema.d.ts +34 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +80 -0
- package/dist/config/schema.mjs +78 -0
- package/dist/index.d.ts +6 -49
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -996
- package/dist/index.mjs +4 -3
- package/dist/utils/file-scanner.d.ts +22 -0
- package/dist/utils/file-scanner.d.ts.map +1 -0
- package/dist/utils/file-scanner.js +70 -0
- package/dist/utils/file-scanner.mjs +65 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +63 -0
- package/dist/utils/logger.mjs +61 -0
- package/dist/utils/translation-parser.d.ts +29 -0
- package/dist/utils/translation-parser.d.ts.map +1 -0
- package/dist/utils/translation-parser.js +225 -0
- package/dist/utils/translation-parser.mjs +218 -0
- package/package.json +5 -5
- package/dist/chunk-GVR6HFHM.mjs +0 -989
- package/dist/chunk-GVR6HFHM.mjs.map +0 -1
- package/dist/cli.d.mts +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cli.mjs.map +0 -1
- package/dist/index.d.mts +0 -49
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extract translation keys and namespaces from file content
|
|
3
|
+
*/
|
|
4
|
+
function extractTranslationsInfo(content, filePath) {
|
|
5
|
+
const result = {
|
|
6
|
+
namespaces: new Map(),
|
|
7
|
+
keys: []
|
|
8
|
+
};
|
|
9
|
+
// match getTranslations({ locale, namespace: 'namespace' }) or getTranslations('namespace')
|
|
10
|
+
const getTranslationsPattern = /getTranslations\(\s*(?:{[^}]*namespace:\s*['"]([^'"]+)['"][^}]*}|['"]([^'"]+)['"])\s*\)/g;
|
|
11
|
+
let match;
|
|
12
|
+
while ((match = getTranslationsPattern.exec(content)) !== null) {
|
|
13
|
+
const namespace = match[1] || match[2];
|
|
14
|
+
if (namespace) {
|
|
15
|
+
// try to find assignment statement, like const t = await getTranslations(...)
|
|
16
|
+
// find the nearest const declaration
|
|
17
|
+
const linesBefore = content.substring(0, match.index).split('\n');
|
|
18
|
+
for (let i = linesBefore.length - 1; i >= Math.max(0, linesBefore.length - 5); i--) {
|
|
19
|
+
const line = linesBefore[i];
|
|
20
|
+
const constMatch = /const\s+(\w+)\s*=/.exec(line);
|
|
21
|
+
if (constMatch && !line.includes('useTranslations') && !line.includes('getTranslations')) {
|
|
22
|
+
result.namespaces.set(constMatch[1], namespace);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// match useTranslations('namespace')
|
|
29
|
+
const useTranslationsPattern = /useTranslations\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
30
|
+
while ((match = useTranslationsPattern.exec(content)) !== null) {
|
|
31
|
+
const namespace = match[1];
|
|
32
|
+
// try to find assignment statement, like const t = useTranslations(...)
|
|
33
|
+
// find the line containing useTranslations
|
|
34
|
+
const currentLine = content.substring(0, match.index).split('\n').pop() || '';
|
|
35
|
+
const constMatch = /const\s+(\w+)\s*=/.exec(currentLine);
|
|
36
|
+
if (constMatch) {
|
|
37
|
+
result.namespaces.set(constMatch[1], namespace);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// match t('key') or t("key"), and check if t is associated with known namespaces
|
|
41
|
+
// modify the matching pattern of t function call
|
|
42
|
+
const tPatterns = [
|
|
43
|
+
// normal string key: t('key') or t("key")
|
|
44
|
+
/(\w+)\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
45
|
+
// template string key: t(`tags.${id}`) or t(`section.${key}`)
|
|
46
|
+
/(\w+)\(\s*`([^`]+)`\s*\)/g,
|
|
47
|
+
// variable key: t(item.key) or t(item.id)
|
|
48
|
+
/(\w+)\(\s*(\w+)\.(\w+)\s*\)/g
|
|
49
|
+
];
|
|
50
|
+
for (const pattern of tPatterns) {
|
|
51
|
+
let match;
|
|
52
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
53
|
+
const funcName = match[1];
|
|
54
|
+
// if the function name is associated with known namespaces
|
|
55
|
+
if (result.namespaces.has(funcName)) {
|
|
56
|
+
const namespace = result.namespaces.get(funcName);
|
|
57
|
+
if (!namespace)
|
|
58
|
+
continue;
|
|
59
|
+
if (pattern.source.includes('`')) {
|
|
60
|
+
// handle template string
|
|
61
|
+
const templateStr = match[2];
|
|
62
|
+
// extract static part (the part before the variable)
|
|
63
|
+
const staticPart = templateStr.split(/\${(?:id|key)}/)[0].trim();
|
|
64
|
+
if (staticPart && !staticPart.includes('/')) {
|
|
65
|
+
// for tags.${id}这样的形式,记录整个 tags 命名空间
|
|
66
|
+
const segments = staticPart.split('.');
|
|
67
|
+
if (segments.length > 0) {
|
|
68
|
+
// record the base path
|
|
69
|
+
result.keys.push(`${namespace}.${segments[0]}`);
|
|
70
|
+
// if it is multi-level, also record the full path
|
|
71
|
+
if (segments.length > 1) {
|
|
72
|
+
result.keys.push(`${namespace}.${segments.join('.')}`);
|
|
73
|
+
}
|
|
74
|
+
// special handling for tags namespace
|
|
75
|
+
if (segments[0] === 'tags') {
|
|
76
|
+
// add all known tag keys
|
|
77
|
+
['productUpdates', 'tutorials', 'makeMoney', 'roadOverSea', 'insights'].forEach(tag => {
|
|
78
|
+
result.keys.push(`${namespace}.tags.${tag}`);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (pattern.source.includes('\\w+\\.\\w+')) {
|
|
85
|
+
// handle variable key t(item.key)
|
|
86
|
+
const varName = match[2];
|
|
87
|
+
match[3];
|
|
88
|
+
// find the possible value of the variable in the file content
|
|
89
|
+
const varPattern = new RegExp(`${varName}\\s*=\\s*{[^}]*key:\\s*['"]([^'"]+)['"]`);
|
|
90
|
+
const varMatch = content.match(varPattern);
|
|
91
|
+
if (varMatch) {
|
|
92
|
+
// if the variable definition is found, add the actual key
|
|
93
|
+
result.keys.push(`${namespace}.${varMatch[1]}`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// if the specific definition is not found, try to infer from the context
|
|
97
|
+
// check if it is used in an array or object of MenuItem type
|
|
98
|
+
if (content.includes('MenuItem[]') || content.includes('MenuItem}')) {
|
|
99
|
+
// add all possible menu keys
|
|
100
|
+
['journey'].forEach(menuKey => {
|
|
101
|
+
result.keys.push(`${namespace}.${menuKey}`);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// handle normal string key
|
|
108
|
+
const key = match[2];
|
|
109
|
+
if (!key.includes('/') && key !== '') {
|
|
110
|
+
result.keys.push(`${namespace}.${key}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// match <FormattedMessage id="key" />
|
|
117
|
+
const formattedMessagePattern = /<FormattedMessage[^>]*id=['"]([^'"]+)['"]/g;
|
|
118
|
+
while ((match = formattedMessagePattern.exec(content)) !== null) {
|
|
119
|
+
const key = match[1];
|
|
120
|
+
if (!key.includes('/') && key !== '') {
|
|
121
|
+
// for FormattedMessage, we need to guess the namespace
|
|
122
|
+
// usually we can find useTranslations call in the same file
|
|
123
|
+
if (result.namespaces.size > 0) {
|
|
124
|
+
const namespace = Array.from(result.namespaces.values())[0];
|
|
125
|
+
result.keys.push(`${namespace}.${key}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// if the namespace is not found, try to infer from the file path
|
|
129
|
+
const pathMatch = filePath.match(/\[locale\]\/(?:\([^)]+\)\/)?([^/]+)/);
|
|
130
|
+
if (pathMatch && pathMatch[1]) {
|
|
131
|
+
const possibleNamespace = pathMatch[1];
|
|
132
|
+
result.keys.push(`${possibleNamespace}.${key}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* get all keys from an object (including nested keys)
|
|
141
|
+
*/
|
|
142
|
+
function getAllKeys(obj, prefix = '') {
|
|
143
|
+
let keys = [];
|
|
144
|
+
for (const key in obj) {
|
|
145
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
146
|
+
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
147
|
+
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
148
|
+
keys = [...keys, ...getAllKeys(obj[key], newKey)];
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
keys.push(newKey);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return keys;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* check if the key exists in the translation file
|
|
159
|
+
*/
|
|
160
|
+
function checkKeyExists(key, translations) {
|
|
161
|
+
const parts = key.split('.');
|
|
162
|
+
let current = translations;
|
|
163
|
+
for (const part of parts) {
|
|
164
|
+
if (current[part] === undefined) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
current = current[part];
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* check if the namespace exists in the translation file
|
|
173
|
+
*/
|
|
174
|
+
function checkNamespaceExists(namespace, translations) {
|
|
175
|
+
return translations[namespace] !== undefined;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* remove the specified key from the translation object
|
|
179
|
+
*/
|
|
180
|
+
function removeKeyFromTranslations(key, translations) {
|
|
181
|
+
const parts = key.split('.');
|
|
182
|
+
const lastPart = parts.pop();
|
|
183
|
+
if (!lastPart)
|
|
184
|
+
return false;
|
|
185
|
+
let current = translations;
|
|
186
|
+
// navigate to the parent object of the last level
|
|
187
|
+
for (const part of parts) {
|
|
188
|
+
if (current[part] === undefined || typeof current[part] !== 'object') {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
current = current[part];
|
|
192
|
+
}
|
|
193
|
+
// delete the key
|
|
194
|
+
if (current[lastPart] !== undefined) {
|
|
195
|
+
delete current[lastPart];
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* clean empty objects (recursively)
|
|
202
|
+
*/
|
|
203
|
+
function cleanEmptyObjects(obj) {
|
|
204
|
+
for (const key in obj) {
|
|
205
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
206
|
+
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
207
|
+
obj[key] = cleanEmptyObjects(obj[key]);
|
|
208
|
+
// if the object is empty, delete it
|
|
209
|
+
if (Object.keys(obj[key]).length === 0) {
|
|
210
|
+
delete obj[key];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return obj;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export { checkKeyExists, checkNamespaceExists, cleanEmptyObjects, extractTranslationsInfo, getAllKeys, removeKeyFromTranslations };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/dev-scripts",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "Development scripts for multilingual projects",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/node": "^20.0.0",
|
|
17
17
|
"@types/fs-extra": "^11.0.4",
|
|
18
|
-
"tsup": "^8.0.0",
|
|
19
18
|
"typescript": "^5.0.0"
|
|
20
19
|
},
|
|
21
20
|
"peerDependencies": {
|
|
@@ -41,8 +40,9 @@
|
|
|
41
40
|
"access": "public"
|
|
42
41
|
},
|
|
43
42
|
"scripts": {
|
|
44
|
-
"build": "
|
|
45
|
-
"build:prod": "
|
|
46
|
-
"dev": "
|
|
43
|
+
"build": "rollup -c rollup.config.mjs",
|
|
44
|
+
"build:prod": "rollup -c rollup.config.mjs",
|
|
45
|
+
"dev": "rollup -c rollup.config.mjs --watch",
|
|
46
|
+
"clean": "rm -rf dist"
|
|
47
47
|
}
|
|
48
48
|
}
|