@lark-apaas/fullstack-cli 1.1.6-alpha.8 → 1.1.6-alpha.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.6-alpha.8",
3
+ "version": "1.1.6-alpha.9",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,9 @@
12
12
  "bin"
13
13
  ],
14
14
  "scripts": {
15
- "build": "tsc",
15
+ "build": "tsup",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
16
18
  "prepublishOnly": "npm run build"
17
19
  },
18
20
  "keywords": [
@@ -30,13 +32,20 @@
30
32
  },
31
33
  "dependencies": {
32
34
  "@lark-apaas/devtool-kits": "^1.2.10",
35
+ "@lark-apaas/http-client": "0.1.2",
33
36
  "@vercel/nft": "^0.30.3",
34
- "cac": "^6.7.14",
37
+ "commander": "^13.0.0",
35
38
  "dotenv": "^16.0.0",
36
- "drizzle-kit": "0.31.5"
39
+ "drizzle-kit": "0.31.5",
40
+ "zod-to-json-schema": "^3.24.1"
37
41
  },
38
42
  "devDependencies": {
39
43
  "@types/node": "^22.0.0",
44
+ "tsup": "^8.3.5",
45
+ "typescript": "^5.9.2",
46
+ "vitest": "^2.1.8"
47
+ },
48
+ "peerDependencies": {
40
49
  "typescript": "^5.9.2"
41
50
  }
42
51
  }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/nest-cli",
3
+ "collection": "@nestjs/schematics",
4
+ "sourceRoot": "server",
5
+ "compilerOptions": {
6
+ "deleteOutDir": true,
7
+ "tsConfigPath": "tsconfig.node.json",
8
+ "assets": [
9
+ {
10
+ "include": "capabilities/**/*.json",
11
+ "outDir": "dist/server",
12
+ "watchAssets": true
13
+ }
14
+ ],
15
+ "plugins": [
16
+ {
17
+ "name": "@nestjs/swagger",
18
+ "options": {
19
+ "introspectComments": true,
20
+ "classValidatorShim": true
21
+ }
22
+ }
23
+ ]
24
+ }
25
+ }
@@ -19,21 +19,28 @@ print_time() {
19
19
  }
20
20
 
21
21
  # ==================== 步骤 0 ====================
22
- echo "📝 [0/4] 更新 openapi 代码"
22
+ echo "🗑️ [0/5] 安装插件"
23
23
  STEP_START=$(node -e "console.log(Date.now())")
24
- npm run gen:openapi
24
+ npx fullstack-cli action-plugin init
25
25
  print_time $STEP_START
26
26
  echo ""
27
27
 
28
28
  # ==================== 步骤 1 ====================
29
- echo "🗑️ [1/4] 清理 dist 目录"
29
+ echo "📝 [1/5] 更新 openapi 代码"
30
30
  STEP_START=$(node -e "console.log(Date.now())")
31
- rm -rf "$ROOT_DIR/dist"
31
+ npm run gen:openapi
32
32
  print_time $STEP_START
33
33
  echo ""
34
34
 
35
35
  # ==================== 步骤 2 ====================
36
- echo "🔨 [2/4] 并行构建 server 和 client"
36
+ echo "🗑️ [2/5] 清理 dist 目录"
37
+ STEP_START=$(node -e "console.log(Date.now())")
38
+ rm -rf "$ROOT_DIR/dist"
39
+ print_time $STEP_START
40
+ echo ""
41
+
42
+ # ==================== 步骤 3 ====================
43
+ echo "🔨 [3/5] 并行构建 server 和 client"
37
44
  STEP_START=$(node -e "console.log(Date.now())")
38
45
 
39
46
  # 并行构建
@@ -70,8 +77,8 @@ echo " ✅ Client 构建完成"
70
77
  print_time $STEP_START
71
78
  echo ""
72
79
 
73
- # ==================== 步骤 3 ====================
74
- echo "📦 [3/4] 准备 server 依赖产物"
80
+ # ==================== 步骤 4 ====================
81
+ echo "📦 [4/5] 准备 server 依赖产物"
75
82
  STEP_START=$(node -e "console.log(Date.now())")
