Skip to content

Commit f87f96d

Browse files
authored
fix: #2138 linter issues with fail function (#2171)
* fix: #2138 linter issues with fail function - refactoring fail function to be a custom Error class - adjusting throw class given the above changes - adding missing imports - removing unused imports * adding tests * typo
1 parent 9577fc7 commit f87f96d

28 files changed

+155
-121
lines changed

__tests__/core/object.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
} from "../../src"
2222

2323
import { autorun, reaction, observable, configure, getDebugName } from "mobx"
24+
import { MstError } from "../../src/internal"
2425

2526
const createTestFactories = () => {
2627
const Factory = types
@@ -887,7 +888,7 @@ test("#993-1 - after attach should have a parent when accesing a reference direc
887888
})
888889
.actions((self) => ({
889890
afterAttach() {
890-
throw fail("should never be called")
891+
throw new MstError("should never be called")
891892
}
892893
}))
893894

__tests__/utils.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { MstError } from "../src/utils"
2+
3+
describe("MstError custom error class", () => {
4+
test("with default message", () => {
5+
const error = new MstError()
6+
expect(error.message).toBe("[mobx-state-tree] Illegal state")
7+
})
8+
9+
test("with custom message", () => {
10+
const customMessage = "custom error message"
11+
const error = new MstError(customMessage)
12+
expect(error.message).toBe(`[mobx-state-tree] ${customMessage}`)
13+
})
14+
15+
test("instance of MstError", () => {
16+
const error = new MstError()
17+
expect(error).toBeInstanceOf(MstError)
18+
expect(error).toBeInstanceOf(Error)
19+
})
20+
})

