diff --git a/.eslintrc.js b/.eslintrc.js index a74dc274e..1ec3834e6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -48,5 +48,9 @@ module.exports = { "afterLineComment": false, "allowBlockStart": true, }], + "@typescript-eslint/member-ordering": [ + "error", + { "default": ["signature", "field", "constructor", "method"] } + ], } -}; +}; \ No newline at end of file diff --git a/docs/docs/api/model/props.md b/docs/docs/api/model/props.md index 5956a14b7..f76919d49 100644 --- a/docs/docs/api/model/props.md +++ b/docs/docs/api/model/props.md @@ -13,46 +13,148 @@ sidebar_position: 4 ### id id + +`@type {string}` + + ### path 返回当前 props 的路径 + +`@type {string[]}` + + ### node 返回当前属性集所属的节点实例 +`@type {IPublicModelNode | null}` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ## 方法签名 ### getProp -getProp(path: string): Prop | null - 获取指定 path 的属性模型实例 +```typescript +/** + * 获取指定 path 的属性模型实例 + * get prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ +getProp(path: string): IPublicModelProp | null; +``` + +相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts) + ### getPropValue -getPropValue(path: string) - 获取指定 path 的属性模型实例值 +```typescript +/** + * 获取指定 path 的属性模型实例值 + * get value of prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ +getPropValue(path: string): any; +``` + ### getExtraProp -getExtraProp(path: string): Prop | null - 获取指定 path 的属性模型实例,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 +```typescript +/** + * 获取指定 path 的属性模型实例, + * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * get extra prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ +getExtraProp(path: string): IPublicModelProp | null; +``` + +相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts) + ### getExtraPropValue -getExtraPropValue(path: string) - 获取指定 path 的属性模型实例值,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 +```typescript +/** + * 获取指定 path 的属性模型实例值 + * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * get value of extra prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ +getExtraPropValue(path: string): any; +``` + ### setPropValue -setPropValue(path: string, value: CompositeValue) - 设置指定 path 的属性模型实例值 +```typescript +/** + * 设置指定 path 的属性模型实例值 + * set value of prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param value 值 + */ +setPropValue(path: string, value: IPublicTypeCompositeValue): void; +``` + +相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts) + ### setExtraPropValue -setExtraPropValue(path: string, value: CompositeValue) +设置指定 path 的属性模型实例值 -设置指定 path 的属性模型实例值 \ No newline at end of file +```typescript +/** + * 设置指定 path 的属性模型实例值 + * set value of extra prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param value 值 + */ +setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void; +``` + +相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts) + + +### has + +当前 props 是否包含某 prop + +```typescript +/** + * 当前 props 是否包含某 prop + * check if the specified key is existing or not. + * @param key + * @since v1.1.0 + */ +has(key: string): boolean; +``` + +**@since v1.1.0** + +### add + +添加一个 prop + +```typescript +/** + * 添加一个 prop + * add a key with given value + * @param value + * @param key + * @since v1.1.0 + */ +add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any; +``` + +相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts) + +**@since v1.1.0** \ No newline at end of file diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 76354bc97..642783588 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -2,7 +2,7 @@ import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, r import { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicEnumTransformStage, IPublicModelProp } from '@alilc/lowcode-types'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils'; import { valueToSource } from './value-to-source'; -import { Props } from './props'; +import { Props, IProps, IPropParent } from './props'; import { SlotNode, INode } from '../node'; // import { TransformStage } from '../transform-stage'; @@ -13,12 +13,12 @@ export type UNSET = typeof UNSET; export interface IProp extends Omit { - delete(prop: Prop): void; - readonly props: Props; readonly owner: INode; + delete(prop: Prop): void; + export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue; getNode(): INode; @@ -26,7 +26,7 @@ export interface IProp extends Omit { export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot'; -export class Prop implements IProp { +export class Prop implements IProp, IPropParent { readonly isProp = true; readonly owner: INode; @@ -45,8 +45,152 @@ export class Prop implements IProp { readonly options: any; + readonly id = uniqueId('prop$'); + + @obx.ref private _type: ValueTypes = 'unset'; + + /** + * 属性类型 + */ + get type(): ValueTypes { + return this._type; + } + + @obx private _value: any = UNSET; + + /** + * 属性值 + */ + @computed get value(): IPublicTypeCompositeValue | UNSET { + return this.export(IPublicEnumTransformStage.Serilize); + } + + private _code: string | null = null; + + /** + * 获得表达式值 + */ + @computed get code() { + if (isJSExpression(this.value)) { + return this.value.value; + } + // todo: JSFunction ... + if (this.type === 'slot') { + return JSON.stringify(this._slotNode!.export(IPublicEnumTransformStage.Save)); + } + return this._code != null ? this._code : JSON.stringify(this.value); + } + + /** + * 设置表达式值 + */ + set code(code: string) { + if (isJSExpression(this._value)) { + this.setValue({ + ...this._value, + value: code, + }); + this._code = code; + return; + } + + try { + const v = JSON.parse(code); + this.setValue(v); + this._code = code; + return; + } catch (e) { + // ignore + } + + this.setValue({ + type: 'JSExpression', + value: code, + mock: this._value, + }); + this._code = code; + } + + private _slotNode?: INode; + + get slotNode(): INode | undefined | null { + return this._slotNode; + } + + @obx.shallow private _items: Prop[] | null = null; + + @obx.shallow private _maps: Map | null = null; + + /** + * 作为 _maps 的一层缓存机制,主要是复用部分已存在的 Prop,保持响应式关系,比如: + * 当前 Prop#_value 值为 { a: 1 },当调用 setValue({ a: 2 }) 时,所有原来的子 Prop 均被销毁, + * 导致假如外部有 mobx reaction(常见于 observer),此时响应式链路会被打断, + * 因为 reaction 监听的是原 Prop(a) 的 _value,而不是新 Prop(a) 的 _value。 + */ + private _prevMaps: Map | null = null; + + /** + * 构造 items 属性,同时构造 maps 属性 + */ + private get items(): Prop[] | null { + if (this._items) return this._items; + return runInAction(() => { + let items: Prop[] | null = null; + if (this._type === 'list') { + const data = this._value; + data.forEach((item: any, idx: number) => { + items = items || []; + items.push(new Prop(this, item, idx)); + }); + this._maps = null; + } else if (this._type === 'map') { + const data = this._value; + const maps = new Map(); + const keys = Object.keys(data); + for (const key of keys) { + let prop: Prop; + if (this._prevMaps?.has(key)) { + prop = this._prevMaps.get(key)!; + prop.setValue(data[key]); + } else { + prop = new Prop(this, data[key], key); + } + items = items || []; + items.push(prop); + maps.set(key, prop); + } + this._maps = maps; + } else { + items = null; + this._maps = null; + } + this._items = items; + return this._items; + }); + } + + @computed private get maps(): Map | null { + if (!this.items) { + return null; + } + return this._maps; + } + + get path(): string[] { + return (this.parent.path || []).concat(this.key as string); + } + + /** + * 元素个数 + */ + get size(): number { + return this.items?.length || 0; + } + + private purged = false; + constructor( - public parent: IProp, + public parent: IPropParent, value: IPublicTypeCompositeValue | UNSET = UNSET, key?: string | number, spread = false, @@ -94,26 +238,6 @@ export class Prop implements IProp { this.get(propName, false)?.unset(); } - readonly id = uniqueId('prop$'); - - @obx.ref private _type: ValueTypes = 'unset'; - - /** - * 属性类型 - */ - get type(): ValueTypes { - return this._type; - } - - @obx private _value: any = UNSET; - - /** - * 属性值 - */ - @computed get value(): IPublicTypeCompositeValue | UNSET { - return this.export(IPublicEnumTransformStage.Serilize); - } - export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): IPublicTypeCompositeValue { stage = compatStage(stage); const type = this._type; @@ -186,52 +310,6 @@ export class Prop implements IProp { } } - private _code: string | null = null; - - /** - * 获得表达式值 - */ - @computed get code() { - if (isJSExpression(this.value)) { - return this.value.value; - } - // todo: JSFunction ... - if (this.type === 'slot') { - return JSON.stringify(this._slotNode!.export(IPublicEnumTransformStage.Save)); - } - return this._code != null ? this._code : JSON.stringify(this.value); - } - - /** - * 设置表达式值 - */ - set code(code: string) { - if (isJSExpression(this._value)) { - this.setValue({ - ...this._value, - value: code, - }); - this._code = code; - return; - } - - try { - const v = JSON.parse(code); - this.setValue(v); - this._code = code; - return; - } catch (e) { - // ignore - } - - this.setValue({ - type: 'JSExpression', - value: code, - mock: this._value, - }); - this._code = code; - } - getAsString(): string { if (this.type === 'literal') { return this._value ? String(this._value) : ''; @@ -311,12 +389,6 @@ export class Prop implements IProp { } } - private _slotNode?: INode; - - get slotNode(): INode | undefined | null { - return this._slotNode; - } - @action setAsSlot(data: IPublicTypeJSSlot) { this._type = 'slot'; @@ -397,69 +469,6 @@ export class Prop implements IProp { return this.code === other.code ? 0 : 2; } - @obx.shallow private _items: Prop[] | null = null; - - @obx.shallow private _maps: Map | null = null; - - /** - * 作为 _maps 的一层缓存机制,主要是复用部分已存在的 Prop,保持响应式关系,比如: - * 当前 Prop#_value 值为 { a: 1 },当调用 setValue({ a: 2 }) 时,所有原来的子 Prop 均被销毁, - * 导致假如外部有 mobx reaction(常见于 observer),此时响应式链路会被打断, - * 因为 reaction 监听的是原 Prop(a) 的 _value,而不是新 Prop(a) 的 _value。 - */ - private _prevMaps: Map | null = null; - - get path(): string[] { - return (this.parent.path || []).concat(this.key as string); - } - - /** - * 构造 items 属性,同时构造 maps 属性 - */ - private get items(): Prop[] | null { - if (this._items) return this._items; - return runInAction(() => { - let items: Prop[] | null = null; - if (this._type === 'list') { - const data = this._value; - data.forEach((item: any, idx: number) => { - items = items || []; - items.push(new Prop(this, item, idx)); - }); - this._maps = null; - } else if (this._type === 'map') { - const data = this._value; - const maps = new Map(); - const keys = Object.keys(data); - for (const key of keys) { - let prop: Prop; - if (this._prevMaps?.has(key)) { - prop = this._prevMaps.get(key)!; - prop.setValue(data[key]); - } else { - prop = new Prop(this, data[key], key); - } - items = items || []; - items.push(prop); - maps.set(key, prop); - } - this._maps = maps; - } else { - items = null; - this._maps = null; - } - this._items = items; - return this._items; - }); - } - - @computed private get maps(): Map | null { - if (!this.items) { - return null; - } - return this._maps; - } - /** * 获取某个属性 * @param createIfNone 当没有的时候,是否创建一个 @@ -552,13 +561,6 @@ export class Prop implements IProp { } } - /** - * 元素个数 - */ - get size(): number { - return this.items?.length || 0; - } - /** * 添加值到列表 * @@ -648,8 +650,6 @@ export class Prop implements IProp { return hasOwnProperty(this._value, key); } - private purged = false; - /** * 回收销毁 */ diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index 95f29f79a..56c1e7711 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -1,8 +1,8 @@ import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-core'; -import { IPublicTypePropsMap, IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage } from '@alilc/lowcode-types'; +import { IPublicTypePropsMap, IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IPublicModelProps } from '@alilc/lowcode-types'; import { uniqueId, compatStage } from '@alilc/lowcode-utils'; import { Prop, IProp, UNSET } from './prop'; -import { Node } from '../node'; +import { INode, Node } from '../node'; // import { TransformStage } from '../transform-stage'; interface ExtrasObject { @@ -23,7 +23,30 @@ export function getConvertedExtraKey(key: string): string { export function getOriginalExtraKey(key: string): string { return key.replace(new RegExp(`${EXTRA_KEY_PREFIX}`, 'g'), ''); } -export class Props implements IProp { + +export interface IPropParent { + + readonly props: Props; + + readonly owner: INode; + + get path(): string[]; + + delete(prop: Prop): void; + +} + +export interface IProps extends Omit { + + /** + * 获取 props 对应的 node + */ + getNode(): INode; + + getProp(path: string): IProp | null; +} + +export class Props implements IProps, IPropParent { readonly id = uniqueId('props'); @obx.shallow private items: Prop[] = []; @@ -46,7 +69,7 @@ export class Props implements IProp { return this; } - readonly owner: Node; + readonly owner: INode; /** * 元素个数 @@ -57,7 +80,9 @@ export class Props implements IProp { @obx type: 'map' | 'list' = 'map'; - constructor(owner: Node, value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject) { + private purged = false; + + constructor(owner: INode, value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject) { makeObservable(this); this.owner = owner; if (Array.isArray(value)) { @@ -196,7 +221,7 @@ export class Props implements IProp { } /** - * 获取某个属性, 如果不存在,临时获取一个待写入 + * 获取某个属性,如果不存在,临时获取一个待写入 * @param createIfNone 当没有的时候,是否创建一个 */ @action @@ -323,8 +348,6 @@ export class Props implements IProp { }); } - private purged = false; - /** * 回收销毁 */ diff --git a/packages/shell/src/model/props.ts b/packages/shell/src/model/props.ts index 801ee39bd..98d0ef143 100644 --- a/packages/shell/src/model/props.ts +++ b/packages/shell/src/model/props.ts @@ -1,8 +1,8 @@ -import { IProp as InnerProps, getConvertedExtraKey } from '@alilc/lowcode-designer'; +import { IProps as InnerProps, getConvertedExtraKey } from '@alilc/lowcode-designer'; import { IPublicTypeCompositeValue, IPublicModelProps, IPublicModelNode, IPublicModelProp } from '@alilc/lowcode-types'; import { propsSymbol } from '../symbols'; -import { Node } from './node'; -import { Prop } from './prop'; +import { Node as ShellNode } from './node'; +import { Prop as ShellProp } from './prop'; export class Props implements IPublicModelProps { private readonly [propsSymbol]: InnerProps; @@ -36,7 +36,7 @@ export class Props implements IPublicModelProps { * 返回所属的 node 实例 */ get node(): IPublicModelNode | null { - return Node.create(this[propsSymbol].getNode()); + return ShellNode.create(this[propsSymbol].getNode()); } /** @@ -45,7 +45,7 @@ export class Props implements IPublicModelProps { * @returns */ getProp(path: string): IPublicModelProp | null { - return Prop.create(this[propsSymbol].getProp(path)); + return ShellProp.create(this[propsSymbol].getProp(path)); } /** @@ -64,7 +64,7 @@ export class Props implements IPublicModelProps { * @returns */ getExtraProp(path: string): IPublicModelProp | null { - return Prop.create(this[propsSymbol].getProp(getConvertedExtraKey(path))); + return ShellProp.create(this[propsSymbol].getProp(getConvertedExtraKey(path))); } /** diff --git a/packages/types/src/shell/model/props.ts b/packages/types/src/shell/model/props.ts index 8d01ade13..9c862a008 100644 --- a/packages/types/src/shell/model/props.ts +++ b/packages/types/src/shell/model/props.ts @@ -2,6 +2,7 @@ import { IPublicTypeCompositeValue } from '../type'; import { IPublicModelNode, IPublicModelProp } from './'; export interface IPublicModelProps { + /** * id */ @@ -9,8 +10,9 @@ export interface IPublicModelProps { /** * 返回当前 props 的路径 + * return path of current props */ - get path(): any[]; + get path(): string[]; /** * 返回所属的 node 实例 @@ -19,62 +21,64 @@ export interface IPublicModelProps { /** * 获取指定 path 的属性模型实例 + * get prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 - * @returns */ getProp(path: string): IPublicModelProp | null; /** * 获取指定 path 的属性模型实例值 + * get value of prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 - * @returns */ getPropValue(path: string): any; /** * 获取指定 path 的属性模型实例, * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * get extra prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 - * @returns */ getExtraProp(path: string): IPublicModelProp | null; /** * 获取指定 path 的属性模型实例值 * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * get value of extra prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 - * @returns */ getExtraPropValue(path: string): any; /** * 设置指定 path 的属性模型实例值 + * set value of prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param value 值 - * @returns */ setPropValue(path: string, value: IPublicTypeCompositeValue): void; /** * 设置指定 path 的属性模型实例值 + * set value of extra prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param value 值 - * @returns */ setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void; /** - * test if the specified key is existing or not. + * 当前 props 是否包含某 prop + * check if the specified key is existing or not. * @param key - * @returns + * @since v1.1.0 */ has(key: string): boolean; /** + * 添加一个 prop * add a key with given value * @param value * @param key - * @returns + * @since v1.1.0 */ add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any;