UNPKG

@lcap/asl

Version:

NetEase Application Specific Language

846 lines 30.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MicroService = exports.WebService = exports.Service = exports.SERVICE_TYPE = void 0; const decorators_1 = require("../decorators"); const __1 = require(".."); const app_1 = __importDefault(require("../../service/app")); const page_1 = __importDefault(require("../../service/page")); const webFile_1 = __importDefault(require("../../service/webFile")); const process_1 = __importDefault(require("../../service/process")); const data_1 = require("../../service/data"); const dataTypeUtils_1 = require("../data/dataTypeUtils"); const dataTypes_1 = require("../data/dataTypes"); const lodash_1 = require("lodash"); var SERVICE_TYPE; (function (SERVICE_TYPE) { SERVICE_TYPE["web"] = "web"; SERVICE_TYPE["micro"] = "micro"; })(SERVICE_TYPE = exports.SERVICE_TYPE || (exports.SERVICE_TYPE = {})); let vertexIdToName; /** * 服务(模块)类 */ class Service extends __1.Vertex { /** * @param source 需要合并的部分参数 */ constructor(source) { super(); /** * 概念类型 */ this.level = __1.LEVEL_ENUM.service; /** * 服务类型 */ this.type = undefined; /** * Service Id */ this.id = undefined; /** * 前端服务标识 */ this.name = undefined; /** * 前端服务标题 */ this.title = undefined; /** * 服务图标 */ this.icon = undefined; /** * App 的 Id */ this.appId = undefined; /** * 数据节点 */ this.data = undefined; /** * 接口列表 */ this.interfaces = []; /** * 逻辑节点 http://doc.hz.netease.com/pages/viewpage.action?pageId=310549021 */ this.globalLogic = undefined; /** * 所在的 App * 父级引用,便于在树状结构中查找 */ this.app = undefined; /** * 节点是否为展开状态 * 前端 UI 状态 */ this.expanded = true; this.data = new __1.DataNode({ service: this }); this.globalLogic = new __1.GlobalLogicNode({ service: this }); source && this.assign(source); } async loadStructures() { const structuresOrigin = await data_1.structureService.loadList({ query: { id: this.id, }, }); const structures = []; structuresOrigin.forEach((item) => { const structureNode = __1.Structure.from(item, this); if (structureNode.serviceType === 'external' && structureNode.category) { this.globalLogic.addCategoryStructure(structureNode); } else { structures.push(structureNode); } }); dataTypes_1.updateDataTypeList(); this.data.assign({ structures }); this.globalLogic.assign({ structures }); return structures; } async syncStructures() { // this.data.structures.forEach((structure) => { // delete dataTypesMap[structure.schemaRef]; // }); // const oldStructuresMap: Map<string, Structure> = new Map(); // this.data.structures.forEach((structure, index) => oldStructuresMap.set(structure.id, structure)); const newStructures = await data_1.structureService.loadList({ query: { id: this.id, }, }); this.globalLogic.syncStructures(newStructures); // newStructures.forEach((item, index) => { // const newStructure = Structure.from(item, this); // if (oldStructuresMap.has(newStructure.id)) { // const oldIndex = this.data.structures.indexOf(oldStructuresMap.get(newStructure.id)); // this.data.structures.splice(oldIndex, 1, newStructure); // oldStructuresMap.delete(newStructure.id); // } else { // this.data.structures.push(newStructure); // } // }); // // Map 直接 forEach 会有问题 // const oldRemains = Array.from(oldStructuresMap, ([id, index]) => ({ id, index })); // oldRemains.forEach((item) => { // const structure = oldStructuresMap.get(item.id); // delete dataTypesMap[structure.schemaRef]; // const oldIndex = this.data.structures.indexOf(structure); // this.data.structures.splice(oldIndex, 1); // structure.destroy(); // }); // updateDataTypeList(); // this.globalLogic.assign({ structures: this.data.structures }); return this.data.structures; } /** * 加载服务所有的接口列表 */ async loadInterfaces() { const RESOLVER_NAMES = ['getAll', 'get', 'create', 'update', 'delete', 'count', 'import', 'export', 'batchDelete', 'batchCreate', 'batchUpdate']; let interfaces = await data_1.interfaceService.loadList({ query: { serviceId: this.id, }, }); interfaces = interfaces.map((item) => { item = __1.Interface.from(item, this); if (item.logic && item.logic.entityId) { const entity = __1.Entity.getVertexByRef(item.logic.entityId); if (entity) entity.assign({ resolvers: entity.resolvers || [] }); const resolverName = RESOLVER_NAMES.find((name) => item.name.startsWith(name)); if (entity) entity.resolvers.push({ level: 'resolver', name: resolverName, interface: item, entity, isLeaf: true, }); } return item; }); this.assign({ interfaces }); return interfaces; } } __decorate([ decorators_1.immutable() ], Service.prototype, "level", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "type", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "id", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "name", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "title", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "icon", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "appId", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "data", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "interfaces", void 0); __decorate([ decorators_1.immutable() ], Service.prototype, "globalLogic", void 0); __decorate([ decorators_1.circular(), decorators_1.immutable() ], Service.prototype, "app", void 0); __decorate([ decorators_1.excludedInJSON() ], Service.prototype, "expanded", void 0); exports.Service = Service; /** * 前端服务(模块)类 */ class WebService extends Service { /** * @param source 需要合并的部分参数 */ constructor(source) { super(); /** * 服务类型 */ this.type = SERVICE_TYPE.web; /** * 服务状态 */ this.status = undefined; /** * 是否为官方服务 */ this.officialType = undefined; this.dnsAddr = undefined; /** * packageJSON 的缩减版 */ this.packageInfo = undefined; /** * 其他配置 */ this.config = undefined; this.api = undefined; /** * 前端页面 */ this.pages = []; source && this.assign(source); this.on('pageTreeChange', lodash_1.throttle(this._onPageTreeChange.bind(this), __1.config.throttleWait, { leading: true, trailing: true })); this.on('vertexIdToNameChange', () => { this.app.firstMicroService.emit('vertexIdToNameChange'); }); } async load() { const result = await app_1.default.loadWebService({ query: { appId: this.id, }, }); // result.id = result.appId; this.assign(result); return this; } async loadPackageInfo() { try { const res = await webFile_1.default.loadFile({ query: { serviceId: this.id, path: `package.partial.json`, }, }); if (res.content) { this.assign({ packageInfo: JSON.parse(res.content) }); } } catch (e) { } finally { if (!this.packageInfo) { this.assign({ packageInfo: { template: { name: 'cloud-admin-template', version: '0.2.23', }, ui: { name: 'cloud-ui.vusion', version: '0.11.30', }, componentDependencies: { 'lcap-login': '0.3.5', }, themeVariables: {}, }, }); } } } async savePackageInfo() { const serviceId = this.id; const path = `package.partial.json`; const promise = webFile_1.default.saveFile({ body: { serviceId, type: 'config', path, content: JSON.stringify(this.packageInfo), }, }); __1.generator.saveLastModified(serviceId, path); return promise; } /** * 根据 packageInfo 的信息生成用于 load 的 assetsInfo * 在环境中需要 basic 和 custom 分开 load,否则容易报错 * @param prefix */ genAllAssetsInfo(prefix) { const packageInfo = this.packageInfo; const scope = this.app.scope; const result = { basic: { js: [ `${prefix}/packages/vue@2/dist/vue.min.js`, // `${prefix}/packages/vue-router@3/dist/vue-router.min.js`, scope === 'h5' ? `${prefix}/packages/@lcap/mobile-ui@${packageInfo.ui.version}/dist-theme/index.js` : `${prefix}/packages/cloud-ui.vusion@${packageInfo.ui.version}/dist-theme/index.js`, scope === 'h5' ? `${prefix}/packages/@lcap/mobile-template@${packageInfo.template.version}/cloudAdminDesigner.umd.min.js` : `${prefix}/packages/lcap-pc-template@${packageInfo.template.version}/cloudAdminDesigner.umd.min.js`, ], css: [ scope === 'h5' ? `${prefix}/packages/@lcap/mobile-ui@${packageInfo.ui.version}/dist-theme/index.css` : `${prefix}/packages/cloud-ui.vusion@${packageInfo.ui.version}/dist-theme/index.css`, scope === 'h5' ? `${prefix}/packages/@lcap/mobile-template@${packageInfo.template.version}/cloudAdminDesigner.css` : `${prefix}/packages/lcap-pc-template@${packageInfo.template.version}/cloudAdminDesigner.css`, ], }, custom: { js: [], css: [], names: [], }, }; Object.keys(packageInfo.componentDependencies).forEach((name) => { const version = packageInfo.componentDependencies[name].replace(/^[^0-9]+/, ''); result.custom.js.push(`${prefix}/packages/${name}@${version}/dist-theme/index.js`); result.custom.css.push(`${prefix}/packages/${name}@${version}/dist-theme/index.css`); result.custom.names.push(name); }); return result; } genThemeCSS() { const themeVariables = this.packageInfo.themeVariables || {}; const keys = Object.keys(themeVariables); if (!keys.length) return; return `:root { ${Object.keys(themeVariables).map((key) => ` ${key}: ${themeVariables[key]};`).join('\n')} } `; } async loadPages() { const result = await page_1.default.loadPages({ query: { serviceId: this.id, }, config: { mock: __1.config.mock, }, }); const pages = result.map((page) => __1.Page.from(page, this)); this.assign({ pages }); return pages; } async addPage(page) { page.assign({ serviceId: this.id }); await page.create(undefined, undefined, async () => { page.assign({ service: this }); this.pages.unshift(page); }); return page; } async importPage(page) { page.assign({ serviceId: this.id }); await page.importPage(undefined, undefined, async () => { page.assign({ service: this }); this.pages.unshift(page); }); return page; } _onPageTreeChange() { __1.generator.savePageTreeCache(this); } /** * 从后端 JSON 生成规范的 WebService 对象 * @param source JSON * @param app 父级 App */ static from(source, app) { source.app = app; // if (!source.packageInfo) { // source.packageInfo = { // template: { // name: 'cloud-admin-template', // version: '0.2.22', // }, // ui: { // name: 'cloud-ui.vusion', // version: '0.11.23', // }, // componentDependencies: { // 'lcap-login': '^0.3.3', // }, // }; // } else if (typeof source.packageInfo === 'string') // source.packageInfo = JSON.parse(source.packageInfo); return new WebService(source); } } __decorate([ decorators_1.immutable() ], WebService.prototype, "type", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "status", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "officialType", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "dnsAddr", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "packageInfo", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "config", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "api", void 0); __decorate([ decorators_1.immutable() ], WebService.prototype, "pages", void 0); __decorate([ decorators_1.action('添加页面') ], WebService.prototype, "addPage", null); __decorate([ decorators_1.action('添加页面') ], WebService.prototype, "importPage", null); exports.WebService = WebService; /** * 后端服务(模块)类 */ class MicroService extends Service { // logics: { [name]: Logic }; /** * @param source 需要合并的部分参数 */ constructor(source) { super(); /** * 服务类型 */ this.type = SERVICE_TYPE.micro; /** * 接口列表 */ this.interfaces = []; /** * 流程列表 */ this.processes = []; source && this.assign(source); this.on('dataTypesChange', lodash_1.throttle(this._onDataTypesChange.bind(this), __1.config.throttleWait, { leading: true, trailing: true })); this.on('enumsChange', lodash_1.throttle(this._onEnumsChange.bind(this), __1.config.throttleWait, { leading: true, trailing: true })); this.on('interfacesChange', lodash_1.throttle(this._onInterfacesChange.bind(this), __1.config.throttleWait, { leading: true, trailing: true })); this._onVertexIdToNameChange = lodash_1.throttle(this._onVertexIdToNameChange, __1.config.throttleWait, { leading: true, trailing: true }); this.on('vertexIdToNameChange', this._onVertexIdToNameChange.bind(this)); this._saveVertexIdToName = lodash_1.throttle(async () => { await __1.generator.saveVertexIdToName(this.app); vertexIdToName = __1.generator.getVertexIdToName(); }, __1.config.throttleWait, { leading: true, trailing: true }); } async _saveVertexIdToName() { } async loadEntities() { const entities = await data_1.entityService.loadList({ query: { microServiceId: this.id, }, }); entities.forEach((item, index) => { dataTypeUtils_1.convert2RefType(item); entities[index] = item = new __1.Entity(item); item.assign({ dataNode: this.data, schemaRef: `#/${this.id}/${item.id}`, }); const lastVersionRef = item.lastVersionDef && item.lastVersionDef.properties || {}; const propertyList = item.propertyList; propertyList.sort((a, b) => a._posIndex - b._posIndex); propertyList.forEach((property, index) => { property = propertyList[index] = new __1.EntityProperty(property); if (lastVersionRef[property.name]) { property.assign({ lastVersion: dataTypeUtils_1.convert2RefType(lastVersionRef[property.name]) }); } property.assign({ root: item }); }); item.assign({ resolvers: [] }); const indexList = item.indexList; indexList.forEach((indexItem, index) => { indexItem = indexList[index] = new __1.EntityIndex(indexItem); indexItem.assign({ root: item }); }); __1.dataTypesMap[item.schemaRef] = item; }); dataTypes_1.updateDataTypeList(); this.data.assign({ entities }); this.mountResolverOnEntity(); return entities; } async addEntity(name) { const entityOptions = { dataNode: this.data, serviceId: this.id, serviceType: this.type, }; let entity; if (typeof name === 'string') { entity = new __1.Entity(Object.assign(entityOptions, { name, })); } else if (name instanceof __1.Entity) { entity = name; } else { entity = new __1.Entity(Object.assign(entityOptions, name)); } entity.loading = true; try { await entity.create(); entity.loading = false; if (!this.data.entities.includes(entity)) this.data.entities.push(entity); entity.propertyList.forEach((property) => property.loading = false); this.globalLogic.syncEntityLogics(); } catch (err) { const index = this.data.entities.indexOf(entity); ~index && this.data.entities.splice(index, 1); } return entity; } async removeEntity(name) { let entity; if (typeof name === 'string') { entity = this.data.entities.find((item) => item.name === name || item.id === name); if (!entity) throw new Error('找不到实体 ' + name); } else { entity = name; } entity.loading = true; await entity.delete(); entity.loading = false; this.globalLogic.syncEntityLogics(); } /** * 加载所有枚举 */ async loadEnums() { const enums = await data_1.enumService.loadList({ query: { microServiceId: this.id, }, }); enums.forEach((item, index) => { dataTypeUtils_1.convert2RefType(item); enums[index] = item = new __1.Enum(item); item.assign({ dataNode: this.data, schemaRef: `#/${this.id}/${item.id}`, }); item.enumItemList.forEach((enumItem, index) => { enumItem = item.enumItemList[index] = new __1.EnumItem(enumItem); enumItem.assign({ root: item }); }); __1.dataTypesMap[item.schemaRef] = item; }); dataTypes_1.updateDataTypeList(); this.data.assign({ enums }); return enums; } /** * 加载所有流程 */ async loadProcesses() { const result = await process_1.default.loadAll({ query: { serviceId: this.id, }, }); const processes = result.map((process) => __1.Process.from(process, this)); this.assign({ processes }); this.mountResolverOnProcess(); return processes; } mountResolverOnProcess() { this.globalLogic.assign({ processLogics: this.processes }); } /** * 导入sql或其他需要同步entity */ async syncEntities() { const entities = await data_1.entityService.loadList({ query: { microServiceId: this.id, }, }); const newEntities = []; const syncEntities = []; entities.forEach((item, index) => { // 已存在的entity直接使用 const tempEntity = __1.vertexsMap.get(item.id); if (tempEntity) { newEntities[index] = tempEntity; } else { dataTypeUtils_1.convert2RefType(item); newEntities[index] = item = new __1.Entity(item); item.assign({ dataNode: this.data, schemaRef: `#/${this.id}/${item.id}`, }); const propertyList = item.propertyList; propertyList.sort((a, b) => a._posIndex - b._posIndex); propertyList.forEach((property, index) => { property = propertyList[index] = new __1.EntityProperty(property); property.assign({ root: item }); }); item.assign({ resolvers: [] }); const indexList = item.indexList; indexList.forEach((indexItem, index) => { indexItem = indexList[index] = new __1.EntityIndex(indexItem); indexItem.assign({ root: item }); }); __1.dataTypesMap[item.schemaRef] = item; syncEntities.push(item); } }); this.data.assign({ entities: newEntities }); const tasks = syncEntities.map((entity) => Promise.all([ // entity.syncStructures(), entity.syncInterfaces(), ])); await Promise.all(tasks).then(() => { dataTypes_1.updateDataTypeList(); this._onDataTypesChange(); this._saveVertexIdToName(); }); return newEntities; } async syncEntityPropertyVersion() { const entities = await data_1.entityService.loadList({ query: { microServiceId: this.id, }, }); entities.forEach((item, index) => { const tempEntity = __1.vertexsMap.get(item.id); if (tempEntity) { tempEntity.assign({ lastVersionDef: item.lastVersionDef }); } const lastVersionRef = item.lastVersionDef && item.lastVersionDef.properties || {}; const propertyList = tempEntity.propertyList; propertyList.forEach((property, index) => { property = __1.vertexsMap.get(property.id); if (property && lastVersionRef[property.name]) { property.assign({ lastVersion: dataTypeUtils_1.convert2RefType(lastVersionRef[property.name]) }); } }); }); } /** * 加载服务所有的接口列表 */ async loadInterfaces() { let interfaces = await data_1.interfaceService.loadList({ query: { serviceId: this.id, }, headers: { IdeVersion: 2.3, }, }); interfaces = interfaces.map((item) => __1.Interface.from(item, this)); interfaces.forEach((i) => { if (i.serviceType === 'export') { const logic = __1.Vertex.getVertexByRef(i.logicId); i.logic = logic; } }); this.assign({ interfaces }); this.mountResolverOnEntity(); this.mountResolverOnInterface(); // this.generateLogics(); return interfaces; } mountResolverOnEntity() { const RESOLVER_NAMES = ['getAll', 'get', 'create', 'update', 'delete', 'count', 'import', 'export', 'batchDelete', 'batchCreate', 'batchUpdate']; if (this.interfaces.length && this.data.entities.length) { const entityLogics = []; this.interfaces.forEach((item) => { if (item.logic && item.logic.entityId) { const entity = __1.Entity.getVertexByRef(item.logic.entityId); if (entity) entity.assign({ resolvers: entity.resolvers || [] }); const resolverName = RESOLVER_NAMES.find((name) => item.name.startsWith(name)); if (entity) { const exist = entity.resolvers.find((r) => r.name === resolverName); if (exist) { exist.interface = item; exist.entity = entity; } else { entity.resolvers.push({ level: 'resolver', name: resolverName, interface: item, entity, isLeaf: true, }); } item.entityId = entity.id; } } }); this.data.entities.forEach((entity) => { entityLogics.push(entity); }); this.globalLogic.assign({ entityLogics }); } } mountResolverOnInterface() { const globalLogics = []; const interfaces = []; const exportInterface = []; const exportLogicId = {}; // const categoryInterfaceMap = {}; // const categoryProccessMap = {}; this.interfaces.forEach((item) => { if (item.serviceType === 'micro') { globalLogics.push(item); } else if (item.serviceType === 'external') { const category = item.category; if (!category) { interfaces.push(item); } else { this.globalLogic.addCategoryInterface(item); // if (!categoryInterfaceMap[category]) { // categoryInterfaceMap[category] = []; // } // categoryInterfaceMap[category].push(item); } } else if (item.serviceType === 'export') { exportInterface.push(item); exportLogicId[item.logicId] = item; } }); // const categories = []; // Object.keys(categoryInterfaceMap).forEach((category) => { // categories.push({ // level: LEVEL_ENUM.category, // name: category, // categoryInterfaces: categoryInterfaceMap[category], // categoryStructures: [], // isLeaf: false, // expanded: false, // }); // }); const exportLogicIdList = Object.keys(exportLogicId); this.interfaces.forEach((item) => { if (exportLogicIdList.includes(item.logicId)) { item.exportedInterface = exportLogicId[item.logicId]; } }); this.globalLogic.assign({ globalLogics, interfaces }); } _onDataTypesChange() { __1.config.webFileCache && __1.generator.saveDataTypesCache(this.app); } _onEnumsChange() { __1.config.webFileCache && __1.generator.saveEnumsCache(this.app); } _onInterfacesChange() { __1.config.webFileCache && __1.generator.saveApisCache(this.app); __1.generator.saveInterfacesCache(this); } async _onVertexIdToNameChange(id, name) { if (!__1.config.webFileCache) return; if (id && name) { if (!vertexIdToName) { vertexIdToName = await __1.generator.loadVertexIdToName(this.app); vertexIdToName = vertexIdToName || {}; } if (vertexIdToName[id] === name) return; } // id 和 name 都没传时,跳过上一步的判断逻辑,直接更新 if ((id && name) || (!id && !name)) { this._saveVertexIdToName(); } } /** * 从后端 JSON 生成规范的 MicroService 对象 * @param source JSON * @param app 父级 App */ static from(source, app) { source.app = app; return new MicroService(source); } } __decorate([ decorators_1.immutable() ], MicroService.prototype, "type", void 0); __decorate([ decorators_1.immutable() ], MicroService.prototype, "packageName", void 0); __decorate([ decorators_1.immutable() ], MicroService.prototype, "serverPort", void 0); __decorate([ decorators_1.immutable() ], MicroService.prototype, "interfaces", void 0); __decorate([ decorators_1.immutable() ], MicroService.prototype, "processes", void 0); exports.MicroService = MicroService; exports.default = Service; //# sourceMappingURL=Service.js.map