UNPKG

3.21 kBPlain TextView Raw
1// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2// Node module: @loopback/repository
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6import {Class} from './common-types';
7
8/**
9 * A type resolver is a function that returns a class representing the type,
10 * typically a Model or Entity (e.g. Product).
11 *
12 * We use type resolvers to break require() loops when defining relations.
13 * The target model (class) is provided via a provider, thus deferring
14 * the actual reference to the class itself until later, when both sides
15 * of the relation are created as JavaScript classes.
16 *
17 * @typeParam Type - The type we are resolving, for example `Entity` or `Product`.
18 * This parameter is required.
19 *
20 * @typeParam StaticMembers - The static properties available on the
21 * type class. For example, all models have static `modelName` property.
22 * When `StaticMembers` are not provided, we default to static properties of
23 * a `Function` - `name`, `length`, `apply`, `call`, etc.
24 * Please note the value returned by the resolver is described as having
25 * arbitrary additional static properties (see how Class is defined).
26 */
27export type TypeResolver<
28 Type extends Object,
29 StaticMembers = Function,
30> = () => Class<Type> & StaticMembers;
31
32/**
33 * A function that checks whether a function is a TypeResolver or not.
34 * @param fn - The value to check.
35 */
36export function isTypeResolver<T extends object>(
37 // eslint-disable-next-line @typescript-eslint/no-explicit-any
38 fn: any,
39): fn is TypeResolver<T> {
40 // 1. A type provider must be a function
41 if (typeof fn !== 'function') return false;
42
43 // 2. A class constructor is not a type provider
44 if (/^class/.test(fn.toString())) return false;
45
46 // 3. Built-in types like Date & Array are not type providers
47 if (isBuiltinType(fn)) return false;
48
49 // TODO(bajtos): support model classes defined via ES5 constructor function
50
51 return true;
52}
53
54/**
55 * A boxed type for `null`
56 */
57// eslint-disable-next-line @typescript-eslint/naming-convention
58export function Null() {
59 return null;
60}
61
62/**
63 * Check if the provided function is a built-in type provided by JavaScript
64 * and/or Node.js. E.g. `Number`, `Array`, `Buffer`, etc.
65 */
66export function isBuiltinType(fn: Function): boolean {
67 return (
68 // scalars
69 fn === Number ||
70 fn === Boolean ||
71 fn === String ||
72 // objects
73 fn === Object ||
74 fn === Array ||
75 fn === Date ||
76 fn === RegExp ||
77 fn === Buffer ||
78 fn === Null ||
79 // function as a type
80 fn === Function
81 );
82}
83
84export type NonFunction<T> = T extends Function ? never : T;
85
86/**
87 * Resolve a type value that may have been provided via TypeResolver.
88 * @param fn - A type class or a type provider.
89 * @returns The resolved type.
90 */
91export function resolveType<T extends object>(
92 fn: TypeResolver<T, {}> | Class<T> | Function,
93): Class<T>;
94
95// An overload to handle the case when `fn` is not a class nor a resolver.
96export function resolveType<T>(fn: NonFunction<T>): T;
97
98export function resolveType<T extends object>(
99 fn: TypeResolver<T> | Class<T> | T,
100) {
101 return isTypeResolver(fn) ? fn() : fn;
102}