UNPKG

5.37 kBPlain TextView Raw
1import { globalState, die } from "../internal"
2
3// We shorten anything used > 5 times
4export const assign = Object.assign
5export const getDescriptor = Object.getOwnPropertyDescriptor
6export const defineProperty = Object.defineProperty
7export const objectPrototype = Object.prototype
8
9export const EMPTY_ARRAY = []
10Object.freeze(EMPTY_ARRAY)
11
12export const EMPTY_OBJECT = {}
13Object.freeze(EMPTY_OBJECT)
14
15export interface Lambda {
16 (): void
17 name?: string
18}
19
20const hasProxy = typeof Proxy !== "undefined"
21const plainObjectString = Object.toString()
22
23export function assertProxies() {
24 if (!hasProxy) {
25 die(
26 __DEV__
27 ? "`Proxy` objects are not available in the current environment. Please configure MobX to enable a fallback implementation.`"
28 : "Proxy not available"
29 )
30 }
31}
32
33export function warnAboutProxyRequirement(msg: string) {
34 if (__DEV__ && globalState.verifyProxies) {
35 die(
36 "MobX is currently configured to be able to run in ES5 mode, but in ES5 MobX won't be able to " +
37 msg
38 )
39 }
40}
41
42export function getNextId() {
43 return ++globalState.mobxGuid
44}
45
46/**
47 * Makes sure that the provided function is invoked at most once.
48 */
49export function once(func: Lambda): Lambda {
50 let invoked = false
51 return function () {
52 if (invoked) return
53 invoked = true
54 return (func as any).apply(this, arguments)
55 }
56}
57
58export const noop = () => {}
59
60export function isFunction(fn: any): fn is Function {
61 return typeof fn === "function"
62}
63
64export function isString(value: any): value is string {
65 return typeof value === "string"
66}
67
68export function isStringish(value: any): value is string | number | symbol {
69 const t = typeof value
70 switch (t) {
71 case "string":
72 case "symbol":
73 case "number":
74 return true
75 }
76 return false
77}
78
79export function isObject(value: any): value is Object {
80 return value !== null && typeof value === "object"
81}
82
83export function isPlainObject(value) {
84 if (!isObject(value)) return false
85 const proto = Object.getPrototypeOf(value)
86 if (proto == null) return true
87 return proto.constructor?.toString() === plainObjectString
88}
89
90// https://stackoverflow.com/a/37865170
91export function isGenerator(obj: any): boolean {
92 const constructor = obj?.constructor
93 if (!constructor) return false
94 if ("GeneratorFunction" === constructor.name || "GeneratorFunction" === constructor.displayName)
95 return true
96 return false
97}
98
99export function addHiddenProp(object: any, propName: PropertyKey, value: any) {
100 defineProperty(object, propName, {
101 enumerable: false,
102 writable: true,
103 configurable: true,
104 value
105 })
106}
107
108export function addHiddenFinalProp(object: any, propName: PropertyKey, value: any) {
109 defineProperty(object, propName, {
110 enumerable: false,
111 writable: false,
112 configurable: true,
113 value
114 })
115}
116
117export function createInstanceofPredicate<T>(
118 name: string,
119 theClass: new (...args: any[]) => T
120): (x: any) => x is T {
121 const propName = "isMobX" + name
122 theClass.prototype[propName] = true
123 return function (x) {
124 return isObject(x) && x[propName] === true
125 } as any
126}
127
128export function isES6Map(thing): boolean {
129 return thing instanceof Map
130}
131
132export function isES6Set(thing): thing is Set<any> {
133 return thing instanceof Set
134}
135
136const hasGetOwnPropertySymbols = typeof Object.getOwnPropertySymbols !== "undefined"
137
138/**
139 * Returns the following: own enumerable keys and symbols.
140 */
141export function getPlainObjectKeys(object) {
142 const keys = Object.keys(object)
143 // Not supported in IE, so there are not going to be symbol props anyway...
144 if (!hasGetOwnPropertySymbols) return keys
145 const symbols = Object.getOwnPropertySymbols(object)
146 if (!symbols.length) return keys
147 return [...keys, ...symbols.filter(s => objectPrototype.propertyIsEnumerable.call(object, s))]
148}
149
150// From Immer utils
151// Returns all own keys, including non-enumerable and symbolic
152export const ownKeys: (target: any) => PropertyKey[] =
153 typeof Reflect !== "undefined" && Reflect.ownKeys
154 ? Reflect.ownKeys
155 : hasGetOwnPropertySymbols
156 ? obj => Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj) as any)
157 : /* istanbul ignore next */ Object.getOwnPropertyNames
158
159export function stringifyKey(key: any): string {
160 if (typeof key === "string") return key
161 if (typeof key === "symbol") return key.toString()
162 return new String(key).toString()
163}
164
165export function toPrimitive(value) {
166 return value === null ? null : typeof value === "object" ? "" + value : value
167}
168
169export function hasProp(target: Object, prop: PropertyKey): boolean {
170 return objectPrototype.hasOwnProperty.call(target, prop)
171}
172
173// From Immer utils
174export const getOwnPropertyDescriptors =
175 Object.getOwnPropertyDescriptors ||
176 function getOwnPropertyDescriptors(target: any) {
177 // Polyfill needed for Hermes and IE, see https://github.com/facebook/hermes/issues/274
178 const res: any = {}
179 // Note: without polyfill for ownKeys, symbols won't be picked up
180 ownKeys(target).forEach(key => {
181 res[key] = getDescriptor(target, key)
182 })
183 return res
184 }