@lcap/asl
Version:
NetEase Application Specific Language
846 lines • 30.8 kB
JavaScript
"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//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//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//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//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