@windrun-huaiin/dev-scripts 6.8.2 → 6.9.1
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
package/dist/cli.js
CHANGED
|
@@ -2,1446 +2,173 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
-
scan: {
|
|
27
|
-
include: ["src/**/*.{tsx,ts,jsx,js}"],
|
|
28
|
-
exclude: ["src/**/*.d.ts", "src/**/*.test.ts", "src/**/*.test.tsx", "node_modules/**"]
|
|
29
|
-
},
|
|
30
|
-
blog: {
|
|
31
|
-
mdxDir: "src/mdx/blog",
|
|
32
|
-
outputFile: "index.mdx",
|
|
33
|
-
metaFile: "meta.json",
|
|
34
|
-
iocSlug: "ioc",
|
|
35
|
-
prefix: "blog"
|
|
36
|
-
},
|
|
37
|
-
output: {
|
|
38
|
-
logDir: "logs",
|
|
39
|
-
verbose: false
|
|
40
|
-
},
|
|
41
|
-
architectureConfig: {
|
|
42
|
-
".": "\u9879\u76EE\u6839\u76EE\u5F55",
|
|
43
|
-
".env.local": "\u672C\u5730\u73AF\u5883\u53D8\u91CF\u914D\u7F6E",
|
|
44
|
-
".eslintrc.json": "ESLint \u4EE3\u7801\u89C4\u8303\u914D\u7F6E",
|
|
45
|
-
".gitignore": "Git\u5FFD\u7565\u6587\u4EF6\u914D\u7F6E",
|
|
46
|
-
".source": "Fuma\u6570\u636E\u6E90Build\u4EA7\u7269",
|
|
47
|
-
"CHANGELOG.md": "\u53D8\u66F4\u8BB0\u5F55",
|
|
48
|
-
"components.json": "\u7EC4\u4EF6\u4F9D\u8D56\u6E05\u5355",
|
|
49
|
-
"dev-scripts.config.json": "dev-scripts\u811A\u672C\u5DE5\u5177\u914D\u7F6E",
|
|
50
|
-
"LICENSE": "\u5F00\u6E90\u8BB8\u53EF\u8BC1",
|
|
51
|
-
"messages": "\u7FFB\u8BD1\u76EE\u5F55",
|
|
52
|
-
"next-env.d.ts": "Next.js\u73AF\u5883\u7C7B\u578B\u58F0\u660E",
|
|
53
|
-
"next.config.ts": "Next.js\u9879\u76EE\u914D\u7F6E",
|
|
54
|
-
"package.json": "\u9879\u76EE\u4F9D\u8D56\u4E0E\u811A\u672C",
|
|
55
|
-
"postcss.config.mjs": "PostCSS \u914D\u7F6E",
|
|
56
|
-
"source.config.ts": "Fuma\u6570\u636E\u6E90\u626B\u63CF\u914D\u7F6E",
|
|
57
|
-
"src": "\u6E90\u7801\u76EE\u5F55",
|
|
58
|
-
"tsconfig.json": "TypeScript\u914D\u7F6E",
|
|
59
|
-
"tsconfig.node.json": "Node.js\u76F8\u5173TypeScript \u914D\u7F6E",
|
|
60
|
-
"logs": "\u65E5\u5FD7\u8F93\u51FA\u76EE\u5F55",
|
|
61
|
-
"apps": "Monorepo\u591A\u5E94\u7528\u76EE\u5F55",
|
|
62
|
-
"packages": "\u5B50\u5DE5\u7A0B\u7EC4\u4EF6\u5E93\u76EE\u5F55",
|
|
63
|
-
"README.md": "\u9879\u76EE\u8BF4\u660E\u6587\u6863",
|
|
64
|
-
"app": "Next.js \u5E94\u7528\u4E3B\u5165\u53E3\u76EE\u5F55",
|
|
65
|
-
"components": "\u9875\u9762\u7EC4\u4EF6",
|
|
66
|
-
"lib": "\u5DE5\u5177\u5305",
|
|
67
|
-
"mdx": "FumaMDX\u6587\u6863",
|
|
68
|
-
"middleware.ts": "\u4E2D\u95F4\u4EF6\u5165\u53E3",
|
|
69
|
-
"i18n.ts": "\u591A\u8BED\u8A00\u914D\u7F6E",
|
|
70
|
-
"globals.css": "\u5168\u5C40\u6837\u5F0F",
|
|
71
|
-
"layout.config.tsx": "\u5E03\u5C40\u914D\u7F6E",
|
|
72
|
-
"layout.tsx": "\u5E03\u5C40",
|
|
73
|
-
"loading.tsx": "\u5168\u5C40\u52A0\u8F7D\u7EC4\u4EF6",
|
|
74
|
-
"hero.tsx": "\u9996\u9875\u5927\u5B57\u7EC4\u4EF6",
|
|
75
|
-
"mdx-components.tsx": "FumaMDX\u7EC4\u4EF6\u5E93(\u81EA\u5B9A\u4E49)",
|
|
76
|
-
"llm-content": "FumaMDX\u590D\u5236\u63A5\u53E3",
|
|
77
|
-
"[locale]": "Nextjs i18n\u8DEF\u7531\u76EE\u5F55",
|
|
78
|
-
"(clerk)": "Clerk\u8BA4\u8BC1",
|
|
79
|
-
"(home)": "\u9996\u9875",
|
|
80
|
-
"[...catchAll]": "\u5168\u5C40404\u9875\u9762",
|
|
81
|
-
"blog": "\u535A\u5BA2",
|
|
82
|
-
"docs": "\u6587\u6863",
|
|
83
|
-
"legal": "\u6CD5\u5F8B",
|
|
84
|
-
"api": "API\u63A5\u53E3",
|
|
85
|
-
"robots.ts": "robots.txt\u751F\u6210\u811A\u672C",
|
|
86
|
-
"sitemap.ts": "\u7F51\u7AD9\u5730\u56FE",
|
|
87
|
-
"appConfig.ts": "\u5E94\u7528\u5168\u5C40\u914D\u7F6E",
|
|
88
|
-
"site-config.ts": "\u7F51\u7AD9\u56FE\u6807\u914D\u7F6E",
|
|
89
|
-
"ioc.mdx": "\u6708\u5EA6/\u7EDF\u8BA1",
|
|
90
|
-
"meta.json": "FumaMDX\u5143\u6570\u636E",
|
|
91
|
-
"nextjs-architecture.mdx": "Next.js\u9879\u76EE\u7ED3\u6784",
|
|
92
|
-
".github": "GitHub \u914D\u7F6E\u76EE\u5F55",
|
|
93
|
-
"workflows": "CI/CD \u5DE5\u4F5C\u6D41\u914D\u7F6E"
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// src/config/index.ts
|
|
98
|
-
function loadPackageJsonConfig(cwd2) {
|
|
99
|
-
try {
|
|
100
|
-
const packageJsonPath = path2__default.default.join(cwd2, "package.json");
|
|
101
|
-
if (!fs__default.default.existsSync(packageJsonPath)) return null;
|
|
102
|
-
const packageJson = JSON.parse(fs__default.default.readFileSync(packageJsonPath, "utf8"));
|
|
103
|
-
const devScripts = packageJson.devScripts;
|
|
104
|
-
if (!devScripts || Object.keys(devScripts).length === 0) {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
const config = {};
|
|
108
|
-
if (devScripts.locales || devScripts.defaultLocale || devScripts.messageRoot) {
|
|
109
|
-
config.i18n = {
|
|
110
|
-
locales: devScripts.locales || DEFAULT_CONFIG.i18n.locales,
|
|
111
|
-
defaultLocale: devScripts.defaultLocale || DEFAULT_CONFIG.i18n.defaultLocale,
|
|
112
|
-
messageRoot: devScripts.messageRoot || DEFAULT_CONFIG.i18n.messageRoot
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (devScripts.scanDirs) {
|
|
116
|
-
config.scan = {
|
|
117
|
-
include: devScripts.scanDirs,
|
|
118
|
-
exclude: DEFAULT_CONFIG.scan.exclude
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
if (devScripts.blogDir) {
|
|
122
|
-
config.blog = {
|
|
123
|
-
mdxDir: devScripts.blogDir,
|
|
124
|
-
...DEFAULT_CONFIG.blog
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (devScripts.logDir) {
|
|
128
|
-
config.output = {
|
|
129
|
-
logDir: devScripts.logDir,
|
|
130
|
-
verbose: DEFAULT_CONFIG.output.verbose
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
return Object.keys(config).length > 0 ? config : null;
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.warn(`Warning: Failed to load package.json config: ${error}`);
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function loadConfigFile(cwd2) {
|
|
140
|
-
try {
|
|
141
|
-
const configPath = path2__default.default.join(cwd2, "dev-scripts.config.json");
|
|
142
|
-
if (!fs__default.default.existsSync(configPath)) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return JSON.parse(fs__default.default.readFileSync(configPath, "utf8"));
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.warn(`Warning: Failed to load dev-scripts.config.json: ${error}`);
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
function mergeConfig(base, override) {
|
|
152
|
-
const result = { ...base };
|
|
153
|
-
for (const [key, value] of Object.entries(override)) {
|
|
154
|
-
if (value !== void 0 && value !== null) {
|
|
155
|
-
if (typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object") {
|
|
156
|
-
result[key] = { ...result[key], ...value };
|
|
157
|
-
} else {
|
|
158
|
-
result[key] = value;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return result;
|
|
163
|
-
}
|
|
164
|
-
function loadConfig(cwd2 = typeof process !== "undefined" ? process.cwd() : ".", override = {}, verbose) {
|
|
165
|
-
let config = { ...DEFAULT_CONFIG };
|
|
166
|
-
const configSources = [];
|
|
167
|
-
const fileConfig = loadConfigFile(cwd2);
|
|
168
|
-
if (fileConfig) {
|
|
169
|
-
config = mergeConfig(config, fileConfig);
|
|
170
|
-
configSources.push("dev-scripts.config.json");
|
|
171
|
-
}
|
|
172
|
-
const packageConfig = loadPackageJsonConfig(cwd2);
|
|
173
|
-
if (packageConfig) {
|
|
174
|
-
config = mergeConfig(config, packageConfig);
|
|
175
|
-
configSources.push("package.json");
|
|
176
|
-
}
|
|
177
|
-
config = mergeConfig(config, override);
|
|
178
|
-
if (Object.keys(override).length > 0) {
|
|
179
|
-
configSources.push("runtime override");
|
|
180
|
-
}
|
|
181
|
-
const shouldPrintConfig = verbose !== void 0 ? verbose : config.output.verbose;
|
|
182
|
-
if (shouldPrintConfig) {
|
|
183
|
-
const configForPrint = { ...config };
|
|
184
|
-
configForPrint.output = { ...config.output, verbose: true };
|
|
185
|
-
printConfigInfo(configForPrint, configSources, cwd2);
|
|
186
|
-
}
|
|
187
|
-
return config;
|
|
188
|
-
}
|
|
189
|
-
function printConfigInfo(config, sources, cwd2) {
|
|
190
|
-
console.log("\n\u{1F4CB} Config Information:");
|
|
191
|
-
console.log(` working directory: ${cwd2}`);
|
|
192
|
-
console.log(` config sources: ${sources.length > 0 ? sources.join(" + ") : "default config"}`);
|
|
193
|
-
console.log("\n\u{1F310} i18n:");
|
|
194
|
-
console.log(` locales: [${config.i18n.locales.join(", ")}]`);
|
|
195
|
-
console.log(` defaultLocale: ${config.i18n.defaultLocale}`);
|
|
196
|
-
console.log(` messageRoot: ${config.i18n.messageRoot}`);
|
|
197
|
-
console.log("\n\u{1F50D} scan:");
|
|
198
|
-
console.log(` include: [${config.scan.include.join(", ")}]`);
|
|
199
|
-
if (config.scan.exclude && config.scan.exclude.length > 0) {
|
|
200
|
-
console.log(` exclude: [${config.scan.exclude.join(", ")}]`);
|
|
201
|
-
}
|
|
202
|
-
if (config.scan.baseDir) {
|
|
203
|
-
console.log(` baseDir: ${config.scan.baseDir}`);
|
|
204
|
-
}
|
|
205
|
-
if (config.blog) {
|
|
206
|
-
console.log("\n\u{1F4DD} blog:");
|
|
207
|
-
console.log(` mdxDir: ${config.blog.mdxDir}`);
|
|
208
|
-
console.log(` outputFile: ${config.blog.outputFile || "index.mdx (default)"}`);
|
|
209
|
-
console.log(` metaFile: ${config.blog.metaFile || "meta.json (default)"}`);
|
|
210
|
-
if (config.blog.iocSlug) {
|
|
211
|
-
console.log(` iocSlug: ${config.blog.iocSlug}`);
|
|
212
|
-
}
|
|
213
|
-
if (config.blog.prefix) {
|
|
214
|
-
console.log(` prefix: ${config.blog.prefix}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
console.log("\n\u{1F4E4} output:");
|
|
218
|
-
console.log(` logDir: ${config.output.logDir}`);
|
|
219
|
-
console.log(` verbose: ${config.output.verbose}`);
|
|
220
|
-
console.log("");
|
|
221
|
-
}
|
|
222
|
-
function validateConfig(config) {
|
|
223
|
-
if (!config.i18n.locales || config.i18n.locales.length === 0) {
|
|
224
|
-
throw new Error("at least one language is required");
|
|
225
|
-
}
|
|
226
|
-
if (!config.i18n.locales.includes(config.i18n.defaultLocale)) {
|
|
227
|
-
throw new Error("default language must be in the supported language list");
|
|
228
|
-
}
|
|
229
|
-
if (config.scan.include.length === 0) {
|
|
230
|
-
throw new Error("at least one scan path is required");
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
var Logger = class {
|
|
234
|
-
constructor(config) {
|
|
235
|
-
this.messages = [];
|
|
236
|
-
this.config = config;
|
|
237
|
-
}
|
|
238
|
-
log(message) {
|
|
239
|
-
if (this.config.output.verbose) {
|
|
240
|
-
console.log(message);
|
|
241
|
-
}
|
|
242
|
-
this.messages.push(message);
|
|
243
|
-
}
|
|
244
|
-
error(message) {
|
|
245
|
-
console.error(message);
|
|
246
|
-
this.messages.push("[ERROR] " + message);
|
|
247
|
-
}
|
|
248
|
-
warn(message) {
|
|
249
|
-
console.warn(message);
|
|
250
|
-
this.messages.push("[WARN] " + message);
|
|
251
|
-
}
|
|
252
|
-
info(message) {
|
|
253
|
-
console.info(message);
|
|
254
|
-
this.messages.push("[INFO] " + message);
|
|
255
|
-
}
|
|
256
|
-
success(message) {
|
|
257
|
-
console.log(`\u2705 ${message}`);
|
|
258
|
-
this.messages.push(`[SUCCESS] ${message}`);
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* save log to file
|
|
262
|
-
*/
|
|
263
|
-
saveToFile(filename, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
264
|
-
try {
|
|
265
|
-
const logFilePath = path2.join(cwd2, this.config.output.logDir, filename);
|
|
266
|
-
const logDir = path2.dirname(logFilePath);
|
|
267
|
-
fs.mkdirSync(logDir, { recursive: true });
|
|
268
|
-
fs.writeFileSync(logFilePath, this.messages.join("\n"), "utf8");
|
|
269
|
-
console.log(`log saved to ${logFilePath}`);
|
|
270
|
-
} catch (error) {
|
|
271
|
-
console.error(`failed to save log file: ${error}`);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* clear log messages
|
|
276
|
-
*/
|
|
277
|
-
clear() {
|
|
278
|
-
this.messages = [];
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* get all log messages
|
|
282
|
-
*/
|
|
283
|
-
getMessages() {
|
|
284
|
-
return [...this.messages];
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
async function scanFiles(config, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
288
|
-
const files = await fg__default.default(config.scan.include, {
|
|
289
|
-
ignore: config.scan.exclude || [],
|
|
290
|
-
cwd: cwd2,
|
|
291
|
-
absolute: false
|
|
292
|
-
});
|
|
293
|
-
const results = [];
|
|
294
|
-
for (const file of files) {
|
|
5
|
+
var index = require('./config/index.js');
|
|
6
|
+
var checkTranslations = require('./commands/check-translations.js');
|
|
7
|
+
var cleanTranslations = require('./commands/clean-translations.js');
|
|
8
|
+
var generateBlogIndex = require('./commands/generate-blog-index.js');
|
|
9
|
+
var deepClean = require('./commands/deep-clean.js');
|
|
10
|
+
var easyChangeset = require('./commands/easy-changeset.js');
|
|
11
|
+
var generateNextjsArchitecture = require('./commands/generate-nextjs-architecture.js');
|
|
12
|
+
var createDiaomaoApp = require('./commands/create-diaomao-app.js');
|
|
13
|
+
|
|
14
|
+
// get current working directory, ensure it works in Node.js environment
|
|
15
|
+
const cwd = typeof process !== 'undefined' ? process.cwd() : '.';
|
|
16
|
+
commander.program
|
|
17
|
+
.name('dev-scripts')
|
|
18
|
+
.description('development scripts for multi-language projects')
|
|
19
|
+
.version('5.0.0');
|
|
20
|
+
commander.program
|
|
21
|
+
.command('check-translations')
|
|
22
|
+
.description('check the completeness and consistency of translation files')
|
|
23
|
+
.option('-v, --verbose', 'show detailed logs', false)
|
|
24
|
+
.action(async (options) => {
|
|
295
25
|
try {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
});
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.warn(`Warning: Failed to read file ${file}: ${error}`);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return results;
|
|
306
|
-
}
|
|
307
|
-
function readJsonFile(filePath) {
|
|
308
|
-
try {
|
|
309
|
-
const content = fs.readFileSync(filePath, "utf8");
|
|
310
|
-
return JSON.parse(content);
|
|
311
|
-
} catch (error) {
|
|
312
|
-
return null;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
function getTranslationFilePath(locale, config, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
316
|
-
return `${cwd2}/${config.i18n.messageRoot}/${locale}.json`;
|
|
317
|
-
}
|
|
318
|
-
function loadTranslations(config, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
319
|
-
const translations = {};
|
|
320
|
-
for (const locale of config.i18n.locales) {
|
|
321
|
-
const filePath = getTranslationFilePath(locale, config, cwd2);
|
|
322
|
-
const translation = readJsonFile(filePath);
|
|
323
|
-
if (translation) {
|
|
324
|
-
translations[locale] = translation;
|
|
325
|
-
} else {
|
|
326
|
-
console.warn(`Warning: Failed to load translation file for locale: ${locale}`);
|
|
327
|
-
translations[locale] = {};
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return translations;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// src/utils/translation-parser.ts
|
|
334
|
-
function extractTranslationsInfo(content, filePath) {
|
|
335
|
-
const result = {
|
|
336
|
-
namespaces: /* @__PURE__ */ new Map(),
|
|
337
|
-
keys: []
|
|
338
|
-
};
|
|
339
|
-
const getTranslationsPattern = /getTranslations\(\s*(?:{[^}]*namespace:\s*['"]([^'"]+)['"][^}]*}|['"]([^'"]+)['"])\s*\)/g;
|
|
340
|
-
let match;
|
|
341
|
-
while ((match = getTranslationsPattern.exec(content)) !== null) {
|
|
342
|
-
const namespace = match[1] || match[2];
|
|
343
|
-
if (namespace) {
|
|
344
|
-
const linesBefore = content.substring(0, match.index).split("\n");
|
|
345
|
-
for (let i = linesBefore.length - 1; i >= Math.max(0, linesBefore.length - 5); i--) {
|
|
346
|
-
const line = linesBefore[i];
|
|
347
|
-
const constMatch = /const\s+(\w+)\s*=/.exec(line);
|
|
348
|
-
if (constMatch && !line.includes("useTranslations") && !line.includes("getTranslations")) {
|
|
349
|
-
result.namespaces.set(constMatch[1], namespace);
|
|
350
|
-
break;
|
|
26
|
+
const config = index.loadConfig(cwd, {}, options.verbose);
|
|
27
|
+
// apply verbose option after loading
|
|
28
|
+
if (options.verbose) {
|
|
29
|
+
config.output.verbose = true;
|
|
351
30
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
while ((match = useTranslationsPattern.exec(content)) !== null) {
|
|
357
|
-
const namespace = match[1];
|
|
358
|
-
const currentLine = content.substring(0, match.index).split("\n").pop() || "";
|
|
359
|
-
const constMatch = /const\s+(\w+)\s*=/.exec(currentLine);
|
|
360
|
-
if (constMatch) {
|
|
361
|
-
result.namespaces.set(constMatch[1], namespace);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
const tPatterns = [
|
|
365
|
-
// normal string key: t('key') or t("key")
|
|
366
|
-
/(\w+)\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
367
|
-
// template string key: t(`tags.${id}`) or t(`section.${key}`)
|
|
368
|
-
/(\w+)\(\s*`([^`]+)`\s*\)/g,
|
|
369
|
-
// variable key: t(item.key) or t(item.id)
|
|
370
|
-
/(\w+)\(\s*(\w+)\.(\w+)\s*\)/g
|
|
371
|
-
];
|
|
372
|
-
for (const pattern of tPatterns) {
|
|
373
|
-
let match2;
|
|
374
|
-
while ((match2 = pattern.exec(content)) !== null) {
|
|
375
|
-
const funcName = match2[1];
|
|
376
|
-
if (result.namespaces.has(funcName)) {
|
|
377
|
-
const namespace = result.namespaces.get(funcName);
|
|
378
|
-
if (!namespace) continue;
|
|
379
|
-
if (pattern.source.includes("`")) {
|
|
380
|
-
const templateStr = match2[2];
|
|
381
|
-
const staticPart = templateStr.split(/\${(?:id|key)}/)[0].trim();
|
|
382
|
-
if (staticPart && !staticPart.includes("/")) {
|
|
383
|
-
const segments = staticPart.split(".");
|
|
384
|
-
if (segments.length > 0) {
|
|
385
|
-
result.keys.push(`${namespace}.${segments[0]}`);
|
|
386
|
-
if (segments.length > 1) {
|
|
387
|
-
result.keys.push(`${namespace}.${segments.join(".")}`);
|
|
388
|
-
}
|
|
389
|
-
if (segments[0] === "tags") {
|
|
390
|
-
["productUpdates", "tutorials", "makeMoney", "roadOverSea", "insights"].forEach((tag) => {
|
|
391
|
-
result.keys.push(`${namespace}.tags.${tag}`);
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
} else if (pattern.source.includes("\\w+\\.\\w+")) {
|
|
397
|
-
const varName = match2[2];
|
|
398
|
-
match2[3];
|
|
399
|
-
const varPattern = new RegExp(`${varName}\\s*=\\s*{[^}]*key:\\s*['"]([^'"]+)['"]`);
|
|
400
|
-
const varMatch = content.match(varPattern);
|
|
401
|
-
if (varMatch) {
|
|
402
|
-
result.keys.push(`${namespace}.${varMatch[1]}`);
|
|
403
|
-
} else {
|
|
404
|
-
if (content.includes("MenuItem[]") || content.includes("MenuItem}")) {
|
|
405
|
-
["journey"].forEach((menuKey) => {
|
|
406
|
-
result.keys.push(`${namespace}.${menuKey}`);
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
} else {
|
|
411
|
-
const key = match2[2];
|
|
412
|
-
if (!key.includes("/") && key !== "") {
|
|
413
|
-
result.keys.push(`${namespace}.${key}`);
|
|
414
|
-
}
|
|
31
|
+
index.validateConfig(config);
|
|
32
|
+
const exitCode = await checkTranslations.checkTranslations(config, cwd);
|
|
33
|
+
if (typeof process !== 'undefined') {
|
|
34
|
+
process.exit(exitCode);
|
|
415
35
|
}
|
|
416
|
-
}
|
|
417
36
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (!key.includes("/") && key !== "") {
|
|
423
|
-
if (result.namespaces.size > 0) {
|
|
424
|
-
const namespace = Array.from(result.namespaces.values())[0];
|
|
425
|
-
result.keys.push(`${namespace}.${key}`);
|
|
426
|
-
} else {
|
|
427
|
-
const pathMatch = filePath.match(/\[locale\]\/(?:\([^)]+\)\/)?([^/]+)/);
|
|
428
|
-
if (pathMatch && pathMatch[1]) {
|
|
429
|
-
const possibleNamespace = pathMatch[1];
|
|
430
|
-
result.keys.push(`${possibleNamespace}.${key}`);
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error('Error:', error);
|
|
39
|
+
if (typeof process !== 'undefined') {
|
|
40
|
+
process.exit(1);
|
|
431
41
|
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return result;
|
|
436
|
-
}
|
|
437
|
-
function getAllKeys(obj, prefix = "") {
|
|
438
|
-
let keys = [];
|
|
439
|
-
for (const key in obj) {
|
|
440
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
441
|
-
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
442
|
-
if (typeof obj[key] === "object" && obj[key] !== null) {
|
|
443
|
-
keys = [...keys, ...getAllKeys(obj[key], newKey)];
|
|
444
|
-
} else {
|
|
445
|
-
keys.push(newKey);
|
|
446
|
-
}
|
|
447
42
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
return true;
|
|
461
|
-
}
|
|
462
|
-
function checkNamespaceExists(namespace, translations) {
|
|
463
|
-
return translations[namespace] !== void 0;
|
|
464
|
-
}
|
|
465
|
-
function removeKeyFromTranslations(key, translations) {
|
|
466
|
-
const parts = key.split(".");
|
|
467
|
-
const lastPart = parts.pop();
|
|
468
|
-
if (!lastPart) return false;
|
|
469
|
-
let current = translations;
|
|
470
|
-
for (const part of parts) {
|
|
471
|
-
if (current[part] === void 0 || typeof current[part] !== "object") {
|
|
472
|
-
return false;
|
|
473
|
-
}
|
|
474
|
-
current = current[part];
|
|
475
|
-
}
|
|
476
|
-
if (current[lastPart] !== void 0) {
|
|
477
|
-
delete current[lastPart];
|
|
478
|
-
return true;
|
|
479
|
-
}
|
|
480
|
-
return false;
|
|
481
|
-
}
|
|
482
|
-
function cleanEmptyObjects(obj) {
|
|
483
|
-
for (const key in obj) {
|
|
484
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
485
|
-
if (typeof obj[key] === "object" && obj[key] !== null) {
|
|
486
|
-
obj[key] = cleanEmptyObjects(obj[key]);
|
|
487
|
-
if (Object.keys(obj[key]).length === 0) {
|
|
488
|
-
delete obj[key];
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
return obj;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// src/commands/check-translations.ts
|
|
497
|
-
async function checkTranslations(config, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
498
|
-
const logger = new Logger(config);
|
|
499
|
-
logger.warn("==============================");
|
|
500
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd2} \u2B55`);
|
|
501
|
-
logger.warn("==============================");
|
|
502
|
-
try {
|
|
503
|
-
logger.log("start checking translations...");
|
|
504
|
-
const scanResults = await scanFiles(config, cwd2);
|
|
505
|
-
logger.log(`found ${scanResults.length} files to scan`);
|
|
506
|
-
const translations = loadTranslations(config, cwd2);
|
|
507
|
-
const foundTranslationKeys = /* @__PURE__ */ new Set();
|
|
508
|
-
const foundNamespaces = /* @__PURE__ */ new Set();
|
|
509
|
-
for (const { filePath, content } of scanResults) {
|
|
510
|
-
try {
|
|
511
|
-
const { namespaces, keys } = extractTranslationsInfo(content, filePath);
|
|
512
|
-
if (keys.length > 0 || namespaces.size > 0) {
|
|
513
|
-
logger.log(`found the following information in the file ${filePath}:`);
|
|
514
|
-
if (namespaces.size > 0) {
|
|
515
|
-
logger.log(` translation function mapping:`);
|
|
516
|
-
namespaces.forEach((namespace, varName) => {
|
|
517
|
-
logger.log(` - ${varName} => ${namespace}`);
|
|
518
|
-
foundNamespaces.add(namespace);
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
if (keys.length > 0) {
|
|
522
|
-
logger.log(` translation keys:`);
|
|
523
|
-
keys.forEach((key) => {
|
|
524
|
-
logger.log(` - ${key}`);
|
|
525
|
-
foundTranslationKeys.add(key);
|
|
526
|
-
});
|
|
527
|
-
}
|
|
43
|
+
});
|
|
44
|
+
commander.program
|
|
45
|
+
.command('clean-translations')
|
|
46
|
+
.description('clean unused translation keys')
|
|
47
|
+
.option('-v, --verbose', 'show detailed logs', false)
|
|
48
|
+
.option('--remove', 'actually delete unused keys (default only show)', false)
|
|
49
|
+
.action(async (options) => {
|
|
50
|
+
try {
|
|
51
|
+
const config = index.loadConfig(cwd, {}, options.verbose);
|
|
52
|
+
// apply verbose option after loading
|
|
53
|
+
if (options.verbose) {
|
|
54
|
+
config.output.verbose = true;
|
|
528
55
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
logger.error(`error processing file ${filePath}: unknown error`);
|
|
56
|
+
index.validateConfig(config);
|
|
57
|
+
const exitCode = await cleanTranslations.cleanTranslations(config, options.remove, cwd);
|
|
58
|
+
if (typeof process !== 'undefined') {
|
|
59
|
+
process.exit(exitCode);
|
|
534
60
|
}
|
|
535
|
-
}
|
|
536
61
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
config.i18n.locales.forEach((locale) => {
|
|
542
|
-
const missingNamespaceKey = `missingNamespacesIn${locale.toUpperCase()}`;
|
|
543
|
-
if (!checkNamespaceExists(namespace, translations[locale])) {
|
|
544
|
-
report[missingNamespaceKey] = report[missingNamespaceKey] || [];
|
|
545
|
-
report[missingNamespaceKey].push(namespace);
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
});
|
|
549
|
-
foundTranslationKeys.forEach((key) => {
|
|
550
|
-
config.i18n.locales.forEach((locale) => {
|
|
551
|
-
const missingKey = `missingIn${locale.toUpperCase()}`;
|
|
552
|
-
if (!checkKeyExists(key, translations[locale])) {
|
|
553
|
-
report[missingKey] = report[missingKey] || [];
|
|
554
|
-
report[missingKey].push(key);
|
|
555
|
-
}
|
|
556
|
-
});
|
|
557
|
-
});
|
|
558
|
-
config.i18n.locales.forEach((locale) => {
|
|
559
|
-
const allKeys = getAllKeys(translations[locale]);
|
|
560
|
-
config.i18n.locales.forEach((otherLocale) => {
|
|
561
|
-
if (locale !== otherLocale) {
|
|
562
|
-
const otherKeys = getAllKeys(translations[otherLocale]);
|
|
563
|
-
const onlyKeys = `${locale}OnlyKeys`;
|
|
564
|
-
report[onlyKeys] = allKeys.filter((key) => !otherKeys.includes(key));
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
});
|
|
568
|
-
logger.log("\n=== translation check report ===\n");
|
|
569
|
-
config.i18n.locales.forEach((locale) => {
|
|
570
|
-
const missingNamespaceKey = `missingNamespacesIn${locale.toUpperCase()}`;
|
|
571
|
-
if (report[missingNamespaceKey]?.length > 0) {
|
|
572
|
-
logger.log(`\u{1F6A8} missing namespaces in the ${locale} translation file:`);
|
|
573
|
-
report[missingNamespaceKey].forEach((namespace) => logger.log(` - ${namespace}`));
|
|
574
|
-
} else {
|
|
575
|
-
logger.success(`${locale} translation file has all used namespaces`);
|
|
576
|
-
}
|
|
577
|
-
});
|
|
578
|
-
config.i18n.locales.forEach((locale) => {
|
|
579
|
-
const missingKey = `missingIn${locale.toUpperCase()}`;
|
|
580
|
-
if (report[missingKey]?.length > 0) {
|
|
581
|
-
logger.log(`
|
|
582
|
-
\u{1F534} missing keys in the ${locale} translation file:`);
|
|
583
|
-
report[missingKey].forEach((key) => logger.log(` - ${key}`));
|
|
584
|
-
} else {
|
|
585
|
-
logger.success(`${locale} translation file has all used keys`);
|
|
586
|
-
}
|
|
587
|
-
});
|
|
588
|
-
config.i18n.locales.forEach((locale) => {
|
|
589
|
-
const onlyKeys = `${locale}OnlyKeys`;
|
|
590
|
-
if (report[onlyKeys]?.length > 0) {
|
|
591
|
-
logger.log(`
|
|
592
|
-
\u26A0\uFE0F keys only exist in the ${locale} translation file:`);
|
|
593
|
-
report[onlyKeys].forEach((key) => logger.log(` - ${key}`));
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
logger.log("\n=== report end ===\n");
|
|
597
|
-
logger.log("\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0Fscript depends on regular matching, for multiple translation namespaces in a single file, use naming to distinguish: t1 | t2 | t3 | ... \u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F");
|
|
598
|
-
logger.saveToFile("check.log", cwd2);
|
|
599
|
-
return Object.values(report).some((keys) => keys.length > 0) ? 1 : 0;
|
|
600
|
-
} catch (error) {
|
|
601
|
-
logger.error(`error checking translations: ${error}`);
|
|
602
|
-
return 1;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
async function cleanTranslations(config, shouldRemove = false, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
606
|
-
const logger = new Logger(config);
|
|
607
|
-
const logFileName = shouldRemove ? "remove.log" : "clean.log";
|
|
608
|
-
logger.warn("==============================");
|
|
609
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd2} \u2B55`);
|
|
610
|
-
logger.warn("==============================");
|
|
611
|
-
try {
|
|
612
|
-
logger.log("start checking unused translation keys...");
|
|
613
|
-
const scanResults = await scanFiles(config, cwd2);
|
|
614
|
-
logger.log(`\u627E\u5230 ${scanResults.length} \u4E2A\u6587\u4EF6\u9700\u8981\u626B\u63CF`);
|
|
615
|
-
const translations = loadTranslations(config, cwd2);
|
|
616
|
-
const foundTranslationKeys = /* @__PURE__ */ new Set();
|
|
617
|
-
const foundNamespaces = /* @__PURE__ */ new Set();
|
|
618
|
-
for (const { filePath, content } of scanResults) {
|
|
619
|
-
try {
|
|
620
|
-
const { namespaces, keys } = extractTranslationsInfo(content, filePath);
|
|
621
|
-
if (keys.length > 0 || namespaces.size > 0) {
|
|
622
|
-
logger.log(`found the following information in the file ${filePath}:`);
|
|
623
|
-
if (namespaces.size > 0) {
|
|
624
|
-
logger.log(` translation function mapping:`);
|
|
625
|
-
namespaces.forEach((namespace, varName) => {
|
|
626
|
-
logger.log(` - ${varName} => ${namespace}`);
|
|
627
|
-
foundNamespaces.add(namespace);
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
if (keys.length > 0) {
|
|
631
|
-
logger.log(` translation keys:`);
|
|
632
|
-
keys.forEach((key) => {
|
|
633
|
-
logger.log(` - ${key}`);
|
|
634
|
-
foundTranslationKeys.add(key);
|
|
635
|
-
});
|
|
636
|
-
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('Error:', error);
|
|
64
|
+
if (typeof process !== 'undefined') {
|
|
65
|
+
process.exit(1);
|
|
637
66
|
}
|
|
638
|
-
} catch (error) {
|
|
639
|
-
if (error instanceof Error) {
|
|
640
|
-
logger.error(`error processing file ${filePath}: ${error.message}`);
|
|
641
|
-
} else {
|
|
642
|
-
logger.error(`error processing file ${filePath}: unknown error`);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
67
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
const allNamespaces = Object.keys(translations[locale] || {});
|
|
658
|
-
allNamespaces.forEach((namespace) => {
|
|
659
|
-
if (!foundNamespaces.has(namespace)) {
|
|
660
|
-
unusedNamespaces[locale].push(namespace);
|
|
68
|
+
});
|
|
69
|
+
commander.program
|
|
70
|
+
.command('generate-blog-index')
|
|
71
|
+
.description('generate blog index file')
|
|
72
|
+
.option('-v, --verbose', 'show detailed logs', false)
|
|
73
|
+
.action(async (options) => {
|
|
74
|
+
try {
|
|
75
|
+
const config = index.loadConfig(cwd, {}, options.verbose);
|
|
76
|
+
// apply verbose option after loading
|
|
77
|
+
if (options.verbose) {
|
|
78
|
+
config.output.verbose = true;
|
|
661
79
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
if (
|
|
665
|
-
|
|
80
|
+
index.validateConfig(config);
|
|
81
|
+
const exitCode = await generateBlogIndex.generateBlogIndex(config, cwd);
|
|
82
|
+
if (typeof process !== 'undefined') {
|
|
83
|
+
process.exit(exitCode);
|
|
666
84
|
}
|
|
667
|
-
});
|
|
668
|
-
logger.log(`
|
|
669
|
-
found ${unusedKeys[locale].length} unused keys in the ${locale} translation file`);
|
|
670
|
-
logger.log(`found ${unusedNamespaces[locale].length} unused namespaces in the ${locale} translation file`);
|
|
671
|
-
});
|
|
672
|
-
if (shouldRemove) {
|
|
673
|
-
logger.log("\nstart deleting unused translation keys...");
|
|
674
|
-
config.i18n.locales.forEach((locale) => {
|
|
675
|
-
const translationsCopy = { ...translations[locale] };
|
|
676
|
-
unusedKeys[locale].forEach((key) => {
|
|
677
|
-
if (removeKeyFromTranslations(key, translationsCopy)) {
|
|
678
|
-
removedKeys[locale].push(key);
|
|
679
|
-
}
|
|
680
|
-
});
|
|
681
|
-
unusedNamespaces[locale].forEach((namespace) => {
|
|
682
|
-
if (translationsCopy[namespace] !== void 0) {
|
|
683
|
-
delete translationsCopy[namespace];
|
|
684
|
-
logger.log(`deleted unused namespace ${namespace} from the ${locale} translation file`);
|
|
685
|
-
}
|
|
686
|
-
});
|
|
687
|
-
const cleanedTranslations = cleanEmptyObjects(translationsCopy);
|
|
688
|
-
const filePath = getTranslationFilePath(locale, config, cwd2);
|
|
689
|
-
fs.writeFileSync(filePath, JSON.stringify(cleanedTranslations, null, 2), "utf8");
|
|
690
|
-
logger.log(`deleted ${removedKeys[locale].length} unused keys from the ${locale} translation file`);
|
|
691
|
-
});
|
|
692
|
-
} else {
|
|
693
|
-
logger.log("\nTo delete unused keys, please run the script with the --remove parameter");
|
|
694
|
-
}
|
|
695
|
-
logger.log("\n=== unused translation keys report ===\n");
|
|
696
|
-
config.i18n.locales.forEach((locale) => {
|
|
697
|
-
if (unusedNamespaces[locale].length > 0) {
|
|
698
|
-
logger.log(`\u{1F50D} unused namespaces in the ${locale} translation file:`);
|
|
699
|
-
unusedNamespaces[locale].forEach((namespace) => logger.log(` - ${namespace}`));
|
|
700
|
-
} else {
|
|
701
|
-
logger.success(`${locale} translation file has no unused namespaces`);
|
|
702
|
-
}
|
|
703
|
-
if (unusedKeys[locale].length > 0) {
|
|
704
|
-
logger.log(`
|
|
705
|
-
\u{1F50D} unused keys in the ${locale} translation file:`);
|
|
706
|
-
unusedKeys[locale].forEach((key) => logger.log(` - ${key}`));
|
|
707
|
-
} else {
|
|
708
|
-
logger.success(`${locale} translation file has no unused keys`);
|
|
709
|
-
}
|
|
710
|
-
if (shouldRemove && removedKeys[locale].length > 0) {
|
|
711
|
-
logger.log(`
|
|
712
|
-
\u{1F5D1}\uFE0F deleted keys from the ${locale} translation file:`);
|
|
713
|
-
removedKeys[locale].forEach((key) => logger.log(` - ${key}`));
|
|
714
|
-
}
|
|
715
|
-
});
|
|
716
|
-
logger.log("\n=== report end ===\n");
|
|
717
|
-
logger.log("\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0Fscript depends on regular matching, for multiple translation namespaces in a single file, use naming to distinguish: t1 | t2 | t3 | ... \u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F");
|
|
718
|
-
logger.saveToFile(logFileName, cwd2);
|
|
719
|
-
return Object.values(unusedKeys).some((keys) => keys.length > 0) || Object.values(unusedNamespaces).some((namespaces) => namespaces.length > 0) ? 1 : 0;
|
|
720
|
-
} catch (error) {
|
|
721
|
-
logger.error(`error cleaning translations: ${error}`);
|
|
722
|
-
return 1;
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
function parseFrontmatter(fileContent) {
|
|
726
|
-
const frontmatter = {};
|
|
727
|
-
const match = fileContent.match(/^---([\s\S]*?)---/);
|
|
728
|
-
if (match && match[1]) {
|
|
729
|
-
const lines = match[1].trim().split("\n");
|
|
730
|
-
for (const line of lines) {
|
|
731
|
-
const [key, ...valueParts] = line.split(":");
|
|
732
|
-
if (key && valueParts.length > 0) {
|
|
733
|
-
const value = valueParts.join(":").trim();
|
|
734
|
-
if (key.trim() === "title") frontmatter.title = value;
|
|
735
|
-
if (key.trim() === "description") frontmatter.description = value;
|
|
736
|
-
if (key.trim() === "icon") frontmatter.icon = value;
|
|
737
|
-
if (key.trim() === "date") frontmatter.date = value;
|
|
738
|
-
}
|
|
739
85
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
if (!iconName) return void 0;
|
|
745
|
-
return `<${iconName} />`;
|
|
746
|
-
}
|
|
747
|
-
function getCurrentDateString() {
|
|
748
|
-
const now = /* @__PURE__ */ new Date();
|
|
749
|
-
const year = now.getFullYear();
|
|
750
|
-
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
751
|
-
const day = String(now.getDate()).padStart(2, "0");
|
|
752
|
-
return `${year}-${month}-${day}`;
|
|
753
|
-
}
|
|
754
|
-
function updateFrontmatterDate(frontmatter) {
|
|
755
|
-
const currentDate = getCurrentDateString();
|
|
756
|
-
if (frontmatter.includes("date:")) {
|
|
757
|
-
return frontmatter.replace(/date:\s*[^\n]*/, `date: ${currentDate}`);
|
|
758
|
-
} else {
|
|
759
|
-
return frontmatter.replace(/---$/, `date: ${currentDate}
|
|
760
|
-
---`);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
function getBlogPrefix(config) {
|
|
764
|
-
if (config.blog?.prefix === void 0 || config.blog?.prefix === null) {
|
|
765
|
-
return "blog";
|
|
766
|
-
} else if (typeof config.blog?.prefix === "string" && config.blog?.prefix.trim() === "") {
|
|
767
|
-
return "";
|
|
768
|
-
} else {
|
|
769
|
-
return String(config.blog.prefix).trim();
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
async function getAllBlogArticles(blogDir, cwd2, logger) {
|
|
773
|
-
const articles = [];
|
|
774
|
-
const blogPath = path2.join(cwd2, blogDir);
|
|
775
|
-
try {
|
|
776
|
-
const files = fs.readdirSync(blogPath);
|
|
777
|
-
for (const file of files) {
|
|
778
|
-
if (file.endsWith(".mdx") && file !== "index.mdx") {
|
|
779
|
-
const slug = file.replace(/\.mdx$/, "");
|
|
780
|
-
const filePath = path2.join(blogPath, file);
|
|
781
|
-
try {
|
|
782
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
783
|
-
const fm = parseFrontmatter(content);
|
|
784
|
-
if (!fm.title) {
|
|
785
|
-
logger.warn(`Article "${file}" is missing a title in its frontmatter. Skipping.`);
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
articles.push({
|
|
789
|
-
slug,
|
|
790
|
-
title: fm.title,
|
|
791
|
-
description: fm.description,
|
|
792
|
-
frontmatterIcon: fm.icon,
|
|
793
|
-
date: fm.date
|
|
794
|
-
});
|
|
795
|
-
} catch (readError) {
|
|
796
|
-
logger.warn(`Could not read or parse frontmatter for "${file}": ${readError}`);
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.error('Error:', error);
|
|
88
|
+
if (typeof process !== 'undefined') {
|
|
89
|
+
process.exit(1);
|
|
797
90
|
}
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
} catch (dirError) {
|
|
801
|
-
logger.error(`Could not read blog directory: ${dirError}`);
|
|
802
|
-
return [];
|
|
803
|
-
}
|
|
804
|
-
return articles;
|
|
805
|
-
}
|
|
806
|
-
async function generateBlogIndex(config, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
807
|
-
const logger = new Logger(config);
|
|
808
|
-
logger.warn("==============================");
|
|
809
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd2} \u2B55`);
|
|
810
|
-
logger.warn("==============================");
|
|
811
|
-
try {
|
|
812
|
-
if (!config.blog) {
|
|
813
|
-
logger.error("Blog configuration is missing. Please configure blog settings.");
|
|
814
|
-
return 1;
|
|
815
|
-
}
|
|
816
|
-
logger.log("Starting to generate blog index...");
|
|
817
|
-
const blogPath = path2.join(cwd2, config.blog.mdxDir);
|
|
818
|
-
const indexFile = path2.join(blogPath, config.blog.outputFile || "index.mdx");
|
|
819
|
-
const metaFile = path2.join(blogPath, config.blog.metaFile || "meta.json");
|
|
820
|
-
const iocFile = path2.join(blogPath, `${config.blog.iocSlug || "ioc"}.mdx`);
|
|
821
|
-
const iocSlug = config.blog.iocSlug || "ioc";
|
|
822
|
-
const blogPrefix = getBlogPrefix(config);
|
|
823
|
-
let meta = { pages: [] };
|
|
824
|
-
const metaContent = readJsonFile(metaFile);
|
|
825
|
-
if (metaContent) {
|
|
826
|
-
meta = metaContent;
|
|
827
|
-
} else {
|
|
828
|
-
logger.warn(`Could not read or parse ${metaFile}. No articles will be marked as featured.`);
|
|
829
|
-
}
|
|
830
|
-
const hiddenSlugs = new Set(
|
|
831
|
-
meta.pages.filter((p) => p.startsWith("!")).map((p) => p.slice(1))
|
|
832
|
-
);
|
|
833
|
-
const featuredSlugs = meta.pages.filter((p) => !p.startsWith("!")).map((p) => p.endsWith(".mdx") ? p.slice(0, -4) : p).filter((slug) => slug !== "index" && slug !== "...");
|
|
834
|
-
logger.log(`Featured slugs (meta-config): ${featuredSlugs.join(", ")}`);
|
|
835
|
-
const allArticles = await getAllBlogArticles(config.blog.mdxDir, cwd2, logger);
|
|
836
|
-
logger.log(`Found ${allArticles.length} all articles.`);
|
|
837
|
-
const visibleArticles = allArticles.filter((a) => !hiddenSlugs.has(a.slug));
|
|
838
|
-
const iocArticle = visibleArticles.find((a) => a.slug === iocSlug);
|
|
839
|
-
const filteredArticles = visibleArticles.filter((a) => a.slug !== iocSlug);
|
|
840
|
-
if (filteredArticles.length === 0 && featuredSlugs.length === 0) {
|
|
841
|
-
logger.warn("No articles found or featured. The generated index might be empty or minimal.");
|
|
842
|
-
}
|
|
843
|
-
const featuredArticles = [];
|
|
844
|
-
const pastArticles = [];
|
|
845
|
-
filteredArticles.forEach((article) => {
|
|
846
|
-
if (featuredSlugs.includes(article.slug)) {
|
|
847
|
-
featuredArticles.push(article);
|
|
848
|
-
} else {
|
|
849
|
-
pastArticles.push(article);
|
|
850
|
-
}
|
|
851
|
-
});
|
|
852
|
-
const sortByDateDesc = (a, b) => {
|
|
853
|
-
if (a.date && b.date) {
|
|
854
|
-
return b.date.localeCompare(a.date);
|
|
855
|
-
}
|
|
856
|
-
if (a.date) return -1;
|
|
857
|
-
if (b.date) return 1;
|
|
858
|
-
return 0;
|
|
859
|
-
};
|
|
860
|
-
featuredArticles.sort(sortByDateDesc);
|
|
861
|
-
pastArticles.sort(sortByDateDesc);
|
|
862
|
-
logger.log(`Found ${featuredArticles.length} featured articles (sorted by date).`);
|
|
863
|
-
logger.log(`Found ${pastArticles.length} past articles (sorted by date).`);
|
|
864
|
-
let currentFileFrontmatter = "---\ntitle: Blog\ndescription: Articles and thoughts about various topics.\nicon: Rss\n---";
|
|
865
|
-
try {
|
|
866
|
-
const currentIndexContent = fs.readFileSync(indexFile, "utf-8");
|
|
867
|
-
const frontmatterMatch = currentIndexContent.match(/^---([\s\S]*?)---/);
|
|
868
|
-
if (frontmatterMatch && frontmatterMatch[0]) {
|
|
869
|
-
currentFileFrontmatter = frontmatterMatch[0];
|
|
870
|
-
logger.log("Preserving existing frontmatter from index.mdx");
|
|
871
|
-
}
|
|
872
|
-
} catch (error) {
|
|
873
|
-
logger.warn("Could not read existing index.mdx or parse its frontmatter. Using default frontmatter.");
|
|
874
91
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
const escapedTitle = (article.title || "").replace(/"/g, """);
|
|
883
|
-
const cardContent = article.date || article.description || "";
|
|
884
|
-
const finalIconProp = iconProp ? `${iconProp} ` : "";
|
|
885
|
-
const href = blogPrefix ? `${blogPrefix}/${article.slug}` : `${article.slug}`;
|
|
886
|
-
return ` <ZiaCard ${finalIconProp} href="${href}" title="${escapedTitle}">
|
|
887
|
-
${cardContent}
|
|
888
|
-
</ZiaCard>
|
|
889
|
-
`;
|
|
890
|
-
};
|
|
891
|
-
if (featuredArticles.length > 0) {
|
|
892
|
-
mdxContent += `## Feature List
|
|
893
|
-
|
|
894
|
-
<Cards>
|
|
895
|
-
`;
|
|
896
|
-
featuredArticles.forEach((article) => {
|
|
897
|
-
mdxContent += createCard(article);
|
|
898
|
-
});
|
|
899
|
-
mdxContent += `</Cards>
|
|
900
|
-
|
|
901
|
-
`;
|
|
902
|
-
}
|
|
903
|
-
if (pastArticles.length > 0) {
|
|
904
|
-
mdxContent += `## Past List
|
|
905
|
-
|
|
906
|
-
<Cards>
|
|
907
|
-
`;
|
|
908
|
-
pastArticles.forEach((article) => {
|
|
909
|
-
mdxContent += createCard(article);
|
|
910
|
-
});
|
|
911
|
-
mdxContent += `</Cards>
|
|
912
|
-
`;
|
|
913
|
-
}
|
|
914
|
-
if (iocArticle) {
|
|
915
|
-
mdxContent += `
|
|
916
|
-
## Monthly Summary
|
|
917
|
-
|
|
918
|
-
<Cards>
|
|
919
|
-
`;
|
|
920
|
-
const iocHref = blogPrefix ? `${blogPrefix}/${iocSlug}` : `${iocSlug}`;
|
|
921
|
-
mdxContent += ` <ZiaCard href="${iocHref}" title="Overview">
|
|
922
|
-
${getCurrentDateString()}
|
|
923
|
-
</ZiaCard>
|
|
924
|
-
`;
|
|
925
|
-
mdxContent += `</Cards>
|
|
926
|
-
`;
|
|
927
|
-
}
|
|
928
|
-
if (featuredArticles.length === 0 && pastArticles.length === 0 && !iocArticle) {
|
|
929
|
-
mdxContent += "## Ooops\nNo blog posts found yet. Stay tuned!\n";
|
|
930
|
-
}
|
|
931
|
-
fs.writeFileSync(indexFile, mdxContent);
|
|
932
|
-
logger.success(`Successfully generated ${indexFile}`);
|
|
933
|
-
await generateMonthlyBlogSummary(config, visibleArticles, iocFile, iocSlug, logger);
|
|
934
|
-
logger.log("Blog index generation completed successfully!");
|
|
935
|
-
logger.saveToFile("generate-blog.log", cwd2);
|
|
936
|
-
return 0;
|
|
937
|
-
} catch (error) {
|
|
938
|
-
logger.error(`Error generating blog index: ${error}`);
|
|
939
|
-
return 1;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
async function generateMonthlyBlogSummary(config, articles, iocFile, iocSlug, logger) {
|
|
943
|
-
try {
|
|
944
|
-
const articlesWithDate = articles.filter((a) => a.date && a.slug !== iocSlug);
|
|
945
|
-
const monthMap = {};
|
|
946
|
-
for (const art of articlesWithDate) {
|
|
947
|
-
const month = art.date.slice(0, 7);
|
|
948
|
-
if (!monthMap[month]) monthMap[month] = [];
|
|
949
|
-
monthMap[month].push({ date: art.date, title: art.title, slug: art.slug });
|
|
950
|
-
}
|
|
951
|
-
const sortedMonths = Object.keys(monthMap).sort((a, b) => b.localeCompare(a));
|
|
952
|
-
for (const month of sortedMonths) {
|
|
953
|
-
monthMap[month].sort((a, b) => b.date.localeCompare(a.date));
|
|
954
|
-
}
|
|
955
|
-
let frontmatter = "";
|
|
92
|
+
});
|
|
93
|
+
commander.program
|
|
94
|
+
.command('deep-clean')
|
|
95
|
+
.description('clean all node_modules, dist, .next, .turbo and related caches in monorepo')
|
|
96
|
+
.option('--yes', 'actually delete matched directories (default only preview)', false)
|
|
97
|
+
.option('-v, --verbose', 'show detailed logs', false)
|
|
98
|
+
.action(async (options) => {
|
|
956
99
|
try {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
} catch {
|
|
961
|
-
}
|
|
962
|
-
if (!frontmatter) {
|
|
963
|
-
frontmatter = "---\ntitle: Monthly Summary\ndescription: Index and Summary\n---";
|
|
964
|
-
}
|
|
965
|
-
frontmatter = updateFrontmatterDate(frontmatter);
|
|
966
|
-
let mdx = `${frontmatter}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
## Overview
|
|
970
|
-
<Files>
|
|
971
|
-
`;
|
|
972
|
-
if (sortedMonths.length === 0) {
|
|
973
|
-
mdx += ' <ZiaFile name="Comming Soon" className="opacity-50" disabled/>\n';
|
|
974
|
-
} else {
|
|
975
|
-
for (const month of sortedMonths) {
|
|
976
|
-
const count = monthMap[month].length;
|
|
977
|
-
const folderTitle = `${month}(${count})`;
|
|
978
|
-
const defaultOpen = month === sortedMonths[0] ? " defaultOpen" : "";
|
|
979
|
-
mdx += ` <ZiaFolder name="${folderTitle}"${defaultOpen}>
|
|
980
|
-
`;
|
|
981
|
-
for (const art of monthMap[month]) {
|
|
982
|
-
const day = art.date.slice(0, 10);
|
|
983
|
-
const href = art.slug ? `./${art.slug}` : "";
|
|
984
|
-
mdx += ` <ZiaFile name="${day}(${art.title})" href="${href}" />
|
|
985
|
-
`;
|
|
100
|
+
const config = index.loadConfig(cwd, {}, options.verbose);
|
|
101
|
+
if (options.verbose) {
|
|
102
|
+
config.output.verbose = true;
|
|
986
103
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
mdx += "</Files>\n\n";
|
|
992
|
-
fs.writeFileSync(iocFile, mdx);
|
|
993
|
-
logger.success(`Successfully generated Monthly Blog Summary: ${iocFile}`);
|
|
994
|
-
} catch (error) {
|
|
995
|
-
logger.error(`Error generating monthly blog summary: ${error}`);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
var MONOREPO_CLEAN_TARGETS = [
|
|
999
|
-
{ pattern: "node_modules", description: "Root directory dependencies" },
|
|
1000
|
-
{ pattern: "packages/*/node_modules", description: "Package dependencies" },
|
|
1001
|
-
{ pattern: "apps/*/node_modules", description: "Application dependencies" },
|
|
1002
|
-
{ pattern: "apps/*/.next", description: "Next.js cache" },
|
|
1003
|
-
{ pattern: "packages/*/dist", description: "Package build artifacts" },
|
|
1004
|
-
{ pattern: "apps/*/dist", description: "Application build artifacts" },
|
|
1005
|
-
{ pattern: ".turbo", description: "Root directory Turbo cache" },
|
|
1006
|
-
{ pattern: "packages/*/.turbo", description: "Package Turbo cache" },
|
|
1007
|
-
{ pattern: "apps/*/.turbo", description: "Application Turbo cache" },
|
|
1008
|
-
{ pattern: "pnpm-lock.yaml", description: "pnpm lock file", isFile: true }
|
|
1009
|
-
];
|
|
1010
|
-
var SINGLE_CLEAN_TARGETS = [
|
|
1011
|
-
{ pattern: "node_modules", description: "Root directory dependencies" },
|
|
1012
|
-
{ pattern: ".next", description: "Next.js cache" },
|
|
1013
|
-
{ pattern: "pnpm-lock.yaml", description: "pnpm lock file", isFile: true }
|
|
1014
|
-
];
|
|
1015
|
-
function globDirsOrFiles(pattern, cwd2, isFile) {
|
|
1016
|
-
if (!pattern.includes("*")) {
|
|
1017
|
-
const abs = path2.resolve(cwd2, pattern);
|
|
1018
|
-
if (isFile) {
|
|
1019
|
-
return fs.existsSync(abs) ? [abs] : [];
|
|
1020
|
-
}
|
|
1021
|
-
return fs.existsSync(abs) && fs.statSync(abs).isDirectory() ? [abs] : [];
|
|
1022
|
-
}
|
|
1023
|
-
const [base, rest] = pattern.split("/*");
|
|
1024
|
-
const absBase = path2.resolve(cwd2, base);
|
|
1025
|
-
if (!fs.existsSync(absBase) || !fs.statSync(absBase).isDirectory()) return [];
|
|
1026
|
-
const subdirs = fs.readdirSync(absBase);
|
|
1027
|
-
return subdirs.map((d) => path2.join(absBase, d, rest.replace(/^[\/]/, ""))).filter((p) => fs.existsSync(p) && (isFile ? true : fs.statSync(p).isDirectory()));
|
|
1028
|
-
}
|
|
1029
|
-
async function deepClean(config, yes = false, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
1030
|
-
const logger = new Logger(config);
|
|
1031
|
-
if (process.env.NODE_ENV === "production") {
|
|
1032
|
-
logger.error("\u274C Production environment prohibits deep clean operations");
|
|
1033
|
-
logger.log(" If you need to clean, please set: NODE_ENV=development");
|
|
1034
|
-
logger.saveToFile("deep-clean.log", cwd2);
|
|
1035
|
-
return 1;
|
|
1036
|
-
}
|
|
1037
|
-
logger.warn("==============================");
|
|
1038
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd2} \u2B55`);
|
|
1039
|
-
logger.warn("==============================");
|
|
1040
|
-
const isMonorepo = fs.existsSync(path2.resolve(cwd2, "pnpm-workspace.yaml"));
|
|
1041
|
-
const cleanTargets = isMonorepo ? MONOREPO_CLEAN_TARGETS : SINGLE_CLEAN_TARGETS;
|
|
1042
|
-
let totalToDelete = [];
|
|
1043
|
-
let groupDeleteMap = {};
|
|
1044
|
-
for (const target of cleanTargets) {
|
|
1045
|
-
const found = globDirsOrFiles(target.pattern, cwd2, target.isFile);
|
|
1046
|
-
groupDeleteMap[target.description] = found;
|
|
1047
|
-
if (found.length === 0) {
|
|
1048
|
-
logger.info(`\u{1F4AF} ${target.description}: No need to clean`);
|
|
1049
|
-
} else {
|
|
1050
|
-
logger.log(`
|
|
1051
|
-
[${target.description}]`);
|
|
1052
|
-
found.forEach((p) => logger.warn(`\u{1F459} [Preview] ${p}`));
|
|
1053
|
-
totalToDelete.push(...found);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
if (totalToDelete.length === 0) {
|
|
1057
|
-
logger.success("No directories or files to clean.");
|
|
1058
|
-
logger.saveToFile("deep-clean.log", cwd2);
|
|
1059
|
-
return 0;
|
|
1060
|
-
}
|
|
1061
|
-
if (!yes) {
|
|
1062
|
-
logger.log("\nIf you need to actually delete, please add --yes parameter.");
|
|
1063
|
-
logger.saveToFile("deep-clean.log", cwd2);
|
|
1064
|
-
return 0;
|
|
1065
|
-
}
|
|
1066
|
-
let deleted = 0;
|
|
1067
|
-
for (const target of cleanTargets) {
|
|
1068
|
-
const items = groupDeleteMap[target.description] || [];
|
|
1069
|
-
if (items.length > 0) {
|
|
1070
|
-
logger.log(`
|
|
1071
|
-
[${target.description}]`);
|
|
1072
|
-
for (const p of items) {
|
|
1073
|
-
try {
|
|
1074
|
-
if (target.isFile) {
|
|
1075
|
-
fs.unlinkSync(p);
|
|
1076
|
-
if (!fs.existsSync(p)) {
|
|
1077
|
-
logger.success(`\u{1F37B} Deleted: ${p}`);
|
|
1078
|
-
deleted++;
|
|
1079
|
-
} else {
|
|
1080
|
-
logger.error(`\u274C Delete failed: ${p} (file still exists)`);
|
|
1081
|
-
}
|
|
1082
|
-
} else {
|
|
1083
|
-
fs.rmSync(p, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
1084
|
-
if (!fs.existsSync(p)) {
|
|
1085
|
-
logger.success(`\u{1F37B} Deleted: ${p}`);
|
|
1086
|
-
deleted++;
|
|
1087
|
-
} else {
|
|
1088
|
-
logger.error(`\u274C Delete failed: ${p} (directory still exists)`);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
} catch (e) {
|
|
1092
|
-
logger.error(`\u274C Delete failed: ${p} (${e.message})`);
|
|
104
|
+
index.validateConfig(config);
|
|
105
|
+
const exitCode = await deepClean.deepClean(config, options.yes, cwd);
|
|
106
|
+
if (typeof process !== 'undefined') {
|
|
107
|
+
process.exit(exitCode);
|
|
1093
108
|
}
|
|
1094
|
-
}
|
|
1095
109
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
return 0;
|
|
1101
|
-
}
|
|
1102
|
-
async function easyChangeset(cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
1103
|
-
if (process.env.NODE_ENV === "production") {
|
|
1104
|
-
console.log("\u274C Production environment prohibits deep clean operations");
|
|
1105
|
-
console.log(" If you need to clean, please set: NODE_ENV=development");
|
|
1106
|
-
return 1;
|
|
1107
|
-
}
|
|
1108
|
-
console.log("==============================");
|
|
1109
|
-
console.log(`\u203C\uFE0F Current working directory: \u2B55 ${cwd2} \u2B55`);
|
|
1110
|
-
console.log("==============================");
|
|
1111
|
-
const changesetDir = path2.join(cwd2, ".changeset");
|
|
1112
|
-
const mdxFile = path2.join(changesetDir, "d8-template.mdx");
|
|
1113
|
-
const mdFile = path2.join(changesetDir, "d8-template.md");
|
|
1114
|
-
if (!fs.existsSync(changesetDir)) {
|
|
1115
|
-
console.log("\u274C No .changeset directory found, skipping.");
|
|
1116
|
-
return 1;
|
|
1117
|
-
}
|
|
1118
|
-
if (!fs.existsSync(mdxFile)) {
|
|
1119
|
-
console.log("\u274C No .changeset/d8-template.mdx file found, skipping.");
|
|
1120
|
-
return 1;
|
|
1121
|
-
}
|
|
1122
|
-
try {
|
|
1123
|
-
const content = fs.readFileSync(mdxFile, "utf-8");
|
|
1124
|
-
fs.writeFileSync(mdFile, content, "utf-8");
|
|
1125
|
-
console.log("\u2705 Copied d8-template.mdx content to d8-template.md");
|
|
1126
|
-
return 0;
|
|
1127
|
-
} catch (e) {
|
|
1128
|
-
console.log("\u274C Copy failed:", e.message);
|
|
1129
|
-
return 1;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
function getCurrentDateString2() {
|
|
1133
|
-
const now = /* @__PURE__ */ new Date();
|
|
1134
|
-
const year = now.getFullYear();
|
|
1135
|
-
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
1136
|
-
const day = String(now.getDate()).padStart(2, "0");
|
|
1137
|
-
return `${year}-${month}-${day}`;
|
|
1138
|
-
}
|
|
1139
|
-
async function generateNextjsArchitecture(config, cwd2 = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
1140
|
-
const logger = new Logger(config);
|
|
1141
|
-
try {
|
|
1142
|
-
let renderTree2 = function(nodes, depth = 0, parentPath = "") {
|
|
1143
|
-
let mdx2 = "";
|
|
1144
|
-
for (const node of nodes) {
|
|
1145
|
-
const nodePath = parentPath ? `${parentPath}/${node.name}` : node.name;
|
|
1146
|
-
const anotion = architectureConfig[node.name] || "";
|
|
1147
|
-
const displayName = depth === 0 && node.name === "." ? "ROOT" : node.name;
|
|
1148
|
-
if (node.type === "directory") {
|
|
1149
|
-
if (!node.contents || node.contents.length === 0) {
|
|
1150
|
-
mdx2 += `${" ".repeat(depth)}<ZiaFolder name="${displayName}" anotion="${anotion}" className="opacity-50" disabled/>
|
|
1151
|
-
`;
|
|
1152
|
-
} else {
|
|
1153
|
-
mdx2 += `${" ".repeat(depth)}<ZiaFolder name="${displayName}" anotion="${anotion}" defaultOpen>
|
|
1154
|
-
`;
|
|
1155
|
-
mdx2 += renderTree2(node.contents, depth + 1, nodePath);
|
|
1156
|
-
mdx2 += `${" ".repeat(depth)}</ZiaFolder>
|
|
1157
|
-
`;
|
|
1158
|
-
}
|
|
1159
|
-
} else if (node.type === "file") {
|
|
1160
|
-
mdx2 += `${" ".repeat(depth)}<ZiaFile name="${node.name}" anotion="${anotion}" href="" />
|
|
1161
|
-
`;
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error('Error:', error);
|
|
112
|
+
if (typeof process !== 'undefined') {
|
|
113
|
+
process.exit(1);
|
|
1162
114
|
}
|
|
1163
|
-
}
|
|
1164
|
-
return mdx2;
|
|
1165
|
-
};
|
|
1166
|
-
var renderTree = renderTree2;
|
|
1167
|
-
const logsDir = path2.join(cwd2, config.output?.logDir || "logs");
|
|
1168
|
-
const blogDir = path2.join(cwd2, config.blog?.mdxDir || "src/mdx/blog");
|
|
1169
|
-
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
1170
|
-
if (!fs.existsSync(blogDir)) fs.mkdirSync(blogDir, { recursive: true });
|
|
1171
|
-
const treeJsonPath = path2.join(logsDir, "project_tree.json");
|
|
1172
|
-
logger.log(`Running tree command to generate ${treeJsonPath}`);
|
|
1173
|
-
child_process.execSync(`tree -a -J -I '.next|node_modules|logs|dist|pnpm-lock.yaml|turbo|.turbo|public|.cursor|.DS_Store|.git' > ${treeJsonPath}`);
|
|
1174
|
-
const tree = readJsonFile(treeJsonPath);
|
|
1175
|
-
if (!tree) {
|
|
1176
|
-
logger.error("Failed to read tree JSON result!");
|
|
1177
|
-
return 1;
|
|
1178
|
-
}
|
|
1179
|
-
const userConfig = config.architectureConfig || {};
|
|
1180
|
-
const architectureConfig = { ...DEFAULT_CONFIG.architectureConfig || {}, ...userConfig };
|
|
1181
|
-
const frontmatter = `---
|
|
1182
|
-
title: About Project Structure
|
|
1183
|
-
description: Show all source code directories and files
|
|
1184
|
-
icon: Gift
|
|
1185
|
-
date: ${getCurrentDateString2()}
|
|
1186
|
-
---
|
|
1187
|
-
|
|
1188
|
-
## Quick Started
|
|
1189
|
-
|
|
1190
|
-
`;
|
|
1191
|
-
const filesContent = renderTree2(tree);
|
|
1192
|
-
const indentedFilesContent = filesContent.split("\n").map((line) => line ? " " + line : "").join("\n");
|
|
1193
|
-
const mdx = frontmatter + "<Files>\n" + indentedFilesContent + "</Files>\n";
|
|
1194
|
-
const outputMdxPath = path2.join(blogDir, "nextjs-architecture.mdx");
|
|
1195
|
-
fs.writeFileSync(outputMdxPath, mdx);
|
|
1196
|
-
logger.success(`Successfully generated ${outputMdxPath}`);
|
|
1197
|
-
logger.saveToFile("generate-nextjs-architecture.log", cwd2);
|
|
1198
|
-
return 0;
|
|
1199
|
-
} catch (error) {
|
|
1200
|
-
logger.error(`Error generating nextjs architecture mdx: ${error}`);
|
|
1201
|
-
return 1;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
async function createDiaomaoApp(targetDir) {
|
|
1205
|
-
if (!targetDir) {
|
|
1206
|
-
console.error("Usage: create-diaomao-app <project-name>");
|
|
1207
|
-
process.exit(1);
|
|
1208
|
-
}
|
|
1209
|
-
const cwd2 = process.cwd();
|
|
1210
|
-
const cwdPackageJson = path2__default.default.join(cwd2, "package.json");
|
|
1211
|
-
const cwdWorkspaceYaml = path2__default.default.join(cwd2, "pnpm-workspace.yaml");
|
|
1212
|
-
const hasPkgJson = await fsExtra.pathExists(cwdPackageJson);
|
|
1213
|
-
const hasWorkspace = await fsExtra.pathExists(cwdWorkspaceYaml);
|
|
1214
|
-
let destDir;
|
|
1215
|
-
if (hasPkgJson && hasWorkspace) {
|
|
1216
|
-
console.error("Detected monorepo environment, NextJS DO NOT SUPPORT MONOREPO WELL!");
|
|
1217
|
-
process.exit(1);
|
|
1218
|
-
} else if (hasPkgJson && !hasWorkspace) {
|
|
1219
|
-
console.error("Warning: You are in a directory that already contains package.json");
|
|
1220
|
-
console.error("This might create a nested project structure which is usually not intended.");
|
|
1221
|
-
console.error("");
|
|
1222
|
-
console.error("Recommendations:");
|
|
1223
|
-
console.error("- If you want to create a standalone project, run this command in an empty directory");
|
|
1224
|
-
console.error("- If you want to add to a monorepo, run this command in the monorepo root");
|
|
1225
|
-
console.error("");
|
|
1226
|
-
process.exit(1);
|
|
1227
|
-
} else {
|
|
1228
|
-
destDir = path2__default.default.resolve(cwd2, targetDir);
|
|
1229
|
-
}
|
|
1230
|
-
const tempDir = path2__default.default.join(os__default.default.tmpdir(), `diaomao-template-${Date.now()}`);
|
|
1231
|
-
console.log(`Creating project: ${targetDir}...`);
|
|
1232
|
-
try {
|
|
1233
|
-
await fsExtra.ensureDir(tempDir);
|
|
1234
|
-
console.log("Downloading diaomao template from npm...");
|
|
1235
|
-
child_process.execSync(`npm pack @windrun-huaiin/diaomao`, { cwd: tempDir, stdio: "inherit" });
|
|
1236
|
-
const packageFiles = child_process.execSync("ls *.tgz", { cwd: tempDir, encoding: "utf8" }).trim().split("\n");
|
|
1237
|
-
const packageFile = packageFiles[0];
|
|
1238
|
-
child_process.execSync(`tar -xzf ${packageFile}`, { cwd: tempDir });
|
|
1239
|
-
const templateDir = path2__default.default.join(tempDir, "package");
|
|
1240
|
-
await fsExtra.copy(templateDir, destDir, { overwrite: true });
|
|
1241
|
-
const envTxtPath = path2__default.default.join(destDir, ".env.local.txt");
|
|
1242
|
-
const envPath = path2__default.default.join(destDir, ".env.local");
|
|
1243
|
-
if (await fsExtra.pathExists(envTxtPath)) {
|
|
1244
|
-
await fsExtra.rename(envTxtPath, envPath);
|
|
1245
|
-
console.log("Renamed .env.local.txt to .env.local");
|
|
1246
|
-
}
|
|
1247
|
-
const changesetDir = path2__default.default.join(destDir, ".changeset");
|
|
1248
|
-
if (await fsExtra.pathExists(changesetDir)) {
|
|
1249
|
-
const templateFile = path2__default.default.join(changesetDir, "d8-template.mdx");
|
|
1250
|
-
const changesetContent = `---
|
|
1251
|
-
"${path2__default.default.basename(targetDir)}": major
|
|
1252
|
-
---
|
|
1253
|
-
|
|
1254
|
-
feat(init): app created by @windrun-huaiin/diaomao`;
|
|
1255
|
-
await fsExtra.writeFile(templateFile, changesetContent, "utf8");
|
|
1256
|
-
console.log("Created changeset template file: d8-template.mdx");
|
|
1257
|
-
}
|
|
1258
|
-
const pkgPath = path2__default.default.join(destDir, "package.json");
|
|
1259
|
-
const pkg = await fsExtra.readJson(pkgPath);
|
|
1260
|
-
pkg.name = path2__default.default.basename(targetDir);
|
|
1261
|
-
pkg.version = "1.0.0";
|
|
1262
|
-
pkg.private = true;
|
|
1263
|
-
pkg.pnpm = {
|
|
1264
|
-
"onlyBuiltDependencies": [
|
|
1265
|
-
"@clerk/shared",
|
|
1266
|
-
"@parcel/watcher",
|
|
1267
|
-
"@tailwindcss/oxide",
|
|
1268
|
-
"core-js",
|
|
1269
|
-
"esbuild",
|
|
1270
|
-
"sharp",
|
|
1271
|
-
"unrs-resolver"
|
|
1272
|
-
],
|
|
1273
|
-
"overrides": {
|
|
1274
|
-
"@types/react": "19.1.2",
|
|
1275
|
-
"@types/react-dom": "19.1.3"
|
|
1276
|
-
},
|
|
1277
|
-
"patchedDependencies": {
|
|
1278
|
-
"fumadocs-ui@15.3.3": "patches/fumadocs-ui@15.3.3.patch"
|
|
1279
|
-
}
|
|
1280
|
-
};
|
|
1281
|
-
if (pkg.scripts) {
|
|
1282
|
-
delete pkg.scripts["djvp"];
|
|
1283
115
|
}
|
|
1284
|
-
delete pkg.publishConfig;
|
|
1285
|
-
delete pkg.files;
|
|
1286
|
-
await fsExtra.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
1287
|
-
console.log("Installing dependencies...");
|
|
1288
|
-
try {
|
|
1289
|
-
child_process.execSync("pnpm install", { cwd: destDir, stdio: "inherit" });
|
|
1290
|
-
} catch (error) {
|
|
1291
|
-
console.warn("pnpm failed, trying npm...");
|
|
1292
|
-
try {
|
|
1293
|
-
child_process.execSync("npm install", { cwd: destDir, stdio: "inherit" });
|
|
1294
|
-
} catch (npmError) {
|
|
1295
|
-
console.error("Failed to install dependencies. Please run npm install or pnpm install manually.");
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
console.log("Initializing Git repository...");
|
|
1299
|
-
try {
|
|
1300
|
-
child_process.execSync("git init", { cwd: destDir, stdio: "inherit" });
|
|
1301
|
-
child_process.execSync("git add .", { cwd: destDir, stdio: "inherit" });
|
|
1302
|
-
child_process.execSync('git commit -m "feat: initial commit from diaomao template"', { cwd: destDir, stdio: "inherit" });
|
|
1303
|
-
} catch (error) {
|
|
1304
|
-
console.warn("Failed to initialize Git repository. Please initialize manually.");
|
|
1305
|
-
}
|
|
1306
|
-
console.log(`
|
|
1307
|
-
\u2705 Project created: ${destDir}`);
|
|
1308
|
-
console.log(`
|
|
1309
|
-
Next steps:`);
|
|
1310
|
-
console.log(` cd ${targetDir}`);
|
|
1311
|
-
console.log(` pnpm build`);
|
|
1312
|
-
console.log(` pnpm dev`);
|
|
1313
|
-
console.log(` NOTE: if you want to update @windrun-huaiin packages, please run pnpm windrun`);
|
|
1314
|
-
console.log(` NOTE: please check .env.local file and set your own env!`);
|
|
1315
|
-
} catch (error) {
|
|
1316
|
-
console.error("Failed to create project:", error);
|
|
1317
|
-
process.exit(1);
|
|
1318
|
-
} finally {
|
|
1319
|
-
try {
|
|
1320
|
-
await fsExtra.remove(tempDir);
|
|
1321
|
-
} catch (cleanupError) {
|
|
1322
|
-
console.warn("Failed to cleanup temporary directory:", tempDir);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
// src/cli.ts
|
|
1328
|
-
var cwd = typeof process !== "undefined" ? process.cwd() : ".";
|
|
1329
|
-
commander.program.name("dev-scripts").description("development scripts for multi-language projects").version("5.0.0");
|
|
1330
|
-
commander.program.command("check-translations").description("check the completeness and consistency of translation files").option("-v, --verbose", "show detailed logs", false).action(async (options) => {
|
|
1331
|
-
try {
|
|
1332
|
-
const config = loadConfig(cwd, {}, options.verbose);
|
|
1333
|
-
if (options.verbose) {
|
|
1334
|
-
config.output.verbose = true;
|
|
1335
|
-
}
|
|
1336
|
-
validateConfig(config);
|
|
1337
|
-
const exitCode = await checkTranslations(config, cwd);
|
|
1338
|
-
if (typeof process !== "undefined") {
|
|
1339
|
-
process.exit(exitCode);
|
|
1340
|
-
}
|
|
1341
|
-
} catch (error) {
|
|
1342
|
-
console.error("Error:", error);
|
|
1343
|
-
if (typeof process !== "undefined") {
|
|
1344
|
-
process.exit(1);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
});
|
|
1348
|
-
commander.program.command("clean-translations").description("clean unused translation keys").option("-v, --verbose", "show detailed logs", false).option("--remove", "actually delete unused keys (default only show)", false).action(async (options) => {
|
|
1349
|
-
try {
|
|
1350
|
-
const config = loadConfig(cwd, {}, options.verbose);
|
|
1351
|
-
if (options.verbose) {
|
|
1352
|
-
config.output.verbose = true;
|
|
1353
|
-
}
|
|
1354
|
-
validateConfig(config);
|
|
1355
|
-
const exitCode = await cleanTranslations(config, options.remove, cwd);
|
|
1356
|
-
if (typeof process !== "undefined") {
|
|
1357
|
-
process.exit(exitCode);
|
|
1358
|
-
}
|
|
1359
|
-
} catch (error) {
|
|
1360
|
-
console.error("Error:", error);
|
|
1361
|
-
if (typeof process !== "undefined") {
|
|
1362
|
-
process.exit(1);
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
});
|
|
1366
|
-
commander.program.command("generate-blog-index").description("generate blog index file").option("-v, --verbose", "show detailed logs", false).action(async (options) => {
|
|
1367
|
-
try {
|
|
1368
|
-
const config = loadConfig(cwd, {}, options.verbose);
|
|
1369
|
-
if (options.verbose) {
|
|
1370
|
-
config.output.verbose = true;
|
|
1371
|
-
}
|
|
1372
|
-
validateConfig(config);
|
|
1373
|
-
const exitCode = await generateBlogIndex(config, cwd);
|
|
1374
|
-
if (typeof process !== "undefined") {
|
|
1375
|
-
process.exit(exitCode);
|
|
1376
|
-
}
|
|
1377
|
-
} catch (error) {
|
|
1378
|
-
console.error("Error:", error);
|
|
1379
|
-
if (typeof process !== "undefined") {
|
|
1380
|
-
process.exit(1);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
116
|
});
|
|
1384
|
-
commander.program
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
process.exit(exitCode);
|
|
117
|
+
commander.program
|
|
118
|
+
.command('easy-changeset')
|
|
119
|
+
.description('copy .changeset/d8-template.mdx to .changeset/d8-template.md if both exist')
|
|
120
|
+
.action(async () => {
|
|
121
|
+
try {
|
|
122
|
+
const exitCode = await easyChangeset.easyChangeset(cwd);
|
|
123
|
+
if (typeof process !== 'undefined') {
|
|
124
|
+
process.exit(exitCode);
|
|
125
|
+
}
|
|
1394
126
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
127
|
+
catch (error) {
|
|
128
|
+
console.error('Error:', error);
|
|
129
|
+
if (typeof process !== 'undefined') {
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
1399
132
|
}
|
|
1400
|
-
}
|
|
1401
133
|
});
|
|
1402
|
-
commander.program
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
134
|
+
commander.program
|
|
135
|
+
.command('generate-nextjs-architecture')
|
|
136
|
+
.description('generate nextjs-architecture.mdx for project structure')
|
|
137
|
+
.option('-v, --verbose', 'show detailed logs', false)
|
|
138
|
+
.action(async (options) => {
|
|
139
|
+
try {
|
|
140
|
+
const config = index.loadConfig(cwd, {}, options.verbose);
|
|
141
|
+
if (options.verbose) {
|
|
142
|
+
config.output.verbose = true;
|
|
143
|
+
}
|
|
144
|
+
index.validateConfig(config);
|
|
145
|
+
const exitCode = await generateNextjsArchitecture.generateNextjsArchitecture(config, cwd);
|
|
146
|
+
if (typeof process !== 'undefined') {
|
|
147
|
+
process.exit(exitCode);
|
|
148
|
+
}
|
|
1407
149
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error('Error:', error);
|
|
152
|
+
if (typeof process !== 'undefined') {
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
1412
155
|
}
|
|
1413
|
-
}
|
|
1414
156
|
});
|
|
1415
|
-
commander.program
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
validateConfig(config);
|
|
1422
|
-
const exitCode = await generateNextjsArchitecture(config, cwd);
|
|
1423
|
-
if (typeof process !== "undefined") {
|
|
1424
|
-
process.exit(exitCode);
|
|
1425
|
-
}
|
|
1426
|
-
} catch (error) {
|
|
1427
|
-
console.error("Error:", error);
|
|
1428
|
-
if (typeof process !== "undefined") {
|
|
1429
|
-
process.exit(1);
|
|
157
|
+
commander.program
|
|
158
|
+
.command('create-diaomao-app <project-name>')
|
|
159
|
+
.description('create a new diaomao app from template')
|
|
160
|
+
.action(async (projectName) => {
|
|
161
|
+
try {
|
|
162
|
+
await createDiaomaoApp.createDiaomaoApp(projectName);
|
|
1430
163
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
} catch (error) {
|
|
1437
|
-
console.error("Error:", error);
|
|
1438
|
-
if (typeof process !== "undefined") {
|
|
1439
|
-
process.exit(1);
|
|
164
|
+
catch (error) {
|
|
165
|
+
console.error('Error:', error);
|
|
166
|
+
if (typeof process !== 'undefined') {
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
1440
169
|
}
|
|
1441
|
-
}
|
|
1442
170
|
});
|
|
1443
|
-
|
|
1444
|
-
|
|
171
|
+
// parse command line arguments
|
|
172
|
+
if (typeof process !== 'undefined') {
|
|
173
|
+
commander.program.parse(process.argv);
|
|
1445
174
|
}
|
|
1446
|
-
//# sourceMappingURL=cli.js.map
|
|
1447
|
-
//# sourceMappingURL=cli.js.map
|