Skip to content

Commit

Permalink
build flattened internal types instead of importing
Browse files Browse the repository at this point in the history
  • Loading branch information
planttheidea committed Jan 6, 2025
1 parent ef3cf30 commit 832f4b5
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 22 deletions.
224 changes: 203 additions & 21 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -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<Key extends object, Value> {
delete(key: Key): boolean;
get(key: Key): Value | undefined;
set(key: Key, value: any): any;
}

export interface State<Meta> {
/**
* Cache used to identify circular references
*/
readonly cache: Cache<any, any> | undefined;
/**
* Method used to determine equality of nested value.
*/
readonly equals: InternalEqualityComparator<Meta>;
/**
* 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<Meta> extends State<Meta> {
readonly cache: Cache<any, any>;
}

export interface DefaultState<Meta> extends State<Meta> {
readonly cache: undefined;
}

export interface Dictionary<Value = any> {
[key: string | symbol]: Value;
$$typeof?: any;
}

export interface ComparatorConfig<Meta> {
/**
* Whether the arrays passed are equal in value. In strict mode, this includes
* additional properties added to the array.
*/
areArraysEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the dates passed are equal in value.
*/
areDatesEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the errors passed are equal in value.
*/
areErrorsEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the functions passed are equal in value.
*/
areFunctionsEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the maps passed are equal in value. In strict mode, this includes
* additional properties added to the map.
*/
areMapsEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the numbers passed are equal in value.
*/
areNumbersEqual: TypeEqualityComparator<any, Meta>;
/**
* 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<any, Meta>;
/**
* Whether the primitive wrappers passed are equal in value.
*/
arePrimitiveWrappersEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the regexps passed are equal in value.
*/
areRegExpsEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the sets passed are equal in value. In strict mode, this includes
* additional properties added to the set.
*/
areSetsEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the typed arrays passed are equal in value. In strict mode, this includes
* additional properties added to the typed array.
*/
areTypedArraysEqual: TypeEqualityComparator<any, Meta>;
/**
* Whether the URLs passed are equal in value.
*/
areUrlsEqual: TypeEqualityComparator<any, Meta>;
}

export type CreateCustomComparatorConfig<Meta> = (
config: ComparatorConfig<Meta>,
) => Partial<ComparatorConfig<Meta>>;

export type CreateState<Meta> = () => {
cache?: Cache<any, any> | undefined;
meta?: Meta;
};

export type EqualityComparator<Meta> = <A, B>(
a: A,
b: B,
state: State<Meta>,
) => boolean;
export type AnyEqualityComparator<Meta> = (
a: any,
b: any,
state: State<Meta>,
) => boolean;

export type EqualityComparatorCreator<Meta> = (
fn: EqualityComparator<Meta>,
) => InternalEqualityComparator<Meta>;

export type InternalEqualityComparator<Meta> = (
a: any,
b: any,
indexOrKeyA: any,
indexOrKeyB: any,
parentA: any,
parentB: any,
state: State<Meta>,
) => 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<Type, Meta = undefined> = (
a: Type,
b: Type,
state: State<Meta>,
) => boolean;

export interface CustomEqualCreatorOptions<Meta> {
/**
* 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<Meta>;
/**
* 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<Meta>,
) => InternalEqualityComparator<Meta>;
/**
* Create a custom `state` object passed between the methods. This allows for
* custom `cache` and/or `meta` values to be used.
*/
createState?: CreateState<Meta>;
/**
* 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.
Expand Down Expand Up @@ -68,4 +250,4 @@ export declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
*/
export declare function createCustomEqual<Meta = undefined>(
options?: CustomEqualCreatorOptions<Meta>,
): <A, B>(a: A, b: B) => boolean;
): <A, B>(a: A, b: B) => boolean;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
64 changes: 64 additions & 0 deletions scripts/fallback-types.mjs
Original file line number Diff line number Diff line change
@@ -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, B>(a: A, b: B) => boolean;
/**
* Whether the items passed are deeply-equal in value.
*/
export declare const deepEqual: <A, B>(a: A, b: B) => boolean;
/**
* Whether the items passed are deeply-equal in value based on strict comparison.
*/
export declare const strictDeepEqual: <A, B>(a: A, b: B) => boolean;
/**
* Whether the items passed are deeply-equal in value, including circular references.
*/
export declare const circularDeepEqual: <A, B>(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, B>(a: A, b: B) => boolean;
/**
* Whether the items passed are shallowly-equal in value.
*/
export declare const shallowEqual: <A, B>(a: A, b: B) => boolean;
/**
* Whether the items passed are shallowly-equal in value based on strict comparison
*/
export declare const strictShallowEqual: <A, B>(a: A, b: B) => boolean;
/**
* Whether the items passed are shallowly-equal in value, including circular references.
*/
export declare const circularShallowEqual: <A, B>(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, B>(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<Meta = undefined>(
options?: CustomEqualCreatorOptions<Meta>,
): <A, B>(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');

0 comments on commit 832f4b5

Please sign in to comment.