mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-03-31 15:20:32 +08:00
feat: add get package
This commit is contained in:
parent
d0c60c4bfa
commit
3e59f0c954
31
.pnp.js
generated
31
.pnp.js
generated
@ -34,6 +34,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"name": "@lowdefy/poc-express",
|
||||
"reference": "workspace:packages/express"
|
||||
},
|
||||
{
|
||||
"name": "@lowdefy/get",
|
||||
"reference": "workspace:packages/get"
|
||||
},
|
||||
{
|
||||
"name": "@lowdefy/graphql",
|
||||
"reference": "workspace:packages/graphql"
|
||||
@ -47,6 +51,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"ignorePatternData": "(^(?:\\.yarn\\/sdks(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)|$))$)",
|
||||
"fallbackExclusionList": [
|
||||
["@lowdefy/engine", ["workspace:packages/engine"]],
|
||||
["@lowdefy/get", ["workspace:packages/get"]],
|
||||
["@lowdefy/graphql", ["workspace:packages/graphql"]],
|
||||
["@lowdefy/poc", ["workspace:."]],
|
||||
["@lowdefy/poc-express", ["workspace:packages/express"]],
|
||||
@ -4124,6 +4129,32 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "SOFT",
|
||||
}]
|
||||
]],
|
||||
["@lowdefy/get", [
|
||||
["workspace:packages/get", {
|
||||
"packageLocation": "./packages/get/",
|
||||
"packageDependencies": [
|
||||
["@lowdefy/get", "workspace:packages/get"],
|
||||
["@babel/cli", "virtual:7fa6405098723f150ab741c1e73c906de11a676b4cc641bac8b3397ea2dd6efbb913e72a780932220533241b442cc586b41b26c7b5ac786de486992cd2db054c#npm:7.8.4"],
|
||||
["@babel/compat-data", "npm:7.9.6"],
|
||||
["@babel/core", "npm:7.9.6"],
|
||||
["@babel/preset-env", "virtual:7fa6405098723f150ab741c1e73c906de11a676b4cc641bac8b3397ea2dd6efbb913e72a780932220533241b442cc586b41b26c7b5ac786de486992cd2db054c#npm:7.9.6"],
|
||||
["@lowdefy/type", "workspace:packages/type"],
|
||||
["babel-jest", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:24.9.0"],
|
||||
["eslint", "npm:6.8.0"],
|
||||
["eslint-config-airbnb", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:18.2.0"],
|
||||
["eslint-config-prettier", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:6.12.0"],
|
||||
["eslint-plugin-import", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:2.22.1"],
|
||||
["eslint-plugin-jsx-a11y", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:6.3.1"],
|
||||
["eslint-plugin-prettier", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:3.1.4"],
|
||||
["eslint-plugin-react", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:7.21.2"],
|
||||
["eslint-plugin-react-hooks", "virtual:73f25cc0d3f57943fa9b1d737e4809af7a52a784e0ac5fed74b4e1e083308ab7ae2fd45a5424a8bc7ff7caab067690c9357630d657cbd636d6037acc1557fdc2#npm:4.1.2"],
|
||||
["jest", "npm:24.9.0"],
|
||||
["jest-diff", "npm:24.9.0"],
|
||||
["prettier", "npm:2.1.2"]
|
||||
],
|
||||
"linkType": "SOFT",
|
||||
}]
|
||||
]],
|
||||
["@lowdefy/graphql", [
|
||||
["workspace:packages/graphql", {
|
||||
"packageLocation": "./packages/graphql/",
|
||||
|
12
packages/get/.babelrc
Normal file
12
packages/get/.babelrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "10"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
19
packages/get/jest.config.js
Normal file
19
packages/get/jest.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
module.exports = {
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: 'coverage',
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
|
||||
|
||||
// A list of reporter names that Jest uses when writing coverage reports
|
||||
coverageReporters: ['text'],
|
||||
|
||||
// The test environment that will be used for testing
|
||||
testEnvironment: 'node',
|
||||
|
||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
|
||||
};
|
33
packages/get/package.json
Normal file
33
packages/get/package.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@lowdefy/get",
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"main": "dist/get.js",
|
||||
"scripts": {
|
||||
"build": "babel src --out-dir dist",
|
||||
"test": "jest --coverage",
|
||||
"prepare": "yarn build",
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lowdefy/type": "1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.8.4",
|
||||
"@babel/compat-data": "7.9.6",
|
||||
"@babel/core": "7.9.6",
|
||||
"@babel/preset-env": "7.9.6",
|
||||
"babel-jest": "24.9.0",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-config-airbnb": "18.2.0",
|
||||
"eslint-config-prettier": "6.12.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "6.3.1",
|
||||
"eslint-plugin-prettier": "3.1.4",
|
||||
"eslint-plugin-react": "7.21.2",
|
||||
"eslint-plugin-react-hooks": "4.1.2",
|
||||
"jest": "24.9.0",
|
||||
"jest-diff": "24.9.0",
|
||||
"prettier": "2.1.2"
|
||||
}
|
||||
}
|
131
packages/get/src/get.js
Normal file
131
packages/get/src/get.js
Normal file
@ -0,0 +1,131 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
// Source:
|
||||
// https://github.com/jonschlinkert/get-value/blob/master/index.js
|
||||
// https://www.npmjs.com/package/get-value
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2014-2018, Jon Schlinkert.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import typeTest from '@lowdefy/type';
|
||||
|
||||
function join(segs, joinChar, options) {
|
||||
if (typeof options.join === 'function') {
|
||||
return options.join(segs);
|
||||
}
|
||||
return segs[0] + joinChar + segs[1];
|
||||
}
|
||||
|
||||
function split(path, splitChar, options) {
|
||||
if (typeof options.split === 'function') {
|
||||
return options.split(path);
|
||||
}
|
||||
return path.split(splitChar);
|
||||
}
|
||||
|
||||
function isValid(key, target, options) {
|
||||
if (typeof options.isValid === 'function') {
|
||||
return options.isValid(key, target);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isValidObject(val) {
|
||||
return typeTest.isObject(val) || Array.isArray(val) || typeof val === 'function';
|
||||
}
|
||||
|
||||
function get(target, path, options) {
|
||||
if (!typeTest.isObject(options)) {
|
||||
options = { default: options };
|
||||
}
|
||||
|
||||
if (typeTest.isNone(path) || !isValidObject(target)) {
|
||||
return typeof options.default !== 'undefined' ? options.default : undefined;
|
||||
}
|
||||
|
||||
if (typeof path === 'number') {
|
||||
path = String(path);
|
||||
}
|
||||
|
||||
const isArray = Array.isArray(path);
|
||||
const isString = typeof path === 'string';
|
||||
const splitChar = options.separator || '.';
|
||||
const joinChar = options.joinChar || (typeof splitChar === 'string' ? splitChar : '.');
|
||||
|
||||
if (isString && path in target) {
|
||||
return isValid(path, target, options) ? target[path] : options.default;
|
||||
}
|
||||
|
||||
const segs = isArray ? path : split(path, splitChar, options);
|
||||
const len = segs.length;
|
||||
let idx = 0;
|
||||
|
||||
do {
|
||||
let prop = segs[idx];
|
||||
if (typeof prop === 'number') {
|
||||
prop = String(prop);
|
||||
}
|
||||
|
||||
while (prop && prop.slice(-1) === '\\') {
|
||||
idx += 1;
|
||||
prop = join([prop.slice(0, -1), segs[idx] || ''], joinChar, options);
|
||||
}
|
||||
|
||||
if (prop in target) {
|
||||
if (!isValid(prop, target, options)) {
|
||||
return options.default;
|
||||
}
|
||||
|
||||
target = target[prop];
|
||||
} else {
|
||||
let hasProp = false;
|
||||
let n = idx + 1;
|
||||
|
||||
while (n < len) {
|
||||
prop = join([prop, segs[n]], joinChar, options);
|
||||
n += 1;
|
||||
hasProp = prop in target;
|
||||
if (hasProp) {
|
||||
if (!isValid(prop, target, options)) {
|
||||
return options.default;
|
||||
}
|
||||
|
||||
target = target[prop];
|
||||
idx = n - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasProp) {
|
||||
return options.default;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-plusplus
|
||||
} while (++idx < len && isValidObject(target));
|
||||
|
||||
if (idx === len) {
|
||||
return target;
|
||||
}
|
||||
|
||||
return options.default;
|
||||
}
|
||||
|
||||
export default get;
|
615
packages/get/test/get.test.js
Normal file
615
packages/get/test/get.test.js
Normal file
@ -0,0 +1,615 @@
|
||||
import get from '../src/get';
|
||||
|
||||
const diff = require('jest-diff');
|
||||
|
||||
const expectToEqual = (result, value) => {
|
||||
expect(result).toEqual(value);
|
||||
};
|
||||
|
||||
const expectToStrictEqual = (result, value) => {
|
||||
expect(result).toStrictEqual(value);
|
||||
};
|
||||
|
||||
expect.extend({
|
||||
deepStrictEqual(received, expected) {
|
||||
const options = {};
|
||||
const pass = this.equals(received, expected);
|
||||
const message = pass
|
||||
? () =>
|
||||
`${this.utils.matcherHint('deepStrictEqual', undefined, undefined, options)}\n\n` +
|
||||
`Expected: ${this.utils.printExpected(expected)}\n` +
|
||||
`Received: ${this.utils.printReceived(received)}`
|
||||
: () => {
|
||||
const diffString = diff(expected, received, {
|
||||
expand: this.expand,
|
||||
});
|
||||
return `${this.utils.matcherHint('deepStrictEqual', undefined, undefined, options)}\n\n${
|
||||
diffString && diffString.includes('- Expect')
|
||||
? `Difference:\n\n${diffString}`
|
||||
: `Expected: ${this.utils.printExpected(
|
||||
expected
|
||||
)}\nReceived: ${this.utils.printReceived(received)}`
|
||||
}`;
|
||||
};
|
||||
|
||||
return { actual: received, message, pass };
|
||||
},
|
||||
});
|
||||
|
||||
const expectDeepStrictEqual = (result, value) => {
|
||||
expect(result).deepStrictEqual(value);
|
||||
};
|
||||
|
||||
test('get a', () => {
|
||||
const objOne = {
|
||||
a: 1,
|
||||
};
|
||||
expect(get(objOne, 'a')).toEqual(1);
|
||||
});
|
||||
|
||||
test('get undefined', () => {
|
||||
const objOne = {
|
||||
a: 1,
|
||||
};
|
||||
expect(get(objOne, 'b')).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('get a.b', () => {
|
||||
const objOne = {
|
||||
a: { b: 1 },
|
||||
};
|
||||
expect(get(objOne, 'a.b')).toEqual(1);
|
||||
});
|
||||
|
||||
test('get --b', () => {
|
||||
const objOne = {
|
||||
'--b': 10,
|
||||
};
|
||||
expect(get(objOne, '--b')).toEqual(10);
|
||||
});
|
||||
|
||||
test('get a.--b', () => {
|
||||
const objOne = {
|
||||
a: { '--b': 1 },
|
||||
};
|
||||
expect(get(objOne, 'a.--b')).toEqual(1);
|
||||
});
|
||||
|
||||
test('get a.undefined', () => {
|
||||
const objOne = {
|
||||
a: { b: 1 },
|
||||
};
|
||||
expect(get(objOne, 'a.c')).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('get a.0.b in array', () => {
|
||||
const objOne = {
|
||||
a: [{ b: 1 }, { c: 2 }],
|
||||
};
|
||||
expect(get(objOne, 'a.1.c')).toEqual(2);
|
||||
});
|
||||
|
||||
test('return alt value', () => {
|
||||
const objOne = {
|
||||
a: 1,
|
||||
};
|
||||
expect(get(objOne, 'b', 3)).toEqual(3);
|
||||
});
|
||||
|
||||
test('return null value', () => {
|
||||
const objOne = {
|
||||
a: null,
|
||||
};
|
||||
expect(get(objOne, 'a', 2)).toEqual(null);
|
||||
});
|
||||
|
||||
test('return arr', () => {
|
||||
const objOne = {
|
||||
a: { b: [] },
|
||||
};
|
||||
expect(get(objOne, 'a.b')).toEqual([]);
|
||||
});
|
||||
|
||||
// tests from
|
||||
// https://github.com/jonschlinkert/get-value/blob/master/test/units.js
|
||||
|
||||
test('should return undefined when non-object given as the first argument', () => {
|
||||
expect(get(null)).toEqual(undefined);
|
||||
expect(get('foo')).toEqual(undefined);
|
||||
expect(get(['a'])).toEqual(undefined);
|
||||
expect(get({ a: 'a' })).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('should return default value when non-object given as the first argument with default value', () => {
|
||||
expect(get(null, undefined, { default: 'default' })).toEqual('default');
|
||||
expect(get('foo', undefined, { default: 'default' })).toEqual('default');
|
||||
expect(get(['a'], undefined, { default: 'default' })).toEqual('default');
|
||||
expect(get({ a: 'a' }, undefined, { default: 'default' })).toEqual('default');
|
||||
});
|
||||
|
||||
test('should get a value', () => {
|
||||
expectToEqual(get({ a: 'a', b: { c: 'd' } }, 'a'), 'a');
|
||||
expectToEqual(get({ a: 'a', b: { c: 'd' } }, 'b.c'), 'd');
|
||||
expectToEqual(get({ foo: 'bar' }, 'foo.bar'), undefined);
|
||||
});
|
||||
|
||||
test('should get a property that has dots in the key', () => {
|
||||
expectToEqual(get({ 'a.b': 'c' }, 'a.b'), 'c');
|
||||
});
|
||||
|
||||
test('should support using dot notation to get nested values', () => {
|
||||
const fixture = {
|
||||
a: { locals: { name: { first: 'Brian' } } },
|
||||
b: { locals: { name: { last: 'Woodward' } } },
|
||||
c: { locals: { paths: ['a.txt', 'b.js', 'c.hbs'] } },
|
||||
};
|
||||
expectDeepStrictEqual(get(fixture, 'a.locals.name'), { first: 'Brian' });
|
||||
expectDeepStrictEqual(get(fixture, 'b.locals.name'), { last: 'Woodward' });
|
||||
expectToStrictEqual(get(fixture, 'b.locals.name.last'), 'Woodward');
|
||||
expectToStrictEqual(get(fixture, 'c.locals.paths.0'), 'a.txt');
|
||||
expectToStrictEqual(get(fixture, 'c.locals.paths.1'), 'b.js');
|
||||
expectToStrictEqual(get(fixture, 'c.locals.paths.2'), 'c.hbs');
|
||||
expectToStrictEqual(get(fixture, 'c.locals.paths.0'), 'a.txt');
|
||||
expectToStrictEqual(get(fixture, 'c.locals.paths.1'), 'b.js');
|
||||
expectToStrictEqual(get(fixture, 'c.locals.paths.2'), 'c.hbs');
|
||||
});
|
||||
|
||||
test('should support a custom separator on options.separator', () => {
|
||||
const fixture = { 'a.b': { c: { d: 'e' } } };
|
||||
expectToStrictEqual(get(fixture, 'a.b/c/d', { separator: '/' }), 'e');
|
||||
expectToStrictEqual(get(fixture, 'a\\.b.c.d', { separator: /\\?\./ }), 'e');
|
||||
});
|
||||
|
||||
test('should support a custom split function', () => {
|
||||
const fixture = { 'a.b': { c: { d: 'e' } } };
|
||||
expectToStrictEqual(get(fixture, 'a.b/c/d', { split: (path) => path.split('/') }), 'e');
|
||||
expectToStrictEqual(get(fixture, 'a\\.b.c.d', { split: (path) => path.split(/\\?\./) }), 'e');
|
||||
});
|
||||
|
||||
test('should support a custom join character', () => {
|
||||
const fixture = { 'a-b': { c: { d: 'e' } } };
|
||||
const options = { joinChar: '-' };
|
||||
expectToStrictEqual(get(fixture, 'a.b.c.d', options), 'e');
|
||||
});
|
||||
|
||||
test('should support a custom join function', () => {
|
||||
const fixture = { 'a-b': { c: { d: 'e' } } };
|
||||
const options = {
|
||||
split: (path) => path.split(/[-/]/),
|
||||
join: (segs) => segs.join('-'),
|
||||
};
|
||||
expectToStrictEqual(get(fixture, 'a/b-c/d', options), 'e');
|
||||
});
|
||||
|
||||
test('should support a default value as the last argument', () => {
|
||||
const fixture = { foo: { c: { d: 'e' } } };
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', 'quz'), 'quz');
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', true), true);
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', false), false);
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', null), null);
|
||||
});
|
||||
|
||||
test('should support options.default', () => {
|
||||
const fixture = { foo: { c: { d: 'e' } } };
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', { default: 'qux' }), 'qux');
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', { default: true }), true);
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', { default: false }), false);
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', { default: null }), null);
|
||||
expectDeepStrictEqual(get(fixture, 'foo.bar.baz', { default: { one: 'two' } }), { one: 'two' });
|
||||
});
|
||||
|
||||
test('should support a custom function for validating the object', () => {
|
||||
const isEnumerable = Object.prototype.propertyIsEnumerable;
|
||||
const options = {
|
||||
isValid(key, obj) {
|
||||
return isEnumerable.call(obj, key);
|
||||
},
|
||||
};
|
||||
|
||||
const fixture = { 'a.b': { c: { d: 'e' } } };
|
||||
expectToStrictEqual(get(fixture, 'a.b.c.d', options), 'e');
|
||||
});
|
||||
|
||||
test('should support nested keys with dots', () => {
|
||||
expectToStrictEqual(get({ 'a.b.c': 'd' }, 'a.b.c'), 'd');
|
||||
expectToStrictEqual(get({ 'a.b': { c: 'd' } }, 'a.b.c'), 'd');
|
||||
expectToStrictEqual(get({ 'a.b': { c: { d: 'e' } } }, 'a.b.c.d'), 'e');
|
||||
expectToStrictEqual(get({ a: { b: { c: 'd' } } }, 'a.b.c'), 'd');
|
||||
expectToStrictEqual(get({ a: { 'b.c': 'd' } }, 'a.b.c'), 'd');
|
||||
expectToStrictEqual(get({ 'a.b.c.d': 'e' }, 'a.b.c.d'), 'e');
|
||||
expectToStrictEqual(get({ 'a.b.c.d': 'e' }, 'a.b.c'), undefined);
|
||||
|
||||
expectToStrictEqual(get({ 'a.b.c.d.e.f': 'g' }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b.c.d.e': { f: 'g' } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b.c.d': { e: { f: 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b.c': { d: { e: { f: 'g' } } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b': { c: { d: { e: { f: 'g' } } } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ a: { b: { c: { d: { e: { f: 'g' } } } } } }, 'a.b.c.d.e.f'), 'g');
|
||||
|
||||
expectDeepStrictEqual(get({ 'a.b.c.d.e': { f: 'g' } }, 'a.b.c.d.e'), {
|
||||
f: 'g',
|
||||
});
|
||||
expectDeepStrictEqual(get({ 'a.b.c.d': { 'e.f': 'g' } }, 'a.b.c.d.e'), undefined);
|
||||
expectDeepStrictEqual(get({ 'a.b.c': { 'd.e.f': 'g' } }, 'a.b.c'), {
|
||||
'd.e.f': 'g',
|
||||
});
|
||||
expectDeepStrictEqual(get({ 'a.b': { 'c.d.e.f': 'g' } }, 'a.b'), {
|
||||
'c.d.e.f': 'g',
|
||||
});
|
||||
expectDeepStrictEqual(get({ a: { 'b.c.d.e.f': 'g' } }, 'a'), {
|
||||
'b.c.d.e.f': 'g',
|
||||
});
|
||||
|
||||
expectToStrictEqual(get({ 'a.b.c.d.e': { f: 'g' } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b.c.d': { 'e.f': 'g' } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b.c': { 'd.e.f': 'g' } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b': { 'c.d.e.f': 'g' } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ a: { 'b.c.d.e.f': 'g' } }, 'a.b.c.d.e.f'), 'g');
|
||||
|
||||
expectToStrictEqual(get({ 'a.b': { 'c.d': { 'e.f': 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ 'a.b': { c: { 'd.e.f': 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ a: { 'b.c.d.e': { f: 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ a: { 'b.c.d': { 'e.f': 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ a: { 'b.c': { 'd.e.f': 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
expectToStrictEqual(get({ a: { b: { 'c.d.e.f': 'g' } } }, 'a.b.c.d.e.f'), 'g');
|
||||
});
|
||||
|
||||
test('should support return default when options.isValid returns false', () => {
|
||||
const fixture = { foo: { bar: { baz: 'qux' }, 'a.b.c': 'xyx', yyy: 'zzz' } };
|
||||
const options = (val) => ({
|
||||
...{
|
||||
default: val,
|
||||
isValid(key) {
|
||||
return key !== 'bar' && key !== 'a.b.c';
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', options('fez')), 'fez');
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', options(true)), true);
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', options(false)), false);
|
||||
expectToEqual(get(fixture, 'foo.bar.baz', options(null)), null);
|
||||
|
||||
expectToEqual(get(fixture, 'foo.a.b.c', options('fez')), 'fez');
|
||||
expectToEqual(get(fixture, 'foo.a.b.c', options(true)), true);
|
||||
expectToEqual(get(fixture, 'foo.a.b.c', options(false)), false);
|
||||
expectToEqual(get(fixture, 'foo.a.b.c', options(null)), null);
|
||||
|
||||
expectToEqual(get(fixture, 'foo.yyy', options('fez')), 'zzz');
|
||||
});
|
||||
|
||||
test('should get a value from an array', () => {
|
||||
const fixture = {
|
||||
a: { paths: ['a.txt', 'a.js', 'a.hbs'] },
|
||||
b: {
|
||||
paths: {
|
||||
0: 'b.txt',
|
||||
1: 'b.js',
|
||||
2: 'b.hbs',
|
||||
3: 'b3.hbs',
|
||||
},
|
||||
},
|
||||
};
|
||||
expectToStrictEqual(get(fixture, 'a.paths.0'), 'a.txt');
|
||||
expectToStrictEqual(get(fixture, 'a.paths.1'), 'a.js');
|
||||
expectToStrictEqual(get(fixture, 'a.paths.2'), 'a.hbs');
|
||||
|
||||
expectToStrictEqual(get(fixture, 'b.paths.0'), 'b.txt');
|
||||
expectToStrictEqual(get(fixture, 'b.paths.1'), 'b.js');
|
||||
expectToStrictEqual(get(fixture, 'b.paths.2'), 'b.hbs');
|
||||
expectToStrictEqual(get(fixture, 'b.paths.3'), 'b3.hbs');
|
||||
});
|
||||
|
||||
test('should get a value from an object in an array', () => {
|
||||
expectToStrictEqual(get({ a: { b: [{ c: 'd' }] } }, 'a.b.0.c'), 'd');
|
||||
expectToStrictEqual(get({ a: { b: [{ c: 'd' }, { e: 'f' }] } }, 'a.b.1.e'), 'f');
|
||||
expectToStrictEqual(get({ a: { b: [{ c: 'd' }] } }, 'a.b.0.c'), 'd');
|
||||
expectToStrictEqual(get({ a: { b: [{ c: 'd' }, { e: 'f' }] } }, 'a.b.1.e'), 'f');
|
||||
});
|
||||
|
||||
test('should return `undefined` if the path is not found', () => {
|
||||
const fixture = { a: { b: {} } };
|
||||
expectToStrictEqual(get(fixture, 'a.b.c'), undefined);
|
||||
expectToStrictEqual(get(fixture, 'a.b.c.d'), undefined);
|
||||
});
|
||||
|
||||
test('should get the specified property', () => {
|
||||
expectDeepStrictEqual(get({ a: 'aaa', b: 'b' }, 'a'), 'aaa');
|
||||
expectDeepStrictEqual(get({ first: 'Jon', last: 'Schlinkert' }, 'first'), 'Jon');
|
||||
expectDeepStrictEqual(get({ locals: { a: 'a' }, options: { b: 'b' } }, 'locals'), { a: 'a' });
|
||||
});
|
||||
|
||||
test('should support passing a property formatted as an array', () => {
|
||||
expectDeepStrictEqual(get({ a: 'aaa', b: 'b' }, ['a']), 'aaa');
|
||||
expectDeepStrictEqual(get({ a: { b: { c: 'd' } } }, ['a', 'b', 'c']), 'd');
|
||||
expectDeepStrictEqual(get({ first: 'Harry', last: 'Potter' }, ['first']), 'Harry');
|
||||
expectDeepStrictEqual(get({ locals: { a: 'a' }, options: { b: 'b' } }, ['locals']), { a: 'a' });
|
||||
});
|
||||
|
||||
test('should support escaped dots', () => {
|
||||
expectDeepStrictEqual(get({ 'a.b': 'a', b: { c: 'd' } }, 'a\\.b'), 'a');
|
||||
expectDeepStrictEqual(get({ 'a.b': { b: { c: 'd' } } }, 'a\\.b.b.c'), 'd');
|
||||
});
|
||||
|
||||
test('should get the value of a deeply nested property', () => {
|
||||
expectToStrictEqual(get({ a: { b: 'c', c: { d: 'e', e: 'f', g: { h: 'i' } } } }, 'a.c.g.h'), 'i');
|
||||
});
|
||||
|
||||
/**
|
||||
* These tests are from the "dot-prop" library
|
||||
*/
|
||||
|
||||
describe('dot-prop tests:', () => {
|
||||
test('should pass dot-prop tests', () => {
|
||||
const f1 = { foo: { bar: 1 } };
|
||||
f1[''] = 'foo';
|
||||
expectDeepStrictEqual(get(f1, ''), 'foo');
|
||||
expectDeepStrictEqual(get(f1, 'foo'), f1.foo);
|
||||
expectDeepStrictEqual(get({ foo: 1 }, 'foo'), 1);
|
||||
expectDeepStrictEqual(get({ foo: null }, 'foo'), null);
|
||||
expectDeepStrictEqual(get({ foo: undefined }, 'foo'), undefined);
|
||||
expectDeepStrictEqual(get({ foo: { bar: true } }, 'foo.bar'), true);
|
||||
expectDeepStrictEqual(get({ foo: { bar: { baz: true } } }, 'foo.bar.baz'), true);
|
||||
expectDeepStrictEqual(get({ foo: { bar: { baz: null } } }, 'foo.bar.baz'), null);
|
||||
expectDeepStrictEqual(get({ '\\': true }, '\\'), true);
|
||||
expectDeepStrictEqual(get({ '\\foo': true }, '\\foo'), true);
|
||||
expectDeepStrictEqual(get({ 'bar\\': true }, 'bar\\'), true);
|
||||
expectDeepStrictEqual(get({ 'foo\\bar': true }, 'foo\\bar'), true);
|
||||
expectDeepStrictEqual(get({ '\\.foo': true }, '\\\\.foo'), true);
|
||||
expectDeepStrictEqual(get({ 'bar\\.': true }, 'bar\\\\.'), true);
|
||||
expectDeepStrictEqual(get({ 'foo\\.bar': true }, 'foo\\\\.bar'), true);
|
||||
expectDeepStrictEqual(get({ foo: 1 }, 'foo.bar'), undefined);
|
||||
|
||||
function fn() {}
|
||||
fn.foo = { bar: 1 };
|
||||
expectDeepStrictEqual(get(fn, 'foo'), fn.foo);
|
||||
expectDeepStrictEqual(get(fn, 'foo.bar'), 1);
|
||||
|
||||
const f3 = { foo: null };
|
||||
expectDeepStrictEqual(get(f3, 'foo.bar'), undefined);
|
||||
expectDeepStrictEqual(get(f3, 'foo.bar', { default: 'some value' }), 'some value');
|
||||
|
||||
expectDeepStrictEqual(get({ 'foo.baz': { bar: true } }, 'foo\\.baz.bar'), true);
|
||||
expectDeepStrictEqual(get({ 'fo.ob.az': { bar: true } }, 'fo\\.ob\\.az.bar'), true);
|
||||
|
||||
expectDeepStrictEqual(get(null, 'foo.bar', { default: false }), false);
|
||||
expectDeepStrictEqual(get('foo', 'foo.bar', { default: false }), false);
|
||||
expectDeepStrictEqual(get([], 'foo.bar', { default: false }), false);
|
||||
expectDeepStrictEqual(get(undefined, 'foo.bar', { default: false }), false);
|
||||
});
|
||||
|
||||
test('should use a custom options.isValid function', () => {
|
||||
const isEnumerable = Object.prototype.propertyIsEnumerable;
|
||||
const options = {
|
||||
isValid: (key, obj) => isEnumerable.call(obj, key),
|
||||
};
|
||||
|
||||
const target = {};
|
||||
Object.defineProperty(target, 'foo', {
|
||||
value: 'bar',
|
||||
enumerable: false,
|
||||
});
|
||||
|
||||
expectDeepStrictEqual(get(target, 'foo', options), undefined);
|
||||
expectDeepStrictEqual(get({}, 'hasOwnProperty', options), undefined);
|
||||
});
|
||||
|
||||
test('should return a default value', () => {
|
||||
expectDeepStrictEqual(get({ foo: { bar: 'a' } }, 'foo.fake'), undefined);
|
||||
expectDeepStrictEqual(get({ foo: { bar: 'a' } }, 'foo.fake.fake2'), undefined);
|
||||
expectDeepStrictEqual(get({ foo: { bar: 'a' } }, 'foo.fake.fake2', 'some value'), 'some value');
|
||||
});
|
||||
|
||||
test('should pass all of the dot-prop tests', () => {
|
||||
const f1 = { foo: { bar: 1 } };
|
||||
expectDeepStrictEqual(get(f1), undefined);
|
||||
expectDeepStrictEqual(get(f1, 'foo'), f1.foo);
|
||||
expectDeepStrictEqual(get({ foo: 1 }, 'foo'), 1);
|
||||
expectDeepStrictEqual(get({ foo: null }, 'foo'), null);
|
||||
expectDeepStrictEqual(get({ foo: undefined }, 'foo'), undefined);
|
||||
expectDeepStrictEqual(get({ foo: { bar: true } }, 'foo.bar'), true);
|
||||
expectDeepStrictEqual(get({ foo: { bar: { baz: true } } }, 'foo.bar.baz'), true);
|
||||
expectDeepStrictEqual(get({ foo: { bar: { baz: null } } }, 'foo.bar.baz'), null);
|
||||
expectDeepStrictEqual(get({ foo: { bar: 'a' } }, 'foo.fake.fake2'), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* These tests are from the "object-path" library
|
||||
*/
|
||||
|
||||
describe('object-path .get tests', () => {
|
||||
function getTestObj() {
|
||||
return {
|
||||
a: 'b',
|
||||
b: {
|
||||
c: [],
|
||||
d: ['a', 'b'],
|
||||
e: [{}, { f: 'g' }],
|
||||
f: 'i',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('should return the value using unicode key', () => {
|
||||
const obj = { '15\u00f8C': { '3\u0111': 1 } };
|
||||
expectToEqual(get(obj, '15\u00f8C.3\u0111'), 1);
|
||||
expectToEqual(get(obj, ['15\u00f8C', '3\u0111']), 1);
|
||||
});
|
||||
|
||||
test('should return the value using dot in key (with array of segments)', () => {
|
||||
const obj = { 'a.b': { 'looks.like': 1 } };
|
||||
expectToEqual(get(obj, ['a.b', 'looks.like']), 1);
|
||||
});
|
||||
|
||||
test('should return the value of an empty array', () => {
|
||||
const obj = { a: { b: [] } };
|
||||
expectToEqual(get(obj, 'a.b'), []);
|
||||
});
|
||||
|
||||
// object-path fails this test
|
||||
test('should return the value using dot in key', () => {
|
||||
const obj = { 'a.b': { 'looks.like': 1 } };
|
||||
expectToEqual(get(obj, 'a.b.looks.like'), 1);
|
||||
});
|
||||
|
||||
test('should return the value under shallow object', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj, 'a'), 'b');
|
||||
expectToEqual(get(obj, ['a']), 'b');
|
||||
});
|
||||
|
||||
test('should work with number path', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj.b.d, 0), 'a');
|
||||
expectToEqual(get(obj.b, 0), undefined);
|
||||
});
|
||||
|
||||
test('should return the value under deep object', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj, 'b.f'), 'i');
|
||||
expectToEqual(get(obj, ['b', 'f']), 'i');
|
||||
});
|
||||
|
||||
test('should return the value under array', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj, 'b.d.0'), 'a');
|
||||
expectToEqual(get(obj, ['b', 'd', 0]), 'a');
|
||||
});
|
||||
|
||||
test('should return the value under array deep', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj, 'b.e.1.f'), 'g');
|
||||
expectToEqual(get(obj, ['b', 'e', 1, 'f']), 'g');
|
||||
});
|
||||
|
||||
test('should return undefined for missing values under object', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj, 'a.b'), undefined);
|
||||
expectToEqual(get(obj, ['a', 'b']), undefined);
|
||||
});
|
||||
|
||||
test('should return undefined for missing values under array', () => {
|
||||
const obj = getTestObj();
|
||||
expectToEqual(get(obj, 'b.d.5'), undefined);
|
||||
expectToEqual(get(obj, ['b', 'd', '5']), undefined);
|
||||
});
|
||||
|
||||
test('should return the value under integer-like key', () => {
|
||||
const obj = { '1a': 'foo' };
|
||||
expectToEqual(get(obj, '1a'), 'foo');
|
||||
expectToEqual(get(obj, ['1a']), 'foo');
|
||||
});
|
||||
|
||||
test('should return the default value when the key doesnt exist', () => {
|
||||
const obj = { '1a': 'foo' };
|
||||
expectToEqual(get(obj, '1b', null), null);
|
||||
expectToEqual(get(obj, ['1b'], null), null);
|
||||
});
|
||||
|
||||
// this test differs from behavior in object-path. I was unable to figure
|
||||
// out exactly how the default values work in object-path.
|
||||
test('should return the default value when path is empty', () => {
|
||||
const obj = { '1a': 'foo' };
|
||||
expectDeepStrictEqual(get(obj, '', null), null);
|
||||
expectDeepStrictEqual(get(obj, []), undefined);
|
||||
expectToEqual(get({}, ['1'], 'foo'), 'foo');
|
||||
});
|
||||
|
||||
test('should return the default value when object is null or undefined', () => {
|
||||
expectDeepStrictEqual(get(null, 'test', { default: 'a' }), 'a');
|
||||
expectDeepStrictEqual(get(undefined, 'test', { default: 'a' }), 'a');
|
||||
});
|
||||
|
||||
test('should not fail on an object with a null prototype', () => {
|
||||
const foo = 'FOO';
|
||||
const objWithNullProto = Object.create(null);
|
||||
objWithNullProto.foo = foo;
|
||||
expectToEqual(get(objWithNullProto, 'foo'), foo);
|
||||
});
|
||||
|
||||
// this differs from object-path, which does not allow
|
||||
// the user to get non-own properties for some reason.
|
||||
test('should get non-"own" properties', () => {
|
||||
const Base = function () {};
|
||||
Base.prototype = {
|
||||
one: {
|
||||
two: true,
|
||||
},
|
||||
};
|
||||
const Extended = function () {
|
||||
Base.call(this, true);
|
||||
};
|
||||
Extended.prototype = Object.create(Base.prototype);
|
||||
|
||||
const extended = new Extended();
|
||||
|
||||
expectToEqual(get(extended, ['one', 'two']), true);
|
||||
extended.enabled = true;
|
||||
|
||||
expectToEqual(get(extended, 'enabled'), true);
|
||||
expectDeepStrictEqual(get(extended, 'one'), { two: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('deep-property unit tests', () => {
|
||||
test('should handle invalid input', () => {
|
||||
const a = undefined;
|
||||
const b = {};
|
||||
|
||||
expectToEqual(get(a, 'sample'), undefined);
|
||||
expectDeepStrictEqual(get(b, undefined), undefined);
|
||||
expectDeepStrictEqual(get(b, ''), undefined);
|
||||
expectDeepStrictEqual(get(b, '...'), undefined);
|
||||
});
|
||||
|
||||
test('should get shallow properties', () => {
|
||||
const fn = function () {};
|
||||
const a = {
|
||||
sample: 'string',
|
||||
example: fn,
|
||||
unknown: undefined,
|
||||
};
|
||||
|
||||
expectToEqual(get(a, 'example'), fn);
|
||||
expectToEqual(get(a, 'sample'), 'string');
|
||||
expectToEqual(get(a, 'unknown'), undefined);
|
||||
expectToEqual(get(a, 'invalid'), undefined);
|
||||
});
|
||||
|
||||
test('should get deep properties', () => {
|
||||
const a = {
|
||||
b: { example: { type: 'vegetable' } },
|
||||
c: { example: { type: 'mineral' } },
|
||||
};
|
||||
|
||||
expectToEqual(get(a, 'b.example.type'), 'vegetable');
|
||||
expectToEqual(get(a, 'c.example.type'), 'mineral');
|
||||
expectToEqual(get(a, 'c.gorky.type'), undefined);
|
||||
});
|
||||
|
||||
// test('should get properties of Error', () => {
|
||||
// const e = new Error(403);
|
||||
// console.log(e.message);
|
||||
// expect(get(e, 'code')).toBe(403);
|
||||
// });
|
||||
|
||||
test('should get properties on non-objects', () => {
|
||||
const fn = function () {};
|
||||
|
||||
// the commented out lines are from from the "deep-property" lib,
|
||||
// but it's invalid javascript. This is a good example of why it's always
|
||||
// better to use "use strict" (and lint your code).
|
||||
|
||||
// const str = 'An example string';
|
||||
// const num = 42;
|
||||
|
||||
fn.path = { to: { property: 'string' } };
|
||||
// str.path = { to: { property: 'string' } };
|
||||
// num.path = { to: { property: 'string' } };
|
||||
|
||||
expectToEqual(get(fn, 'path.to.property'), 'string');
|
||||
// expectToEqual(get(str, 'path.to.property'), undefined);
|
||||
// expectToEqual(get(num, 'path.to.property'), undefined);
|
||||
});
|
||||
});
|
28
yarn.lock
28
yarn.lock
@ -2710,6 +2710,30 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@lowdefy/get@workspace:packages/get":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@lowdefy/get@workspace:packages/get"
|
||||
dependencies:
|
||||
"@babel/cli": 7.8.4
|
||||
"@babel/compat-data": 7.9.6
|
||||
"@babel/core": 7.9.6
|
||||
"@babel/preset-env": 7.9.6
|
||||
"@lowdefy/type": 1.0.1
|
||||
babel-jest: 24.9.0
|
||||
eslint: 6.8.0
|
||||
eslint-config-airbnb: 18.2.0
|
||||
eslint-config-prettier: 6.12.0
|
||||
eslint-plugin-import: 2.22.1
|
||||
eslint-plugin-jsx-a11y: 6.3.1
|
||||
eslint-plugin-prettier: 3.1.4
|
||||
eslint-plugin-react: 7.21.2
|
||||
eslint-plugin-react-hooks: 4.1.2
|
||||
jest: 24.9.0
|
||||
jest-diff: 24.9.0
|
||||
prettier: 2.1.2
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@lowdefy/graphql@0.0.0-experimental.0, @lowdefy/graphql@workspace:packages/graphql":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@lowdefy/graphql@workspace:packages/graphql"
|
||||
@ -2775,7 +2799,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@lowdefy/type@workspace:packages/type":
|
||||
"@lowdefy/type@1.0.1, @lowdefy/type@workspace:packages/type":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@lowdefy/type@workspace:packages/type"
|
||||
dependencies:
|
||||
@ -10106,7 +10130,7 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jest-diff@npm:^24.9.0":
|
||||
"jest-diff@npm:24.9.0, jest-diff@npm:^24.9.0":
|
||||
version: 24.9.0
|
||||
resolution: "jest-diff@npm:24.9.0"
|
||||
dependencies:
|
||||
|
Loading…
x
Reference in New Issue
Block a user