compare-anything 0.3.5 → 1.0.0
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/README.md +3 -0
- package/dist/index.cjs +113 -0
- package/dist/index.es.js +106 -0
- package/dist/types/compareObjectArraysBasedOn.d.ts +6 -0
- package/dist/types/compareObjectsBasedOn.d.ts +6 -0
- package/dist/types/index.d.ts +24 -0
- package/package.json +64 -32
- package/.eslintignore +0 -10
- package/.eslintrc.js +0 -17
- package/.github/FUNDING.yml +0 -12
- package/.prettierrc +0 -10
- package/.vscode/settings.json +0 -25
- package/build/rollup.js +0 -64
- package/src/compareObjectArraysBasedOn.ts +0 -26
- package/src/compareObjectsBasedOn.ts +0 -31
- package/src/index.ts +0 -94
- package/test/compareObjectsBasedOn.ts +0 -49
- package/test/index.ts +0 -95
- package/tsconfig.json +0 -15
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Compare anything 🛰
|
|
2
2
|
|
|
3
|
+
<a href="https://www.npmjs.com/package/compare-anything"><img src="https://img.shields.io/npm/v/compare-anything.svg" alt="Total Downloads"></a>
|
|
4
|
+
<a href="https://www.npmjs.com/package/compare-anything"><img src="https://img.shields.io/npm/dw/compare-anything.svg" alt="Latest Stable Version"></a>
|
|
5
|
+
|
|
3
6
|
```
|
|
4
7
|
npm i compare-anything
|
|
5
8
|
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var isWhat = require('is-what');
|
|
6
|
+
var filterAnything = require('filter-anything');
|
|
7
|
+
|
|
8
|
+
function compareObjectsBasedOn(propKeys, objects) {
|
|
9
|
+
const baseProps = propKeys;
|
|
10
|
+
const baseObject = objects[0];
|
|
11
|
+
const differentPropsSet = objects.reduce((carry, object, index) => {
|
|
12
|
+
if (index === 0)
|
|
13
|
+
return carry;
|
|
14
|
+
for (const prop of baseProps) {
|
|
15
|
+
if (object[prop] !== baseObject[prop])
|
|
16
|
+
carry.add(prop);
|
|
17
|
+
}
|
|
18
|
+
return carry;
|
|
19
|
+
}, new Set());
|
|
20
|
+
const differentProps = [...differentPropsSet];
|
|
21
|
+
const differentPropsPicked = objects.map((object) => filterAnything.pick(object, differentProps));
|
|
22
|
+
return {
|
|
23
|
+
differentProps,
|
|
24
|
+
differentPropsPicked,
|
|
25
|
+
equal: differentProps.length === 0,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function compareObjectArraysBasedOn(propKeys, objectArrays) {
|
|
30
|
+
const firstArray = objectArrays[0];
|
|
31
|
+
const comparison = {
|
|
32
|
+
perIndex: [],
|
|
33
|
+
equal: true,
|
|
34
|
+
};
|
|
35
|
+
firstArray.forEach((object, index) => {
|
|
36
|
+
const objectsToCompare = objectArrays.map((arr) => arr[index]);
|
|
37
|
+
const compared = compareObjectsBasedOn(propKeys, objectsToCompare);
|
|
38
|
+
if (!compared.equal)
|
|
39
|
+
comparison.equal = false;
|
|
40
|
+
comparison.perIndex.push(compared);
|
|
41
|
+
});
|
|
42
|
+
return comparison;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function compareObjectProps(...params) {
|
|
46
|
+
const propsSet = new Set();
|
|
47
|
+
const res = {
|
|
48
|
+
props: [],
|
|
49
|
+
presentInAll: {},
|
|
50
|
+
presentIn: {},
|
|
51
|
+
perProp: {},
|
|
52
|
+
};
|
|
53
|
+
params.forEach((object, index) => {
|
|
54
|
+
if (!isWhat.isAnyObject(object)) {
|
|
55
|
+
throw new Error("'compareObjectProps' can only compare objects");
|
|
56
|
+
}
|
|
57
|
+
Object.keys(object).forEach((prop) => {
|
|
58
|
+
propsSet.add(prop);
|
|
59
|
+
if (!(prop in res.presentIn))
|
|
60
|
+
res.presentIn[prop] = [];
|
|
61
|
+
res.presentIn[prop].push(index);
|
|
62
|
+
if (!(prop in res.perProp))
|
|
63
|
+
res.perProp[prop] = [];
|
|
64
|
+
res.perProp[prop].push(object);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
const paramCount = params.length;
|
|
68
|
+
res.presentInAll = Object.keys(res.presentIn).reduce((carry, prop) => {
|
|
69
|
+
const propCount = res.presentIn[prop].length;
|
|
70
|
+
carry[prop] = propCount === paramCount;
|
|
71
|
+
return carry;
|
|
72
|
+
}, {});
|
|
73
|
+
res.props = Array.from(propsSet);
|
|
74
|
+
return res;
|
|
75
|
+
}
|
|
76
|
+
function compareArrays(...params) {
|
|
77
|
+
const valuesSet = new Set();
|
|
78
|
+
const res = {
|
|
79
|
+
values: [],
|
|
80
|
+
infoPerValue: {},
|
|
81
|
+
presentInAll: [],
|
|
82
|
+
};
|
|
83
|
+
const getEmptyArray = () => params.map(() => undefined);
|
|
84
|
+
params.forEach((array, paramIndex) => {
|
|
85
|
+
if (!isWhat.isArray(array))
|
|
86
|
+
throw new Error("'compareArrays' can only compare arrays");
|
|
87
|
+
array.forEach((val, valIndex) => {
|
|
88
|
+
valuesSet.add(val);
|
|
89
|
+
const parsedVal = isWhat.isNumber(val) || isWhat.isString(val) ? String(val) : JSON.stringify(val);
|
|
90
|
+
if (!(parsedVal in res.infoPerValue)) {
|
|
91
|
+
res.infoPerValue[parsedVal] = {
|
|
92
|
+
indexPerArray: getEmptyArray(),
|
|
93
|
+
presentInAll: false,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
res.infoPerValue[parsedVal].indexPerArray[paramIndex] = valIndex;
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
Object.entries(res.infoPerValue).forEach(([parsedVal, info]) => {
|
|
100
|
+
const isInAllArrays = info.indexPerArray.every((index) => isWhat.isNumber(index) && index >= 0) &&
|
|
101
|
+
info.indexPerArray.length === params.length;
|
|
102
|
+
info.presentInAll = isInAllArrays;
|
|
103
|
+
if (isInAllArrays)
|
|
104
|
+
res.presentInAll.push(parsedVal);
|
|
105
|
+
});
|
|
106
|
+
res.values = Array.from(valuesSet);
|
|
107
|
+
return res;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
exports.compareArrays = compareArrays;
|
|
111
|
+
exports.compareObjectArraysBasedOn = compareObjectArraysBasedOn;
|
|
112
|
+
exports.compareObjectProps = compareObjectProps;
|
|
113
|
+
exports.compareObjectsBasedOn = compareObjectsBasedOn;
|
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isAnyObject, isArray, isNumber, isString } from 'is-what';
|
|
2
|
+
import { pick } from 'filter-anything';
|
|
3
|
+
|
|
4
|
+
function compareObjectsBasedOn(propKeys, objects) {
|
|
5
|
+
const baseProps = propKeys;
|
|
6
|
+
const baseObject = objects[0];
|
|
7
|
+
const differentPropsSet = objects.reduce((carry, object, index) => {
|
|
8
|
+
if (index === 0)
|
|
9
|
+
return carry;
|
|
10
|
+
for (const prop of baseProps) {
|
|
11
|
+
if (object[prop] !== baseObject[prop])
|
|
12
|
+
carry.add(prop);
|
|
13
|
+
}
|
|
14
|
+
return carry;
|
|
15
|
+
}, new Set());
|
|
16
|
+
const differentProps = [...differentPropsSet];
|
|
17
|
+
const differentPropsPicked = objects.map((object) => pick(object, differentProps));
|
|
18
|
+
return {
|
|
19
|
+
differentProps,
|
|
20
|
+
differentPropsPicked,
|
|
21
|
+
equal: differentProps.length === 0,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function compareObjectArraysBasedOn(propKeys, objectArrays) {
|
|
26
|
+
const firstArray = objectArrays[0];
|
|
27
|
+
const comparison = {
|
|
28
|
+
perIndex: [],
|
|
29
|
+
equal: true,
|
|
30
|
+
};
|
|
31
|
+
firstArray.forEach((object, index) => {
|
|
32
|
+
const objectsToCompare = objectArrays.map((arr) => arr[index]);
|
|
33
|
+
const compared = compareObjectsBasedOn(propKeys, objectsToCompare);
|
|
34
|
+
if (!compared.equal)
|
|
35
|
+
comparison.equal = false;
|
|
36
|
+
comparison.perIndex.push(compared);
|
|
37
|
+
});
|
|
38
|
+
return comparison;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function compareObjectProps(...params) {
|
|
42
|
+
const propsSet = new Set();
|
|
43
|
+
const res = {
|
|
44
|
+
props: [],
|
|
45
|
+
presentInAll: {},
|
|
46
|
+
presentIn: {},
|
|
47
|
+
perProp: {},
|
|
48
|
+
};
|
|
49
|
+
params.forEach((object, index) => {
|
|
50
|
+
if (!isAnyObject(object)) {
|
|
51
|
+
throw new Error("'compareObjectProps' can only compare objects");
|
|
52
|
+
}
|
|
53
|
+
Object.keys(object).forEach((prop) => {
|
|
54
|
+
propsSet.add(prop);
|
|
55
|
+
if (!(prop in res.presentIn))
|
|
56
|
+
res.presentIn[prop] = [];
|
|
57
|
+
res.presentIn[prop].push(index);
|
|
58
|
+
if (!(prop in res.perProp))
|
|
59
|
+
res.perProp[prop] = [];
|
|
60
|
+
res.perProp[prop].push(object);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
const paramCount = params.length;
|
|
64
|
+
res.presentInAll = Object.keys(res.presentIn).reduce((carry, prop) => {
|
|
65
|
+
const propCount = res.presentIn[prop].length;
|
|
66
|
+
carry[prop] = propCount === paramCount;
|
|
67
|
+
return carry;
|
|
68
|
+
}, {});
|
|
69
|
+
res.props = Array.from(propsSet);
|
|
70
|
+
return res;
|
|
71
|
+
}
|
|
72
|
+
function compareArrays(...params) {
|
|
73
|
+
const valuesSet = new Set();
|
|
74
|
+
const res = {
|
|
75
|
+
values: [],
|
|
76
|
+
infoPerValue: {},
|
|
77
|
+
presentInAll: [],
|
|
78
|
+
};
|
|
79
|
+
const getEmptyArray = () => params.map(() => undefined);
|
|
80
|
+
params.forEach((array, paramIndex) => {
|
|
81
|
+
if (!isArray(array))
|
|
82
|
+
throw new Error("'compareArrays' can only compare arrays");
|
|
83
|
+
array.forEach((val, valIndex) => {
|
|
84
|
+
valuesSet.add(val);
|
|
85
|
+
const parsedVal = isNumber(val) || isString(val) ? String(val) : JSON.stringify(val);
|
|
86
|
+
if (!(parsedVal in res.infoPerValue)) {
|
|
87
|
+
res.infoPerValue[parsedVal] = {
|
|
88
|
+
indexPerArray: getEmptyArray(),
|
|
89
|
+
presentInAll: false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
res.infoPerValue[parsedVal].indexPerArray[paramIndex] = valIndex;
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
Object.entries(res.infoPerValue).forEach(([parsedVal, info]) => {
|
|
96
|
+
const isInAllArrays = info.indexPerArray.every((index) => isNumber(index) && index >= 0) &&
|
|
97
|
+
info.indexPerArray.length === params.length;
|
|
98
|
+
info.presentInAll = isInAllArrays;
|
|
99
|
+
if (isInAllArrays)
|
|
100
|
+
res.presentInAll.push(parsedVal);
|
|
101
|
+
});
|
|
102
|
+
res.values = Array.from(valuesSet);
|
|
103
|
+
return res;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { compareArrays, compareObjectArraysBasedOn, compareObjectProps, compareObjectsBasedOn };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ComparisonObjects } from './compareObjectsBasedOn';
|
|
2
|
+
export declare type ComparisonObjectArrays<ObjectType> = {
|
|
3
|
+
perIndex: ComparisonObjects<ObjectType>[];
|
|
4
|
+
equal: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function compareObjectArraysBasedOn<ObjectType extends Record<string, any> | any = Record<string, any>>(propKeys: (keyof ObjectType)[], objectArrays: [[ObjectType, ...any[]], ...any[]]): ComparisonObjectArrays<ObjectType>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare type ComparisonObjects<ObjectType> = {
|
|
2
|
+
differentProps: (keyof ObjectType)[];
|
|
3
|
+
differentPropsPicked: Partial<ObjectType>[];
|
|
4
|
+
equal: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function compareObjectsBasedOn<ObjectType extends Record<string, any> | any = Record<string, any>>(propKeys: (keyof ObjectType)[], objects: [ObjectType, ...any[]]): ComparisonObjects<ObjectType>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { compareObjectsBasedOn } from './compareObjectsBasedOn';
|
|
2
|
+
export { compareObjectArraysBasedOn } from './compareObjectArraysBasedOn';
|
|
3
|
+
export declare function compareObjectProps(...params: Record<string, any>[]): {
|
|
4
|
+
props: string[];
|
|
5
|
+
presentInAll: {
|
|
6
|
+
[key in string]: boolean;
|
|
7
|
+
};
|
|
8
|
+
perProp: {
|
|
9
|
+
[key in string]: Record<string, any>;
|
|
10
|
+
};
|
|
11
|
+
presentIn: {
|
|
12
|
+
[key in string]: number[];
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare function compareArrays(...params: any[][]): {
|
|
16
|
+
values: any[];
|
|
17
|
+
infoPerValue: {
|
|
18
|
+
[key in string]: {
|
|
19
|
+
indexPerArray: (number | undefined)[];
|
|
20
|
+
presentInAll: boolean;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
presentInAll: string[];
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,40 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compare-anything",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "1.0.0",
|
|
5
6
|
"description": "Compares objects and arrays and tells you which props or values are duplicates, and which are only present once.",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"types": "types/index.d.ts",
|
|
7
|
+
"module": "./dist/index.es.js",
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"types": "./dist/types/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.es.js",
|
|
13
|
+
"require": "./dist/index.cjs",
|
|
14
|
+
"types": "./dist/types/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=12.13",
|
|
22
|
+
"npm": ">=7"
|
|
23
|
+
},
|
|
9
24
|
"repository": "https://github.com/mesqueeb/compare-anything",
|
|
10
25
|
"author": "Luca Ban - Mesqueeb",
|
|
26
|
+
"funding": "https://github.com/sponsors/mesqueeb",
|
|
11
27
|
"license": "MIT",
|
|
12
28
|
"scripts": {
|
|
13
|
-
"test": "
|
|
14
|
-
"lint": "eslint
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"release": "npm run build && np"
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"lint": "tsc --noEmit && eslint ./src --ext .ts",
|
|
31
|
+
"build": "rollup -c ./scripts/build.js",
|
|
32
|
+
"release": "npm run lint && del dist && npm run build && np"
|
|
18
33
|
},
|
|
19
34
|
"dependencies": {
|
|
20
35
|
"filter-anything": "^2.2.1",
|
|
21
|
-
"is-what": "^
|
|
36
|
+
"is-what": "^4.1.1"
|
|
22
37
|
},
|
|
23
38
|
"devDependencies": {
|
|
24
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
25
|
-
"@typescript-eslint/parser": "^
|
|
26
|
-
"
|
|
27
|
-
"eslint": "^7.
|
|
28
|
-
"eslint-config-prettier": "^8.
|
|
29
|
-
"eslint-plugin-tree-shaking": "^1.
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
|
40
|
+
"@typescript-eslint/parser": "^5.10.1",
|
|
41
|
+
"del-cli": "^4.0.1",
|
|
42
|
+
"eslint": "^8.7.0",
|
|
43
|
+
"eslint-config-prettier": "^8.3.0",
|
|
44
|
+
"eslint-plugin-tree-shaking": "^1.10.0",
|
|
30
45
|
"flatten-anything": "^2.0.4",
|
|
31
|
-
"np": "^7.
|
|
32
|
-
"prettier": "^2.
|
|
33
|
-
"rollup": "^2.
|
|
34
|
-
"rollup-plugin-typescript2": "^0.
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"typescript": "^4.2.3"
|
|
46
|
+
"np": "^7.6.0",
|
|
47
|
+
"prettier": "^2.5.1",
|
|
48
|
+
"rollup": "^2.66.0",
|
|
49
|
+
"rollup-plugin-typescript2": "^0.31.1",
|
|
50
|
+
"typescript": "^4.5.5",
|
|
51
|
+
"vitest": "^0.2.1"
|
|
38
52
|
},
|
|
39
53
|
"keywords": [
|
|
40
54
|
"typescript",
|
|
@@ -52,17 +66,35 @@
|
|
|
52
66
|
"url": "https://github.com/mesqueeb/compare-anything/issues"
|
|
53
67
|
},
|
|
54
68
|
"homepage": "https://github.com/mesqueeb/compare-anything#readme",
|
|
55
|
-
"ava": {
|
|
56
|
-
"extensions": [
|
|
57
|
-
"ts"
|
|
58
|
-
],
|
|
59
|
-
"require": [
|
|
60
|
-
"tsconfig-paths/register",
|
|
61
|
-
"ts-node/register"
|
|
62
|
-
]
|
|
63
|
-
},
|
|
64
69
|
"np": {
|
|
65
70
|
"yarn": false,
|
|
66
71
|
"branch": "production"
|
|
72
|
+
},
|
|
73
|
+
"eslintConfig": {
|
|
74
|
+
"ignorePatterns": [
|
|
75
|
+
"node_modules",
|
|
76
|
+
"dist",
|
|
77
|
+
"scripts",
|
|
78
|
+
"test"
|
|
79
|
+
],
|
|
80
|
+
"root": true,
|
|
81
|
+
"parser": "@typescript-eslint/parser",
|
|
82
|
+
"plugins": [
|
|
83
|
+
"@typescript-eslint",
|
|
84
|
+
"tree-shaking"
|
|
85
|
+
],
|
|
86
|
+
"extends": [
|
|
87
|
+
"eslint:recommended",
|
|
88
|
+
"plugin:@typescript-eslint/eslint-recommended",
|
|
89
|
+
"plugin:@typescript-eslint/recommended",
|
|
90
|
+
"prettier"
|
|
91
|
+
],
|
|
92
|
+
"rules": {
|
|
93
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
94
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
95
|
+
"@typescript-eslint/ban-ts-ignore": "off",
|
|
96
|
+
"tree-shaking/no-side-effects-in-initialization": "error",
|
|
97
|
+
"@typescript-eslint/ban-ts-comment": "off"
|
|
98
|
+
}
|
|
67
99
|
}
|
|
68
100
|
}
|
package/.eslintignore
DELETED
package/.eslintrc.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-plugin-tree-shaking
|
|
2
|
-
module.exports = {
|
|
3
|
-
root: true,
|
|
4
|
-
parser: '@typescript-eslint/parser',
|
|
5
|
-
plugins: ['@typescript-eslint', 'tree-shaking'],
|
|
6
|
-
extends: [
|
|
7
|
-
'eslint:recommended',
|
|
8
|
-
'plugin:@typescript-eslint/eslint-recommended',
|
|
9
|
-
'plugin:@typescript-eslint/recommended',
|
|
10
|
-
'prettier',
|
|
11
|
-
],
|
|
12
|
-
rules: {
|
|
13
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
14
|
-
'@typescript-eslint/ban-ts-ignore': 'off',
|
|
15
|
-
'tree-shaking/no-side-effects-in-initialization': 'error',
|
|
16
|
-
},
|
|
17
|
-
}
|
package/.github/FUNDING.yml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# These are supported funding model platforms
|
|
2
|
-
|
|
3
|
-
github: mesqueeb
|
|
4
|
-
patreon: # Replace with a single Patreon username
|
|
5
|
-
open_collective: # Replace with a single Open Collective username
|
|
6
|
-
ko_fi: # Replace with a single Ko-fi username
|
|
7
|
-
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
8
|
-
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
9
|
-
liberapay: # Replace with a single Liberapay username
|
|
10
|
-
issuehunt: # Replace with a single IssueHunt username
|
|
11
|
-
otechie: # Replace with a single Otechie username
|
|
12
|
-
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
package/.prettierrc
DELETED
package/.vscode/settings.json
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"editor.formatOnSave": true,
|
|
3
|
-
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
4
|
-
"[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
|
5
|
-
"[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
|
6
|
-
"[sass]": { "editor.defaultFormatter": "syler.sass-indented" },
|
|
7
|
-
// disable conflicting formatting
|
|
8
|
-
"javascript.validate.enable": true,
|
|
9
|
-
"typescript.format.enable": true,
|
|
10
|
-
"standard.enable": false,
|
|
11
|
-
// global important defaults
|
|
12
|
-
"editor.tabSize": 2, // make sure this is the same as .prettierrc
|
|
13
|
-
"editor.insertSpaces": true,
|
|
14
|
-
"files.trimFinalNewlines": true,
|
|
15
|
-
"files.insertFinalNewline": true,
|
|
16
|
-
"files.trimTrailingWhitespace": true,
|
|
17
|
-
// sass
|
|
18
|
-
"sass.format.debug": false,
|
|
19
|
-
"sass.format.deleteEmptyRows": true,
|
|
20
|
-
"sass.format.deleteWhitespace": true,
|
|
21
|
-
"sass.format.convert": true,
|
|
22
|
-
"sass.format.setPropertySpace": true,
|
|
23
|
-
// typescript
|
|
24
|
-
"typescript.tsdk": "node_modules/typescript/lib"
|
|
25
|
-
}
|
package/build/rollup.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
|
|
3
|
-
// npm install rollup-plugin-typescript2 typescript --save-dev
|
|
4
|
-
import typescript from 'rollup-plugin-typescript2'
|
|
5
|
-
// import { terser } from 'rollup-plugin-terser'
|
|
6
|
-
// import resolve from 'rollup-plugin-node-resolve'
|
|
7
|
-
|
|
8
|
-
// ------------------------------------------------------------------------------------------
|
|
9
|
-
// formats
|
|
10
|
-
// ------------------------------------------------------------------------------------------
|
|
11
|
-
// amd – Asynchronous Module Definition, used with module loaders like RequireJS
|
|
12
|
-
// cjs – CommonJS, suitable for Node and Browserify/Webpack
|
|
13
|
-
// esm – Keep the bundle as an ES module file
|
|
14
|
-
// iife – A self-executing function, suitable for inclusion as a <script> tag. (If you want to create a bundle for your application, you probably want to use this, because it leads to smaller file sizes.)
|
|
15
|
-
// umd – Universal Module Definition, works as amd, cjs and iife all in one
|
|
16
|
-
// system – Native format of the SystemJS loader
|
|
17
|
-
|
|
18
|
-
// ------------------------------------------------------------------------------------------
|
|
19
|
-
// setup
|
|
20
|
-
// ------------------------------------------------------------------------------------------
|
|
21
|
-
const pkg = require('../package.json')
|
|
22
|
-
const name = pkg.name
|
|
23
|
-
const className = name.replace(/(^\w|-\w)/g, c =>
|
|
24
|
-
c.replace('-', '').toUpperCase()
|
|
25
|
-
)
|
|
26
|
-
const external = Object.keys(pkg.dependencies || [])
|
|
27
|
-
const plugins = [
|
|
28
|
-
typescript({
|
|
29
|
-
useTsconfigDeclarationDir: true,
|
|
30
|
-
tsconfigOverride: { exclude: ['test/**/*'] }
|
|
31
|
-
})
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
// ------------------------------------------------------------------------------------------
|
|
35
|
-
// Builds
|
|
36
|
-
// ------------------------------------------------------------------------------------------
|
|
37
|
-
function defaults (config) {
|
|
38
|
-
// defaults
|
|
39
|
-
const defaults = {
|
|
40
|
-
plugins,
|
|
41
|
-
external
|
|
42
|
-
}
|
|
43
|
-
// defaults.output
|
|
44
|
-
config.output = config.output.map(output => {
|
|
45
|
-
return Object.assign(
|
|
46
|
-
{
|
|
47
|
-
sourcemap: false,
|
|
48
|
-
name: className
|
|
49
|
-
},
|
|
50
|
-
output
|
|
51
|
-
)
|
|
52
|
-
})
|
|
53
|
-
return Object.assign(defaults, config)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export default [
|
|
57
|
-
defaults({
|
|
58
|
-
input: 'src/index.ts',
|
|
59
|
-
output: [
|
|
60
|
-
{ file: 'dist/index.cjs.js', format: 'cjs' },
|
|
61
|
-
{ file: 'dist/index.esm.js', format: 'esm' }
|
|
62
|
-
]
|
|
63
|
-
})
|
|
64
|
-
]
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { ComparisonObjects, compareObjectsBasedOn } from './compareObjectsBasedOn'
|
|
2
|
-
|
|
3
|
-
export type ComparisonObjectArrays<ObjectType> = {
|
|
4
|
-
perIndex: ComparisonObjects<ObjectType>[]
|
|
5
|
-
equal: boolean
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function compareObjectArraysBasedOn<
|
|
9
|
-
ObjectType extends Record<string, any> | any = Record<string, any>
|
|
10
|
-
>(
|
|
11
|
-
propKeys: (keyof ObjectType)[],
|
|
12
|
-
objectArrays: [[ObjectType, ...any[]], ...any[]]
|
|
13
|
-
): ComparisonObjectArrays<ObjectType> {
|
|
14
|
-
const firstArray = objectArrays[0]
|
|
15
|
-
const comparison: ComparisonObjectArrays<ObjectType> = {
|
|
16
|
-
perIndex: [],
|
|
17
|
-
equal: true,
|
|
18
|
-
}
|
|
19
|
-
firstArray.forEach((object, index) => {
|
|
20
|
-
const objectsToCompare = objectArrays.map((arr) => arr[index])
|
|
21
|
-
const compared = compareObjectsBasedOn(propKeys, objectsToCompare as any)
|
|
22
|
-
if (!compared.equal) comparison.equal = false
|
|
23
|
-
comparison.perIndex.push(compared)
|
|
24
|
-
})
|
|
25
|
-
return comparison
|
|
26
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { pick } from 'filter-anything'
|
|
2
|
-
|
|
3
|
-
export type ComparisonObjects<ObjectType> = {
|
|
4
|
-
differentProps: (keyof ObjectType)[]
|
|
5
|
-
differentPropsPicked: Partial<ObjectType>[]
|
|
6
|
-
equal: boolean
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function compareObjectsBasedOn<
|
|
10
|
-
ObjectType extends Record<string, any> | any = Record<string, any>
|
|
11
|
-
>(propKeys: (keyof ObjectType)[], objects: [ObjectType, ...any[]]): ComparisonObjects<ObjectType> {
|
|
12
|
-
type PropKeys = keyof ObjectType
|
|
13
|
-
const baseProps = propKeys
|
|
14
|
-
const baseObject = objects[0]
|
|
15
|
-
const differentPropsSet: Set<PropKeys> = objects.reduce((carry, object, index) => {
|
|
16
|
-
if (index === 0) return carry
|
|
17
|
-
for (const prop of baseProps) {
|
|
18
|
-
if (object[prop] !== baseObject[prop]) carry.add(prop)
|
|
19
|
-
}
|
|
20
|
-
return carry
|
|
21
|
-
}, new Set() as Set<PropKeys>)
|
|
22
|
-
const differentProps = [...differentPropsSet]
|
|
23
|
-
const differentPropsPicked = objects.map((object) =>
|
|
24
|
-
pick(object, differentProps as string[])
|
|
25
|
-
) as Partial<ObjectType>[]
|
|
26
|
-
return {
|
|
27
|
-
differentProps,
|
|
28
|
-
differentPropsPicked,
|
|
29
|
-
equal: differentProps.length === 0,
|
|
30
|
-
}
|
|
31
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { isAnyObject, isArray, isString, isNumber } from 'is-what'
|
|
2
|
-
|
|
3
|
-
export { compareObjectsBasedOn } from './compareObjectsBasedOn'
|
|
4
|
-
export { compareObjectArraysBasedOn } from './compareObjectArraysBasedOn'
|
|
5
|
-
|
|
6
|
-
export function compareObjectProps(
|
|
7
|
-
...params: Record<string, any>[]
|
|
8
|
-
): {
|
|
9
|
-
props: string[]
|
|
10
|
-
presentInAll: { [prop: string]: boolean }
|
|
11
|
-
perProp: { [prop: string]: Record<string, any> }
|
|
12
|
-
presentIn: { [prop: string]: number[] }
|
|
13
|
-
} {
|
|
14
|
-
const propsSet = new Set()
|
|
15
|
-
const res = {
|
|
16
|
-
props: null,
|
|
17
|
-
presentInAll: null,
|
|
18
|
-
presentIn: {},
|
|
19
|
-
perProp: {},
|
|
20
|
-
}
|
|
21
|
-
params.forEach((object, index) => {
|
|
22
|
-
if (!isAnyObject(object)) {
|
|
23
|
-
throw new Error("'compareObjectProps' can only compare objects")
|
|
24
|
-
}
|
|
25
|
-
Object.keys(object).forEach((prop) => {
|
|
26
|
-
propsSet.add(prop)
|
|
27
|
-
if (!(prop in res.presentIn)) res.presentIn[prop] = []
|
|
28
|
-
res.presentIn[prop].push(index)
|
|
29
|
-
if (!(prop in res.perProp)) res.perProp[prop] = []
|
|
30
|
-
res.perProp[prop].push(object)
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
const paramCount = params.length
|
|
34
|
-
res.presentInAll = Object.keys(res.presentIn).reduce((carry, prop) => {
|
|
35
|
-
const propCount = res.presentIn[prop].length
|
|
36
|
-
carry[prop] = propCount === paramCount
|
|
37
|
-
return carry
|
|
38
|
-
}, {})
|
|
39
|
-
res.props = Array.from(propsSet)
|
|
40
|
-
return res
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function compareArrays(
|
|
44
|
-
...params: any[][]
|
|
45
|
-
): {
|
|
46
|
-
values: any[]
|
|
47
|
-
infoPerValue: {
|
|
48
|
-
[prop: string]: {
|
|
49
|
-
indexPerArray: (number | undefined)[]
|
|
50
|
-
presentInAll: boolean
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
presentInAll: any[]
|
|
54
|
-
} {
|
|
55
|
-
const valuesSet = new Set()
|
|
56
|
-
const res: {
|
|
57
|
-
values: null | any[]
|
|
58
|
-
infoPerValue: {
|
|
59
|
-
[val: string]: {
|
|
60
|
-
indexPerArray: (number | undefined)[]
|
|
61
|
-
presentInAll: boolean
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
presentInAll: string[]
|
|
65
|
-
} = {
|
|
66
|
-
values: null,
|
|
67
|
-
infoPerValue: {},
|
|
68
|
-
presentInAll: [],
|
|
69
|
-
}
|
|
70
|
-
const getEmptyArray = (): undefined[] => params.map(() => undefined)
|
|
71
|
-
params.forEach((array, paramIndex) => {
|
|
72
|
-
if (!isArray(array)) throw new Error("'compareArrays' can only compare arrays")
|
|
73
|
-
array.forEach((val, valIndex) => {
|
|
74
|
-
valuesSet.add(val)
|
|
75
|
-
const parsedVal = isNumber(val) || isString(val) ? String(val) : JSON.stringify(val)
|
|
76
|
-
if (!(parsedVal in res.infoPerValue)) {
|
|
77
|
-
res.infoPerValue[parsedVal] = {
|
|
78
|
-
indexPerArray: getEmptyArray(),
|
|
79
|
-
presentInAll: false,
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
res.infoPerValue[parsedVal].indexPerArray[paramIndex] = valIndex
|
|
83
|
-
})
|
|
84
|
-
})
|
|
85
|
-
Object.entries(res.infoPerValue).forEach(([parsedVal, info]) => {
|
|
86
|
-
const isInAllArrays =
|
|
87
|
-
info.indexPerArray.every((index) => isNumber(index) && index >= 0) &&
|
|
88
|
-
info.indexPerArray.length === params.length
|
|
89
|
-
info.presentInAll = isInAllArrays
|
|
90
|
-
if (isInAllArrays) res.presentInAll.push(parsedVal)
|
|
91
|
-
})
|
|
92
|
-
res.values = Array.from(valuesSet)
|
|
93
|
-
return res
|
|
94
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import test from 'ava'
|
|
3
|
-
import { compareObjectsBasedOn } from '../src'
|
|
4
|
-
|
|
5
|
-
test('compareObjectsBasedOn', (t) => {
|
|
6
|
-
const base = { a: 1, b: true, c: 'CC' }
|
|
7
|
-
const check = { d: 1 }
|
|
8
|
-
const result = compareObjectsBasedOn(['a', 'b'], [base, check])
|
|
9
|
-
t.deepEqual(result.differentProps, ['a', 'b'])
|
|
10
|
-
t.deepEqual(result.differentPropsPicked, [{ a: 1, b: true }, {}])
|
|
11
|
-
t.deepEqual(result.equal, false)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
// I don't think I want this syntax because it's too complex:
|
|
15
|
-
// test('compareObjectsBasedOn - nested', t => {
|
|
16
|
-
// const base = { nested: { a: 1, b: 2 } }
|
|
17
|
-
// const check = { nested: { a: 1, b: 3 } }
|
|
18
|
-
// const result = compareObjectsBasedOn(['nested.a', 'nested.b'] as any[], [base, check])
|
|
19
|
-
// t.deepEqual(result.differentProps, ['nested.b'])
|
|
20
|
-
// t.deepEqual(result.differentPropsPicked, [{ b: 2 }, { b: 3 }] as any)
|
|
21
|
-
// t.deepEqual(result.equal, false)
|
|
22
|
-
// })
|
|
23
|
-
|
|
24
|
-
test('compareObjectsBasedOn - check nested props flat', (t) => {
|
|
25
|
-
const base = { nested: { a: 1, b: 2 } }
|
|
26
|
-
const check = { nested: { a: 1, b: 3 } }
|
|
27
|
-
const result = compareObjectsBasedOn(['nested'], [base, check])
|
|
28
|
-
t.deepEqual(result.differentProps, ['nested'])
|
|
29
|
-
t.deepEqual(result.differentPropsPicked, [{ nested: { a: 1, b: 2 } }, { nested: { a: 1, b: 3 } }])
|
|
30
|
-
t.deepEqual(result.equal, false)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('compareObjectsBasedOn - check nested props flattened', (t) => {
|
|
34
|
-
const base = { 'nested.deep.a': 1, 'nested.deep.b': 2 }
|
|
35
|
-
const check = { 'nested.deep.a': 1, 'nested.deep.b': 3 }
|
|
36
|
-
const result = compareObjectsBasedOn(['nested.deep.a', 'nested.deep.b'], [base, check])
|
|
37
|
-
t.deepEqual(result.differentProps, ['nested.deep.b'])
|
|
38
|
-
t.deepEqual(result.differentPropsPicked, [{ 'nested.deep.b': 2 }, { 'nested.deep.b': 3 }])
|
|
39
|
-
t.deepEqual(result.equal, false)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
test('compareObjectsBasedOn - ok', (t) => {
|
|
43
|
-
const base = { a: 1, b: true, c: 'CC' }
|
|
44
|
-
const check = { a: 1, c: 'CC', d: 1 }
|
|
45
|
-
const result = compareObjectsBasedOn(['a', 'c'], [base, check])
|
|
46
|
-
t.deepEqual(result.differentProps, [])
|
|
47
|
-
t.deepEqual(result.differentPropsPicked, [{}, {}])
|
|
48
|
-
t.deepEqual(result.equal, true)
|
|
49
|
-
})
|
package/test/index.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import test from 'ava'
|
|
2
|
-
import { flatten } from 'flatten-anything'
|
|
3
|
-
import { compareObjectProps, compareArrays } from '../src/index'
|
|
4
|
-
|
|
5
|
-
test('compareObjectProps', t => {
|
|
6
|
-
let res, objectA, objectB
|
|
7
|
-
objectA = { a: '', b: '', c: '', d: '' }
|
|
8
|
-
objectB = { b: '', c: '', e: '', f: '' }
|
|
9
|
-
|
|
10
|
-
res = compareObjectProps(objectA, objectB)
|
|
11
|
-
t.deepEqual(res, {
|
|
12
|
-
props: ['a', 'b', 'c', 'd', 'e', 'f'],
|
|
13
|
-
presentInAll: { a: false, b: true, c: true, d: false, e: false, f: false },
|
|
14
|
-
presentIn: { a: [0], b: [0, 1], c: [0, 1], d: [0], e: [1], f: [1] },
|
|
15
|
-
perProp: {
|
|
16
|
-
a: [objectA],
|
|
17
|
-
b: [objectA, objectB],
|
|
18
|
-
c: [objectA, objectB],
|
|
19
|
-
d: [objectA],
|
|
20
|
-
e: [objectB],
|
|
21
|
-
f: [objectB]
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('compareObjectProps 3 or more', t => {
|
|
27
|
-
let res, objectA, objectB, objectC, objectD
|
|
28
|
-
objectA = { a: '', b: '', c: '', d: '' }
|
|
29
|
-
objectB = { b: '', c: '', e: '', f: '' }
|
|
30
|
-
objectC = { b: '1', e: '', d: '' }
|
|
31
|
-
objectD = { b: '2', c: '', a: '', f: '' }
|
|
32
|
-
|
|
33
|
-
res = compareObjectProps(objectA, objectB, objectC, objectD)
|
|
34
|
-
t.deepEqual(res, {
|
|
35
|
-
props: ['a', 'b', 'c', 'd', 'e', 'f'],
|
|
36
|
-
presentInAll: { a: false, b: true, c: false, d: false, e: false, f: false },
|
|
37
|
-
presentIn: {
|
|
38
|
-
a: [0, 3],
|
|
39
|
-
b: [0, 1, 2, 3],
|
|
40
|
-
c: [0, 1, 3],
|
|
41
|
-
d: [0, 2],
|
|
42
|
-
e: [1, 2],
|
|
43
|
-
f: [1, 3]
|
|
44
|
-
},
|
|
45
|
-
perProp: {
|
|
46
|
-
a: [objectA, objectD],
|
|
47
|
-
b: [objectA, objectB, objectC, objectD],
|
|
48
|
-
c: [objectA, objectB, objectD],
|
|
49
|
-
d: [objectA, objectC],
|
|
50
|
-
e: [objectB, objectC],
|
|
51
|
-
f: [objectB, objectD]
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
test('compareObjectProps flat', t => {
|
|
57
|
-
let res
|
|
58
|
-
const objectA = { nested: { a: '🃏️', b: '🎴' } }
|
|
59
|
-
const objectB = { nested: { a: '🃏', c: '🀄️' } }
|
|
60
|
-
const flatA = flatten(objectA)
|
|
61
|
-
// → {'nested.a': '🃏️', 'nested.b': '🎴'}
|
|
62
|
-
const flatB = flatten(objectB)
|
|
63
|
-
// → {'nested.a': '🃏️', 'nested.c': '🀄️'}
|
|
64
|
-
res = compareObjectProps(flatA, flatB)
|
|
65
|
-
t.deepEqual(res, {
|
|
66
|
-
props: ['nested.a', 'nested.b', 'nested.c'],
|
|
67
|
-
presentInAll: { 'nested.a': true, 'nested.b': false, 'nested.c': false },
|
|
68
|
-
presentIn: { 'nested.a': [0, 1], 'nested.b': [0], 'nested.c': [1] },
|
|
69
|
-
perProp: {
|
|
70
|
-
'nested.a': [flatA, flatB],
|
|
71
|
-
'nested.b': [flatA],
|
|
72
|
-
'nested.c': [flatB]
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('compareArrays', t => {
|
|
78
|
-
let res, arrayA, arrayB
|
|
79
|
-
arrayA = ['a', 'b', 'c', 'd']
|
|
80
|
-
arrayB = ['b', 'c', 'e', 'f']
|
|
81
|
-
|
|
82
|
-
res = compareArrays(arrayA, arrayB)
|
|
83
|
-
t.deepEqual(res, {
|
|
84
|
-
values: ['a', 'b', 'c', 'd', 'e', 'f'],
|
|
85
|
-
infoPerValue: {
|
|
86
|
-
a: { indexPerArray: [0, undefined], presentInAll: false },
|
|
87
|
-
b: { indexPerArray: [1, 0], presentInAll: true },
|
|
88
|
-
c: { indexPerArray: [2, 1], presentInAll: true },
|
|
89
|
-
d: { indexPerArray: [3, undefined], presentInAll: false },
|
|
90
|
-
e: { indexPerArray: [undefined, 2], presentInAll: false },
|
|
91
|
-
f: { indexPerArray: [undefined, 3], presentInAll: false }
|
|
92
|
-
},
|
|
93
|
-
presentInAll: ['b', 'c']
|
|
94
|
-
})
|
|
95
|
-
})
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"baseUrl": ".",
|
|
4
|
-
"downlevelIteration": true,
|
|
5
|
-
"outDir": "./dist",
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"declarationDir": "./types/",
|
|
8
|
-
"target": "es5",
|
|
9
|
-
"lib": ["es5", "es2015", "es2016", "es2017", "dom"]
|
|
10
|
-
},
|
|
11
|
-
"include": [
|
|
12
|
-
"src/**/*",
|
|
13
|
-
"test/**/*"
|
|
14
|
-
]
|
|
15
|
-
}
|