fast-equals 4.0.3 → 5.0.0-beta.1

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.
Files changed (71) hide show
  1. package/.babelrc +34 -0
  2. package/.prettierrc +4 -0
  3. package/CHANGELOG.md +39 -0
  4. package/README.md +146 -39
  5. package/build/rollup/config.base.js +49 -0
  6. package/build/rollup/config.cjs.js +10 -0
  7. package/build/rollup/config.esm.js +10 -0
  8. package/build/rollup/config.min.js +13 -0
  9. package/build/rollup/config.umd.js +10 -0
  10. package/build/tsconfig/base.json +32 -0
  11. package/build/tsconfig/cjs.json +8 -0
  12. package/build/tsconfig/declarations.json +9 -0
  13. package/build/tsconfig/esm.json +8 -0
  14. package/build/tsconfig/min.json +8 -0
  15. package/build/tsconfig/umd.json +8 -0
  16. package/build/webpack.config.js +57 -0
  17. package/dist/cjs/index.cjs +510 -0
  18. package/dist/cjs/index.cjs.map +1 -0
  19. package/dist/cjs/types/comparator.d.ts +2 -0
  20. package/dist/cjs/types/equals.d.ts +46 -0
  21. package/dist/cjs/types/index.d.ts +56 -0
  22. package/dist/cjs/types/internalTypes.d.ts +36 -0
  23. package/dist/cjs/types/utils.d.ts +19 -0
  24. package/dist/esm/index.mjs +499 -0
  25. package/dist/esm/index.mjs.map +1 -0
  26. package/dist/esm/types/comparator.d.ts +2 -0
  27. package/dist/esm/types/equals.d.ts +46 -0
  28. package/dist/esm/types/index.d.ts +56 -0
  29. package/dist/esm/types/internalTypes.d.ts +36 -0
  30. package/dist/esm/types/utils.d.ts +19 -0
  31. package/dist/min/index.js +1 -0
  32. package/dist/min/types/comparator.d.ts +2 -0
  33. package/dist/min/types/equals.d.ts +46 -0
  34. package/dist/min/types/index.d.ts +56 -0
  35. package/dist/min/types/internalTypes.d.ts +36 -0
  36. package/dist/min/types/utils.d.ts +19 -0
  37. package/dist/umd/index.js +516 -0
  38. package/dist/umd/index.js.map +1 -0
  39. package/dist/umd/types/comparator.d.ts +2 -0
  40. package/dist/umd/types/equals.d.ts +46 -0
  41. package/dist/umd/types/index.d.ts +56 -0
  42. package/dist/umd/types/internalTypes.d.ts +36 -0
  43. package/dist/umd/types/utils.d.ts +19 -0
  44. package/index.d.ts +62 -55
  45. package/package.json +59 -38
  46. package/recipes/explicit-property-check.md +4 -6
  47. package/recipes/legacy-circular-equal-support.md +28 -20
  48. package/recipes/legacy-regexp-support.md +15 -16
  49. package/recipes/non-standard-properties.md +35 -23
  50. package/recipes/using-meta-in-comparison.md +10 -13
  51. package/src/comparator.ts +43 -40
  52. package/src/equals.ts +263 -0
  53. package/src/index.ts +183 -79
  54. package/src/internalTypes.ts +74 -0
  55. package/src/utils.ts +42 -49
  56. package/dist/fast-equals.cjs.js +0 -432
  57. package/dist/fast-equals.cjs.js.map +0 -1
  58. package/dist/fast-equals.esm.js +0 -422
  59. package/dist/fast-equals.esm.js.map +0 -1
  60. package/dist/fast-equals.js +0 -438
  61. package/dist/fast-equals.js.map +0 -1
  62. package/dist/fast-equals.min.js +0 -1
  63. package/dist/fast-equals.mjs +0 -422
  64. package/dist/fast-equals.mjs.map +0 -1
  65. package/recipes/strict-property-descriptor-check.md +0 -42
  66. package/src/arrays.ts +0 -36
  67. package/src/dates.ts +0 -12
  68. package/src/maps.ts +0 -66
  69. package/src/objects.ts +0 -62
  70. package/src/regexps.ts +0 -11
  71. package/src/sets.ts +0 -61