76
83
 
77
84
  mkdir -p "$OUT_DIR/dist/client"
@@ -89,8 +96,8 @@ rm -rf "$ROOT_DIR/dist/tsconfig.node.tsbuildinfo"
89
96
  print_time $STEP_START
90
97
  echo ""
91
98
 
92
- # ==================== 步骤 4 ====================
93
- echo "✂️ [4/4] 智能依赖裁剪"
99
+ # ==================== 步骤 5 ====================
100
+ echo "✂️ [5/5] 智能依赖裁剪"
94
101
  STEP_START=$(node -e "console.log(Date.now())")
95
102
 
96
103
  # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
@@ -36,6 +36,15 @@ split_logs() {
36
36
  LOG_DIR=${LOG_DIR:-logs}
37
37
  mkdir -p "${LOG_DIR}"
38
38
 
39
+ # Initialize action plugins before starting dev servers (non-blocking)
40
+ echo "🔌 Initializing action plugins..."
41
+ if npx fullstack-cli action-plugin init; then
42
+ echo "✅ Action plugins initialized"
43
+ else
44
+ echo "⚠️ Action plugin initialization failed, continuing anyway..."
45
+ fi
46
+ echo ""
47
+
39
48
  concurrently -p "[{time}] [{name}]" -t "yyyy-MM-dd HH:mm:ss" -n "server,client" -c "blue,green" \
40
49
  "npm run dev:server" \
41
50
  "npm run dev:client" 2>&1 | split_logs "${LOG_DIR}"
@@ -178,9 +178,41 @@ async function smartPrune() {
178
178
  }
179
179
  }
180
180
 
181
- console.log(`📦 实际需要 ${requiredPackages.size} 个 npm 包\n`);
181
+ console.log(`📦 静态分析需要 ${requiredPackages.size} 个 npm 包`);
182
182
 
183
- // 4. 选择性复制包(只复制需要的)
183
+ // 4. 处理 actionPlugins(动态加载的插件,无法被静态分析追踪)
184
+ const originalPackage = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8'));
185
+ const actionPlugins = originalPackage.actionPlugins || {};
186
+ const actionPluginNames = Object.keys(actionPlugins);
187
+
188
+ if (actionPluginNames.length > 0) {
189
+ console.log(`🔌 发现 ${actionPluginNames.length} 个 Action 插件,添加到依赖列表...`);
190
+
191
+ for (const pluginName of actionPluginNames) {
192
+ requiredPackages.add(pluginName);
193
+
194
+ // 检查插件的 peerDependencies,也添加进去
195
+ const pluginPkgPath = path.join(ROOT_NODE_MODULES, pluginName, 'package.json');
196
+ if (fs.existsSync(pluginPkgPath)) {
197
+ try {
198
+ const pluginPkg = JSON.parse(fs.readFileSync(pluginPkgPath, 'utf8'));
199
+ if (pluginPkg.peerDependencies) {
200
+ for (const peerDep of Object.keys(pluginPkg.peerDependencies)) {
201
+ requiredPackages.add(peerDep);
202
+ }
203
+ }
204
+ } catch {
205
+ // 忽略解析错误
206
+ }
207
+ }
208
+ }
209
+
210
+ console.log(` ✅ 插件: ${actionPluginNames.join(', ')}`);
211
+ }
212
+
213
+ console.log(`📦 总共需要 ${requiredPackages.size} 个 npm 包\n`);
214
+
215
+ // 5. 选择性复制包(只复制需要的)
184
216
  console.log('📋 选择性复制 node_modules(仅复制需要的包)...');
185
217
  const copyStart = Date.now();
186
218
 
