aboutsummaryrefslogtreecommitdiff
path: root/src/fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields')
-rw-r--r--src/fields/Doc.ts228
-rw-r--r--src/fields/DocSymbols.ts26
-rw-r--r--src/fields/FieldSymbols.ts21
-rw-r--r--src/fields/List.ts92
-rw-r--r--src/fields/util.ts80
5 files changed, 222 insertions, 225 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index d0e5d03b3..72eeedcff 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -11,9 +11,38 @@ import { SelectionManager } from '../client/util/SelectionManager';
import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from '../client/util/SerializationHelper';
import { undoable, UndoManager } from '../client/util/UndoManager';
import { decycle } from '../decycler/decycler';
+import * as JSZipUtils from '../JSZipUtils';
import { DashColor, incrementTitleCopy, intersectRect, Utils } from '../Utils';
import { DateField } from './DateField';
-import { Copy, HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from './FieldSymbols';
+import {
+ AclAdmin,
+ AclAugment,
+ AclEdit,
+ AclPrivate,
+ AclReadonly,
+ AclSelfEdit,
+ AclUnset,
+ Animation,
+ CachedUpdates,
+ DirectLinks,
+ DocAcl,
+ DocCss,
+ DocData,
+ DocFields,
+ DocLayout,
+ FieldKeys,
+ FieldTuples,
+ ForceServerWrite,
+ Height,
+ Highlight,
+ Initializing,
+ Self,
+ SelfProxy,
+ Update,
+ UpdatingFromServer,
+ Width,
+} from './DocSymbols';
+import { Copy, HandleUpdate, Id, OnUpdate, Parent, ToScriptString, ToString } from './FieldSymbols';
import { InkField, InkTool } from './InkField';
import { List, ListFieldName } from './List';
import { ObjectField } from './ObjectField';
@@ -26,7 +55,6 @@ import { Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Ty
import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
import { deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from './util';
import JSZip = require('jszip');
-import * as JSZipUtils from '../JSZipUtils';
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
const onDelegate = Object.keys(doc).includes(key.replace(/^_/, ''));
@@ -93,28 +121,6 @@ export function DocListCast(field: FieldResult, defaultVal: Doc[] = []) {
return Cast(field, listSpec(Doc), defaultVal).filter(d => d instanceof Doc) as Doc[];
}
-export const WidthSym = Symbol('Width');
-export const HeightSym = Symbol('Height');
-export const AnimationSym = Symbol('Animation');
-export const HighlightSym = Symbol('Highlight');
-export const DataSym = Symbol('Data');
-export const LayoutSym = Symbol('Layout');
-export const FieldsSym = Symbol('Fields');
-export const CssSym = Symbol('Css');
-export const AclSym = Symbol('Acl');
-export const DirectLinksSym = Symbol('DirectLinks');
-export const AclUnset = Symbol('AclUnset');
-export const AclPrivate = Symbol('AclOwnerOnly');
-export const AclReadonly = Symbol('AclReadOnly');
-export const AclAugment = Symbol('AclAugment');
-export const AclSelfEdit = Symbol('AclSelfEdit');
-export const AclEdit = Symbol('AclEdit');
-export const AclAdmin = Symbol('AclAdmin');
-export const UpdatingFromServer = Symbol('UpdatingFromServer');
-export const Initializing = Symbol('Initializing');
-export const ForceServerWrite = Symbol('ForceServerWrite');
-export const CachedUpdates = Symbol('Cached updates');
-
export enum aclLevel {
unset = -1,
unshared = 0,
@@ -141,15 +147,15 @@ export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol }>
export function updateCachedAcls(doc: Doc) {
if (!doc) return;
- const target = (doc as any)?.__fields ?? doc;
+ const target = (doc as any)?.__fieldTuples ?? doc;
const permissions: { [key: string]: symbol } = !target.author || target.author === Doc.CurrentUserEmail ? { 'acl-Me': AclAdmin } : {};
Object.keys(target).filter(key => key.startsWith('acl') && (permissions[key] = ReverseHierarchyMap.get(StrCast(target[key]))!.acl));
- if (Object.keys(permissions).length || doc[AclSym]?.length) {
- runInAction(() => (doc[AclSym] = permissions));
+ if (Object.keys(permissions).length || doc[DocAcl]?.length) {
+ runInAction(() => (doc[DocAcl] = permissions));
}
if (doc.proto instanceof Promise) {
- doc.proto.then(updateCachedAcls);
+ doc.proto.then(proto => updateCachedAcls(DocCast(proto)));
return doc.proto;
}
}
@@ -295,25 +301,20 @@ export class Doc extends RefField {
set: setter,
get: getter,
// getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter
- has: (target, key) => GetEffectiveAcl(target) !== AclPrivate && key in target.__fields,
+ has: (target, key) => GetEffectiveAcl(target) !== AclPrivate && key in target.__fieldTuples,
ownKeys: target => {
- const obj = {} as any;
- if (GetEffectiveAcl(target) !== AclPrivate) Object.assign(obj, target.___fieldKeys);
- runInAction(() => (obj.__LAYOUT__ = target.__LAYOUT__));
- return Object.keys(obj);
+ const keys = GetEffectiveAcl(target) !== AclPrivate ? Object.keys(target[FieldKeys]) : [];
+ return [...keys, '__LAYOUT__'];
},
getOwnPropertyDescriptor: (target, prop) => {
- if (prop.toString() === '__LAYOUT__') {
+ if (prop.toString() === '__LAYOUT__' || !(prop in target[FieldKeys])) {
return Reflect.getOwnPropertyDescriptor(target, prop);
}
- if (prop in target.__fieldKeys) {
- return {
- configurable: true, //TODO Should configurable be true?
- enumerable: true,
- value: 0, //() => target.__fields[prop])
- };
- }
- return Reflect.getOwnPropertyDescriptor(target, prop);
+ return {
+ configurable: true, //TODO Should configurable be true?
+ enumerable: true,
+ value: 0, //() => target.__fieldTuples[prop])
+ };
},
deleteProperty: deleteProperty,
defineProperty: () => {
@@ -327,41 +328,35 @@ export class Doc extends RefField {
return docProxy;
}
- proto: Opt<Doc>;
[key: string]: FieldResult;
@serializable(alias('fields', map(autoObject(), { afterDeserialize: afterDocDeserialize })))
- private get __fields() {
- return this.___fields;
+ private get __fieldTuples() {
+ return this[FieldTuples];
}
- private set __fields(value) {
- this.___fields = value;
+ private set __fieldTuples(value) {
+ // called by deserializer to set all fields in one shot
+ this[FieldTuples] = value;
for (const key in value) {
const field = value[key];
- field !== undefined && (this.__fieldKeys[key] = true);
+ field !== undefined && (this[FieldKeys][key] = true);
if (!(field instanceof ObjectField)) continue;
field[Parent] = this[Self];
field[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]);
}
}
- private get __fieldKeys() {
- return this.___fieldKeys;
- }
- private set __fieldKeys(value) {
- this.___fieldKeys = value;
- }
- @observable private ___fields: any = {};
- @observable private ___fieldKeys: any = {};
+ @observable private [FieldTuples]: any = {};
+ @observable private [FieldKeys]: any = {};
/// all of the raw acl's that have been set on this document. Use GetEffectiveAcl to determine the actual ACL of the doc for editing
- @observable public [AclSym]: { [key: string]: symbol } = {};
- @observable public [CssSym]: number = 0; // incrementer denoting a change to CSS layout
- @observable public [DirectLinksSym]: Set<Doc> = new Set();
- @observable public [AnimationSym]: Opt<Doc>;
- @observable public [HighlightSym]: boolean = false;
+ @observable public [DocAcl]: { [key: string]: symbol } = {};
+ @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout
+ @observable public [DirectLinks]: Set<Doc> = new Set();
+ @observable public [Animation]: Opt<Doc>;
+ @observable public [Highlight]: boolean = false;
static __Anim(Doc: Doc) {
// for debugging to print AnimationSym field easily.
- return Doc[AnimationSym];
+ return Doc[Animation];
}
private [UpdatingFromServer]: boolean = false;
@@ -374,15 +369,15 @@ export class Doc extends RefField {
private [Self] = this;
private [SelfProxy]: any;
- public [FieldsSym] = () => this[Self].___fields; // Object.keys(this).reduce((fields, key) => { fields[key] = this[key]; return fields; }, {} as any);
- public [WidthSym] = () => NumCast(this[SelfProxy]._width);
- public [HeightSym] = () => NumCast(this[SelfProxy]._height);
+ public [DocFields] = () => this[Self][FieldTuples]; // Object.keys(this).reduce((fields, key) => { fields[key] = this[key]; return fields; }, {} as any);
+ public [Width] = () => NumCast(this[SelfProxy]._width);
+ public [Height] = () => NumCast(this[SelfProxy]._height);
public [ToScriptString] = () => `idToDoc("${this[Self][Id]}")`;
public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`;
- public get [LayoutSym]() {
+ public get [DocLayout]() {
return this[SelfProxy].__LAYOUT__;
}
- public get [DataSym](): Doc {
+ public get [DocData](): Doc {
const self = this[SelfProxy];
return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self);
}
@@ -535,17 +530,17 @@ export namespace Doc {
if (key.startsWith('_')) key = key.substring(1);
const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined;
const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
- const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1;
+ const onProto = hasProto && Object.getOwnPropertyNames(hasProto).indexOf(key) !== -1;
if (onDeleg || !hasProto || (!onProto && !defaultProto)) {
doc[key] = value;
- } else doc.proto![key] = value;
+ } else hasProto[key] = value;
}
export function GetAllPrototypes(doc: Doc): Doc[] {
const protos: Doc[] = [];
let d: Opt<Doc> = doc;
while (d) {
protos.push(d);
- d = FieldValue(d.proto);
+ d = DocCast(FieldValue(d.proto));
}
return protos;
}
@@ -585,7 +580,7 @@ export namespace Doc {
// return the doc's proto, but rather recursively searches through the proto inheritance chain
// and returns the document who's proto is undefined or whose proto is marked as a data doc ('isDataDoc').
export function GetProto(doc: Doc): Doc {
- const proto = doc && (Doc.GetT(doc, 'isDataDoc', 'boolean', true) ? doc : doc.proto || doc);
+ const proto = doc && (Doc.GetT(doc, 'isDataDoc', 'boolean', true) ? doc : DocCast(doc.proto, doc));
return proto === doc ? proto : Doc.GetProto(proto);
}
export function GetDataDoc(doc: Doc): Doc {
@@ -599,7 +594,7 @@ export namespace Doc {
let proto: Doc | undefined = doc;
while (proto) {
Object.keys(proto).forEach(key => results.add(key));
- proto = proto.proto;
+ proto = DocCast(FieldValue(proto.proto));
}
return Array.from(results);
@@ -676,7 +671,7 @@ export namespace Doc {
const bounds = docList.reduce(
(bounds, doc) => {
const [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
- const [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
+ const [bptX, bptY] = [sptX + doc[Width](), sptY + doc[Height]()];
return {
x: Math.min(sptX, bounds.x),
y: Math.min(sptY, bounds.y),
@@ -700,7 +695,7 @@ export namespace Doc {
embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`);
embedding.author = Doc.CurrentUserEmail;
- Doc.AddDocToList(Doc.GetProto(doc)[DataSym], 'proto_embeddings', embedding);
+ Doc.AddDocToList(Doc.GetProto(doc)[DocData], 'proto_embeddings', embedding);
return embedding;
}
@@ -772,7 +767,7 @@ export namespace Doc {
}
})
);
- Array.from(doc[DirectLinksSym]).forEach(async link => {
+ Array.from(doc[DirectLinks]).forEach(async link => {
if (
cloneLinks ||
((cloneMap.has(DocCast(link.link_anchor_1)?.[Id]) || cloneMap.has(DocCast(DocCast(link.link_anchor_1)?.annotationOn)?.[Id])) &&
@@ -930,7 +925,7 @@ export namespace Doc {
if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc))) {
expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params
} else {
- templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype
+ templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = DocCast(templateLayoutDoc.proto, templateLayoutDoc)); // if the template has already been applied (ie, a nested template), then use the template's prototype
if (!targetDoc[expandedLayoutFieldKey]) {
_pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true);
setTimeout(
@@ -969,7 +964,7 @@ export namespace Doc {
const field = ProxyField.WithoutProxy(() => doc[key]);
if (key === 'proto' && copyProto) {
if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) {
- overwrite[key] = Doc.Overwrite(doc[key]!, overwrite.proto);
+ overwrite[key] = Doc.Overwrite(doc.proto, overwrite.proto);
}
} else {
if (field instanceof RefField) {
@@ -991,38 +986,37 @@ export namespace Doc {
const copy = new Doc(copyProtoId, true);
updateCachedAcls(copy);
const exclude = [...StrListCast(doc.cloneFieldFilter), 'dragFactory_count', 'cloneFieldFilter'];
- Object.keys(doc).forEach(key => {
- if (exclude.includes(key)) return;
- const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
- const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
- if (key === 'proto' && copyProto) {
- if (doc[key] instanceof Doc) {
- copy[key] = Doc.MakeCopy(doc[key]!, false);
- }
- } else {
- if (field instanceof RefField) {
- copy[key] = field;
- } else if (cfield instanceof ComputedField) {
- copy[key] = cfield[Copy](); // ComputedField.MakeFunction(cfield.script.originalScript);
- } else if (field instanceof ObjectField) {
- copy[key] =
- doc[key] instanceof Doc
- ? key.includes('layout[')
- ? undefined
- : doc[key] // reference documents except remove documents that are expanded teplate fields
- : ObjectField.MakeCopy(field);
- } else if (field instanceof Promise) {
- debugger; //This shouldn't happend...
+ Object.keys(doc)
+ .filter(key => !exclude.includes(key))
+ .forEach(key => {
+ if (key === 'proto' && copyProto) {
+ if (doc.proto instanceof Doc) {
+ copy[key] = Doc.MakeCopy(doc.proto, false);
+ }
} else {
- copy[key] = field;
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+ const field = key === 'author' ? Doc.CurrentUserEmail : ProxyField.WithoutProxy(() => doc[key]);
+ if (field instanceof RefField) {
+ copy[key] = field;
+ } else if (cfield instanceof ComputedField) {
+ copy[key] = cfield[Copy](); // ComputedField.MakeFunction(cfield.script.originalScript);
+ } else if (field instanceof ObjectField) {
+ copy[key] =
+ doc[key] instanceof Doc && key.includes('layout[')
+ ? undefined // remove expanded template field documents
+ : ObjectField.MakeCopy(field);
+ } else if (field instanceof Promise) {
+ debugger; //This shouldn't happend...
+ } else {
+ copy[key] = field;
+ }
}
- }
- });
+ });
if (copyProto) {
Doc.GetProto(copy).embedContainer = undefined;
Doc.GetProto(copy).proto_embeddings = new List<Doc>([copy]);
} else {
- Doc.AddDocToList(Doc.GetProto(copy)[DataSym], 'proto_embeddings', copy);
+ Doc.AddDocToList(Doc.GetProto(copy)[DocData], 'proto_embeddings', copy);
}
copy.embedContainer = undefined;
Doc.defaultAclPrivate && (copy['acl-Public'] = 'Not Shared');
@@ -1045,7 +1039,7 @@ export namespace Doc {
Object.keys(doc)
.filter(key => key.startsWith('acl'))
.forEach(key => (delegate[key] = doc[key]));
- if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DataSym], 'proto_embeddings', delegate);
+ if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate);
title && (delegate.title = title);
delegate[Initializing] = false;
Doc.AddFileOrphan(delegate);
@@ -1069,7 +1063,7 @@ export namespace Doc {
delegate[Initializing] = true;
delegate.proto = delegateProto;
delegate.author = Doc.CurrentUserEmail;
- Doc.AddDocToList(delegateProto[DataSym], 'proto_embeddings', delegate);
+ Doc.AddDocToList(delegateProto[DocData], 'proto_embeddings', delegate);
delegate[Initializing] = false;
delegateProto[Initializing] = false;
return delegate;
@@ -1173,7 +1167,7 @@ export namespace Doc {
}
export const brushManager = new DocBrush();
- export class DocData {
+ export class UserDocData {
@observable _user_doc: Doc = undefined!;
@observable _sharing_doc: Doc = undefined!;
@observable _searchQuery: string = '';
@@ -1183,7 +1177,7 @@ export namespace Doc {
// a layout field or 'layout' is given.
export function Layout(doc: Doc, layout?: Doc): Doc {
const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}-layout[` + layout[Id] + ']'], Doc, null);
- return overrideLayout || doc[LayoutSym] || doc;
+ return overrideLayout || doc[DocLayout] || doc;
}
export function SetLayout(doc: Doc, layout: Doc | string) {
doc[StrCast(doc.layout_fieldKey, 'layout')] = layout;
@@ -1198,12 +1192,12 @@ export namespace Doc {
return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1);
}
export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) {
- return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[WidthSym]() : 0));
+ return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[Width]() : 0));
}
export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) {
if (!doc) return 0;
- const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]();
- const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[HeightSym]() : 0);
+ const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[Height]()) / doc[Width]();
+ const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[Height]() : 0);
return NumCast(doc._nativeHeight, nheight || dheight);
}
export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) {
@@ -1213,7 +1207,7 @@ export namespace Doc {
doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height;
}
- const manager = new DocData();
+ const manager = new UserDocData();
export function SearchQuery(): string {
return manager._searchQuery;
}
@@ -1348,16 +1342,16 @@ export namespace Doc {
export var highlightedDocs = new ObservableSet<Doc>();
export function IsHighlighted(doc: Doc) {
if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false;
- return doc[HighlightSym] || Doc.GetProto(doc)[HighlightSym];
+ return doc[Highlight] || Doc.GetProto(doc)[Highlight];
}
export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presEffect?: Doc) {
runInAction(() => {
highlightedDocs.add(doc);
- doc[HighlightSym] = true;
- doc[AnimationSym] = presEffect;
+ doc[Highlight] = true;
+ doc[Animation] = presEffect;
if (dataAndDisplayDocs) {
highlightedDocs.add(Doc.GetProto(doc));
- Doc.GetProto(doc)[HighlightSym] = true;
+ Doc.GetProto(doc)[Highlight] = true;
}
});
}
@@ -1367,8 +1361,8 @@ export namespace Doc {
(doc ? [doc] : Array.from(highlightedDocs)).forEach(doc => {
highlightedDocs.delete(doc);
highlightedDocs.delete(Doc.GetProto(doc));
- doc[HighlightSym] = Doc.GetProto(doc)[HighlightSym] = false;
- doc[AnimationSym] = undefined;
+ doc[Highlight] = Doc.GetProto(doc)[Highlight] = false;
+ doc[Animation] = undefined;
});
});
}
diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts
new file mode 100644
index 000000000..65decc147
--- /dev/null
+++ b/src/fields/DocSymbols.ts
@@ -0,0 +1,26 @@
+export const Update = Symbol('DocUpdate');
+export const Self = Symbol('DocSelf');
+export const SelfProxy = Symbol('DocSelfProxy');
+export const FieldKeys = Symbol('DocFieldKeys');
+export const FieldTuples = Symbol('DocFieldTuples');
+export const Width = Symbol('DocWidth');
+export const Height = Symbol('DocHeight');
+export const Animation = Symbol('DocAnimation');
+export const Highlight = Symbol('DocHighlight');
+export const DocData = Symbol('DocData');
+export const DocLayout = Symbol('DocLayout');
+export const DocFields = Symbol('DocFields');
+export const DocCss = Symbol('DocCss');
+export const DocAcl = Symbol('DocAcl');
+export const DirectLinks = Symbol('DocDirectLinks');
+export const AclUnset = Symbol('DocAclUnset');
+export const AclPrivate = Symbol('DocAclOwnerOnly');
+export const AclReadonly = Symbol('DocAclReadOnly');
+export const AclAugment = Symbol('DocAclAugment');
+export const AclSelfEdit = Symbol('DocAclSelfEdit');
+export const AclEdit = Symbol('DocAclEdit');
+export const AclAdmin = Symbol('DocAclAdmin');
+export const UpdatingFromServer = Symbol('DocUpdatingFromServer');
+export const Initializing = Symbol('DocInitializing');
+export const ForceServerWrite = Symbol('DocForceServerWrite');
+export const CachedUpdates = Symbol('DocCachedUpdates');
diff --git a/src/fields/FieldSymbols.ts b/src/fields/FieldSymbols.ts
index e50c2856f..c381f14f5 100644
--- a/src/fields/FieldSymbols.ts
+++ b/src/fields/FieldSymbols.ts
@@ -1,12 +1,9 @@
-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');
+export const HandleUpdate = Symbol('FieldHandleUpdate');
+export const Id = Symbol('FieldId');
+export const OnUpdate = Symbol('FieldOnUpdate');
+export const Parent = Symbol('FieldParent');
+export const Copy = Symbol('FieldCopy');
+export const ToValue = Symbol('FieldToValue');
+export const ToScriptString = Symbol('FieldToScriptString');
+export const ToPlainText = Symbol('FieldToPlainText');
+export const ToString = Symbol('FieldToString');
diff --git a/src/fields/List.ts b/src/fields/List.ts
index dfd24cf7a..033fa569b 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -3,8 +3,9 @@ import { alias, list, serializable } from 'serializr';
import { DocServer } from '../client/DocServer';
import { ScriptingGlobals } from '../client/util/ScriptingGlobals';
import { afterDocDeserialize, autoObject, Deserializable } from '../client/util/SerializationHelper';
+import { FieldTuples, Self, SelfProxy, Update } from './DocSymbols';
import { Field } from './Doc';
-import { Copy, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from './FieldSymbols';
+import { Copy, OnUpdate, Parent, ToScriptString, ToString } from './FieldSymbols';
import { ObjectField } from './ObjectField';
import { ProxyField } from './Proxy';
import { RefField } from './RefField';
@@ -21,12 +22,12 @@ const listHandlers: any = {
if (value instanceof RefField) {
throw new Error('fill with RefFields not supported yet');
}
- const res = this[Self].__fields.fill(value, start, end);
+ const res = this[Self].__fieldTuples.fill(value, start, end);
this[Update]();
return res;
},
pop(): any {
- const field = toRealField(this[Self].__fields.pop());
+ const field = toRealField(this[Self].__fieldTuples.pop());
this[Update]();
return field;
},
@@ -34,7 +35,7 @@ const listHandlers: any = {
items = items.map(toObjectField);
const list = this[Self];
- const length = list.__fields.length;
+ const length = list.__fieldTuples.length;
for (let i = 0; i < items.length; i++) {
const item = items[i];
//TODO Error checking to make sure parent doesn't already exist
@@ -43,23 +44,23 @@ const listHandlers: any = {
item[OnUpdate] = updateFunction(list, i + length, item, this);
}
}
- const res = list.__fields.push(...items);
+ const res = list.__fieldTuples.push(...items);
this[Update]({ op: '$addToSet', items, length: length + items.length });
return res;
}),
reverse() {
- const res = this[Self].__fields.reverse();
+ const res = this[Self].__fieldTuples.reverse();
this[Update]();
return res;
},
shift() {
- const res = toRealField(this[Self].__fields.shift());
+ const res = toRealField(this[Self].__fieldTuples.shift());
this[Update]();
return res;
},
sort(cmpFunc: any) {
this[Self].__realFields(); // coerce retrieving entire array
- const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined);
+ const res = this[Self].__fieldTuples.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined);
this[Update]();
return res;
},
@@ -67,7 +68,7 @@ const listHandlers: any = {
this[Self].__realFields(); // coerce retrieving entire array
items = items.map(toObjectField);
const list = this[Self];
- const removed = list.__fields.filter((item: any, i: number) => i >= start && i < start + deleteCount);
+ const removed = list.__fieldTuples.filter((item: any, i: number) => i >= start && i < start + deleteCount);
for (let i = 0; i < items.length; i++) {
const item = items[i];
//TODO Error checking to make sure parent doesn't already exist
@@ -77,18 +78,18 @@ const listHandlers: any = {
item[OnUpdate] = updateFunction(list, i + start, item, this);
}
}
- let hintArray: {val : any, index : number}[] = [];
- for(let i = start; i < start + deleteCount; i++) {
- hintArray.push({val : list.__fields[i], index : i});
+ let hintArray: { val: any; index: number }[] = [];
+ for (let i = start; i < start + deleteCount; i++) {
+ hintArray.push({ val: list.__fieldTuples[i], index: i });
}
- const res = list.__fields.splice(start, deleteCount, ...items);
+ const res = list.__fieldTuples.splice(start, deleteCount, ...items);
// the hint object sends the starting index of the slice and the number
- // of elements to delete.
+ // of elements to delete.
this[Update](
items.length === 0 && deleteCount
- ? { op: '$remFromSet', items: removed, hint : { start : start, deleteCount : deleteCount }, length: list.__fields.length }
- : items.length && !deleteCount && start === list.__fields.length
- ? { op: '$addToSet', items, length: list.__fields.length }
+ ? { op: '$remFromSet', items: removed, hint: { start: start, deleteCount: deleteCount }, length: list.__fieldTuples.length }
+ : items.length && !deleteCount && start === list.__fieldTuples.length
+ ? { op: '$addToSet', items, length: list.__fieldTuples.length }
: undefined
);
return res.map(toRealField);
@@ -96,7 +97,7 @@ const listHandlers: any = {
unshift(...items: any[]) {
items = items.map(toObjectField);
const list = this[Self];
- const length = list.__fields.length;
+ const length = list.__fieldTuples.length;
for (let i = 0; i < items.length; i++) {
const item = items[i];
//TODO Error checking to make sure parent doesn't already exist
@@ -106,32 +107,32 @@ const listHandlers: any = {
item[OnUpdate] = updateFunction(list, i, item, this);
}
}
- const res = this[Self].__fields.unshift(...items);
+ const res = this[Self].__fieldTuples.unshift(...items);
this[Update]();
return res;
},
/// Accessor methods
concat: action(function (this: any, ...items: any[]) {
this[Self].__realFields();
- return this[Self].__fields.map(toRealField).concat(...items);
+ return this[Self].__fieldTuples.map(toRealField).concat(...items);
}),
includes(valueToFind: any, fromIndex: number) {
if (valueToFind instanceof RefField) {
return this[Self].__realFields().includes(valueToFind, fromIndex);
} else {
- return this[Self].__fields.includes(valueToFind, fromIndex);
+ return this[Self].__fieldTuples.includes(valueToFind, fromIndex);
}
},
indexOf(valueToFind: any, fromIndex: number) {
if (valueToFind instanceof RefField) {
return this[Self].__realFields().indexOf(valueToFind, fromIndex);
} else {
- return this[Self].__fields.indexOf(valueToFind, fromIndex);
+ return this[Self].__fieldTuples.indexOf(valueToFind, fromIndex);
}
},
join(separator: any) {
this[Self].__realFields();
- return this[Self].__fields.map(toRealField).join(separator);
+ return this[Self].__fieldTuples.map(toRealField).join(separator);
},
lastElement() {
return this[Self].__realFields().lastElement();
@@ -140,12 +141,12 @@ const listHandlers: any = {
if (valueToFind instanceof RefField) {
return this[Self].__realFields().lastIndexOf(valueToFind, fromIndex);
} else {
- return this[Self].__fields.lastIndexOf(valueToFind, fromIndex);
+ return this[Self].__fieldTuples.lastIndexOf(valueToFind, fromIndex);
}
},
slice(begin: number, end: number) {
this[Self].__realFields();
- return this[Self].__fields.slice(begin, end).map(toRealField);
+ return this[Self].__fieldTuples.slice(begin, end).map(toRealField);
},
/// Iteration methods
@@ -156,55 +157,55 @@ const listHandlers: any = {
return this[Self].__realFields().every(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
filter(callback: any, thisArg: any) {
return this[Self].__realFields().filter(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
find(callback: any, thisArg: any) {
return this[Self].__realFields().find(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
findIndex(callback: any, thisArg: any) {
return this[Self].__realFields().findIndex(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
forEach(callback: any, thisArg: any) {
return this[Self].__realFields().forEach(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
map(callback: any, thisArg: any) {
return this[Self].__realFields().map(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
reduce(callback: any, initialValue: any) {
return this[Self].__realFields().reduce(callback, initialValue);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
+ // return this[Self].__fieldTuples.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
},
reduceRight(callback: any, initialValue: any) {
return this[Self].__realFields().reduceRight(callback, initialValue);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
+ // return this[Self].__fieldTuples.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
},
some(callback: any, thisArg: any) {
return this[Self].__realFields().some(callback, thisArg);
// TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
// If we don't want to support the array parameter, we should use this version instead
- // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+ // return this[Self].__fieldTuples.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
},
values() {
return this[Self].__realFields().values();
@@ -246,7 +247,7 @@ type ListUpdate<T> = ListSpliceUpdate<T> | ListIndexUpdate<T>;
type StoredType<T extends Field> = T extends RefField ? ProxyField<T> : T;
-export const ListFieldName="fields";
+export const ListFieldName = 'fields';
@Deserializable('list')
class ListImpl<T extends Field> extends ObjectField {
constructor(fields?: T[]) {
@@ -254,9 +255,9 @@ class ListImpl<T extends Field> extends ObjectField {
const list = new Proxy<this>(this, {
set: setter,
get: listGetter,
- ownKeys: target => Object.keys(target.__fields),
+ ownKeys: target => Object.keys(target.__fieldTuples),
getOwnPropertyDescriptor: (target, prop) => {
- if (prop in target.__fields) {
+ if (prop in target[FieldTuples]) {
return {
configurable: true, //TODO Should configurable be true?
enumerable: true,
@@ -281,7 +282,7 @@ class ListImpl<T extends Field> extends ObjectField {
// this requests all ProxyFields at the same time to avoid the overhead
// of separate network requests and separate updates to the React dom.
private __realFields() {
- const unrequested = this.__fields.filter(f => f instanceof ProxyField && f.needsRequesting).map(f => f as ProxyField<RefField>);
+ const unrequested = this[FieldTuples].filter(f => f instanceof ProxyField && f.needsRequesting).map(f => f as ProxyField<RefField>);
// if we find any ProxyFields that don't have a current value, then
// start the server request for all of them
if (unrequested.length) {
@@ -293,17 +294,16 @@ class ListImpl<T extends Field> extends ObjectField {
// will await the batch request and return the requested field value.
unrequested.forEach(p => p.setExternalValuePromise(allSetPromise));
}
- return this.__fields.map(toRealField);
+ return this[FieldTuples].map(toRealField);
}
- public static FieldDataName = 'fields';
@serializable(alias(ListFieldName, list(autoObject(), { afterDeserialize: afterDocDeserialize })))
- private get __fields() {
- return this.___fields;
+ private get __fieldTuples() {
+ return this[FieldTuples];
}
- private set __fields(value) {
- this.___fields = value;
+ private set __fieldTuples(value) {
+ this[FieldTuples] = value;
for (const key in value) {
const field = value[key];
if (field instanceof ObjectField) {
@@ -314,14 +314,14 @@ class ListImpl<T extends Field> extends ObjectField {
}
[Copy]() {
- const copiedData = this[Self].__fields.map(f => (f instanceof ObjectField ? f[Copy]() : f));
+ const copiedData = this[Self].__fieldTuples.map(f => (f instanceof ObjectField ? f[Copy]() : f));
const deepCopy = new ListImpl<T>(copiedData as any);
return deepCopy;
}
// @serializable(alias("fields", list(autoObject())))
@observable
- private ___fields: StoredType<T>[] = [];
+ private [FieldTuples]: StoredType<T>[] = [];
private [Update] = (diff: any) => {
// console.log(diff);
diff --git a/src/fields/util.ts b/src/fields/util.ts
index a2b445d6c..62f27c7d2 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -7,28 +7,9 @@ import { SerializationHelper } from '../client/util/SerializationHelper';
import { UndoManager } from '../client/util/UndoManager';
import { returnZero } from '../Utils';
import CursorField from './CursorField';
-import {
- AclAdmin,
- AclEdit,
- aclLevel,
- AclPrivate,
- AclSelfEdit,
- AclSym,
- DataSym,
- Doc,
- DocListCast,
- DocListCastAsync,
- ForceServerWrite,
- HeightSym,
- HierarchyMapping,
- Initializing,
- LayoutSym,
- ReverseHierarchyMap,
- updateCachedAcls,
- UpdatingFromServer,
- WidthSym,
-} from './Doc';
-import { Id, OnUpdate, Parent, SelfProxy, ToValue, Update } from './FieldSymbols';
+import { aclLevel, Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap, updateCachedAcls } from './Doc';
+import { AclAdmin, AclEdit, AclPrivate, AclSelfEdit, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, Update, UpdatingFromServer, Width } from './DocSymbols';
+import { Id, OnUpdate, Parent, ToValue } from './FieldSymbols';
import { List } from './List';
import { ObjectField } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
@@ -56,7 +37,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
if (value !== undefined) {
value = value[SelfProxy] || value;
}
- const curValue = target.__fields[prop];
+ const curValue = target.__fieldTuples[prop];
if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) {
// TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically
// curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way
@@ -88,11 +69,11 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
if (writeToDoc) {
if (value === undefined) {
- target.__fieldKeys && delete target.__fieldKeys[prop];
- delete target.__fields[prop];
+ delete target[FieldKeys][prop];
+ delete target.__fieldTuples[prop];
} else {
- target.__fieldKeys && (target.__fieldKeys[prop] = true);
- target.__fields[prop] = value;
+ target[FieldKeys][prop] = true;
+ target.__fieldTuples[prop] = value;
}
if (writeToServer) {
@@ -148,12 +129,12 @@ export function denormalizeEmail(email: string) {
*/
export function inheritParentAcls(parent: Doc, child: Doc) {
return;
- const dataDoc = parent[DataSym];
- for (const key of Object.keys(dataDoc)) {
- // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
- const permission = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : dataDoc[key];
- key.startsWith('acl') && distributeAcls(key, permission, child);
- }
+ // const dataDoc = parent[DataSym];
+ // for (const key of Object.keys(dataDoc)) {
+ // // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
+ // const permission = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : dataDoc[key];
+ // key.startsWith('acl') && distributeAcls(key, permission, child);
+ // }
}
/**
@@ -212,7 +193,7 @@ export function SetCachedGroups(groups: string[]) {
runInAction(() => cachedGroups.push(...groups));
}
function getEffectiveAcl(target: any, user?: string): symbol {
- const targetAcls = target[AclSym];
+ const targetAcls = target[DocAcl];
if (targetAcls?.['acl-Me'] === AclAdmin || GetCachedGroupByName('Admin')) return AclAdmin;
const userChecked = user || Doc.CurrentUserEmail; // if the current user is the author of the document / the current user is a member of the admin group
@@ -237,7 +218,7 @@ function getEffectiveAcl(target: any, user?: string): symbol {
return DocServer?.Control?.isReadOnly?.() && HierarchyMapping.get(effectiveAcl)!.level < aclLevel.editable ? AclEdit : effectiveAcl;
}
// authored documents are private until an ACL is set.
- const targetAuthor = target.__fields?.author || target.author; // target may be a Doc of Proxy, so check __fields.author and .author
+ const targetAuthor = target.__fieldTuples?.author || target.author; // target may be a Doc of Proxy, so check __fieldTuples.author and .author
if (targetAuthor && targetAuthor !== userChecked) return AclPrivate;
return AclAdmin;
}
@@ -277,7 +258,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
}
let dataDocChanged = false;
- const dataDoc = target[DataSym];
+ const dataDoc = target[DocData];
if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || ReverseHierarchyMap.get(StrCast(dataDoc[key]))! > ReverseHierarchyMap.get(acl)!)) {
if (GetEffectiveAcl(dataDoc) === AclAdmin) {
dataDoc[key] = acl;
@@ -290,13 +271,13 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
// maps over the children of the document
DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).forEach(d => {
distributeAcls(key, acl, d, inheritingFromCollection, visited);
- distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
+ distributeAcls(key, acl, d[DocData], inheritingFromCollection, visited);
});
// maps over the annotations of the document
DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '_annotations']).forEach(d => {
distributeAcls(key, acl, d, inheritingFromCollection, visited);
- distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
+ distributeAcls(key, acl, d[DocData], inheritingFromCollection, visited);
});
}
@@ -311,16 +292,16 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
// if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't
if (typeof prop === 'string' && prop.startsWith('acl') && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true;
- if (typeof prop === 'string' && prop !== '__id' && prop !== '__fields' && prop.startsWith('_')) {
+ if (typeof prop === 'string' && prop !== '__id' && prop !== '__fieldTuples' && prop.startsWith('_')) {
if (!prop.startsWith('__')) prop = prop.substring(1);
if (target.__LAYOUT__) {
target.__LAYOUT__[prop] = value;
return true;
}
}
- if (target.__fields[prop] instanceof ComputedField) {
- if (target.__fields[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) {
- return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false;
+ if (target.__fieldTuples[prop] instanceof ComputedField) {
+ if (target.__fieldTuples[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) {
+ return ScriptCast(target.__fieldTuples[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false;
}
}
return _setter(target, prop, value, receiver);
@@ -330,14 +311,13 @@ 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':
+ case 'constructor': case 'toString': case 'valueOf':
+ case 'serializeInfo': case 'factory':
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;
+ case DocAcl : return target[DocAcl];
+ case $mobx: return target.__fieldTuples[prop];
+ case DocLayout: return target.__LAYOUT__;
+ case Height: case Width: if (GetEffectiveAcl(target) === AclPrivate) return returnZero;
default :
if (typeof prop === 'symbol') return target[prop];
if (prop.startsWith('isMobX')) return target[prop];
@@ -351,7 +331,7 @@ export function getter(target: any, prop: string | symbol, proxy: any): any {
}
function getFieldImpl(target: any, prop: string | number, proxy: any, ignoreProto: boolean = false): any {
- const field = target.__fields[prop];
+ const field = target.__fieldTuples[prop];
const value = field?.[ToValue]?.(proxy); // converts ComputedFields to values, or unpacks ProxyFields into Proxys
if (value) return value.value;
if (field === undefined && !ignoreProto && prop !== 'proto') {