@@ -0,0 +1,56 @@
1
+ import type { CreateCustomComparatorConfig, CreateState, EqualityComparator } from './internalTypes';
2
+ import { createInternalComparator, sameValueZeroEqual } from './utils';
3
+ export { sameValueZeroEqual };
4
+ interface DefaultEqualCreatorOptions<Meta> {
5
+ comparator?: EqualityComparator<Meta>;
6
+ circular?: boolean;
7
+ strict?: boolean;
8
+ }
9
+ interface CustomEqualCreatorOptions<Meta> extends DefaultEqualCreatorOptions<Meta> {
10
+ createCustomConfig?: CreateCustomComparatorConfig<Meta>;
11
+ createInternalComparator?: typeof createInternalComparator;
12
+ createState?: CreateState<Meta>;
13
+ }
14
+ /**
15
+ * Whether the items passed are deeply-equal in value.
16
+ */
17
+ export declare const deepEqual: <A, B>(a: A, b: B) => boolean;
18
+ /**
19
+ * Whether the items passed are deeply-equal in value based on strict comparison.
20
+ */
21
+ export declare const strictDeepEqual: <A, B>(a: A, b: B) => boolean;
22
+ /**
23
+ * Whether the items passed are deeply-equal in value, including circular references.
24
+ */
25
+ export declare const circularDeepEqual: <A, B>(a: A, b: B) => boolean;
26
+ /**
27
+ * Whether the items passed are deeply-equal in value, including circular references,
28
+ * based on strict comparison.
29
+ */
30
+ export declare const strictCircularDeepEqual: <A, B>(a: A, b: B) => boolean;
31
+ /**
32
+ * Whether the items passed are shallowly-equal in value.
33
+ */
34
+ export declare const shallowEqual: <A, B>(a: A, b: B) => boolean;
35
+ /**
36
+ * Whether the items passed are shallowly-equal in value based on strict comparison
37
+ */
38
+ export declare const strictShallowEqual: <A, B>(a: A, b: B) => boolean;
39
+ /**
40
+ * Whether the items passed are shallowly-equal in value, including circular references.
41
+ */
42
+ export declare const circularShallowEqual: <A, B>(a: A, b: B) => boolean;
43
+ /**
44
+ * Whether the items passed are shallowly-equal in value, including circular references,
45
+ * based on strict comparison.
46
+ */
47
+ export declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
48
+ /**
49
+ * Create a custom equality comparison method.
50
+ *
51
+ * This can be done to create very targeted comparisons in extreme hot-path scenarios
52
+ * where the standard methods are not performant enough, but can also be used to provide
53
+ * support for legacy environments that do not support expected features like
54
+ * `RegExp.prototype.flags` out of the box.
55
+ */
56
+ export declare function createCustomEqual<Meta>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B, metaOverride?: Meta) => boolean;
@@ -0,0 +1,36 @@
1
+ export interface BaseCircular extends Pick<WeakMap<any, any>, 'delete' | 'get'> {
2
+ set(key: object, value: any): any;
3
+ }
4
+ export type State<Meta> = CircularState<Meta> | DefaultState<Meta>;
5
+ export interface CircularState<Meta> {
6
+ readonly cache: BaseCircular;
7
+ readonly equals: InternalEqualityComparator<Meta>;
8
+ meta: Meta;
9
+ readonly strict: boolean;
10
+ }
11
+ export interface DefaultState<Meta> {
12
+ readonly cache: undefined;
13
+ readonly equals: InternalEqualityComparator<Meta>;
14
+ meta: Meta;
15
+ readonly strict: boolean;
16
+ }
17
+ export interface Dictionary<Value = any> {
18
+ [key: string | symbol]: Value;
19
+ $$typeof?: any;
20
+ }
21
+ export interface ComparatorConfig<Meta> {
22
+ areArraysEqual: TypeEqualityComparator<any, Meta>;
23
+ areDatesEqual: TypeEqualityComparator<any, Meta>;
24
+ areMapsEqual: TypeEqualityComparator<any, Meta>;
25
+ areObjectsEqual: TypeEqualityComparator<any, Meta>;
26
+ arePrimitiveWrappersEqual: TypeEqualityComparator<any, Meta>;
27
+ areRegExpsEqual: TypeEqualityComparator<any, Meta>;
28
+ areSetsEqual: TypeEqualityComparator<any, Meta>;
29
+ }
30
+ export type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
31
+ export type CreateState<Meta> = (comparator: EqualityComparator<Meta>) => Partial<State<Meta>>;
32
+ export type EqualityComparator<Meta> = <A, B>(a: A, b: B, state: State<Meta>) => boolean;
33
+ export type AnyEqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
34
+ export type EqualityComparatorCreator<Meta> = (fn: EqualityComparator<Meta>) => InternalEqualityComparator<Meta>;
35
+ export type InternalEqualityComparator<Meta> = (a: any, b: any, indexOrKeyA: any, indexOrKeyB: any, parentA: any, parentB: any, state: State<Meta>) => boolean;
36
+ export type TypeEqualityComparator<Type, Meta = undefined> = (a: Type, b: Type, state: State<Meta>) => boolean;
@@ -0,0 +1,19 @@
1
+ import { AnyEqualityComparator, Dictionary, EqualityComparator, InternalEqualityComparator, State, TypeEqualityComparator } from './internalTypes';
2
+ export declare function combineComparators<Meta>(comparatorA: AnyEqualityComparator<Meta>, comparatorB: AnyEqualityComparator<Meta>): <A, B>(a: A, b: B, state: State<Meta>) => boolean;
3
+ /**
4
+ * Default equality comparator pass-through, used as the standard `isEqual` creator for
5
+ * use inside the built comparator.
6
+ */
7
+ export declare function createInternalComparator<Meta>(compare: EqualityComparator<Meta>): InternalEqualityComparator<Meta>;
8
+ /**
9
+ * Wrap the provided `areItemsEqual` method to manage the circular state, allowing
10
+ * for circular references to be safely included in the comparison without creating
11
+ * stack overflows.
12
+ */
13
+ export declare function createIsCircular<AreItemsEqual extends TypeEqualityComparator<any, any>>(areItemsEqual: AreItemsEqual): AreItemsEqual;
14
+ export declare function getStrictProperties(object: Dictionary): Array<string | symbol>;
15
+ export declare const hasOwn: (o: object, v: PropertyKey) => boolean;
16
+ /**
17
+ * Whether the values passed are strictly equal or both NaN.
18
+ */
19
+ export declare function sameValueZeroEqual(a: any, b: any): boolean;
package/index.d.ts CHANGED
@@ -1,58 +1,65 @@
1
- export interface BaseCircularMeta
2
- extends Pick<WeakMap<any, any>, 'delete' | 'get'> {
3
- set(key: object, value: any): any;
4
- }
1
+ import type {
2
+ CreateCustomComparatorConfig,
3
+ CreateState,
4
+ EqualityComparator,
5
+ } from './src/internalTypes';
6
+ import { createInternalComparator, sameValueZeroEqual } from './src/utils';
7
+ export { sameValueZeroEqual };
5
8
 
