UNPKG

@wuapi/processor

Version:
309 lines (308 loc) 10.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.verifyProject = exports.buildProject = void 0; const Definitions_1 = require("./Definitions"); const essential_1 = require("@wuapi/essential"); const lodash_1 = __importDefault(require("lodash")); const ForbiddenKeys_1 = __importDefault(require("./ForbiddenKeys")); const Log_1 = require("./Log"); /** * Generate a new WuApiProject object from this project. * @returns The WuApiProject generated */ function buildProject(self) { const prj = new essential_1.$Project(self.name, self.version, self.targetPackage); self.modules.forEach((module, key) => { const mdl = buildModule(module); prj.modules[key] = mdl; }); return prj; } exports.buildProject = buildProject; /** * Generate a new WuApiModule object from module. * @param self The {@link Module} object * @returns WuApiModule object generated */ function buildModule(self) { const mdl = new essential_1.$Module(); self.entities.forEach((entity, _) => { _traverseEntityTree(entity, self); }); self.enums.forEach((enu, key) => { mdl.enums[key] = buildEnum(enu); }); self.entities.forEach((entity, key) => { mdl.entities[key] = buildEntity(entity, self); }); return mdl; } /** * Preprocessor. * Recursively go through the entity, find all sub entities or enumerations, and add them to * the module object. * @param entity The entity object to check. * @param module The module where to where the new found entities or enums will be added to. */ function _traverseEntityTree(entity, module) { function checkField(field) { // check enum fields if (field instanceof Definitions_1.EnumField) { if (field.enu.name) { module.enums.set(field.enu.name, field.enu.element); } } // check object fields if (field instanceof Definitions_1.ObjectField) { if (field.entity.name) { module.entities.set(field.entity.name, field.entity.element); _traverseEntityTree(field.entity.element, module); } } // check list fields if (field instanceof Definitions_1.ListField) { checkField(field.member); } } if (entity.response != null && entity.response.name) { const key = entity.response.name; const ent = entity.response.element; if (!ent.comment) { ent.comment = entity.comment; } module.entities.set(key, ent); _traverseEntityTree(ent, module); } entity.fields.forEach((field) => { checkField(field); }); entity.knownMap.forEach((field) => { checkField(field); }); } /** * Generate a new WuApiEnum object from enum. * @param self The {@link Enum} object * @returns WuApiEnum object generated */ function buildEnum(self) { const enu = new essential_1.$Enum(); enu.comment = self.comment; self.items.forEach((item, key) => { const itm = new essential_1.$EnumItem(item.value); itm.realname = item.realname; itm.comment = item.comment; enu.enumMap[key] = itm; }); return enu; } /** * Find an entity from a project, and return the module name and entity name. * @param module The {@link Module} object, from where to find. * @param element The element object to find. * @returns */ function _findModuleAndName(module, element) { if (element.name) { return new essential_1.$ElementPath(module.name, element.name); } else { return _findModuleAndElementName(module, element.element); } } /** * Find an entity from a project, and return the module name and entity name. * @param module The {@link Module} object, from where to find. * @param element The element object to find. * @returns */ function _findModuleAndElementName(module, element) { for (const m of module.project.modules.values()) { const list = element instanceof Definitions_1.Entity ? m.entities : m.enums; for (const key of list.keys()) { const e = list.get(key); if (e == element) { return new essential_1.$ElementPath(m.name, key); } } } return new essential_1.$ElementPath(null, null); } /** * Generate a new WuApiEntity object from entity. * @param self The {@link Entity} object * @param module The {@link Module} object * @returns WuApiEntity object generated */ function buildEntity(self, module) { var ent = new essential_1.$Entity(self.type); ent.isAbstract = self.abstract; ent.comment = self.comment; ent.path = self.path; ent.method = self.method; if (self.parent) { ent.parent = _findModuleAndElementName(module, self.parent); } if (self.response) { if (self.response?.name) { ent.response = new essential_1.$ElementPath(module.name, self.response.name); } else if (self.response?.element) { ent.response = _findModuleAndName(module, self.response); } } self.knownMap.forEach((field, key) => { ent.genericMap[key] = buildField(field, module); }); self.fields.forEach((field, key) => { ent.fieldsLocal[key] = buildField(field, module); }); return ent; } /** * Generate a new WuApiField object from field. * @param self The {@link Field} object * @param module The {@link MOdeul} object * @returns WuApiField object generated */ function buildField(self, module) { var type = null; switch (self.constructor.name) { case 'IntegerField': type = new essential_1.$TInteger(); break; case 'LongField': type = new essential_1.$TLong(); break; case 'DoubleField': type = new essential_1.$TDouble(); break; case 'IDField': type = new essential_1.$TID(); break; case 'URLField': type = new essential_1.$TURL(); break; case 'DateTimeField': type = new essential_1.$TDateTime(); break; case 'BooleanField': type = new essential_1.$TBoolean(); break; case 'StringField': type = new essential_1.$TString(); break; case 'SSMapField': type = new essential_1.$TSSMap(); break; case 'EnumField': { const result = _findModuleAndName(module, self.enu); type = new essential_1.$TEnum(result); break; } case 'ObjectField': { const result = _findModuleAndName(module, self.entity); type = new essential_1.$TObject(result); break; } case 'ListField': { const _f = self; type = new essential_1.$TList(buildField(_f.member, module).type); break; } case 'UnknownField': { const _f = self; type = new essential_1.$TUnknown(_f.name); break; } default: { throw `Unknow field type: ${self.constructor.name}`; } } const fld = new essential_1.$Field(type); fld.comment = self.comment; fld.fixedValue = self.fixed; fld.isOptional = self.optional; fld.isPathParameter = self.isPathParameter; fld.realname = self.realname; fld.config = self.config; return fld; } /** * Verify a project. * @param project The project to verify * @returns true if there's no problem (may still have wanrings), false otherwise. */ function verifyProject(project) { let wrong = false; let nameMap = new Map(); // print path function pp(pth) { return `${pth.module}/${pth.name}`; } // check standard C variable format function validName(name, location) { if (!name || !name.match(/^[_a-zA-Z][_a-zA-Z0-9]*$/)) { (0, Log_1.error)(`${location}: "${name}" is not valid name. Should use standard C variable format`); wrong = true; } } function keyword(name, location) { if (!name || ForbiddenKeys_1.default.indexOf(name) >= 0) { (0, Log_1.error)(`${location}: "${name}" is a keyword. Please use another name`); wrong = true; } } //////////////////// // Check entity & enum names lodash_1.default.concat(lodash_1.default.map(project.flatEntities(), (o) => o.path), lodash_1.default.map(project.flatEnums(), (o) => o.path)).forEach((o) => { validName(o.name, `${pp(o)}`); keyword(o.name, `${pp(o)}`); if (!o.name?.match(/^[A-Z]/)) { (0, Log_1.warning)(`${pp(o)}: "${o.name}" should start with uppercase letter`); } const existing = nameMap.get(o.name); if (existing) { (0, Log_1.error)(`Name "${pp(o)}" duplicates with "${pp(existing)}"`); wrong = true; } else { nameMap.set(o.name, o); } }); //////////////////// // Check entity contents project.flatEntities().forEach(({ path, entity }) => { // Check generic name entity.getGenericLocal().forEach((g) => { validName(g, `${pp(path)}: Generic <${g}> `); if (!g.match(/^[A-Z]$/)) { (0, Log_1.warning)(`${pp(path)}: Generic <${g}> should use single upper case letter.`); } }); // Check fields lodash_1.default.forIn(entity.fieldsLocal, (_, name) => { validName(name, `${pp(path)}: Field "${name}" `); keyword(name, `${pp(path)}: Field "${name}" `); if (!name.match(/^[a-z]/)) { (0, Log_1.warning)(`${pp(path)}: Field "${name}" should start with lowercase letter.`); } }); }); //////////////////// // Check enum items project.flatEnums().forEach(({ path, enu }) => { // Check items enu.flat().forEach((e) => { validName(e.name, `${pp(path)}: Item "${e.name}"`); keyword(e.name, `${pp(path)}: Item "${e.name}"`); }); }); return !wrong; } exports.verifyProject = verifyProject;