feng3d-cli 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -17
- package/bin/cli.js +135 -0
- package/dist/index.js +792 -9
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +792 -0
- package/dist/index.umd.cjs.map +1 -0
- package/{dist → lib}/commands/create.d.ts.map +1 -1
- package/{dist → lib}/commands/update.d.ts +1 -0
- package/{dist → lib}/commands/update.d.ts.map +1 -1
- package/{dist → lib}/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -0
- package/{dist → lib}/templates.d.ts +10 -14
- package/lib/templates.d.ts.map +1 -0
- package/{dist → lib}/types/config.d.ts +2 -0
- package/{dist → lib}/types/config.d.ts.map +1 -1
- package/package.json +20 -22
- package/schemas/feng3d.schema.json +5 -0
- package/templates/.github/workflows/pages.yml +35 -2
- package/templates/.github/workflows/publish.yml +2 -8
- package/templates/.github/workflows/pull-request.yml +7 -2
- package/templates/feng3d.json +2 -1
- package/templates/gitignore +3 -0
- package/templates/scripts/postpublish.js +19 -0
- package/templates/scripts/prepublish.js +19 -0
- package/templates/typedoc.json +2 -2
- package/templates/vite.config.js +49 -0
- package/dist/cli.d.ts +0 -7
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -108
- package/dist/cli.js.map +0 -1
- package/dist/commands/create.js +0 -125
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/oss.js +0 -132
- package/dist/commands/oss.js.map +0 -1
- package/dist/commands/update.js +0 -482
- package/dist/commands/update.js.map +0 -1
- package/dist/eslint.d.ts +0 -236
- package/dist/eslint.d.ts.map +0 -1
- package/dist/eslint.js +0 -119
- package/dist/eslint.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js +0 -153
- package/dist/templates.js.map +0 -1
- package/dist/types/config.js +0 -50
- package/dist/types/config.js.map +0 -1
- package/dist/versions.js +0 -60
- package/dist/versions.js.map +0 -1
- package/templates/vitest.config.ts +0 -8
- /package/{dist → lib}/commands/create.d.ts +0 -0
- /package/{dist → lib}/commands/oss.d.ts +0 -0
- /package/{dist → lib}/commands/oss.d.ts.map +0 -0
- /package/{dist → lib}/versions.d.ts +0 -0
- /package/{dist → lib}/versions.d.ts.map +0 -0
package/dist/index.js
CHANGED
|
@@ -1,10 +1,793 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import OSS from "ali-oss";
|
|
5
|
+
import fs$1 from "fs";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
const VERSIONS = {
|
|
8
|
+
// TypeScript 相关
|
|
9
|
+
typescript: "5.8.3",
|
|
10
|
+
tslib: "^2.8.1",
|
|
11
|
+
// ESLint 相关
|
|
12
|
+
eslint: "9.26.0",
|
|
13
|
+
"@eslint/js": "^9.0.0",
|
|
14
|
+
"@typescript-eslint/eslint-plugin": "8.32.1",
|
|
15
|
+
"@typescript-eslint/parser": "8.32.1",
|
|
16
|
+
"typescript-eslint": "^8.32.1",
|
|
17
|
+
globals: "^14.0.0",
|
|
18
|
+
// 测试相关
|
|
19
|
+
vitest: "^3.1.3",
|
|
20
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
21
|
+
"happy-dom": "^20.0.11",
|
|
22
|
+
// 构建工具
|
|
23
|
+
vite: "^6.3.5",
|
|
24
|
+
rimraf: "6.0.1",
|
|
25
|
+
"cross-env": "7.0.3",
|
|
26
|
+
// 文档
|
|
27
|
+
typedoc: "^0.28.4",
|
|
28
|
+
// Git hooks
|
|
29
|
+
husky: "^9.1.7",
|
|
30
|
+
"lint-staged": "^15.2.10"
|
|
31
|
+
};
|
|
32
|
+
function getDevDependencies(options = {}) {
|
|
33
|
+
const deps = {
|
|
34
|
+
"@eslint/js": VERSIONS["@eslint/js"],
|
|
35
|
+
"@typescript-eslint/eslint-plugin": VERSIONS["@typescript-eslint/eslint-plugin"],
|
|
36
|
+
"@typescript-eslint/parser": VERSIONS["@typescript-eslint/parser"],
|
|
37
|
+
"cross-env": VERSIONS["cross-env"],
|
|
38
|
+
eslint: VERSIONS.eslint,
|
|
39
|
+
globals: VERSIONS.globals,
|
|
40
|
+
rimraf: VERSIONS.rimraf,
|
|
41
|
+
tslib: VERSIONS.tslib,
|
|
42
|
+
typescript: VERSIONS.typescript,
|
|
43
|
+
"typescript-eslint": VERSIONS["typescript-eslint"],
|
|
44
|
+
vite: VERSIONS.vite
|
|
45
|
+
};
|
|
46
|
+
if (options.includeVitest !== false) {
|
|
47
|
+
deps.vitest = VERSIONS.vitest;
|
|
48
|
+
}
|
|
49
|
+
if (options.includeCoverage) {
|
|
50
|
+
deps["@vitest/coverage-v8"] = VERSIONS["@vitest/coverage-v8"];
|
|
51
|
+
}
|
|
52
|
+
if (options.includeTypedoc !== false) {
|
|
53
|
+
deps.typedoc = VERSIONS.typedoc;
|
|
54
|
+
}
|
|
55
|
+
deps.husky = VERSIONS.husky;
|
|
56
|
+
deps["lint-staged"] = VERSIONS["lint-staged"];
|
|
57
|
+
return deps;
|
|
58
|
+
}
|
|
59
|
+
const __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
60
|
+
const TEMPLATES_DIR = path.resolve(__dirname$1, "../templates");
|
|
61
|
+
function getGitignoreTemplate() {
|
|
62
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "gitignore"), "utf-8");
|
|
63
|
+
}
|
|
64
|
+
function getCursorrrulesTemplate() {
|
|
65
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, ".cursorrules"), "utf-8");
|
|
66
|
+
}
|
|
67
|
+
function getTsconfigTemplate() {
|
|
68
|
+
return fs.readJsonSync(path.join(TEMPLATES_DIR, "tsconfig.json"));
|
|
69
|
+
}
|
|
70
|
+
function getTsconfigTemplateString() {
|
|
71
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "tsconfig.json"), "utf-8");
|
|
72
|
+
}
|
|
73
|
+
function getViteConfigTemplate() {
|
|
74
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "vite.config.js"), "utf-8");
|
|
75
|
+
}
|
|
76
|
+
function getEslintConfigTemplate() {
|
|
77
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "eslint.config.js"), "utf-8");
|
|
78
|
+
}
|
|
79
|
+
function getTypedocConfig(options) {
|
|
80
|
+
return JSON.parse(getTypedocConfigTemplate(options));
|
|
81
|
+
}
|
|
82
|
+
function getTypedocConfigTemplate(options) {
|
|
83
|
+
const templateContent = fs.readFileSync(path.join(TEMPLATES_DIR, "typedoc.json"), "utf-8");
|
|
84
|
+
return templateContent.replace(/\{\{repoName\}\}/g, options.repoName);
|
|
85
|
+
}
|
|
86
|
+
function getTestIndexTemplate(_options) {
|
|
87
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "test/_.test.ts"), "utf-8");
|
|
88
|
+
}
|
|
89
|
+
function getPublishWorkflowTemplate() {
|
|
90
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, ".github/workflows/publish.yml"), "utf-8");
|
|
91
|
+
}
|
|
92
|
+
function getPagesWorkflowTemplate() {
|
|
93
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, ".github/workflows/pages.yml"), "utf-8");
|
|
94
|
+
}
|
|
95
|
+
function getPullRequestWorkflowTemplate() {
|
|
96
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, ".github/workflows/pull-request.yml"), "utf-8");
|
|
97
|
+
}
|
|
98
|
+
function getHuskyPreCommitTemplate() {
|
|
99
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, ".husky/pre-commit"), "utf-8");
|
|
100
|
+
}
|
|
101
|
+
function getLicenseTemplate(ctx = {}) {
|
|
102
|
+
const year = ctx.year || (/* @__PURE__ */ new Date()).getFullYear();
|
|
103
|
+
const template = fs.readFileSync(path.join(TEMPLATES_DIR, "LICENSE"), "utf-8");
|
|
104
|
+
return template.replace("{{year}}", String(year));
|
|
105
|
+
}
|
|
106
|
+
function getVscodeSettingsTemplate() {
|
|
107
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, ".vscode/settings.json"), "utf-8");
|
|
108
|
+
}
|
|
109
|
+
function getPrepublishScriptTemplate() {
|
|
110
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "scripts/prepublish.js"), "utf-8");
|
|
111
|
+
}
|
|
112
|
+
function getPostpublishScriptTemplate() {
|
|
113
|
+
return fs.readFileSync(path.join(TEMPLATES_DIR, "scripts/postpublish.js"), "utf-8");
|
|
114
|
+
}
|
|
115
|
+
const SCHEMA_PATHS = [
|
|
116
|
+
"./schemas/feng3d.schema.json",
|
|
117
|
+
"./node_modules/feng3d-cli/schemas/feng3d.schema.json"
|
|
118
|
+
];
|
|
119
|
+
function detectSchemaPath(projectDir) {
|
|
120
|
+
for (const schemaPath of SCHEMA_PATHS) {
|
|
121
|
+
const fullPath = path.join(projectDir, schemaPath);
|
|
122
|
+
if (fs.existsSync(fullPath)) {
|
|
123
|
+
return schemaPath;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return SCHEMA_PATHS[1];
|
|
127
|
+
}
|
|
128
|
+
function getFeng3dConfigTemplate(options) {
|
|
129
|
+
const templateContent = fs.readFileSync(path.join(TEMPLATES_DIR, "feng3d.json"), "utf-8");
|
|
130
|
+
const content = templateContent.replace(/\{\{name\}\}/g, options.name);
|
|
131
|
+
const config = JSON.parse(content);
|
|
132
|
+
if (options.schemaPath) {
|
|
133
|
+
config.$schema = options.schemaPath;
|
|
134
|
+
}
|
|
135
|
+
return config;
|
|
136
|
+
}
|
|
137
|
+
const DEFAULT_UPDATE_CONFIG = {
|
|
138
|
+
config: true,
|
|
139
|
+
eslint: true,
|
|
140
|
+
gitignore: true,
|
|
141
|
+
cursorrules: true,
|
|
142
|
+
publish: true,
|
|
143
|
+
pages: true,
|
|
144
|
+
pullRequest: true,
|
|
145
|
+
typedoc: true,
|
|
146
|
+
test: true,
|
|
147
|
+
deps: true,
|
|
148
|
+
husky: true,
|
|
149
|
+
license: true,
|
|
150
|
+
vscode: true,
|
|
151
|
+
tsconfig: true,
|
|
152
|
+
vite: true
|
|
153
|
+
};
|
|
154
|
+
const DEFAULT_CONFIG = {
|
|
155
|
+
eslint: {
|
|
156
|
+
enabled: true,
|
|
157
|
+
ignores: [],
|
|
158
|
+
rules: {}
|
|
159
|
+
},
|
|
160
|
+
vitest: {
|
|
161
|
+
enabled: true,
|
|
162
|
+
testTimeout: 0
|
|
163
|
+
},
|
|
164
|
+
typedoc: {
|
|
165
|
+
enabled: true,
|
|
166
|
+
outDir: "public"
|
|
167
|
+
},
|
|
168
|
+
oss: {
|
|
169
|
+
localDir: "./public",
|
|
170
|
+
ossDir: ""
|
|
171
|
+
},
|
|
172
|
+
templates: {
|
|
173
|
+
examples: true,
|
|
174
|
+
test: true
|
|
175
|
+
},
|
|
176
|
+
update: DEFAULT_UPDATE_CONFIG
|
|
177
|
+
};
|
|
178
|
+
const configPath = "C:/Users/Administrator/oss_config.json";
|
|
179
|
+
async function ossUploadDir(localDirPath, ossDirPath) {
|
|
180
|
+
const config = readConfig(configPath);
|
|
181
|
+
if (!config) {
|
|
182
|
+
console.error("无法读取配置文件");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const client = initializeOSS(config);
|
|
186
|
+
const { files, failedFiles } = collectFiles(localDirPath, ossDirPath);
|
|
187
|
+
console.log(`总文件数: ${files.length}`);
|
|
188
|
+
const { successCount, failureCount } = await uploadFiles(files, client, failedFiles);
|
|
189
|
+
console.log(`上传完成: 成功 ${successCount} 个, 失败 ${failureCount} 个`);
|
|
190
|
+
if (failureCount > 0) {
|
|
191
|
+
console.log("上传失败的文件列表:");
|
|
192
|
+
failedFiles.forEach((file) => console.log(file));
|
|
193
|
+
}
|
|
194
|
+
if (successCount > 0) {
|
|
195
|
+
const baseUrl = config.baseUrl || `https://${config.bucket}.${config.region}.aliyuncs.com`;
|
|
196
|
+
const accessUrl = `${baseUrl}/${ossDirPath}/`;
|
|
197
|
+
console.log(`
|
|
198
|
+
📎 访问路径: ${accessUrl}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function readConfig(filePath) {
|
|
202
|
+
try {
|
|
203
|
+
const fileContent = fs$1.readFileSync(filePath, "utf8");
|
|
204
|
+
const config = JSON.parse(fileContent);
|
|
205
|
+
return config;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error("读取或解析配置文件时出错:", error);
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function initializeOSS(config) {
|
|
212
|
+
return new OSS({
|
|
213
|
+
region: config.region,
|
|
214
|
+
accessKeyId: config.accessKeyId,
|
|
215
|
+
accessKeySecret: config.accessKeySecret,
|
|
216
|
+
bucket: config.bucket
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function collectFiles(dirPath, ossDirPath) {
|
|
220
|
+
const files = [];
|
|
221
|
+
const failedFiles = [];
|
|
222
|
+
function traverseDirectory(currentDirPath, currentOssPath) {
|
|
223
|
+
const items = fs$1.readdirSync(currentDirPath);
|
|
224
|
+
for (const item of items) {
|
|
225
|
+
const localFilePath = path.join(currentDirPath, item);
|
|
226
|
+
const ossFilePath = `${currentOssPath}/${item}`;
|
|
227
|
+
if (fs$1.statSync(localFilePath).isDirectory()) {
|
|
228
|
+
traverseDirectory(localFilePath, ossFilePath);
|
|
229
|
+
} else {
|
|
230
|
+
files.push({ localFilePath, ossFilePath });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
traverseDirectory(dirPath, ossDirPath);
|
|
235
|
+
return { files, failedFiles };
|
|
236
|
+
}
|
|
237
|
+
function renderProgressBar(current, total, barLength = 30) {
|
|
238
|
+
const percent = current / total;
|
|
239
|
+
const filled = Math.round(barLength * percent);
|
|
240
|
+
const empty = barLength - filled;
|
|
241
|
+
const bar = "█".repeat(filled) + "░".repeat(empty);
|
|
242
|
+
const percentText = (percent * 100).toFixed(0).padStart(3, " ");
|
|
243
|
+
return `[${bar}] ${percentText}% (${current}/${total})`;
|
|
244
|
+
}
|
|
245
|
+
async function uploadFiles(files, client, failedFiles) {
|
|
246
|
+
let successCount = 0;
|
|
247
|
+
let failureCount = 0;
|
|
248
|
+
let uploadedCount = 0;
|
|
249
|
+
const total = files.length;
|
|
250
|
+
process.stdout.write(`上传进度: ${renderProgressBar(0, total)}`);
|
|
251
|
+
for (const { localFilePath, ossFilePath } of files) {
|
|
252
|
+
try {
|
|
253
|
+
await client.put(ossFilePath, localFilePath);
|
|
254
|
+
successCount++;
|
|
255
|
+
} catch (e) {
|
|
256
|
+
process.stdout.write("\n");
|
|
257
|
+
console.error(`文件上传失败: ${localFilePath}`, e);
|
|
258
|
+
failedFiles.push(localFilePath);
|
|
259
|
+
failureCount++;
|
|
260
|
+
}
|
|
261
|
+
uploadedCount++;
|
|
262
|
+
process.stdout.write(`\r上传进度: ${renderProgressBar(uploadedCount, total)}`);
|
|
263
|
+
}
|
|
264
|
+
process.stdout.write("\n");
|
|
265
|
+
return { successCount, failureCount, uploadedCount };
|
|
266
|
+
}
|
|
267
|
+
const AUTO_GENERATED_FILES = [
|
|
268
|
+
{ path: ".cursorrules", getTemplate: () => getCursorrrulesTemplate() },
|
|
269
|
+
{ path: "eslint.config.js", getTemplate: () => getEslintConfigTemplate() },
|
|
270
|
+
{ path: "typedoc.json", getTemplate: (ctx) => getTypedocConfigTemplate({ repoName: ctx.repoName }) },
|
|
271
|
+
{ path: "test/_.test.ts", getTemplate: (ctx) => getTestIndexTemplate({ name: ctx.name }) },
|
|
272
|
+
{ path: ".husky/pre-commit", getTemplate: () => getHuskyPreCommitTemplate() },
|
|
273
|
+
{ path: ".vscode/settings.json", getTemplate: () => getVscodeSettingsTemplate() },
|
|
274
|
+
{ path: "tsconfig.json", getTemplate: () => getTsconfigTemplateString() },
|
|
275
|
+
{ path: "vite.config.js", getTemplate: () => getViteConfigTemplate() },
|
|
276
|
+
{ path: "scripts/prepublish.js", getTemplate: () => getPrepublishScriptTemplate() },
|
|
277
|
+
{ path: "scripts/postpublish.js", getTemplate: () => getPostpublishScriptTemplate() }
|
|
278
|
+
];
|
|
279
|
+
async function isFileInGitignore(projectDir, filePath) {
|
|
280
|
+
const gitignorePath = path.join(projectDir, ".gitignore");
|
|
281
|
+
if (!await fs.pathExists(gitignorePath)) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
const gitignoreContent = await fs.readFile(gitignorePath, "utf-8");
|
|
285
|
+
const escapedPath = filePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
286
|
+
const regex = new RegExp(`^${escapedPath}$`, "m");
|
|
287
|
+
return regex.test(gitignoreContent);
|
|
288
|
+
}
|
|
289
|
+
async function updateFeng3dConfig(projectDir) {
|
|
290
|
+
const configPath2 = path.join(projectDir, "feng3d.json");
|
|
291
|
+
const schemaPath = detectSchemaPath(projectDir);
|
|
292
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
293
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
294
|
+
const name = packageJson.name || path.basename(projectDir);
|
|
295
|
+
const isInGitignore = await isFileInGitignore(projectDir, "feng3d.json");
|
|
296
|
+
if (!await fs.pathExists(configPath2) || isInGitignore) {
|
|
297
|
+
const configTemplate = getFeng3dConfigTemplate({ name, schemaPath });
|
|
298
|
+
await fs.writeJson(configPath2, configTemplate, { spaces: 4 });
|
|
299
|
+
console.log(chalk.gray(isInGitignore ? " 覆盖: feng3d.json(在忽略列表中)" : " 创建: feng3d.json"));
|
|
300
|
+
} else {
|
|
301
|
+
try {
|
|
302
|
+
const configData = await fs.readJson(configPath2);
|
|
303
|
+
let updated = false;
|
|
304
|
+
if (configData.$schema !== schemaPath) {
|
|
305
|
+
configData.$schema = schemaPath;
|
|
306
|
+
updated = true;
|
|
307
|
+
}
|
|
308
|
+
if (configData.name !== name) {
|
|
309
|
+
configData.name = name;
|
|
310
|
+
updated = true;
|
|
311
|
+
}
|
|
312
|
+
if (updated) {
|
|
313
|
+
await fs.writeJson(configPath2, configData, { spaces: 4 });
|
|
314
|
+
console.log(chalk.gray(" 更新: feng3d.json"));
|
|
315
|
+
} else {
|
|
316
|
+
console.log(chalk.gray(" 跳过: feng3d.json(无需更新)"));
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
const configTemplate = getFeng3dConfigTemplate({ name, schemaPath });
|
|
320
|
+
await fs.writeJson(configPath2, configTemplate, { spaces: 4 });
|
|
321
|
+
console.log(chalk.gray(" 重建: feng3d.json"));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function loadProjectConfig(projectDir) {
|
|
326
|
+
const configPath2 = path.join(projectDir, "feng3d.json");
|
|
327
|
+
if (!await fs.pathExists(configPath2)) {
|
|
328
|
+
return DEFAULT_CONFIG;
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
const configData = await fs.readJson(configPath2);
|
|
332
|
+
return { ...DEFAULT_CONFIG, ...configData };
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.log(chalk.yellow(` 警告: 无法加载 feng3d.json,使用默认配置 (${error})`));
|
|
335
|
+
return DEFAULT_CONFIG;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function hasAnyUpdateOption(options) {
|
|
339
|
+
return !!(options.config || options.eslint || options.gitignore || options.cursorrules || options.publish || options.pages || options.pullRequest || options.typedoc || options.test || options.deps || options.husky || options.license || options.vscode || options.tsconfig);
|
|
340
|
+
}
|
|
341
|
+
function mergeUpdateOptions(cliOptions, configUpdate) {
|
|
342
|
+
if (cliOptions.all) {
|
|
343
|
+
return DEFAULT_UPDATE_CONFIG;
|
|
344
|
+
}
|
|
345
|
+
if (hasAnyUpdateOption(cliOptions)) {
|
|
346
|
+
return {
|
|
347
|
+
config: cliOptions.config || false,
|
|
348
|
+
eslint: cliOptions.eslint || false,
|
|
349
|
+
gitignore: cliOptions.gitignore || false,
|
|
350
|
+
cursorrules: cliOptions.cursorrules || false,
|
|
351
|
+
publish: cliOptions.publish || false,
|
|
352
|
+
pages: cliOptions.pages || false,
|
|
353
|
+
pullRequest: cliOptions.pullRequest || false,
|
|
354
|
+
typedoc: cliOptions.typedoc || false,
|
|
355
|
+
test: cliOptions.test || false,
|
|
356
|
+
deps: cliOptions.deps || false,
|
|
357
|
+
husky: cliOptions.husky || false,
|
|
358
|
+
license: cliOptions.license || false,
|
|
359
|
+
vscode: cliOptions.vscode || false,
|
|
360
|
+
tsconfig: cliOptions.tsconfig || false
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return { ...DEFAULT_UPDATE_CONFIG, ...configUpdate };
|
|
364
|
+
}
|
|
365
|
+
async function updateProject(options) {
|
|
366
|
+
const projectDir = path.resolve(options.directory);
|
|
367
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
368
|
+
if (!await fs.pathExists(packageJsonPath)) {
|
|
369
|
+
throw new Error(`${projectDir} 不是有效的项目目录(未找到 package.json)`);
|
|
370
|
+
}
|
|
371
|
+
const config = await loadProjectConfig(projectDir);
|
|
372
|
+
const updateConfig = mergeUpdateOptions(options, config.update || {});
|
|
373
|
+
if (updateConfig.config) {
|
|
374
|
+
await updateFeng3dConfig(projectDir);
|
|
375
|
+
}
|
|
376
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
377
|
+
const name = packageJson.name || path.basename(projectDir);
|
|
378
|
+
const repoName = name.replace(/^@[^/]+\//, "");
|
|
379
|
+
const templateContext = { name, repoName };
|
|
380
|
+
if (updateConfig.gitignore) {
|
|
381
|
+
const gitignorePath = path.join(projectDir, ".gitignore");
|
|
382
|
+
if (!await fs.pathExists(gitignorePath)) {
|
|
383
|
+
await fs.writeFile(gitignorePath, getGitignoreTemplate());
|
|
384
|
+
console.log(chalk.gray(" 创建: .gitignore"));
|
|
385
|
+
} else {
|
|
386
|
+
console.log(chalk.gray(" 跳过: .gitignore(已存在)"));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (updateConfig.cursorrules) {
|
|
390
|
+
await fs.writeFile(path.join(projectDir, ".cursorrules"), getCursorrrulesTemplate());
|
|
391
|
+
console.log(chalk.gray(" 更新: .cursorrules"));
|
|
392
|
+
}
|
|
393
|
+
if (updateConfig.eslint) {
|
|
394
|
+
if (config.eslint?.enabled !== false) {
|
|
395
|
+
await createEslintConfigFile(projectDir);
|
|
396
|
+
console.log(chalk.gray(" 更新: eslint.config.js"));
|
|
397
|
+
} else {
|
|
398
|
+
console.log(chalk.gray(" 跳过: eslint.config.js(配置中已禁用)"));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (updateConfig.publish) {
|
|
402
|
+
await fs.ensureDir(path.join(projectDir, ".github/workflows"));
|
|
403
|
+
await fs.writeFile(path.join(projectDir, ".github/workflows/publish.yml"), getPublishWorkflowTemplate());
|
|
404
|
+
console.log(chalk.gray(" 更新: .github/workflows/publish.yml"));
|
|
405
|
+
}
|
|
406
|
+
if (updateConfig.pages) {
|
|
407
|
+
await fs.ensureDir(path.join(projectDir, ".github/workflows"));
|
|
408
|
+
await fs.writeFile(path.join(projectDir, ".github/workflows/pages.yml"), getPagesWorkflowTemplate());
|
|
409
|
+
console.log(chalk.gray(" 更新: .github/workflows/pages.yml"));
|
|
410
|
+
}
|
|
411
|
+
if (updateConfig.pullRequest) {
|
|
412
|
+
await fs.ensureDir(path.join(projectDir, ".github/workflows"));
|
|
413
|
+
await fs.writeFile(path.join(projectDir, ".github/workflows/pull-request.yml"), getPullRequestWorkflowTemplate());
|
|
414
|
+
console.log(chalk.gray(" 更新: .github/workflows/pull-request.yml"));
|
|
415
|
+
}
|
|
416
|
+
if (updateConfig.typedoc) {
|
|
417
|
+
if (config.typedoc?.enabled !== false) {
|
|
418
|
+
const typedocContent = getTypedocConfigTemplate({ repoName });
|
|
419
|
+
await fs.writeFile(path.join(projectDir, "typedoc.json"), typedocContent);
|
|
420
|
+
console.log(chalk.gray(" 更新: typedoc.json"));
|
|
421
|
+
} else {
|
|
422
|
+
console.log(chalk.gray(" 跳过: typedoc.json(配置中已禁用)"));
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (updateConfig.test) {
|
|
426
|
+
if (config.vitest?.enabled !== false) {
|
|
427
|
+
const testDir = path.join(projectDir, "test");
|
|
428
|
+
const testFilePath = path.join(testDir, "_.test.ts");
|
|
429
|
+
let hasOtherFiles = false;
|
|
430
|
+
if (await fs.pathExists(testDir)) {
|
|
431
|
+
const files = await fs.readdir(testDir);
|
|
432
|
+
hasOtherFiles = files.some((file) => file !== "_.test.ts");
|
|
433
|
+
}
|
|
434
|
+
if (!hasOtherFiles) {
|
|
435
|
+
await fs.ensureDir(testDir);
|
|
436
|
+
const testContent = getTestIndexTemplate();
|
|
437
|
+
await fs.writeFile(testFilePath, testContent);
|
|
438
|
+
console.log(chalk.gray(" 更新: test/_.test.ts"));
|
|
439
|
+
} else {
|
|
440
|
+
console.log(chalk.gray(" 跳过: test/_.test.ts(测试目录已有其他文件)"));
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
console.log(chalk.gray(" 跳过: test/_.test.ts(vitest 配置中已禁用)"));
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (updateConfig.deps) {
|
|
447
|
+
await updateDependencies(projectDir, config);
|
|
448
|
+
console.log(chalk.gray(" 更新: package.json devDependencies"));
|
|
449
|
+
}
|
|
450
|
+
if (updateConfig.husky) {
|
|
451
|
+
await fs.ensureDir(path.join(projectDir, ".husky"));
|
|
452
|
+
await fs.writeFile(path.join(projectDir, ".husky/pre-commit"), getHuskyPreCommitTemplate());
|
|
453
|
+
console.log(chalk.gray(" 更新: .husky/pre-commit"));
|
|
454
|
+
await updateHuskyConfig(projectDir);
|
|
455
|
+
}
|
|
456
|
+
if (updateConfig.license) {
|
|
457
|
+
const licensePath = path.join(projectDir, "LICENSE");
|
|
458
|
+
if (!await fs.pathExists(licensePath)) {
|
|
459
|
+
await fs.writeFile(licensePath, getLicenseTemplate());
|
|
460
|
+
console.log(chalk.gray(" 创建: LICENSE"));
|
|
461
|
+
} else {
|
|
462
|
+
console.log(chalk.gray(" 跳过: LICENSE(已存在)"));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (updateConfig.vscode) {
|
|
466
|
+
await fs.ensureDir(path.join(projectDir, ".vscode"));
|
|
467
|
+
await fs.writeFile(path.join(projectDir, ".vscode/settings.json"), getVscodeSettingsTemplate());
|
|
468
|
+
console.log(chalk.gray(" 更新: .vscode/settings.json"));
|
|
469
|
+
}
|
|
470
|
+
const isFeng3dCli = name === "feng3d-cli";
|
|
471
|
+
if (updateConfig.tsconfig && !isFeng3dCli) {
|
|
472
|
+
const tsconfigPath = path.join(projectDir, "tsconfig.json");
|
|
473
|
+
const isIgnored = await isFileInGitignore(projectDir, "tsconfig.json");
|
|
474
|
+
if (isIgnored || !await fs.pathExists(tsconfigPath)) {
|
|
475
|
+
await fs.writeFile(tsconfigPath, getTsconfigTemplateString());
|
|
476
|
+
console.log(chalk.gray(isIgnored ? " 覆盖: tsconfig.json(在忽略列表中)" : " 创建: tsconfig.json"));
|
|
477
|
+
} else {
|
|
478
|
+
console.log(chalk.gray(" 跳过: tsconfig.json(已存在且不在忽略列表中)"));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (updateConfig.vite && !isFeng3dCli) {
|
|
482
|
+
const viteConfigPath = path.join(projectDir, "vite.config.js");
|
|
483
|
+
const isIgnored = await isFileInGitignore(projectDir, "vite.config.js");
|
|
484
|
+
if (isIgnored || !await fs.pathExists(viteConfigPath)) {
|
|
485
|
+
await fs.writeFile(viteConfigPath, getViteConfigTemplate());
|
|
486
|
+
console.log(chalk.gray(isIgnored ? " 覆盖: vite.config.js(在忽略列表中)" : " 创建: vite.config.js"));
|
|
487
|
+
} else {
|
|
488
|
+
console.log(chalk.gray(" 跳过: vite.config.js(已存在且不在忽略列表中)"));
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const scriptsDir = path.join(projectDir, "scripts");
|
|
492
|
+
const prepublishPath = path.join(scriptsDir, "prepublish.js");
|
|
493
|
+
const postpublishPath = path.join(scriptsDir, "postpublish.js");
|
|
494
|
+
if (!await fs.pathExists(prepublishPath)) {
|
|
495
|
+
await fs.ensureDir(scriptsDir);
|
|
496
|
+
await fs.writeFile(prepublishPath, getPrepublishScriptTemplate());
|
|
497
|
+
console.log(chalk.gray(" 创建: scripts/prepublish.js"));
|
|
498
|
+
}
|
|
499
|
+
if (!await fs.pathExists(postpublishPath)) {
|
|
500
|
+
await fs.ensureDir(scriptsDir);
|
|
501
|
+
await fs.writeFile(postpublishPath, getPostpublishScriptTemplate());
|
|
502
|
+
console.log(chalk.gray(" 创建: scripts/postpublish.js"));
|
|
503
|
+
}
|
|
504
|
+
await syncGitignoreForModifiedFiles(projectDir, templateContext, name);
|
|
505
|
+
}
|
|
506
|
+
async function createEslintConfigFile(projectDir) {
|
|
507
|
+
await fs.writeFile(path.join(projectDir, "eslint.config.js"), getEslintConfigTemplate());
|
|
508
|
+
}
|
|
509
|
+
function detectIndent(content) {
|
|
510
|
+
const match = content.match(/^[ \t]+/m);
|
|
511
|
+
return match ? match[0] : " ";
|
|
512
|
+
}
|
|
513
|
+
async function updateDependencies(projectDir, config) {
|
|
514
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
515
|
+
const originalContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
516
|
+
const indent = detectIndent(originalContent);
|
|
517
|
+
const hasTrailingNewline = originalContent.endsWith("\n");
|
|
518
|
+
const packageJson = JSON.parse(originalContent);
|
|
519
|
+
const standardDeps = getDevDependencies({
|
|
520
|
+
includeVitest: config.vitest?.enabled !== false,
|
|
521
|
+
includeTypedoc: config.typedoc?.enabled !== false
|
|
522
|
+
});
|
|
523
|
+
let updated = false;
|
|
524
|
+
if (!packageJson.devDependencies) {
|
|
525
|
+
packageJson.devDependencies = {};
|
|
526
|
+
}
|
|
527
|
+
for (const [key, value] of Object.entries(standardDeps)) {
|
|
528
|
+
if (!(key in packageJson.devDependencies)) {
|
|
529
|
+
packageJson.devDependencies[key] = value;
|
|
530
|
+
updated = true;
|
|
531
|
+
console.log(chalk.gray(` 添加: devDependencies.${key} = "${value}"`));
|
|
532
|
+
} else if (packageJson.devDependencies[key] !== value) {
|
|
533
|
+
packageJson.devDependencies[key] = value;
|
|
534
|
+
updated = true;
|
|
535
|
+
console.log(chalk.gray(` 更新: devDependencies.${key} = "${value}"`));
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (!packageJson.scripts) {
|
|
539
|
+
packageJson.scripts = {};
|
|
540
|
+
}
|
|
541
|
+
const standardScripts = {
|
|
542
|
+
clean: "rimraf lib dist public",
|
|
543
|
+
build: "vite build && tsc",
|
|
544
|
+
lint: "eslint . --ext .js,.ts --max-warnings 0",
|
|
545
|
+
lintfix: "npm run lint -- --fix",
|
|
546
|
+
docs: "typedoc",
|
|
547
|
+
upload_oss: "npm run docs && npx feng3d-cli oss_upload_dir",
|
|
548
|
+
update: "npx feng3d-cli update && npm install",
|
|
549
|
+
prepublishOnly: "node scripts/prepublish.js",
|
|
550
|
+
postpublish: "node scripts/postpublish.js"
|
|
551
|
+
};
|
|
552
|
+
for (const [key, value] of Object.entries(standardScripts)) {
|
|
553
|
+
if (!(key in packageJson.scripts)) {
|
|
554
|
+
packageJson.scripts[key] = value;
|
|
555
|
+
updated = true;
|
|
556
|
+
console.log(chalk.gray(` 添加: scripts.${key}`));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (updated) {
|
|
560
|
+
let newContent = JSON.stringify(packageJson, null, indent);
|
|
561
|
+
if (hasTrailingNewline) {
|
|
562
|
+
newContent += "\n";
|
|
563
|
+
}
|
|
564
|
+
await fs.writeFile(packageJsonPath, newContent);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async function updateHuskyConfig(projectDir) {
|
|
568
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
569
|
+
const originalContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
570
|
+
const indent = detectIndent(originalContent);
|
|
571
|
+
const hasTrailingNewline = originalContent.endsWith("\n");
|
|
572
|
+
const packageJson = JSON.parse(originalContent);
|
|
573
|
+
let updated = false;
|
|
574
|
+
if (!packageJson.devDependencies) {
|
|
575
|
+
packageJson.devDependencies = {};
|
|
576
|
+
}
|
|
577
|
+
if (!packageJson.devDependencies.husky) {
|
|
578
|
+
packageJson.devDependencies.husky = VERSIONS.husky;
|
|
579
|
+
updated = true;
|
|
580
|
+
console.log(chalk.gray(` 添加: devDependencies.husky = "${VERSIONS.husky}"`));
|
|
581
|
+
}
|
|
582
|
+
if (!packageJson.devDependencies["lint-staged"]) {
|
|
583
|
+
packageJson.devDependencies["lint-staged"] = VERSIONS["lint-staged"];
|
|
584
|
+
updated = true;
|
|
585
|
+
console.log(chalk.gray(` 添加: devDependencies.lint-staged = "${VERSIONS["lint-staged"]}"`));
|
|
586
|
+
}
|
|
587
|
+
if (!packageJson.scripts) {
|
|
588
|
+
packageJson.scripts = {};
|
|
589
|
+
}
|
|
590
|
+
if (packageJson.scripts.prepare !== "husky") {
|
|
591
|
+
packageJson.scripts.prepare = "husky";
|
|
592
|
+
updated = true;
|
|
593
|
+
console.log(chalk.gray(' 添加: scripts.prepare = "husky"'));
|
|
594
|
+
}
|
|
595
|
+
if (!packageJson["lint-staged"]) {
|
|
596
|
+
packageJson["lint-staged"] = {
|
|
597
|
+
"*.{js,ts}": ["eslint --fix --max-warnings 0"]
|
|
598
|
+
};
|
|
599
|
+
updated = true;
|
|
600
|
+
console.log(chalk.gray(" 添加: lint-staged 配置"));
|
|
601
|
+
}
|
|
602
|
+
if (updated) {
|
|
603
|
+
let newContent = JSON.stringify(packageJson, null, indent);
|
|
604
|
+
if (hasTrailingNewline) {
|
|
605
|
+
newContent += "\n";
|
|
606
|
+
}
|
|
607
|
+
await fs.writeFile(packageJsonPath, newContent);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const AUTO_GENERATED_COMMENT = `# 以下文件可由 feng3d-cli 自动生成,无需提交
|
|
611
|
+
# 运行 \`feng3d-cli update\` 可重新生成`;
|
|
612
|
+
async function syncGitignoreForModifiedFiles(projectDir, _ctx, projectName) {
|
|
613
|
+
const gitignorePath = path.join(projectDir, ".gitignore");
|
|
614
|
+
if (!await fs.pathExists(gitignorePath)) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
let gitignoreContent = await fs.readFile(gitignorePath, "utf-8");
|
|
618
|
+
let modified = false;
|
|
619
|
+
const isFeng3dCli = projectName === "feng3d-cli";
|
|
620
|
+
const skipFiles = isFeng3dCli ? ["tsconfig.json", "vite.config.js"] : [];
|
|
621
|
+
const filesToAdd = [];
|
|
622
|
+
const feng3dConfigPath = "feng3d.json";
|
|
623
|
+
const escapedFeng3dPath = feng3dConfigPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
624
|
+
const feng3dRegex = new RegExp(`^${escapedFeng3dPath}$`, "m");
|
|
625
|
+
if (!feng3dRegex.test(gitignoreContent)) {
|
|
626
|
+
filesToAdd.push(feng3dConfigPath);
|
|
627
|
+
}
|
|
628
|
+
for (const file of AUTO_GENERATED_FILES) {
|
|
629
|
+
if (skipFiles.includes(file.path)) {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const escapedPath = file.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
633
|
+
const regex = new RegExp(`^${escapedPath}$`, "m");
|
|
634
|
+
if (!regex.test(gitignoreContent)) {
|
|
635
|
+
const filePath = path.join(projectDir, file.path);
|
|
636
|
+
if (await fs.pathExists(filePath)) {
|
|
637
|
+
const fileContent = await fs.readFile(filePath, "utf-8");
|
|
638
|
+
const templateContent = file.getTemplate(_ctx);
|
|
639
|
+
if (fileContent.trim() === templateContent.trim()) {
|
|
640
|
+
filesToAdd.push(file.path);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (filesToAdd.length > 0) {
|
|
646
|
+
const hasComment = gitignoreContent.includes("# 以下文件可由 feng3d-cli 自动生成");
|
|
647
|
+
if (!hasComment) {
|
|
648
|
+
gitignoreContent = gitignoreContent.trim() + "\n\n" + AUTO_GENERATED_COMMENT + "\n" + filesToAdd.join("\n") + "\n";
|
|
649
|
+
} else {
|
|
650
|
+
for (const filePath of filesToAdd) {
|
|
651
|
+
gitignoreContent = gitignoreContent.trim() + "\n" + filePath + "\n";
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
modified = true;
|
|
655
|
+
for (const filePath of filesToAdd) {
|
|
656
|
+
console.log(chalk.gray(` 添加到 .gitignore: ${filePath}`));
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (modified) {
|
|
660
|
+
gitignoreContent = gitignoreContent.replace(/\n\n+/g, "\n\n").trim() + "\n";
|
|
661
|
+
await fs.writeFile(gitignorePath, gitignoreContent);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
async function createProject(name, options) {
|
|
665
|
+
const projectDir = path.join(options.directory, name);
|
|
666
|
+
if (await fs.pathExists(projectDir)) {
|
|
667
|
+
throw new Error(`目录 ${projectDir} 已存在`);
|
|
668
|
+
}
|
|
669
|
+
await fs.ensureDir(projectDir);
|
|
670
|
+
await fs.ensureDir(path.join(projectDir, "src"));
|
|
671
|
+
console.log(chalk.gray(` 创建目录: ${projectDir}`));
|
|
672
|
+
const packageJson = createPackageJson(name, options);
|
|
673
|
+
await fs.writeJson(path.join(projectDir, "package.json"), packageJson, { spaces: 4 });
|
|
674
|
+
console.log(chalk.gray(" 创建: package.json"));
|
|
675
|
+
await fs.writeJson(path.join(projectDir, "tsconfig.json"), getTsconfigTemplate(), { spaces: 4 });
|
|
676
|
+
console.log(chalk.gray(" 创建: tsconfig.json"));
|
|
677
|
+
await fs.writeFile(path.join(projectDir, ".gitignore"), getGitignoreTemplate());
|
|
678
|
+
console.log(chalk.gray(" 创建: .gitignore"));
|
|
679
|
+
await fs.writeFile(path.join(projectDir, ".cursorrules"), getCursorrrulesTemplate());
|
|
680
|
+
console.log(chalk.gray(" 创建: .cursorrules"));
|
|
681
|
+
await createEslintConfigFile(projectDir);
|
|
682
|
+
console.log(chalk.gray(" 创建: eslint.config.js"));
|
|
683
|
+
const typedocConfig = getTypedocConfig({ repoName: name });
|
|
684
|
+
await fs.writeJson(path.join(projectDir, "typedoc.json"), typedocConfig, { spaces: 4 });
|
|
685
|
+
console.log(chalk.gray(" 创建: typedoc.json"));
|
|
686
|
+
await fs.writeFile(path.join(projectDir, "src/index.ts"), `/**
|
|
687
|
+
* @feng3d/${name}
|
|
4
688
|
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
689
|
+
|
|
690
|
+
export {};
|
|
691
|
+
`);
|
|
692
|
+
console.log(chalk.gray(" 创建: src/index.ts"));
|
|
693
|
+
await fs.writeFile(path.join(projectDir, "README.md"), `# @feng3d/${name}
|
|
694
|
+
`);
|
|
695
|
+
console.log(chalk.gray(" 创建: README.md"));
|
|
696
|
+
if (options.examples !== false) {
|
|
697
|
+
await fs.ensureDir(path.join(projectDir, "examples"));
|
|
698
|
+
console.log(chalk.gray(" 创建: examples/"));
|
|
699
|
+
}
|
|
700
|
+
if (options.vitest !== false) {
|
|
701
|
+
await fs.ensureDir(path.join(projectDir, "test"));
|
|
702
|
+
console.log(chalk.gray(" 创建: test/"));
|
|
703
|
+
}
|
|
704
|
+
await fs.ensureDir(path.join(projectDir, ".github/workflows"));
|
|
705
|
+
await fs.writeFile(path.join(projectDir, ".github/workflows/publish.yml"), getPublishWorkflowTemplate());
|
|
706
|
+
console.log(chalk.gray(" 创建: .github/workflows/publish.yml"));
|
|
707
|
+
await fs.ensureDir(path.join(projectDir, "scripts"));
|
|
708
|
+
await fs.writeFile(path.join(projectDir, "scripts/prepublish.js"), getPrepublishScriptTemplate());
|
|
709
|
+
await fs.writeFile(path.join(projectDir, "scripts/postpublish.js"), getPostpublishScriptTemplate());
|
|
710
|
+
console.log(chalk.gray(" 创建: scripts/prepublish.js"));
|
|
711
|
+
console.log(chalk.gray(" 创建: scripts/postpublish.js"));
|
|
712
|
+
await fs.writeJson(path.join(projectDir, "feng3d.json"), getFeng3dConfigTemplate({ name }), { spaces: 4 });
|
|
713
|
+
console.log(chalk.gray(" 创建: feng3d.json"));
|
|
714
|
+
}
|
|
715
|
+
function createPackageJson(name, options) {
|
|
716
|
+
const scripts = {
|
|
717
|
+
dev: "cd examples && npm run dev",
|
|
718
|
+
clean: "rimraf lib dist public",
|
|
719
|
+
build: "vite build && tsc",
|
|
720
|
+
types: "tsc",
|
|
721
|
+
watch: "tsc -w",
|
|
722
|
+
lint: "eslint . --ext .js,.ts --max-warnings 0",
|
|
723
|
+
lintfix: "npm run lint -- --fix",
|
|
724
|
+
docs: "typedoc",
|
|
725
|
+
release: "npm run clean && npm run lint && npm test && npm run build && npm run docs && npm publish",
|
|
726
|
+
prepublishOnly: "node scripts/prepublish.js",
|
|
727
|
+
postpublish: "node scripts/postpublish.js"
|
|
728
|
+
};
|
|
729
|
+
if (options.vitest !== false) {
|
|
730
|
+
scripts.test = "vitest run";
|
|
731
|
+
scripts["test:watch"] = "vitest";
|
|
732
|
+
}
|
|
733
|
+
return {
|
|
734
|
+
name: `@feng3d/${name}`,
|
|
735
|
+
version: "0.0.1",
|
|
736
|
+
description: "",
|
|
737
|
+
homepage: `https://feng3d.com/${name}/`,
|
|
738
|
+
author: "feng",
|
|
739
|
+
type: "module",
|
|
740
|
+
main: "./src/index.ts",
|
|
741
|
+
types: "./src/index.ts",
|
|
742
|
+
module: "./src/index.ts",
|
|
743
|
+
exports: {
|
|
744
|
+
".": {
|
|
745
|
+
types: "./src/index.ts",
|
|
746
|
+
import: "./src/index.ts",
|
|
747
|
+
require: "./src/index.ts"
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
scripts,
|
|
751
|
+
repository: {
|
|
752
|
+
type: "git",
|
|
753
|
+
url: `https://github.com/feng3d-labs/${name}.git`
|
|
754
|
+
},
|
|
755
|
+
publishConfig: {
|
|
756
|
+
access: "public"
|
|
757
|
+
},
|
|
758
|
+
files: ["src", "dist", "lib"],
|
|
759
|
+
devDependencies: getDevDependencies({
|
|
760
|
+
includeVitest: options.vitest !== false,
|
|
761
|
+
includeTypedoc: true
|
|
762
|
+
})
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
export {
|
|
766
|
+
DEFAULT_CONFIG,
|
|
767
|
+
DEFAULT_UPDATE_CONFIG,
|
|
768
|
+
VERSIONS,
|
|
769
|
+
createProject,
|
|
770
|
+
detectSchemaPath,
|
|
771
|
+
getCursorrrulesTemplate,
|
|
772
|
+
getDevDependencies,
|
|
773
|
+
getEslintConfigTemplate,
|
|
774
|
+
getFeng3dConfigTemplate,
|
|
775
|
+
getGitignoreTemplate,
|
|
776
|
+
getHuskyPreCommitTemplate,
|
|
777
|
+
getLicenseTemplate,
|
|
778
|
+
getPagesWorkflowTemplate,
|
|
779
|
+
getPostpublishScriptTemplate,
|
|
780
|
+
getPrepublishScriptTemplate,
|
|
781
|
+
getPublishWorkflowTemplate,
|
|
782
|
+
getPullRequestWorkflowTemplate,
|
|
783
|
+
getTestIndexTemplate,
|
|
784
|
+
getTsconfigTemplate,
|
|
785
|
+
getTsconfigTemplateString,
|
|
786
|
+
getTypedocConfig,
|
|
787
|
+
getTypedocConfigTemplate,
|
|
788
|
+
getViteConfigTemplate,
|
|
789
|
+
getVscodeSettingsTemplate,
|
|
790
|
+
ossUploadDir,
|
|
791
|
+
updateProject
|
|
792
|
+
};
|
|
793
|
+
//# sourceMappingURL=index.js.map
|