UNPKG

@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
"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