6
- export interface CreateComparatorCreatorOptions<Meta> {
7
- areArraysEqual: TypeEqualityComparator<any, Meta>;
8
- areDatesEqual: TypeEqualityComparator<any, Meta>;
9
- areMapsEqual: TypeEqualityComparator<any, Meta>;
10
- areObjectsEqual: TypeEqualityComparator<any, Meta>;
11
- areRegExpsEqual: TypeEqualityComparator<any, Meta>;
12
- areSetsEqual: TypeEqualityComparator<any, Meta>;
13
- createIsNestedEqual: EqualityComparatorCreator<Meta>;
9
+ interface DefaultEqualCreatorOptions<Meta> {
10
+ comparator?: EqualityComparator<Meta>;
11
+ circular?: boolean;
12
+ strict?: boolean;
13
+ }
14
+ interface CustomEqualCreatorOptions<Meta>
15
+ extends DefaultEqualCreatorOptions<Meta> {
16
+ createCustomConfig?: CreateCustomComparatorConfig<Meta>;
17
+ createInternalComparator?: typeof createInternalComparator;
18
+ createState?: CreateState<Meta>;
14
19
  }
15
20
 
16
- export type GetComparatorOptions<Meta> = (
17
- defaultOptions: CreateComparatorCreatorOptions<Meta>,
18
- ) => Partial<CreateComparatorCreatorOptions<Meta>>;
19
-
20
- export type InternalEqualityComparator<Meta> = (
21
- a: any,
22
- b: any,
23
- indexOrKeyA: any,
24
- indexOrKeyB: any,
25
- parentA: any,
26
- parentB: any,
27
- meta: Meta,
28
- ) => boolean;
29
-
30
- export type EqualityComparator<Meta> = Meta extends undefined
31
- ? <A, B>(a: A, b: B, meta?: Meta) => boolean
32
- : <A, B>(a: A, b: B, meta: Meta) => boolean;
33
-
34
- export type EqualityComparatorCreator<Meta> = (
35
- fn: EqualityComparator<Meta>,
36
- ) => InternalEqualityComparator<Meta>;
37
-
38
- export type NativeEqualityComparator = <A, B>(a: A, b: B) => boolean;
39
-
40
- export type TypeEqualityComparator<Type, Meta> = (
41
- a: Type,
42
- b: Type,
43
- isEqual: InternalEqualityComparator<Meta>,
44
- meta: Meta,
45
- ) => boolean;
46
-
47
- export function circularDeepEqual<A, B>(a: A, b: B): boolean;
48
- export function circularShallowEqual<A, B>(a: A, b: B): boolean;
49
- export function deepEqual<A, B>(a: A, b: B): boolean;
50
- export function shallowEqual<A, B>(a: A, b: B): boolean;
51
- export function sameValueZeroEqual<A, B>(a: A, b: B): boolean;
52
-
53
- export function createCustomEqual<Meta = undefined>(
54
- getComparatorOptions: GetComparatorOptions<Meta>,
55
- ): EqualityComparator<Meta>;
56
- export function createCustomCircularEqual<Meta = WeakMap<any, any>>(
57
- getComparatorOptions: GetComparatorOptions<Meta>,
58
- ): EqualityComparator<Meta>;
21
+ /**
22
+ * Whether the items passed are deeply-equal in value.
23
+ */
24
+ export declare const deepEqual: <A, B>(a: A, b: B) => boolean;
25
+ /**
26
+ * Whether the items passed are deeply-equal in value based on strict comparison.
27
+ */
28
+ export declare const strictDeepEqual: <A, B>(a: A, b: B) => boolean;
29
+ /**
30
+ * Whether the items passed are deeply-equal in value, including circular references.
31
+ */
32
+ export declare const circularDeepEqual: <A, B>(a: A, b: B) => boolean;
33
+ /**
34
+ * Whether the items passed are deeply-equal in value, including circular references,
35
+ * based on strict comparison.
36
+ */
37
+ export declare const strictCircularDeepEqual: <A, B>(a: A, b: B) => boolean;
38
+ /**
39
+ * Whether the items passed are shallowly-equal in value.
40
+ */
41
+ export declare const shallowEqual: <A, B>(a: A, b: B) => boolean;
42
+ /**
43
+ * Whether the items passed are shallowly-equal in value based on strict comparison
44
+ */
45
+ export declare const strictShallowEqual: <A, B>(a: A, b: B) => boolean;
46
+ /**
47
+ * Whether the items passed are shallowly-equal in value, including circular references.
48
+ */
49
+ export declare const circularShallowEqual: <A, B>(a: A, b: B) => boolean;
50
+ /**
51
+ * Whether the items passed are shallowly-equal in value, including circular references,
52
+ * based on strict comparison.
53
+ */
54
+ export declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
55
+ /**
56
+ * Create a custom equality comparison method.
57
+ *
58
+ * This can be done to create very targeted comparisons in extreme hot-path scenarios
59
+ * where the standard methods are not performant enough, but can also be used to provide
60
+ * support for legacy environments that do not support expected features like
61
+ * `RegExp.prototype.flags` out of the box.
62
+ */
63
+ export declare function createCustomEqual<Meta>(
64
+ options?: CustomEqualCreatorOptions<Meta>,
65
+ ): <A, B>(a: A, b: B, metaOverride?: Meta) => boolean;
package/package.json CHANGED
@@ -1,53 +1,69 @@
1
1
  {
2
2
  "author": "tony_quetano@planttheidea.com",
3
- "browser": "dist/fast-equals.js",
3
+ "browser": "dist/umd/index.js",
4
4
  "bugs": {
5
5
  "url": "https://github.com/planttheidea/fast-equals/issues"
6
6
  },
7
7
  "description": "A blazing fast equality comparison, either shallow or deep",
8
8
  "devDependencies": {
9
- "@rollup/plugin-node-resolve": "^13.1.3",
10
- "@types/jest": "^28.1.8",
9
+ "@rollup/plugin-commonjs": "^24.0.0",
10
+ "@rollup/plugin-node-resolve": "^15.0.1",
11
+ "@rollup/plugin-replace": "^5.0.2",
12
+ "@rollup/plugin-terser": "^0.4.0",
13
+ "@rollup/plugin-typescript": "^11.0.0",
14
+ "@types/jest": "^29.2.5",
11
15
  "@types/lodash": "^4.14.184",
12
- "@types/node": "^18.7.13",
13
- "@types/ramda": "^0.28.15",
14
- "@types/react": "^18.0.17",
15
- "@typescript-eslint/eslint-plugin": "^5.35.1",
16
- "@typescript-eslint/parser": "^5.35.1",
17
- "benchee": "^1.1.0",
18
- "cli-table3": "^0.6.1",
16
+ "@types/node": "^18.14.0",
17
+ "@types/ramda": "^0.28.23",
18
+ "@types/react": "^18.0.28",
19
+ "@types/react-dom": "^18.0.11",
20
+ "@typescript-eslint/eslint-plugin": "^5.52.0",
21
+ "@typescript-eslint/parser": "^5.52.0",
19
22
  "decircularize": "^1.0.0",
20
23
  "deep-eql": "^4.1.0",
21
24
  "deep-equal": "^2.0.5",
22
- "eslint": "^8.22.0",
23
- "eslint-config-airbnb": "^19.0.4",
24
- "eslint-plugin-import": "^2.25.4",
25
- "eslint-plugin-jsx-a11y": "^6.6.1",
26
- "eslint-plugin-react": "^7.31.0",
27
- "eslint-webpack-plugin": "^3.2.0",
25
+ "eslint": "^8.34.0",
26
+ "eslint-friendly-formatter": "^4.0.1",
27
+ "eslint-webpack-plugin": "^4.0.0",
28
28
  "fast-deep-equal": "^3.1.3",
29
- "fs-extra": "^10.0.0",
30
29
  "html-webpack-plugin": "^5.5.0",
31
30
  "in-publish": "^2.0.0",
32
- "jest": "^28.1.3",
31
+ "jest": "^29.4.3",
32
+ "jest-environment-jsdom": "^29.4.3",
33
+ "jest-expect-message": "^1.1.3",
33
34
  "lodash": "^4.17.21",
34
35
  "nano-equal": "^2.0.2",
35
- "prettier": "^2.7.1",
36
+ "prettier": "^2.8.4",
36
37
  "react": "^18.2.0",
37
38
  "react-dom": "^18.2.0",
38
39
  "react-fast-compare": "^3.2.0",
39
- "release-it": "^15.4.0",
40
- "rollup": "^2.78.1",
41
- "rollup-plugin-terser": "^7.0.2",
42
- "rollup-plugin-typescript2": "^0.33.0",
40
+ "release-it": "^15.6.0",
41
+ "rollup": "^3.16.0",
43
42
  "shallow-equal-fuzzy": "^0.0.2",
44
- "ts-jest": "^28.0.8",
45
- "ts-loader": "^9.3.1",
46
- "typescript": "^4.7.4",
43
+ "tinybench": "^2.3.1",
44
+ "ts-jest": "^29.0.3",
45
+ "ts-loader": "^9.4.2",
46
+ "typescript": "^4.9.5",
47
47
  "underscore": "^1.13.4",
48
- "webpack": "^5.74.0",
49
- "webpack-cli": "^4.10.0",
50
- "webpack-dev-server": "^4.10.0"
48
+ "webpack": "^5.75.0",
49
+ "webpack-cli": "^5.0.1",
50
+ "webpack-dev-server": "^4.11.1"
51
+ },
52
+ "exports": {
53
+ ".": {
54
+ "import": {
55
+ "types": "./dist/esm/types/index.d.ts",
56
+ "default": "./dist/esm/index.mjs"
57
+ },
58
+ "require": {
59
+ "types": "./dist/cjs/types/index.d.ts",
60
+ "default": "./dist/cjs/index.cjs"
61
+ },
62
+ "default": {
63
+ "types": "./dist/umd/types/index.d.ts",
64
+ "default": "./dist/umd/index.js"
65
+ }
66
+ }
51
67
  },
52
68
  "homepage": "https://github.com/planttheidea/fast-equals#readme",
53
69
  "keywords": [
@@ -58,32 +74,37 @@
58
74
  "equivalent"
59
75
  ],
60
76
  "license": "MIT",
61
- "main": "dist/fast-equals.cjs.js",
62
- "module": "dist/fast-equals.esm.js",
77
+ "main": "dist/cjs/index.cjs",
78
+ "module": "dist/esm/index.mjs",
63
79
  "name": "fast-equals",
64
80
  "repository": {
65
81
  "type": "git",
66
82
  "url": "git+https://github.com/planttheidea/fast-equals.git"
67
83
  },
68
84
  "scripts": {
69
- "benchmark": "npm run dist && node benchmark/index.js",
70
- "build": "NODE_ENV=production rollup -c",
71
- "dev": "NODE_ENV=development webpack serve --progress --config=webpack/webpack.config.js",
85
+ "benchmark": "npm run build:esm && node benchmark/index.js",
86
+ "build": "npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:min",
87
+ "build:cjs": "rimraf dist/cjs && NODE_ENV=production rollup -c build/rollup/config.cjs.js && tsc -p ./build/tsconfig/cjs.json",
88
+ "build:esm": "rimraf dist/esm && NODE_ENV=production rollup -c build/rollup/config.esm.js && tsc -p ./build/tsconfig/esm.json",
89
+ "build:min": "rimraf dist/min && NODE_ENV=production rollup -c build/rollup/config.min.js && tsc -p ./build/tsconfig/min.json",
90
+ "build:umd": "rimraf dist/umd && NODE_ENV=production rollup -c build/rollup/config.umd.js && tsc -p ./build/tsconfig/umd.json",
91
+ "dev": "NODE_ENV=development webpack serve --progress --config=build/webpack.config.js",
72
92
  "dist": "rimraf dist && npm run build",
73
93
  "format": "prettier **/*.ts --write",
74
94
  "lint": "eslint src/*.ts",
75
95
  "lint:fix": "npm run lint -- --fix",
76
96
  "start": "npm run dev",
77
97
  "prepublish": "if in-publish; then npm run prepublish:compile; fi",
78
- "prepublish:compile": "npm run typecheck && npm run lint && npm run test && npm run dist",
79
98
  "release": "release-it",
80
99
  "release:beta": "release-it --config=.release-it.beta.json",
100
+ "release:scripts": "npm run typecheck && npm run lint && npm run test && npm run dist",
81
101
  "test": "NODE_PATH=. jest",
82
- "test:coverage": "npm test -- --coverage",
102
+ "test:coverage": "rimraf coverage && npm test -- --coverage",
83
103
  "test:watch": "npm test -- --watch",
84
104
  "typecheck": "tsc --noEmit"
85
105
  },
86
106
  "sideEffects": false,
87
- "types": "index.d.ts",
88
- "version": "4.0.3"
107
+ "type": "module",
108
+ "types": "./index.d.ts",
109
+ "version": "5.0.0-beta.1"
89
110
  }
@@ -18,11 +18,9 @@ interface SpecialObject {
18
18
  const areObjectsEqual: TypeEqualityComparator<SpecialObject, undefined> = (
19
19
  a,
20
20
  b,
21
- ) => {
22
- return a.foo === b.foo && a.bar.baz === b.bar.baz;
23
- };
21
+ ) => a.foo === b.foo && a.bar.baz === b.bar.baz;
24
22
 
25
- const isSpecialObjectEqual = createCustomEqual(() => ({
26
- areObjectsEqual,
27
- }));
23
+ const isSpecialObjectEqual = createCustomEqual({
24
+ createCustomConfig: () => ({ areObjectsEqual }),
25
+ });
28
26
  ```
@@ -3,14 +3,9 @@
3
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, creating a custom comparator that uses a custom cache implementation with the same contract is a simple solution.
4
4
 
5
5
  ```ts
6
- import { createCustomEqual, sameValueZeroEqual } from 'deep-Equals';
6
+ import { createCustomEqual, sameValueZeroEqual } from 'fast-equals';
7
7
 
8
- interface Cache extends BaseCircularMeta {
9
- customMethod(): void;
10
- customValue: string;
11
- }
12
-
13
- function getCache(): Cache {
8
+ function getCache(): BaseCircular {
14
9
  const entries: Array<[object, any]> = [];
15
10
 
16
11
  return {
@@ -45,22 +40,35 @@ function getCache(): Cache {
45
40
 
46
41
  return this;
47
42
  },
48
-
49
- customMethod() {
50
- console.log('hello!');
51
- },
52
- customValue: 'goodbye',
53
43
  };
54
44
  }
55
45
 
56
- const customDeepCircularHandler = createCustomCircularEqual<Cache>(() => ({}));
46
+ interface Meta {
47
+ customMethod(): void;
48
+ customValue: string;
49
+ }
50
+
51
+ const meta = {
52
+ customMethod() {
53
+ console.log('hello!');
54
+ },
55
+ customValue: 'goodbye',
56
+ };
57
57
 
58
- const customDeepCircularHandler = createCustomCircularEqual<Cache>(() => ({
59
- createIsNestedEqual: () => sameValueZeroEqual,
60
- }));
58
+ const circularDeepEqual = createCustomEqual<Cache>({
59
+ circular: true,
60
+ createState: () => ({
61
+ cache: getCache(),
62
+ meta,
63
+ }),
64
+ });
61
65
 
62
- const circularDeepEqual = <A, B>(a: A, b: B) =>
63
- customDeepCircularHandler(a, b, getCache());
64
- const circularShallowEqual = <A, B>(a: A, b: B) =>
65
- customShallowCircularHandler(a, b, getCache());
66
+ const circularShallowEqual = createCustomEqual<Cache>({
67
+ circular: true,
68
+ comparator: sameValueZeroEqual,
69
+ createState: () => ({
70
+ cache: getCache(),
71
+ meta,
72
+ }),
73
+ });
66
74
  ```
@@ -6,21 +6,20 @@ Starting in `4.x.x`, `RegExp.prototype.flags` is expected to be available in the
6
6
  import { createCustomEqual, sameValueZeroEqual } from 'deep-Equals';
7
7
  import type { TypeEqualityComparator } from 'fast-equals';
8
8
 
9
- const areRegExpsEqual: TypeEqualityComparator<RegExp, undefined> = (a, b) => {
10
- return (
11
- a.source === b.source &&
12
- a.global === b.global &&
13
- a.ignoreCase === b.ignoreCase &&
14
- a.multiline === b.multiline &&
15
- a.unicode === b.unicode &&
16
- a.sticky === b.sticky &&
17
- a.lastIndex === b.lastIndex
18
- );
19
- };
9
+ const areRegExpsEqual: TypeEqualityComparator<RegExp, undefined> = (a, b) =>
10
+ a.source === b.source &&
11
+ a.global === b.global &&
12
+ a.ignoreCase === b.ignoreCase &&
13
+ a.multiline === b.multiline &&
14
+ a.unicode === b.unicode &&
15
+ a.sticky === b.sticky &&
16
+ a.lastIndex === b.lastIndex;
20
17
 
21
- const deepEqual = createCustomEqual(() => ({ areRegExpsEqual }));
22
- const shallowEqual = createCustomEqual(() => ({
23
- areRegExpsEqual,
24
- createIsNestedEqual: () => sameValueZeroEqual,
25
- }));
18
+ const deepEqual = createCustomEqual({
19
+ createCustomConfig: () => ({ areRegExpsEqual }),
20
+ });
21
+ const shallowEqual = createCustomEqual({
22
+ comparator: sameValueZero,
23
+ createCustomConfig: () => ({ areRegExpsEqual }),
24
+ });
26
25
  ```
@@ -1,34 +1,46 @@
1
1
  # Non-standard properties
2
2
 
3
- Sometimes, objects require a comparison that extend beyond its own keys. Perhaps there is a non-enumerable property that is important, or perhaps there are symbols as keys. In this case, the standard validators will return false positives, because internally `fast-equals` uses `Object.keys()` for object comparisons.
4
-
5
- Using a custom object comparator with `createCustomEqual` allows these kinds of comparisons.
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.
6
4
 
7
5
  ```ts
8
6
  import { createCustomEqual } from 'fast-equals';
9
7
  import type { TypeEqualityComparator } from 'fast-equals';
10
8
 
11
- const areObjectsEqual: TypeEqualityComparator<Record<any, any>, undefined> = (
12
- a,
13
- b,
14
- ) => {
15
- const propertiesA = [
16
- ...Object.getOwnPropertyNames(a),
17
- ...Object.getOwnPropertySymbols(a),
18
- ];
19
- const propertiesB = [
20
- ...Object.getOwnPropertyNames(b),
21
- ...Object.getOwnPropertySymbols(b),
22
- ];
23
-
24
- if (propertiesA.length !== propertiesB.length) {
25
- return false;
9
+ class HiddenProperty {
10
+ visible: boolean;
11
+ #hidden: string;
12
+
13
+ constructor(value: string) {
14
+ this.visible = true;
15
+ this.#hidden = value;
16
+ }
17
+
18
+ get hidden() {
19
+ return this.#hidden;
26
20
  }
21
+ }
22
+
23
+ function createAreObjectsEqual(
24
+ areObjectsEqual: TypeEqualityComparator<Record<any, any>, undefined>,
25
+ ): TypeEqualityComparator<Record<any, any>, undefined> {
26
+ return function (a, b, state) {
27
+ if (!areObjectsEqual(a, b, state)) {
28
+ return false;
29
+ }
30
+
31
+ const aInstance = a instanceof HiddenProperty;
32
+ const bInstance = b instanceof HiddenProperty;
33
+
34
+ if (aInstance || bInstance) {
35
+ return aInstance && bInstance && a.hidden === b.hidden;
36
+ }
27
37
 
28
- return propertiesA.every(
29
- (property) => a[property as any] === b[property as any],
30
- );
31
- };
38
+ return true;
39
+ };
40
+ }
32
41
 
33
- const deepEqual = createCustomEqual(() => ({ areObjectsEqual }));
42
+ const deepEqual = createCustomEqual({
43
+ createCustomConfig: ({ areObjectsEqual }) =>
44
+ createAreObjectsEqual(areObjectsEqual),
45
+ });
34
46
  ```
@@ -1,23 +1,20 @@
1
1
  # Using `meta` in comparison
2
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 comparator that checks `meta` values.
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
4
 
5
5
  ```ts
6
6
  import { createCustomEqual } from 'fast-equals';
7
- import type {
8
- EqualityComparator,
9
- InternalEqualityComparator,
10
- } from 'fast-equals';
11
7
 
12
- interface MutableState {
13
- state: string;
8
+ interface Meta {
9
+ value: string;
14
10
  }
15
11
 
16
- const mutableState: MutableState = { state: 'baz' };
12
+ const meta: Meta = { value: 'baz' };
17
13
 
18
- const createIsNestedEqual: EqualityComparatorCreator<MutableState> =
19
- (deepEqual) => (a, b, keyA, keyB, parentA, parentB, meta) =>
20
- deepEqual(a, b, meta) || a === meta.state || b === meta.state;
21
-
22
- const deepEqual = createCustomEqual(() => ({ createIsNestedEqual }));
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
+ });
23
20
  ```