flu-cli-core 1.0.0 → 1.0.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/README.md +6 -0
- package/dist/index.cjs +8 -9
- package/dist/index.js +8 -9
- package/package.json +2 -2
- package/templates/snippets/flu-cli.code-snippets +52 -0
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
从 V6.0 开始,核心生成器由传统的命令式逻辑转变为 **原子化任务流水线** 架构。
|
|
8
8
|
|
|
9
9
|
### 1. 乐高式搭建 (The Lego Model)
|
|
10
|
+
|
|
10
11
|
`ProjectGenerator` 不再直接操作文件,而是作为一个 **Orchestrator (指挥官)**。它通过 `ProjectPipeline` 编排一系列 `IProjectTask`。
|
|
11
12
|
|
|
12
13
|
```mermaid
|
|
@@ -22,6 +23,7 @@ graph LR
|
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
### 2. 骨架 + 增强 (Skeleton + Enrichment)
|
|
26
|
+
|
|
25
27
|
- **Skeleton (骨架)**: 从 Git 或本地加载的纯净 Flutter 代码模板。
|
|
26
28
|
- **Enrichment (增强)**: CLI 通过任务流水线动态注入的功能层(如:`NetworkEnrichTask` 注入 Dio 封装,`StateManagerEnrichTask` 注入状态管理适配器)。
|
|
27
29
|
|
|
@@ -35,10 +37,13 @@ graph LR
|
|
|
35
37
|
## 🚀 核心组件
|
|
36
38
|
|
|
37
39
|
### 生成器 (Generators)
|
|
40
|
+
|
|
38
41
|
- **ProjectGenerator**: 采用 Pipeline 模式的项目实例化引擎。
|
|
39
42
|
- **Page/ViewModel/Model Generator**: 针对不同架构模板的高级代码生成器。
|
|
43
|
+
- **Service Generator**: 智能服务层生成器,支持自动网络层检测与 Mock 降级。
|
|
40
44
|
|
|
41
45
|
### 任务体系 (Tasks)
|
|
46
|
+
|
|
42
47
|
- `FlutterInitTask`: 确保原生 Flutter 环境就绪。
|
|
43
48
|
- `TemplateCopyTask`: 智能处理模板复制与冗余清理。
|
|
44
49
|
- `NetworkEnrichTask`: 声明式注入网络层基础设施。
|
|
@@ -48,6 +53,7 @@ graph LR
|
|
|
48
53
|
## 🛠 开发与扩展
|
|
49
54
|
|
|
50
55
|
### 如何添加一个新任务?
|
|
56
|
+
|
|
51
57
|
1. 在 `src/generators/tasks/` 创建实现 `IProjectTask` 的类。
|
|
52
58
|
2. 在 `ProjectGenerator.generate` 中通过 `.addTask()` 链式调用。
|
|
53
59
|
|
package/dist/index.cjs
CHANGED
|
@@ -1545,6 +1545,8 @@ function getTemplatesRootDir() {
|
|
|
1545
1545
|
searchDirs.push((0, import_path6.join)(temp, "packages", "core", "templates"));
|
|
1546
1546
|
searchDirs.push((0, import_path6.join)(temp, "templates"));
|
|
1547
1547
|
searchDirs.push((0, import_path6.join)(temp, "..", "templates"));
|
|
1548
|
+
searchDirs.push((0, import_path6.join)(temp, "dist", "templates"));
|
|
1549
|
+
searchDirs.push((0, import_path6.join)(temp, "..", "dist", "templates"));
|
|
1548
1550
|
temp = (0, import_path6.dirname)(temp);
|
|
1549
1551
|
if (temp === (0, import_path6.dirname)(temp)) break;
|
|
1550
1552
|
}
|
|
@@ -2015,19 +2017,16 @@ class ${namePascal} extends StatelessWidget {
|
|
|
2015
2017
|
}
|
|
2016
2018
|
function getSimpleModel(namePascal) {
|
|
2017
2019
|
return `class ${namePascal} {
|
|
2018
|
-
// TODO: Add properties
|
|
2019
2020
|
|
|
2020
2021
|
${namePascal}();
|
|
2021
2022
|
|
|
2022
2023
|
factory ${namePascal}.fromJson(Map<String, dynamic> json) {
|
|
2023
2024
|
return ${namePascal}(
|
|
2024
|
-
// TODO: Map json to properties
|
|
2025
2025
|
);
|
|
2026
2026
|
}
|
|
2027
2027
|
|
|
2028
2028
|
Map<String, dynamic> toJson() {
|
|
2029
2029
|
return {
|
|
2030
|
-
// TODO: Map properties to json
|
|
2031
2030
|
};
|
|
2032
2031
|
}
|
|
2033
2032
|
}
|
|
@@ -2830,7 +2829,8 @@ async function generateService(name, options = {}, customLogger) {
|
|
|
2830
2829
|
}
|
|
2831
2830
|
const templateType = selectTemplate(outputDir, serviceConfig);
|
|
2832
2831
|
let content = null;
|
|
2833
|
-
const
|
|
2832
|
+
const defaultSnippetKey = templateType === "network" ? "flu.service.network" : "flu.service";
|
|
2833
|
+
const snippetKey = serviceConfig?.snippetKey || defaultSnippetKey;
|
|
2834
2834
|
content = getSnippetContent(outputDir, snippetKey, {
|
|
2835
2835
|
Name: namePascal,
|
|
2836
2836
|
snake_name: nameSnake,
|
|
@@ -2892,6 +2892,7 @@ class ${namePascal}Service {
|
|
|
2892
2892
|
int page = 1,
|
|
2893
2893
|
int pageSize = 10,
|
|
2894
2894
|
}) async {
|
|
2895
|
+
// \u964D\u7EA7\u4E0E Mock \u5904\u7406
|
|
2895
2896
|
if (AppConfig.I.useMockData) {
|
|
2896
2897
|
return _loadMockData(page, pageSize);
|
|
2897
2898
|
}
|
|
@@ -2901,28 +2902,26 @@ class ${namePascal}Service {
|
|
|
2901
2902
|
queryParameters: {'page': page, 'pageSize': pageSize},
|
|
2902
2903
|
);
|
|
2903
2904
|
|
|
2904
|
-
// \
|
|
2905
|
+
// \u6210\u529F\u5904\u7406
|
|
2905
2906
|
if (response.isSuccess && response.data is List) {
|
|
2906
2907
|
return response.data as List;
|
|
2907
2908
|
}
|
|
2908
2909
|
|
|
2910
|
+
// \u5931\u8D25\u56DE\u9000
|
|
2909
2911
|
return _loadMockData(page, pageSize);
|
|
2910
2912
|
}
|
|
2911
2913
|
|
|
2912
2914
|
/// \u6839\u636E ID \u83B7\u53D6\u8BE6\u60C5
|
|
2913
2915
|
Future<dynamic> fetchById(String id) async {
|
|
2914
2916
|
if (AppConfig.I.useMockData) {
|
|
2915
|
-
return null;
|
|
2917
|
+
return null;
|
|
2916
2918
|
}
|
|
2917
2919
|
|
|
2918
2920
|
final response = await _http.get('/${nameSnake}/$id');
|
|
2919
2921
|
return response.isSuccess ? response.data : null;
|
|
2920
2922
|
}
|
|
2921
2923
|
|
|
2922
|
-
/// Mock \u6570\u636E\u52A0\u8F7D
|
|
2923
2924
|
List<dynamic> _loadMockData(int page, int pageSize) {
|
|
2924
|
-
// \u6A21\u62DF\u6570\u636E\u52A0\u8F7D\u903B\u8F91
|
|
2925
|
-
// \u793A\u4F8B: \u8FD4\u56DE\u6D4B\u8BD5\u6570\u636E\u6216\u4ECE\u672C\u5730\u5B58\u50A8\u8BFB\u53D6
|
|
2926
2925
|
return [];
|
|
2927
2926
|
}
|
|
2928
2927
|
}
|
package/dist/index.js
CHANGED
|
@@ -931,6 +931,8 @@ function getTemplatesRootDir() {
|
|
|
931
931
|
searchDirs.push(join6(temp, "packages", "core", "templates"));
|
|
932
932
|
searchDirs.push(join6(temp, "templates"));
|
|
933
933
|
searchDirs.push(join6(temp, "..", "templates"));
|
|
934
|
+
searchDirs.push(join6(temp, "dist", "templates"));
|
|
935
|
+
searchDirs.push(join6(temp, "..", "dist", "templates"));
|
|
934
936
|
temp = dirname(temp);
|
|
935
937
|
if (temp === dirname(temp)) break;
|
|
936
938
|
}
|
|
@@ -1399,19 +1401,16 @@ class ${namePascal} extends StatelessWidget {
|
|
|
1399
1401
|
}
|
|
1400
1402
|
function getSimpleModel(namePascal) {
|
|
1401
1403
|
return `class ${namePascal} {
|
|
1402
|
-
// TODO: Add properties
|
|
1403
1404
|
|
|
1404
1405
|
${namePascal}();
|
|
1405
1406
|
|
|
1406
1407
|
factory ${namePascal}.fromJson(Map<String, dynamic> json) {
|
|
1407
1408
|
return ${namePascal}(
|
|
1408
|
-
// TODO: Map json to properties
|
|
1409
1409
|
);
|
|
1410
1410
|
}
|
|
1411
1411
|
|
|
1412
1412
|
Map<String, dynamic> toJson() {
|
|
1413
1413
|
return {
|
|
1414
|
-
// TODO: Map properties to json
|
|
1415
1414
|
};
|
|
1416
1415
|
}
|
|
1417
1416
|
}
|
|
@@ -2210,7 +2209,8 @@ async function generateService(name, options = {}, customLogger) {
|
|
|
2210
2209
|
}
|
|
2211
2210
|
const templateType = selectTemplate(outputDir, serviceConfig);
|
|
2212
2211
|
let content = null;
|
|
2213
|
-
const
|
|
2212
|
+
const defaultSnippetKey = templateType === "network" ? "flu.service.network" : "flu.service";
|
|
2213
|
+
const snippetKey = serviceConfig?.snippetKey || defaultSnippetKey;
|
|
2214
2214
|
content = getSnippetContent(outputDir, snippetKey, {
|
|
2215
2215
|
Name: namePascal,
|
|
2216
2216
|
snake_name: nameSnake,
|
|
@@ -2272,6 +2272,7 @@ class ${namePascal}Service {
|
|
|
2272
2272
|
int page = 1,
|
|
2273
2273
|
int pageSize = 10,
|
|
2274
2274
|
}) async {
|
|
2275
|
+
// \u964D\u7EA7\u4E0E Mock \u5904\u7406
|
|
2275
2276
|
if (AppConfig.I.useMockData) {
|
|
2276
2277
|
return _loadMockData(page, pageSize);
|
|
2277
2278
|
}
|
|
@@ -2281,28 +2282,26 @@ class ${namePascal}Service {
|
|
|
2281
2282
|
queryParameters: {'page': page, 'pageSize': pageSize},
|
|
2282
2283
|
);
|
|
2283
2284
|
|
|
2284
|
-
// \
|
|
2285
|
+
// \u6210\u529F\u5904\u7406
|
|
2285
2286
|
if (response.isSuccess && response.data is List) {
|
|
2286
2287
|
return response.data as List;
|
|
2287
2288
|
}
|
|
2288
2289
|
|
|
2290
|
+
// \u5931\u8D25\u56DE\u9000
|
|
2289
2291
|
return _loadMockData(page, pageSize);
|
|
2290
2292
|
}
|
|
2291
2293
|
|
|
2292
2294
|
/// \u6839\u636E ID \u83B7\u53D6\u8BE6\u60C5
|
|
2293
2295
|
Future<dynamic> fetchById(String id) async {
|
|
2294
2296
|
if (AppConfig.I.useMockData) {
|
|
2295
|
-
return null;
|
|
2297
|
+
return null;
|
|
2296
2298
|
}
|
|
2297
2299
|
|
|
2298
2300
|
final response = await _http.get('/${nameSnake}/$id');
|
|
2299
2301
|
return response.isSuccess ? response.data : null;
|
|
2300
2302
|
}
|
|
2301
2303
|
|
|
2302
|
-
/// Mock \u6570\u636E\u52A0\u8F7D
|
|
2303
2304
|
List<dynamic> _loadMockData(int page, int pageSize) {
|
|
2304
|
-
// \u6A21\u62DF\u6570\u636E\u52A0\u8F7D\u903B\u8F91
|
|
2305
|
-
// \u793A\u4F8B: \u8FD4\u56DE\u6D4B\u8BD5\u6570\u636E\u6216\u4ECE\u672C\u5730\u5B58\u50A8\u8BFB\u53D6
|
|
2306
2305
|
return [];
|
|
2307
2306
|
}
|
|
2308
2307
|
}
|
package/package.json
CHANGED
|
@@ -245,6 +245,58 @@
|
|
|
245
245
|
""
|
|
246
246
|
]
|
|
247
247
|
},
|
|
248
|
+
"flu.service.network": {
|
|
249
|
+
"prefix": "serviceNetwork",
|
|
250
|
+
"description": "Service (Network Enabled)",
|
|
251
|
+
"body": [
|
|
252
|
+
"import '${relative_core_path}';",
|
|
253
|
+
"",
|
|
254
|
+
"class ${1:Name}Service {",
|
|
255
|
+
" final AppHttp _http;",
|
|
256
|
+
"",
|
|
257
|
+
" ${1:Name}Service({AppHttp? http}) : _http = http ?? AppHttp();",
|
|
258
|
+
"",
|
|
259
|
+
" /// 获取列表数据",
|
|
260
|
+
" Future<List<dynamic>> fetchList({",
|
|
261
|
+
" int page = 1,",
|
|
262
|
+
" int pageSize = 10,",
|
|
263
|
+
" }) async {",
|
|
264
|
+
" // 降级与 Mock 处理",
|
|
265
|
+
" if (AppConfig.I.useMockData) {",
|
|
266
|
+
" return _loadMockData(page, pageSize);",
|
|
267
|
+
" }",
|
|
268
|
+
"",
|
|
269
|
+
" final response = await _http.get(",
|
|
270
|
+
" '/${snake_name}/list',",
|
|
271
|
+
" queryParameters: {'page': page, 'pageSize': pageSize},",
|
|
272
|
+
" );",
|
|
273
|
+
"",
|
|
274
|
+
" // 成功处理",
|
|
275
|
+
" if (response.isSuccess && response.data is List) {",
|
|
276
|
+
" return response.data as List;",
|
|
277
|
+
" }",
|
|
278
|
+
"",
|
|
279
|
+
" // 失败回退",
|
|
280
|
+
" return _loadMockData(page, pageSize);",
|
|
281
|
+
" }",
|
|
282
|
+
"",
|
|
283
|
+
" /// 根据 ID 获取详情",
|
|
284
|
+
" Future<dynamic> fetchById(String id) async {",
|
|
285
|
+
" if (AppConfig.I.useMockData) {",
|
|
286
|
+
" return null;",
|
|
287
|
+
" }",
|
|
288
|
+
"",
|
|
289
|
+
" final response = await _http.get('/${snake_name}/$id');",
|
|
290
|
+
" return response.isSuccess ? response.data : null;",
|
|
291
|
+
" }",
|
|
292
|
+
"",
|
|
293
|
+
" List<dynamic> _loadMockData(int page, int pageSize) {",
|
|
294
|
+
" return [];",
|
|
295
|
+
" }",
|
|
296
|
+
"}",
|
|
297
|
+
""
|
|
298
|
+
]
|
|
299
|
+
},
|
|
248
300
|
"flu.component": {
|
|
249
301
|
"prefix": "component",
|
|
250
302
|
"description": "通用组件",
|