diff --git a/package.json b/package.json index 850bea2e..ffb7c852 100644 --- a/package.json +++ b/package.json @@ -59,5 +59,9 @@ "eslint": "^6.8.0", "jest": "^24.1.0", "semantic-release": "^17.2.2" + }, + "dependencies": { + "dotprop": "^1.2.0", + "dset": "^2.0.1" } } diff --git a/src/Model.js b/src/Model.js index 1510716f..601c2dc9 100644 --- a/src/Model.js +++ b/src/Model.js @@ -1,6 +1,7 @@ -import Builder from './Builder'; -import StaticModel from './StaticModel'; -import { getProp, setProp } from './utils' +import getProp from 'dotprop' +import setProp from 'dset' +import Builder from './Builder' +import StaticModel from './StaticModel' export default class Model extends StaticModel { diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index 01843f79..00000000 --- a/src/utils.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Get property defined by dot notation in string. - * - * Based on {@link https://github.com/dy/dotprop } (MIT) - * - * @param {Object} holder - Target object where to look property up. - * @param {string | string[]} propName - Dot notation, like `'a.b.c'` or `['a', 'b', 'c']`. - * @return {*} - A property value. - */ -export function getProp (holder, propName) { - if (!propName || !holder) { - return holder || {} - } - - if (propName in holder) { - return holder[propName] - } - - const propParts = Array.isArray(propName) ? propName : (propName + '').split('.') - - let result = holder - while (propParts.length && result) { - result = result[propParts.shift()] - } - - return result -} - -/** - * Set property defined by dot notation in string. - * - * Based on {@link https://github.com/lukeed/dset} (MIT) - * - * @param {Object} holder - Target object where to look property up. - * @param {string | string[]} propName - Dot notation, like `'a.b.c'` or `['a', 'b', 'c']`. - * @param {*} value - The value to be set. - */ -export function setProp (holder, propName, value) { - const propParts = Array.isArray(propName) ? propName : (propName + '').split('.') - let i = 0, l = propParts.length, t = holder, x - - for (; i < l; ++i) { - x = t[propParts[i]] - t = t[propParts[i]] = (i === l - 1 ? value : (x != null ? x : (!!~propParts[i + 1].indexOf('.') || !(+propParts[i + 1] > -1)) ? {} : [])) - } -} diff --git a/tests/utils.test.js b/tests/utils.test.js deleted file mode 100644 index fac116aa..00000000 --- a/tests/utils.test.js +++ /dev/null @@ -1,186 +0,0 @@ -import { getProp, setProp } from '../src/utils' - -describe('Utilities', () => { - /** - * Tests of `getProp` - * Based on tests from https://github.com/dy/dotprop (MIT) - */ - - test('[getProp]: Get property defined by dot notation in string.', () => { - const holder = { - a: { - b: { - c: 1 - } - } - } - - const result = getProp(holder, 'a.b.c') - - expect(result).toBe(1) - }) - - test('[getProp]: Get property defined by array-type keys.', () => { - const holder = { - a: { - b: { - c: 1 - } - } - } - - const result = getProp(holder, ['a', 'b', 'c']) - - expect(result).toBe(1) - }) - - test('[getProp]: Get property defined by simple string.', () => { - const holder = { - a: { - b: { - c: 1 - } - } - } - - const result = getProp(holder, 'a') - - expect(result).toBe(holder.a) - }) - - test('[getProp]: Get holder when propName is not defined.', () => { - const holder = { - a: { - b: { - c: 1 - } - } - } - - // @ts-ignore - const result = getProp(holder) - - expect(result).toBe(holder) - }) - - test('[getProp]: Get empty object when holder is not defined.', () => { - // @ts-ignore - const result = getProp() - - expect(result).toStrictEqual({}) - }) - - /** - * Tests of `setProp` - * Based on tests from https://github.com/lukeed/dset (MIT) - */ - - test('[setProp]: Does not return output', () => { - const foo = { a: 1, b: 2 } - const out = setProp(foo, 'c', 3) - - expect(out).toBeUndefined() - }) - - test('[setProp]: Mutates; adds simple key:val', () => { - const foo = { a: 1, b: 2 } - setProp(foo, 'c', 3) - - expect(foo).toStrictEqual({ a: 1, b: 2, c: 3 }) - }) - - test('[setProp]: Mutates; adds deeply nested key:val', () => { - const foo = {} - - // Add deep - setProp(foo, 'a.b.c', 999) - - expect(foo).toStrictEqual({ a: { b: { c: 999 } } }) - }) - - test('[setProp]: Mutates; changes the value via array-type keys', () => { - const foo = {} - - // Add deep - setProp(foo, ['a', 'b', 'c'], 123) - - expect(foo).toStrictEqual({ a: { b: { c: 123 } } }) - }) - - test('[setProp]: Mutates; changes the value via array-type keys and add array with value in index "0"', () => { - const foo = {} - - setProp(foo, ['x', '0', 'z'], 123) - - expect(foo).toStrictEqual({ x: [{ z: 123 }] }) - expect(Array.isArray(foo.x)).toBeTruthy() - }) - - test('[setProp]: Mutates; changes the value via array-type keys and add array with value in index "1"', () => { - const foo = {} - - setProp(foo, ['x', '1', 'z'], 123) - - expect(foo).toEqual({ x: [undefined, { z: 123 }] }) - expect(Array.isArray(foo.x)).toBeTruthy() - }) - - test('[setProp]: Mutates; changes the value via array-type keys, but as "10.0" is float, it doesn\'t create an array', () => { - const foo = {} - - setProp(foo, ['x', '10.0', 'z'], 123) - - expect(foo).toStrictEqual({ x: { '10.0': { z: 123 } } }) - expect(Array.isArray(foo.x)).toBeFalsy() - }) - - test('[setProp]: Mutates; changes the value via array-type keys, but as "10.2" is float, it doesn\'t create an array', () => { - const foo = {} - - setProp(foo, ['x', '10.2', 'z'], 123) - expect(foo).toStrictEqual({ x: { '10.2': { z: 123 } } }) - expect(Array.isArray(foo.x)).toBeFalsy() - }) - - test('[setProp]: Mutates; can create arrays when key is numeric', () => { - const foo = { a: 1 } - - // Create arrays instead of objects - setProp(foo, 'e.0.0', 2) - - expect(foo.e[0][0]).toStrictEqual(2) - expect(foo).toStrictEqual({ a: 1, e: [[2]] }) - expect(Array.isArray(foo.e)).toBeTruthy() - }) - - test('[setProp]: Mutates; writes into/preserves existing object', () => { - const foo = { a: { b: { c: 123 } } } - - // Preserve existing structure - setProp(foo, 'a.b.x.y', 456) - - expect(foo).toStrictEqual({ a: { b: { c: 123, x: { y: 456 } } } }) - }) - - test('[setProp]: Refuses to convert existing non-object value into object', () => { - const foo = { a: { b: 123 } } - const error = () => { - // Preserve non-object value, won't alter - setProp(foo, 'a.b.c', 'hello') - } - - expect(error).toThrow('Cannot create property \'c\' on number \'123\'') - - expect(foo.a.b).toStrictEqual(123) - expect(foo).toStrictEqual({ a: { b: 123 } }) - }) - - test('[setProp]: Mutates; writes into existing object w/ array value', () => { - const foo = { a: { b: { c: 123, d: { e: 5 } } } } - - // Preserve object tree, with array value - setProp(foo, 'a.b.d.z', [1,2,3,4]) - - expect(foo.a.b.d).toStrictEqual({ e: 5, z: [1, 2, 3, 4] }) - }) -}) diff --git a/yarn.lock b/yarn.lock index caebf2a0..57831421 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2437,7 +2437,7 @@ debug@^4.0.0: dependencies: ms "2.1.2" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= @@ -2584,6 +2584,16 @@ dotenv@^5.0.1: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== +dotprop@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/dotprop/-/dotprop-1.2.0.tgz#8fdf345c757da479ec8af218ae4239a73df721a7" + integrity sha512-mVQb8y5u3UkzNua2Hc8Ut/uKyCjm9GG2MRk/0fxJ9Mxo8Nb8XyWqaP0wVXerMucmu0mQmlcZm3S1mjOdcbCwQA== + +dset@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/dset/-/dset-2.0.1.tgz#a15fff3d1e4d60ac0c95634625cbd5441a76deb1" + integrity sha512-nI29OZMRYq36hOcifB6HTjajNAAiBKSXsyWZrq+VniusseuP2OpNlTiYgsaNRSGvpyq5Wjbc2gQLyBdTyWqhnQ== + duplexer2@~0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" @@ -3676,7 +3686,7 @@ import-local@^2.0.0: pkg-dir "^3.0.0" resolve-cwd "^2.0.0" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= @@ -4878,11 +4888,6 @@ lockfile@^1.0.4: dependencies: signal-exit "^3.0.2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -4891,33 +4896,11 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= - -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= - -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= -lodash._getnative@*, lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= - lodash._root@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" @@ -4953,11 +4936,6 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= -lodash.restparam@*: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"