From 75e70fa448f2d202e092306ada27e0adc74aa25f Mon Sep 17 00:00:00 2001 From: Antonio Barcelos Date: Fri, 2 Sep 2022 12:01:20 +0200 Subject: [PATCH] Remove circular dependency between `json` and `util` Extracting `object-util` resolve this circular dependency issue. --- .../bolt-connection/src/bolt/transformer.js | 4 +- packages/core/src/internal/index.ts | 4 +- packages/core/src/internal/object-util.ts | 87 +++++++++++++++++++ packages/core/src/internal/util.ts | 68 +-------------- packages/core/src/json.ts | 2 +- .../core/test/internal/object-util.test.ts | 67 ++++++++++++++ packages/core/test/internal/util.test.ts | 49 +---------- packages/core/test/json.test.ts | 2 +- 8 files changed, 163 insertions(+), 120 deletions(-) create mode 100644 packages/core/src/internal/object-util.ts create mode 100644 packages/core/test/internal/object-util.test.ts diff --git a/packages/bolt-connection/src/bolt/transformer.js b/packages/bolt-connection/src/bolt/transformer.js index 726f05fe7..f7311f6c7 100644 --- a/packages/bolt-connection/src/bolt/transformer.js +++ b/packages/bolt-connection/src/bolt/transformer.js @@ -20,7 +20,7 @@ import { structure } from '../packstream' import { internal } from 'neo4j-driver-core' -const { util } = internal +const { objectUtil } = internal /** * Class responsible for applying the expected {@link TypeTransformer} to @@ -53,7 +53,7 @@ export default class Transformer { } return struct } catch (error) { - return util.createBrokenObject(error) + return objectUtil.createBrokenObject(error) } } diff --git a/packages/core/src/internal/index.ts b/packages/core/src/internal/index.ts index 00b91f965..ba8515a39 100644 --- a/packages/core/src/internal/index.ts +++ b/packages/core/src/internal/index.ts @@ -29,6 +29,7 @@ import * as logger from './logger' import * as urlUtil from './url-util' import * as serverAddress from './server-address' import * as resolver from './resolver' +import * as objectUtil from './object-util' export { util, @@ -42,5 +43,6 @@ export { logger, urlUtil, serverAddress, - resolver + resolver, + objectUtil } diff --git a/packages/core/src/internal/object-util.ts b/packages/core/src/internal/object-util.ts new file mode 100644 index 000000000..77016038c --- /dev/null +++ b/packages/core/src/internal/object-util.ts @@ -0,0 +1,87 @@ +/** + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +const __isBrokenObject__ = '__isBrokenObject__' +// eslint-disable-next-line @typescript-eslint/naming-convention +const __reason__ = '__reason__' + +/** + * Creates a object which all method call will throw the given error + * + * @param {Error} error The error + * @param {any} object The object. Default: {} + * @returns {any} A broken object + */ +function createBrokenObject (error: Error, object: any = {}): T { + const fail: () => T = () => { + throw error + } + + return new Proxy(object, { + get: (_: T, p: string | Symbol): any => { + if (p === __isBrokenObject__) { + return true + } else if (p === __reason__) { + return error + } else if (p === 'toJSON') { + return undefined + } + fail() + }, + set: fail, + apply: fail, + construct: fail, + defineProperty: fail, + deleteProperty: fail, + getOwnPropertyDescriptor: fail, + getPrototypeOf: fail, + has: fail, + isExtensible: fail, + ownKeys: fail, + preventExtensions: fail, + setPrototypeOf: fail + }) +} + +/** + * Verifies if it is a Broken Object + * @param {any} object The object + * @returns {boolean} If it was created with createBrokenObject + */ +function isBrokenObject (object: any): boolean { + return object !== null && typeof object === 'object' && object[__isBrokenObject__] === true +} + +/** + * Returns if the reason the object is broken. + * + * This method should only be called with instances create with {@link createBrokenObject} + * + * @param {any} object The object + * @returns {Error} The reason the object is broken + */ +function getBrokenObjectReason (object: any): Error { + return object[__reason__] +} + +export { + createBrokenObject, + isBrokenObject, + getBrokenObjectReason +} diff --git a/packages/core/src/internal/util.ts b/packages/core/src/internal/util.ts index 3b7ad1525..1d7e152d7 100644 --- a/packages/core/src/internal/util.ts +++ b/packages/core/src/internal/util.ts @@ -24,10 +24,6 @@ import { stringify } from '../json' const ENCRYPTION_ON: EncryptionLevel = 'ENCRYPTION_ON' const ENCRYPTION_OFF: EncryptionLevel = 'ENCRYPTION_OFF' -// eslint-disable-next-line @typescript-eslint/naming-convention -const __isBrokenObject__ = '__isBrokenObject__' -// eslint-disable-next-line @typescript-eslint/naming-convention -const __reason__ = '__reason__' /** * Verifies if the object is null or empty * @param obj The subject object @@ -227,65 +223,6 @@ function isString (str: any): str is string { return Object.prototype.toString.call(str) === '[object String]' } -/** - * Creates a object which all method call will throw the given error - * - * @param {Error} error The error - * @param {any} object The object. Default: {} - * @returns {any} A broken object - */ -function createBrokenObject (error: Error, object: any = {}): T { - const fail: () => T = () => { - throw error - } - - return new Proxy(object, { - get: (_: T, p: string | Symbol): any => { - if (p === __isBrokenObject__) { - return true - } else if (p === __reason__) { - return error - } else if (p === 'toJSON') { - return undefined - } - fail() - }, - set: fail, - apply: fail, - construct: fail, - defineProperty: fail, - deleteProperty: fail, - getOwnPropertyDescriptor: fail, - getPrototypeOf: fail, - has: fail, - isExtensible: fail, - ownKeys: fail, - preventExtensions: fail, - setPrototypeOf: fail - }) -} - -/** - * Verifies if it is a Broken Object - * @param {any} object The object - * @returns {boolean} If it was created with createBrokenObject - */ -function isBrokenObject (object: any): boolean { - return object !== null && typeof object === 'object' && object[__isBrokenObject__] === true -} - -/** - * Returns if the reason the object is broken. - * - * This method should only be called with instances create with {@link createBrokenObject} - * - * @param {any} object The object - * @returns {Error} The reason the object is broken - */ -function getBrokenObjectReason (object: any): Error { - return object[__reason__] -} - export { isEmptyObjectOrNull, isObject, @@ -297,8 +234,5 @@ export { assertValidDate, validateQueryAndParameters, ENCRYPTION_ON, - ENCRYPTION_OFF, - createBrokenObject, - isBrokenObject, - getBrokenObjectReason + ENCRYPTION_OFF } diff --git a/packages/core/src/json.ts b/packages/core/src/json.ts index 67fd90c42..247b9b9c9 100644 --- a/packages/core/src/json.ts +++ b/packages/core/src/json.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { isBrokenObject, getBrokenObjectReason } from './internal/util' +import { isBrokenObject, getBrokenObjectReason } from './internal/object-util' /** * Custom version on JSON.stringify that can handle values that normally don't support serialization, such as BigInt. diff --git a/packages/core/test/internal/object-util.test.ts b/packages/core/test/internal/object-util.test.ts new file mode 100644 index 000000000..792fcecae --- /dev/null +++ b/packages/core/test/internal/object-util.test.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { newError } from '../../src' +import { + createBrokenObject, + isBrokenObject, + getBrokenObjectReason +} from '../../src/internal/object-util' + +describe('isBrokenObject', () => { + it('should return true when object created with createBrokenObject', () => { + const object = createBrokenObject(newError('error'), {}) + + expect(isBrokenObject(object)).toBe(true) + }) + + it('should return false for regular objects', () => { + const object = {} + + expect(isBrokenObject(object)).toBe(false) + }) + + it('should return false for non-objects', () => { + expect(isBrokenObject(null)).toBe(false) + expect(isBrokenObject(undefined)).toBe(false) + expect(isBrokenObject(1)).toBe(false) + expect(isBrokenObject(() => {})).toBe(false) + expect(isBrokenObject('string')).toBe(false) + }) +}) + +describe('getBrokenObjectReason', () => { + it('should return the reason the object is broken', () => { + const reason = newError('error') + const object = createBrokenObject(reason, {}) + + expect(getBrokenObjectReason(object)).toBe(reason) + }) +}) + +describe('createBrokenObject', () => { + describe('toJSON', () => { + it('should return undefined', () => { + const reason = newError('error') + const object = createBrokenObject(reason, {}) + + // @ts-expect-error + expect(object.toJSON).toBeUndefined() + }) + }) +}) diff --git a/packages/core/test/internal/util.test.ts b/packages/core/test/internal/util.test.ts index b3c88df19..df218ae20 100644 --- a/packages/core/test/internal/util.test.ts +++ b/packages/core/test/internal/util.test.ts @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { newError } from '../../src' import Integer, { int } from '../../src/integer' import { isEmptyObjectOrNull, @@ -29,10 +28,7 @@ import { assertValidDate, validateQueryAndParameters, ENCRYPTION_ON, - ENCRYPTION_OFF, - createBrokenObject, - isBrokenObject, - getBrokenObjectReason + ENCRYPTION_OFF } from '../../src/internal/util' /* eslint-disable no-new-wrappers */ @@ -254,47 +250,4 @@ describe('Util', () => { expect(ENCRYPTION_ON).toBe('ENCRYPTION_ON')) test('should ENCRYPTION_OFF toBe "ENCRYPTION_OFF"', () => expect(ENCRYPTION_OFF).toBe('ENCRYPTION_OFF')) - - describe('isBrokenObject', () => { - it('should return true when object created with createBrokenObject', () => { - const object = createBrokenObject(newError('error'), {}) - - expect(isBrokenObject(object)).toBe(true) - }) - - it('should return false for regular objects', () => { - const object = {} - - expect(isBrokenObject(object)).toBe(false) - }) - - it('should return false for non-objects', () => { - expect(isBrokenObject(null)).toBe(false) - expect(isBrokenObject(undefined)).toBe(false) - expect(isBrokenObject(1)).toBe(false) - expect(isBrokenObject(() => {})).toBe(false) - expect(isBrokenObject('string')).toBe(false) - }) - }) - - describe('getBrokenObjectReason', () => { - it('should return the reason the object is broken', () => { - const reason = newError('error') - const object = createBrokenObject(reason, {}) - - expect(getBrokenObjectReason(object)).toBe(reason) - }) - }) - - describe('createBrokenObject', () => { - describe('toJSON', () => { - it('should return undefined', () => { - const reason = newError('error') - const object = createBrokenObject(reason, {}) - - // @ts-expect-error - expect(object.toJSON).toBeUndefined() - }) - }) - }) }) diff --git a/packages/core/test/json.test.ts b/packages/core/test/json.test.ts index 2c2f9239e..aba214df4 100644 --- a/packages/core/test/json.test.ts +++ b/packages/core/test/json.test.ts @@ -18,7 +18,7 @@ */ import { json, newError } from '../src' -import { createBrokenObject } from '../src/internal/util' +import { createBrokenObject } from '../src/internal/object-util' describe('json', () => { describe('.stringify', () => {