mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 11:43:51 +00:00
Remove dependenc on MergeDeep
This caused failures when building outside of the IDE for unknown reasons.
This commit is contained in:
@@ -9,6 +9,10 @@ type ExampleOptions = {
|
||||
readonly d?: number;
|
||||
readonly e: string;
|
||||
};
|
||||
readonly f: {
|
||||
readonly h?: number;
|
||||
readonly i: string;
|
||||
};
|
||||
};
|
||||
|
||||
const EXAMPLE_DEFAULTS = Object.freeze({
|
||||
@@ -27,12 +31,16 @@ describe("mergeOptions", () => {
|
||||
const options: ExampleOptions = {
|
||||
required_func: () => {},
|
||||
b: "test",
|
||||
f: {
|
||||
i: "example",
|
||||
},
|
||||
};
|
||||
|
||||
const merged = mergeOptions(options, EXAMPLE_DEFAULTS);
|
||||
|
||||
// can access properties
|
||||
expect(merged.a).toBe(42);
|
||||
expect(merged.c.d).toBe(1);
|
||||
|
||||
expect(merged).toEqual({
|
||||
a: 0,
|
||||
|
||||
@@ -1,151 +1,36 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-object-type -- used in type-fest's code*/
|
||||
import { RequiredKeysOf, Simplify, Primitive } from "type-fest";
|
||||
import { Simplify, Primitive, ConditionalKeys } from "type-fest";
|
||||
|
||||
type Function = (...args: any[]) => any;
|
||||
|
||||
/** FIXME: this is pulled from type-fest-v4. remove when we update package */
|
||||
export type ConditionalSimplifyDeep<
|
||||
Type,
|
||||
ExcludeType = never,
|
||||
IncludeType = unknown,
|
||||
> = Type extends ExcludeType
|
||||
? Type
|
||||
: Type extends IncludeType
|
||||
? { [TypeKey in keyof Type]: ConditionalSimplifyDeep<Type[TypeKey], ExcludeType, IncludeType> }
|
||||
: Type;
|
||||
export type BuiltIns = Primitive | void | Date | RegExp;
|
||||
export type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
|
||||
export type SimplifyDeep<Type, ExcludeType = never> = ConditionalSimplifyDeep<
|
||||
Type,
|
||||
ExcludeType | NonRecursiveType | Set<unknown> | Map<unknown, unknown>,
|
||||
object
|
||||
>;
|
||||
/** FIXME: taken from type-fest-v4. remove once we upgrade */
|
||||
export type RequiredKeysOf<BaseType extends object> = BaseType extends unknown // For distributing `BaseType`
|
||||
? Exclude<keyof BaseType, OptionalKeysOf<BaseType>>
|
||||
: never; // Should never happen
|
||||
export type OptionalKeysOf<BaseType extends object> = BaseType extends unknown // For distributing `BaseType`
|
||||
? keyof {
|
||||
[Key in keyof BaseType as BaseType extends Record<Key, BaseType[Key]> ? never : Key]: never;
|
||||
} &
|
||||
keyof BaseType // Intersect with `keyof BaseType` to ensure result of `OptionalKeysOf<BaseType>` is always assignable to `keyof BaseType`
|
||||
: never; // Should never happen
|
||||
|
||||
type SimplifyDeepExcludeArray<T> = SimplifyDeep<T, UnknownArray>;
|
||||
export type UnknownArray = readonly unknown[];
|
||||
export type UnknownRecord = Record<PropertyKey, unknown>;
|
||||
export type UnknownArrayOrTuple = readonly [...unknown[]];
|
||||
export type OmitIndexSignature<ObjectType> = {
|
||||
[KeyType in keyof ObjectType as {} extends Record<KeyType, unknown>
|
||||
? never
|
||||
: KeyType]: ObjectType[KeyType];
|
||||
};
|
||||
export type PickIndexSignature<ObjectType> = {
|
||||
[KeyType in keyof ObjectType as {} extends Record<KeyType, unknown>
|
||||
? KeyType
|
||||
: never]: ObjectType[KeyType];
|
||||
};
|
||||
/** END FIXME: taken from type-fest-v4. remove once we upgrade */
|
||||
|
||||
type MergeDeepRecordProperty<Destination, Source> = undefined extends Source
|
||||
?
|
||||
| MergeDeepOrReturn<Source, Exclude<Destination, undefined>, Exclude<Source, undefined>>
|
||||
| undefined
|
||||
: MergeDeepOrReturn<Source, Destination, Source>;
|
||||
type RequiredFilter<Type, Key extends keyof Type> = undefined extends Type[Key]
|
||||
? Type[Key] extends undefined
|
||||
? Key
|
||||
: never
|
||||
: Key;
|
||||
|
||||
// Returns `never` if the key is required otherwise return the key type.
|
||||
type OptionalFilter<Type, Key extends keyof Type> = undefined extends Type[Key]
|
||||
? Type[Key] extends undefined
|
||||
? never
|
||||
: Key
|
||||
: never;
|
||||
|
||||
export type EnforceOptional<ObjectType> = Simplify<
|
||||
// Merges options with defaults, deeply preferring default types over options types.
|
||||
// FIXME: It's likely the type-fests `MergeDeep` will be a better fit for this, but that is in v4+,
|
||||
// marked experimental, _and_ caused flaky build failures when testing.
|
||||
export type OptionsWithDefaultsDeep<Options, Defaults> = Simplify<
|
||||
{
|
||||
[Key in keyof ObjectType as RequiredFilter<ObjectType, Key>]: ObjectType[Key];
|
||||
[K in keyof Required<Options> & keyof Defaults]: Defaults[K] extends Primitive | Function
|
||||
? Defaults[K]
|
||||
: Defaults[K] extends object
|
||||
? // note: exclude undefined here so that if the type is a union with undefined, we can still get the keys correctly
|
||||
OptionsWithDefaultsDeep<Exclude<Options[K], undefined>, Defaults[K]>
|
||||
: never; // should only ever be primitive, function, or object
|
||||
} & {
|
||||
[Key in keyof ObjectType as OptionalFilter<ObjectType, Key>]?: Exclude<
|
||||
ObjectType[Key],
|
||||
undefined
|
||||
>;
|
||||
[K in Exclude<keyof Required<Options>, keyof Defaults>]: Options[K];
|
||||
}
|
||||
>;
|
||||
|
||||
type MergeDeepOrReturn<DefaultType, Destination, Source> = SimplifyDeepExcludeArray<
|
||||
[undefined] extends [Destination | Source]
|
||||
? DefaultType
|
||||
: Destination extends UnknownRecord
|
||||
? Source extends UnknownRecord
|
||||
? MergeDeepRecord<Destination, Source>
|
||||
: DefaultType
|
||||
: Destination extends UnknownArrayOrTuple
|
||||
? Source extends UnknownArrayOrTuple
|
||||
? MergeDeepArrayOrTuple<Destination, Source>
|
||||
: DefaultType
|
||||
: DefaultType
|
||||
>;
|
||||
|
||||
type MergeDeepArrayOrTuple<
|
||||
Destination extends UnknownArrayOrTuple,
|
||||
Source extends UnknownArrayOrTuple,
|
||||
> = Array<Exclude<Destination, undefined>[number] | Exclude<Source, undefined>[number]>;
|
||||
|
||||
type MergeDeepRecord<
|
||||
Destination extends UnknownRecord,
|
||||
Source extends UnknownRecord,
|
||||
> = DoMergeDeepRecord<OmitIndexSignature<Destination>, OmitIndexSignature<Source>> &
|
||||
Merge<PickIndexSignature<Destination>, PickIndexSignature<Source>>;
|
||||
|
||||
type DoMergeDeepRecord<Destination extends UnknownRecord, Source extends UnknownRecord> =
|
||||
// Case in rule 1: The destination contains the key but the source doesn't.
|
||||
{
|
||||
[Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key];
|
||||
} & {
|
||||
// Case in rule 2: The source contains the key but the destination doesn't.
|
||||
[Key in keyof Source as Key extends keyof Destination ? never : Key]: Source[Key];
|
||||
} & {
|
||||
// Case in rule 3: Both the source and the destination contain the key.
|
||||
[Key in keyof Source as Key extends keyof Destination ? Key : never]: MergeDeepRecordProperty<
|
||||
Destination[Key],
|
||||
Source[Key]
|
||||
>;
|
||||
};
|
||||
type SimpleMerge<Destination, Source> = {
|
||||
[Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key];
|
||||
} & Source;
|
||||
|
||||
export type Merge<Destination, Source> = Simplify<
|
||||
SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<Source>> &
|
||||
SimpleMerge<OmitIndexSignature<Destination>, OmitIndexSignature<Source>>
|
||||
>;
|
||||
export type IfNever<T, TypeIfNever = true, TypeIfNotNever = false> =
|
||||
IsNever<T> extends true ? TypeIfNever : TypeIfNotNever;
|
||||
export type IsNever<T> = [T] extends [never] ? true : false;
|
||||
|
||||
type MergeDeep<Destination, Source> = SimplifyDeepExcludeArray<
|
||||
[undefined] extends [Destination | Source]
|
||||
? never
|
||||
: Destination extends UnknownRecord
|
||||
? Source extends UnknownRecord
|
||||
? MergeDeepRecord<Destination, Source>
|
||||
: never
|
||||
: Destination extends UnknownArrayOrTuple
|
||||
? Source extends UnknownArrayOrTuple
|
||||
? MergeDeepArrayOrTuple<Destination, Source>
|
||||
: never
|
||||
: never
|
||||
>;
|
||||
export type ConditionalKeys<Base, Condition> = {
|
||||
// Map through all the keys of the given base type.
|
||||
[Key in keyof Base]-?: Base[Key] extends Condition // Pick only keys with types extending the given `Condition` type.
|
||||
? // Retain this key
|
||||
// If the value for the key extends never, only include it if `Condition` also extends never
|
||||
IfNever<Base[Key], IfNever<Condition, Key, never>, Key>
|
||||
: // Discard this key since the condition fails.
|
||||
never;
|
||||
// Convert the produced object into a union type of the keys which passed the conditional test.
|
||||
}[keyof Base];
|
||||
|
||||
/** END FIXME: this is pulled from type-fest-v4. remove when we update package */
|
||||
|
||||
export type OptionsWithDefaultsDeep<Options, Defaults> =
|
||||
// FIXME: replace with MergeDeep<Options, Defaults> when type-fest is updated to v4+
|
||||
MergeDeep<Options, Defaults>;
|
||||
|
||||
type DefaultsForDeep<Options extends object> = Simplify<
|
||||
Omit<
|
||||
Required<{
|
||||
@@ -171,10 +56,10 @@ type RequiredMethodKeysOf<Obj extends object> = RequiredKeysOf<
|
||||
|
||||
export function mergeOptions<
|
||||
Options extends object,
|
||||
const Defaults extends DefaultsForDeep<Options>,
|
||||
// const Defaults extends DefaultsForDeep<Options>,
|
||||
>(
|
||||
options: Options,
|
||||
defaults: Defaults,
|
||||
defaults: DefaultsForDeep<Options>, //Defaults,
|
||||
): OptionsWithDefaultsDeep<Options, DefaultsForDeep<Options>> {
|
||||
const result = { ...options } as any;
|
||||
for (const key in defaults) {
|
||||
|
||||
Reference in New Issue
Block a user