diff --git a/src/api/converter.ts b/src/api/converter.ts index b1ba92408..e5a1e1752 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -202,7 +202,10 @@ function toValueType(valueType: PrimitiveType): PbValueType { case PrimitiveType.Date: return PbValueType.DATE; default: - throw new YorkieError(Code.Unsupported, `unsupported type: ${valueType}`); + throw new YorkieError( + Code.ErrInvalidType, + `unsupported type: ${valueType}`, + ); } } @@ -216,7 +219,10 @@ function toCounterType(valueType: CounterType): PbValueType { case CounterType.LongCnt: return PbValueType.LONG_CNT; default: - throw new YorkieError(Code.Unsupported, `unsupported type: ${valueType}`); + throw new YorkieError( + Code.ErrInvalidType, + `unsupported type: ${valueType}`, + ); } } @@ -859,7 +865,7 @@ function fromPresenceChange

( }; } - throw new YorkieError(Code.Unsupported, `unsupported type: ${type}`); + throw new YorkieError(Code.ErrInvalidType, `unsupported type: ${type}`); } /** @@ -1476,7 +1482,7 @@ function bytesToSnapshot

( */ function bytesToObject(bytes?: Uint8Array): CRDTObject { if (!bytes) { - throw new Error('bytes is empty'); + throw new YorkieError(Code.ErrInvalidArgument, 'bytes is empty'); } const pbElement = PbJSONElement.fromBinary(bytes); @@ -1495,7 +1501,7 @@ function objectToBytes(obj: CRDTObject): Uint8Array { */ function bytesToArray(bytes?: Uint8Array): CRDTArray { if (!bytes) { - throw new Error('bytes is empty'); + throw new YorkieError(Code.ErrInvalidArgument, 'bytes is empty'); } const pbElement = PbJSONElement.fromBinary(bytes); @@ -1514,7 +1520,7 @@ function arrayToBytes(array: CRDTArray): Uint8Array { */ function bytesToTree(bytes?: Uint8Array): CRDTTree { if (!bytes) { - throw new Error('bytes is empty'); + throw new YorkieError(Code.ErrInvalidArgument, 'bytes is empty'); } const pbElement = PbJSONElement.fromBinary(bytes); diff --git a/src/document/crdt/element_rht.ts b/src/document/crdt/element_rht.ts index d9d3bdadd..83700a549 100644 --- a/src/document/crdt/element_rht.ts +++ b/src/document/crdt/element_rht.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; +import { YorkieError, Code } from '@yorkie-js-sdk/src/util/error'; /** * `ElementRHTNode` is a node of ElementRHT. @@ -114,7 +114,10 @@ export class ElementRHT { */ public delete(createdAt: TimeTicket, executedAt: TimeTicket): CRDTElement { if (!this.nodeMapByCreatedAt.has(createdAt.toIDString())) { - logger.fatal(`fail to find ${createdAt.toIDString()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${createdAt.toIDString()}`, + ); } const node = this.nodeMapByCreatedAt.get(createdAt.toIDString())!; @@ -142,8 +145,10 @@ export class ElementRHT { element.getCreatedAt().toIDString(), ); if (!node) { - logger.fatal(`fail to find ${element.getCreatedAt().toIDString()}`); - return; + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${element.getCreatedAt().toIDString()}`, + ); } const nodeByKey = this.nodeMapByKey.get(node.getStrKey()); diff --git a/src/document/crdt/rga_tree_list.ts b/src/document/crdt/rga_tree_list.ts index df7bd0854..c4901baf0 100644 --- a/src/document/crdt/rga_tree_list.ts +++ b/src/document/crdt/rga_tree_list.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { SplayNode, SplayTree } from '@yorkie-js-sdk/src/util/splay_tree'; import { InitialTimeTicket, @@ -22,6 +21,7 @@ import { } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { Primitive } from '@yorkie-js-sdk/src/document/crdt/primitive'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `RGATreeListNode` is a node of RGATreeList. @@ -180,7 +180,10 @@ export class RGATreeList { ): RGATreeListNode { let node = this.nodeMapByCreatedAt.get(createdAt.toIDString()); if (!node) { - logger.fatal(`cant find the given node: ${createdAt.toIDString()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `cant find the given node: ${createdAt.toIDString()}`, + ); } while ( @@ -232,12 +235,18 @@ export class RGATreeList { ): void { const prevNode = this.nodeMapByCreatedAt.get(prevCreatedAt.toIDString()); if (!prevNode) { - logger.fatal(`cant find the given node: ${prevCreatedAt.toIDString()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `cant find the given node: ${prevCreatedAt.toIDString()}`, + ); } const node = this.nodeMapByCreatedAt.get(createdAt.toIDString()); if (!node) { - logger.fatal(`cant find the given node: ${createdAt.toIDString()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `cant find the given node: ${createdAt.toIDString()}`, + ); } if ( @@ -284,7 +293,8 @@ export class RGATreeList { element.getCreatedAt().toIDString(), ); if (!node) { - logger.fatal( + throw new YorkieError( + Code.ErrInvalidArgument, `fail to find the given createdAt: ${element .getCreatedAt() .toIDString()}`, diff --git a/src/document/crdt/rga_tree_split.ts b/src/document/crdt/rga_tree_split.ts index 0d28d0895..45d8fd34d 100644 --- a/src/document/crdt/rga_tree_split.ts +++ b/src/document/crdt/rga_tree_split.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { ActorID } from '@yorkie-js-sdk/src/document/time/actor_id'; import { Comparator } from '@yorkie-js-sdk/src/util/comparator'; import { SplayNode, SplayTree } from '@yorkie-js-sdk/src/util/splay_tree'; @@ -26,6 +25,7 @@ import { TimeTicketStruct, } from '@yorkie-js-sdk/src/document/time/ticket'; import { GCChild, GCPair, GCParent } from '@yorkie-js-sdk/src/document/crdt/gc'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; export interface ValueChange { actor: ActorID; @@ -634,7 +634,8 @@ export class RGATreeSplit implements GCParent { ? this.findFloorNodePreferToLeft(absoluteID) : this.findFloorNode(absoluteID); if (!node) { - logger.fatal( + throw new YorkieError( + Code.ErrInvalidArgument, `the node of the given id should be found: ${absoluteID.toTestString()}`, ); } @@ -793,7 +794,8 @@ export class RGATreeSplit implements GCParent { ): RGATreeSplitNode { let node = this.findFloorNode(id); if (!node) { - logger.fatal( + throw new YorkieError( + Code.ErrInvalidArgument, `the node of the given id should be found: ${id.toTestString()}`, ); } @@ -847,7 +849,10 @@ export class RGATreeSplit implements GCParent { offset: number, ): RGATreeSplitNode | undefined { if (offset > node.getContentLength()) { - logger.fatal('offset should be less than or equal to length'); + throw new YorkieError( + Code.ErrInvalidArgument, + `offset should be less than or equal to length`, + ); } if (offset === 0) { diff --git a/src/document/crdt/root.ts b/src/document/crdt/root.ts index efe2305af..fe962f4b4 100644 --- a/src/document/crdt/root.ts +++ b/src/document/crdt/root.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { InitialTimeTicket, TimeTicket, @@ -27,6 +26,7 @@ import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { GCPair } from '@yorkie-js-sdk/src/document/crdt/gc'; import { CRDTText } from '@yorkie-js-sdk/src/document/crdt/text'; import { CRDTTree } from '@yorkie-js-sdk/src/document/crdt/tree'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `CRDTElementPair` is a structure that represents a pair of element and its @@ -134,7 +134,10 @@ export class CRDTRoot { const createdAt = pair.element.getCreatedAt(); const subPath = pair.parent.subPathOf(createdAt); if (subPath === undefined) { - logger.fatal(`cant find the given element: ${createdAt.toIDString()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `cant find the given element: ${createdAt.toIDString()}`, + ); } subPaths.unshift(subPath!); diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index 33624631f..7c5800205 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -43,6 +43,7 @@ import { Indexable } from '@yorkie-js-sdk/src/document/document'; import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; import { escapeString } from '@yorkie-js-sdk/src/document/json/strings'; import { GCChild, GCPair, GCParent } from '@yorkie-js-sdk/src/document/crdt/gc'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `TreeNode` represents a node in the tree. @@ -223,7 +224,8 @@ export class CRDTTreePos { const parentNode = tree.findFloorNode(parentID); let leftNode = tree.findFloorNode(leftSiblingID); if (!parentNode || !leftNode) { - throw new Error( + throw new YorkieError( + Code.ErrRefused, `cannot find node of CRDTTreePos(${parentID.toTestString()}, ${leftSiblingID.toTestString()})`, ); } @@ -514,7 +516,10 @@ export class CRDTTreeNode */ get value() { if (!this.isText) { - throw new Error(`cannot get value of element node: ${this.type}`); + throw new YorkieError( + Code.ErrInvalidType, + `cannot get value of element node: ${this.type}`, + ); } return this._value; @@ -525,7 +530,10 @@ export class CRDTTreeNode */ set value(v: string) { if (!this.isText) { - throw new Error(`cannot set value of element node: ${this.type}`); + throw new YorkieError( + Code.ErrInvalidType, + `cannot set value of element node: ${this.type}`, + ); } this._value = v; @@ -1217,7 +1225,10 @@ export class CRDTTree extends CRDTElement implements GCParent { ticket: TimeTicket, ): void { // TODO(hackerwins, easylogic): Implement this with keeping references of the nodes. - throw new Error(`not implemented: ${target}, ${source}, ${ticket}`); + throw new YorkieError( + Code.ErrUnimplemented, + `not implemented: ${target}, ${source}, ${ticket}`, + ); } /** diff --git a/src/document/document.ts b/src/document/document.ts index 0ebf79ece..9343b6353 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -660,7 +660,7 @@ export class Document { } catch (err) { // drop clone because it is contaminated. this.clone = undefined; - logger.error(err); + throw err; } finally { this.isUpdating = false; @@ -847,7 +847,10 @@ export class Document { ): Unsubscribe { if (typeof arg1 === 'string') { if (typeof arg2 !== 'function') { - throw new Error('Second argument must be a callback function'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'Second argument must be a callback function', + ); } if (arg1 === 'presence') { const callback = arg2 as DocEventCallbackMap

['presence']; @@ -1021,7 +1024,7 @@ export class Document { complete, ); } - throw new Error(`"${arg1}" is not a valid`); + throw new YorkieError(Code.ErrInvalidArgument, `"${arg1}" is not a valid`); } /** @@ -1761,11 +1764,17 @@ export class Document { */ private undo(): void { if (this.isUpdating) { - throw new Error('Undo is not allowed during an update'); + throw new YorkieError( + Code.ErrRefused, + 'Undo is not allowed during an update', + ); } const undoOps = this.internalHistory.popUndo(); if (undoOps === undefined) { - throw new Error('There is no operation to be undone'); + throw new YorkieError( + Code.ErrRefused, + 'There is no operation to be undone', + ); } this.ensureClone(); @@ -1855,12 +1864,18 @@ export class Document { */ private redo(): void { if (this.isUpdating) { - throw new Error('Redo is not allowed during an update'); + throw new YorkieError( + Code.ErrRefused, + 'Redo is not allowed during an update', + ); } const redoOps = this.internalHistory.popRedo(); if (redoOps === undefined) { - throw new Error('There is no operation to be redone'); + throw new YorkieError( + Code.ErrRefused, + 'There is no operation to be redone', + ); } this.ensureClone(); diff --git a/src/document/json/counter.ts b/src/document/json/counter.ts index 6e1f9013a..fdffc975d 100644 --- a/src/document/json/counter.ts +++ b/src/document/json/counter.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { ChangeContext } from '@yorkie-js-sdk/src/document/change/context'; import { Primitive } from '@yorkie-js-sdk/src/document/crdt/primitive'; @@ -25,6 +24,7 @@ import { CRDTCounter, } from '@yorkie-js-sdk/src/document/crdt/counter'; import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `Counter` is a custom data type that is used to counter. @@ -78,9 +78,10 @@ export class Counter { */ public increase(v: number | Long): Counter { if (!this.context || !this.counter) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Counter is not initialized yet', + ); } const ticket = this.context.issueTimeTicket(); @@ -105,7 +106,10 @@ export class Counter { */ public toJSForTest(): Devtools.JSONElement { if (!this.context || !this.counter) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Counter is not initialized yet', + ); } return this.counter.toJSForTest(); diff --git a/src/document/json/text.ts b/src/document/json/text.ts index cebe776f8..28e8dba77 100644 --- a/src/document/json/text.ts +++ b/src/document/json/text.ts @@ -38,6 +38,7 @@ import { stringifyObjectValues } from '@yorkie-js-sdk/src/util/object'; import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; import { SplayTree } from '@yorkie-js-sdk/src/util/splay_tree'; import { LLRBTree } from '@yorkie-js-sdk/src/util/llrb_tree'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `TextPosStruct` represents the structure of RGATreeSplitPos. @@ -92,13 +93,17 @@ export class Text { attributes?: A, ): [number, number] | undefined { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } if (fromIdx > toIdx) { - logger.fatal('from should be less than or equal to to'); - return; + throw new YorkieError( + Code.ErrInvalidArgument, + 'from should be less than or equal to to', + ); } const range = this.text.indexRangeToPosRange(fromIdx, toIdx); @@ -154,13 +159,17 @@ export class Text { */ setStyle(fromIdx: number, toIdx: number, attributes: A): boolean { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - return false; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } if (fromIdx > toIdx) { - logger.fatal('from should be less than or equal to to'); - return false; + throw new YorkieError( + Code.ErrInvalidArgument, + 'from should be less than or equal to to', + ); } const range = this.text.indexRangeToPosRange(fromIdx, toIdx); @@ -203,9 +212,10 @@ export class Text { */ indexRangeToPosRange(range: [number, number]): TextPosStructRange { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } const textRange = this.text.indexRangeToPosRange(range[0], range[1]); @@ -217,9 +227,10 @@ export class Text { */ posRangeToIndexRange(range: TextPosStructRange): [number, number] { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } const textRange = this.text.findIndexesFromRange([ @@ -235,9 +246,10 @@ export class Text { */ toTestString(): string { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } return this.text.toTestString(); @@ -248,9 +260,10 @@ export class Text { */ values(): Array> { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } return this.text.values(); @@ -285,8 +298,10 @@ export class Text { */ toString(): string { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - return ''; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } return this.text.toString(); @@ -297,7 +312,10 @@ export class Text { */ public toJSON(): string { if (!this.context || !this.text) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } return this.text.toJSON(); @@ -309,7 +327,10 @@ export class Text { */ public toJSForTest(): Devtools.JSONElement { if (!this.context || !this.text) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } return this.text.toJSForTest(); @@ -321,9 +342,10 @@ export class Text { */ createRangeForTest(fromIdx: number, toIdx: number): RGATreeSplitPosRange { if (!this.context || !this.text) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Text is not initialized yet', + ); } return this.text.indexRangeToPosRange(fromIdx, toIdx); diff --git a/src/document/json/tree.ts b/src/document/json/tree.ts index 94c6ce06d..b99161875 100644 --- a/src/document/json/tree.ts +++ b/src/document/json/tree.ts @@ -32,7 +32,6 @@ import { TreeEditOperation } from '@yorkie-js-sdk/src/document/operation/tree_ed import { isEmpty, stringifyObjectValues } from '@yorkie-js-sdk/src/util/object'; import { RHT } from '../crdt/rht'; import { TreeStyleOperation } from '../operation/tree_style_operation'; -import { logger } from '@yorkie-js-sdk/src/util/logger'; import type { ElementNode, TextNode, @@ -43,6 +42,7 @@ import type { CRDTTreeNodeIDStruct, } from '@yorkie-js-sdk/src/document/crdt/tree'; import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * NOTE(hackerwins): In normal case, we should define the following types in @@ -153,7 +153,10 @@ function createCRDTTreeNode(context: ChangeContext, content: TreeNode) { */ function validateTextNode(textNode: TextNode): boolean { if (!textNode.value.length) { - throw new Error('text node cannot have empty value'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'text node cannot have empty value', + ); } return true; @@ -172,7 +175,10 @@ function validateTreeNodes(treeNodes: Array): boolean { for (const treeNode of treeNodes) { const { type } = treeNode; if (type !== DefaultTextType) { - throw new Error('element node and text node cannot be passed together'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'element node and text node cannot be passed together', + ); } validateTextNode(treeNode as TextNode); } @@ -180,7 +186,10 @@ function validateTreeNodes(treeNodes: Array): boolean { for (const treeNode of treeNodes) { const { type } = treeNode; if (type === DefaultTextType) { - throw new Error('element node and text node cannot be passed together'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'element node and text node cannot be passed together', + ); } } } @@ -247,7 +256,10 @@ export class Tree { */ public getSize(): number { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.getSize(); @@ -258,7 +270,10 @@ export class Tree { */ public getNodeSize(): number { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.getNodeSize(); @@ -269,7 +284,10 @@ export class Tree { */ public getIndexTree(): IndexTree { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.getIndexTree(); @@ -280,11 +298,17 @@ export class Tree { */ public styleByPath(path: Array, attributes: { [key: string]: any }) { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (!path.length) { - throw new Error('path should not be empty'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'path should not be empty', + ); } const [fromPos, toPos] = this.tree.pathToPosRange(path); const ticket = this.context.issueTimeTicket(); @@ -317,11 +341,17 @@ export class Tree { attributes: { [key: string]: any }, ) { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (fromIdx > toIdx) { - throw new Error('from should be less than or equal to to'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'from should be less than or equal to to', + ); } const fromPos = this.tree.findPos(fromIdx); @@ -360,11 +390,17 @@ export class Tree { attributesToRemove: Array, ) { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (fromIdx > toIdx) { - throw new Error('from should be less than or equal to to'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'from should be less than or equal to to', + ); } const fromPos = this.tree.findPos(fromIdx); @@ -470,13 +506,22 @@ export class Tree { splitLevel = 0, ): boolean { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (fromPath.length !== toPath.length) { - throw new Error('path length should be equal'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'path length should be equal', + ); } if (!fromPath.length || !toPath.length) { - throw new Error('path should not be empty'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'path should not be empty', + ); } const fromPos = this.tree.pathToPos(fromPath); @@ -500,13 +545,22 @@ export class Tree { splitLevel = 0, ): boolean { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (fromPath.length !== toPath.length) { - throw new Error('path length should be equal'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'path length should be equal', + ); } if (!fromPath.length || !toPath.length) { - throw new Error('path should not be empty'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'path should not be empty', + ); } const fromPos = this.tree.pathToPos(fromPath); @@ -525,10 +579,16 @@ export class Tree { splitLevel = 0, ): boolean { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (fromIdx > toIdx) { - throw new Error('from should be less than or equal to to'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'from should be less than or equal to to', + ); } const fromPos = this.tree.findPos(fromIdx); @@ -552,10 +612,16 @@ export class Tree { splitLevel = 0, ): boolean { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } if (fromIdx > toIdx) { - throw new Error('from should be less than or equal to to'); + throw new YorkieError( + Code.ErrInvalidArgument, + 'from should be less than or equal to to', + ); } const fromPos = this.tree.findPos(fromIdx); @@ -569,7 +635,10 @@ export class Tree { */ public toXML(): string { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.toXML(); @@ -580,7 +649,10 @@ export class Tree { */ public toJSON(): string { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.toJSON(); @@ -592,7 +664,10 @@ export class Tree { */ public toJSForTest(): Devtools.JSONElement { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.toJSForTest(); @@ -605,7 +680,10 @@ export class Tree { */ public toJSInfoForTest(): Devtools.TreeNodeInfo { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.toJSInfoForTest(); @@ -616,7 +694,10 @@ export class Tree { */ public getRootTreeNode() { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.getRootTreeNode(); @@ -627,7 +708,10 @@ export class Tree { */ public indexToPath(index: number): Array { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.indexToPath(index); @@ -638,7 +722,10 @@ export class Tree { */ public pathToIndex(path: Array): number { if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.pathToIndex(path); @@ -651,9 +738,10 @@ export class Tree { range: [Array, Array], ): TreePosStructRange { if (!this.context || !this.tree) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } const indexRange: [number, number] = [ @@ -669,9 +757,10 @@ export class Tree { */ indexRangeToPosRange(range: [number, number]): TreePosStructRange { if (!this.context || !this.tree) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } return this.tree.indexRangeToPosStructRange(range); @@ -682,9 +771,10 @@ export class Tree { */ posRangeToIndexRange(range: TreePosStructRange): [number, number] { if (!this.context || !this.tree) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } const posRange: [CRDTTreePos, CRDTTreePos] = [ @@ -702,9 +792,10 @@ export class Tree { range: TreePosStructRange, ): [Array, Array] { if (!this.context || !this.tree) { - logger.fatal('it is not initialized yet'); - // @ts-ignore - return; + throw new YorkieError( + Code.ErrNotInitialized, + 'Tree is not initialized yet', + ); } const posRange: [CRDTTreePos, CRDTTreePos] = [ diff --git a/src/document/operation/add_operation.ts b/src/document/operation/add_operation.ts index ec7208677..478f46c26 100644 --- a/src/document/operation/add_operation.ts +++ b/src/document/operation/add_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; @@ -23,6 +22,7 @@ import { Operation, ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `AddOperation` is an operation representing adding an element to an Array. @@ -60,10 +60,16 @@ export class AddOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTArray)) { - logger.fatal(`fail to execute, only array can execute add`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only array can execute add`, + ); } const array = parentObject as CRDTArray; const value = this.value.deepcopy(); diff --git a/src/document/operation/edit_operation.ts b/src/document/operation/edit_operation.ts index 6175f9d77..290d6a819 100644 --- a/src/document/operation/edit_operation.ts +++ b/src/document/operation/edit_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { RGATreeSplitPos } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split'; @@ -25,6 +24,7 @@ import { ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; import { Indexable } from '../document'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `EditOperation` is an operation representing editing Text. Most of the same as @@ -83,10 +83,16 @@ export class EditOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTText)) { - logger.fatal(`fail to execute, only Text can execute edit`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only Text can execute edit`, + ); } const text = parentObject as CRDTText; diff --git a/src/document/operation/increase_operation.ts b/src/document/operation/increase_operation.ts index d606f271b..287087935 100644 --- a/src/document/operation/increase_operation.ts +++ b/src/document/operation/increase_operation.ts @@ -26,8 +26,8 @@ import { Primitive, PrimitiveType, } from '@yorkie-js-sdk/src/document/crdt/primitive'; -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { CRDTCounter } from '@yorkie-js-sdk/src/document/crdt/counter'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `IncreaseOperation` represents an operation that increments a numeric value to Counter. @@ -62,10 +62,16 @@ export class IncreaseOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTCounter)) { - logger.fatal(`fail to execute, only Counter can execute increase`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only Counter can execute increase`, + ); } const counter = parentObject as CRDTCounter; const value = this.value.deepcopy() as Primitive; diff --git a/src/document/operation/move_operation.ts b/src/document/operation/move_operation.ts index 6a26b3e65..864d0372f 100644 --- a/src/document/operation/move_operation.ts +++ b/src/document/operation/move_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; @@ -22,6 +21,7 @@ import { Operation, ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `MoveOperation` is an operation representing moving an element to an Array. @@ -64,10 +64,16 @@ export class MoveOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTArray)) { - logger.fatal(`fail to execute, only array can execute move`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only array can execute move`, + ); } const array = parentObject as CRDTArray; const previousIndex = Number(array.subPathOf(this.createdAt)); diff --git a/src/document/operation/operation.ts b/src/document/operation/operation.ts index bde2aca29..18057b00a 100644 --- a/src/document/operation/operation.ts +++ b/src/document/operation/operation.ts @@ -19,6 +19,7 @@ import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { TreeNode } from '@yorkie-js-sdk/src/document/crdt/tree'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { Indexable } from '@yorkie-js-sdk/src/document/document'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `OpSource` represents the source of the operation. It is used to handle @@ -210,7 +211,7 @@ export abstract class Operation { // it doesn't have an executedAt yet. The executedAt is set when // the operation is executed through undo or redo. if (!this.executedAt) { - throw new Error(`executedAt has not been set yet`); + throw new YorkieError(Code.ErrNotReady, 'executedAt is not set yet'); } return this.executedAt; } diff --git a/src/document/operation/remove_operation.ts b/src/document/operation/remove_operation.ts index 5e88da410..f1ad7b453 100644 --- a/src/document/operation/remove_operation.ts +++ b/src/document/operation/remove_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { @@ -30,6 +29,7 @@ import { import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; import { SetOperation } from '@yorkie-js-sdk/src/document/operation/set_operation'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `RemoveOperation` is an operation that removes an element from `CRDTContainer`. @@ -68,10 +68,16 @@ export class RemoveOperation extends Operation { this.getParentCreatedAt(), ) as CRDTContainer; if (!container) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(container instanceof CRDTContainer)) { - logger.fatal(`only object and array can execute remove: ${container}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `only object and array can execute remove: ${container}`, + ); } // NOTE(chacha912): Handle cases where operation cannot be executed during undo and redo. diff --git a/src/document/operation/set_operation.ts b/src/document/operation/set_operation.ts index 8d01db463..ca30b6730 100644 --- a/src/document/operation/set_operation.ts +++ b/src/document/operation/set_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; @@ -25,6 +24,7 @@ import { ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; import { RemoveOperation } from '@yorkie-js-sdk/src/document/operation/remove_operation'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `SetOperation` represents an operation that stores the value corresponding to the @@ -66,10 +66,16 @@ export class SetOperation extends Operation { ): ExecutionResult | undefined { const obj = root.findByCreatedAt(this.getParentCreatedAt()) as CRDTObject; if (!obj) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(obj instanceof CRDTObject)) { - logger.fatal(`fail to execute, only object can execute set`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only object can execute set`, + ); } // NOTE(chacha912): Handle cases where operation cannot be executed during undo and redo. diff --git a/src/document/operation/style_operation.ts b/src/document/operation/style_operation.ts index b0a248998..b7b4af721 100644 --- a/src/document/operation/style_operation.ts +++ b/src/document/operation/style_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { RGATreeSplitPos } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split'; @@ -25,6 +24,7 @@ import { ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; import { Indexable } from '../document'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `StyleOperation` is an operation applies the style of the given range to Text. @@ -77,10 +77,16 @@ export class StyleOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTText)) { - logger.fatal(`fail to execute, only Text can execute edit`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only Text can execute edit`, + ); } const text = parentObject as CRDTText; const [, pairs, changes] = text.setStyle( diff --git a/src/document/operation/tree_edit_operation.ts b/src/document/operation/tree_edit_operation.ts index 6a2bb6f82..3557a765a 100644 --- a/src/document/operation/tree_edit_operation.ts +++ b/src/document/operation/tree_edit_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { @@ -28,6 +27,7 @@ import { OperationInfo, ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `TreeEditOperation` is an operation representing Tree editing. @@ -85,10 +85,16 @@ export class TreeEditOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTTree)) { - logger.fatal(`fail to execute, only Tree can execute edit`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only Tree can execute edit`, + ); } const editedAt = this.getExecutedAt(); const tree = parentObject as CRDTTree; diff --git a/src/document/operation/tree_style_operation.ts b/src/document/operation/tree_style_operation.ts index 5f16f92a4..ecaad81da 100644 --- a/src/document/operation/tree_style_operation.ts +++ b/src/document/operation/tree_style_operation.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { @@ -28,6 +27,7 @@ import { ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; import { GCPair } from '@yorkie-js-sdk/src/document/crdt/gc'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; /** * `TreeStyleOperation` represents an operation that modifies the style of the @@ -107,10 +107,16 @@ export class TreeStyleOperation extends Operation { public execute(root: CRDTRoot): ExecutionResult { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to find ${this.getParentCreatedAt()}`, + ); } if (!(parentObject instanceof CRDTTree)) { - logger.fatal(`fail to execute, only Tree can execute edit`); + throw new YorkieError( + Code.ErrInvalidArgument, + `fail to execute, only Tree can execute edit`, + ); } const tree = parentObject as CRDTTree; let changes: Array; diff --git a/src/util/error.ts b/src/util/error.ts index 981da64b5..3abd06324 100644 --- a/src/util/error.ts +++ b/src/util/error.ts @@ -27,8 +27,11 @@ export enum Code { // ErrUnimplemented is returned when the operation is not implemented. ErrUnimplemented = 'ErrUnimplemented', - // Unsupported is returned when the operation is not supported. - Unsupported = 'unsupported', + // ErrInvalidType is returned when the type is invalid. + ErrInvalidType = 'ErrInvalidType', + + // ErrDummy is used to verify errors for testing purposes. + ErrDummy = 'ErrDummy', // ErrDocumentNotAttached is returned when the document is not attached. ErrDocumentNotAttached = 'ErrDocumentNotAttached', @@ -44,6 +47,15 @@ export enum Code { // ErrInvalidArgument is returned when the argument is invalid. ErrInvalidArgument = 'ErrInvalidArgument', + + // ErrNotInitialized is returned when required initialization has not been completed. + ErrNotInitialized = 'ErrNotInitialized', + + // ErrNotReady is returned when execution of following actions is not ready. + ErrNotReady = 'ErrNotReady', + + // ErrRefused is returned when the execution is rejected. + ErrRefused = 'ErrRefused', } /** @@ -55,7 +67,6 @@ export class YorkieError extends Error { constructor(readonly code: Code, readonly message: string) { super(message); - this.toString = (): string => - `${this.name}: [code=${this.code}]: ${this.message}`; + this.toString = (): string => `[code=${this.code}]: ${this.message}`; } } diff --git a/src/util/index_tree.ts b/src/util/index_tree.ts index 9f7c856dd..97c960615 100644 --- a/src/util/index_tree.ts +++ b/src/util/index_tree.ts @@ -15,6 +15,7 @@ */ import { TimeTicket } from '../yorkie'; +import { Code, YorkieError } from './error'; /** * About `index`, `path`, `size` and `TreePos` in crdt.IndexTree. @@ -129,7 +130,7 @@ export abstract class IndexTreeNode> { this._children = children; if (this.isText && this._children.length > 0) { - throw new Error(`Text node cannot have children: ${this.type}`); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } } @@ -303,7 +304,7 @@ export abstract class IndexTreeNode> { */ append(...newNode: Array): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } this._children.push(...newNode); @@ -319,7 +320,7 @@ export abstract class IndexTreeNode> { */ prepend(...newNode: Array): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } this._children.unshift(...newNode); @@ -333,12 +334,12 @@ export abstract class IndexTreeNode> { */ insertBefore(newNode: T, referenceNode: T): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } const offset = this._children.indexOf(referenceNode); if (offset === -1) { - throw new Error('child not found'); + throw new YorkieError(Code.ErrInvalidArgument, 'child not found'); } this.insertAtInternal(newNode, offset); @@ -350,12 +351,12 @@ export abstract class IndexTreeNode> { */ insertAfter(newNode: T, referenceNode: T): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } const offset = this._children.indexOf(referenceNode); if (offset === -1) { - throw new Error('child not found'); + throw new YorkieError(Code.ErrInvalidArgument, 'child not found'); } this.insertAtInternal(newNode, offset + 1); @@ -367,7 +368,7 @@ export abstract class IndexTreeNode> { */ insertAt(newNode: T, offset: number): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } this.insertAtInternal(newNode, offset); @@ -379,12 +380,12 @@ export abstract class IndexTreeNode> { */ removeChild(child: T) { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } const offset = this._children.indexOf(child); if (offset === -1) { - throw new Error('child not found'); + throw new YorkieError(Code.ErrInvalidArgument, 'child not found'); } this._children.splice(offset, 1); @@ -435,12 +436,12 @@ export abstract class IndexTreeNode> { */ insertAfterInternal(newNode: T, referenceNode: T): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } const offset = this._children.indexOf(referenceNode); if (offset === -1) { - throw new Error('child not found'); + throw new YorkieError(Code.ErrInvalidArgument, 'child not found'); } this.insertAtInternal(newNode, offset + 1); @@ -452,7 +453,7 @@ export abstract class IndexTreeNode> { */ insertAtInternal(newNode: T, offset: number): void { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } this._children.splice(offset, 0, newNode); @@ -465,7 +466,7 @@ export abstract class IndexTreeNode> { */ findOffset(node: T): number { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } if (node.isRemoved) { @@ -489,7 +490,7 @@ export abstract class IndexTreeNode> { */ findBranchOffset(node: T): number { if (this.isText) { - throw new Error('Text node cannot have children'); + throw new YorkieError(Code.ErrRefused, 'Text node cannot have children'); } let current: T | undefined = node; @@ -577,15 +578,24 @@ function tokensBetween>( callback: (token: TreeToken, ended: boolean) => void, ) { if (from > to) { - throw new Error(`from is greater than to: ${from} > ${to}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `from is greater than to: ${from} > ${to}`, + ); } if (from > root.size) { - throw new Error(`from is out of range: ${from} > ${root.size}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `from is out of range: ${from} > ${root.size}`, + ); } if (to > root.size) { - throw new Error(`to is out of range: ${to} > ${root.size}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `to is out of range: ${to} > ${root.size}`, + ); } if (from === to) { @@ -663,7 +673,10 @@ function findTreePos>( preferText = true, ): TreePos { if (index > node.size) { - throw new Error(`index is out of range: ${index} > ${node.size}`); + throw new YorkieError( + Code.ErrInvalidArgument, + `index is out of range: ${index} > ${node.size}`, + ); } if (node.isText) { @@ -764,7 +777,7 @@ export function findLeftmost>(node: T): T { */ function findTextPos>(node: T, pathElement: number) { if (node.size < pathElement) { - throw new Error('unacceptable path'); + throw new YorkieError(Code.ErrInvalidArgument, 'unacceptable path'); } for (let i = 0; i < node.children.length; i++) { @@ -834,7 +847,7 @@ export class IndexTree> { if (node.isText) { const offset = node.parent!.findOffset(node); if (offset === -1) { - throw new Error('invalid treePos'); + throw new YorkieError(Code.ErrInvalidArgument, 'invalid treePos'); } const sizeOfLeftSiblings = addSizeOfLeftSiblings( @@ -858,7 +871,7 @@ export class IndexTree> { while (node.parent) { const offset = node.parent.findOffset(node); if (offset === -1) { - throw new Error('invalid treePos'); + throw new YorkieError(Code.ErrInvalidArgument, 'invalid treePos'); } path.push(offset); @@ -882,7 +895,7 @@ export class IndexTree> { */ public pathToTreePos(path: Array): TreePos { if (!path.length) { - throw new Error('unacceptable path'); + throw new YorkieError(Code.ErrInvalidArgument, 'unacceptable path'); } let node = this.root; @@ -891,7 +904,7 @@ export class IndexTree> { node = node.children[pathElement]; if (!node) { - throw new Error('unacceptable path'); + throw new YorkieError(Code.ErrInvalidArgument, 'unacceptable path'); } } @@ -900,7 +913,7 @@ export class IndexTree> { } if (node.children.length < path[path.length - 1]) { - throw new Error('unacceptable path'); + throw new YorkieError(Code.ErrInvalidArgument, 'unacceptable path'); } return { @@ -965,7 +978,7 @@ export class IndexTree> { const parent = node.parent! as T; const offsetOfNode = parent.findOffset(node); if (offsetOfNode === -1) { - throw new Error('invalid pos'); + throw new YorkieError(Code.ErrInvalidArgument, 'invalid pos'); } size += addSizeOfLeftSiblings(parent, offsetOfNode); @@ -979,7 +992,7 @@ export class IndexTree> { const parent = node.parent; const offsetOfNode = parent.findOffset(node); if (offsetOfNode === -1) { - throw new Error('invalid pos'); + throw new YorkieError(Code.ErrInvalidArgument, 'invalid pos'); } size += addSizeOfLeftSiblings(parent, offsetOfNode); diff --git a/src/util/logger.ts b/src/util/logger.ts index fd33c5a56..15d2a9334 100644 --- a/src/util/logger.ts +++ b/src/util/logger.ts @@ -91,7 +91,7 @@ export const logger = { } }, - fatal: (message: string, ...messages: Array): void => { + fatal: (...messages: Array): void => { if (typeof console != 'undefined') { if (typeof console.error !== 'undefined') { console.error('YORKIE F:', ...messages); @@ -99,8 +99,6 @@ export const logger = { console.log('YORKIE F:', ...messages); } } - - throw new Error(`YORKIE F: ${message}`); }, isEnabled: (l: LogLevel): boolean => { diff --git a/src/util/observable.ts b/src/util/observable.ts index fc36ef15c..c80f1efb9 100644 --- a/src/util/observable.ts +++ b/src/util/observable.ts @@ -16,6 +16,7 @@ import { logger } from '@yorkie-js-sdk/src/util/logger'; import { uuid } from '@yorkie-js-sdk/src/util/uuid'; +import { Code, YorkieError } from './error'; export type NextFn = (value: T) => void; @@ -106,11 +107,14 @@ class ObserverProxy implements Observer { let observer: Observer; if (!nextOrObserver) { - logger.fatal('missing observer'); + throw new YorkieError(Code.ErrInvalidArgument, 'missing observer'); } if (this.finalized) { - logger.fatal('observable is finalized due to previous error'); + throw new YorkieError( + Code.ErrRefused, + 'observable is finalized due to previous error', + ); } if (typeof nextOrObserver === 'object') { diff --git a/src/util/splay_tree.ts b/src/util/splay_tree.ts index 9dc0ce4b4..e10060494 100644 --- a/src/util/splay_tree.ts +++ b/src/util/splay_tree.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { logger } from '@yorkie-js-sdk/src/util/logger'; +import { Code, YorkieError } from './error'; /** * `SplayNode` is a node of SplayTree. @@ -206,7 +206,8 @@ export class SplayTree { } } if (pos > node.getLength()) { - logger.fatal( + throw new YorkieError( + Code.ErrInvalidArgument, `out of index range: pos: ${pos} > node.length: ${node.getLength()}`, ); } diff --git a/test/bench/tree.bench.ts b/test/bench/tree.bench.ts index cec67a367..b8bb2f8ce 100644 --- a/test/bench/tree.bench.ts +++ b/test/bench/tree.bench.ts @@ -98,7 +98,7 @@ const benchmarkTreeConvert = (size: number) => { root.tree = new Tree({ type: 'doc', - children: [{ type: 'p', children: children }], + children: [{ type: 'p', children }], }); }); diff --git a/test/helper/helper.ts b/test/helper/helper.ts index bb736b7a8..dbc6e6470 100644 --- a/test/helper/helper.ts +++ b/test/helper/helper.ts @@ -36,6 +36,7 @@ import { InitialChangeID } from '@yorkie-js-sdk/src/document/change/change_id'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { ElementRHT } from '@yorkie-js-sdk/src/document/crdt/element_rht'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; export type Indexable = Record; @@ -66,9 +67,12 @@ export class EventCollector { resolve(); } else { reject( - new Error(`event is not equal ${count}- - expected: ${JSON.stringify(event)}, - actual: ${JSON.stringify(this.events[count - 1])}`), + new YorkieError( + Code.ErrInvalidArgument, + `event is not equal ${count}- + expected: ${JSON.stringify(event)}, + actual: ${JSON.stringify(this.events[count - 1])}`, + ), ); } return; diff --git a/test/integration/client_test.ts b/test/integration/client_test.ts index c56997f10..b315408f4 100644 --- a/test/integration/client_test.ts +++ b/test/integration/client_test.ts @@ -32,7 +32,7 @@ import { withTwoClientsAndDocuments, } from '@yorkie-js-sdk/test/integration/integration_helper'; import { ConnectError, Code as ConnectCode } from '@connectrpc/connect'; -import { Code } from '@yorkie-js-sdk/src/util/error'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; describe.sequential('Client', function () { afterEach(() => { @@ -133,7 +133,7 @@ describe.sequential('Client', function () { // Simulate network error with fetch vi.stubGlobal('fetch', () => { return Promise.resolve().then(() => { - throw new Error('Failed to fetch'); + throw new YorkieError(Code.ErrDummy, 'Failed to fetch'); }); }); @@ -211,7 +211,7 @@ describe.sequential('Client', function () { // Simulate network error vi.stubGlobal('fetch', () => { return Promise.resolve().then(() => { - throw new Error('Failed to fetch'); + throw new YorkieError(Code.ErrDummy, 'Failed to fetch'); }); }); diff --git a/test/integration/object_test.ts b/test/integration/object_test.ts index c4b982367..b033e100e 100644 --- a/test/integration/object_test.ts +++ b/test/integration/object_test.ts @@ -8,7 +8,7 @@ import { testRPCAddr, } from '@yorkie-js-sdk/test/integration/integration_helper'; import { toStringHistoryOp } from '@yorkie-js-sdk/test/helper/helper'; -import { YorkieError } from '@yorkie-js-sdk/src/util/error'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; describe('Object', function () { it('valid key test', function () { @@ -63,7 +63,7 @@ describe('Object', function () { assert.throws(() => { doc.update((root) => { root['k2'].push('4'); - throw new Error('dummy error'); + throw new YorkieError(Code.ErrDummy, 'dummy error'); }, 'push "4"'); }, 'dummy error'); assert.equal( diff --git a/test/integration/primitive_test.ts b/test/integration/primitive_test.ts index f102cb23f..c7bac18fd 100644 --- a/test/integration/primitive_test.ts +++ b/test/integration/primitive_test.ts @@ -3,6 +3,7 @@ import Long from 'long'; import { Document } from '@yorkie-js-sdk/src/document/document'; import { InitialCheckpoint } from '@yorkie-js-sdk/src/document/change/checkpoint'; import { withTwoClientsAndDocuments } from '@yorkie-js-sdk/test/integration/integration_helper'; +import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; describe('Primitive', function () { it('should apply updates of string', function () { @@ -35,10 +36,11 @@ describe('Primitive', function () { }); assert.equal('{"k1":{"k1-1":1,"k1-2":2}}', doc.toSortedJSON()); assert.throws(() => { + const errorMsg = 'dummy error'; doc.update((root) => { delete root['k1']['k1-1']; - throw Error('dummy error'); - }, 'dummy error'); + throw new YorkieError(Code.ErrDummy, errorMsg); + }, errorMsg); }); assert.equal('{"k1":{"k1-1":1,"k1-2":2}}', doc.toSortedJSON()); });