mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-15 05:36:39 +00:00
initial
This commit is contained in:
parent
625cba310c
commit
ffeebdfad3
@ -1,5 +1,6 @@
|
||||
import Project from '../project';
|
||||
import { RootSchema, NodeData, isDOMText, isJSExpression } from '../schema';
|
||||
import Node from './node';
|
||||
|
||||
export default class DocumentContext {
|
||||
/**
|
||||
@ -65,7 +66,9 @@ export default class DocumentContext {
|
||||
/**
|
||||
* 插入一个节点
|
||||
*/
|
||||
insertNode(parent: Node, thing: Node | Schema, at?: number | null, copy?: boolean): Node;
|
||||
insertNode(parent: Node, thing: Node | Schema, at?: number | null, copy?: boolean): Node {
|
||||
|
||||
}
|
||||
/**
|
||||
* 移除一个节点
|
||||
*/
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { NodeSchema, isNodeSchema, NodeData, DOMText, JSExpression, PropsMap } from '../schema';
|
||||
import { obx } from '@recore/obx';
|
||||
import { NodeSchema, NodeData, PropsMap, PropsList } from '../schema';
|
||||
import Props, { Prop } from './props';
|
||||
import DocumentContext from './document-context';
|
||||
|
||||
/**
|
||||
* nodeSchema are:
|
||||
@ -18,6 +20,7 @@ import Props, { Prop } from './props';
|
||||
* .hidden
|
||||
* .locked
|
||||
*/
|
||||
const DIRECTIVES = ['condition', 'conditionGroup', 'loop', 'loopArgs', 'title', 'ignore', 'hidden', 'locked'];
|
||||
export default class Node {
|
||||
/**
|
||||
* 是节点实例
|
||||
@ -40,18 +43,26 @@ export default class Node {
|
||||
*/
|
||||
readonly componentName: string;
|
||||
|
||||
readonly props?: Props<Node>;
|
||||
readonly directives?: Props<Node>;
|
||||
readonly extras?: Props<Node>;
|
||||
|
||||
constructor(readonly document: DocumentContext, private nodeSchema: NodeSchema) {
|
||||
const { componentName, id, children, props, leadingComponents, ...directives } = nodeSchema;
|
||||
// clone
|
||||
const { componentName, id, children, props, ...extras } = nodeSchema;
|
||||
this.id = id || `node$${document.nextId()}`;
|
||||
this.componentName = componentName;
|
||||
if (this.isNodeParent()) {
|
||||
this._props = new Props(this, props);
|
||||
this._directives = new Props(this, directives as PropsMap);
|
||||
this.props = new Props(this, props);
|
||||
this.directives = new Props(this, {});
|
||||
Object.keys(extras).forEach(key => {
|
||||
this.directives!.add((extras as any)[key], key);
|
||||
delete (extras as any)[key];
|
||||
});
|
||||
this.extras = new Props(this, extras as any);
|
||||
if (children) {
|
||||
this._children = (Array.isArray(children) ? children : [children]).map(child => {
|
||||
const node = this.document.createNode(child);
|
||||
node.internalSetParent(this);
|
||||
node.internalSetParent(this as INodeParent);
|
||||
return node;
|
||||
});
|
||||
}
|
||||
@ -65,20 +76,20 @@ export default class Node {
|
||||
return this.componentName.charAt(0) !== '#';
|
||||
}
|
||||
|
||||
private _parent: Node | null = null;
|
||||
private _parent: INodeParent | null = null;
|
||||
|
||||
/**
|
||||
* 父级节点
|
||||
*/
|
||||
get parent(): Node | null {
|
||||
get parent(): INodeParent | null {
|
||||
return this._parent;
|
||||
}
|
||||
/**
|
||||
* 内部方法
|
||||
* 内部方法,请勿使用
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
internalSetParent(parent: Node | null) {
|
||||
internalSetParent(parent: INodeParent | null) {
|
||||
if (this._parent === parent) {
|
||||
return;
|
||||
}
|
||||
@ -108,34 +119,32 @@ export default class Node {
|
||||
*/
|
||||
get children(): Node[] | null {
|
||||
if (this.purged) {
|
||||
return [];
|
||||
}
|
||||
if (this._children) {
|
||||
return this._children;
|
||||
return null;
|
||||
}
|
||||
return this._children;
|
||||
}
|
||||
|
||||
/*
|
||||
@obx.ref get component(): ReactType {
|
||||
return this.document.getComponent(this.tagName);
|
||||
}
|
||||
@obx.ref get prototype(): Prototype {
|
||||
return this.document.getPrototype(this.component, this.tagName);
|
||||
}
|
||||
*/
|
||||
|
||||
@obx.ref get props(): object {
|
||||
@obx.ref get propsData(): PropsMap | PropsList | null {
|
||||
if (!this.isNodeParent() || this.componentName === 'Fragment') {
|
||||
return {};
|
||||
return null;
|
||||
}
|
||||
// ...
|
||||
return this.props?.value || null;
|
||||
}
|
||||
|
||||
private _directives: any = {};
|
||||
get directives() {
|
||||
return {
|
||||
condition: this.condition,
|
||||
conditionGroup: this.conditionGroup,
|
||||
loop: '',
|
||||
};
|
||||
get directivesData(): PropsMap | null {
|
||||
if (!this.isNodeParent()) {
|
||||
return null;
|
||||
}
|
||||
return this.directives?.value as PropsMap || null;
|
||||
}
|
||||
|
||||
private _conditionGroup: string | null = null;
|
||||
@ -171,6 +180,8 @@ export default class Node {
|
||||
return this._condition;
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO
|
||||
// 外部修改,merge 进来,产生一次可恢复的历史数据
|
||||
merge(data: ElementData) {
|
||||
this.elementData = data;
|
||||
@ -197,15 +208,14 @@ export default class Node {
|
||||
this.children.splice(data.length).forEach(child => child.purge());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
getProp(path: string): Prop;
|
||||
getProp(path: string, useStash: true): Prop;
|
||||
getProp(path: string, useStash = true): Prop | null {
|
||||
return this._props!.query(path, useStash)!;
|
||||
getProp(path: string, useStash: boolean = true): Prop | null {
|
||||
return this.props?.query(path, useStash as any) || null;
|
||||
}
|
||||
|
||||
getProps(): Props {
|
||||
return this._props;
|
||||
getDirective(name: string, useStash: boolean = true): Prop | null {
|
||||
return this.directives?.get(name, useStash as any) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,7 +323,9 @@ export default class Node {
|
||||
return;
|
||||
}
|
||||
this.purged = true;
|
||||
this.children.forEach(child => child.purge());
|
||||
if (this._children) {
|
||||
this._children.forEach(child => child.purge());
|
||||
}
|
||||
// TODO: others dispose...
|
||||
}
|
||||
}
|
||||
|
||||
@ -450,8 +450,8 @@ export function isProp(obj: any): obj is Prop {
|
||||
return obj && obj.isProp;
|
||||
}
|
||||
|
||||
export default class Props<T> implements IPropParent {
|
||||
@obx.val private readonly items: Prop[] = [];
|
||||
export default class Props<O = any> implements IPropParent {
|
||||
@obx.val private items: Prop[] = [];
|
||||
@obx.ref private get maps(): Map<string, Prop> {
|
||||
const maps = new Map();
|
||||
if (this.items.length > 0) {
|
||||
@ -474,32 +474,64 @@ export default class Props<T> implements IPropParent {
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 元素个数
|
||||
*/
|
||||
get size() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
private _type: 'map' | 'list' | 'unset' = 'unset';
|
||||
@computed get value(): PropsMap | PropsList | null {
|
||||
if (this.items.length < 1) {
|
||||
return null;
|
||||
}
|
||||
if (this.type === 'list') {
|
||||
return this.items.map(item => ({
|
||||
spread: item.spread,
|
||||
name: item.key as string,
|
||||
value: item.value,
|
||||
}));
|
||||
}
|
||||
const maps: any = {};
|
||||
this.items.forEach(prop => {
|
||||
if (prop.key) {
|
||||
maps[prop.key] = prop.value;
|
||||
}
|
||||
});
|
||||
return maps;
|
||||
}
|
||||
|
||||
constructor(owner: T, value?: PropsMap | PropsList | null) {
|
||||
if (value == null) {
|
||||
this._type = 'unset';
|
||||
} else if (Array.isArray(value)) {
|
||||
this._type = 'list';
|
||||
@obx type: 'map' | 'list' = 'map';
|
||||
|
||||
constructor(readonly owner: O, value?: PropsMap | PropsList | null) {
|
||||
if (Array.isArray(value)) {
|
||||
this.type = 'list';
|
||||
value.forEach(item => {});
|
||||
} else {
|
||||
this._type = 'map';
|
||||
} else if (value != null) {
|
||||
this.type = 'map';
|
||||
}
|
||||
}
|
||||
|
||||
delete(prop: Prop) {
|
||||
const i = this.items.indexOf(prop);
|
||||
if (i > -1) {
|
||||
this.items.splice(i, 1);
|
||||
prop.purge();
|
||||
}
|
||||
}
|
||||
|
||||
query(path: string, useStash = true) {
|
||||
/**
|
||||
* 根据 path 路径查询属性,如果没有则临时生成一个
|
||||
*/
|
||||
query(path: string): Prop;
|
||||
/**
|
||||
* 根据 path 路径查询属性
|
||||
*
|
||||
* @useStash 如果没有则临时生成一个
|
||||
*/
|
||||
query(path: string, useStash: true): Prop;
|
||||
/**
|
||||
* 根据 path 路径查询属性
|
||||
*/
|
||||
query(path: string, useStash: false): Prop | null;
|
||||
/**
|
||||
* 根据 path 路径查询属性
|
||||
*
|
||||
* @useStash 如果没有则临时生成一个
|
||||
*/
|
||||
query(path: string, useStash: boolean = true) {
|
||||
let matchedLength = 0;
|
||||
let firstMatched = null;
|
||||
if (this.items) {
|
||||
@ -537,16 +569,109 @@ export default class Props<T> implements IPropParent {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个属性, 如果不存在,临时获取一个待写入
|
||||
* @param useStash 强制
|
||||
*/
|
||||
get(path: string, useStash: true): Prop;
|
||||
/**
|
||||
* 获取某个属性
|
||||
* @param useStash 强制
|
||||
*/
|
||||
get(path: string, useStash: false): Prop | null;
|
||||
/**
|
||||
* 获取某个属性
|
||||
*/
|
||||
get(path: string): Prop | null;
|
||||
get(name: string, useStash = false) {
|
||||
return this.maps.get(name) || (useStash && this.stash.get(name)) || null;
|
||||
}
|
||||
|
||||
add(value: CompositeValue | null, key?: string | number, spread = false) {
|
||||
/**
|
||||
* 删除项
|
||||
*/
|
||||
delete(prop: Prop): void {
|
||||
const i = this.items.indexOf(prop);
|
||||
if (i > -1) {
|
||||
this.items.splice(i, 1);
|
||||
prop.purge();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 key
|
||||
*/
|
||||
deleteKey(key: string): void {
|
||||
this.items = this.items.filter(item => {
|
||||
if (item.key === key) {
|
||||
item.purge();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加值
|
||||
*/
|
||||
add(value: CompositeValue | null, key?: string | number, spread = false): Prop {
|
||||
const prop = new Prop(this, value, key, spread);
|
||||
this.items.push(prop);
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在 key
|
||||
*/
|
||||
has(key: string): boolean {
|
||||
return this.maps.has(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代器
|
||||
*/
|
||||
[Symbol.iterator](): { next(): { value: Prop } } {
|
||||
let index = 0;
|
||||
const items = this.items;
|
||||
const length = items.length || 0;
|
||||
return {
|
||||
next() {
|
||||
if (index < length) {
|
||||
return {
|
||||
value: items[index++],
|
||||
done: false,
|
||||
};
|
||||
}
|
||||
return {
|
||||
value: undefined as any,
|
||||
done: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历
|
||||
*/
|
||||
forEach(fn: (item: Prop, key: number | string | undefined) => void): void {
|
||||
this.items.forEach(item => {
|
||||
return fn(item, item.key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历
|
||||
*/
|
||||
map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null {
|
||||
return this.items.map(item => {
|
||||
return fn(item, item.key);
|
||||
});
|
||||
}
|
||||
|
||||
private purged = false;
|
||||
/**
|
||||
* 回收销毁
|
||||
*/
|
||||
purge() {
|
||||
if (this.purged) {
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user