@e22m4u/js-repository 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.c8rc +9 -0
- package/.commitlintrc +5 -0
- package/.editorconfig +13 -0
- package/.eslintignore +1 -0
- package/.eslintrc.cjs +27 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +9 -0
- package/.mocharc.cjs +7 -0
- package/.prettierrc +7 -0
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/mocha.setup.js +10 -0
- package/package.json +57 -0
- package/src/adapter/adapter-loader.d.ts +16 -0
- package/src/adapter/adapter-loader.js +63 -0
- package/src/adapter/adapter-loader.spec.js +31 -0
- package/src/adapter/adapter-registry.d.ts +14 -0
- package/src/adapter/adapter-registry.js +36 -0
- package/src/adapter/adapter-registry.spec.js +36 -0
- package/src/adapter/adapter.d.ts +118 -0
- package/src/adapter/adapter.js +181 -0
- package/src/adapter/adapter.spec.js +144 -0
- package/src/adapter/builtin/memory-adapter.d.ts +118 -0
- package/src/adapter/builtin/memory-adapter.js +342 -0
- package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
- package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
- package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
- package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
- package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
- package/src/adapter/decorator/data-validation-decorator.js +41 -0
- package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
- package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
- package/src/adapter/decorator/default-values-decorator.js +57 -0
- package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
- package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
- package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
- package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
- package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
- package/src/adapter/decorator/inclusion-decorator.js +78 -0
- package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
- package/src/adapter/decorator/index.d.ts +5 -0
- package/src/adapter/decorator/index.js +5 -0
- package/src/adapter/index.d.ts +3 -0
- package/src/adapter/index.js +3 -0
- package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
- package/src/definition/datasource/datasource-definition-validator.js +33 -0
- package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
- package/src/definition/datasource/datasource-definition.d.ts +7 -0
- package/src/definition/datasource/index.d.ts +2 -0
- package/src/definition/datasource/index.js +1 -0
- package/src/definition/definition-registry.d.ts +50 -0
- package/src/definition/definition-registry.js +98 -0
- package/src/definition/definition-registry.spec.js +78 -0
- package/src/definition/index.d.ts +3 -0
- package/src/definition/index.js +3 -0
- package/src/definition/model/index.d.ts +7 -0
- package/src/definition/model/index.js +6 -0
- package/src/definition/model/model-data-sanitizer.d.ts +15 -0
- package/src/definition/model/model-data-sanitizer.js +33 -0
- package/src/definition/model/model-data-validator.d.ts +32 -0
- package/src/definition/model/model-data-validator.js +144 -0
- package/src/definition/model/model-data-validator.spec.js +1889 -0
- package/src/definition/model/model-definition-utils.d.ts +161 -0
- package/src/definition/model/model-definition-utils.js +371 -0
- package/src/definition/model/model-definition-utils.spec.js +1474 -0
- package/src/definition/model/model-definition-validator.d.ts +14 -0
- package/src/definition/model/model-definition-validator.js +83 -0
- package/src/definition/model/model-definition-validator.spec.js +143 -0
- package/src/definition/model/model-definition.d.ts +28 -0
- package/src/definition/model/properties/data-type.d.ts +11 -0
- package/src/definition/model/properties/data-type.js +11 -0
- package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/default-values-definition-validator.js +53 -0
- package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
- package/src/definition/model/properties/index.d.ts +5 -0
- package/src/definition/model/properties/index.js +4 -0
- package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
- package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
- package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/properties-definition-validator.js +194 -0
- package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
- package/src/definition/model/properties/property-definition.d.ts +20 -0
- package/src/definition/model/relations/index.d.ts +3 -0
- package/src/definition/model/relations/index.js +2 -0
- package/src/definition/model/relations/relation-definition.d.ts +254 -0
- package/src/definition/model/relations/relation-type.d.ts +9 -0
- package/src/definition/model/relations/relation-type.js +9 -0
- package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
- package/src/definition/model/relations/relations-definition-validator.js +449 -0
- package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
- package/src/errors/index.d.ts +3 -0
- package/src/errors/index.js +3 -0
- package/src/errors/invalid-argument-error.d.ts +6 -0
- package/src/errors/invalid-argument-error.js +6 -0
- package/src/errors/invalid-argument-error.spec.js +33 -0
- package/src/errors/invalid-operator-value-error.d.ts +13 -0
- package/src/errors/invalid-operator-value-error.js +24 -0
- package/src/errors/invalid-operator-value-error.spec.js +11 -0
- package/src/errors/not-implemented-error.d.ts +6 -0
- package/src/errors/not-implemented-error.js +6 -0
- package/src/errors/not-implemented-error.spec.js +33 -0
- package/src/filter/fields-clause-tool.d.ts +38 -0
- package/src/filter/fields-clause-tool.js +88 -0
- package/src/filter/fields-clause-tool.spec.js +133 -0
- package/src/filter/filter.d.ts +335 -0
- package/src/filter/include-clause-tool.d.ts +53 -0
- package/src/filter/include-clause-tool.js +364 -0
- package/src/filter/include-clause-tool.spec.js +653 -0
- package/src/filter/index.d.ts +7 -0
- package/src/filter/index.js +6 -0
- package/src/filter/operator-clause-tool.d.ts +223 -0
- package/src/filter/operator-clause-tool.js +515 -0
- package/src/filter/operator-clause-tool.spec.js +1064 -0
- package/src/filter/order-clause-tool.d.ts +32 -0
- package/src/filter/order-clause-tool.js +97 -0
- package/src/filter/order-clause-tool.spec.js +438 -0
- package/src/filter/slice-clause-tool.d.ts +30 -0
- package/src/filter/slice-clause-tool.js +65 -0
- package/src/filter/slice-clause-tool.spec.js +117 -0
- package/src/filter/where-clause-tool.d.ts +23 -0
- package/src/filter/where-clause-tool.js +165 -0
- package/src/filter/where-clause-tool.spec.js +280 -0
- package/src/index.d.ts +9 -0
- package/src/index.js +8 -0
- package/src/relations/belongs-to-resolver.d.ts +46 -0
- package/src/relations/belongs-to-resolver.js +242 -0
- package/src/relations/belongs-to-resolver.spec.js +1047 -0
- package/src/relations/has-many-resolver.d.ts +67 -0
- package/src/relations/has-many-resolver.js +317 -0
- package/src/relations/has-many-resolver.spec.js +2911 -0
- package/src/relations/has-one-resolver.d.ts +67 -0
- package/src/relations/has-one-resolver.js +311 -0
- package/src/relations/has-one-resolver.spec.js +2274 -0
- package/src/relations/index.d.ts +4 -0
- package/src/relations/index.js +4 -0
- package/src/relations/references-many-resolver.d.ts +27 -0
- package/src/relations/references-many-resolver.js +113 -0
- package/src/relations/references-many-resolver.spec.js +631 -0
- package/src/repository/index.d.ts +2 -0
- package/src/repository/index.js +2 -0
- package/src/repository/repository-registry.d.ts +29 -0
- package/src/repository/repository-registry.js +57 -0
- package/src/repository/repository-registry.spec.js +38 -0
- package/src/repository/repository.d.ts +164 -0
- package/src/repository/repository.js +207 -0
- package/src/repository/repository.spec.js +202 -0
- package/src/schema.d.ts +37 -0
- package/src/schema.js +41 -0
- package/src/types.d.ts +30 -0
- package/src/utils/capitalize.d.ts +6 -0
- package/src/utils/capitalize.js +10 -0
- package/src/utils/capitalize.spec.js +14 -0
- package/src/utils/clone-deep.d.ts +6 -0
- package/src/utils/clone-deep.js +61 -0
- package/src/utils/clone-deep.spec.js +28 -0
- package/src/utils/exclude-object-keys.d.ts +10 -0
- package/src/utils/exclude-object-keys.js +20 -0
- package/src/utils/exclude-object-keys.spec.js +49 -0
- package/src/utils/get-ctor-name.d.ts +6 -0
- package/src/utils/get-ctor-name.js +11 -0
- package/src/utils/get-ctor-name.spec.js +17 -0
- package/src/utils/get-value-by-path.d.ts +12 -0
- package/src/utils/get-value-by-path.js +23 -0
- package/src/utils/get-value-by-path.spec.js +36 -0
- package/src/utils/index.d.ts +10 -0
- package/src/utils/index.js +10 -0
- package/src/utils/is-ctor.d.ts +7 -0
- package/src/utils/is-ctor.js +10 -0
- package/src/utils/is-ctor.spec.js +26 -0
- package/src/utils/is-pure-object.d.ts +6 -0
- package/src/utils/is-pure-object.js +15 -0
- package/src/utils/is-pure-object.spec.js +25 -0
- package/src/utils/select-object-keys.d.ts +10 -0
- package/src/utils/select-object-keys.js +37 -0
- package/src/utils/select-object-keys.spec.js +40 -0
- package/src/utils/singularize.d.ts +6 -0
- package/src/utils/singularize.js +22 -0
- package/src/utils/singularize.spec.js +23 -0
- package/src/utils/string-to-regexp.d.ts +10 -0
- package/src/utils/string-to-regexp.js +22 -0
- package/src/utils/string-to-regexp.spec.js +35 -0
- package/tsconfig.json +9 -0
package/src/schema.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {Service} from '@e22m4u/js-service';
|
|
2
|
+
import {Repository} from './repository/index.js';
|
|
3
|
+
import {DefinitionRegistry} from './definition/index.js';
|
|
4
|
+
import {RepositoryRegistry} from './repository/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Schema.
|
|
8
|
+
*/
|
|
9
|
+
export class Schema extends Service {
|
|
10
|
+
/**
|
|
11
|
+
* Define datasource.
|
|
12
|
+
*
|
|
13
|
+
* @param {object} datasourceDef
|
|
14
|
+
* @returns {this}
|
|
15
|
+
*/
|
|
16
|
+
defineDatasource(datasourceDef) {
|
|
17
|
+
this.getService(DefinitionRegistry).addDatasource(datasourceDef);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Define model.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} modelDef
|
|
25
|
+
* @returns {this}
|
|
26
|
+
*/
|
|
27
|
+
defineModel(modelDef) {
|
|
28
|
+
this.getService(DefinitionRegistry).addModel(modelDef);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get repository.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} modelName
|
|
36
|
+
* @returns {Repository}
|
|
37
|
+
*/
|
|
38
|
+
getRepository(modelName) {
|
|
39
|
+
return this.getService(RepositoryRegistry).getRepository(modelName);
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Free-form object with open properties.
|
|
3
|
+
*/
|
|
4
|
+
export declare type AnyObject = {
|
|
5
|
+
[property: string]: unknown;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Makes specific field as optional.
|
|
10
|
+
*/
|
|
11
|
+
export declare type PartialBy<T, K extends keyof T> = Omit<T, K> &
|
|
12
|
+
Partial<Pick<T, K>>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Model data.
|
|
16
|
+
*/
|
|
17
|
+
export declare type ModelData = {
|
|
18
|
+
[property: string]: unknown;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Model id.
|
|
23
|
+
*/
|
|
24
|
+
export declare type ModelId = unknown;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Flatten.
|
|
28
|
+
*/
|
|
29
|
+
type Identity<T> = T;
|
|
30
|
+
export declare type Flatten<T> = Identity<{[k in keyof T]: T[k]}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {capitalize} from './capitalize.js';
|
|
3
|
+
|
|
4
|
+
describe('capitalize', function () {
|
|
5
|
+
it('makes the first letter to upper case', function () {
|
|
6
|
+
expect(capitalize('foo')).to.be.eq('Foo');
|
|
7
|
+
expect(capitalize('foo bar')).to.be.eq('Foo bar');
|
|
8
|
+
expect(capitalize(10)).to.be.eq(10);
|
|
9
|
+
expect(capitalize(true)).to.be.eq(true);
|
|
10
|
+
expect(capitalize(false)).to.be.eq(false);
|
|
11
|
+
expect(capitalize(undefined)).to.be.eq(undefined);
|
|
12
|
+
expect(capitalize(null)).to.be.eq(null);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clone deep.
|
|
3
|
+
*
|
|
4
|
+
* @author https://stackoverflow.com/a/4460624
|
|
5
|
+
* @param {*} value
|
|
6
|
+
* @returns {*}
|
|
7
|
+
*/
|
|
8
|
+
export function cloneDeep(value) {
|
|
9
|
+
if (!value) return value; // null, undefined values check
|
|
10
|
+
|
|
11
|
+
const types = [Number, String, Boolean];
|
|
12
|
+
let result;
|
|
13
|
+
|
|
14
|
+
// normalizing primitives if someone did new String('aaa'),
|
|
15
|
+
// or new Number('444');
|
|
16
|
+
types.forEach(type => {
|
|
17
|
+
if (value instanceof type) result = type(value);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (result === undefined) {
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
result = [];
|
|
23
|
+
value.forEach((child, index) => {
|
|
24
|
+
result[index] = cloneDeep(child);
|
|
25
|
+
});
|
|
26
|
+
} else if (typeof value === 'object') {
|
|
27
|
+
// testing that this is DOM
|
|
28
|
+
if (
|
|
29
|
+
'nodeType' in value &&
|
|
30
|
+
value.nodeType &&
|
|
31
|
+
'cloneNode' in value &&
|
|
32
|
+
typeof value.cloneNode === 'function'
|
|
33
|
+
) {
|
|
34
|
+
result = value.cloneNode(true);
|
|
35
|
+
// check that this is a literal
|
|
36
|
+
} else if (!('prototype' in value) || !value.prototype) {
|
|
37
|
+
if (value instanceof Date) {
|
|
38
|
+
result = new Date(value);
|
|
39
|
+
} else if (value.constructor && value.constructor.name === 'Object') {
|
|
40
|
+
// it is an object literal
|
|
41
|
+
result = {};
|
|
42
|
+
for (const key in value) {
|
|
43
|
+
result[key] = cloneDeep(value[key]);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// just keep the reference,
|
|
47
|
+
// or create new object
|
|
48
|
+
result = value;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
// just keep the reference,
|
|
52
|
+
// or create new object
|
|
53
|
+
result = value;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
result = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {cloneDeep} from './clone-deep.js';
|
|
3
|
+
|
|
4
|
+
describe('cloneDeep', function () {
|
|
5
|
+
it('returns a deep copy of a given object', function () {
|
|
6
|
+
const value = {
|
|
7
|
+
stringProp: 'string',
|
|
8
|
+
numberProp: 10,
|
|
9
|
+
booleanProp: true,
|
|
10
|
+
arrayProp: [1, 2, 3],
|
|
11
|
+
objectProp: {
|
|
12
|
+
foo: 'string',
|
|
13
|
+
bar: 'string',
|
|
14
|
+
},
|
|
15
|
+
dateProp: new Date(),
|
|
16
|
+
nullProp: null,
|
|
17
|
+
};
|
|
18
|
+
const result = cloneDeep(value);
|
|
19
|
+
expect(result).to.be.eql(value);
|
|
20
|
+
expect(result).to.be.not.eq(value);
|
|
21
|
+
expect(result.arrayProp).to.be.not.eq(value.arrayProp);
|
|
22
|
+
expect(result.arrayProp).to.be.eql(value.arrayProp);
|
|
23
|
+
expect(result.objectProp).to.be.not.eq(value.objectProp);
|
|
24
|
+
expect(result.objectProp).to.be.eql(value.objectProp);
|
|
25
|
+
expect(result.dateProp).to.be.not.eq(value.dateProp);
|
|
26
|
+
expect(result.dateProp.getTime()).to.be.eq(value.dateProp.getTime());
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {InvalidArgumentError} from '../errors/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Exclude object keys.
|
|
5
|
+
*
|
|
6
|
+
* @param {object} obj
|
|
7
|
+
* @param {string|string[]} keys
|
|
8
|
+
* @returns {object}
|
|
9
|
+
*/
|
|
10
|
+
export function excludeObjectKeys(obj, keys) {
|
|
11
|
+
if (typeof obj !== 'object' || !obj || Array.isArray(obj))
|
|
12
|
+
throw new InvalidArgumentError(
|
|
13
|
+
'Cannot exclude keys from a non-Object value, %v given.',
|
|
14
|
+
obj,
|
|
15
|
+
);
|
|
16
|
+
const result = {...obj};
|
|
17
|
+
keys = Array.isArray(keys) ? keys : [keys];
|
|
18
|
+
keys.forEach(key => delete result[key]);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {format} from '@e22m4u/js-format';
|
|
3
|
+
import {excludeObjectKeys} from './exclude-object-keys.js';
|
|
4
|
+
|
|
5
|
+
describe('excludeObjectKeys', function () {
|
|
6
|
+
it('returns a given object without a specified key', function () {
|
|
7
|
+
const input = {
|
|
8
|
+
foo: 'string',
|
|
9
|
+
bar: 10,
|
|
10
|
+
baz: true,
|
|
11
|
+
qux: [1, 2, 3],
|
|
12
|
+
};
|
|
13
|
+
const result = excludeObjectKeys(input, 'bar');
|
|
14
|
+
expect(result).to.be.not.eq(input);
|
|
15
|
+
expect(result).to.be.eql({
|
|
16
|
+
foo: 'string',
|
|
17
|
+
baz: true,
|
|
18
|
+
qux: [1, 2, 3],
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns a given object without a specified keys', function () {
|
|
23
|
+
const input = {
|
|
24
|
+
foo: 'string',
|
|
25
|
+
bar: 10,
|
|
26
|
+
baz: true,
|
|
27
|
+
qux: [1, 2, 3],
|
|
28
|
+
};
|
|
29
|
+
const result = excludeObjectKeys(input, ['bar', 'qux']);
|
|
30
|
+
expect(result).to.be.not.eq(input);
|
|
31
|
+
expect(result).to.be.eql({
|
|
32
|
+
foo: 'string',
|
|
33
|
+
baz: true,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('throws an error for a non-object values', function () {
|
|
38
|
+
const throwable = v => () => excludeObjectKeys(v, 'key');
|
|
39
|
+
const error = v =>
|
|
40
|
+
format('Cannot exclude keys from a non-Object value, %s given.', v);
|
|
41
|
+
expect(throwable('str')).to.throw(error('"str"'));
|
|
42
|
+
expect(throwable(10)).to.throw(error('10'));
|
|
43
|
+
expect(throwable(true)).to.throw(error('true'));
|
|
44
|
+
expect(throwable(false)).to.throw(error('false'));
|
|
45
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
46
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
47
|
+
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get ctor name.
|
|
3
|
+
*
|
|
4
|
+
* @param {*} value
|
|
5
|
+
* @returns {string|undefined}
|
|
6
|
+
*/
|
|
7
|
+
export function getCtorName(value) {
|
|
8
|
+
if (value === null) return 'Null';
|
|
9
|
+
if (value === undefined) return 'Undefined';
|
|
10
|
+
return (value.constructor && value.constructor.name) || undefined;
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {getCtorName} from './get-ctor-name.js';
|
|
3
|
+
|
|
4
|
+
describe('getCtorName', function () {
|
|
5
|
+
it('returns a constructor name of a given value', function () {
|
|
6
|
+
expect(getCtorName({})).to.be.eq('Object');
|
|
7
|
+
expect(getCtorName(new Date())).to.be.eq('Date');
|
|
8
|
+
expect(getCtorName([])).to.be.eq('Array');
|
|
9
|
+
expect(getCtorName(() => undefined)).to.be.eq('Function');
|
|
10
|
+
expect(getCtorName('string')).to.be.eq('String');
|
|
11
|
+
expect(getCtorName(10)).to.be.eq('Number');
|
|
12
|
+
expect(getCtorName(true)).to.be.eq('Boolean');
|
|
13
|
+
expect(getCtorName(false)).to.be.eq('Boolean');
|
|
14
|
+
expect(getCtorName(null)).to.be.eq('Null');
|
|
15
|
+
expect(getCtorName(undefined)).to.be.eq('Undefined');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get value by path.
|
|
3
|
+
*
|
|
4
|
+
* @param {object} obj
|
|
5
|
+
* @param {string} path
|
|
6
|
+
* @param {*} orElse
|
|
7
|
+
* @returns {*}
|
|
8
|
+
*/
|
|
9
|
+
export function getValueByPath(obj, path, orElse = undefined) {
|
|
10
|
+
if (!obj || typeof obj !== 'object') return orElse;
|
|
11
|
+
if (!path || typeof path !== 'string') return orElse;
|
|
12
|
+
const keys = path.split('.');
|
|
13
|
+
let value = obj;
|
|
14
|
+
for (const key of keys) {
|
|
15
|
+
if (typeof value === 'object' && value !== null && key in value) {
|
|
16
|
+
value = value[key];
|
|
17
|
+
} else {
|
|
18
|
+
value = orElse;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {getValueByPath} from './get-value-by-path.js';
|
|
3
|
+
|
|
4
|
+
const VAL = 'value';
|
|
5
|
+
|
|
6
|
+
describe('getValueByPath', function () {
|
|
7
|
+
it('returns undefined if no value', function () {
|
|
8
|
+
expect(getValueByPath({}, 'foo')).to.be.undefined;
|
|
9
|
+
expect(getValueByPath({}, 'foo.bar')).to.be.undefined;
|
|
10
|
+
expect(getValueByPath({foo: {}}, 'foo.bar.baz')).to.be.undefined;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('returns a value by given path', function () {
|
|
14
|
+
expect(getValueByPath({foo: VAL}, 'foo')).to.be.eq(VAL);
|
|
15
|
+
expect(getValueByPath({foo: {bar: VAL}}, 'foo.bar')).to.be.eq(VAL);
|
|
16
|
+
expect(getValueByPath({foo: {bar: {baz: VAL}}}, 'foo.bar.baz')).to.be.eq(
|
|
17
|
+
VAL,
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('returns a given fallback if no value', function () {
|
|
22
|
+
expect(getValueByPath({}, 'foo', VAL)).to.be.eq(VAL);
|
|
23
|
+
expect(getValueByPath({}, 'foo.bar', VAL)).to.be.eq(VAL);
|
|
24
|
+
expect(getValueByPath({foo: {}}, 'foo.bar.baz', VAL)).to.be.eq(VAL);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns a given fallback for null or undefined object', function () {
|
|
28
|
+
expect(getValueByPath(null, 'foo', VAL)).to.be.eq(VAL);
|
|
29
|
+
expect(getValueByPath(undefined, 'foo', VAL)).to.be.eq(VAL);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('returns a given fallback for null or undefined key', function () {
|
|
33
|
+
expect(getValueByPath({}, null, VAL)).to.be.eq(VAL);
|
|
34
|
+
expect(getValueByPath({}, undefined, VAL)).to.be.eq(VAL);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './is-ctor.js';
|
|
2
|
+
export * from './capitalize.js';
|
|
3
|
+
export * from './clone-deep.js';
|
|
4
|
+
export * from './singularize.js';
|
|
5
|
+
export * from './get-ctor-name.js';
|
|
6
|
+
export * from './is-pure-object.js';
|
|
7
|
+
export * from './string-to-regexp.js';
|
|
8
|
+
export * from './get-value-by-path.js';
|
|
9
|
+
export * from './select-object-keys.js';
|
|
10
|
+
export * from './exclude-object-keys.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './is-ctor.js';
|
|
2
|
+
export * from './capitalize.js';
|
|
3
|
+
export * from './clone-deep.js';
|
|
4
|
+
export * from './singularize.js';
|
|
5
|
+
export * from './get-ctor-name.js';
|
|
6
|
+
export * from './is-pure-object.js';
|
|
7
|
+
export * from './string-to-regexp.js';
|
|
8
|
+
export * from './get-value-by-path.js';
|
|
9
|
+
export * from './select-object-keys.js';
|
|
10
|
+
export * from './exclude-object-keys.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {isCtor} from './is-ctor.js';
|
|
3
|
+
|
|
4
|
+
describe('isConstructor', function () {
|
|
5
|
+
it('returns true if a given value is a constructor', function () {
|
|
6
|
+
expect(isCtor(Date)).to.be.true;
|
|
7
|
+
expect(isCtor(Number)).to.be.true;
|
|
8
|
+
expect(isCtor(String)).to.be.true;
|
|
9
|
+
class MyClass {}
|
|
10
|
+
expect(isCtor(MyClass)).to.be.true;
|
|
11
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
12
|
+
function FunctionCtor() {}
|
|
13
|
+
expect(isCtor(FunctionCtor)).to.be.true;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('returns false if a given value is not a constructor', function () {
|
|
17
|
+
expect(isCtor(() => undefined)).to.be.false;
|
|
18
|
+
expect(isCtor('string')).to.be.false;
|
|
19
|
+
expect(isCtor(10)).to.be.false;
|
|
20
|
+
expect(isCtor(true)).to.be.false;
|
|
21
|
+
expect(isCtor({})).to.be.false;
|
|
22
|
+
expect(isCtor([])).to.be.false;
|
|
23
|
+
expect(isCtor(undefined)).to.be.false;
|
|
24
|
+
expect(isCtor(null)).to.be.false;
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is pure object.
|
|
3
|
+
*
|
|
4
|
+
* @param {*} value
|
|
5
|
+
* @returns {boolean}
|
|
6
|
+
*/
|
|
7
|
+
export function isPureObject(value) {
|
|
8
|
+
return Boolean(
|
|
9
|
+
typeof value === 'object' &&
|
|
10
|
+
value &&
|
|
11
|
+
!Array.isArray(value) &&
|
|
12
|
+
(!value.constructor ||
|
|
13
|
+
(value.constructor && value.constructor.name === 'Object')),
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {isPureObject} from './is-pure-object.js';
|
|
3
|
+
|
|
4
|
+
describe('isPureObject', function () {
|
|
5
|
+
it('returns ture if a pure object given', function () {
|
|
6
|
+
expect(isPureObject({})).to.be.true;
|
|
7
|
+
expect(isPureObject({key: 'val'})).to.be.true;
|
|
8
|
+
expect(isPureObject(Object.create(null))).to.be.true;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('returns false if a non-pure object given', function () {
|
|
12
|
+
expect(isPureObject(new Date())).to.be.false;
|
|
13
|
+
expect(isPureObject([])).to.be.false;
|
|
14
|
+
expect(isPureObject(() => undefined)).to.be.false;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('returns false if a non-object given', function () {
|
|
18
|
+
expect(isPureObject('string')).to.be.false;
|
|
19
|
+
expect(isPureObject(10)).to.be.false;
|
|
20
|
+
expect(isPureObject(true)).to.be.false;
|
|
21
|
+
expect(isPureObject(false)).to.be.false;
|
|
22
|
+
expect(isPureObject(null)).to.be.false;
|
|
23
|
+
expect(isPureObject(undefined)).to.be.false;
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {InvalidArgumentError} from '../errors/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Select object keys.
|
|
5
|
+
*
|
|
6
|
+
* @param {object} obj
|
|
7
|
+
* @param {string[]} keys
|
|
8
|
+
* @returns {object}
|
|
9
|
+
*/
|
|
10
|
+
export function selectObjectKeys(obj, keys) {
|
|
11
|
+
if (!obj || typeof obj !== 'object' || Array.isArray(obj))
|
|
12
|
+
throw new InvalidArgumentError(
|
|
13
|
+
'A first argument of selectObjectKeys ' +
|
|
14
|
+
'should be an Object, but %v given.',
|
|
15
|
+
obj,
|
|
16
|
+
);
|
|
17
|
+
if (!Array.isArray(keys))
|
|
18
|
+
throw new InvalidArgumentError(
|
|
19
|
+
'A second argument of selectObjectKeys ' +
|
|
20
|
+
'should be an Array of String, but %v given.',
|
|
21
|
+
keys,
|
|
22
|
+
);
|
|
23
|
+
keys.forEach(key => {
|
|
24
|
+
if (typeof key !== 'string')
|
|
25
|
+
throw new InvalidArgumentError(
|
|
26
|
+
'A second argument of selectObjectKeys ' +
|
|
27
|
+
'should be an Array of String, but %v given.',
|
|
28
|
+
key,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
const result = {};
|
|
32
|
+
const allKeys = Object.keys(obj);
|
|
33
|
+
allKeys.forEach(key => {
|
|
34
|
+
if (keys.includes(key)) result[key] = obj[key];
|
|
35
|
+
});
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {selectObjectKeys} from './select-object-keys.js';
|
|
3
|
+
|
|
4
|
+
describe('selectObjectKeys', function () {
|
|
5
|
+
it('returns a new object with selected fields', function () {
|
|
6
|
+
const input = {foo: 'foo', bar: 'bar', baz: 'baz'};
|
|
7
|
+
const result = selectObjectKeys(input, ['bar', 'baz']);
|
|
8
|
+
expect(result).to.be.eql({bar: 'bar', baz: 'baz'});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('does not throw an error if a selected property is not found', function () {
|
|
12
|
+
const input = {foo: 'foo', bar: 'bar', baz: 'baz'};
|
|
13
|
+
const result = selectObjectKeys(input, ['bar', 'qux']);
|
|
14
|
+
expect(result).to.be.eql({bar: 'bar'});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('throws an error if a given value is not an Object', function () {
|
|
18
|
+
const throwable = () => selectObjectKeys(10, ['key']);
|
|
19
|
+
expect(throwable).to.throw(
|
|
20
|
+
'A first argument of selectObjectKeys ' +
|
|
21
|
+
'should be an Object, but 10 given.',
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('throws an error if a given keys is not an Array', function () {
|
|
26
|
+
const throwable = () => selectObjectKeys({});
|
|
27
|
+
expect(throwable).to.throw(
|
|
28
|
+
'A second argument of selectObjectKeys ' +
|
|
29
|
+
'should be an Array of String, but undefined given.',
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('throws an error if a given keys is not an String', function () {
|
|
34
|
+
const throwable = () => selectObjectKeys({}, [10]);
|
|
35
|
+
expect(throwable).to.throw(
|
|
36
|
+
'A second argument of selectObjectKeys ' +
|
|
37
|
+
'should be an Array of String, but 10 given.',
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singularize.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} noun
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
export function singularize(noun) {
|
|
8
|
+
if (!noun || typeof noun !== 'string') return noun;
|
|
9
|
+
const endings = {
|
|
10
|
+
ves: 'fe',
|
|
11
|
+
ies: 'y',
|
|
12
|
+
i: 'us',
|
|
13
|
+
zes: 'ze',
|
|
14
|
+
ses: 's',
|
|
15
|
+
es: 'e',
|
|
16
|
+
s: '',
|
|
17
|
+
};
|
|
18
|
+
return noun.replace(
|
|
19
|
+
new RegExp(`(${Object.keys(endings).join('|')})$`),
|
|
20
|
+
r => endings[r],
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {singularize} from './singularize.js';
|
|
3
|
+
|
|
4
|
+
describe('singularize', function () {
|
|
5
|
+
it('returns a singular noun', function () {
|
|
6
|
+
expect(singularize('papers')).to.be.eq('paper');
|
|
7
|
+
expect(singularize('strategies')).to.be.eq('strategy');
|
|
8
|
+
expect(singularize('lives')).to.be.eq('life');
|
|
9
|
+
expect(singularize('games')).to.be.eq('game');
|
|
10
|
+
expect(singularize('cacti')).to.be.eq('cactus');
|
|
11
|
+
expect(singularize('dozes')).to.be.eq('doze');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('returns non-string values as is', function () {
|
|
15
|
+
expect(singularize(10)).to.be.eq(10);
|
|
16
|
+
expect(singularize([])).to.be.eql([]);
|
|
17
|
+
expect(singularize({})).to.be.eql({});
|
|
18
|
+
expect(singularize(true)).to.be.eq(true);
|
|
19
|
+
expect(singularize(false)).to.be.eq(false);
|
|
20
|
+
expect(singularize(undefined)).to.be.eq(undefined);
|
|
21
|
+
expect(singularize(null)).to.be.eq(null);
|
|
22
|
+
});
|
|
23
|
+
});
|