entity-baker
Version:
Generates simple and powerful entity classes for ORM systems, like Doctrine and/or Entity Framework.
377 lines • 14.2 kB
JavaScript
;
/**
* This file is part of the node-entity-baker distribution.
* Copyright (c) Marcel Joachim Kloubert.
*
* node-entity-baker is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 3.
*
* node-entity-baker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const eb_lib_doctrine = require("./doctrine");
const eb_lib_ef = require("./ef");
const eb_lib_ef_core = require("./efcore");
const eb_lib_helpers = require("./helpers");
const Enumerable = require("node-enumerable");
const Path = require("path");
/**
* List of known frameworks.
*/
var EntityFramework;
(function (EntityFramework) {
/**
* Doctrine (PHP)
*/
EntityFramework[EntityFramework["Doctrine"] = 1] = "Doctrine";
/**
* Microsoft's Entity Framework
*/
EntityFramework[EntityFramework["EntityFramework"] = 2] = "EntityFramework";
/**
* Microsoft's Entity Framework Core
*/
EntityFramework[EntityFramework["EntityFrameworkCore"] = 3] = "EntityFrameworkCore";
})(EntityFramework = exports.EntityFramework || (exports.EntityFramework = {}));
/**
* The default name of an entity file.
*/
exports.DEFAULT_ENTITY_FILE = 'entities.json';
// data types
exports.TYPE__DEFAULT = '';
exports.TYPE_BIGINT = 'bigint';
exports.TYPE_BIN = 'bin';
exports.TYPE_BINARY = 'binary';
exports.TYPE_BLOB = 'blob';
exports.TYPE_BOOL = 'bool';
exports.TYPE_BOOLEAN = 'boolean';
exports.TYPE_DATE = 'date';
exports.TYPE_DATETIME = 'datetime';
exports.TYPE_DATETIME_TZ = 'datetimetz';
exports.TYPE_FLOAT = 'float';
exports.TYPE_DECIMAL = 'decimal';
exports.TYPE_GUID = 'guid';
exports.TYPE_INT = 'int';
exports.TYPE_INT16 = 'int16';
exports.TYPE_INT32 = 'int32';
exports.TYPE_INTEGER = 'integer';
exports.TYPE_INT64 = 'int64';
exports.TYPE_JSON = 'json';
exports.TYPE_SMALLINT = 'smallint';
exports.TYPE_STR = 'str';
exports.TYPE_STRING = 'string';
exports.TYPE_TEXT = 'text';
exports.TYPE_TIME = 'time';
exports.TYPE_UINT16 = 'int16';
exports.TYPE_UINT32 = 'int32';
exports.TYPE_UINT64 = 'int64';
exports.TYPE_UUID = 'uuid';
/**
* An entity compiler.
*/
class EntityCompiler {
/**
* Initializes a new instance of that class.
*
* @param {EntityCompilerOptions} [options] Options for compilation operations.
*/
constructor(options) {
this.options = options;
if (!this.options) {
this.options = {};
}
}
/**
* Compiles entities.
*
* @return {Promise<EntityCompilerResult>} The promise with the result.
*/
compile() {
return __awaiter(this, void 0, void 0, function* () {
const RESULT = {};
let cwd = eb_lib_helpers.toStringSafe(this.options.cwd);
if (eb_lib_helpers.isEmptyString(cwd)) {
cwd = process.cwd();
}
if (!Path.isAbsolute(cwd)) {
cwd = Path.join(process.cwd(), cwd);
}
cwd = Path.resolve(cwd);
let outDir = eb_lib_helpers.toStringSafe(this.options.outDir);
if (eb_lib_helpers.isEmptyString(cwd)) {
outDir = cwd;
}
if (!Path.isAbsolute(outDir)) {
outDir = Path.join(cwd, outDir);
}
outDir = Path.resolve(outDir);
const FILE = this.options.file;
if (eb_lib_helpers.isObj(FILE)) {
const NAMESPACE = eb_lib_helpers.toStringSafe(FILE['namespace']).split('.').map(x => {
return x.trim();
}).filter(x => {
return '' !== x;
});
const ENTITIES = FILE.entities;
if (eb_lib_helpers.isObj(ENTITIES)) {
let callbacks = this.options.callbacks;
if (!callbacks) {
callbacks = {};
}
yield this.compileEntities(NAMESPACE, ENTITIES, callbacks, outDir);
}
}
return RESULT;
});
}
/**
* Compiles entities.
*
* @param {string[]} ns The namespace without dots.
* @param {EntityDescriptions} entities The entities.
* @param {CompilerCallbacks} callbacks Callbacks.
* @param {string} outDir The output directory.
*/
compileEntities(ns, entities, callbacks, outDir) {
return __awaiter(this, void 0, void 0, function* () {
for (const E in entities) {
if (callbacks.onBeforeGenerateClass) {
yield Promise.resolve(callbacks.onBeforeGenerateClass(E, this.options.target));
}
let err;
try {
const CLASS_NAME = parseForClass(E);
if (false === CLASS_NAME) {
throw new Error(`The class name '${E}' is invalid!`);
}
const ENTITY_CLASS = entities[E];
if (!eb_lib_helpers.isObj(ENTITY_CLASS)) {
continue;
}
const COLUMNS = {};
if (eb_lib_helpers.isObj(ENTITY_CLASS.columns)) {
for (const C in ENTITY_CLASS.columns) {
const COLUMN_NAME = parseForClass(C);
if (false === COLUMN_NAME) {
throw new Error(`The column name '${C}' is invalid!`);
}
if (eb_lib_helpers.isObj(COLUMNS[COLUMN_NAME])) {
throw new Error(`The column '${COLUMN_NAME}' has already been defined!`);
}
let colEntry = ENTITY_CLASS.columns[C];
if (!eb_lib_helpers.isObj(colEntry)) {
colEntry = {
type: eb_lib_helpers.normalizeString(colEntry),
};
}
COLUMNS[COLUMN_NAME] = colEntry;
}
}
const METHODS = {};
for (const C in COLUMNS) {
let wordsOfColumn = eb_lib_helpers.replaceAll(C, '_', ' ');
wordsOfColumn = eb_lib_helpers.replaceAll(C, '-', ' ');
wordsOfColumn = eb_lib_helpers.replaceAll(C, "\t", ' ');
const WORDS = Enumerable.from(wordsOfColumn.split(' ')).select(w => {
return w.trim();
}).where(w => {
return '' !== w;
}).select(w => {
return w[0].toUpperCase() + w.substr(1).trim();
}).toArray();
METHODS[C] = WORDS.join('');
}
let generator;
let generatorThisArg = this;
const TARGET = this.options.target;
switch (TARGET) {
case EntityFramework.Doctrine:
generator = eb_lib_doctrine.generateClassForDoctrine;
break;
case EntityFramework.EntityFramework:
generator = eb_lib_ef.generateClassForEntityFramework;
break;
case EntityFramework.EntityFrameworkCore:
generator = eb_lib_ef_core.generateClassForEntityFrameworkCore;
break;
}
if (!generator) {
throw new Error(`Target ${eb_lib_helpers.toStringSafe(TARGET)} is not supported!`);
}
const CTX = {
columnNames: Object.keys(COLUMNS).sort((x, y) => {
return eb_lib_helpers.compareValuesBy(x, y, c => {
return eb_lib_helpers.normalizeString(c);
});
}),
columns: COLUMNS,
entity: ENTITY_CLASS,
methods: METHODS,
name: CLASS_NAME,
'namespace': ns,
options: this.options,
outDir: outDir,
};
yield Promise.resolve(generator.apply(generatorThisArg, [CTX]));
}
catch (e) {
err = e;
}
finally {
if (callbacks.onClassGenerated) {
yield Promise.resolve(callbacks.onClassGenerated(err, E, this.options.target));
}
}
}
});
}
}
exports.EntityCompiler = EntityCompiler;
/**
* Compiles entities.
*
* @param {EntityCompilerOptions} [opts] Options for the operation.
*
* @return {Promise<EntityCompilerResult>} The promise with the result.
*/
function compile(opts) {
return __awaiter(this, void 0, void 0, function* () {
const COMPILER = new EntityCompiler(opts);
return yield COMPILER.compile();
});
}
exports.compile = compile;
/**
* Parses a value for a class or for use in a class.
*
* @param {any} val The input value.
*
* @return {string|false} The parsed name or (false) if invalid.
*/
function parseForClass(val) {
val = eb_lib_helpers.toStringSafe(val).trim();
if (/^([a-z|A-Z|0-9|_]+)$/i.test(val) &&
!/^([0-9]+)/i.test(val)) {
return val;
}
return false;
}
exports.parseForClass = parseForClass;
/**
* Converts a data type from a entity file to a CLR type.
*
* @param {string} type The entity type.
* @param {Function} canBeNull The function that provides if value can be (null) or not.
* @param {Function} isID The function that provides if value is an ID value or not.
*
* @return {string} The CLR type.
*/
function toClrType(type, canBeNull, isID) {
type = eb_lib_helpers.normalizeString(type);
switch (type) {
case exports.TYPE_BIGINT:
case exports.TYPE_INT64:
type = 'long';
break;
case exports.TYPE_BIN:
case exports.TYPE_BINARY:
case exports.TYPE_BLOB:
type = 'byte[]';
break;
case exports.TYPE_BOOL:
case exports.TYPE_BOOLEAN:
type = 'bool';
break;
case exports.TYPE_DATE:
case exports.TYPE_DATETIME:
type = 'global::System.DateTime';
break;
case exports.TYPE_DATETIME_TZ:
type = 'global::System.DateTimeOffset';
break;
case exports.TYPE_DECIMAL:
type = 'decimal';
break;
case exports.TYPE_FLOAT:
type = 'float';
break;
case exports.TYPE_GUID:
case exports.TYPE_UUID:
type = 'global::System.Guid';
break;
case exports.TYPE_INT:
case exports.TYPE_INT32:
case exports.TYPE_INTEGER:
type = 'int';
break;
case exports.TYPE_INT16:
case exports.TYPE_SMALLINT:
type = 'short';
break;
case exports.TYPE_JSON:
type = 'dynamic';
break;
case exports.TYPE_STR:
case exports.TYPE_STRING:
case exports.TYPE_TEXT:
type = 'string';
break;
case exports.TYPE_TIME:
type = 'System.TimeSpan';
break;
case exports.TYPE_UINT16:
type = 'ushort';
break;
case exports.TYPE_UINT32:
type = 'uint';
break;
case exports.TYPE_UINT64:
type = 'ulong';
break;
case exports.TYPE__DEFAULT:
type = 'string';
if (isID()) {
type = 'int';
}
break;
default:
throw new Error(`The data type '${type}' is not supported by CLR!`);
}
if (canBeNull()) {
switch (type) {
case 'bool':
case 'decimal':
case 'float':
case 'int':
case 'long':
case 'short':
case 'ushort':
case 'uint':
case 'ulong':
case 'global::System.DateTime':
case 'global::System.DateTimeOffset':
case 'global::System.Guid':
case 'System.TimeSpan':
type += '?';
break;
}
}
return type;
}
exports.toClrType = toClrType;
//# sourceMappingURL=compiler.js.map