wlmaker 1.2.11 → 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 +250 -51
- 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,10 +1147,6 @@ 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);
|
|
@@ -1141,6 +1180,16 @@ function injectExport(filePath, exportLine) {
|
|
|
1141
1180
|
lines.sort();
|
|
1142
1181
|
fs8.writeFileSync(filePath, lines.join("\n") + "\n");
|
|
1143
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
|
+
}
|
|
1144
1193
|
|
|
1145
1194
|
// src/core/create-endpoint.ts
|
|
1146
1195
|
async function createEndpoint(options) {
|
|
@@ -1162,7 +1211,6 @@ async function createEndpoint(options) {
|
|
|
1162
1211
|
const methodParamsForSignature = methodParams.map((p) => ({ name: p.name, type: p.type }));
|
|
1163
1212
|
const modelType = `${pascal}Model`;
|
|
1164
1213
|
const entityType = `${pascal}Entity`;
|
|
1165
|
-
const repositoryInterfaceSnake = path8.basename(repositoryInterfaceFile, ".dart");
|
|
1166
1214
|
const spinner2 = (msg) => console.log(chalk4.cyan(` \u2192 ${msg}`));
|
|
1167
1215
|
spinner2("Generating entity");
|
|
1168
1216
|
const entityDir = path8.join(lib, "domain", "entities", feature);
|
|
@@ -1192,15 +1240,13 @@ async function createEndpoint(options) {
|
|
|
1192
1240
|
if (fs9.existsSync(bffPath)) {
|
|
1193
1241
|
const retrofitParams = buildRetrofitParams(options, pathParams, needsBody);
|
|
1194
1242
|
const method = retrofitMethod(
|
|
1195
|
-
|
|
1243
|
+
camelCase2(options.useCaseName),
|
|
1196
1244
|
options.endpointPath,
|
|
1197
1245
|
options.httpMethod,
|
|
1198
1246
|
retrofitParams,
|
|
1199
1247
|
modelType
|
|
1200
1248
|
);
|
|
1201
1249
|
injectMethod(bffPath, extractClassName(bffPath), method);
|
|
1202
|
-
const modelImport = `import 'package:${options.projectName}/data/models/${feature}/${useCaseSnake}_model.dart';`;
|
|
1203
|
-
injectImport(bffPath, modelImport);
|
|
1204
1250
|
} else {
|
|
1205
1251
|
console.log(chalk4.yellow(` \u26A0 BFF API file not found: ${bffPath}`));
|
|
1206
1252
|
}
|
|
@@ -1208,7 +1254,7 @@ async function createEndpoint(options) {
|
|
|
1208
1254
|
const dsPath = path8.resolve(datasourceFile);
|
|
1209
1255
|
if (fs9.existsSync(dsPath)) {
|
|
1210
1256
|
const dsMethod = datasourceMethod(
|
|
1211
|
-
|
|
1257
|
+
camelCase2(options.useCaseName),
|
|
1212
1258
|
modelType,
|
|
1213
1259
|
methodParamsForSignature
|
|
1214
1260
|
);
|
|
@@ -1220,22 +1266,20 @@ async function createEndpoint(options) {
|
|
|
1220
1266
|
const repoIfacePath = path8.resolve(repositoryInterfaceFile);
|
|
1221
1267
|
if (fs9.existsSync(repoIfacePath)) {
|
|
1222
1268
|
const ifaceMethod = repositoryInterfaceMethod(
|
|
1223
|
-
|
|
1269
|
+
camelCase2(options.useCaseName),
|
|
1224
1270
|
entityType,
|
|
1225
1271
|
methodParamsForSignature
|
|
1226
1272
|
);
|
|
1227
1273
|
injectMethod(repoIfacePath, repositoryInterfaceName, ifaceMethod);
|
|
1228
|
-
const entityImport = `import 'package:${options.projectName}/domain/entities/${feature}/${useCaseSnake}_entity.dart';`;
|
|
1229
|
-
injectImport(repoIfacePath, entityImport);
|
|
1230
1274
|
} else {
|
|
1231
1275
|
console.log(chalk4.yellow(` \u26A0 Repository interface not found: ${repoIfacePath}`));
|
|
1232
1276
|
}
|
|
1233
1277
|
spinner2("Injecting repository implementation method");
|
|
1234
1278
|
const repoImplPath = path8.resolve(repositoryImplFile);
|
|
1235
1279
|
if (fs9.existsSync(repoImplPath)) {
|
|
1236
|
-
const dsVarName =
|
|
1280
|
+
const dsVarName = camelCase2(datasourceClassName);
|
|
1237
1281
|
const implMethod = repositoryImplMethod(
|
|
1238
|
-
|
|
1282
|
+
camelCase2(options.useCaseName),
|
|
1239
1283
|
entityType,
|
|
1240
1284
|
modelType,
|
|
1241
1285
|
methodParamsForSignature,
|
|
@@ -1251,15 +1295,20 @@ async function createEndpoint(options) {
|
|
|
1251
1295
|
fs9.writeFileSync(
|
|
1252
1296
|
path8.join(useCaseDir, `${useCaseSnake}_usecase.dart`),
|
|
1253
1297
|
useCaseTemplate2(
|
|
1254
|
-
useCaseSnake,
|
|
1255
1298
|
useCasePascal,
|
|
1256
|
-
|
|
1299
|
+
camelCase2(options.useCaseName),
|
|
1257
1300
|
methodParamsForSignature,
|
|
1258
1301
|
entityType,
|
|
1259
|
-
|
|
1302
|
+
repositoryInterfaceName,
|
|
1303
|
+
options.projectName
|
|
1260
1304
|
)
|
|
1261
1305
|
);
|
|
1262
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
|
+
);
|
|
1263
1312
|
const entityBarrel = path8.join(lib, "domain", "entities", feature, `${feature}.dart`);
|
|
1264
1313
|
injectExport(entityBarrel, `export '${useCaseSnake}_entity.dart';`);
|
|
1265
1314
|
injectExport(
|
|
@@ -1281,6 +1330,44 @@ async function createEndpoint(options) {
|
|
|
1281
1330
|
path8.join(lib, "domain", "usecases", "usecases.dart"),
|
|
1282
1331
|
`export '${feature}/${feature}.dart';`
|
|
1283
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
|
+
}
|
|
1284
1371
|
console.log(chalk4.green(`
|
|
1285
1372
|
\u2713 Endpoint "${options.useCaseName}" generated successfully.`));
|
|
1286
1373
|
}
|
|
@@ -1324,6 +1411,58 @@ function extractClassName(filePath) {
|
|
|
1324
1411
|
if (!match) throw new Error(`No class found in ${filePath}`);
|
|
1325
1412
|
return match[1];
|
|
1326
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
|
+
}
|
|
1327
1466
|
|
|
1328
1467
|
// src/interactive.ts
|
|
1329
1468
|
var SNAKE_CASE_REGEX4 = /^[a-z][a-z0-9_]*$/;
|
|
@@ -1546,8 +1685,8 @@ async function widgetFlow() {
|
|
|
1546
1685
|
clack.outro(chalk5.red(`Error: ${error}`));
|
|
1547
1686
|
}
|
|
1548
1687
|
}
|
|
1549
|
-
async function useCaseFlow(
|
|
1550
|
-
const ds = detectDesignSystem(
|
|
1688
|
+
async function useCaseFlow() {
|
|
1689
|
+
const ds = detectDesignSystem(process.cwd());
|
|
1551
1690
|
if (!ds) {
|
|
1552
1691
|
clack.outro(
|
|
1553
1692
|
chalk5.red(
|
|
@@ -1603,7 +1742,7 @@ async function useCaseFlow(project) {
|
|
|
1603
1742
|
genSpinner.start("Generating use-case file...");
|
|
1604
1743
|
try {
|
|
1605
1744
|
await createUseCase(name, tier, {
|
|
1606
|
-
projectRoot:
|
|
1745
|
+
projectRoot: process.cwd(),
|
|
1607
1746
|
buildRunner: runBuildRunner2
|
|
1608
1747
|
});
|
|
1609
1748
|
genSpinner.stop("Use-case generated");
|
|
@@ -1630,7 +1769,7 @@ function findBffFiles(dir) {
|
|
|
1630
1769
|
function inferBffFile(bffFiles, endpointPath) {
|
|
1631
1770
|
const firstSegment = endpointPath.replace(/^\//, "").split("/")[0].toLowerCase();
|
|
1632
1771
|
if (!firstSegment) return null;
|
|
1633
|
-
const withDomains = bffFiles.map((f) => {
|
|
1772
|
+
const withDomains = bffFiles.filter((f) => /^bff_.+_api\.dart$/.test(path9.basename(f))).map((f) => {
|
|
1634
1773
|
const base = path9.basename(f, ".dart");
|
|
1635
1774
|
const domain = base.replace(/^bff_/, "").replace(/_api$/, "");
|
|
1636
1775
|
return { file: f, domain };
|
|
@@ -1655,14 +1794,29 @@ async function resolveEndpointProject() {
|
|
|
1655
1794
|
s.start("Finding BFF package...");
|
|
1656
1795
|
const monorepoRoot = findMonorepoRoot(process.cwd());
|
|
1657
1796
|
if (monorepoRoot) {
|
|
1658
|
-
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1797
|
+
s.message(`Monorepo found at ${monorepoRoot}`);
|
|
1798
|
+
const packageBases = ["packages", "packages/features"];
|
|
1799
|
+
for (const base of packageBases) {
|
|
1800
|
+
const baseDir = path9.join(monorepoRoot, base);
|
|
1801
|
+
if (!fs10.existsSync(baseDir)) continue;
|
|
1802
|
+
const entries = fs10.readdirSync(baseDir, { withFileTypes: true });
|
|
1803
|
+
for (const entry of entries) {
|
|
1804
|
+
if (!entry.isDirectory()) continue;
|
|
1805
|
+
const candidate = path9.join(baseDir, entry.name);
|
|
1806
|
+
if (!fs10.existsSync(path9.join(candidate, "pubspec.yaml"))) continue;
|
|
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;
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1665
1817
|
}
|
|
1818
|
+
} else {
|
|
1819
|
+
s.message("No monorepo root found");
|
|
1666
1820
|
}
|
|
1667
1821
|
const cwdProject = analyzeProject(process.cwd());
|
|
1668
1822
|
if (cwdProject && fs10.existsSync(path9.join(cwdProject.projectRoot, "lib", "data", "api", "bff"))) {
|
|
@@ -1670,8 +1824,29 @@ async function resolveEndpointProject() {
|
|
|
1670
1824
|
return cwdProject;
|
|
1671
1825
|
}
|
|
1672
1826
|
s.stop("No BFF package found");
|
|
1673
|
-
|
|
1674
|
-
|
|
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;
|
|
1675
1850
|
}
|
|
1676
1851
|
async function endpointFlow() {
|
|
1677
1852
|
const project = await resolveEndpointProject();
|
|
@@ -1741,6 +1916,31 @@ async function endpointFlow() {
|
|
|
1741
1916
|
clack.cancel("Cancelled");
|
|
1742
1917
|
return;
|
|
1743
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
|
+
}
|
|
1744
1944
|
const genSpinner = clack.spinner();
|
|
1745
1945
|
genSpinner.start("Generating endpoint stack...");
|
|
1746
1946
|
try {
|
|
@@ -1750,7 +1950,9 @@ async function endpointFlow() {
|
|
|
1750
1950
|
httpMethod,
|
|
1751
1951
|
endpointPath,
|
|
1752
1952
|
bffApiFile,
|
|
1753
|
-
useCaseName
|
|
1953
|
+
useCaseName,
|
|
1954
|
+
diTarget,
|
|
1955
|
+
diLazySingleton
|
|
1754
1956
|
});
|
|
1755
1957
|
genSpinner.stop("Endpoint generated");
|
|
1756
1958
|
clack.outro(chalk5.green("Done!"));
|
|
@@ -1793,12 +1995,9 @@ async function interactiveMode() {
|
|
|
1793
1995
|
case "widget":
|
|
1794
1996
|
await widgetFlow();
|
|
1795
1997
|
break;
|
|
1796
|
-
case "usecase":
|
|
1797
|
-
|
|
1798
|
-
if (!project) return;
|
|
1799
|
-
await useCaseFlow(project);
|
|
1998
|
+
case "usecase":
|
|
1999
|
+
await useCaseFlow();
|
|
1800
2000
|
break;
|
|
1801
|
-
}
|
|
1802
2001
|
case "endpoint":
|
|
1803
2002
|
await endpointFlow();
|
|
1804
2003
|
break;
|