UNPKG

base-domain

Version:

simple module to help build Domain-Driven Design

498 lines (427 loc) 16.7 kB
var Base, BaseModel, ClassInfo, ESCodeGenerator, EntryGenerator, EntryGeneratorInput, Facade, JSCodeGenerator, MasterDataResource, Path, camelize, fs, requireFile, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; fs = require('fs'); Path = require('path'); if (Path.isAbsolute == null) { Path.isAbsolute = function(str) { return str.charAt(0) === '/'; }; } camelize = require('./util').camelize; Facade = require('./main'); requireFile = Facade.requireFile; Base = Facade.Base, BaseModel = Facade.BaseModel; MasterDataResource = require('./master-data-resource'); ClassInfo = (function() { function ClassInfo(name1, relPath1, className1, moduleName1) { this.name = name1; this.relPath = relPath1; this.className = className1; this.moduleName = moduleName1; } Object.defineProperties(ClassInfo.prototype, { modFullName: { get: function() { if (this.moduleName) { return this.moduleName + '/' + this.name; } else { return this.name; } } }, fullClassName: { get: function() { return camelize(this.moduleName) + this.className; } } }); return ClassInfo; })(); EntryGeneratorInput = (function() { function EntryGeneratorInput(facadePath, dirname, outfile) { this.validate(facadePath, dirname, outfile); this.absDirname = this.absolutePath(dirname); this.absOutfilePath = this.absolutePath(outfile); this.facadePath = this.relativePath(facadePath); this.coreClasses = this.getClassInfoList(this.absDirname); this.modules = this.getModulesClasses(); this.facadeClassName = requireFile(this.absolutePath(facadePath)).name; this.facade = this.createFacade(); this.masterJSONStr = JSON.stringify(this.getMasterJSON()); this.factories = this.getPreferredFactoryNames(); } EntryGeneratorInput.prototype.createFacade = function() { var allModules, i, len, moduleName, ref; allModules = {}; ref = this.getModuleNames(); for (i = 0, len = ref.length; i < len; i++) { moduleName = ref[i]; allModules[moduleName] = Path.join(this.absDirname, moduleName); } return Facade.createInstance({ dirname: this.absDirname, modules: allModules, master: true }); }; /** @return {Array(ClassInfo)} */ EntryGeneratorInput.prototype.getClassInfoList = function(dirPath, moduleName) { var className, filename, i, len, name, ref, relDirname, relPath, results; if (moduleName == null) { moduleName = ''; } relDirname = this.relativePath(dirPath); ref = this.getClassFiles(dirPath); results = []; for (i = 0, len = ref.length; i < len; i++) { filename = ref[i]; name = filename.split('.')[0]; relPath = relDirname + '/' + name; className = requireFile(Path.resolve(dirPath, name)).name; results.push(new ClassInfo(name, relPath, className, moduleName)); } return results; }; /** @return {{[string]: Array(ClassInfo)}} */ EntryGeneratorInput.prototype.getModulesClasses = function() { var i, len, moduleName, modulePath, modules, ref; modules = {}; ref = this.getModuleNames(); for (i = 0, len = ref.length; i < len; i++) { moduleName = ref[i]; modulePath = Path.join(this.absDirname, moduleName); modules[moduleName] = this.getClassInfoList(modulePath, moduleName); } return modules; }; /** @method getMasterJSON @private @return {Object} master data */ EntryGeneratorInput.prototype.getMasterJSON = function() { var e, masterJSONPath; try { masterJSONPath = this.facade.master.masterJSONPath; if (!fs.existsSync(masterJSONPath)) { return null; } return require(masterJSONPath); } catch (error) { e = error; return null; } }; /** @return {Array(string)} array of module names */ EntryGeneratorInput.prototype.getModuleNames = function() { return fs.readdirSync(this.absDirname).filter(function(subDirName) { return subDirName !== 'master-data'; }).filter(function(subDirName) { return subDirName !== 'custom-roles'; }).map((function(_this) { return function(subDirname) { return Path.join(_this.absDirname, subDirname); }; })(this)).filter(function(subDirPath) { return fs.statSync(subDirPath).isDirectory(); }).filter(function(subDirPath) { return fs.readdirSync(subDirPath).some(function(filename) { var klass; klass = requireFile(Path.join(subDirPath, filename)); return klass.isBaseDomainClass; }); }).map(function(subDirPath) { return Path.basename(subDirPath); }); }; /** get domain files to load @method getClassFiles @private @return {Array(string)} filenames */ EntryGeneratorInput.prototype.getClassFiles = function(path) { var ParentClass, ext, fileInfo, fileInfoDict, filename, files, i, klass, len, name, pntFileName, ref, ref1, ref2; fileInfoDict = {}; ref = fs.readdirSync(path); for (i = 0, len = ref.length; i < len; i++) { filename = ref[i]; ref1 = filename.split('.'), name = ref1[0], ext = ref1[1]; if (ext !== 'js' && ext !== 'coffee') { continue; } klass = requireFile(path + '/' + filename); fileInfoDict[name] = { filename: filename, klass: klass }; } files = []; for (name in fileInfoDict) { fileInfo = fileInfoDict[name]; klass = fileInfo.klass, filename = fileInfo.filename; if (indexOf.call(files, filename) >= 0) { continue; } ParentClass = Object.getPrototypeOf(klass.prototype).constructor; if (ParentClass.className && (pntFileName = (ref2 = fileInfoDict[ParentClass.getName()]) != null ? ref2.filename : void 0)) { if (indexOf.call(files, pntFileName) < 0) { files.push(pntFileName); } } files.push(filename); } return files; }; /** get entities with no factory */ EntryGeneratorInput.prototype.getPreferredFactoryNames = function() { var classInfo, classes, factories, i, j, k, len, len1, modName, ref, ref1, v; factories = {}; ref = this.coreClasses; for (i = 0, len = ref.length; i < len; i++) { classInfo = ref[i]; factories[classInfo.modFullName] = this.getPreferredFactoryName(classInfo); } ref1 = this.modules; for (modName in ref1) { classes = ref1[modName]; for (j = 0, len1 = classes.length; j < len1; j++) { classInfo = classes[j]; factories[classInfo.modFullName] = this.getPreferredFactoryName(classInfo); } } for (k in factories) { v = factories[k]; if (v == null) { delete factories[k]; } } return factories; }; EntryGeneratorInput.prototype.getPreferredFactoryName = function(classInfo) { var ModelClass, e, factory; ModelClass = this.facade.require(classInfo.modFullName); if (!(ModelClass.prototype instanceof BaseModel)) { return; } try { factory = this.facade.createPreferredFactory(classInfo.modFullName); return "'" + factory.constructor.className + "'"; } catch (error) { e = error; return 'null'; } }; /** validate input data */ EntryGeneratorInput.prototype.validate = function(facadePath, dirname, outfile) { var absDirname, absFacadePath, outDir; absFacadePath = this.absolutePath(facadePath); absDirname = this.absolutePath(dirname); outDir = Path.dirname(this.absolutePath(outfile)); if (!fs.existsSync(absFacadePath)) { throw new Error("'" + absFacadePath + "' is not found."); } if (!fs.existsSync(absDirname)) { throw new Error("dirname: '" + absDirname + "' is not found."); } if (!fs.existsSync(outDir)) { throw new Error("output directory: '" + outDir + "' is not found."); } }; EntryGeneratorInput.prototype.absolutePath = function(path) { if (Path.isAbsolute(path)) { return Path.resolve(path); } return Path.resolve(process.cwd(), path); }; EntryGeneratorInput.prototype.relativePath = function(path) { var relPath; relPath = Path.relative(Path.dirname(this.absOutfilePath), path); if (relPath.charAt(0) !== '.') { relPath = './' + relPath; } return relPath; }; return EntryGeneratorInput; })(); EntryGenerator = (function() { EntryGenerator.generate = function(facadePath, dirname, outfile, esCode) { var generator, input; if (esCode == null) { esCode = false; } input = new EntryGeneratorInput(facadePath, dirname, outfile); if (esCode) { generator = new ESCodeGenerator(input, 'const'); } else { generator = new JSCodeGenerator(input, 'var'); } return generator.generate(); }; function EntryGenerator(input1, declaration) { this.input = input1; this.declaration = declaration; } EntryGenerator.prototype.generate = function() { var code; code = [this.getPragmas(), this.getImportStatements(), this.getPackedData(), this.getExportStatements()].join('\n') + '\n'; return fs.writeFileSync(this.input.absOutfilePath, code); }; EntryGenerator.prototype.getPragmas = function() { return ''; }; EntryGenerator.prototype.getPackedData = function() { var coreClasses, facadeClassName, factories, masterJSONStr, modules, ref; ref = this.input, factories = ref.factories, coreClasses = ref.coreClasses, modules = ref.modules, masterJSONStr = ref.masterJSONStr, facadeClassName = ref.facadeClassName; return this.declaration + " packedData = {\n // eslint-disable-next-line quotes, key-spacing, object-curly-spacing, comma-spacing\n masterData : " + masterJSONStr + ",\n core: {\n" + (this.getPackedCode(coreClasses, 2)) + ",\n },\n modules: {\n" + (this.getModulesPackedData(modules)) + "\n },\n factories: {\n" + (this.getFactoriesPackedData(factories, 2)) + "\n }\n}\n" + facadeClassName + ".prototype.init = function init() { return this.initWithPacked(packedData) }"; }; EntryGenerator.prototype.getPackedCode = function(classes, indent) { var i, ref, results, spaces; spaces = (function() { results = []; for (var i = 0, ref = indent * 4; 0 <= ref ? i < ref : i > ref; 0 <= ref ? i++ : i--){ results.push(i); } return results; }).apply(this).map(function(x) { return ' '; }).join(''); return spaces + classes.map(function(classInfo) { return "'" + classInfo.name + "': " + classInfo.fullClassName; }).join(',\n' + spaces); }; EntryGenerator.prototype.getModulesPackedData = function(modules) { var _; _ = ' '; return Object.keys(modules).map((function(_this) { return function(modName) { var modClasses; modClasses = modules[modName]; return _ + "'" + modName + "': {\n" + (_this.getPackedCode(modClasses, 3)) + "\n" + _ + "}"; }; })(this)).join(',\n'); }; EntryGenerator.prototype.getFactoriesPackedData = function(factories, indent) { var i, ref, results, spaces; spaces = (function() { results = []; for (var i = 0, ref = indent * 4; 0 <= ref ? i < ref : i > ref; 0 <= ref ? i++ : i--){ results.push(i); } return results; }).apply(this).map(function(x) { return ' '; }).join(''); return spaces + Object.keys(factories).map((function(_this) { return function(modelName) { var factoryName; factoryName = factories[modelName]; return "'" + modelName + "': " + factoryName; }; })(this)).join(',\n' + spaces); }; return EntryGenerator; })(); JSCodeGenerator = (function(superClass) { extend(JSCodeGenerator, superClass); function JSCodeGenerator() { return JSCodeGenerator.__super__.constructor.apply(this, arguments); } JSCodeGenerator.prototype.getPragmas = function() { return "/* eslint quote-props: 0, object-shorthand: 0, no-underscore-dangle: 0 */\n" + this.declaration + " __ = function __(m) { return m.default ? m.default : m }"; }; JSCodeGenerator.prototype.getImportStatements = function() { var classInfo, code, coreClasses, facadeClassName, facadePath, i, j, len, len1, modClasses, modName, modules, ref; ref = this.input, coreClasses = ref.coreClasses, modules = ref.modules, facadePath = ref.facadePath, facadeClassName = ref.facadeClassName; code = this.getRequireStatement(facadeClassName, facadePath); for (i = 0, len = coreClasses.length; i < len; i++) { classInfo = coreClasses[i]; code += this.getRequireStatement(classInfo.className, classInfo.relPath); } for (modName in modules) { modClasses = modules[modName]; for (j = 0, len1 = modClasses.length; j < len1; j++) { classInfo = modClasses[j]; code += this.getRequireStatement(classInfo.fullClassName, classInfo.relPath); } } return code; }; JSCodeGenerator.prototype.getExportStatements = function() { var classNames, coreClasses, facadeClassName, keyValues, modClasses, modName, modules, ref; ref = this.input, coreClasses = ref.coreClasses, modules = ref.modules, facadeClassName = ref.facadeClassName; classNames = coreClasses.map(function(coreClass) { return coreClass.className; }); for (modName in modules) { modClasses = modules[modName]; classNames = classNames.concat(modClasses.map(function(modClass) { return modClass.fullClassName; })); } keyValues = classNames.map(function(className) { return className + ": " + className; }); return "module.exports = {\n \"default\": " + facadeClassName + ",\n " + facadeClassName + ": " + facadeClassName + ",\n " + (keyValues.join(',\n ')) + "\n}"; }; JSCodeGenerator.prototype.getRequireStatement = function(className, path) { return this.declaration + " " + className + " = __(require('" + path + "'))\n"; }; return JSCodeGenerator; })(EntryGenerator); ESCodeGenerator = (function(superClass) { extend(ESCodeGenerator, superClass); function ESCodeGenerator() { return ESCodeGenerator.__super__.constructor.apply(this, arguments); } ESCodeGenerator.prototype.getPragmas = function() { return "// @flow\n/* eslint quote-props: 0, max-len: 0 */"; }; ESCodeGenerator.prototype.getImportStatements = function() { var classInfo, code, coreClasses, facadeClassName, facadePath, i, j, len, len1, modClasses, modName, modules, ref; ref = this.input, coreClasses = ref.coreClasses, modules = ref.modules, facadePath = ref.facadePath, facadeClassName = ref.facadeClassName; code = this.getImportStatement(facadeClassName, facadePath); for (i = 0, len = coreClasses.length; i < len; i++) { classInfo = coreClasses[i]; code += this.getImportStatement(classInfo.className, classInfo.relPath); } for (modName in modules) { modClasses = modules[modName]; for (j = 0, len1 = modClasses.length; j < len1; j++) { classInfo = modClasses[j]; code += this.getImportStatement(classInfo.fullClassName, classInfo.relPath); } } return code; }; ESCodeGenerator.prototype.getExportStatements = function() { var classNames, coreClasses, facadeClassName, modClasses, modName, modules, ref; ref = this.input, coreClasses = ref.coreClasses, modules = ref.modules, facadeClassName = ref.facadeClassName; classNames = coreClasses.map(function(coreClass) { return coreClass.className; }); for (modName in modules) { modClasses = modules[modName]; classNames = classNames.concat(modClasses.map(function(modClass) { return modClass.fullClassName; })); } return "export default " + facadeClassName + "\nexport {\n " + facadeClassName + ",\n " + (classNames.join(',\n ')) + "\n}"; }; /** get import statement from className and path */ ESCodeGenerator.prototype.getImportStatement = function(className, path) { return "import " + className + " from '" + path + "'\n"; }; return ESCodeGenerator; })(EntryGenerator); module.exports = EntryGenerator;