"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.keysOf = keysOf;
exports.assertNever = void 0;
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 *
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var assertNever = function assertNever(x) {
  throw new Error("Unexpected value ".concat(x));
};

// utility types:
/**
 * XOR for some properties applied to a type
 * (XOR is one of these but not both or neither)
 *
 * Usage: OneOf<typeToExtend, one | but | not | multiple | of | these | are | required>
 *
 * To require aria-label or aria-labelledby but not both
 * Example: OneOf<Type, 'aria-label' | 'aria-labelledby'>
 */
exports.assertNever = assertNever;
/**
 * Wraps Object.keys with proper typescript definition of the resulting array
 */
function keysOf(obj) {
  return Object.keys(obj);
}

// Utility methods for ApplyClassComponentDefaults

/**
 * Because of how TypeScript's LibraryManagedAttributes is designed to handle defaultProps (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#support-for-defaultprops-in-jsx)
 * we can't directly export the props definition as the defaulted values are not made optional,
 * because it isn't processed by LibraryManagedAttributes. To get around this, we:
 * - remove the props which have default values applied
 * - export (Props - Defaults) & Partial<Defaults>
 */

/*
https://github.com/Microsoft/TypeScript/issues/28339
Problem: Pick and Omit do not distribute over union types, which manifests when
optional values become required after a Pick or Omit operation. These
Distributive forms correctly operate on union types, preserving optionality.
 */

/*
TypeScript's discriminated unions are overly permissive: as long as one type of the union is satisfied
the other types are not validated against. For example:

type Foo = {
  value: string,
  foo: string
};
type Bar = {
  value: number,
  bar: string
}
function what(x: Foo | Bar) {
  return x.value;
}

As you would expect -

what({ value: 'asdf', foo: 'asdf' }); // fine
what({ value: 5, foo: 'asdf' }); // error
what({ value: 5, bar: 'asdf' }); // fine
what({ value: 'asdf', bar: 'asdf' }); // error

However, if Foo is satisfied then you can pass any value you want to Bar's unique properties:
what({ value: 'asdf', foo: 'asdf', bar: false }) // works

TypeScript is okay with this as a type guard would detect the object is Foo and prevent accessing `bar`.
Unfortunately this prevents feedback to the user about potentially unintentional effects, for example:

A common pattern in EUI is to render something as a div OR as a button, depending on if an onClick prop is passed.
passing additional props down through `...rest`, which can be specified as

type Spanlike = HTMLAttributes<HTMLSpanElement>;
type Buttonlike = { onClick: MouseEventHandler<HTMLButtonElement> }; // onClick is the discriminant
React.FunctionComponent<Spanlike | Buttonlike>

Internally, the component would have a type guard to check if props contains `onClick` and resolve to Buttonlike.
Externally, however, you could use the component as

<Component value="buzz"/>

and no error would occur as the Spanlike type is satisfied and the type guard would prevent accessing button attributes.
This prevents immediate feedback to the develop, and would actually lead to React warnings as the `value` prop would
still propagate down to the span's props, which is invalid. The following two utility types provide a solution for
creating exclusive unions:

React.FunctionComponent<ExclusiveUnion<Spanlike, Buttonlike>>
 */

/**
 * Returns member keys in U not present in T set to never
 * T = { 'one', 'two', 'three' }
 * U = { 'three', 'four', 'five' }
 * returns { 'four': never, 'five': never }
 */

/**
 * Allow either T or U, preventing any additional keys of the other type from being present
 */

/**
 * For components that conditionally render <button> or <a>
 * Convenience types for extending base props (T) and
 * element-specific props (P) with standard clickable properties
 *
 * These will likely be used together, along with `ExclusiveUnion`:
 *
 * type AnchorLike = PropsForAnchor<BaseProps>
 * type ButtonLike = PropsForButton<BaseProps>
 * type ComponentProps = ExclusiveUnion<AnchorLike, ButtonLike>
 * const Component: FunctionComponent<ComponentProps> ...
 */

/**
 * Replaces all properties on any type as optional, includes nested types
 *
 * @example
 * ```ts
 * interface Person {
 *  name: string;
 *  age?: number;
 *  spouse: Person;
 *  children: Person[];
 * }
 * type PartialPerson = RecursivePartial<Person>;
 * // results in
 * interface PartialPerson {
 *  name?: string;
 *  age?: number;
 *  spouse?: RecursivePartial<Person>;
 *  children?: RecursivePartial<Person>[]
 * }
 * ```
 */