fast-equals 5.3.1 → 5.3.2
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/CHANGELOG.md +5 -0
- package/dist/min/index.js +1 -1
- package/package.json +14 -5
- package/.babelrc +0 -34
- package/.prettierrc +0 -8
- package/.release-it.beta.json +0 -18
- package/.release-it.json +0 -14
- package/.yarnrc.yml +0 -5
- package/BUILD.md +0 -37
- package/config/rollup/config.base.js +0 -49
- package/config/rollup/config.cjs.js +0 -10
- package/config/rollup/config.esm.js +0 -10
- package/config/rollup/config.min.js +0 -13
- package/config/rollup/config.umd.js +0 -10
- package/config/tsconfig/base.json +0 -32
- package/config/tsconfig/cjs.json +0 -8
- package/config/tsconfig/declarations.json +0 -9
- package/config/tsconfig/esm.json +0 -8
- package/config/tsconfig/min.json +0 -8
- package/config/tsconfig/umd.json +0 -8
- package/config/webpack.config.js +0 -57
- package/recipes/explicit-property-check.md +0 -26
- package/recipes/legacy-circular-equal-support.md +0 -75
- package/recipes/legacy-regexp-support.md +0 -24
- package/recipes/non-standard-properties.md +0 -48
- package/recipes/special-objects.md +0 -25
- package/recipes/using-meta-in-comparison.md +0 -20
- package/scripts/apply-type-file-extensions.mjs +0 -33
- package/scripts/fallback-types.mjs +0 -64
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# fast-equals CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 5.3.2
|
|
4
|
+
|
|
5
|
+
- [#154](https://github.com/planttheidea/fast-equals/pull/154) - Use include with `"files"` instead of exclude with `.npmignore` (Thanks [@43081j](https://github.com/43081j))
|
|
6
|
+
- [#155](https://github.com/planttheidea/fast-equals/pull/155) - Upgrade build dependencies to resolve security vulnerabilities
|
|
7
|
+
|
|
3
8
|
## 5.3.1
|
|
4
9
|
|
|
5
10
|
- [#153](https://github.com/planttheidea/fast-equals/pull/153) - Avoid publishing `.yarn` folder
|
package/dist/min/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((r="undefined"!=typeof globalThis?globalThis:r||self)["fast-equals"]={})}(this,
|
|
1
|
+
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((r="undefined"!=typeof globalThis?globalThis:r||self)["fast-equals"]={})}(this,function(r){"use strict";var e=Object.getOwnPropertyNames,t=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty;function n(r,e){return function(t,a,n){return r(t,a,n)&&e(t,a,n)}}function u(r){return function(e,t,a){if(!e||!t||"object"!=typeof e||"object"!=typeof t)return r(e,t,a);var n=a.cache,u=n.get(e),o=n.get(t);if(u&&o)return u===t&&o===e;n.set(e,t),n.set(t,e);var i=r(e,t,a);return n.delete(e),n.delete(t),i}}function o(r){return e(r).concat(t(r))}var i=Object.hasOwn||function(r,e){return a.call(r,e)};function c(r,e){return r===e||!r&&!e&&r!=r&&e!=e}var l=Object.getOwnPropertyDescriptor,f=Object.keys;function s(r,e,t){var a=r.length;if(e.length!==a)return!1;for(;a-- >0;)if(!t.equals(r[a],e[a],a,a,r,e,t))return!1;return!0}function p(r,e){return c(r.getTime(),e.getTime())}function v(r,e){return r.name===e.name&&r.message===e.message&&r.cause===e.cause&&r.stack===e.stack}function q(r,e){return r===e}function E(r,e,t){var a=r.size;if(a!==e.size)return!1;if(!a)return!0;for(var n,u,o=new Array(a),i=r.entries(),c=0;(n=i.next())&&!n.done;){for(var l=e.entries(),f=!1,s=0;(u=l.next())&&!u.done;)if(o[s])s++;else{var p=n.value,v=u.value;if(t.equals(p[0],v[0],c,s,r,e,t)&&t.equals(p[1],v[1],p[0],v[0],r,e,t)){f=o[s]=!0;break}s++}if(!f)return!1;c++}return!0}var b=c;function m(r,e,t){var a=f(r),n=a.length;if(f(e).length!==n)return!1;for(;n-- >0;)if(!O(r,e,t,a[n]))return!1;return!0}function y(r,e,t){var a,n,u,i=o(r),c=i.length;if(o(e).length!==c)return!1;for(;c-- >0;){if(!O(r,e,t,a=i[c]))return!1;if(n=l(r,a),u=l(e,a),(n||u)&&(!n||!u||n.configurable!==u.configurable||n.enumerable!==u.enumerable||n.writable!==u.writable))return!1}return!0}function g(r,e){return c(r.valueOf(),e.valueOf())}function h(r,e){return r.source===e.source&&r.flags===e.flags}function d(r,e,t){var a=r.size;if(a!==e.size)return!1;if(!a)return!0;for(var n,u,o=new Array(a),i=r.values();(n=i.next())&&!n.done;){for(var c=e.values(),l=!1,f=0;(u=c.next())&&!u.done;){if(!o[f]&&t.equals(n.value,u.value,n.value,u.value,r,e,t)){l=o[f]=!0;break}f++}if(!l)return!1}return!0}function j(r,e){var t=r.length;if(e.length!==t)return!1;for(;t-- >0;)if(r[t]!==e[t])return!1;return!0}function w(r,e){return r.hostname===e.hostname&&r.pathname===e.pathname&&r.protocol===e.protocol&&r.port===e.port&&r.hash===e.hash&&r.username===e.username&&r.password===e.password}function O(r,e,t,a){return!("_owner"!==a&&"__o"!==a&&"__v"!==a||!r.$$typeof&&!e.$$typeof)||i(e,a)&&t.equals(r[a],e[a],a,a,r,e,t)}var S=Array.isArray,A="function"==typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView:null,C=Object.assign,x=Object.prototype.toString.call.bind(Object.prototype.toString);function k(r){var e=r.areArraysEqual,t=r.areDatesEqual,a=r.areErrorsEqual,n=r.areFunctionsEqual,u=r.areMapsEqual,o=r.areNumbersEqual,i=r.areObjectsEqual,c=r.arePrimitiveWrappersEqual,l=r.areRegExpsEqual,f=r.areSetsEqual,s=r.areTypedArraysEqual,p=r.areUrlsEqual,v=r.unknownTagComparators;return function(r,q,E){if(r===q)return!0;if(null==r||null==q)return!1;var b=typeof r;if(b!==typeof q)return!1;if("object"!==b)return"number"===b?o(r,q,E):"function"===b&&n(r,q,E);var m=r.constructor;if(m!==q.constructor)return!1;if(m===Object)return i(r,q,E);if(S(r))return e(r,q,E);if(null!=A&&A(r))return s(r,q,E);if(m===Date)return t(r,q,E);if(m===RegExp)return l(r,q,E);if(m===Map)return u(r,q,E);if(m===Set)return f(r,q,E);var y,g=x(r);if("[object Date]"===g)return t(r,q,E);if("[object RegExp]"===g)return l(r,q,E);if("[object Map]"===g)return u(r,q,E);if("[object Set]"===g)return f(r,q,E);if("[object Object]"===g)return"function"!=typeof r.then&&"function"!=typeof q.then&&i(r,q,E);if("[object URL]"===g)return p(r,q,E);if("[object Error]"===g)return a(r,q,E);if("[object Arguments]"===g)return i(r,q,E);if("[object Boolean]"===g||"[object Number]"===g||"[object String]"===g)return c(r,q,E);if(v){var h=v[g];if(!h){var d=null!=(y=r)?y[Symbol.toStringTag]:void 0;d&&(h=v[d])}if(h)return h(r,q,E)}return!1}}var T=B(),D=B({strict:!0}),M=B({circular:!0}),P=B({circular:!0,strict:!0}),I=B({createInternalComparator:function(){return c}}),R=B({strict:!0,createInternalComparator:function(){return c}}),_=B({circular:!0,createInternalComparator:function(){return c}}),z=B({circular:!0,createInternalComparator:function(){return c},strict:!0});function B(r){void 0===r&&(r={});var e,t=r.circular,a=void 0!==t&&t,o=r.createInternalComparator,i=r.createState,c=r.strict,l=void 0!==c&&c,f=function(r){var e=r.circular,t=r.createCustomConfig,a=r.strict,o={areArraysEqual:a?y:s,areDatesEqual:p,areErrorsEqual:v,areFunctionsEqual:q,areMapsEqual:a?n(E,y):E,areNumbersEqual:b,areObjectsEqual:a?y:m,arePrimitiveWrappersEqual:g,areRegExpsEqual:h,areSetsEqual:a?n(d,y):d,areTypedArraysEqual:a?y:j,areUrlsEqual:w,unknownTagComparators:void 0};if(t&&(o=C({},o,t(o))),e){var i=u(o.areArraysEqual),c=u(o.areMapsEqual),l=u(o.areObjectsEqual),f=u(o.areSetsEqual);o=C({},o,{areArraysEqual:i,areMapsEqual:c,areObjectsEqual:l,areSetsEqual:f})}return o}(r),O=k(f);return function(r){var e=r.circular,t=r.comparator,a=r.createState,n=r.equals,u=r.strict;if(a)return function(r,o){var i=a(),c=i.cache,l=void 0===c?e?new WeakMap:void 0:c,f=i.meta;return t(r,o,{cache:l,equals:n,meta:f,strict:u})};if(e)return function(r,e){return t(r,e,{cache:new WeakMap,equals:n,meta:void 0,strict:u})};var o={cache:void 0,equals:n,meta:void 0,strict:u};return function(r,e){return t(r,e,o)}}({circular:a,comparator:O,createState:i,equals:o?o(O):(e=O,function(r,t,a,n,u,o,i){return e(r,t,i)}),strict:l})}r.circularDeepEqual=M,r.circularShallowEqual=_,r.createCustomEqual=B,r.deepEqual=T,r.sameValueZeroEqual=c,r.shallowEqual=I,r.strictCircularDeepEqual=P,r.strictCircularShallowEqual=z,r.strictDeepEqual=D,r.strictShallowEqual=R});
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"react": "^18.3.1",
|
|
40
40
|
"react-dom": "^18.3.1",
|
|
41
41
|
"react-fast-compare": "^3.2.1",
|
|
42
|
-
"release-it": "^
|
|
42
|
+
"release-it": "^19.0.5",
|
|
43
43
|
"rollup": "^3.29.5",
|
|
44
44
|
"shallow-equal-fuzzy": "^0.0.2",
|
|
45
45
|
"tinybench": "^2.9.0",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"ts-loader": "^9.4.2",
|
|
48
48
|
"typescript": "^4.9.5",
|
|
49
49
|
"underscore": "^1.13.4",
|
|
50
|
-
"webpack": "^5.
|
|
51
|
-
"webpack-cli": "^
|
|
52
|
-
"webpack-dev-server": "^5.2.
|
|
50
|
+
"webpack": "^5.101.3",
|
|
51
|
+
"webpack-cli": "^6.0.1",
|
|
52
|
+
"webpack-dev-server": "^5.2.2"
|
|
53
53
|
},
|
|
54
54
|
"engines": {
|
|
55
55
|
"node": ">=6.0.0"
|
|
@@ -70,6 +70,15 @@
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
|
+
"files": [
|
|
74
|
+
"dist",
|
|
75
|
+
"src",
|
|
76
|
+
"CHANGELOG.md",
|
|
77
|
+
"index.d.ts",
|
|
78
|
+
"LICENSE",
|
|
79
|
+
"package.json",
|
|
80
|
+
"README.md"
|
|
81
|
+
],
|
|
73
82
|
"homepage": "https://github.com/planttheidea/fast-equals#readme",
|
|
74
83
|
"keywords": [
|
|
75
84
|
"fast",
|
|
@@ -110,5 +119,5 @@
|
|
|
110
119
|
"sideEffects": false,
|
|
111
120
|
"type": "module",
|
|
112
121
|
"types": "./index.d.ts",
|
|
113
|
-
"version": "5.3.
|
|
122
|
+
"version": "5.3.2"
|
|
114
123
|
}
|
package/.babelrc
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"lib": {
|
|
4
|
-
"presets": [
|
|
5
|
-
[
|
|
6
|
-
"@babel/preset-env",
|
|
7
|
-
{
|
|
8
|
-
"loose": true
|
|
9
|
-
}
|
|
10
|
-
]
|
|
11
|
-
]
|
|
12
|
-
},
|
|
13
|
-
"test": {
|
|
14
|
-
"presets": [
|
|
15
|
-
[
|
|
16
|
-
"@babel/preset-env",
|
|
17
|
-
{
|
|
18
|
-
"loose": true
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
]
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"presets": [
|
|
25
|
-
"@babel/preset-typescript",
|
|
26
|
-
[
|
|
27
|
-
"@babel/preset-env",
|
|
28
|
-
{
|
|
29
|
-
"loose": true,
|
|
30
|
-
"modules": false
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
]
|
|
34
|
-
}
|
package/.prettierrc
DELETED
package/.release-it.beta.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"github": {
|
|
3
|
-
"release": true,
|
|
4
|
-
"tagName": "v${version}"
|
|
5
|
-
},
|
|
6
|
-
"hooks": {
|
|
7
|
-
"before:init": [
|
|
8
|
-
"npm run typecheck",
|
|
9
|
-
"npm run lint",
|
|
10
|
-
"npm run test",
|
|
11
|
-
"npm run build"
|
|
12
|
-
]
|
|
13
|
-
},
|
|
14
|
-
"npm": {
|
|
15
|
-
"tag": "next"
|
|
16
|
-
},
|
|
17
|
-
"preReleaseId": "beta"
|
|
18
|
-
}
|
package/.release-it.json
DELETED
package/.yarnrc.yml
DELETED
package/BUILD.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Reproducing a build
|
|
2
|
-
|
|
3
|
-
## Clone version
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
git clone https://github.com/planttheidea/fast-equals.git
|
|
7
|
-
cd fast-equals
|
|
8
|
-
git checkout {version}
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Replace `{version}` above with the appropriate package version. If you want to compare a version older than `1.6.2`, you'll need to use a commit hash directly.
|
|
12
|
-
|
|
13
|
-
## Install
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
yarn install
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
We use `yarn` for our package management, so to ensure that exact dependencies you should also use it.
|
|
20
|
-
|
|
21
|
-
## Build artifacts
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
yarn run build
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**NOTE**: To get an exact checksum match with the versions released on npm, it may be necessary to change line endings. For example, on Linux you might run:
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
unix2dos dist/fast-equals.min.js
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Get checksum
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
sha256sum dist/fast-equals.min.js
|
|
37
|
-
```
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import commonjs from '@rollup/plugin-commonjs';
|
|
2
|
-
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
3
|
-
import replace from '@rollup/plugin-replace';
|
|
4
|
-
import typescript from '@rollup/plugin-typescript';
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import tsc from 'typescript';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
|
|
10
|
-
const ROOT = fileURLToPath(new URL('../..', import.meta.url));
|
|
11
|
-
|
|
12
|
-
export const PACKAGE_JSON = JSON.parse(
|
|
13
|
-
fs.readFileSync(path.resolve(ROOT, 'package.json')),
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
const external = [
|
|
17
|
-
...Object.keys(PACKAGE_JSON.dependencies || {}),
|
|
18
|
-
...Object.keys(PACKAGE_JSON.peerDependencies || {}),
|
|
19
|
-
];
|
|
20
|
-
const globals = external.reduce((globals, name) => {
|
|
21
|
-
globals[name] = name;
|
|
22
|
-
|
|
23
|
-
return globals;
|
|
24
|
-
}, {});
|
|
25
|
-
|
|
26
|
-
export const BASE_CONFIG = {
|
|
27
|
-
external,
|
|
28
|
-
input: path.resolve(ROOT, 'src', 'index.ts'),
|
|
29
|
-
output: {
|
|
30
|
-
exports: 'named',
|
|
31
|
-
globals,
|
|
32
|
-
name: 'fast-equals',
|
|
33
|
-
sourcemap: true,
|
|
34
|
-
},
|
|
35
|
-
plugins: [
|
|
36
|
-
replace({
|
|
37
|
-
'process.env.NODE_ENV': JSON.stringify('production'),
|
|
38
|
-
preventAssignment: true,
|
|
39
|
-
}),
|
|
40
|
-
nodeResolve({
|
|
41
|
-
mainFields: ['module', 'browser', 'main'],
|
|
42
|
-
}),
|
|
43
|
-
commonjs({ include: /use-sync-external-store/ }),
|
|
44
|
-
typescript({
|
|
45
|
-
tsconfig: path.resolve(ROOT, 'config', 'tsconfig', 'base.json'),
|
|
46
|
-
typescript: tsc,
|
|
47
|
-
}),
|
|
48
|
-
],
|
|
49
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { BASE_CONFIG, PACKAGE_JSON } from './config.base.js';
|
|
2
|
-
import terser from '@rollup/plugin-terser';
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
...BASE_CONFIG,
|
|
6
|
-
output: {
|
|
7
|
-
...BASE_CONFIG.output,
|
|
8
|
-
file: PACKAGE_JSON.browser.replace('umd', 'min'),
|
|
9
|
-
format: 'umd',
|
|
10
|
-
sourcemap: false,
|
|
11
|
-
},
|
|
12
|
-
plugins: [...BASE_CONFIG.plugins, terser()],
|
|
13
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"allowJs": true,
|
|
4
|
-
"allowUnreachableCode": false,
|
|
5
|
-
"baseUrl": "../../src",
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"jsx": "react-jsx",
|
|
8
|
-
"lib": ["DOM", "ESNext"],
|
|
9
|
-
"module": "ESNext",
|
|
10
|
-
"moduleResolution": "Node",
|
|
11
|
-
"noFallthroughCasesInSwitch": true,
|
|
12
|
-
"noImplicitAny": true,
|
|
13
|
-
"noImplicitReturns": true,
|
|
14
|
-
"noImplicitThis": true,
|
|
15
|
-
"noUncheckedIndexedAccess": true,
|
|
16
|
-
"noUnusedLocals": true,
|
|
17
|
-
"noUnusedParameters": true,
|
|
18
|
-
"outDir": "../../../dist",
|
|
19
|
-
"resolveJsonModule": true,
|
|
20
|
-
"skipLibCheck": true,
|
|
21
|
-
"sourceMap": true,
|
|
22
|
-
"strict": true,
|
|
23
|
-
"strictBindCallApply": true,
|
|
24
|
-
"strictNullChecks": true,
|
|
25
|
-
"inlineSources": true,
|
|
26
|
-
"target": "es5",
|
|
27
|
-
"types": ["jest", "node", "react"]
|
|
28
|
-
},
|
|
29
|
-
"exclude": ["../../node_modules"],
|
|
30
|
-
"include": ["../../src/**/*", "../../__tests__/**/*", "../../DEV_ONLY/**/*"],
|
|
31
|
-
"files": ["../../node_modules/jest-expect-message/types/index.d.ts"]
|
|
32
|
-
}
|
package/config/tsconfig/cjs.json
DELETED
package/config/tsconfig/esm.json
DELETED
package/config/tsconfig/min.json
DELETED
package/config/tsconfig/umd.json
DELETED
package/config/webpack.config.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
-
|
|
3
|
-
import ESLintWebpackPlugin from 'eslint-webpack-plugin';
|
|
4
|
-
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
import webpack from 'webpack';
|
|
8
|
-
|
|
9
|
-
const ROOT = fileURLToPath(new URL('..', import.meta.url));
|
|
10
|
-
const PORT = 3000;
|
|
11
|
-
|
|
12
|
-
export default {
|
|
13
|
-
cache: true,
|
|
14
|
-
|
|
15
|
-
devServer: {
|
|
16
|
-
host: 'localhost',
|
|
17
|
-
port: PORT,
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
devtool: 'source-map',
|
|
21
|
-
|
|
22
|
-
entry: [path.resolve(ROOT, 'DEV_ONLY', 'index.tsx')],
|
|
23
|
-
|
|
24
|
-
mode: 'development',
|
|
25
|
-
|
|
26
|
-
module: {
|
|
27
|
-
rules: [
|
|
28
|
-
{
|
|
29
|
-
include: [path.resolve(ROOT, 'src'), path.resolve(ROOT, 'DEV_ONLY')],
|
|
30
|
-
loader: 'ts-loader',
|
|
31
|
-
options: {
|
|
32
|
-
reportFiles: ['src/*.{ts|tsx}'],
|
|
33
|
-
},
|
|
34
|
-
test: /\.(ts|tsx)$/,
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
output: {
|
|
40
|
-
filename: 'fast-equals.js',
|
|
41
|
-
library: 'fastEquals',
|
|
42
|
-
libraryTarget: 'umd',
|
|
43
|
-
path: path.resolve(ROOT, 'dist'),
|
|
44
|
-
publicPath: `http://localhost:${PORT}/`,
|
|
45
|
-
umdNamedDefine: true,
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
plugins: [
|
|
49
|
-
new ESLintWebpackPlugin(),
|
|
50
|
-
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
|
51
|
-
new HtmlWebpackPlugin(),
|
|
52
|
-
],
|
|
53
|
-
|
|
54
|
-
resolve: {
|
|
55
|
-
extensions: ['.tsx', '.ts', '.js'],
|
|
56
|
-
},
|
|
57
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Explicit property check
|
|
2
|
-
|
|
3
|
-
Sometimes it is necessary to squeeze every once of performance out of your runtime code, and deep equality checks can be a bottleneck. When this is occurs, it can be advantageous to build a custom comparison that allows for highly specific equality checks.
|
|
4
|
-
|
|
5
|
-
An example where you know the shape of the objects being passed in, where the `foo` property is a simple primitive and the `bar` property is a nested object:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { createCustomEqual } from 'fast-equals';
|
|
9
|
-
import type { TypeEqualityComparator } from 'fast-equals';
|
|
10
|
-
|
|
11
|
-
interface SpecialObject {
|
|
12
|
-
foo: string;
|
|
13
|
-
bar: {
|
|
14
|
-
baz: number;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const areObjectsEqual: TypeEqualityComparator<SpecialObject, undefined> = (
|
|
19
|
-
a,
|
|
20
|
-
b,
|
|
21
|
-
) => a.foo === b.foo && a.bar.baz === b.bar.baz;
|
|
22
|
-
|
|
23
|
-
const isSpecialObjectEqual = createCustomEqual({
|
|
24
|
-
createCustomConfig: () => ({ areObjectsEqual }),
|
|
25
|
-
});
|
|
26
|
-
```
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Legacy environment support for circular equal comparators
|
|
2
|
-
|
|
3
|
-
Starting in `4.x.x`, `WeakMap` is expected to be available in the environment. All modern browsers support this global object, however there may be situations where a legacy environmental support is required (example: IE11). If you need to support such an environment and polyfilling is not an option, creating a custom comparator that uses a custom cache implementation with the same contract is a simple solution.
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
import { createCustomEqual, sameValueZeroEqual } from 'fast-equals';
|
|
7
|
-
import type { Cache } from 'fast-equals';
|
|
8
|
-
|
|
9
|
-
function getCache(): Cache<any, any> {
|
|
10
|
-
const entries: Array<[object, any]> = [];
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
delete(key) {
|
|
14
|
-
for (let index = 0; index < entries.length; ++index) {
|
|
15
|
-
if (entries[index][0] === key) {
|
|
16
|
-
entries.splice(index, 1);
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return false;
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
get(key) {
|
|
25
|
-
for (let index = 0; index < entries.length; ++index) {
|
|
26
|
-
if (entries[index][0] === key) {
|
|
27
|
-
return entries[index][1];
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
set(key, value) {
|
|
33
|
-
for (let index = 0; index < entries.length; ++index) {
|
|
34
|
-
if (entries[index][0] === key) {
|
|
35
|
-
entries[index][1] = value;
|
|
36
|
-
return this;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
entries.push([key, value]);
|
|
41
|
-
|
|
42
|
-
return this;
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface Meta {
|
|
48
|
-
customMethod(): void;
|
|
49
|
-
customValue: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const meta = {
|
|
53
|
-
customMethod() {
|
|
54
|
-
console.log('hello!');
|
|
55
|
-
},
|
|
56
|
-
customValue: 'goodbye',
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const circularDeepEqual = createCustomEqual<Cache>({
|
|
60
|
-
circular: true,
|
|
61
|
-
createState: () => ({
|
|
62
|
-
cache: getCache(),
|
|
63
|
-
meta,
|
|
64
|
-
}),
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const circularShallowEqual = createCustomEqual<Cache>({
|
|
68
|
-
circular: true,
|
|
69
|
-
comparator: sameValueZeroEqual,
|
|
70
|
-
createState: () => ({
|
|
71
|
-
cache: getCache(),
|
|
72
|
-
meta,
|
|
73
|
-
}),
|
|
74
|
-
});
|
|
75
|
-
```
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Legacy environment support for `RegExp` comparators
|
|
2
|
-
|
|
3
|
-
Starting in `4.x.x`, `RegExp.prototype.flags` is expected to be available in the environment. All modern browsers support this feature, however there may be situations where a legacy environmental support is required (example: IE11). If you need to support such an environment and polyfilling is not an option, creating a custom comparator that uses a more verbose comparison of all possible flags is a simple solution.
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
import { createCustomEqual, sameValueZeroEqual } from 'deep-Equals';
|
|
7
|
-
|
|
8
|
-
const areRegExpsEqual = (a: RegExp, b: RegExp) =>
|
|
9
|
-
a.source === b.source &&
|
|
10
|
-
a.global === b.global &&
|
|
11
|
-
a.ignoreCase === b.ignoreCase &&
|
|
12
|
-
a.multiline === b.multiline &&
|
|
13
|
-
a.unicode === b.unicode &&
|
|
14
|
-
a.sticky === b.sticky &&
|
|
15
|
-
a.lastIndex === b.lastIndex;
|
|
16
|
-
|
|
17
|
-
const deepEqual = createCustomEqual({
|
|
18
|
-
createCustomConfig: () => ({ areRegExpsEqual }),
|
|
19
|
-
});
|
|
20
|
-
const shallowEqual = createCustomEqual({
|
|
21
|
-
comparator: sameValueZero,
|
|
22
|
-
createCustomConfig: () => ({ areRegExpsEqual }),
|
|
23
|
-
});
|
|
24
|
-
```
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Non-standard properties
|
|
2
|
-
|
|
3
|
-
Sometimes, objects require a comparison that extend beyond its own keys, or even its own properties or symbols. Using a custom object comparator with `createCustomEqual` allows these kinds of comparisons.
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
import { createCustomEqual } from 'fast-equals';
|
|
7
|
-
import type { TypeEqualityComparator } from 'fast-equals';
|
|
8
|
-
|
|
9
|
-
type AreObjectsEqual = TypeEqualityComparator<Record<any, any>, undefined>;
|
|
10
|
-
|
|
11
|
-
class HiddenProperty {
|
|
12
|
-
visible: boolean;
|
|
13
|
-
#hidden: string;
|
|
14
|
-
|
|
15
|
-
constructor(value: string) {
|
|
16
|
-
this.visible = true;
|
|
17
|
-
this.#hidden = value;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
get hidden() {
|
|
21
|
-
return this.#hidden;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function createAreObjectsEqual(
|
|
26
|
-
areObjectsEqual: AreObjectsEqual,
|
|
27
|
-
): AreObjectsEqual {
|
|
28
|
-
return function (a, b, state) {
|
|
29
|
-
if (!areObjectsEqual(a, b, state)) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const aInstance = a instanceof HiddenProperty;
|
|
34
|
-
const bInstance = b instanceof HiddenProperty;
|
|
35
|
-
|
|
36
|
-
if (aInstance || bInstance) {
|
|
37
|
-
return aInstance && bInstance && a.hidden === b.hidden;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return true;
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const deepEqual = createCustomEqual({
|
|
45
|
-
createCustomConfig: ({ areObjectsEqual }) =>
|
|
46
|
-
createAreObjectsEqual(areObjectsEqual),
|
|
47
|
-
});
|
|
48
|
-
```
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Handling special (built-in) objects
|
|
2
|
-
|
|
3
|
-
The `createCustomEqual` uses `@@toStringTag` to decide which well-known comparator to call. However, some values might not fit either of them. For example `WeakMap` is compared intentionally. Additionally, it's possible that new built-in objects are added to the language. Third parties might also add `@@toStringTag` to their objects.
|
|
4
|
-
|
|
5
|
-
For example the [TC39 Temporal spec](https://tc39.es/proposal-temporal/docs/) requires `@@toStringTag` being implemetend and the polyfills do that. Passing `areObjectsEqual` will not work in that scenario. Instead you'll have to register a handler for the tag instead.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { createCustomEqual } from 'fast-equals';
|
|
9
|
-
import type { TypeEqualityComparator } from 'fast-equals';
|
|
10
|
-
|
|
11
|
-
const areZonedDateTimesEqual: TypeEqualityComparator<unknown, undefined> = (
|
|
12
|
-
a,
|
|
13
|
-
b,
|
|
14
|
-
) => a instanceof Temporal.ZonedDateTime
|
|
15
|
-
&& b instanceof Temporal.ZonedDateTime
|
|
16
|
-
&& a.equals(b);
|
|
17
|
-
|
|
18
|
-
const isSpecialObjectEqual = createCustomEqual({
|
|
19
|
-
createCustomConfig: () => ({
|
|
20
|
-
unknownTagComparators: {
|
|
21
|
-
"Temporal.ZonedDateTime", areZonedDateTimesEqual,
|
|
22
|
-
}
|
|
23
|
-
}),
|
|
24
|
-
});
|
|
25
|
-
```
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Using `meta` in comparison
|
|
2
|
-
|
|
3
|
-
Sometimes a "pure" equality between two objects is insufficient, because the comparison relies on some external state. While these kinds of scenarios should generally be avoided, it is possible to handle them with a custom internal comparator that checks `meta` values.
|
|
4
|
-
|
|
5
|
-
```ts
|
|
6
|
-
import { createCustomEqual } from 'fast-equals';
|
|
7
|
-
|
|
8
|
-
interface Meta {
|
|
9
|
-
value: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const meta: Meta = { value: 'baz' };
|
|
13
|
-
|
|
14
|
-
const deepEqual = createCustomEqual<Meta>({
|
|
15
|
-
createInternalComparator:
|
|
16
|
-
(compare) => (a, b, _keyA, _keyB, _parentA, _parentB, state) =>
|
|
17
|
-
compare(a, b, state) || a === state.meta.value || b === state.meta.value,
|
|
18
|
-
createState: () => ({ meta }),
|
|
19
|
-
});
|
|
20
|
-
```
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import glob from 'fast-glob';
|
|
2
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
|
|
5
|
-
const IMPORT_STATEMENT_REGEXP =
|
|
6
|
-
/import([ \n\t]*(?:[^ \n\t\{\}]+[ \n\t]*,?)?(?:[ \n\t]*\{(?:[ \n\t]*[^ \n\t"'\{\}]+[ \n\t]*,?)+\})?[ \n\t]*)from[ \n\t]*(['"])([^'"\n]+)(?:['"])/g;
|
|
7
|
-
|
|
8
|
-
const EXPORT_STATEMENT_REGEXP =
|
|
9
|
-
/export([ \n\t]*(?:[^ \n\t\{\}]+[ \n\t]*,?)?(?:[ \n\t]*\{(?:[ \n\t]*[^ \n\t"'\{\}]+[ \n\t]*,?)+\})?[ \n\t]*)from[ \n\t]*(['"])([^'"\n]+)(?:['"])/g;
|
|
10
|
-
|
|
11
|
-
const files = glob.sync(
|
|
12
|
-
join(import.meta.dirname, '..', 'dist', '*', 'types', '*.d.ts'),
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
function getReplacement(type) {
|
|
16
|
-
return function (line, dependencies, _quoteType, location) {
|
|
17
|
-
const extension = line.startsWith(`${type} type`) ? 'd.ts' : 'ts';
|
|
18
|
-
|
|
19
|
-
return `${type}${dependencies}from '${location}.${extension}'`;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function getReplacedContents(contents) {
|
|
24
|
-
return contents
|
|
25
|
-
.replaceAll(IMPORT_STATEMENT_REGEXP, getReplacement('import'))
|
|
26
|
-
.replaceAll(EXPORT_STATEMENT_REGEXP, getReplacement('export'));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
for (const file of files) {
|
|
30
|
-
const contents = readFileSync(file, 'utf-8');
|
|
31
|
-
|
|
32
|
-
writeFileSync(file, getReplacedContents(contents), 'utf-8');
|
|
33
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
const METHODS = `
|
|
5
|
-
/**
|
|
6
|
-
* Whether the values passed are strictly equal or both NaN.
|
|
7
|
-
*/
|
|
8
|
-
export declare const sameValueZeroEqual: <A, B>(a: A, b: B) => boolean;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Whether the items passed are deeply-equal in value.
|
|
12
|
-
*/
|
|
13
|
-
export declare const deepEqual: <A, B>(a: A, b: B) => boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Whether the items passed are deeply-equal in value based on strict comparison.
|
|
16
|
-
*/
|
|
17
|
-
export declare const strictDeepEqual: <A, B>(a: A, b: B) => boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Whether the items passed are deeply-equal in value, including circular references.
|
|
20
|
-
*/
|
|
21
|
-
export declare const circularDeepEqual: <A, B>(a: A, b: B) => boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Whether the items passed are deeply-equal in value, including circular references,
|
|
24
|
-
* based on strict comparison.
|
|
25
|
-
*/
|
|
26
|
-
export declare const strictCircularDeepEqual: <A, B>(a: A, b: B) => boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Whether the items passed are shallowly-equal in value.
|
|
29
|
-
*/
|
|
30
|
-
export declare const shallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Whether the items passed are shallowly-equal in value based on strict comparison
|
|
33
|
-
*/
|
|
34
|
-
export declare const strictShallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
35
|
-
/**
|
|
36
|
-
* Whether the items passed are shallowly-equal in value, including circular references.
|
|
37
|
-
*/
|
|
38
|
-
export declare const circularShallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Whether the items passed are shallowly-equal in value, including circular references,
|
|
41
|
-
* based on strict comparison.
|
|
42
|
-
*/
|
|
43
|
-
export declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Create a custom equality comparison method.
|
|
46
|
-
*
|
|
47
|
-
* This can be done to create very targeted comparisons in extreme hot-path scenarios
|
|
48
|
-
* where the standard methods are not performant enough, but can also be used to provide
|
|
49
|
-
* support for legacy environments that cannot polyfill for modern features expected by
|
|
50
|
-
* \`fast-equals\`, such as \`WeakMap\` or \`RegExp.prototype.flags\`.
|
|
51
|
-
*/
|
|
52
|
-
export declare function createCustomEqual<Meta = undefined>(
|
|
53
|
-
options?: CustomEqualCreatorOptions<Meta>,
|
|
54
|
-
): <A, B>(a: A, b: B) => boolean;
|
|
55
|
-
`;
|
|
56
|
-
|
|
57
|
-
const INTERNAL_TYPES = fs.readFileSync(
|
|
58
|
-
path.join(import.meta.dirname, '..', 'src', 'internalTypes.ts'),
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const OUTPUT = `${INTERNAL_TYPES}\n${METHODS}`.trim();
|
|
62
|
-
const OUTPUT_DESTINATION = path.join(import.meta.dirname, '..', 'index.d.ts');
|
|
63
|
-
|
|
64
|
-
fs.writeFileSync(OUTPUT_DESTINATION, OUTPUT, 'utf-8');
|