@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/chunk-GVR6HFHM.mjs
DELETED
|
@@ -1,989 +0,0 @@
|
|
|
1
|
-
import fs, { mkdirSync, writeFileSync, readFileSync, readdirSync } from 'fs';
|
|
2
|
-
import path, { join, dirname } from 'path';
|
|
3
|
-
import fg from 'fast-glob';
|
|
4
|
-
|
|
5
|
-
// src/config/index.ts
|
|
6
|
-
|
|
7
|
-
// src/config/schema.ts
|
|
8
|
-
var DEFAULT_CONFIG = {
|
|
9
|
-
i18n: {
|
|
10
|
-
locales: ["en", "zh"],
|
|
11
|
-
defaultLocale: "en",
|
|
12
|
-
messageRoot: "messages"
|
|
13
|
-
},
|
|
14
|
-
scan: {
|
|
15
|
-
include: ["src/**/*.{tsx,ts,jsx,js}"],
|
|
16
|
-
exclude: ["src/**/*.d.ts", "src/**/*.test.ts", "src/**/*.test.tsx", "node_modules/**"]
|
|
17
|
-
},
|
|
18
|
-
blog: {
|
|
19
|
-
mdxDir: "src/mdx/blog",
|
|
20
|
-
outputFile: "index.mdx",
|
|
21
|
-
metaFile: "meta.json",
|
|
22
|
-
iocSlug: "ioc",
|
|
23
|
-
prefix: "blog"
|
|
24
|
-
},
|
|
25
|
-
output: {
|
|
26
|
-
logDir: "logs",
|
|
27
|
-
verbose: false
|
|
28
|
-
},
|
|
29
|
-
architectureConfig: {
|
|
30
|
-
".": "\u9879\u76EE\u6839\u76EE\u5F55",
|
|
31
|
-
".env.local": "\u672C\u5730\u73AF\u5883\u53D8\u91CF\u914D\u7F6E",
|
|
32
|
-
".eslintrc.json": "ESLint \u4EE3\u7801\u89C4\u8303\u914D\u7F6E",
|
|
33
|
-
".gitignore": "Git\u5FFD\u7565\u6587\u4EF6\u914D\u7F6E",
|
|
34
|
-
".source": "Fuma\u6570\u636E\u6E90Build\u4EA7\u7269",
|
|
35
|
-
"CHANGELOG.md": "\u53D8\u66F4\u8BB0\u5F55",
|
|
36
|
-
"components.json": "\u7EC4\u4EF6\u4F9D\u8D56\u6E05\u5355",
|
|
37
|
-
"dev-scripts.config.json": "dev-scripts\u811A\u672C\u5DE5\u5177\u914D\u7F6E",
|
|
38
|
-
"LICENSE": "\u5F00\u6E90\u8BB8\u53EF\u8BC1",
|
|
39
|
-
"messages": "\u7FFB\u8BD1\u76EE\u5F55",
|
|
40
|
-
"next-env.d.ts": "Next.js\u73AF\u5883\u7C7B\u578B\u58F0\u660E",
|
|
41
|
-
"next.config.ts": "Next.js\u9879\u76EE\u914D\u7F6E",
|
|
42
|
-
"package.json": "\u9879\u76EE\u4F9D\u8D56\u4E0E\u811A\u672C",
|
|
43
|
-
"postcss.config.mjs": "PostCSS \u914D\u7F6E",
|
|
44
|
-
"source.config.ts": "Fuma\u6570\u636E\u6E90\u626B\u63CF\u914D\u7F6E",
|
|
45
|
-
"src": "\u6E90\u7801\u76EE\u5F55",
|
|
46
|
-
"tsconfig.json": "TypeScript\u914D\u7F6E",
|
|
47
|
-
"tsconfig.node.json": "Node.js\u76F8\u5173TypeScript \u914D\u7F6E",
|
|
48
|
-
"logs": "\u65E5\u5FD7\u8F93\u51FA\u76EE\u5F55",
|
|
49
|
-
"apps": "Monorepo\u591A\u5E94\u7528\u76EE\u5F55",
|
|
50
|
-
"packages": "\u5B50\u5DE5\u7A0B\u7EC4\u4EF6\u5E93\u76EE\u5F55",
|
|
51
|
-
"README.md": "\u9879\u76EE\u8BF4\u660E\u6587\u6863",
|
|
52
|
-
"app": "Next.js \u5E94\u7528\u4E3B\u5165\u53E3\u76EE\u5F55",
|
|
53
|
-
"components": "\u9875\u9762\u7EC4\u4EF6",
|
|
54
|
-
"lib": "\u5DE5\u5177\u5305",
|
|
55
|
-
"mdx": "FumaMDX\u6587\u6863",
|
|
56
|
-
"middleware.ts": "\u4E2D\u95F4\u4EF6\u5165\u53E3",
|
|
57
|
-
"i18n.ts": "\u591A\u8BED\u8A00\u914D\u7F6E",
|
|
58
|
-
"globals.css": "\u5168\u5C40\u6837\u5F0F",
|
|
59
|
-
"layout.config.tsx": "\u5E03\u5C40\u914D\u7F6E",
|
|
60
|
-
"layout.tsx": "\u5E03\u5C40",
|
|
61
|
-
"loading.tsx": "\u5168\u5C40\u52A0\u8F7D\u7EC4\u4EF6",
|
|
62
|
-
"hero.tsx": "\u9996\u9875\u5927\u5B57\u7EC4\u4EF6",
|
|
63
|
-
"mdx-components.tsx": "FumaMDX\u7EC4\u4EF6\u5E93(\u81EA\u5B9A\u4E49)",
|
|
64
|
-
"llm-content": "FumaMDX\u590D\u5236\u63A5\u53E3",
|
|
65
|
-
"[locale]": "Nextjs i18n\u8DEF\u7531\u76EE\u5F55",
|
|
66
|
-
"(clerk)": "Clerk\u8BA4\u8BC1",
|
|
67
|
-
"(home)": "\u9996\u9875",
|
|
68
|
-
"[...catchAll]": "\u5168\u5C40404\u9875\u9762",
|
|
69
|
-
"blog": "\u535A\u5BA2",
|
|
70
|
-
"docs": "\u6587\u6863",
|
|
71
|
-
"legal": "\u6CD5\u5F8B",
|
|
72
|
-
"api": "API\u63A5\u53E3",
|
|
73
|
-
"robots.ts": "robots.txt\u751F\u6210\u811A\u672C",
|
|
74
|
-
"sitemap.ts": "\u7F51\u7AD9\u5730\u56FE",
|
|
75
|
-
"appConfig.ts": "\u5E94\u7528\u5168\u5C40\u914D\u7F6E",
|
|
76
|
-
"site-config.ts": "\u7F51\u7AD9\u56FE\u6807\u914D\u7F6E",
|
|
77
|
-
"ioc.mdx": "\u6708\u5EA6/\u7EDF\u8BA1",
|
|
78
|
-
"meta.json": "FumaMDX\u5143\u6570\u636E",
|
|
79
|
-
"nextjs-architecture.mdx": "Next.js\u9879\u76EE\u7ED3\u6784",
|
|
80
|
-
".github": "GitHub \u914D\u7F6E\u76EE\u5F55",
|
|
81
|
-
"workflows": "CI/CD \u5DE5\u4F5C\u6D41\u914D\u7F6E"
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// src/config/index.ts
|
|
86
|
-
function loadPackageJsonConfig(cwd) {
|
|
87
|
-
try {
|
|
88
|
-
const packageJsonPath = path.join(cwd, "package.json");
|
|
89
|
-
if (!fs.existsSync(packageJsonPath)) return null;
|
|
90
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
91
|
-
const devScripts = packageJson.devScripts;
|
|
92
|
-
if (!devScripts || Object.keys(devScripts).length === 0) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
const config = {};
|
|
96
|
-
if (devScripts.locales || devScripts.defaultLocale || devScripts.messageRoot) {
|
|
97
|
-
config.i18n = {
|
|
98
|
-
locales: devScripts.locales || DEFAULT_CONFIG.i18n.locales,
|
|
99
|
-
defaultLocale: devScripts.defaultLocale || DEFAULT_CONFIG.i18n.defaultLocale,
|
|
100
|
-
messageRoot: devScripts.messageRoot || DEFAULT_CONFIG.i18n.messageRoot
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
if (devScripts.scanDirs) {
|
|
104
|
-
config.scan = {
|
|
105
|
-
include: devScripts.scanDirs,
|
|
106
|
-
exclude: DEFAULT_CONFIG.scan.exclude
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
if (devScripts.blogDir) {
|
|
110
|
-
config.blog = {
|
|
111
|
-
mdxDir: devScripts.blogDir,
|
|
112
|
-
...DEFAULT_CONFIG.blog
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (devScripts.logDir) {
|
|
116
|
-
config.output = {
|
|
117
|
-
logDir: devScripts.logDir,
|
|
118
|
-
verbose: DEFAULT_CONFIG.output.verbose
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
return Object.keys(config).length > 0 ? config : null;
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.warn(`Warning: Failed to load package.json config: ${error}`);
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function loadConfigFile(cwd) {
|
|
128
|
-
try {
|
|
129
|
-
const configPath = path.join(cwd, "dev-scripts.config.json");
|
|
130
|
-
if (!fs.existsSync(configPath)) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
return JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.warn(`Warning: Failed to load dev-scripts.config.json: ${error}`);
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function mergeConfig(base, override) {
|
|
140
|
-
const result = { ...base };
|
|
141
|
-
for (const [key, value] of Object.entries(override)) {
|
|
142
|
-
if (value !== void 0 && value !== null) {
|
|
143
|
-
if (typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object") {
|
|
144
|
-
result[key] = { ...result[key], ...value };
|
|
145
|
-
} else {
|
|
146
|
-
result[key] = value;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return result;
|
|
151
|
-
}
|
|
152
|
-
function loadConfig(cwd = typeof process !== "undefined" ? process.cwd() : ".", override = {}, verbose) {
|
|
153
|
-
let config = { ...DEFAULT_CONFIG };
|
|
154
|
-
const configSources = [];
|
|
155
|
-
const fileConfig = loadConfigFile(cwd);
|
|
156
|
-
if (fileConfig) {
|
|
157
|
-
config = mergeConfig(config, fileConfig);
|
|
158
|
-
configSources.push("dev-scripts.config.json");
|
|
159
|
-
}
|
|
160
|
-
const packageConfig = loadPackageJsonConfig(cwd);
|
|
161
|
-
if (packageConfig) {
|
|
162
|
-
config = mergeConfig(config, packageConfig);
|
|
163
|
-
configSources.push("package.json");
|
|
164
|
-
}
|
|
165
|
-
config = mergeConfig(config, override);
|
|
166
|
-
if (Object.keys(override).length > 0) {
|
|
167
|
-
configSources.push("runtime override");
|
|
168
|
-
}
|
|
169
|
-
const shouldPrintConfig = verbose !== void 0 ? verbose : config.output.verbose;
|
|
170
|
-
if (shouldPrintConfig) {
|
|
171
|
-
const configForPrint = { ...config };
|
|
172
|
-
configForPrint.output = { ...config.output, verbose: true };
|
|
173
|
-
printConfigInfo(configForPrint, configSources, cwd);
|
|
174
|
-
}
|
|
175
|
-
return config;
|
|
176
|
-
}
|
|
177
|
-
function printConfigInfo(config, sources, cwd) {
|
|
178
|
-
console.log("\n\u{1F4CB} Config Information:");
|
|
179
|
-
console.log(` working directory: ${cwd}`);
|
|
180
|
-
console.log(` config sources: ${sources.length > 0 ? sources.join(" + ") : "default config"}`);
|
|
181
|
-
console.log("\n\u{1F310} i18n:");
|
|
182
|
-
console.log(` locales: [${config.i18n.locales.join(", ")}]`);
|
|
183
|
-
console.log(` defaultLocale: ${config.i18n.defaultLocale}`);
|
|
184
|
-
console.log(` messageRoot: ${config.i18n.messageRoot}`);
|
|
185
|
-
console.log("\n\u{1F50D} scan:");
|
|
186
|
-
console.log(` include: [${config.scan.include.join(", ")}]`);
|
|
187
|
-
if (config.scan.exclude && config.scan.exclude.length > 0) {
|
|
188
|
-
console.log(` exclude: [${config.scan.exclude.join(", ")}]`);
|
|
189
|
-
}
|
|
190
|
-
if (config.scan.baseDir) {
|
|
191
|
-
console.log(` baseDir: ${config.scan.baseDir}`);
|
|
192
|
-
}
|
|
193
|
-
if (config.blog) {
|
|
194
|
-
console.log("\n\u{1F4DD} blog:");
|
|
195
|
-
console.log(` mdxDir: ${config.blog.mdxDir}`);
|
|
196
|
-
console.log(` outputFile: ${config.blog.outputFile || "index.mdx (default)"}`);
|
|
197
|
-
console.log(` metaFile: ${config.blog.metaFile || "meta.json (default)"}`);
|
|
198
|
-
if (config.blog.iocSlug) {
|
|
199
|
-
console.log(` iocSlug: ${config.blog.iocSlug}`);
|
|
200
|
-
}
|
|
201
|
-
if (config.blog.prefix) {
|
|
202
|
-
console.log(` prefix: ${config.blog.prefix}`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
console.log("\n\u{1F4E4} output:");
|
|
206
|
-
console.log(` logDir: ${config.output.logDir}`);
|
|
207
|
-
console.log(` verbose: ${config.output.verbose}`);
|
|
208
|
-
console.log("");
|
|
209
|
-
}
|
|
210
|
-
function validateConfig(config) {
|
|
211
|
-
if (!config.i18n.locales || config.i18n.locales.length === 0) {
|
|
212
|
-
throw new Error("at least one language is required");
|
|
213
|
-
}
|
|
214
|
-
if (!config.i18n.locales.includes(config.i18n.defaultLocale)) {
|
|
215
|
-
throw new Error("default language must be in the supported language list");
|
|
216
|
-
}
|
|
217
|
-
if (config.scan.include.length === 0) {
|
|
218
|
-
throw new Error("at least one scan path is required");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
var Logger = class {
|
|
222
|
-
constructor(config) {
|
|
223
|
-
this.messages = [];
|
|
224
|
-
this.config = config;
|
|
225
|
-
}
|
|
226
|
-
log(message) {
|
|
227
|
-
if (this.config.output.verbose) {
|
|
228
|
-
console.log(message);
|
|
229
|
-
}
|
|
230
|
-
this.messages.push(message);
|
|
231
|
-
}
|
|
232
|
-
error(message) {
|
|
233
|
-
console.error(message);
|
|
234
|
-
this.messages.push("[ERROR] " + message);
|
|
235
|
-
}
|
|
236
|
-
warn(message) {
|
|
237
|
-
console.warn(message);
|
|
238
|
-
this.messages.push("[WARN] " + message);
|
|
239
|
-
}
|
|
240
|
-
info(message) {
|
|
241
|
-
console.info(message);
|
|
242
|
-
this.messages.push("[INFO] " + message);
|
|
243
|
-
}
|
|
244
|
-
success(message) {
|
|
245
|
-
console.log(`\u2705 ${message}`);
|
|
246
|
-
this.messages.push(`[SUCCESS] ${message}`);
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* save log to file
|
|
250
|
-
*/
|
|
251
|
-
saveToFile(filename, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
252
|
-
try {
|
|
253
|
-
const logFilePath = join(cwd, this.config.output.logDir, filename);
|
|
254
|
-
const logDir = dirname(logFilePath);
|
|
255
|
-
mkdirSync(logDir, { recursive: true });
|
|
256
|
-
writeFileSync(logFilePath, this.messages.join("\n"), "utf8");
|
|
257
|
-
console.log(`log saved to ${logFilePath}`);
|
|
258
|
-
} catch (error) {
|
|
259
|
-
console.error(`failed to save log file: ${error}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* clear log messages
|
|
264
|
-
*/
|
|
265
|
-
clear() {
|
|
266
|
-
this.messages = [];
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* get all log messages
|
|
270
|
-
*/
|
|
271
|
-
getMessages() {
|
|
272
|
-
return [...this.messages];
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
async function scanFiles(config, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
276
|
-
const files = await fg(config.scan.include, {
|
|
277
|
-
ignore: config.scan.exclude || [],
|
|
278
|
-
cwd,
|
|
279
|
-
absolute: false
|
|
280
|
-
});
|
|
281
|
-
const results = [];
|
|
282
|
-
for (const file of files) {
|
|
283
|
-
try {
|
|
284
|
-
const content = readFileSync(file, "utf8");
|
|
285
|
-
results.push({
|
|
286
|
-
filePath: file,
|
|
287
|
-
content
|
|
288
|
-
});
|
|
289
|
-
} catch (error) {
|
|
290
|
-
console.warn(`Warning: Failed to read file ${file}: ${error}`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return results;
|
|
294
|
-
}
|
|
295
|
-
function readJsonFile(filePath) {
|
|
296
|
-
try {
|
|
297
|
-
const content = readFileSync(filePath, "utf8");
|
|
298
|
-
return JSON.parse(content);
|
|
299
|
-
} catch (error) {
|
|
300
|
-
return null;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
function getTranslationFilePath(locale, config, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
304
|
-
return `${cwd}/${config.i18n.messageRoot}/${locale}.json`;
|
|
305
|
-
}
|
|
306
|
-
function loadTranslations(config, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
307
|
-
const translations = {};
|
|
308
|
-
for (const locale of config.i18n.locales) {
|
|
309
|
-
const filePath = getTranslationFilePath(locale, config, cwd);
|
|
310
|
-
const translation = readJsonFile(filePath);
|
|
311
|
-
if (translation) {
|
|
312
|
-
translations[locale] = translation;
|
|
313
|
-
} else {
|
|
314
|
-
console.warn(`Warning: Failed to load translation file for locale: ${locale}`);
|
|
315
|
-
translations[locale] = {};
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return translations;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// src/utils/translation-parser.ts
|
|
322
|
-
function extractTranslationsInfo(content, filePath) {
|
|
323
|
-
const result = {
|
|
324
|
-
namespaces: /* @__PURE__ */ new Map(),
|
|
325
|
-
keys: []
|
|
326
|
-
};
|
|
327
|
-
const getTranslationsPattern = /getTranslations\(\s*(?:{[^}]*namespace:\s*['"]([^'"]+)['"][^}]*}|['"]([^'"]+)['"])\s*\)/g;
|
|
328
|
-
let match;
|
|
329
|
-
while ((match = getTranslationsPattern.exec(content)) !== null) {
|
|
330
|
-
const namespace = match[1] || match[2];
|
|
331
|
-
if (namespace) {
|
|
332
|
-
const linesBefore = content.substring(0, match.index).split("\n");
|
|
333
|
-
for (let i = linesBefore.length - 1; i >= Math.max(0, linesBefore.length - 5); i--) {
|
|
334
|
-
const line = linesBefore[i];
|
|
335
|
-
const constMatch = /const\s+(\w+)\s*=/.exec(line);
|
|
336
|
-
if (constMatch && !line.includes("useTranslations") && !line.includes("getTranslations")) {
|
|
337
|
-
result.namespaces.set(constMatch[1], namespace);
|
|
338
|
-
break;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
const useTranslationsPattern = /useTranslations\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
344
|
-
while ((match = useTranslationsPattern.exec(content)) !== null) {
|
|
345
|
-
const namespace = match[1];
|
|
346
|
-
const currentLine = content.substring(0, match.index).split("\n").pop() || "";
|
|
347
|
-
const constMatch = /const\s+(\w+)\s*=/.exec(currentLine);
|
|
348
|
-
if (constMatch) {
|
|
349
|
-
result.namespaces.set(constMatch[1], namespace);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
const tPatterns = [
|
|
353
|
-
// normal string key: t('key') or t("key")
|
|
354
|
-
/(\w+)\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
355
|
-
// template string key: t(`tags.${id}`) or t(`section.${key}`)
|
|
356
|
-
/(\w+)\(\s*`([^`]+)`\s*\)/g,
|
|
357
|
-
// variable key: t(item.key) or t(item.id)
|
|
358
|
-
/(\w+)\(\s*(\w+)\.(\w+)\s*\)/g
|
|
359
|
-
];
|
|
360
|
-
for (const pattern of tPatterns) {
|
|
361
|
-
let match2;
|
|
362
|
-
while ((match2 = pattern.exec(content)) !== null) {
|
|
363
|
-
const funcName = match2[1];
|
|
364
|
-
if (result.namespaces.has(funcName)) {
|
|
365
|
-
const namespace = result.namespaces.get(funcName);
|
|
366
|
-
if (!namespace) continue;
|
|
367
|
-
if (pattern.source.includes("`")) {
|
|
368
|
-
const templateStr = match2[2];
|
|
369
|
-
const staticPart = templateStr.split(/\${(?:id|key)}/)[0].trim();
|
|
370
|
-
if (staticPart && !staticPart.includes("/")) {
|
|
371
|
-
const segments = staticPart.split(".");
|
|
372
|
-
if (segments.length > 0) {
|
|
373
|
-
result.keys.push(`${namespace}.${segments[0]}`);
|
|
374
|
-
if (segments.length > 1) {
|
|
375
|
-
result.keys.push(`${namespace}.${segments.join(".")}`);
|
|
376
|
-
}
|
|
377
|
-
if (segments[0] === "tags") {
|
|
378
|
-
["productUpdates", "tutorials", "makeMoney", "roadOverSea", "insights"].forEach((tag) => {
|
|
379
|
-
result.keys.push(`${namespace}.tags.${tag}`);
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
} else if (pattern.source.includes("\\w+\\.\\w+")) {
|
|
385
|
-
const varName = match2[2];
|
|
386
|
-
match2[3];
|
|
387
|
-
const varPattern = new RegExp(`${varName}\\s*=\\s*{[^}]*key:\\s*['"]([^'"]+)['"]`);
|
|
388
|
-
const varMatch = content.match(varPattern);
|
|
389
|
-
if (varMatch) {
|
|
390
|
-
result.keys.push(`${namespace}.${varMatch[1]}`);
|
|
391
|
-
} else {
|
|
392
|
-
if (content.includes("MenuItem[]") || content.includes("MenuItem}")) {
|
|
393
|
-
["journey"].forEach((menuKey) => {
|
|
394
|
-
result.keys.push(`${namespace}.${menuKey}`);
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
} else {
|
|
399
|
-
const key = match2[2];
|
|
400
|
-
if (!key.includes("/") && key !== "") {
|
|
401
|
-
result.keys.push(`${namespace}.${key}`);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
const formattedMessagePattern = /<FormattedMessage[^>]*id=['"]([^'"]+)['"]/g;
|
|
408
|
-
while ((match = formattedMessagePattern.exec(content)) !== null) {
|
|
409
|
-
const key = match[1];
|
|
410
|
-
if (!key.includes("/") && key !== "") {
|
|
411
|
-
if (result.namespaces.size > 0) {
|
|
412
|
-
const namespace = Array.from(result.namespaces.values())[0];
|
|
413
|
-
result.keys.push(`${namespace}.${key}`);
|
|
414
|
-
} else {
|
|
415
|
-
const pathMatch = filePath.match(/\[locale\]\/(?:\([^)]+\)\/)?([^/]+)/);
|
|
416
|
-
if (pathMatch && pathMatch[1]) {
|
|
417
|
-
const possibleNamespace = pathMatch[1];
|
|
418
|
-
result.keys.push(`${possibleNamespace}.${key}`);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return result;
|
|
424
|
-
}
|
|
425
|
-
function getAllKeys(obj, prefix = "") {
|
|
426
|
-
let keys = [];
|
|
427
|
-
for (const key in obj) {
|
|
428
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
429
|
-
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
430
|
-
if (typeof obj[key] === "object" && obj[key] !== null) {
|
|
431
|
-
keys = [...keys, ...getAllKeys(obj[key], newKey)];
|
|
432
|
-
} else {
|
|
433
|
-
keys.push(newKey);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
return keys;
|
|
438
|
-
}
|
|
439
|
-
function checkKeyExists(key, translations) {
|
|
440
|
-
const parts = key.split(".");
|
|
441
|
-
let current = translations;
|
|
442
|
-
for (const part of parts) {
|
|
443
|
-
if (current[part] === void 0) {
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
446
|
-
current = current[part];
|
|
447
|
-
}
|
|
448
|
-
return true;
|
|
449
|
-
}
|
|
450
|
-
function checkNamespaceExists(namespace, translations) {
|
|
451
|
-
return translations[namespace] !== void 0;
|
|
452
|
-
}
|
|
453
|
-
function removeKeyFromTranslations(key, translations) {
|
|
454
|
-
const parts = key.split(".");
|
|
455
|
-
const lastPart = parts.pop();
|
|
456
|
-
if (!lastPart) return false;
|
|
457
|
-
let current = translations;
|
|
458
|
-
for (const part of parts) {
|
|
459
|
-
if (current[part] === void 0 || typeof current[part] !== "object") {
|
|
460
|
-
return false;
|
|
461
|
-
}
|
|
462
|
-
current = current[part];
|
|
463
|
-
}
|
|
464
|
-
if (current[lastPart] !== void 0) {
|
|
465
|
-
delete current[lastPart];
|
|
466
|
-
return true;
|
|
467
|
-
}
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
function cleanEmptyObjects(obj) {
|
|
471
|
-
for (const key in obj) {
|
|
472
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
473
|
-
if (typeof obj[key] === "object" && obj[key] !== null) {
|
|
474
|
-
obj[key] = cleanEmptyObjects(obj[key]);
|
|
475
|
-
if (Object.keys(obj[key]).length === 0) {
|
|
476
|
-
delete obj[key];
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
return obj;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// src/commands/check-translations.ts
|
|
485
|
-
async function checkTranslations(config, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
486
|
-
const logger = new Logger(config);
|
|
487
|
-
logger.warn("==============================");
|
|
488
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd} \u2B55`);
|
|
489
|
-
logger.warn("==============================");
|
|
490
|
-
try {
|
|
491
|
-
logger.log("start checking translations...");
|
|
492
|
-
const scanResults = await scanFiles(config, cwd);
|
|
493
|
-
logger.log(`found ${scanResults.length} files to scan`);
|
|
494
|
-
const translations = loadTranslations(config, cwd);
|
|
495
|
-
const foundTranslationKeys = /* @__PURE__ */ new Set();
|
|
496
|
-
const foundNamespaces = /* @__PURE__ */ new Set();
|
|
497
|
-
for (const { filePath, content } of scanResults) {
|
|
498
|
-
try {
|
|
499
|
-
const { namespaces, keys } = extractTranslationsInfo(content, filePath);
|
|
500
|
-
if (keys.length > 0 || namespaces.size > 0) {
|
|
501
|
-
logger.log(`found the following information in the file ${filePath}:`);
|
|
502
|
-
if (namespaces.size > 0) {
|
|
503
|
-
logger.log(` translation function mapping:`);
|
|
504
|
-
namespaces.forEach((namespace, varName) => {
|
|
505
|
-
logger.log(` - ${varName} => ${namespace}`);
|
|
506
|
-
foundNamespaces.add(namespace);
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
if (keys.length > 0) {
|
|
510
|
-
logger.log(` translation keys:`);
|
|
511
|
-
keys.forEach((key) => {
|
|
512
|
-
logger.log(` - ${key}`);
|
|
513
|
-
foundTranslationKeys.add(key);
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
} catch (error) {
|
|
518
|
-
if (error instanceof Error) {
|
|
519
|
-
logger.error(`error processing file ${filePath}: ${error.message}`);
|
|
520
|
-
} else {
|
|
521
|
-
logger.error(`error processing file ${filePath}: unknown error`);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
logger.log(`
|
|
526
|
-
found ${foundNamespaces.size} used namespaces in the code: ${Array.from(foundNamespaces).join(", ")}`);
|
|
527
|
-
const report = {};
|
|
528
|
-
foundNamespaces.forEach((namespace) => {
|
|
529
|
-
config.i18n.locales.forEach((locale) => {
|
|
530
|
-
const missingNamespaceKey = `missingNamespacesIn${locale.toUpperCase()}`;
|
|
531
|
-
if (!checkNamespaceExists(namespace, translations[locale])) {
|
|
532
|
-
report[missingNamespaceKey] = report[missingNamespaceKey] || [];
|
|
533
|
-
report[missingNamespaceKey].push(namespace);
|
|
534
|
-
}
|
|
535
|
-
});
|
|
536
|
-
});
|
|
537
|
-
foundTranslationKeys.forEach((key) => {
|
|
538
|
-
config.i18n.locales.forEach((locale) => {
|
|
539
|
-
const missingKey = `missingIn${locale.toUpperCase()}`;
|
|
540
|
-
if (!checkKeyExists(key, translations[locale])) {
|
|
541
|
-
report[missingKey] = report[missingKey] || [];
|
|
542
|
-
report[missingKey].push(key);
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
config.i18n.locales.forEach((locale) => {
|
|
547
|
-
const allKeys = getAllKeys(translations[locale]);
|
|
548
|
-
config.i18n.locales.forEach((otherLocale) => {
|
|
549
|
-
if (locale !== otherLocale) {
|
|
550
|
-
const otherKeys = getAllKeys(translations[otherLocale]);
|
|
551
|
-
const onlyKeys = `${locale}OnlyKeys`;
|
|
552
|
-
report[onlyKeys] = allKeys.filter((key) => !otherKeys.includes(key));
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
});
|
|
556
|
-
logger.log("\n=== translation check report ===\n");
|
|
557
|
-
config.i18n.locales.forEach((locale) => {
|
|
558
|
-
const missingNamespaceKey = `missingNamespacesIn${locale.toUpperCase()}`;
|
|
559
|
-
if (report[missingNamespaceKey]?.length > 0) {
|
|
560
|
-
logger.log(`\u{1F6A8} missing namespaces in the ${locale} translation file:`);
|
|
561
|
-
report[missingNamespaceKey].forEach((namespace) => logger.log(` - ${namespace}`));
|
|
562
|
-
} else {
|
|
563
|
-
logger.success(`${locale} translation file has all used namespaces`);
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
config.i18n.locales.forEach((locale) => {
|
|
567
|
-
const missingKey = `missingIn${locale.toUpperCase()}`;
|
|
568
|
-
if (report[missingKey]?.length > 0) {
|
|
569
|
-
logger.log(`
|
|
570
|
-
\u{1F534} missing keys in the ${locale} translation file:`);
|
|
571
|
-
report[missingKey].forEach((key) => logger.log(` - ${key}`));
|
|
572
|
-
} else {
|
|
573
|
-
logger.success(`${locale} translation file has all used keys`);
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
config.i18n.locales.forEach((locale) => {
|
|
577
|
-
const onlyKeys = `${locale}OnlyKeys`;
|
|
578
|
-
if (report[onlyKeys]?.length > 0) {
|
|
579
|
-
logger.log(`
|
|
580
|
-
\u26A0\uFE0F keys only exist in the ${locale} translation file:`);
|
|
581
|
-
report[onlyKeys].forEach((key) => logger.log(` - ${key}`));
|
|
582
|
-
}
|
|
583
|
-
});
|
|
584
|
-
logger.log("\n=== report end ===\n");
|
|
585
|
-
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");
|
|
586
|
-
logger.saveToFile("check.log", cwd);
|
|
587
|
-
return Object.values(report).some((keys) => keys.length > 0) ? 1 : 0;
|
|
588
|
-
} catch (error) {
|
|
589
|
-
logger.error(`error checking translations: ${error}`);
|
|
590
|
-
return 1;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
async function cleanTranslations(config, shouldRemove = false, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
594
|
-
const logger = new Logger(config);
|
|
595
|
-
const logFileName = shouldRemove ? "remove.log" : "clean.log";
|
|
596
|
-
logger.warn("==============================");
|
|
597
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd} \u2B55`);
|
|
598
|
-
logger.warn("==============================");
|
|
599
|
-
try {
|
|
600
|
-
logger.log("start checking unused translation keys...");
|
|
601
|
-
const scanResults = await scanFiles(config, cwd);
|
|
602
|
-
logger.log(`\u627E\u5230 ${scanResults.length} \u4E2A\u6587\u4EF6\u9700\u8981\u626B\u63CF`);
|
|
603
|
-
const translations = loadTranslations(config, cwd);
|
|
604
|
-
const foundTranslationKeys = /* @__PURE__ */ new Set();
|
|
605
|
-
const foundNamespaces = /* @__PURE__ */ new Set();
|
|
606
|
-
for (const { filePath, content } of scanResults) {
|
|
607
|
-
try {
|
|
608
|
-
const { namespaces, keys } = extractTranslationsInfo(content, filePath);
|
|
609
|
-
if (keys.length > 0 || namespaces.size > 0) {
|
|
610
|
-
logger.log(`found the following information in the file ${filePath}:`);
|
|
611
|
-
if (namespaces.size > 0) {
|
|
612
|
-
logger.log(` translation function mapping:`);
|
|
613
|
-
namespaces.forEach((namespace, varName) => {
|
|
614
|
-
logger.log(` - ${varName} => ${namespace}`);
|
|
615
|
-
foundNamespaces.add(namespace);
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
if (keys.length > 0) {
|
|
619
|
-
logger.log(` translation keys:`);
|
|
620
|
-
keys.forEach((key) => {
|
|
621
|
-
logger.log(` - ${key}`);
|
|
622
|
-
foundTranslationKeys.add(key);
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
} catch (error) {
|
|
627
|
-
if (error instanceof Error) {
|
|
628
|
-
logger.error(`error processing file ${filePath}: ${error.message}`);
|
|
629
|
-
} else {
|
|
630
|
-
logger.error(`error processing file ${filePath}: unknown error`);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
logger.log(`
|
|
635
|
-
found ${foundTranslationKeys.size} used translation keys in the code`);
|
|
636
|
-
logger.log(`found ${foundNamespaces.size} used namespaces in the code: ${Array.from(foundNamespaces).join(", ")}`);
|
|
637
|
-
const unusedKeys = {};
|
|
638
|
-
const removedKeys = {};
|
|
639
|
-
const unusedNamespaces = {};
|
|
640
|
-
config.i18n.locales.forEach((locale) => {
|
|
641
|
-
unusedKeys[locale] = [];
|
|
642
|
-
removedKeys[locale] = [];
|
|
643
|
-
unusedNamespaces[locale] = [];
|
|
644
|
-
const allTranslationKeys = getAllKeys(translations[locale]);
|
|
645
|
-
const allNamespaces = Object.keys(translations[locale] || {});
|
|
646
|
-
allNamespaces.forEach((namespace) => {
|
|
647
|
-
if (!foundNamespaces.has(namespace)) {
|
|
648
|
-
unusedNamespaces[locale].push(namespace);
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
allTranslationKeys.forEach((key) => {
|
|
652
|
-
if (!foundTranslationKeys.has(key)) {
|
|
653
|
-
unusedKeys[locale].push(key);
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
logger.log(`
|
|
657
|
-
found ${unusedKeys[locale].length} unused keys in the ${locale} translation file`);
|
|
658
|
-
logger.log(`found ${unusedNamespaces[locale].length} unused namespaces in the ${locale} translation file`);
|
|
659
|
-
});
|
|
660
|
-
if (shouldRemove) {
|
|
661
|
-
logger.log("\nstart deleting unused translation keys...");
|
|
662
|
-
config.i18n.locales.forEach((locale) => {
|
|
663
|
-
const translationsCopy = { ...translations[locale] };
|
|
664
|
-
unusedKeys[locale].forEach((key) => {
|
|
665
|
-
if (removeKeyFromTranslations(key, translationsCopy)) {
|
|
666
|
-
removedKeys[locale].push(key);
|
|
667
|
-
}
|
|
668
|
-
});
|
|
669
|
-
unusedNamespaces[locale].forEach((namespace) => {
|
|
670
|
-
if (translationsCopy[namespace] !== void 0) {
|
|
671
|
-
delete translationsCopy[namespace];
|
|
672
|
-
logger.log(`deleted unused namespace ${namespace} from the ${locale} translation file`);
|
|
673
|
-
}
|
|
674
|
-
});
|
|
675
|
-
const cleanedTranslations = cleanEmptyObjects(translationsCopy);
|
|
676
|
-
const filePath = getTranslationFilePath(locale, config, cwd);
|
|
677
|
-
writeFileSync(filePath, JSON.stringify(cleanedTranslations, null, 2), "utf8");
|
|
678
|
-
logger.log(`deleted ${removedKeys[locale].length} unused keys from the ${locale} translation file`);
|
|
679
|
-
});
|
|
680
|
-
} else {
|
|
681
|
-
logger.log("\nTo delete unused keys, please run the script with the --remove parameter");
|
|
682
|
-
}
|
|
683
|
-
logger.log("\n=== unused translation keys report ===\n");
|
|
684
|
-
config.i18n.locales.forEach((locale) => {
|
|
685
|
-
if (unusedNamespaces[locale].length > 0) {
|
|
686
|
-
logger.log(`\u{1F50D} unused namespaces in the ${locale} translation file:`);
|
|
687
|
-
unusedNamespaces[locale].forEach((namespace) => logger.log(` - ${namespace}`));
|
|
688
|
-
} else {
|
|
689
|
-
logger.success(`${locale} translation file has no unused namespaces`);
|
|
690
|
-
}
|
|
691
|
-
if (unusedKeys[locale].length > 0) {
|
|
692
|
-
logger.log(`
|
|
693
|
-
\u{1F50D} unused keys in the ${locale} translation file:`);
|
|
694
|
-
unusedKeys[locale].forEach((key) => logger.log(` - ${key}`));
|
|
695
|
-
} else {
|
|
696
|
-
logger.success(`${locale} translation file has no unused keys`);
|
|
697
|
-
}
|
|
698
|
-
if (shouldRemove && removedKeys[locale].length > 0) {
|
|
699
|
-
logger.log(`
|
|
700
|
-
\u{1F5D1}\uFE0F deleted keys from the ${locale} translation file:`);
|
|
701
|
-
removedKeys[locale].forEach((key) => logger.log(` - ${key}`));
|
|
702
|
-
}
|
|
703
|
-
});
|
|
704
|
-
logger.log("\n=== report end ===\n");
|
|
705
|
-
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");
|
|
706
|
-
logger.saveToFile(logFileName, cwd);
|
|
707
|
-
return Object.values(unusedKeys).some((keys) => keys.length > 0) || Object.values(unusedNamespaces).some((namespaces) => namespaces.length > 0) ? 1 : 0;
|
|
708
|
-
} catch (error) {
|
|
709
|
-
logger.error(`error cleaning translations: ${error}`);
|
|
710
|
-
return 1;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
function parseFrontmatter(fileContent) {
|
|
714
|
-
const frontmatter = {};
|
|
715
|
-
const match = fileContent.match(/^---([\s\S]*?)---/);
|
|
716
|
-
if (match && match[1]) {
|
|
717
|
-
const lines = match[1].trim().split("\n");
|
|
718
|
-
for (const line of lines) {
|
|
719
|
-
const [key, ...valueParts] = line.split(":");
|
|
720
|
-
if (key && valueParts.length > 0) {
|
|
721
|
-
const value = valueParts.join(":").trim();
|
|
722
|
-
if (key.trim() === "title") frontmatter.title = value;
|
|
723
|
-
if (key.trim() === "description") frontmatter.description = value;
|
|
724
|
-
if (key.trim() === "icon") frontmatter.icon = value;
|
|
725
|
-
if (key.trim() === "date") frontmatter.date = value;
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
return frontmatter;
|
|
730
|
-
}
|
|
731
|
-
function getIconComponentString(iconName) {
|
|
732
|
-
if (!iconName) return void 0;
|
|
733
|
-
return `<${iconName} />`;
|
|
734
|
-
}
|
|
735
|
-
function getCurrentDateString() {
|
|
736
|
-
const now = /* @__PURE__ */ new Date();
|
|
737
|
-
const year = now.getFullYear();
|
|
738
|
-
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
739
|
-
const day = String(now.getDate()).padStart(2, "0");
|
|
740
|
-
return `${year}-${month}-${day}`;
|
|
741
|
-
}
|
|
742
|
-
function updateFrontmatterDate(frontmatter) {
|
|
743
|
-
const currentDate = getCurrentDateString();
|
|
744
|
-
if (frontmatter.includes("date:")) {
|
|
745
|
-
return frontmatter.replace(/date:\s*[^\n]*/, `date: ${currentDate}`);
|
|
746
|
-
} else {
|
|
747
|
-
return frontmatter.replace(/---$/, `date: ${currentDate}
|
|
748
|
-
---`);
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
function getBlogPrefix(config) {
|
|
752
|
-
if (config.blog?.prefix === void 0 || config.blog?.prefix === null) {
|
|
753
|
-
return "blog";
|
|
754
|
-
} else if (typeof config.blog?.prefix === "string" && config.blog?.prefix.trim() === "") {
|
|
755
|
-
return "";
|
|
756
|
-
} else {
|
|
757
|
-
return String(config.blog.prefix).trim();
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
async function getAllBlogArticles(blogDir, cwd, logger) {
|
|
761
|
-
const articles = [];
|
|
762
|
-
const blogPath = join(cwd, blogDir);
|
|
763
|
-
try {
|
|
764
|
-
const files = readdirSync(blogPath);
|
|
765
|
-
for (const file of files) {
|
|
766
|
-
if (file.endsWith(".mdx") && file !== "index.mdx") {
|
|
767
|
-
const slug = file.replace(/\.mdx$/, "");
|
|
768
|
-
const filePath = join(blogPath, file);
|
|
769
|
-
try {
|
|
770
|
-
const content = readFileSync(filePath, "utf-8");
|
|
771
|
-
const fm = parseFrontmatter(content);
|
|
772
|
-
if (!fm.title) {
|
|
773
|
-
logger.warn(`Article "${file}" is missing a title in its frontmatter. Skipping.`);
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
articles.push({
|
|
777
|
-
slug,
|
|
778
|
-
title: fm.title,
|
|
779
|
-
description: fm.description,
|
|
780
|
-
frontmatterIcon: fm.icon,
|
|
781
|
-
date: fm.date
|
|
782
|
-
});
|
|
783
|
-
} catch (readError) {
|
|
784
|
-
logger.warn(`Could not read or parse frontmatter for "${file}": ${readError}`);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
} catch (dirError) {
|
|
789
|
-
logger.error(`Could not read blog directory: ${dirError}`);
|
|
790
|
-
return [];
|
|
791
|
-
}
|
|
792
|
-
return articles;
|
|
793
|
-
}
|
|
794
|
-
async function generateBlogIndex(config, cwd = typeof process !== "undefined" ? process.cwd() : ".") {
|
|
795
|
-
const logger = new Logger(config);
|
|
796
|
-
logger.warn("==============================");
|
|
797
|
-
logger.warn(`\u203C\uFE0F Current working directory: \u2B55 ${cwd} \u2B55`);
|
|
798
|
-
logger.warn("==============================");
|
|
799
|
-
try {
|
|
800
|
-
if (!config.blog) {
|
|
801
|
-
logger.error("Blog configuration is missing. Please configure blog settings.");
|
|
802
|
-
return 1;
|
|
803
|
-
}
|
|
804
|
-
logger.log("Starting to generate blog index...");
|
|
805
|
-
const blogPath = join(cwd, config.blog.mdxDir);
|
|
806
|
-
const indexFile = join(blogPath, config.blog.outputFile || "index.mdx");
|
|
807
|
-
const metaFile = join(blogPath, config.blog.metaFile || "meta.json");
|
|
808
|
-
const iocFile = join(blogPath, `${config.blog.iocSlug || "ioc"}.mdx`);
|
|
809
|
-
const iocSlug = config.blog.iocSlug || "ioc";
|
|
810
|
-
const blogPrefix = getBlogPrefix(config);
|
|
811
|
-
let meta = { pages: [] };
|
|
812
|
-
const metaContent = readJsonFile(metaFile);
|
|
813
|
-
if (metaContent) {
|
|
814
|
-
meta = metaContent;
|
|
815
|
-
} else {
|
|
816
|
-
logger.warn(`Could not read or parse ${metaFile}. No articles will be marked as featured.`);
|
|
817
|
-
}
|
|
818
|
-
const hiddenSlugs = new Set(
|
|
819
|
-
meta.pages.filter((p) => p.startsWith("!")).map((p) => p.slice(1))
|
|
820
|
-
);
|
|
821
|
-
const featuredSlugs = meta.pages.filter((p) => !p.startsWith("!")).map((p) => p.endsWith(".mdx") ? p.slice(0, -4) : p).filter((slug) => slug !== "index" && slug !== "...");
|
|
822
|
-
logger.log(`Featured slugs (meta-config): ${featuredSlugs.join(", ")}`);
|
|
823
|
-
const allArticles = await getAllBlogArticles(config.blog.mdxDir, cwd, logger);
|
|
824
|
-
logger.log(`Found ${allArticles.length} all articles.`);
|
|
825
|
-
const visibleArticles = allArticles.filter((a) => !hiddenSlugs.has(a.slug));
|
|
826
|
-
const iocArticle = visibleArticles.find((a) => a.slug === iocSlug);
|
|
827
|
-
const filteredArticles = visibleArticles.filter((a) => a.slug !== iocSlug);
|
|
828
|
-
if (filteredArticles.length === 0 && featuredSlugs.length === 0) {
|
|
829
|
-
logger.warn("No articles found or featured. The generated index might be empty or minimal.");
|
|
830
|
-
}
|
|
831
|
-
const featuredArticles = [];
|
|
832
|
-
const pastArticles = [];
|
|
833
|
-
filteredArticles.forEach((article) => {
|
|
834
|
-
if (featuredSlugs.includes(article.slug)) {
|
|
835
|
-
featuredArticles.push(article);
|
|
836
|
-
} else {
|
|
837
|
-
pastArticles.push(article);
|
|
838
|
-
}
|
|
839
|
-
});
|
|
840
|
-
const sortByDateDesc = (a, b) => {
|
|
841
|
-
if (a.date && b.date) {
|
|
842
|
-
return b.date.localeCompare(a.date);
|
|
843
|
-
}
|
|
844
|
-
if (a.date) return -1;
|
|
845
|
-
if (b.date) return 1;
|
|
846
|
-
return 0;
|
|
847
|
-
};
|
|
848
|
-
featuredArticles.sort(sortByDateDesc);
|
|
849
|
-
pastArticles.sort(sortByDateDesc);
|
|
850
|
-
logger.log(`Found ${featuredArticles.length} featured articles (sorted by date).`);
|
|
851
|
-
logger.log(`Found ${pastArticles.length} past articles (sorted by date).`);
|
|
852
|
-
let currentFileFrontmatter = "---\ntitle: Blog\ndescription: Articles and thoughts about various topics.\nicon: Rss\n---";
|
|
853
|
-
try {
|
|
854
|
-
const currentIndexContent = readFileSync(indexFile, "utf-8");
|
|
855
|
-
const frontmatterMatch = currentIndexContent.match(/^---([\s\S]*?)---/);
|
|
856
|
-
if (frontmatterMatch && frontmatterMatch[0]) {
|
|
857
|
-
currentFileFrontmatter = frontmatterMatch[0];
|
|
858
|
-
logger.log("Preserving existing frontmatter from index.mdx");
|
|
859
|
-
}
|
|
860
|
-
} catch (error) {
|
|
861
|
-
logger.warn("Could not read existing index.mdx or parse its frontmatter. Using default frontmatter.");
|
|
862
|
-
}
|
|
863
|
-
currentFileFrontmatter = updateFrontmatterDate(currentFileFrontmatter);
|
|
864
|
-
let mdxContent = `${currentFileFrontmatter}
|
|
865
|
-
|
|
866
|
-
`;
|
|
867
|
-
const createCard = (article) => {
|
|
868
|
-
const iconString = getIconComponentString(article.frontmatterIcon);
|
|
869
|
-
const iconProp = iconString ? `icon={${iconString}}` : "";
|
|
870
|
-
const escapedTitle = (article.title || "").replace(/"/g, """);
|
|
871
|
-
const cardContent = article.date || article.description || "";
|
|
872
|
-
const finalIconProp = iconProp ? `${iconProp} ` : "";
|
|
873
|
-
const href = blogPrefix ? `${blogPrefix}/${article.slug}` : `${article.slug}`;
|
|
874
|
-
return ` <ZiaCard ${finalIconProp} href="${href}" title="${escapedTitle}">
|
|
875
|
-
${cardContent}
|
|
876
|
-
</ZiaCard>
|
|
877
|
-
`;
|
|
878
|
-
};
|
|
879
|
-
if (featuredArticles.length > 0) {
|
|
880
|
-
mdxContent += `## Feature List
|
|
881
|
-
|
|
882
|
-
<Cards>
|
|
883
|
-
`;
|
|
884
|
-
featuredArticles.forEach((article) => {
|
|
885
|
-
mdxContent += createCard(article);
|
|
886
|
-
});
|
|
887
|
-
mdxContent += `</Cards>
|
|
888
|
-
|
|
889
|
-
`;
|
|
890
|
-
}
|
|
891
|
-
if (pastArticles.length > 0) {
|
|
892
|
-
mdxContent += `## Past List
|
|
893
|
-
|
|
894
|
-
<Cards>
|
|
895
|
-
`;
|
|
896
|
-
pastArticles.forEach((article) => {
|
|
897
|
-
mdxContent += createCard(article);
|
|
898
|
-
});
|
|
899
|
-
mdxContent += `</Cards>
|
|
900
|
-
`;
|
|
901
|
-
}
|
|
902
|
-
if (iocArticle) {
|
|
903
|
-
mdxContent += `
|
|
904
|
-
## Monthly Summary
|
|
905
|
-
|
|
906
|
-
<Cards>
|
|
907
|
-
`;
|
|
908
|
-
const iocHref = blogPrefix ? `${blogPrefix}/${iocSlug}` : `${iocSlug}`;
|
|
909
|
-
mdxContent += ` <ZiaCard href="${iocHref}" title="Overview">
|
|
910
|
-
${getCurrentDateString()}
|
|
911
|
-
</ZiaCard>
|
|
912
|
-
`;
|
|
913
|
-
mdxContent += `</Cards>
|
|
914
|
-
`;
|
|
915
|
-
}
|
|
916
|
-
if (featuredArticles.length === 0 && pastArticles.length === 0 && !iocArticle) {
|
|
917
|
-
mdxContent += "## Ooops\nNo blog posts found yet. Stay tuned!\n";
|
|
918
|
-
}
|
|
919
|
-
writeFileSync(indexFile, mdxContent);
|
|
920
|
-
logger.success(`Successfully generated ${indexFile}`);
|
|
921
|
-
await generateMonthlyBlogSummary(config, visibleArticles, iocFile, iocSlug, logger);
|
|
922
|
-
logger.log("Blog index generation completed successfully!");
|
|
923
|
-
logger.saveToFile("generate-blog.log", cwd);
|
|
924
|
-
return 0;
|
|
925
|
-
} catch (error) {
|
|
926
|
-
logger.error(`Error generating blog index: ${error}`);
|
|
927
|
-
return 1;
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
async function generateMonthlyBlogSummary(config, articles, iocFile, iocSlug, logger) {
|
|
931
|
-
try {
|
|
932
|
-
const articlesWithDate = articles.filter((a) => a.date && a.slug !== iocSlug);
|
|
933
|
-
const monthMap = {};
|
|
934
|
-
for (const art of articlesWithDate) {
|
|
935
|
-
const month = art.date.slice(0, 7);
|
|
936
|
-
if (!monthMap[month]) monthMap[month] = [];
|
|
937
|
-
monthMap[month].push({ date: art.date, title: art.title, slug: art.slug });
|
|
938
|
-
}
|
|
939
|
-
const sortedMonths = Object.keys(monthMap).sort((a, b) => b.localeCompare(a));
|
|
940
|
-
for (const month of sortedMonths) {
|
|
941
|
-
monthMap[month].sort((a, b) => b.date.localeCompare(a.date));
|
|
942
|
-
}
|
|
943
|
-
let frontmatter = "";
|
|
944
|
-
try {
|
|
945
|
-
const content = readFileSync(iocFile, "utf-8");
|
|
946
|
-
const match = content.match(/^---([\s\S]*?)---/);
|
|
947
|
-
if (match && match[0]) frontmatter = match[0];
|
|
948
|
-
} catch {
|
|
949
|
-
}
|
|
950
|
-
if (!frontmatter) {
|
|
951
|
-
frontmatter = "---\ntitle: Monthly Summary\ndescription: Index and Summary\n---";
|
|
952
|
-
}
|
|
953
|
-
frontmatter = updateFrontmatterDate(frontmatter);
|
|
954
|
-
let mdx = `${frontmatter}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
## Overview
|
|
958
|
-
<Files>
|
|
959
|
-
`;
|
|
960
|
-
if (sortedMonths.length === 0) {
|
|
961
|
-
mdx += ' <ZiaFile name="Comming Soon" className="opacity-50" disabled/>\n';
|
|
962
|
-
} else {
|
|
963
|
-
for (const month of sortedMonths) {
|
|
964
|
-
const count = monthMap[month].length;
|
|
965
|
-
const folderTitle = `${month}(${count})`;
|
|
966
|
-
const defaultOpen = month === sortedMonths[0] ? " defaultOpen" : "";
|
|
967
|
-
mdx += ` <ZiaFolder name="${folderTitle}"${defaultOpen}>
|
|
968
|
-
`;
|
|
969
|
-
for (const art of monthMap[month]) {
|
|
970
|
-
const day = art.date.slice(0, 10);
|
|
971
|
-
const href = art.slug ? `./${art.slug}` : "";
|
|
972
|
-
mdx += ` <ZiaFile name="${day}(${art.title})" href="${href}" />
|
|
973
|
-
`;
|
|
974
|
-
}
|
|
975
|
-
mdx += ` </ZiaFolder>
|
|
976
|
-
`;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
mdx += "</Files>\n\n";
|
|
980
|
-
writeFileSync(iocFile, mdx);
|
|
981
|
-
logger.success(`Successfully generated Monthly Blog Summary: ${iocFile}`);
|
|
982
|
-
} catch (error) {
|
|
983
|
-
logger.error(`Error generating monthly blog summary: ${error}`);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
export { DEFAULT_CONFIG, Logger, checkTranslations, cleanTranslations, generateBlogIndex, loadConfig, readJsonFile, validateConfig };
|
|
988
|
-
//# sourceMappingURL=chunk-GVR6HFHM.mjs.map
|
|
989
|
-
//# sourceMappingURL=chunk-GVR6HFHM.mjs.map
|