@udraft/core
Version:
uDraft is a language and stack agnostic code-generation tool that simplifies full-stack development by converting a single YAML file into code for rapid development.
308 lines (296 loc) • 13.4 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const Case = __importStar(require("case"));
const path = __importStar(require("path"));
const renderer_1 = require("../entities/renderer");
const package_1 = require("../helpers/package");
const queries_1 = require("../shortcuts/queries");
const attributes_1 = require("../shortcuts/attributes");
const KEYS = {
pubspec: "pubspec",
baseApiClient: "ApiClient",
};
const DEFAULT_API_CLIENT_CODE = `
import 'package:dio/dio.dart';
class ApiClient {
final Dio dio;
ApiClient({required this.dio});
Future<dynamic> request(
String path, {
required String method,
String? contentType,
Map<String, dynamic>? queryParameters,
dynamic data,
}) async {
try {
final response = await dio.request(
path,
options: Options(
method: method,
contentType: contentType,
),
queryParameters: queryParameters,
data: data,
);
return response.data;
} on DioException catch (e) {
throw ApiException(
code: e.response?.statusCode,
message: e.message ?? 'Unknown error',
);
}
}
}
class ApiResponse<T> {
final T? data;
final String? error;
final int? statusCode;
ApiResponse.success(this.data)
: statusCode = 200, error = null;
ApiResponse.error({this.statusCode, String? message})
: data = null, error = message ?? 'Unknown error';
bool get isSuccess => error == null;
}
class ApiException implements Exception {
final int? code;
final String message;
ApiException({this.code, required this.message});
@override
String toString() => message;
}
`.trim();
class DartApiClientRenderer extends renderer_1.URenderer {
constructor(options) {
super("dart@api-client");
this._serviceDir = "lib/apis";
this._baseClientPath = "lib/core/api_client.dart";
if (options === null || options === void 0 ? void 0 : options.serviceDir)
this._serviceDir = options.serviceDir;
if (options === null || options === void 0 ? void 0 : options.baseClientPath)
this._baseClientPath = options.baseClientPath;
this._where = options === null || options === void 0 ? void 0 : options.where;
}
$moduleServiceName(module) {
return `${Case.pascal(module.$name())}Api`;
}
$fileName(module, extension = true) {
return `${Case.snake(module.$name())}_api${extension ? ".dart" : ""}`;
}
resolveFeatureRoute(module, feature) {
const moduleConfig = (0, queries_1.$attr)(module, (0, attributes_1._http)());
const featureConfig = (0, queries_1.$attr)(feature, (0, attributes_1._http)());
return (((moduleConfig === null || moduleConfig === void 0 ? void 0 : moduleConfig.url) || "") +
"/" +
((featureConfig === null || featureConfig === void 0 ? void 0 : featureConfig.url) || "")).replace(/\/{2,}/, "/");
}
getHttpMethod(feature) {
var _a;
return (((_a = (0, queries_1.$attr)(feature, (0, attributes_1._http)())) === null || _a === void 0 ? void 0 : _a.method) || "get").toUpperCase();
}
select() {
return __awaiter(this, void 0, void 0, function* () {
const modules = [];
const features = [];
this.$features((m, f) => !!(0, queries_1.$attr)(f, (0, attributes_1._http)()) && (this._where ? this._where(m, f) : true)).forEach((feature) => {
const mod = (0, queries_1.$attr)(feature, (0, attributes_1._rootModule)());
if (mod && !modules.find((m) => m.$name() == mod.$name()))
modules.push(mod);
if (!features.find((f) => f.$name() == feature.$name()))
features.push(feature);
});
const paths = [
{ key: KEYS.pubspec, path: "pubspec.yaml" },
{
key: KEYS.baseApiClient,
path: this._baseClientPath,
meta: { isBase: true },
},
];
modules.forEach((module) => {
if (module.$features().length > 0) {
paths.push({
key: this.$moduleServiceName(module),
meta: { module: module.$name() },
path: path.join(this._serviceDir, this.$fileName(module)),
});
}
});
return {
paths,
modules,
features,
};
});
}
render() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const output = [
{
key: KEYS.pubspec,
content: (0, package_1.addPubspecDependency)(((_a = this.$content(KEYS.pubspec)) === null || _a === void 0 ? void 0 : _a.content) || "", [{ name: "dio", version: "^5.4.0" }]),
},
];
// Generate base API client if missing
const baseApiClientPath = this.$path(KEYS.baseApiClient);
const baseApiClient = this.$content(KEYS.baseApiClient);
if (!(baseApiClient === null || baseApiClient === void 0 ? void 0 : baseApiClient.content)) {
output.push({
key: KEYS.baseApiClient,
content: DEFAULT_API_CLIENT_CODE,
meta: { isBase: true },
});
}
// Generate module APIs
const modules = this.$selection().modules || [];
for (const module of modules) {
const features = module.$features(this.$selection().features);
if (features.length === 0)
continue;
const serviceName = this.$moduleServiceName(module);
const modulePath = this.$path(serviceName);
const dartClassRenderer = this.$draft().$requireRenderer(this, "dart@classes");
if (!modulePath)
continue;
let imports = `import "${this.$resolveRelativePath(modulePath.path, (baseApiClientPath === null || baseApiClientPath === void 0 ? void 0 : baseApiClientPath.path) + "")}";`;
let importedModels = [];
let methods = [];
const importModel = (model) => {
var _a;
const modelKey = dartClassRenderer.$key(model);
const modelPath = (_a = dartClassRenderer.$path(modelKey)) === null || _a === void 0 ? void 0 : _a.path;
if (importedModels.includes(modelKey))
return;
imports += `\nimport "${this.$resolveRelativePath(modulePath.path, modelPath + "")}";`;
};
features.forEach((feature) => {
const methodName = Case.camel(feature.$name());
const inputModel = feature.$input();
const outputModel = feature.$output();
const httpConfig = (0, queries_1.$attr)(feature, (0, attributes_1._http)());
const contentType = httpConfig === null || httpConfig === void 0 ? void 0 : httpConfig.contentType;
const params = (httpConfig === null || httpConfig === void 0 ? void 0 : httpConfig.params) || {};
const method = this.getHttpMethod(feature);
const route = this.resolveFeatureRoute(module, feature);
// Process route with path parameters
let processedRoute = route.replace(/{([^}]+)}/g, (match, param) => {
const fieldName = params[param];
return inputModel && fieldName
? `\${${Case.camel(inputModel.$name())}.${fieldName}}`
: match;
});
// Build query parameters
const queryParamEntries = ((inputModel === null || inputModel === void 0 ? void 0 : inputModel.$fields()) || [])
.filter((field) => !Object.values(params).some((n) => n == field.$name()))
.map((field) => `'${dartClassRenderer.$fieldName(field)}': ${Case.camel((inputModel === null || inputModel === void 0 ? void 0 : inputModel.$name()) + "")}.${dartClassRenderer.$fieldName(field)}`);
const queryParamsCode = queryParamEntries.length > 0
? `queryParameters: {${queryParamEntries.join(", ")}}`
: "";
// Build data based on content type
// And handle input model
let inputType = "void";
let dataCode = "";
if (inputModel) {
const inputClassName = dartClassRenderer.$className(inputModel);
importModel(inputModel);
inputType = inputClassName;
const inputVar = Case.camel(inputModel.$name());
dataCode = `data: ${inputVar}.toJson(),`;
}
// Handle output model
let outputType = "void";
if (outputModel) {
const outputClassName = dartClassRenderer.$className(outputModel);
importModel(outputModel);
outputType = outputClassName;
}
// Build method parameters
const methodParams = inputModel
? `${inputType} ${Case.camel(inputModel.$name())}`
: "";
const sendQuery = (httpConfig === null || httpConfig === void 0 ? void 0 : httpConfig.noBody) !== undefined
? httpConfig.noBody
: ["GET", "SEARCH", "DELETE"].includes(method);
// Build method implementation
methods.push(`
Future<ApiResponse<${outputType}>> ${methodName}(${methodParams}) async {
try {
${outputModel ? "final response = " : ""}await client.request(
'${processedRoute}',
method: '${method}',${contentType ? `\n contentType: '${contentType}',` : ""}${sendQuery && queryParamsCode ? `\n ${queryParamsCode},` : ""}${!sendQuery ? `\n ${dataCode}` : ""}
);
return ApiResponse.success(${outputModel
? `${dartClassRenderer.$className(outputModel)}.fromJson(response)`
: "null"});
} on ApiException catch (e) {
return ApiResponse.error(
statusCode: e.code,
message: e.message,
);
}
}`);
});
const content = `
${imports}
class ${serviceName} {
final ApiClient client;
${serviceName}({
required this.client,
});
${methods.join("\n")}
}
`.trim();
output.push({
key: serviceName,
content,
meta: modulePath.meta,
});
}
return output;
});
}
}
exports.default = DartApiClientRenderer;
//# sourceMappingURL=dart-api-client-renderer.js.map
;