aboutsummaryrefslogtreecommitdiff
path: root/src/fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields')
-rw-r--r--src/fields/Doc.ts8
-rw-r--r--src/fields/FieldSymbols.ts24
-rw-r--r--src/fields/Proxy.ts17
-rw-r--r--src/fields/ScriptField.ts16
-rw-r--r--src/fields/util.ts76
5 files changed, 63 insertions, 78 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 51313a8df..6762665a2 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -276,7 +276,7 @@ export class Doc extends RefField {
}
constructor(id?: FieldId, forceSave?: boolean) {
super(id);
- const doc = new Proxy<this>(this, {
+ const docProxy = new Proxy<this>(this, {
set: setter,
get: getter,
// getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter
@@ -305,11 +305,11 @@ export class Doc extends RefField {
throw new Error("Currently properties can't be defined on documents using Object.defineProperty");
},
});
- this[SelfProxy] = doc;
+ this[SelfProxy] = docProxy;
if (!id || forceSave) {
- DocServer.CreateField(doc);
+ DocServer.CreateField(docProxy);
}
- return doc;
+ return docProxy;
}
proto: Opt<Doc>;
diff --git a/src/fields/FieldSymbols.ts b/src/fields/FieldSymbols.ts
index 8d040f493..e50c2856f 100644
--- a/src/fields/FieldSymbols.ts
+++ b/src/fields/FieldSymbols.ts
@@ -1,12 +1,12 @@
-
-export const Update = Symbol("Update");
-export const Self = Symbol("Self");
-export const SelfProxy = Symbol("SelfProxy");
-export const HandleUpdate = Symbol("HandleUpdate");
-export const Id = Symbol("Id");
-export const OnUpdate = Symbol("OnUpdate");
-export const Parent = Symbol("Parent");
-export const Copy = Symbol("Copy");
-export const ToScriptString = Symbol("ToScriptString");
-export const ToPlainText = Symbol("ToPlainText");
-export const ToString = Symbol("ToString");
+export const Update = Symbol('Update');
+export const Self = Symbol('Self');
+export const SelfProxy = Symbol('SelfProxy');
+export const HandleUpdate = Symbol('HandleUpdate');
+export const Id = Symbol('Id');
+export const OnUpdate = Symbol('OnUpdate');
+export const Parent = Symbol('Parent');
+export const Copy = Symbol('Copy');
+export const ToValue = Symbol('ToValue');
+export const ToScriptString = Symbol('ToScriptString');
+export const ToPlainText = Symbol('ToPlainText');
+export const ToString = Symbol('ToString');
diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts
index 1266e6e3c..55d1d9ea4 100644
--- a/src/fields/Proxy.ts
+++ b/src/fields/Proxy.ts
@@ -5,9 +5,8 @@ import { observable, action, runInAction, computed } from 'mobx';
import { DocServer } from '../client/DocServer';
import { RefField } from './RefField';
import { ObjectField } from './ObjectField';
-import { Id, Copy, ToScriptString, ToString } from './FieldSymbols';
+import { Id, Copy, ToScriptString, ToString, ToValue } from './FieldSymbols';
import { scriptingGlobal } from '../client/util/ScriptingGlobals';
-import { Plugins } from './util';
function deserializeProxy(field: any) {
if (!field.cache.field) {
@@ -30,6 +29,10 @@ export class ProxyField<T extends RefField> extends ObjectField {
}
}
+ [ToValue](doc: any) {
+ return ProxyField.toValue(this);
+ }
+
[Copy]() {
if (this.cache.field) return new ProxyField<T>(this.cache.field);
return new ProxyField<T>(this.fieldId);
@@ -105,12 +108,10 @@ export namespace ProxyField {
}
}
- export function initPlugin() {
- Plugins.addGetterPlugin((doc, _, value) => {
- if (useProxy && value instanceof ProxyField) {
- return { value: value.value };
- }
- });
+ export function toValue(value: any) {
+ if (useProxy) {
+ return { value: value.value };
+ }
}
}
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index 4896c027d..b23732b45 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -6,11 +6,10 @@ import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGloba
import { autoObject, Deserializable } from '../client/util/SerializationHelper';
import { numberRange } from '../Utils';
import { Doc, Field, Opt } from './Doc';
-import { Copy, Id, ToScriptString, ToString } from './FieldSymbols';
+import { Copy, Id, ToScriptString, ToString, ToValue } from './FieldSymbols';
import { List } from './List';
import { ObjectField } from './ObjectField';
import { Cast, StrCast } from './Types';
-import { Plugins } from './util';
function optional(propSchema: PropSchema) {
return custom(
@@ -175,6 +174,9 @@ export class ComputedField extends ScriptField {
value = computedFn((doc: Doc) => this._valueOutsideReaction(doc));
_valueOutsideReaction = (doc: Doc) => (this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult, _readOnly_: true }, console.log).result);
+ [ToValue](doc: Doc) {
+ return ComputedField.toValue(doc, this);
+ }
[Copy](): ObjectField {
return new ComputedField(this.script, this.setterscript, this.rawscript);
}
@@ -239,12 +241,10 @@ export namespace ComputedField {
}
}
- export function initPlugin() {
- Plugins.addGetterPlugin((doc, _, value) => {
- if (useComputed && value instanceof ComputedField) {
- return { value: value._valueOutsideReaction(doc), shouldReturn: true };
- }
- });
+ export function toValue(doc: any, value: any) {
+ if (useComputed) {
+ return { value: value._valueOutsideReaction(doc) };
+ }
}
}
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 51c76b19a..285cbb4c6 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,4 +1,4 @@
-import { action, observable, runInAction, trace } from 'mobx';
+import { $mobx, action, observable, runInAction, trace } from 'mobx';
import { computedFn } from 'mobx-utils';
import { DocServer } from '../client/DocServer';
import { CollectionViewType } from '../client/documents/DocumentTypes';
@@ -28,7 +28,7 @@ import {
UpdatingFromServer,
WidthSym,
} from './Doc';
-import { Id, OnUpdate, Parent, Self, SelfProxy, Update } from './FieldSymbols';
+import { Id, OnUpdate, Parent, SelfProxy, ToValue, Update } from './FieldSymbols';
import { List } from './List';
import { ObjectField } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
@@ -47,19 +47,6 @@ export function TraceMobx() {
tracing && trace();
}
-export interface GetterResult {
- value: FieldResult;
- shouldReturn?: boolean;
-}
-export type GetterPlugin = (receiver: any, prop: string | number, currentValue: any) => GetterResult | undefined;
-const getterPlugins: GetterPlugin[] = [];
-
-export namespace Plugins {
- export function addGetterPlugin(plugin: GetterPlugin) {
- getterPlugins.push(plugin);
- }
-}
-
const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
if (SerializationHelper.IsSerializing()) {
target[prop] = value;
@@ -353,47 +340,44 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
return _setter(target, prop, value, receiver);
}
-export function getter(target: any, in_prop: string | symbol, receiver: any): any {
- if (in_prop === 'constructor' || in_prop === 'toString' || in_prop === 'valueOf' || in_prop === 'factory' || in_prop === 'serializeInfo') return target[in_prop];
- if (in_prop === 'then') return undefined; //If we're being awaited
- if (in_prop === AclSym) return target[AclSym];
- if (in_prop === LayoutSym) return target.__LAYOUT__;
- if ((in_prop === HeightSym || in_prop === WidthSym) && GetEffectiveAcl(target) === AclPrivate) return returnZero;
- if (typeof in_prop === 'symbol' || in_prop.startsWith('isMobX') || in_prop.startsWith('__')) return target.__fields[in_prop] || target[in_prop];
- if (GetEffectiveAcl(target) === AclPrivate) {
- if (in_prop === 'author') return target.__fields[in_prop] || target[in_prop];
- return undefined;
+export function getter(target: any, prop: string | symbol, proxy: any): any {
+ // prettier-ignore
+ switch (prop) {
+ case 'then' : return undefined;
+ case '__fields' : case '__id':
+ case 'constructor': case 'toString': case 'valueOf':
+ case 'factory': case 'serializeInfo':
+ return target[prop];
+ case AclSym : return target[AclSym];
+ case $mobx: return target.__fields[prop];
+ case LayoutSym: return target.__Layout__;
+ case HeightSym: case WidthSym: if (GetEffectiveAcl(target) === AclPrivate) return returnZero;
+ default :
+ if (typeof prop === 'symbol') return target[prop];
+ if (prop.startsWith('isMobX')) return target[prop];
+ if (prop.startsWith('__')) return target[prop];
+ if (GetEffectiveAcl(target) === AclPrivate && prop !== 'author') return undefined;
}
- const prop = in_prop.startsWith('_') ? in_prop.substring(1) : in_prop;
- if (prop !== in_prop && target.__LAYOUT__) return target.__LAYOUT__[prop];
- if (SerializationHelper.IsSerializing()) return target[prop];
- return getFieldImpl(target, prop, receiver);
+ const layout_prop = prop.startsWith('_') ? prop.substring(1) : undefined;
+ if (layout_prop && target.__LAYOUT__) return target.__LAYOUT__[layout_prop];
+ return getFieldImpl(target, layout_prop ?? prop, proxy);
}
-function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any {
- receiver = receiver || target[SelfProxy];
- let field = target.__fields[prop];
- for (const plugin of getterPlugins) {
- const res = plugin(receiver, prop, field);
- if (res === undefined) continue;
- if (res.shouldReturn) {
- return res.value;
- } else {
- field = res.value;
- }
- }
- if (field === undefined && !ignoreProto && prop !== 'proto') {
- const proto = getFieldImpl(target, 'proto', receiver, true); //TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters
+function getFieldImpl(target: any, prop: string | number, proxy: any, ignoreProto: boolean = false): any {
+ const field = target.__fields[prop];
+ const value = field?.[ToValue]?.(proxy); // converts ComputedFields to values, or unpacks ProxyFields into Proxys
+ if (value) return value.value;
+ if (!field && !ignoreProto && prop !== 'proto') {
+ const proto = getFieldImpl(target, 'proto', proxy, true); //TODO tfs: instead of proxy we could use target[SelfProxy]... I don't which semantics we want or if it really matters
if (proto instanceof Doc && GetEffectiveAcl(proto) !== AclPrivate) {
- return getFieldImpl(proto[Self], prop, receiver, ignoreProto);
+ return getFieldImpl(proto, prop, proxy, ignoreProto);
}
- return undefined;
}
return field;
}
export function getField(target: any, prop: string | number, ignoreProto: boolean = false): any {
- return getFieldImpl(target, prop, undefined, ignoreProto);
+ return getFieldImpl(target, prop, target[SelfProxy], ignoreProto);
}
export function deleteProperty(target: any, prop: string | number | symbol) {