src/core/action.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { action as mobxAction } from "mobx"
22
import {
33
getStateTreeNode,
4-
fail,
4+
MstError,
55
argsToArray,
66
IDisposer,
77
getRoot,
@@ -292,12 +292,12 @@ function runMiddleWares(
292292
if (devMode()) {
293293
if (!nextInvoked && !abortInvoked) {
294294
const node2 = getStateTreeNode(call.tree)
295-
throw fail(
295+
throw new MstError(
296296
`Neither the next() nor the abort() callback within the middleware ${handler.name} for the action: "${call.name}" on the node: ${node2.type.name} was invoked.`
297297
)
298298
} else if (nextInvoked && abortInvoked) {
299299
const node2 = getStateTreeNode(call.tree)
300-
throw fail(
300+
throw new MstError(
301301
`The next() and abort() callback within the middleware ${handler.name} for the action: "${call.name}" on the node: ${node2.type.name} were invoked.`
302302
)
303303
}

src/core/flow.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { argsToArray, fail, setImmediateWithFallback } from "../utils"
1+
import { argsToArray, MstError, setImmediateWithFallback } from "../utils"
22
import {
33
FunctionWithFlag,
44
getCurrentActionContext,
@@ -98,11 +98,11 @@ export function createFlowSpawner(name: string, generator: FunctionWithFlag) {
9898
const runId = getNextActionId()
9999
const parentContext = getCurrentActionContext()!
100100
if (!parentContext) {
101-
throw fail("a mst flow must always have a parent context")
101+
throw new MstError("a mst flow must always have a parent context")
102102
}
103103
const parentActionContext = getParentActionContext(parentContext)
104104
if (!parentActionContext) {
105-
throw fail("a mst flow must always have a parent action context")
105+
throw new MstError("a mst flow must always have a parent action context")
106106
}
107107

108108
const contextBase = {
@@ -193,7 +193,7 @@ export function createFlowSpawner(name: string, generator: FunctionWithFlag) {
193193
// TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100
194194
if (!ret.value || typeof ret.value.then !== "function") {
195195
// istanbul ignore next
196-
throw fail("Only promises can be yielded to `async`, got: " + ret)
196+
throw new MstError("Only promises can be yielded to `async`, got: " + ret)
197197
}
198198
return ret.value.then(onFulfilled, onRejected)
199199
}

src/core/json-patch.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fail, stringStartsWith } from "../internal"
1+
import { MstError, stringStartsWith } from "../internal"
22

33
/**
44
* https://tools.ietf.org/html/rfc6902
@@ -19,7 +19,8 @@ export interface IReversibleJsonPatch extends IJsonPatch {
1919
* @hidden
2020
*/
2121
export function splitPatch(patch: IReversibleJsonPatch): [IJsonPatch, IJsonPatch] {
22-
if (!("oldValue" in patch)) throw fail(`Patches without \`oldValue\` field cannot be inversed`)
22+
if (!("oldValue" in patch))
23+
throw new MstError(`Patches without \`oldValue\` field cannot be inversed`)
2324
return [stripPatch(patch), invertPatch(patch)]
2425
}
2526

@@ -127,7 +128,7 @@ export function splitJsonPath(path: string): string[] {
127128
stringStartsWith(path, "./") ||
128129
stringStartsWith(path, "../")
129130
if (!valid) {
130-
throw fail(`a json path must be either rooted, empty or relative, but got '${path}'`)
131+
throw new MstError(`a json path must be either rooted, empty or relative, but got '${path}'`)
131132
}
132133

133134
// '/a/b/c' -> ["a", "b", "c"]

src/core/mst-operations.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
splitJsonPath,
1111
asArray,
1212
EMPTY_OBJECT,
13-
fail,
13+
MstError,
1414
IDisposer,
1515
resolveNodeByPath,
1616
getRelativePathBetweenNodes,
@@ -268,7 +268,7 @@ export function protect(target: IAnyStateTreeNode): void {
268268
assertIsStateTreeNode(target, 1)
269269

270270
const node = getStateTreeNode(target)
271-
if (!node.isRoot) throw fail("`protect` can only be invoked on root nodes")
271+
if (!node.isRoot) throw new MstError("`protect` can only be invoked on root nodes")
272272
node.isProtectionEnabled = true
273273
}
274274

@@ -301,7 +301,7 @@ export function unprotect(target: IAnyStateTreeNode): void {
301301
assertIsStateTreeNode(target, 1)
302302

303303
const node = getStateTreeNode(target)
304-
if (!node.isRoot) throw fail("`unprotect` can only be invoked on root nodes")
304+
if (!node.isRoot) throw new MstError("`unprotect` can only be invoked on root nodes")
305305
node.isProtectionEnabled = false
306306
}
307307

@@ -394,7 +394,7 @@ export function getParent<IT extends IAnyStateTreeNode | IAnyComplexType>(
394394
if (--d === 0) return parent.storedValue as any
395395
parent = parent.parent
396396
}
397-
throw fail(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`)
397+
throw new MstError(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`)
398398
}
399399

400400
/**
@@ -437,7 +437,7 @@ export function getParentOfType<IT extends IAnyComplexType>(
437437
if (type.is(parent.storedValue)) return parent.storedValue
438438
parent = parent.parent
439439
}
440-
throw fail(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`)
440+
throw new MstError(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`)
441441
}
442442

443443
/**
@@ -577,7 +577,7 @@ export function tryReference<N extends IAnyStateTreeNode>(
577577
return isAlive(node) ? node : undefined
578578
}
579579
} else {
580-
throw fail("The reference to be checked is not one of node, null or undefined")
580+
throw new MstError("The reference to be checked is not one of node, null or undefined")
581581
}
582582
} catch (e) {
583583
if (e instanceof InvalidReferenceError) {
@@ -605,7 +605,7 @@ export function isValidReference<N extends IAnyStateTreeNode>(
605605
} else if (isStateTreeNode(node)) {
606606
return checkIfAlive ? isAlive(node) : true
607607
} else {
608-
throw fail("The reference to be checked is not one of node, null or undefined")
608+
throw new MstError("The reference to be checked is not one of node, null or undefined")
609609
}
610610
} catch (e) {
611611
if (e instanceof InvalidReferenceError) {
@@ -777,7 +777,7 @@ export function getEnv<T = any>(target: IAnyStateTreeNode): T {
777777

778778
const node = getStateTreeNode(target)
779779
const env = node.root.environment
780-
if (!env) throw fail(`Failed to find the environment of ${node} ${node.path}`)
780+
if (!env) throw new MstError(`Failed to find the environment of ${node} ${node.path}`)
781781
return env
782782
}
783783

src/core/node/BaseNode.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
IAnyType,
88
IDisposer,
99
devMode,
10-
fail
10+
MstError
1111
} from "../../internal"
1212
import { createAtom, IAtom } from "mobx"
1313

@@ -164,7 +164,9 @@ export abstract class BaseNode<C, S, T> {
164164
if (devMode()) {
165165
if (!this.isAlive) {
166166
// istanbul ignore next
167-
throw fail("assertion failed: cannot finalize the creation of a node that is already dead")
167+
throw new MstError(
168+
"assertion failed: cannot finalize the creation of a node that is already dead"
169+
)
168170
}
169171
}
170172

src/core/node/create-node.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
fail,
2+
MstError,
33
ObjectNode,
44
ScalarNode,
55
AnyNode,
@@ -24,7 +24,7 @@ export function createObjectNode<C, S, T>(
2424
if (existingNode) {
2525
if (existingNode.parent) {
2626
// istanbul ignore next
27-
throw fail(
27+
throw new MstError(
2828
`Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '${
2929
parent ? parent.path : ""
3030
}/${subpath}', but it lives already at '${existingNode.path}'`

src/core/node/identifier-cache.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IObservableArray, values, observable, entries } from "mobx"
2-
import { fail, ObjectNode, mobxShallow, AnyObjectNode, IAnyComplexType } from "../../internal"
2+
import { MstError, ObjectNode, mobxShallow, AnyObjectNode, IAnyComplexType } from "../../internal"
33

44
let identifierCacheId = 0
55

@@ -37,7 +37,7 @@ export class IdentifierCache {
3737
this.cache.set(identifier, observable.array<AnyObjectNode>([], mobxShallow))
3838
}
3939
const set = this.cache.get(identifier)!
40-
if (set.indexOf(node) !== -1) throw fail(`Already registered`)
40+
if (set.indexOf(node) !== -1) throw new MstError(`Already registered`)
4141
set.push(node)
4242
if (lastCacheUpdate) {
4343
this.updateLastCacheModificationPerId(identifier)
@@ -114,7 +114,7 @@ export class IdentifierCache {
114114
case 1:
115115
return matches[0]
116116
default:
117-
throw fail(
117+
throw new MstError(
118118
`Cannot resolve a reference to type '${
119119
type.name
120120
}' with id: '${identifier}' unambigously, there are multiple candidates: ${matches

src/core/node/node-utils.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
fail,
2+
MstError,
33
ObjectNode,
44
splitJsonPath,
55
joinJsonPath,
@@ -89,7 +89,7 @@ export function assertIsStateTreeNode(
8989
export function getStateTreeNode(value: IAnyStateTreeNode): AnyObjectNode {
9090
if (!isStateTreeNode(value)) {
9191
// istanbul ignore next
92-
throw fail(`Value ${value} is no MST Node`)
92+
throw new MstError(`Value ${value} is no MST Node`)
9393
}
9494
return value.$treenode!
9595
}
@@ -119,7 +119,7 @@ const doubleDot = (_: any) => ".."
119119
export function getRelativePathBetweenNodes(base: AnyObjectNode, target: AnyObjectNode): string {
120120
// PRE condition target is (a child of) base!
121121
if (base.root !== target.root) {
122-
throw fail(
122+
throw new MstError(
123123
`Cannot calculate relative path: objects '${base}' and '${target}' are not part of the same object tree`
124124
)
125125
}
@@ -182,7 +182,7 @@ export function resolveNodeByPathParts(
182182
}
183183
}
184184
}
185-
throw fail(
185+
throw new MstError(
186186
`Could not resolve '${part}' in path '${
187187
joinJsonPath(pathParts.slice(0, i)) || "/"
188188
}' while resolving '${joinJsonPath(pathParts)}'`

src/core/node/object-node.ts

+13-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
createActionInvoker,
88
EMPTY_OBJECT,
99
extend,
10-
fail,
10+
MstError,
1111
freeze,
1212
IAnyType,
1313
IdentifierCache,
@@ -155,7 +155,7 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
155155
}
156156

157157
if (typeof id !== "string" && typeof id !== "number") {
158-
throw fail(
158+
throw new MstError(
159159
`Instance identifier '${this.identifierAttribute}' for type '${this.type.name}' must be a string or a number`
160160
)
161161
}
@@ -182,7 +182,7 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
182182
if (devMode()) {
183183
if (this.state !== NodeLifeCycle.INITIALIZING) {
184184
// istanbul ignore next
185-
throw fail(
185+
throw new MstError(
186186
"assertion failed: the creation of the observable instance must be done on the initializing phase"
187187
)
188188
}
@@ -294,25 +294,25 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
294294
if (devMode()) {
295295
if (!subpath) {
296296
// istanbul ignore next
297-
throw fail("assertion failed: subpath expected")
297+
throw new MstError("assertion failed: subpath expected")
298298
}
299299
if (!newParent) {
300300
// istanbul ignore next
301-
throw fail("assertion failed: new parent expected")
301+
throw new MstError("assertion failed: new parent expected")
302302
}
303303

304304
if (this.parent && parentChanged) {
305-
throw fail(
305+
throw new MstError(
306306
`A node cannot exists twice in the state tree. Failed to add ${this} to path '${newParent.path}/${subpath}'.`
307307
)
308308
}
309309
if (!this.parent && newParent.root === this) {
310-
throw fail(
310+
throw new MstError(
311311
`A state tree is not allowed to contain itself. Cannot assign ${this} to path '${newParent.path}/${subpath}'`
312312
)
313313
}
314314
if (!this.parent && !!this.environment && this.environment !== newParent.root.environment) {
315-
throw fail(
315+
throw new MstError(
316316
`A state tree cannot be made part of another state tree as long as their environments are different.`
317317
)
318318
}
@@ -394,7 +394,7 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
394394
const error = this._getAssertAliveError(context)
395395
switch (livelinessChecking) {
396396
case "error":
397-
throw fail(error)
397+
throw new MstError(error)
398398
case "warn":
399399
warnError(error)
400400
}
@@ -460,7 +460,7 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
460460
assertWritable(context: AssertAliveContext): void {
461461
this.assertAlive(context)
462462
if (!this.isRunningAction() && this.isProtected) {
463-
throw fail(
463+
throw new MstError(
464464
`Cannot modify '${this}', the object is protected and can only be modified by using an action.`
465465
)
466466
}
@@ -497,7 +497,7 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
497497
}
498498

499499
detach(): void {
500-
if (!this.isAlive) throw fail(`Error while detaching, node is not alive.`)
500+
if (!this.isAlive) throw new MstError(`Error while detaching, node is not alive.`)
501501

502502
this.clearParent()
503503
}
@@ -607,12 +607,12 @@ export class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
607607
this._internalEventsRegister(InternalEvents.Dispose, disposer, true)
608608
return
609609
}
610-
throw fail("cannot add a disposer when it is already registered for execution")
610+
throw new MstError("cannot add a disposer when it is already registered for execution")
611611
}
612612

613613
removeDisposer(disposer: () => void): void {
614614
if (!this._internalEventsHas(InternalEvents.Dispose, disposer)) {
615-
throw fail("cannot remove a disposer which was never registered for execution")
615+
throw new MstError("cannot remove a disposer which was never registered for execution")
616616
}
617617
this._internalEventsUnregister(InternalEvents.Dispose, disposer)
618618
}

0 commit comments

Comments
 (0)