wlmaker 1.2.12 → 1.2.13
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.mjs +254 -45
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -966,14 +966,20 @@ import chalk5 from "chalk";
|
|
|
966
966
|
import * as fs9 from "fs";
|
|
967
967
|
import * as path8 from "path";
|
|
968
968
|
import chalk4 from "chalk";
|
|
969
|
-
import { pascalCase as pascalCase4, camelCase } from "change-case";
|
|
969
|
+
import { pascalCase as pascalCase4, camelCase as camelCase2 } from "change-case";
|
|
970
970
|
|
|
971
971
|
// src/core/endpoint-templates.ts
|
|
972
|
+
import { camelCase } from "change-case";
|
|
972
973
|
function entityBoilerplate(pascal) {
|
|
973
|
-
return `
|
|
974
|
+
return `import 'package:equatable/equatable.dart';
|
|
975
|
+
|
|
976
|
+
class ${pascal}Entity extends Equatable {
|
|
974
977
|
// TODO: Define fields
|
|
975
978
|
|
|
976
979
|
const ${pascal}Entity();
|
|
980
|
+
|
|
981
|
+
@override
|
|
982
|
+
List<Object?> get props => [];
|
|
977
983
|
}
|
|
978
984
|
`;
|
|
979
985
|
}
|
|
@@ -1019,27 +1025,26 @@ class ${pascal}RequestModel {
|
|
|
1019
1025
|
}
|
|
1020
1026
|
`;
|
|
1021
1027
|
}
|
|
1022
|
-
function useCaseTemplate2(
|
|
1028
|
+
function useCaseTemplate2(pascal, method, params, returnType, repositoryInterface, projectName) {
|
|
1023
1029
|
const hasParams = params.length > 0;
|
|
1024
1030
|
const paramsClass = hasParams ? `
|
|
1025
1031
|
class Params {
|
|
1026
|
-
${params.map((p) => ` final ${p.type} ${p.name};`).join("\n")}
|
|
1027
1032
|
const Params({${params.map((p) => `required this.${p.name}`).join(", ")}});
|
|
1033
|
+
${params.map((p) => ` final ${p.type} ${p.name};`).join("\n")}
|
|
1028
1034
|
}
|
|
1029
1035
|
` : "";
|
|
1030
1036
|
const callParams = hasParams ? "Params params" : "";
|
|
1031
1037
|
const callReturn = `Future<${returnType}>`;
|
|
1032
1038
|
const args = hasParams ? params.map((p) => `params.${p.name}`).join(", ") : "";
|
|
1033
|
-
return `import 'package
|
|
1034
|
-
import '../../repositories/${repositoryInterface}.dart';
|
|
1039
|
+
return `import 'package:${projectName}/core.dart';
|
|
1035
1040
|
|
|
1036
1041
|
class ${pascal}UseCase {
|
|
1037
|
-
final ${repositoryInterface} _repository;
|
|
1038
|
-
|
|
1039
1042
|
${pascal}UseCase(this._repository);
|
|
1043
|
+
|
|
1044
|
+
final ${repositoryInterface} _repository;
|
|
1040
1045
|
${paramsClass}
|
|
1041
1046
|
${callReturn} call(${callParams}) async {
|
|
1042
|
-
return
|
|
1047
|
+
return _repository.${method}(${args});
|
|
1043
1048
|
}
|
|
1044
1049
|
}
|
|
1045
1050
|
`;
|
|
@@ -1066,20 +1071,58 @@ function repositoryInterfaceMethod(methodName, returnType, params) {
|
|
|
1066
1071
|
const paramList = params.map((p) => `${p.type} ${p.name}`).join(", ");
|
|
1067
1072
|
return `Future<${returnType}> ${methodName}(${paramList});`;
|
|
1068
1073
|
}
|
|
1069
|
-
function repositoryImplMethod(methodName, returnType,
|
|
1074
|
+
function repositoryImplMethod(methodName, returnType, _modelType, params, _datasourceName) {
|
|
1070
1075
|
const paramList = params.map((p) => `${p.type} ${p.name}`).join(", ");
|
|
1071
|
-
const args = params.map((p) => p.name).join(", ");
|
|
1072
1076
|
return `@override
|
|
1073
|
-
Future<${returnType}> ${methodName}(${paramList})
|
|
1074
|
-
|
|
1075
|
-
|
|
1077
|
+
Future<${returnType}> ${methodName}(${paramList}) {
|
|
1078
|
+
// TODO: implement ${methodName}
|
|
1079
|
+
throw UnimplementedError();
|
|
1076
1080
|
}`;
|
|
1077
1081
|
}
|
|
1082
|
+
function datasourceModuleRegistration(domainPascal, lazy = true) {
|
|
1083
|
+
const dsClass = `${domainPascal}RestDataSource`;
|
|
1084
|
+
const dsCamel = camelCase(dsClass);
|
|
1085
|
+
const apiClass = `Bff${domainPascal}Api`;
|
|
1086
|
+
const annotation = lazy ? "@lazySingleton\n" : "";
|
|
1087
|
+
return `//============================================================================
|
|
1088
|
+
// ${domainPascal}
|
|
1089
|
+
//============================================================================
|
|
1090
|
+
${annotation}${dsClass} ${dsCamel}(${apiClass} api) =>
|
|
1091
|
+
${dsClass}(api: api);`;
|
|
1092
|
+
}
|
|
1093
|
+
function repositoryModuleRegistration(domainPascal, lazy = true) {
|
|
1094
|
+
const repoInterface = `${domainPascal}Repository`;
|
|
1095
|
+
const repoCamel = camelCase(repoInterface);
|
|
1096
|
+
const repoImpl = `${domainPascal}RepositoryData`;
|
|
1097
|
+
const dsClass = `${domainPascal}RestDataSource`;
|
|
1098
|
+
const annotation = lazy ? "@lazySingleton\n" : "";
|
|
1099
|
+
return `//============================================================================
|
|
1100
|
+
// ${domainPascal}
|
|
1101
|
+
//============================================================================
|
|
1102
|
+
${annotation}${repoInterface} ${repoCamel}(
|
|
1103
|
+
${dsClass} restDataSource,
|
|
1104
|
+
) => ${repoImpl}(restDataSource: restDataSource);`;
|
|
1105
|
+
}
|
|
1106
|
+
function useCaseModuleRegistration(useCasePascal, domainPascal, lazy = true) {
|
|
1107
|
+
const useCaseClass = `${useCasePascal}UseCase`;
|
|
1108
|
+
const useCaseCamel = camelCase(useCaseClass);
|
|
1109
|
+
const repoInterface = `${domainPascal}Repository`;
|
|
1110
|
+
const annotation = lazy ? "@lazySingleton\n" : "";
|
|
1111
|
+
return `//============================================================================
|
|
1112
|
+
// ${domainPascal}
|
|
1113
|
+
//============================================================================
|
|
1114
|
+
${annotation}${useCaseClass} ${useCaseCamel}(${repoInterface} repository) =>
|
|
1115
|
+
${useCaseClass}(repository);`;
|
|
1116
|
+
}
|
|
1078
1117
|
|
|
1079
1118
|
// src/core/dart-injector.ts
|
|
1080
1119
|
import * as fs8 from "fs";
|
|
1081
|
-
function injectMethod(filePath, className, methodCode) {
|
|
1120
|
+
function injectMethod(filePath, className, methodCode, dedupKey) {
|
|
1082
1121
|
const content = fs8.readFileSync(filePath, "utf8");
|
|
1122
|
+
const dedup = dedupKey ?? findSignature(methodCode);
|
|
1123
|
+
if (dedup && content.includes(dedup)) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1083
1126
|
const classRegex = new RegExp(`class\\s+${className}\\s*[^{]*\\{`);
|
|
1084
1127
|
const classMatch = content.match(classRegex);
|
|
1085
1128
|
if (!classMatch) {
|
|
@@ -1104,14 +1147,26 @@ function injectMethod(filePath, className, methodCode) {
|
|
|
1104
1147
|
if (classEnd === -1) {
|
|
1105
1148
|
throw new Error(`Could not find closing brace for class "${className}" in ${filePath}`);
|
|
1106
1149
|
}
|
|
1107
|
-
const methodSignature = methodCode.trim().split("\n")[0].trim();
|
|
1108
|
-
if (content.includes(methodSignature)) {
|
|
1109
|
-
return;
|
|
1110
|
-
}
|
|
1111
1150
|
const indentedMethod = methodCode.split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
|
|
1112
1151
|
const newContent = content.slice(0, classEnd) + "\n" + indentedMethod + "\n" + content.slice(classEnd);
|
|
1113
1152
|
fs8.writeFileSync(filePath, newContent);
|
|
1114
1153
|
}
|
|
1154
|
+
function injectImport(filePath, importLine) {
|
|
1155
|
+
const content = fs8.readFileSync(filePath, "utf8");
|
|
1156
|
+
if (content.includes(importLine.trim())) {
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
const importRegex = /^import\s+[^;]+;/gm;
|
|
1160
|
+
const imports = [...content.matchAll(importRegex)];
|
|
1161
|
+
if (imports.length > 0) {
|
|
1162
|
+
const lastImport = imports[imports.length - 1];
|
|
1163
|
+
const insertPos = lastImport.index + lastImport[0].length;
|
|
1164
|
+
const newContent = content.slice(0, insertPos) + "\n" + importLine + content.slice(insertPos);
|
|
1165
|
+
fs8.writeFileSync(filePath, newContent);
|
|
1166
|
+
} else {
|
|
1167
|
+
fs8.writeFileSync(filePath, importLine + "\n\n" + content);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1115
1170
|
function injectExport(filePath, exportLine) {
|
|
1116
1171
|
let content = "";
|
|
1117
1172
|
if (fs8.existsSync(filePath)) {
|
|
@@ -1125,6 +1180,16 @@ function injectExport(filePath, exportLine) {
|
|
|
1125
1180
|
lines.sort();
|
|
1126
1181
|
fs8.writeFileSync(filePath, lines.join("\n") + "\n");
|
|
1127
1182
|
}
|
|
1183
|
+
function findSignature(methodCode) {
|
|
1184
|
+
const lines = methodCode.trim().split("\n");
|
|
1185
|
+
for (const line of lines) {
|
|
1186
|
+
const stripped = line.trim();
|
|
1187
|
+
if (stripped && !stripped.startsWith("@")) {
|
|
1188
|
+
return stripped;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return null;
|
|
1192
|
+
}
|
|
1128
1193
|
|
|
1129
1194
|
// src/core/create-endpoint.ts
|
|
1130
1195
|
async function createEndpoint(options) {
|
|
@@ -1146,7 +1211,6 @@ async function createEndpoint(options) {
|
|
|
1146
1211
|
const methodParamsForSignature = methodParams.map((p) => ({ name: p.name, type: p.type }));
|
|
1147
1212
|
const modelType = `${pascal}Model`;
|
|
1148
1213
|
const entityType = `${pascal}Entity`;
|
|
1149
|
-
const repositoryInterfaceSnake = path8.basename(repositoryInterfaceFile, ".dart");
|
|
1150
1214
|
const spinner2 = (msg) => console.log(chalk4.cyan(` \u2192 ${msg}`));
|
|
1151
1215
|
spinner2("Generating entity");
|
|
1152
1216
|
const entityDir = path8.join(lib, "domain", "entities", feature);
|
|
@@ -1176,7 +1240,7 @@ async function createEndpoint(options) {
|
|
|
1176
1240
|
if (fs9.existsSync(bffPath)) {
|
|
1177
1241
|
const retrofitParams = buildRetrofitParams(options, pathParams, needsBody);
|
|
1178
1242
|
const method = retrofitMethod(
|
|
1179
|
-
|
|
1243
|
+
camelCase2(options.useCaseName),
|
|
1180
1244
|
options.endpointPath,
|
|
1181
1245
|
options.httpMethod,
|
|
1182
1246
|
retrofitParams,
|
|
@@ -1190,7 +1254,7 @@ async function createEndpoint(options) {
|
|
|
1190
1254
|
const dsPath = path8.resolve(datasourceFile);
|
|
1191
1255
|
if (fs9.existsSync(dsPath)) {
|
|
1192
1256
|
const dsMethod = datasourceMethod(
|
|
1193
|
-
|
|
1257
|
+
camelCase2(options.useCaseName),
|
|
1194
1258
|
modelType,
|
|
1195
1259
|
methodParamsForSignature
|
|
1196
1260
|
);
|
|
@@ -1202,7 +1266,7 @@ async function createEndpoint(options) {
|
|
|
1202
1266
|
const repoIfacePath = path8.resolve(repositoryInterfaceFile);
|
|
1203
1267
|
if (fs9.existsSync(repoIfacePath)) {
|
|
1204
1268
|
const ifaceMethod = repositoryInterfaceMethod(
|
|
1205
|
-
|
|
1269
|
+
camelCase2(options.useCaseName),
|
|
1206
1270
|
entityType,
|
|
1207
1271
|
methodParamsForSignature
|
|
1208
1272
|
);
|
|
@@ -1213,9 +1277,9 @@ async function createEndpoint(options) {
|
|
|
1213
1277
|
spinner2("Injecting repository implementation method");
|
|
1214
1278
|
const repoImplPath = path8.resolve(repositoryImplFile);
|
|
1215
1279
|
if (fs9.existsSync(repoImplPath)) {
|
|
1216
|
-
const dsVarName =
|
|
1280
|
+
const dsVarName = camelCase2(datasourceClassName);
|
|
1217
1281
|
const implMethod = repositoryImplMethod(
|
|
1218
|
-
|
|
1282
|
+
camelCase2(options.useCaseName),
|
|
1219
1283
|
entityType,
|
|
1220
1284
|
modelType,
|
|
1221
1285
|
methodParamsForSignature,
|
|
@@ -1231,15 +1295,20 @@ async function createEndpoint(options) {
|
|
|
1231
1295
|
fs9.writeFileSync(
|
|
1232
1296
|
path8.join(useCaseDir, `${useCaseSnake}_usecase.dart`),
|
|
1233
1297
|
useCaseTemplate2(
|
|
1234
|
-
useCaseSnake,
|
|
1235
1298
|
useCasePascal,
|
|
1236
|
-
|
|
1299
|
+
camelCase2(options.useCaseName),
|
|
1237
1300
|
methodParamsForSignature,
|
|
1238
1301
|
entityType,
|
|
1239
|
-
|
|
1302
|
+
repositoryInterfaceName,
|
|
1303
|
+
options.projectName
|
|
1240
1304
|
)
|
|
1241
1305
|
);
|
|
1242
1306
|
spinner2("Updating barrel files");
|
|
1307
|
+
const dsFileName = path8.basename(datasourceFile);
|
|
1308
|
+
injectExport(
|
|
1309
|
+
path8.join(lib, "data", "datasources", "datasources.dart"),
|
|
1310
|
+
`export '${dsFileName}';`
|
|
1311
|
+
);
|
|
1243
1312
|
const entityBarrel = path8.join(lib, "domain", "entities", feature, `${feature}.dart`);
|
|
1244
1313
|
injectExport(entityBarrel, `export '${useCaseSnake}_entity.dart';`);
|
|
1245
1314
|
injectExport(
|
|
@@ -1261,6 +1330,44 @@ async function createEndpoint(options) {
|
|
|
1261
1330
|
path8.join(lib, "domain", "usecases", "usecases.dart"),
|
|
1262
1331
|
`export '${feature}/${feature}.dart';`
|
|
1263
1332
|
);
|
|
1333
|
+
if (options.diTarget && options.diTarget !== "none") {
|
|
1334
|
+
spinner2("Registering in DI modules");
|
|
1335
|
+
const appBaseDir = findAppBasePackageDir(options.projectRoot, options.diTarget);
|
|
1336
|
+
if (appBaseDir) {
|
|
1337
|
+
const domainPascal = pascalCase4(domain);
|
|
1338
|
+
const lazy = options.diLazySingleton !== false;
|
|
1339
|
+
const dsModuleFile = path8.join(appBaseDir, "datasources_module.dart");
|
|
1340
|
+
const dsRegistration = datasourceModuleRegistration(domainPascal, lazy);
|
|
1341
|
+
injectModuleRegistration(
|
|
1342
|
+
dsModuleFile,
|
|
1343
|
+
"DataSourceModule",
|
|
1344
|
+
dsRegistration,
|
|
1345
|
+
`${domainPascal}RestDataSource`
|
|
1346
|
+
);
|
|
1347
|
+
const repoModuleFile = path8.join(appBaseDir, "repositories_module.dart");
|
|
1348
|
+
const repoRegistration = repositoryModuleRegistration(domainPascal, lazy);
|
|
1349
|
+
injectModuleRegistration(
|
|
1350
|
+
repoModuleFile,
|
|
1351
|
+
"RepositoriesModule",
|
|
1352
|
+
repoRegistration,
|
|
1353
|
+
`${domainPascal}RepositoryData`
|
|
1354
|
+
);
|
|
1355
|
+
const ucModuleFile = path8.join(appBaseDir, "usecases_module.dart");
|
|
1356
|
+
const ucRegistration = useCaseModuleRegistration(useCasePascal, domainPascal, lazy);
|
|
1357
|
+
injectModuleRegistration(
|
|
1358
|
+
ucModuleFile,
|
|
1359
|
+
"UseCasesModule",
|
|
1360
|
+
ucRegistration,
|
|
1361
|
+
`${useCasePascal}UseCase`
|
|
1362
|
+
);
|
|
1363
|
+
const coreImport = `import 'package:${options.projectName}/core.dart';`;
|
|
1364
|
+
injectImport(dsModuleFile, coreImport);
|
|
1365
|
+
injectImport(repoModuleFile, coreImport);
|
|
1366
|
+
injectImport(ucModuleFile, coreImport);
|
|
1367
|
+
} else {
|
|
1368
|
+
console.log(chalk4.yellow(` \u26A0 Package "${options.diTarget}" not found in monorepo`));
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1264
1371
|
console.log(chalk4.green(`
|
|
1265
1372
|
\u2713 Endpoint "${options.useCaseName}" generated successfully.`));
|
|
1266
1373
|
}
|
|
@@ -1304,6 +1411,58 @@ function extractClassName(filePath) {
|
|
|
1304
1411
|
if (!match) throw new Error(`No class found in ${filePath}`);
|
|
1305
1412
|
return match[1];
|
|
1306
1413
|
}
|
|
1414
|
+
function findAppBasePackageDir(projectRoot, packageName) {
|
|
1415
|
+
let dir = path8.resolve(projectRoot);
|
|
1416
|
+
for (let i = 0; i < 10; i++) {
|
|
1417
|
+
const candidate = path8.join(dir, "packages", packageName, "lib", "dependencies");
|
|
1418
|
+
if (fs9.existsSync(candidate)) {
|
|
1419
|
+
return candidate;
|
|
1420
|
+
}
|
|
1421
|
+
const parent = path8.dirname(dir);
|
|
1422
|
+
if (parent === dir) break;
|
|
1423
|
+
dir = parent;
|
|
1424
|
+
}
|
|
1425
|
+
return null;
|
|
1426
|
+
}
|
|
1427
|
+
function injectModuleRegistration(filePath, className, registrationCode, dedupKey) {
|
|
1428
|
+
if (!fs9.existsSync(filePath)) {
|
|
1429
|
+
console.log(chalk4.yellow(` \u26A0 Module file not found: ${filePath}`));
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
1433
|
+
if (content.includes(dedupKey)) {
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
const classRegex = new RegExp(`class\\s+${className}\\s*[^{]*\\{`);
|
|
1437
|
+
const classMatch = content.match(classRegex);
|
|
1438
|
+
if (!classMatch) {
|
|
1439
|
+
console.log(chalk4.yellow(` \u26A0 Class "${className}" not found in ${filePath}`));
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
const classStart = content.indexOf(classMatch[0]);
|
|
1443
|
+
let braceCount = 0;
|
|
1444
|
+
let classEnd = -1;
|
|
1445
|
+
let foundOpen = false;
|
|
1446
|
+
for (let i = classStart; i < content.length; i++) {
|
|
1447
|
+
if (content[i] === "{") {
|
|
1448
|
+
braceCount++;
|
|
1449
|
+
foundOpen = true;
|
|
1450
|
+
} else if (content[i] === "}") {
|
|
1451
|
+
braceCount--;
|
|
1452
|
+
if (foundOpen && braceCount === 0) {
|
|
1453
|
+
classEnd = i;
|
|
1454
|
+
break;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
if (classEnd === -1) {
|
|
1459
|
+
console.log(chalk4.yellow(` \u26A0 Could not find closing brace for "${className}" in ${filePath}`));
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
const indentedCode = registrationCode.split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
|
|
1463
|
+
const newContent = content.slice(0, classEnd) + "\n" + indentedCode + "\n" + content.slice(classEnd);
|
|
1464
|
+
fs9.writeFileSync(filePath, newContent);
|
|
1465
|
+
}
|
|
1307
1466
|
|
|
1308
1467
|
// src/interactive.ts
|
|
1309
1468
|
var SNAKE_CASE_REGEX4 = /^[a-z][a-z0-9_]*$/;
|
|
@@ -1526,8 +1685,8 @@ async function widgetFlow() {
|
|
|
1526
1685
|
clack.outro(chalk5.red(`Error: ${error}`));
|
|
1527
1686
|
}
|
|
1528
1687
|
}
|
|
1529
|
-
async function useCaseFlow(
|
|
1530
|
-
const ds = detectDesignSystem(
|
|
1688
|
+
async function useCaseFlow() {
|
|
1689
|
+
const ds = detectDesignSystem(process.cwd());
|
|
1531
1690
|
if (!ds) {
|
|
1532
1691
|
clack.outro(
|
|
1533
1692
|
chalk5.red(
|
|
@@ -1583,7 +1742,7 @@ async function useCaseFlow(project) {
|
|
|
1583
1742
|
genSpinner.start("Generating use-case file...");
|
|
1584
1743
|
try {
|
|
1585
1744
|
await createUseCase(name, tier, {
|
|
1586
|
-
projectRoot:
|
|
1745
|
+
projectRoot: process.cwd(),
|
|
1587
1746
|
buildRunner: runBuildRunner2
|
|
1588
1747
|
});
|
|
1589
1748
|
genSpinner.stop("Use-case generated");
|
|
@@ -1610,7 +1769,7 @@ function findBffFiles(dir) {
|
|
|
1610
1769
|
function inferBffFile(bffFiles, endpointPath) {
|
|
1611
1770
|
const firstSegment = endpointPath.replace(/^\//, "").split("/")[0].toLowerCase();
|
|
1612
1771
|
if (!firstSegment) return null;
|
|
1613
|
-
const withDomains = bffFiles.map((f) => {
|
|
1772
|
+
const withDomains = bffFiles.filter((f) => /^bff_.+_api\.dart$/.test(path9.basename(f))).map((f) => {
|
|
1614
1773
|
const base = path9.basename(f, ".dart");
|
|
1615
1774
|
const domain = base.replace(/^bff_/, "").replace(/_api$/, "");
|
|
1616
1775
|
return { file: f, domain };
|
|
@@ -1635,6 +1794,7 @@ async function resolveEndpointProject() {
|
|
|
1635
1794
|
s.start("Finding BFF package...");
|
|
1636
1795
|
const monorepoRoot = findMonorepoRoot(process.cwd());
|
|
1637
1796
|
if (monorepoRoot) {
|
|
1797
|
+
s.message(`Monorepo found at ${monorepoRoot}`);
|
|
1638
1798
|
const packageBases = ["packages", "packages/features"];
|
|
1639
1799
|
for (const base of packageBases) {
|
|
1640
1800
|
const baseDir = path9.join(monorepoRoot, base);
|
|
@@ -1644,15 +1804,19 @@ async function resolveEndpointProject() {
|
|
|
1644
1804
|
if (!entry.isDirectory()) continue;
|
|
1645
1805
|
const candidate = path9.join(baseDir, entry.name);
|
|
1646
1806
|
if (!fs10.existsSync(path9.join(candidate, "pubspec.yaml"))) continue;
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1807
|
+
const bffPath = path9.join(candidate, "lib", "data", "api", "bff");
|
|
1808
|
+
s.message(`Checking ${candidate} \u2192 bff exists: ${fs10.existsSync(bffPath)}`);
|
|
1809
|
+
if (fs10.existsSync(bffPath)) {
|
|
1810
|
+
const project2 = analyzeProject(candidate);
|
|
1811
|
+
if (project2) {
|
|
1812
|
+
s.stop(`Using ${chalk5.green(project2.projectName)}`);
|
|
1813
|
+
return project2;
|
|
1652
1814
|
}
|
|
1653
1815
|
}
|
|
1654
1816
|
}
|
|
1655
1817
|
}
|
|
1818
|
+
} else {
|
|
1819
|
+
s.message("No monorepo root found");
|
|
1656
1820
|
}
|
|
1657
1821
|
const cwdProject = analyzeProject(process.cwd());
|
|
1658
1822
|
if (cwdProject && fs10.existsSync(path9.join(cwdProject.projectRoot, "lib", "data", "api", "bff"))) {
|
|
@@ -1660,8 +1824,29 @@ async function resolveEndpointProject() {
|
|
|
1660
1824
|
return cwdProject;
|
|
1661
1825
|
}
|
|
1662
1826
|
s.stop("No BFF package found");
|
|
1663
|
-
|
|
1664
|
-
|
|
1827
|
+
const manualPath = await clack.text({
|
|
1828
|
+
message: "Enter the path to the package (must contain lib/data/api/bff/):",
|
|
1829
|
+
placeholder: "e.g. /path/to/my-package or ./packages/core",
|
|
1830
|
+
validate: (v) => {
|
|
1831
|
+
if (!v.trim()) return "Path is required";
|
|
1832
|
+
const resolved2 = path9.resolve(v.trim());
|
|
1833
|
+
if (!fs10.existsSync(resolved2)) return "Path does not exist";
|
|
1834
|
+
if (!fs10.existsSync(path9.join(resolved2, "pubspec.yaml"))) return "No pubspec.yaml found at this path";
|
|
1835
|
+
if (!fs10.existsSync(path9.join(resolved2, "lib", "data", "api", "bff"))) return "No lib/data/api/bff/ found at this path";
|
|
1836
|
+
}
|
|
1837
|
+
});
|
|
1838
|
+
if (clack.isCancel(manualPath)) {
|
|
1839
|
+
clack.cancel("Cancelled");
|
|
1840
|
+
return null;
|
|
1841
|
+
}
|
|
1842
|
+
const resolved = path9.resolve(manualPath);
|
|
1843
|
+
const project = analyzeProject(resolved);
|
|
1844
|
+
if (!project) {
|
|
1845
|
+
clack.outro(chalk5.red(`Could not analyze project at ${resolved}`));
|
|
1846
|
+
return null;
|
|
1847
|
+
}
|
|
1848
|
+
clack.log.info(`Using ${chalk5.green(project.projectName)}`);
|
|
1849
|
+
return project;
|
|
1665
1850
|
}
|
|
1666
1851
|
async function endpointFlow() {
|
|
1667
1852
|
const project = await resolveEndpointProject();
|
|
@@ -1731,6 +1916,31 @@ async function endpointFlow() {
|
|
|
1731
1916
|
clack.cancel("Cancelled");
|
|
1732
1917
|
return;
|
|
1733
1918
|
}
|
|
1919
|
+
const diTarget = await clack.select({
|
|
1920
|
+
message: "Where to register DI modules?",
|
|
1921
|
+
options: [
|
|
1922
|
+
{ value: "app_base", label: "app_base" },
|
|
1923
|
+
{ value: "app_base_loyalty", label: "app_base_loyalty" },
|
|
1924
|
+
{ value: "none", label: "Skip (no DI registration)" }
|
|
1925
|
+
],
|
|
1926
|
+
initialValue: "app_base"
|
|
1927
|
+
});
|
|
1928
|
+
if (clack.isCancel(diTarget)) {
|
|
1929
|
+
clack.cancel("Cancelled");
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
let diLazySingleton = true;
|
|
1933
|
+
if (diTarget !== "none") {
|
|
1934
|
+
const lazyAnswer = await clack.confirm({
|
|
1935
|
+
message: "Use @lazySingleton annotation?",
|
|
1936
|
+
initialValue: true
|
|
1937
|
+
});
|
|
1938
|
+
if (clack.isCancel(lazyAnswer)) {
|
|
1939
|
+
clack.cancel("Cancelled");
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
diLazySingleton = lazyAnswer;
|
|
1943
|
+
}
|
|
1734
1944
|
const genSpinner = clack.spinner();
|
|
1735
1945
|
genSpinner.start("Generating endpoint stack...");
|
|
1736
1946
|
try {
|
|
@@ -1740,7 +1950,9 @@ async function endpointFlow() {
|
|
|
1740
1950
|
httpMethod,
|
|
1741
1951
|
endpointPath,
|
|
1742
1952
|
bffApiFile,
|
|
1743
|
-
useCaseName
|
|
1953
|
+
useCaseName,
|
|
1954
|
+
diTarget,
|
|
1955
|
+
diLazySingleton
|
|
1744
1956
|
});
|
|
1745
1957
|
genSpinner.stop("Endpoint generated");
|
|
1746
1958
|
clack.outro(chalk5.green("Done!"));
|
|
@@ -1783,12 +1995,9 @@ async function interactiveMode() {
|
|
|
1783
1995
|
case "widget":
|
|
1784
1996
|
await widgetFlow();
|
|
1785
1997
|
break;
|
|
1786
|
-
case "usecase":
|
|
1787
|
-
|
|
1788
|
-
if (!project) return;
|
|
1789
|
-
await useCaseFlow(project);
|
|
1998
|
+
case "usecase":
|
|
1999
|
+
await useCaseFlow();
|
|
1790
2000
|
break;
|
|
1791
|
-
}
|
|
1792
2001
|
case "endpoint":
|
|
1793
2002
|
await endpointFlow();
|
|
1794
2003
|
break;
|