@@ -192,16 +224,15 @@ async function smartPrune() {
192
224
  console.log(` 成功: ${copiedCount.success} 个包,失败: ${copiedCount.failed} 个`);
193
225
  console.log(` 硬链接: ${fileStats.hardLinks} 个文件,复制: ${fileStats.copies} 个文件\n`);
194
226
 
195
- // 5. 读取原始 package.json 并生成精简版本
196
- const originalPackage = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8'));
197
-
227
+ // 6. 生成精简版 package.json
198
228
  // 优化:直接构建 dependencies,避免多次对象展开
199
229
  const prunedDependencies = {};
200
230
  const allDeps = originalPackage.dependencies || {};
201
231
  const allDevDeps = originalPackage.devDependencies || {};
202
232
 
203
233
  for (const pkg of requiredPackages) {
204
- const version = allDeps[pkg] || allDevDeps[pkg];
234
+ // 优先从 dependencies/devDependencies 获取版本,其次从 actionPlugins 获取
235
+ const version = allDeps[pkg] || allDevDeps[pkg] || actionPlugins[pkg];
205
236
  if (version) {
206
237
  prunedDependencies[pkg] = version;
207
238
  }
@@ -222,11 +253,14 @@ async function smartPrune() {
222
253
 
223
254
  const totalElapsed = Date.now() - totalStartTime;
224
255
 
225
- // 6. 输出统计信息
256
+ // 7. 输出统计信息
226
257
  console.log('='.repeat(60));
227
258
  console.log('📊 智能裁剪统计:');
228
259
  console.log('='.repeat(60));
229
260
  console.log(` 需要的包数量: ${requiredPackages.size}`);
261
+ if (actionPluginNames.length > 0) {
262
+ console.log(` Action 插件: ${actionPluginNames.length} 个`);
263
+ }
230
264
  console.log(` 成功复制: ${copiedCount.success} 个包`);
231
265
  console.log(` 失败: ${copiedCount.failed} 个包`);
232
266
  console.log(` 硬链接文件: ${fileStats.hardLinks} 个`);
@@ -1,20 +0,0 @@
1
- /**
2
- * 生成数据库 schema
3
- *
4
- * 命令行选项:
5
- * - --output <path>: schema 输出路径,默认 'server/database/schema.ts'
6
- * - --schema-filter <schemas>: schema 过滤器,逗号分隔
7
- * - --tables-filter <tables>: 表过滤器,逗号分隔,默认 '*'
8
- *
9
- * 环境变量配置:
10
- * - SUDA_DATABASE_URL: 数据库连接 URL(必需)
11
- * - DB_SCHEMA_OUTPUT: schema 输出路径(命令行选项优先)
12
- * - DRIZZLE_SCHEMA_FILTER: schema 过滤器(命令行选项优先)
13
- * - DRIZZLE_TABLES_FILTER: 表过滤器(命令行选项优先)
14
- */
15
- export declare function run(options?: {
16
- enableNestModuleGenerate?: boolean;
17
- output?: string;
18
- schemaFilter?: string;
19
- tablesFilter?: string;
20
- }): Promise<void>;
@@ -1,115 +0,0 @@
1
- import path from 'node:path';
2
- import fs from 'node:fs';
3
- import { fileURLToPath } from 'node:url';
4
- import { spawnSync } from 'node:child_process';
5
- import { createRequire } from 'node:module';
6
- // 加载 .env 配置
7
- import { config as loadEnv } from 'dotenv';
8
- // 创建 require 函数来加载 CommonJS 模块
9
- const require = createRequire(import.meta.url);
10
- /**
11
- * 生成数据库 schema
12
- *
13
- * 命令行选项:
14
- * - --output <path>: schema 输出路径,默认 'server/database/schema.ts'
15
- * - --schema-filter <schemas>: schema 过滤器,逗号分隔
16
- * - --tables-filter <tables>: 表过滤器,逗号分隔,默认 '*'
17
- *
18
- * 环境变量配置:
19
- * - SUDA_DATABASE_URL: 数据库连接 URL(必需)
20
- * - DB_SCHEMA_OUTPUT: schema 输出路径(命令行选项优先)
21
- * - DRIZZLE_SCHEMA_FILTER: schema 过滤器(命令行选项优先)
22
- * - DRIZZLE_TABLES_FILTER: 表过滤器(命令行选项优先)
23
- */
24
- export async function run(options = {}) {
25
- // 加载用户项目的 .env 文件
26
- let exitCode = 0;
27
- const envPath = path.resolve(process.cwd(), '.env');
28
- if (fs.existsSync(envPath)) {
29
- loadEnv({ path: envPath });
30
- console.log('[gen-db-schema] ✓ Loaded .env file');
31
- }
32
- const databaseUrl = process.env.SUDA_DATABASE_URL;
33
- if (!databaseUrl) {
34
- console.error('[gen-db-schema] Error: SUDA_DATABASE_URL environment variable is required');
35
- process.exit(1);
36
- }
37
- // 命令行选项优先于环境变量
38
- const outputPath = options.output || process.env.DB_SCHEMA_OUTPUT || 'server/database/schema.ts';
39
- const OUT_DIR = path.resolve(process.cwd(), 'server/database/.introspect');
40
- const SCHEMA_FILE = path.resolve(process.cwd(), outputPath);
41
- console.log('[gen-db-schema] Starting...');
42
- // 获取当前文件所在目录(ESM 方式)
43
- const __filename = fileURLToPath(import.meta.url);
44
- const __dirname = path.dirname(__filename);
45
- // 使用 CLI 内部的 drizzle 配置
46
- const cliRoot = path.resolve(__dirname, '../');
47
- const configPath = path.join(cliRoot, 'config', 'drizzle.config.js');
48
- if (!fs.existsSync(configPath)) {
49
- console.error('[gen-db-schema] Error: drizzle config not found in CLI package');
50
- process.exit(1);
51
- }
52
- try {
53
- // 通过环境变量传递绝对路径给配置文件
54
- const env = {
55
- ...process.env,
56
- __DRIZZLE_OUT_DIR__: OUT_DIR,
57
- __DRIZZLE_SCHEMA_PATH__: SCHEMA_FILE,
58
- };
59
- // 执行 drizzle-kit introspect
60
- const args = process.argv.slice(3).filter((arg) => !arg.startsWith('--enable-nest-module-generate'));
61
- const spawnArgs = ['--yes', 'drizzle-kit', 'introspect', '--config', configPath, ...args];
62
- const result = spawnSync('npx', spawnArgs, { stdio: 'inherit', env });
63
- if (result.error) {
64
- console.error('[gen-db-schema] Execution failed:', result.error);
65
- throw result.error;
66
- }
67
- if ((result.status ?? 0) !== 0) {
68
- throw new Error(`drizzle-kit introspect failed with status ${result.status}`);
69
- }
70
- // 复制生成的 schema
71
- const generatedSchema = path.join(OUT_DIR, 'schema.ts');
72
- if (!fs.existsSync(generatedSchema)) {
73
- console.error('[gen-db-schema] schema.ts not generated');
74
- throw new Error('drizzle-kit introspect failed to generate schema.ts');
75
- }
76
- fs.mkdirSync(path.dirname(SCHEMA_FILE), { recursive: true });
77
- fs.copyFileSync(generatedSchema, SCHEMA_FILE);
78
- console.log(`[gen-db-schema] ✓ Copied to ${outputPath}`);
79
- // 后处理 schema(使用 CommonJS require 方式加载)
80
- const { postprocessDrizzleSchema } = require('@lark-apaas/devtool-kits');
81
- const stats = postprocessDrizzleSchema(SCHEMA_FILE);
82
- if (stats?.unmatchedUnknown?.length) {
83
- console.warn('[gen-db-schema] Unmatched custom types detected:', stats.unmatchedUnknown);
84
- }
85
- console.log('[gen-db-schema] ✓ Postprocessed schema');
86
- try {
87
- if (options.enableNestModuleGenerate) {
88
- const { parseAndGenerateNestResourceTemplate } = require('@lark-apaas/devtool-kits');
89
- const tsConfigFilePath = path.resolve(process.cwd(), 'tsconfig.json');
90
- const schemaFilePath = SCHEMA_FILE;
91
- await parseAndGenerateNestResourceTemplate({
92
- tsConfigFilePath,
93
- schemaFilePath,
94
- moduleOutputDir: path.resolve(process.cwd(), 'server/modules'),
95
- });
96
- console.log('[gen-db-schema] ✓ Generate NestJS Module Boilerplate Successfully');
97
- }
98
- }
99
- catch (error) {
100
- console.warn('[gen-db-schema] Generate NestJS Module Boilerplate failed:', error instanceof Error ? error.message : String(error));
101
- }
102
- console.log('[gen-db-schema] ✓ Complete');
103
- }
104
- catch (err) {
105
- console.error('[gen-db-schema] Failed:', err instanceof Error ? err.message : String(err));
106
- exitCode = 1;
107
- }
108
- finally {
109
- // 清理临时文件
110
- if (fs.existsSync(OUT_DIR)) {
111
- fs.rmSync(OUT_DIR, { recursive: true, force: true });
112
- }
113
- process.exit(exitCode);
114
- }
115
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * 同步模板文件到用户项目
3
- */
4
- export declare function run(options: {
5
- disableGenOpenapi?: boolean;
6
- }): Promise<void>;
@@ -1,204 +0,0 @@
1
- import path from 'node:path';
2
- import fs from 'node:fs';
3
- import { fileURLToPath } from 'node:url';
4
- import { genSyncConfig } from '../config/sync.js';
5
- /**
6
- * 同步模板文件到用户项目
7
- */
8
- export async function run(options) {
9
- // 检测是否在用户项目中(通过 INIT_CWD 判断)
10
- const userProjectRoot = process.env.INIT_CWD || process.cwd();
11
- // 获取插件根目录
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = path.dirname(__filename);
14
- const pluginRoot = path.resolve(__dirname, '../..');
15
- // 只有在插件自己的开发目录中才跳过(避免在开发插件时触发 sync)
16
- if (userProjectRoot === pluginRoot) {
17
- console.log('[fullstack-cli] Skip syncing (installing plugin itself)');
18
- process.exit(0);
19
- }
20
- // 检查是否存在 package.json,确保是有效的项目
21
- const userPackageJson = path.join(userProjectRoot, 'package.json');
22
- if (!fs.existsSync(userPackageJson)) {
23
- console.log('[fullstack-cli] Skip syncing (not a valid npm project)');
24
- process.exit(0);
25
- }
26
- try {
27
- console.log('[fullstack-cli] Starting sync...');
28
- // 使用配置
29
- const config = genSyncConfig({
30
- disableGenOpenapi: options.disableGenOpenapi ?? false,
31
- });
32
- if (!config || !config.sync) {
33
- console.warn('[fullstack-cli] No sync configuration found');
34
- process.exit(0);
35
- }
36
- // 执行同步规则
37
- for (const rule of config.sync) {
38
- await syncRule(rule, pluginRoot, userProjectRoot);
39
- }
40
- // 设置权限
41
- if (config.permissions) {
42
- setPermissions(config.permissions, userProjectRoot);
43
- }
44
- console.log('[fullstack-cli] Sync completed successfully ✅');
45
- }
46
- catch (error) {
47
- const message = error instanceof Error ? error.message : String(error);
48
- console.error('[fullstack-cli] Failed to sync:', message);
49
- process.exit(1);
50
- }
51
- }
52
- /**
53
- * 执行单个同步规则
54
- */
55
- async function syncRule(rule, pluginRoot, userProjectRoot) {
56
- // 处理删除操作(只需要 to 路径)
57
- if (rule.type === 'delete-file' || rule.type === 'delete-directory') {
58
- const destPath = path.join(userProjectRoot, rule.to);
59
- if (rule.type === 'delete-file') {
60
- deleteFile(destPath);
61
- }
62
- else {
63
- deleteDirectory(destPath);
64
- }
65
- return;
66
- }
67
- // TypeScript 类型窄化:使用 'from' in rule 确保类型安全
68
- if (!('from' in rule)) {
69
- return;
70
- }
71
- // 处理需要源文件的操作(CopyRule 和 AppendRule)
72
- const srcPath = path.join(pluginRoot, rule.from);
73
- const destPath = path.join(userProjectRoot, rule.to);
74
- if (!fs.existsSync(srcPath)) {
75
- console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
76
- return;
77
- }
78
- switch (rule.type) {
79
- case 'directory':
80
- syncDirectory(srcPath, destPath, rule.overwrite ?? true);
81
- break;
82
- case 'file':
83
- syncFile(srcPath, destPath, rule.overwrite ?? true);
84
- break;
85
- case 'append':
86
- appendToFile(srcPath, destPath);
87
- break;
88
- }
89
- }
90
- /**
91
- * 同步单个文件
92
- */
93
- function syncFile(src, dest, overwrite = true) {
94
- // 确保目标目录存在
95
- const destDir = path.dirname(dest);
96
- if (!fs.existsSync(destDir)) {
97
- fs.mkdirSync(destDir, { recursive: true });
98
- }
99
- // 检查目标文件是否存在
100
- if (fs.existsSync(dest) && !overwrite) {
101
- console.log(`[fullstack-cli] ○ ${path.basename(dest)} (skipped, already exists)`);
102
- return;
103
- }
104
- // 复制文件
105
- fs.copyFileSync(src, dest);
106
- console.log(`[fullstack-cli] ✓ ${path.basename(dest)}`);
107
- }
108
- /**
109
- * 同步整个目录
110
- */
111
- function syncDirectory(src, dest, overwrite = true) {
112
- // 确保目标目录存在
113
- if (!fs.existsSync(dest)) {
114
- fs.mkdirSync(dest, { recursive: true });
115
- }
116
- // 读取源目录所有文件
117
- const files = fs.readdirSync(src);
118
- let count = 0;
119
- files.forEach(file => {
120
- const srcFile = path.join(src, file);
121
- const destFile = path.join(dest, file);
122
- const stats = fs.statSync(srcFile);
123
- if (stats.isDirectory()) {
124
- // 递归处理子目录
125
- syncDirectory(srcFile, destFile, overwrite);
126
- }
127
- else {
128
- // 复制文件
129
- if (overwrite || !fs.existsSync(destFile)) {
130
- fs.copyFileSync(srcFile, destFile);
131
- console.log(`[fullstack-cli] ✓ ${path.relative(dest, destFile)}`);
132
- count++;
133
- }
134
- }
135
- });
136
- if (count > 0) {
137
- console.log(`[fullstack-cli] Synced ${count} files to ${path.basename(dest)}/`);
138
- }
139
- }
140
- /**
141
- * 追加内容到文件
142
- */
143
- function appendToFile(src, dest) {
144
- const content = fs.readFileSync(src, 'utf-8');
145
- // 读取目标文件内容(如果存在)
146
- let existingContent = '';
147
- if (fs.existsSync(dest)) {
148
- existingContent = fs.readFileSync(dest, 'utf-8');
149
- }
150
- // 检查是否已包含相同内容(避免重复追加)
151
- if (existingContent.includes(content.trim())) {
152
- console.log(`[fullstack-cli] ○ ${path.basename(dest)} (already contains content)`);
153
- return;
154
- }
155
- // 追加内容
156
- fs.appendFileSync(dest, content);
157
- console.log(`[fullstack-cli] ✓ ${path.basename(dest)} (appended)`);
158
- }
159
- /**
160
- * 设置文件权限
161
- */
162
- function setPermissions(permissions, projectRoot) {
163
- for (const [pattern, mode] of Object.entries(permissions)) {
164
- // 简单实现:只支持 **/*.sh 这种模式
165
- if (pattern === '**/*.sh') {
166
- const scriptsDir = path.join(projectRoot, 'scripts');
167
- if (fs.existsSync(scriptsDir)) {
168
- const files = fs.readdirSync(scriptsDir);
169
- files.forEach(file => {
170
- if (file.endsWith('.sh')) {
171
- const filePath = path.join(scriptsDir, file);
172
- fs.chmodSync(filePath, mode);
173
- }
174
- });
175
- }
176
- }
177
- }
178
- }
179
- /**
180
- * 删除单个文件
181
- * @param filePath 要删除的文件路径
182
- */
183
- function deleteFile(filePath) {
184
- if (fs.existsSync(filePath)) {
185
- fs.unlinkSync(filePath);
186
- console.log(`[fullstack-cli] ✓ ${path.basename(filePath)} (deleted)`);
187
- }
188
- else {
189
- console.log(`[fullstack-cli] ○ ${path.basename(filePath)} (not found)`);
190
- }
191
- }
192
- /**
193
- * 删除整个目录
194
- * @param dirPath 要删除的目录路径
195
- */
196
- function deleteDirectory(dirPath) {
197
- if (fs.existsSync(dirPath)) {
198
- fs.rmSync(dirPath, { recursive: true });
199
- console.log(`[fullstack-cli] ✓ ${path.basename(dirPath)} (deleted)`);
200
- }
201
- else {
202
- console.log(`[fullstack-cli] ○ ${path.basename(dirPath)} (not found)`);
203
- }
204
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * fullstack-cli 派生配置
3
- * 定义哪些文件/目录需要同步到用户项目
4
- */
5
- /** 复制目录或文件规则 */
6
- type CopyRule = {
7
- /** 源文件/目录路径(相对于插件根目录) */
8
- from: string;
9
- /** 目标文件/目录路径(相对于用户项目根目录) */
10
- to: string;
11
- /** 同步类型 */
12
- type: 'directory' | 'file';
13
- /** 是否覆盖已存在的文件 */
14
- overwrite?: boolean;
15
- };
16
- /** 追加内容规则 */
17
- type AppendRule = {
18
- /** 源文件路径(相对于插件根目录) */
19
- from: string;
20
- /** 目标文件路径(相对于用户项目根目录) */
21
- to: string;
22
- /** 同步类型 */
23
- type: 'append';
24
- };
25
- /** 删除文件或目录规则 */
26
- type DeleteRule = {
27
- /** 目标文件/目录路径(相对于用户项目根目录) */
28
- to: string;
29
- /** 同步类型 */
30
- type: 'delete-file' | 'delete-directory';
31
- };
32
- /** 同步规则联合类型 */
33
- export type SyncRule = CopyRule | AppendRule | DeleteRule;
34
- export interface SyncConfig {
35
- /** 派生规则 */
36
- sync: SyncRule[];
37
- /** 文件权限设置 */
38
- permissions?: Record<string, number>;
39
- }
40
- export declare function genSyncConfig(perms?: {
41
- disableGenOpenapi?: boolean;
42
- }): SyncConfig;
43
- export {};
@@ -1,48 +0,0 @@
1
- /**
2
- * fullstack-cli 派生配置
3
- * 定义哪些文件/目录需要同步到用户项目
4
- */
5
- const syncConfig = {
6
- // 派生规则
7
- sync: [
8
- // 1. 派生 scripts 目录(总是覆盖)
9
- {
10
- from: 'templates/scripts',
11
- to: 'scripts',
12
- type: 'directory',
13
- overwrite: true,
14
- },
15
- // // 2. 追加内容到 .gitignore
16
- // {
17
- // from: 'templates/.gitignore.append',
18
- // to: '.gitignore',
19
- // type: 'append',
20
- // },
21
- // 3. 派生 server/type.ts 文件(总是覆盖)
22
- // {
23
- // from: 'templates/server/global.d.ts',
24
- // to: 'server/types/global.d.ts',
25
- // type: 'file',
26
- // },
27
- {
28
- type: 'delete-directory',
29
- to: '.swc', // 删除 .swc 目录(如果存在)
30
- },
31
- ],
32
- // 文件权限设置
33
- permissions: {
34
- // 所有 .sh 文件设置为可执行
35
- // '**/*.sh': 0o755,
36
- },
37
- };
38
- export function genSyncConfig(perms = {}) {
39
- if (!perms.disableGenOpenapi) {
40
- syncConfig.sync.push({
41
- from: 'templates/helper/gen-openapi.ts',
42
- to: 'scripts/gen-openapi.ts',
43
- type: 'file',
44
- overwrite: true,
45
- });
46
- }
47
- return syncConfig;
48
- }