UNPKG

@gmetrixr/rjson

Version:
225 lines (224 loc) 11.4 kB
import { RecordNode, ROM, RecordMap, ClipboardR } from "./RecordNode"; import { RT, RTP } from "./RecordTypes"; /** * A convenient Factory class to maninpulate a RecordNode object of any type * This class can be extended to provide any recordType specific funcitonality * * Using arrow functions in Classes has a runtime performance cost. The constructor bloats up. * Solution: https://www.typescriptlang.org/docs/handbook/2/classes.html#this-parameters */ export declare class RecordFactory<T extends RT> { protected readonly _json: RecordNode<T>; protected readonly _type: RT; constructor(json: RecordNode<T>); /** * Returns the value of a property, or it default in case the value isn't defined. * In case there is no default defined, it returns "undefined" */ getValueOrDefault(this: RecordFactory<T>, property: RTP[T]): unknown; /** * Returns a clone default value of a property. If no default is found, returns undefined * Note: the returned object is a cloned value to avoid reuse of references across r objects */ getDefault(this: RecordFactory<T>, property: RTP[T]): unknown; json(this: RecordFactory<T>): RecordNode<T>; getId(this: RecordFactory<T>): number; getName(this: RecordFactory<T>): string | undefined; /** A list of recordNode.props' keys in the json */ getProps(this: RecordFactory<T>): string[]; /** A list of Records this json has (eg: project might have scene, variable, menu) */ getROMTypes(this: RecordFactory<T>): RT[]; /** A list of props this RecordType is supposed to have */ getRecordTypeProps(this: RecordFactory<T>): string[]; /** In case a property isn't defined in the json, this method returns "undefined" */ get(this: RecordFactory<T>, property: RTP[T]): unknown; set(this: RecordFactory<T>, property: RTP[T], value: unknown): RecordFactory<T>; delete(this: RecordFactory<T>, property: string): RecordFactory<T>; /** get RecordOrderedMap for a particular sub record, of the shape {map: {}, order: []} - */ getROM<N extends RT>(this: RecordFactory<T>, type: N): ROM<N> | undefined; getRecordMap<N extends RT>(this: RecordFactory<T>, type: N): RecordMap<N>; getRecordOrder(this: RecordFactory<T>, type: RT): number[]; getRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined; getRecords<N extends RT>(this: RecordFactory<T>, type: N): RecordNode<N>[]; changeRecordId<N extends RT>(this: RecordFactory<T>, type: N, id: number, newId?: number): RecordNode<N> | undefined; changeRecordName<N extends RT>(this: RecordFactory<T>, type: N, id: number, newName?: string): RecordNode<N> | undefined; changeDeepRecordName<N extends RT>(this: RecordFactory<T>, type: N, id: number, newName?: string): RecordNode<N> | undefined; changePropertyName(this: RecordFactory<T>, propertyName: string, newPropertyName: string): RecordFactory<T>; deleteProperty(this: RecordFactory<T>, propertyName: string): RecordFactory<T>; addBlankRecord<N extends RT>(this: RecordFactory<T>, type: N, position?: number): RecordNode<N>; addRecord<N extends RT>(this: RecordFactory<T>, record: RecordNode<N>, position?: number): RecordNode<N> | undefined; duplicateRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined; duplicateDeepRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined; deleteRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined; deleteDeepRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined; /** * Used in drag-drop operations * Allows moving multiple items at the same time * Changes order in place * * Input: [1, 2, 3, 4, 5, 6] * Operation: nodeIds: [2,4], position: 5 * Output: [1, 3, 5, 6, 2, 4] */ transposeRecords(this: RecordFactory<T>, type: RT, ids: number[], position: number): undefined; getDeepChildAndParent<N extends RT>(this: RecordFactory<T>, type: N, id: number): { c: RecordNode<N>; p: RecordNode<RT>; } | undefined; getAllDeepChildrenIds<N extends RT>(this: RecordFactory<T>, type: N): number[]; getAllDeepChildren<N extends RT>(this: RecordFactory<T>, type: N): RecordNode<N>[]; /** * Documentation for filter predicate: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#description */ getAllDeepChildrenIdsWithFilter<N extends RT>(this: RecordFactory<T>, type: N, predicate: (value: RecordNode<N>, index?: number, array?: RecordNode<N>[]) => boolean): number[]; getAllDeepChildrenWithFilter<N extends RT>(this: RecordFactory<T>, type: N, predicate: (value: RecordNode<N>, index?: number, array?: RecordNode<N>[]) => boolean): RecordNode<N>[]; /** * Returns the object that needs to be stringified before sending to clipboard * Needs to be overriden at Project/Scene level to ensure that * 1) Vars are copied correctly (in case of scene copy). Vars pasting will be a bit different - no point changing ids. * 2) element ids don't conflict at any depth while pasting * 3) To ensure Ctrl+V of scene works even within another scene (ie project's paste gets used) * * * For clipboard operation, this function can only be called at the parent level * * For scene copy, call to r.project() * * For element copy, call to r.scene() * * Scene copy logic: * In scene rules, vars can be referenced via ids or via variable names (in templates used in elements) * Copy all variables referenced. * * Scene paste logic: * For EACH variable which was copied * - If the variable id and name doesn't exist - paste it * - If the variable id exists, but name doesn't - ignore it. (To make this work, we need to go to each string template used in rules * and elements in the new scene, and change the templates to use the new name) * - If the variable id doesn't exist, but name does - replace the variable id in the new scene being pasted (in all rules) * with the new variable id * - If both the variable id and name exist - ignore it */ copyToClipboardObject(this: RecordFactory<T>, ids: number[]): ClipboardR; /** * Once the clipboard has been converted into ClipboardR, this function can be used to merge into parent RecordNode */ pasteFromClipboardObject(this: RecordFactory<T>, { obj, position }: { obj: ClipboardR; position?: number; }): void; /** * Add moveRecords in RecordFactory. ProjectFactory will override this to add rules logic. * moveRecords(selectIds: [{id: , path: [recordId, parentRecordId, parent2RecordId....]}], destiation: {id: ,path: []}, destinationPosition) */ /** * RFC: https://docs.google.com/document/d/1DVM_i_Go5iX5-EShV5FikfI29k8YEC9cAjzeAY49blc/edit# * get the address of the RecordNode. In case parentAddr is not passed (root levels) then self address is returned */ getSelfRecordAddress(this: RecordFactory<T>, parentAddr?: string): string; /** * get the address of a reacord node property. incase when index is passed, return address to indexed property * 1. project:1|scene:1|element:2!opacity * 2. project:1|scene:1|element:2!wh>1 */ getPropertyAddress(this: RecordFactory<T>, recordAddress: string, property: RTP[T], index?: number): string; /** * Find the record at a given address. Searches only in child record nodes. * Assumes that 1st entry in addr is self * * examples for ref * 1. project:1|scene:1 * 2. project:1|scene:1|element:2 * 3. project:1|scene:1|element:2!opacity * 4. project:1|scene:1|element:2!wh>1 * */ getRecordAtAddress(this: RecordFactory<T>, addr: string): RecordNode<RT> | null; /** * Find the record at a given address. Searches only in child record nodes. * Returns both self and parent * Assumes that 1st entry in addr is self * * examples for ref * 1. project:1|scene:1 * 2. project:1|scene:1|element:2 * 3. project:1|scene:1|element:2!opacity * 4. project:1|scene:1|element:2!wh>1 * */ getRecordAndParentAtAddress(this: RecordFactory<T>, addr: string): { p?: RecordNode<RT>; c: RecordNode<RT>; } | null; /** * Update the value of a property at an address * examples for ref * 1. project:1|scene:1|element:2!opacity * 2. project:1|scene:1|element:2!wh>1 * * First find the RecordNode using getRecordAtAddress method * if the property address contains an index, check if the property is an array type * 1. if yes, udpate the value at index * 2. else return false * else update property value directly in the RecordNode * */ updatePropertyAtAddress(this: RecordFactory<T>, addr: string, value: unknown): boolean; /** * This allows re-parenting records between different depths inside a tree using their addresses. * This needs to be called for the record where both sourceParentRecord and destParentRecord are child records of a common super parent record * For almost all operations, we will use a top down approach here for re-parenting, i.e re-parenting process needs to start from the top most parent * in this case, it is almost always project * Example1: moving elements from within a group to 1 level above. * * Scene1 * Element1 <-------| * Element2 | * Element3 (group) | * Element31 -----| * Element32 * * In above scenario we want to move Element31 below Element1 * sourceRecordAddr = [{parentAddr: Scene:1|Element:3, recordAddr: Scene:1|Element:3|Element:31}] * destParentAddr = Scene:1 * destPosition = 0 (we insert at x+1 index) * * Example2: moving elements from one scene to another * * Scene1 * Element1 * Element2 * Element3 (group) * Element31 * Element32 <-| * Scene2 | * Element4 ------| * Element5 * * In above scenario we want to move Element4 from Scene2 to Element3(Group) * sourceRecordAddr = [{parentAddr: Scene:2, recordAddr: Scene:2|Element:4}] * destParentAddr = Scene:1|Element:3 * destPosition = 1 (we insert at x+1 index) * */ reParentRecordsWithAddress(destParentAddr: string, sourceRecordAddr: { parentAddr: string; recordAddr: string; }[], destPosition?: number): [RecordNode<RT>[], RecordNode<RT>[]]; /** * This returns all the nodes in the path from a parent to a leaf */ getBreadcrumbs(this: RecordFactory<T>, id: number, type: RT): RecordNode<RT>[]; /** * Get address for a deep record */ getDeepRecordAddress(this: RecordFactory<T>, { id, type, parentAddr }: { id: number; type: RT; parentAddr?: string; }): string; /** * Get record + parent address for a given record */ getDeepChildAndParentAddress(this: RecordFactory<T>, id: number, type: RT): string[] | undefined; } export declare class RecordUtils { static getDefaultValues: <T extends RT>(type: T) => Record<string, unknown>; }