@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.
251 lines • 13.3 kB
JavaScript
"use strict";
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 queries_1 = require("../shortcuts/queries");
const rendering_1 = require("../utils/rendering");
const attributes_1 = require("../shortcuts/attributes");
class TSClassRenderer extends renderer_1.URenderer {
constructor(options) {
super("ts@classes");
this._entityDir = "src/entities";
this._dtoDir = "src/dtos";
this._enumDir = "src/types";
this._includeModuleInDir = true;
if (options === null || options === void 0 ? void 0 : options.modelDir)
this._entityDir = options.modelDir;
if (options === null || options === void 0 ? void 0 : options.dtoDir)
this._dtoDir = options.dtoDir;
if (options === null || options === void 0 ? void 0 : options.includeModuleInDir)
this._includeModuleInDir = options.includeModuleInDir;
if (options === null || options === void 0 ? void 0 : options.where)
this._where = options.where;
}
$isDto(model) {
var _a;
const output = this.$output(model.$name());
if (output)
return !!((_a = output.meta) === null || _a === void 0 ? void 0 : _a.isDto);
return null;
}
$resolveImport(from, model) {
const modelPath = this.$path(this.$className(model));
if (!(modelPath === null || modelPath === void 0 ? void 0 : modelPath.path))
return "";
const importPath = this.$resolveRelativePath(from, modelPath.path);
return `import { ${this.$className(model)} } from '${importPath}';\n`;
}
$key(model) {
return this.$className(model);
}
$keys(models) {
return models.map((model) => this.$key(model));
}
$paths(models) {
let paths = super.$paths();
if (models)
paths = paths.filter((p) => models.some((m) => p.key === this.$key(m)));
return paths;
}
$className(model) {
return Case.pascal(model.$name());
}
$fileName(model, extension = true) {
return `${Case.kebab(model.$name())}${extension ? ".ts" : ""}`;
}
$fieldName(field) {
let nameParts = field.$name().match(/([^A-Za-z]*)(.+)/);
if (nameParts)
return nameParts[1] + Case.camel(nameParts[2]);
return Case.camel(field.$name());
}
$fieldType(field) {
let type = field.$type() + "";
if (type === "date")
type = "Date";
else if (type === "reference")
type = "string";
else if (["int", "float"].includes(type))
type = "number";
return type;
}
$fieldSignature(field) {
let type = this.$fieldType(field);
if (type === "nested") {
const nestedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)());
if (nestedModel)
type = this.$className(nestedModel);
}
return `${this.$fieldName(field)}${!(0, queries_1.$attr)(field, (0, attributes_1._required)()) ? "?" : ""}: ${type}${(0, queries_1.$attr)(field, (0, attributes_1._array)()) ? "[]" : ""}`;
}
select() {
return __awaiter(this, void 0, void 0, function* () {
const models = this.$models(this._where);
const paths = [];
models.forEach((model) => {
if (paths.some((p) => p.key === this.$key(model)))
return;
const mod = (0, queries_1.$attr)(model, (0, attributes_1._rootModule)());
const isDto = !!model.$name().match(/dto$/i);
const isEnum = !!(0, queries_1.$attr)(model, (0, attributes_1._enum)());
paths.push({
key: this.$key(model),
meta: { isDto, isEnum },
path: path.join(isDto ? this._dtoDir : isEnum ? this._enumDir : this._entityDir, this._includeModuleInDir ? Case.kebab(mod ? mod.$name() : "") : "", this.$fileName(model)),
});
});
return {
paths,
models,
};
});
}
render() {
return __awaiter(this, void 0, void 0, function* () {
const output = [];
const models = this.$selection().models || [];
models.forEach((model) => {
var _a;
const modelKey = this.$key(model);
const modelPath = this.$path(modelKey);
if (!modelPath)
return;
let content = "";
const enumDefinition = (0, queries_1.$attr)(model, (0, attributes_1._enum)());
if (enumDefinition) {
const enumCursor = "#enum-cursor\n";
content = `export enum ${this.$className(model)} {\n${enumCursor}}`;
Object.keys(enumDefinition).forEach((key) => {
content = (0, rendering_1.writeToCursor)(enumCursor, ` ${key} = ${JSON.stringify(enumDefinition[key])},\n`, content);
});
content = (0, rendering_1.closeCursor)(enumCursor, content);
}
else {
const fieldCursor = "#field-cursor\n";
const importCursor = "#import-cursor\n";
const fromJsonCursor = "#from-json-cursor\n";
const toJsonCursor = "#to-json-cursor\n";
content = `${importCursor}export class ${this.$className(model)} {\n${fieldCursor}\n constructor(data?: Omit<${this.$className(model)}, "toJson">) {
if (data) ${this.$className(model)}.fromJson(data, this);
}\n\n${fromJsonCursor}\n${toJsonCursor}}`;
const fields = model.$fields();
const importedModels = [];
fields.forEach((field) => {
var _a;
const fieldSignature = this.$fieldSignature(field);
if (field.$type() == "nested") {
const nestedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)());
if (nestedModel) {
if (this.$className(model) != this.$className(nestedModel) &&
!importedModels.includes(this.$className(nestedModel))) {
content = (0, rendering_1.writeToCursor)(importCursor, this.$resolveImport((_a = modelPath.path) !== null && _a !== void 0 ? _a : "", nestedModel), content);
importedModels.push(this.$className(nestedModel));
}
}
}
content = (0, rendering_1.writeToCursor)(fieldCursor, ` ${fieldSignature};\n`, content);
});
let fromJsonMethod = ` static fromJson(json: Record<string, any>, instance?: ${this.$className(model)}): ${this.$className(model)} {\n instance = instance ?? new ${this.$className(model)}();\n`;
let toJsonMethod = ` toJson(): Record<string, any> {\n return {\n`;
fields.forEach((field) => {
const fieldName = this.$fieldName(field);
const type = field.$type();
if (type === "date") {
// For Date fields, assume the JSON value is an ISO string.
fromJsonMethod += ` if(json.${fieldName}) instance.${fieldName} = new Date(json.${fieldName});\n`;
toJsonMethod += ` ${fieldName}: this.${fieldName} ? this.${fieldName}.toISOString() : undefined,\n`;
}
else if (type === "nested") {
// For nested objects, call the nested type's fromJson/toJson.
const nestedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)());
const isEnum = !nestedModel || !!(0, queries_1.$attr)(nestedModel, (0, attributes_1._enum)());
if (nestedModel && !isEnum) {
if ((0, queries_1.$attr)(field, (0, attributes_1._array)())) {
// Nested array: map each item.
fromJsonMethod += ` if(json.${fieldName}) instance.${fieldName} =json.${fieldName}.map((item: any) => ${this.$className(nestedModel)}.fromJson(item));\n`;
toJsonMethod += ` ${fieldName}: this.${fieldName} ? this.${fieldName}.map((item: any) => item.toJson()) : undefined,\n`;
}
else {
// Single nested object.
fromJsonMethod += ` if(json.${fieldName}) instance.${fieldName} = ${this.$className(nestedModel)}.fromJson(json.${fieldName});\n`;
toJsonMethod += ` ${fieldName}: this.${fieldName} ? this.${fieldName}.toJson() : undefined,\n`;
}
}
else if (nestedModel) {
fromJsonMethod += ` instance.${fieldName} = json.${fieldName};\n`;
toJsonMethod += ` ${fieldName}: this.${fieldName},\n`;
}
}
else {
// For primitives and other types, assign directly.
fromJsonMethod += ` instance.${fieldName} = json.${fieldName};\n`;
toJsonMethod += ` ${fieldName}: this.${fieldName},\n`;
}
});
fromJsonMethod += ` return instance;\n }\n`;
toJsonMethod += ` };\n }\n`;
content = (0, rendering_1.writeToCursor)(fromJsonCursor, fromJsonMethod, content);
content = (0, rendering_1.writeToCursor)(toJsonCursor, toJsonMethod, content);
if (importedModels.length > 0)
content = (0, rendering_1.writeToCursor)(importCursor, "\n", content);
content = (0, rendering_1.closeCursor)(fieldCursor, content);
content = (0, rendering_1.closeCursor)(importCursor, content);
content = (0, rendering_1.closeCursor)(fromJsonCursor, content);
content = (0, rendering_1.closeCursor)(toJsonCursor, content);
}
if (content)
output.push({
key: modelKey,
content,
meta: (_a = modelPath.meta) !== null && _a !== void 0 ? _a : {},
});
});
return output;
});
}
}
exports.default = TSClassRenderer;
//# sourceMappingURL=ts-class-renderer.js.map