From 832f4b5313bfa90316c1117e683efa0f974628ee Mon Sep 17 00:00:00 2001 From: Tony Quetano Date: Mon, 6 Jan 2025 18:41:16 -0500 Subject: [PATCH] build flattened internal types instead of importing --- index.d.ts | 224 +++++++++++++++++++++++++++++++++---- package.json | 3 +- scripts/fallback-types.mjs | 64 +++++++++++ 3 files changed, 269 insertions(+), 22 deletions(-) create mode 100644 scripts/fallback-types.mjs diff --git a/index.d.ts b/index.d.ts index 7421fc6..3debc1d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,23 +1,205 @@ -import type { CustomEqualCreatorOptions } from './src/internalTypes'; - -export type { - AnyEqualityComparator, - Cache, - CircularState, - ComparatorConfig, - CreateCustomComparatorConfig, - CreateState, - CustomEqualCreatorOptions, - DefaultState, - Dictionary, - EqualityComparator, - EqualityComparatorCreator, - InternalEqualityComparator, - PrimitiveWrapper, - State, - TypeEqualityComparator, - TypedArray, -} from './src/internalTypes'; +/** + * Cache used to store references to objects, used for circular + * reference checks. + */ +export interface Cache { + delete(key: Key): boolean; + get(key: Key): Value | undefined; + set(key: Key, value: any): any; +} + +export interface State { + /** + * Cache used to identify circular references + */ + readonly cache: Cache | undefined; + /** + * Method used to determine equality of nested value. + */ + readonly equals: InternalEqualityComparator; + /** + * Additional value that can be used for comparisons. + */ + meta: Meta; + /** + * Whether the equality comparison is strict, meaning it matches + * all properties (including symbols and non-enumerable properties) + * with equal shape of descriptors. + */ + readonly strict: boolean; +} + +export interface CircularState extends State { + readonly cache: Cache; +} + +export interface DefaultState extends State { + readonly cache: undefined; +} + +export interface Dictionary { + [key: string | symbol]: Value; + $$typeof?: any; +} + +export interface ComparatorConfig { + /** + * Whether the arrays passed are equal in value. In strict mode, this includes + * additional properties added to the array. + */ + areArraysEqual: TypeEqualityComparator; + /** + * Whether the dates passed are equal in value. + */ + areDatesEqual: TypeEqualityComparator; + /** + * Whether the errors passed are equal in value. + */ + areErrorsEqual: TypeEqualityComparator; + /** + * Whether the functions passed are equal in value. + */ + areFunctionsEqual: TypeEqualityComparator; + /** + * Whether the maps passed are equal in value. In strict mode, this includes + * additional properties added to the map. + */ + areMapsEqual: TypeEqualityComparator; + /** + * Whether the numbers passed are equal in value. + */ + areNumbersEqual: TypeEqualityComparator; + /** + * Whether the objects passed are equal in value. In strict mode, this includes + * non-enumerable properties added to the map, as well as symbol properties. + */ + areObjectsEqual: TypeEqualityComparator; + /** + * Whether the primitive wrappers passed are equal in value. + */ + arePrimitiveWrappersEqual: TypeEqualityComparator; + /** + * Whether the regexps passed are equal in value. + */ + areRegExpsEqual: TypeEqualityComparator; + /** + * Whether the sets passed are equal in value. In strict mode, this includes + * additional properties added to the set. + */ + areSetsEqual: TypeEqualityComparator; + /** + * Whether the typed arrays passed are equal in value. In strict mode, this includes + * additional properties added to the typed array. + */ + areTypedArraysEqual: TypeEqualityComparator; + /** + * Whether the URLs passed are equal in value. + */ + areUrlsEqual: TypeEqualityComparator; +} + +export type CreateCustomComparatorConfig = ( + config: ComparatorConfig, +) => Partial>; + +export type CreateState = () => { + cache?: Cache | undefined; + meta?: Meta; +}; + +export type EqualityComparator = ( + a: A, + b: B, + state: State, +) => boolean; +export type AnyEqualityComparator = ( + a: any, + b: any, + state: State, +) => boolean; + +export type EqualityComparatorCreator = ( + fn: EqualityComparator, +) => InternalEqualityComparator; + +export type InternalEqualityComparator = ( + a: any, + b: any, + indexOrKeyA: any, + indexOrKeyB: any, + parentA: any, + parentB: any, + state: State, +) => boolean; + +// We explicitly check for primitive wrapper types +// eslint-disable-next-line @typescript-eslint/ban-types +export type PrimitiveWrapper = Boolean | Number | String; + +/** + * Type which encompasses possible instances of TypedArray + * classes. + * + * **NOTE**: This does not include `BigInt64Array` and + * `BitUint64Array` because those are part of ES2020 and + * not supported by certain TS configurations. If using + * either in `areTypedArraysEqual`, you can cast the + * instance as `TypedArray` and it will work as expected, + * because runtime checks will still work for those classes. + */ +export type TypedArray = + | Float32Array + | Float64Array + | Int8Array + | Int16Array + | Int32Array + | Uint16Array + | Uint32Array + | Uint8Array + | Uint8ClampedArray; + +export type TypeEqualityComparator = ( + a: Type, + b: Type, + state: State, +) => boolean; + +export interface CustomEqualCreatorOptions { + /** + * Whether circular references should be supported. It causes the + * comparison to be slower, but for objects that have circular references + * it is required to avoid stack overflows. + */ + circular?: boolean; + /** + * Create a custom configuration of type-specific equality comparators. + * This receives the default configuration, which allows either replacement + * or supersetting of the default methods. + */ + createCustomConfig?: CreateCustomComparatorConfig; + /** + * Create a custom internal comparator, which is used as an override to the + * default entry point for nested value equality comparisons. This is often + * used for doing custom logic for specific types (such as handling a specific + * class instance differently than other objects) or to incorporate `meta` in + * the comparison. See the recipes for examples. + */ + createInternalComparator?: ( + compare: EqualityComparator, + ) => InternalEqualityComparator; + /** + * Create a custom `state` object passed between the methods. This allows for + * custom `cache` and/or `meta` values to be used. + */ + createState?: CreateState; + /** + * Whether the equality comparison is strict, meaning it matches + * all properties (including symbols and non-enumerable properties) + * with equal shape of descriptors. + */ + strict?: boolean; +} + /** * Whether the values passed are strictly equal or both NaN. @@ -68,4 +250,4 @@ export declare const strictCircularShallowEqual: (a: A, b: B) => boolean; */ export declare function createCustomEqual( options?: CustomEqualCreatorOptions, -): (a: A, b: B) => boolean; +): (a: A, b: B) => boolean; \ No newline at end of file diff --git a/package.json b/package.json index 6857a02..5a7ce4c 100644 --- a/package.json +++ b/package.json @@ -87,10 +87,11 @@ }, "scripts": { "benchmark": "npm run build:esm && node benchmark/index.js", - "build": "npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:min", + "build": "npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:min && npm run build:types", "build:cjs": "rm -rf dist/cjs && NODE_ENV=production rollup -c config/rollup/config.cjs.js && tsc -p ./config/tsconfig/cjs.json", "build:esm": "rm -rf dist/esm && NODE_ENV=production rollup -c config/rollup/config.esm.js && tsc -p ./config/tsconfig/esm.json", "build:min": "rm -rf dist/min && NODE_ENV=production rollup -c config/rollup/config.min.js && tsc -p ./config/tsconfig/min.json", + "build:types": "node scripts/fallback-types.mjs", "build:umd": "rm -rf dist/umd && NODE_ENV=production rollup -c config/rollup/config.umd.js && tsc -p ./config/tsconfig/umd.json", "dev": "NODE_ENV=development webpack serve --progress --config=config/webpack.config.js", "format": "prettier **/*.ts --write", diff --git a/scripts/fallback-types.mjs b/scripts/fallback-types.mjs new file mode 100644 index 0000000..46d41d9 --- /dev/null +++ b/scripts/fallback-types.mjs @@ -0,0 +1,64 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const METHODS = ` +/** + * Whether the values passed are strictly equal or both NaN. + */ +export declare const sameValueZeroEqual: (a: A, b: B) => boolean; + +/** + * Whether the items passed are deeply-equal in value. + */ +export declare const deepEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are deeply-equal in value based on strict comparison. + */ +export declare const strictDeepEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are deeply-equal in value, including circular references. + */ +export declare const circularDeepEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are deeply-equal in value, including circular references, + * based on strict comparison. + */ +export declare const strictCircularDeepEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are shallowly-equal in value. + */ +export declare const shallowEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are shallowly-equal in value based on strict comparison + */ +export declare const strictShallowEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are shallowly-equal in value, including circular references. + */ +export declare const circularShallowEqual: (a: A, b: B) => boolean; +/** + * Whether the items passed are shallowly-equal in value, including circular references, + * based on strict comparison. + */ +export declare const strictCircularShallowEqual: (a: A, b: B) => boolean; +/** + * Create a custom equality comparison method. + * + * This can be done to create very targeted comparisons in extreme hot-path scenarios + * where the standard methods are not performant enough, but can also be used to provide + * support for legacy environments that cannot polyfill for modern features expected by + * \`fast-equals\`, such as \`WeakMap\` or \`RegExp.prototype.flags\`. + */ +export declare function createCustomEqual( + options?: CustomEqualCreatorOptions, +): (a: A, b: B) => boolean; +`; + +const INTERNAL_TYPES = fs.readFileSync( + path.join(import.meta.dirname, '..', 'src', 'internalTypes.ts'), +); + +const OUTPUT = `${INTERNAL_TYPES}\n${METHODS}`.trim(); +const OUTPUT_DESTINATION = path.join(import.meta.dirname, '..', 'index.d.ts'); + +fs.writeFileSync(OUTPUT_DESTINATION, OUTPUT, 'utf-8');