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.

290 lines 15.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 renderer_1 = require("../entities/renderer"); const package_1 = require("../helpers/package"); const queries_1 = require("../shortcuts/queries"); const rendering_1 = require("../utils/rendering"); const attributes_1 = require("../shortcuts/attributes"); const missing_attribute_error_1 = require("../errors/missing-attribute-error"); const path = __importStar(require("path")); const Case = __importStar(require("case")); const KEYS = { packageJson: "packageJson", }; class TSMongooseSchemaRenderer extends renderer_1.URenderer { constructor(options) { super("ts@mongoose-schema"); this._schemaDir = "src/schemas"; this._includeModuleInDir = true; this._updatePackageJson = false; if (options === null || options === void 0 ? void 0 : options.where) this._where = options.where; if (options === null || options === void 0 ? void 0 : options.schemaDir) this._schemaDir = options.schemaDir; if (options === null || options === void 0 ? void 0 : options.includeModuleInDir) this._includeModuleInDir = options.includeModuleInDir; if (options === null || options === void 0 ? void 0 : options.updatePackageJson) this._updatePackageJson = options.updatePackageJson; } $schema(model) { var _a; return (_a = (0, queries_1.$attr)(model, (0, attributes_1._schema)())) !== null && _a !== void 0 ? _a : null; } $key(model) { return this.$schemaName(model); } $keys(models) { return models.map((model) => this.$key(model)); } $schemaName(model) { return Case.pascal(model.$name()) + "Schema"; } $modelName(model) { return Case.pascal(model.$name()) + "Model"; } $fileName(model, extension = true) { return `${Case.kebab(model.$name())}-schema${extension ? ".ts" : ""}`; } $fieldName(field) { return Case.camel(field.$name()); } $fieldType(field) { let type = field.$type() + ""; if (type == "reference") return "mongoose.Schema.ObjectId as any"; if (["int", "float"].includes(type)) return "Number"; if (type !== "nested") return Case.pascal(type); } $fieldDeclaration(field) { const type = field.$type() + ""; let transformedType = this.$fieldType(field); let enumModel = null; if (type == "nested") { const referencedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)()); if (referencedModel) { let enumDefinition = (0, queries_1.$attr)(referencedModel, (0, attributes_1._enum)()); if (enumDefinition) { transformedType = Case.pascal(typeof Object.values(enumDefinition)[0]); enumModel = referencedModel; } else transformedType = this.$schemaName(referencedModel); } } let properties = !!(0, queries_1.$attr)(field, (0, attributes_1._array)()) ? ` type: [${transformedType}],` : ` type: ${transformedType},`; if (enumModel) { properties += ` enum: ${this._classRenderer.$className(enumModel)},`; } if (type == "reference") { const referencedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)()); if (referencedModel) { const schema = (0, queries_1.$attr)(referencedModel, (0, attributes_1._schema)()); if (!schema) throw new missing_attribute_error_1.MissingAttributeError(referencedModel.$name(), "model", "_schema()"); properties += ` ref: () => ${this.$modelName(referencedModel)},`; } } const addProperty = (key, value) => { properties += ` ${key}: ${value},`; }; if (!!(0, queries_1.$attr)(field, (0, attributes_1._required)())) addProperty("required", "true"); if (!!(0, queries_1.$attr)(field, (0, attributes_1._unique)())) addProperty("unique", "true"); if (!!(0, queries_1.$attr)(field, (0, attributes_1._index)())) addProperty("index", (0, queries_1.$attr)(field, (0, attributes_1._index)())); if ((0, queries_1.$attr)(field, (0, attributes_1._min)()) !== null) addProperty("min", (0, queries_1.$attr)(field, (0, attributes_1._min)())); if ((0, queries_1.$attr)(field, (0, attributes_1._max)()) !== null) addProperty("max", (0, queries_1.$attr)(field, (0, attributes_1._max)())); if ((0, queries_1.$attr)(field, (0, attributes_1._minLength)()) !== null) addProperty("minlength", (0, queries_1.$attr)(field, (0, attributes_1._minLength)())); if ((0, queries_1.$attr)(field, (0, attributes_1._maxLength)()) !== null) addProperty("maxlength", (0, queries_1.$attr)(field, (0, attributes_1._maxLength)())); if (!!(0, queries_1.$attr)(field, (0, attributes_1._in)())) addProperty("enum", JSON.stringify((0, queries_1.$attr)(field, (0, attributes_1._in)()))); if (!!(0, queries_1.$attr)(field, (0, attributes_1._regex)())) addProperty("match", (0, queries_1.$attr)(field, (0, attributes_1._regex)()).toString()); return ` ${this.$fieldName(field)}: {${properties.replace(/,$/, "")} },\n`; } select() { return __awaiter(this, void 0, void 0, function* () { this._classRenderer = this.$draft().$requireRenderer(this, "ts@classes"); const models = this.$models(this._where).filter((model) => !!this.$schema(model) && !!this._classRenderer.$output(this._classRenderer.$key(model))); const extraSchemas = []; models.forEach((model) => { model.$fields().forEach((field) => { if (["nested", "reference"].includes(field.$type() + "")) { const referencedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)()); if (referencedModel && !models.some((m) => m.$name() === referencedModel.$name()) && !extraSchemas.includes(referencedModel.$name()) && !(0, queries_1.$attr)(referencedModel, (0, attributes_1._enum)())) { models.push(referencedModel); extraSchemas.push(referencedModel.$name()); } } }); }); const paths = []; if (this._updatePackageJson) paths.push({ key: KEYS.packageJson, path: "package.json", }); models.forEach((model) => { if (paths.some((p) => p.key === this.$key(model))) return; const mod = (0, queries_1.$attr)(model, (0, attributes_1._rootModule)()); paths.push({ key: this.$key(model), path: path.join(this._schemaDir, this._includeModuleInDir ? Case.kebab(mod ? mod.$name() : "") : "", this.$fileName(model)), }); }); return { paths, models, }; }); } render() { return __awaiter(this, void 0, void 0, function* () { const output = []; if (this._updatePackageJson) output.push({ key: KEYS.packageJson, content: (0, package_1.addPackageJsonDependency)(this.$content("packageJson").content, [ { name: "mongoose", version: "^8.11.0", }, ]), }); const models = this.$selection().models || []; models.forEach((model) => { const modelKey = this._classRenderer.$key(model); const schemaKey = this.$key(model); const classPath = this._classRenderer.$path(modelKey); const schemaPath = this.$path(schemaKey); if (!schemaPath || !classPath) return; const importCursor = "#import-cursor\n"; const fieldCursor = "#field-cursor\n"; const optionsCursor = "#options-cursor\n"; const textIndexCursor = "#text-index-cursor\n"; let content = `import mongoose from "mongoose";\nimport { ${this._classRenderer.$className(model)} } from "${this.$resolveRelativePath(schemaPath.path, classPath.path).replace(".ts", "")}";\n${importCursor}\n` + `export const ${this.$schemaName(model)} = new mongoose.Schema<${this._classRenderer.$className(model)}>({\n${fieldCursor}}${optionsCursor});${textIndexCursor}`; if ((0, queries_1.$attr)(model, (0, attributes_1._schema)())) content += `\n\nexport const ${this.$modelName(model)} = mongoose.model<${this._classRenderer.$className(model)}>("${(0, queries_1.$attr)(model, (0, attributes_1._schema)())}", ${this.$schemaName(model)});`; const fields = model.$fields(); const importedSchemas = []; let disableNoExplicityAny = false; const textIndexes = []; const customTextIndexes = (0, queries_1.$attr)(model, (0, attributes_1._textIndex)()); if (customTextIndexes && Array.isArray(customTextIndexes)) textIndexes.push(...customTextIndexes); fields.forEach((field) => { if (field.$name() == "_id" || (0, queries_1.$attr)(field, (0, attributes_1._virtual)())) return; const fieldDeclaration = this.$fieldDeclaration(field); if (!!(0, queries_1.$attr)(field, (0, attributes_1._textIndex)())) textIndexes.push(field.$name()); if (["nested", "reference"].includes(field.$type() + "")) { const referencedModel = (0, queries_1.$attr)(field, (0, attributes_1._ref)()); if (referencedModel) { if (this.$schemaName(model) != this.$schemaName(referencedModel) && !importedSchemas.includes(this.$schemaName(referencedModel))) { const isRefId = field.$type() == "reference"; const enumDefinition = (0, queries_1.$attr)(referencedModel, (0, attributes_1._enum)()); if (isRefId) disableNoExplicityAny = true; content = (0, rendering_1.writeToCursor)(importCursor, `import { ${isRefId ? this.$modelName(referencedModel) : enumDefinition ? this._classRenderer.$className(referencedModel) : this.$schemaName(referencedModel)} } from "${this.$resolveRelativePath(schemaPath.path, (enumDefinition ? this._classRenderer.$path(this._classRenderer.$key(referencedModel)) : this.$path(this.$key(referencedModel))).path).replace(".ts", "")}";\n`, content); importedSchemas.push(this.$schemaName(referencedModel)); } } } content = (0, rendering_1.writeToCursor)(fieldCursor, fieldDeclaration, content); }); if (!!(0, queries_1.$attr)(model, (0, attributes_1._noId)())) { content = (0, rendering_1.writeToCursor)(optionsCursor, `,\n{ _id: false }\n`, content); } if (textIndexes.length > 0) { content = (0, rendering_1.writeToCursor)(textIndexCursor, `\n\n${this.$schemaName(model)}.index({ ` + textIndexes .map((textIndex) => `"${textIndex}": "text"`) .join(", ") + `});`, content); } content = (0, rendering_1.closeCursor)(fieldCursor, content); content = (0, rendering_1.closeCursor)(importCursor, content); content = (0, rendering_1.closeCursor)(optionsCursor, content); content = (0, rendering_1.closeCursor)(textIndexCursor, content); if (disableNoExplicityAny) { content = "/* eslint-disable @typescript-eslint/no-explicit-any */\n\n" + content; } output.push({ key: schemaKey, content, }); }); return output; }); } } exports.default = TSMongooseSchemaRenderer; //# sourceMappingURL=ts-mongoose-schema-renderer.js.map