@lcap/asl
Version:
NetEase Application Specific Language
266 lines (245 loc) • 7.69 kB
text/typescript
import { action, excludedInJSON, immutable } from '../decorators';
import { LEVEL_ENUM, vertexsMap, utils, EventEmitter } from '..';
import { at } from 'lodash';
import { findUsageService } from '../../service/common';
import { v4 as uuidv4 } from 'uuid';
/**
* 顶点类
* 属性均为只读,仅在初始化和 load 的情况下可以修改
*/
export class Vertex extends EventEmitter {
/**
* 可修改标志,内部属性
* 标记在构造函数结束后是否可修改
*/
()
protected _mutable = true;
/**
* 概念类型
*/
()
public readonly level: LEVEL_ENUM = LEVEL_ENUM.vertex;
/**
* toJSON 时需要去除的键,为了避免出现 CircularJSON
*/
()
protected readonly JSON_EXCLUDED_KEYS: Set<string>;
/**
* 顶点 id
*/
()
public readonly id: string = undefined;
/**
* 唯一 uuid
* 目前主要用于前端 Debug 区分两个实例
*/
()
public readonly _uuid: string = uuidv4();
/**
* 前端记录缓存的时间戳
*/
()
public readonly _cacheTimestamp: string = undefined;
/**
* 名称
*/
()
public readonly name: string;
/**
* 创建人
*/
()
public readonly createdBy: string = undefined;
/**
* 创建时间
*/
()
public readonly createdTime: string = undefined;
/**
* 修改人
*/
()
public readonly updatedBy: string = undefined;
/**
* 修改时间
*/
()
public readonly updatedTime: string = undefined;
/**
* IDE 版本
*/
()
public readonly ideVersion: string = undefined;
/**
* 是否可编辑
*/
public editable: boolean = true;
/**
* 是否正在编辑
* 前端 UI 状态
*/
()
public editing: boolean = false;
/**
* 是否正在请求
* 前端 UI 状态
*/
()
public loading: boolean = false;
/**
* 节点是否为展开状态
* 前端 UI 状态
*/
()
public expanded: boolean = false;
/**
* 是否为叶子节点
* 前端 UI 状态
*/
()
public isLeaf: boolean = false;
/**
* @param source 需要合并的部分参数
*/
constructor(source?: Partial<Vertex>) {
super();
if (typeof window !== 'undefined') {
const globalData = (window as any).globalData;
this.ideVersion = globalData && globalData.ideVersion;
} else {
this.ideVersion = '1.2';
}
source && this.assign(source);
if (this.hasOwnProperty('JSON_EXCLUDED_KEYS') && this.JSON_EXCLUDED_KEYS === undefined)
delete (this as any).JSON_EXCLUDED_KEYS;
}
assign(source: any) {
this._mutable = true;
const oldId = this.id;
Object.assign(this, source);
oldId && vertexsMap.delete(oldId);
this.id && vertexsMap.set(this.id, this);
this.emitVertexIdToNameChange();
this._mutable = false;
}
emitVertexIdToNameChange() {
if (typeof window === 'undefined')
return;
const { id, name } = this;
const service = window
&& (window as any).$data
&& (window as any).$data.app
&& (window as any).$data.app.firstMicroService;
if (service)
service.emit('vertexIdToNameChange', id, name);
}
plainAssign(source: any) {
this._mutable = true;
const oldId = this.id;
Object.keys(source).forEach((key) => {
const value = source[key];
if (typeof value !== 'object' && typeof value !== 'function')
(this as any)[key] = value;
});
oldId && vertexsMap.delete(oldId);
this.id && vertexsMap.set(this.id, this);
this.emitVertexIdToNameChange();
this._mutable = false;
}
pick(source: any, keys: Array<string> = []) {
const obj: { [name: string]: any } = {};
keys.forEach((key) => obj[key] = source[key]);
// 这里统一用 assign,集中处理 id 的问题
this.assign(obj);
}
/**
* 从对象中深度获取
* @param source
* @param keys
* @example 比如一般后端返回只是添加了个 id
* ```
* this.deepPick(result, ['id'])
*/
deepPick(source: any, keys: Array<string> = []) {
utils.traverse((current) => {
const subSource = current.jsonPath ? at(source, [current.jsonPath])[0] : source;
const target = current.jsonPath ? at(this as any, [current.jsonPath])[0] : this;
if (!target)
return;
const obj: { [name: string]: any } = {};
keys.forEach((key) => {
if (subSource.hasOwnProperty(key)) {
obj[key] = subSource[key];
}
});
// 这里统一用 assign,集中处理 id 的问题
target.assign ? target.assign(obj) : Object.assign(target, obj);
}, { node: source }, { mode: 'anyObject' });
}
/**
* 去除循环依赖,转为纯 JSON
* @param parentKey 外面的 key,提供给 JSON.stringify 使用
* @param excludedKeys 需要额外排除的 keys
*/
toJSON(parentKey?: string, excludedKeys: Array<string> = []): any {
const JSON_EXCLUDED_KEYS = new Set(this.JSON_EXCLUDED_KEYS || []); // Object.getPrototypeOf(this).constructor.JSON_EXCLUDED_KEYS || [];
excludedKeys.forEach((key) => JSON_EXCLUDED_KEYS.add(key));
const temp: { [prop: string]: any } = {};
Object.keys(this).forEach((key) => {
if (!JSON_EXCLUDED_KEYS.has(key))
temp[key] = (this as any)[key];
});
return JSON.parse(JSON.stringify(temp));
}
/**
* 转为单层的 JSON
* @param parentKey 外面的 key,提供给 JSON.stringify 使用
* @param excludedKeys 需要额外排除的 keys
*/
toPlainJSON(parentKey?: string, excludedKeys: Array<string> = []): any {
const JSON_EXCLUDED_KEYS = new Set(this.JSON_EXCLUDED_KEYS || []); // Object.getPrototypeOf(this).constructor.JSON_EXCLUDED_KEYS || [];
excludedKeys.forEach((key) => JSON_EXCLUDED_KEYS.add(key));
const temp: { [prop: string]: any } = {};
Object.keys(this).forEach((key) => {
const value = (this as any)[key];
if (!JSON_EXCLUDED_KEYS.has(key)
&& typeof value !== 'object' && typeof value !== 'function')
temp[key] = value;
});
return JSON.parse(JSON.stringify(temp));
}
/**
* 查找引用
*/
('查找引用')
async findUsage() {
const result = await findUsageService.findUsage({
query: {
id: this.id,
},
});
return result;
}
/**
* 销毁
* 从 Map 中删除点和子节点
*/
destroy() {
utils.traverse((current) => {
vertexsMap.delete(current.node.id);
}, { node: this }, {
mode: 'anyObject',
excludedKeySet: this.JSON_EXCLUDED_KEYS,
});
}
/**
* 通过 Ref 去查找点
* @param ref
*/
public static getVertexByRef(ref: string) {
const arr = ref.split('/');
const id = arr[arr.length - 1];
return vertexsMap.get(id);
}
}
export default Vertex;