UNPKG

9.26 kBJavaScriptView Raw
1"use strict";
2// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
3// Node module: @loopback/context
4// This file is licensed under the MIT License.
5// License text available at https://opensource.org/licenses/MIT
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.UUID_PATTERN = exports.uuid = exports.transformValueOrPromise = exports.resolveUntil = exports.tryCatchFinally = exports.tryWithFinally = exports.resolveList = exports.resolveMap = exports.getDeepProperty = exports.isPromiseLike = void 0;
8/**
9 * This module contains types for values and/or promises as well as a set of
10 * utility methods to handle values and/or promises.
11 */
12const uuid_1 = require("uuid");
13/**
14 * Check whether a value is a Promise-like instance.
15 * Recognizes both native promises and third-party promise libraries.
16 *
17 * @param value - The value to check.
18 */
19function isPromiseLike(value) {
20 if (!value)
21 return false;
22 if (typeof value !== 'object' && typeof value !== 'function')
23 return false;
24 return typeof value.then === 'function';
25}
26exports.isPromiseLike = isPromiseLike;
27/**
28 * Get nested properties of an object by path
29 * @param value - Value of the source object
30 * @param path - Path to the property
31 */
32function getDeepProperty(value, path) {
33 let result = value;
34 const props = path.split('.').filter(Boolean);
35 for (const p of props) {
36 if (result == null) {
37 return undefined;
38 }
39 result = result[p];
40 }
41 return result;
42}
43exports.getDeepProperty = getDeepProperty;
44/**
45 * Resolve entries of an object into a new object with the same keys. If one or
46 * more entries of the source object are resolved to a promise by the `resolver`
47 * function, this method returns a promise which will be resolved to the new
48 * object with fully resolved entries.
49 *
50 * @example
51 *
52 * - Example 1: resolve all entries synchronously
53 * ```ts
54 * const result = resolveMap({a: 'x', b: 'y'}, v => v.toUpperCase());
55 * ```
56 * The `result` will be `{a: 'X', b: 'Y'}`.
57 *
58 * - Example 2: resolve one or more entries asynchronously
59 * ```ts
60 * const result = resolveMap({a: 'x', b: 'y'}, v =>
61 * Promise.resolve(v.toUpperCase()),
62 * );
63 * ```
64 * The `result` will be a promise of `{a: 'X', b: 'Y'}`.
65 *
66 * @param map - The original object containing the source entries
67 * @param resolver - A function resolves an entry to a value or promise. It will
68 * be invoked with the property value, the property name, and the source object.
69 */
70function resolveMap(map, resolver) {
71 const result = {};
72 let asyncResolvers = undefined;
73 const setter = (key) => (val) => {
74 if (val !== undefined) {
75 // Only set the value if it's not undefined so that the default value
76 // for a key will be honored
77 result[key] = val;
78 }
79 };
80 for (const key in map) {
81 const valueOrPromise = resolver(map[key], key, map);
82 if (isPromiseLike(valueOrPromise)) {
83 if (!asyncResolvers)
84 asyncResolvers = [];
85 asyncResolvers.push(valueOrPromise.then(setter(key)));
86 }
87 else {
88 if (valueOrPromise !== undefined) {
89 // Only set the value if it's not undefined so that the default value
90 // for a key will be honored
91 result[key] = valueOrPromise;
92 }
93 }
94 }
95 if (asyncResolvers) {
96 return Promise.all(asyncResolvers).then(() => result);
97 }
98 else {
99 return result;
100 }
101}
102exports.resolveMap = resolveMap;
103/**
104 * Resolve entries of an array into a new array with the same indexes. If one or
105 * more entries of the source array are resolved to a promise by the `resolver`
106 * function, this method returns a promise which will be resolved to the new
107 * array with fully resolved entries.
108 *
109 * @example
110 *
111 * - Example 1: resolve all entries synchronously
112 * ```ts
113 * const result = resolveList(['a', 'b'], v => v.toUpperCase());
114 * ```
115 * The `result` will be `['A', 'B']`.
116 *
117 * - Example 2: resolve one or more entries asynchronously
118 * ```ts
119 * const result = resolveList(['a', 'b'], v =>
120 * Promise.resolve(v.toUpperCase()),
121 * );
122 * ```
123 * The `result` will be a promise of `['A', 'B']`.
124 *
125 * @param list - The original array containing the source entries
126 * @param resolver - A function resolves an entry to a value or promise. It will
127 * be invoked with the property value, the property index, and the source array.
128 */
129function resolveList(list, resolver) {
130 const result = new Array(list.length);
131 let asyncResolvers = undefined;
132 const setter = (index) => (val) => {
133 result[index] = val;
134 };
135 for (let ix = 0; ix < list.length; ix++) {
136 const valueOrPromise = resolver(list[ix], ix, list);
137 if (isPromiseLike(valueOrPromise)) {
138 if (!asyncResolvers)
139 asyncResolvers = [];
140 asyncResolvers.push(valueOrPromise.then(setter(ix)));
141 }
142 else {
143 result[ix] = valueOrPromise;
144 }
145 }
146 if (asyncResolvers) {
147 return Promise.all(asyncResolvers).then(() => result);
148 }
149 else {
150 return result;
151 }
152}
153exports.resolveList = resolveList;
154/**
155 * Try to run an action that returns a promise or a value
156 * @param action - A function that returns a promise or a value
157 * @param finalAction - A function to be called once the action
158 * is fulfilled or rejected (synchronously or asynchronously)
159 *
160 * @typeParam T - Type for the return value
161 */
162function tryWithFinally(action, finalAction) {
163 return tryCatchFinally(action, undefined, finalAction);
164}
165exports.tryWithFinally = tryWithFinally;
166/**
167 * Try to run an action that returns a promise or a value with error and final
168 * actions to mimic `try {} catch(err) {} finally {}` for a value or promise.
169 *
170 * @param action - A function that returns a promise or a value
171 * @param errorAction - A function to be called once the action
172 * is rejected (synchronously or asynchronously). It must either return a new
173 * value or throw an error.
174 * @param finalAction - A function to be called once the action
175 * is fulfilled or rejected (synchronously or asynchronously)
176 *
177 * @typeParam T - Type for the return value
178 */
179function tryCatchFinally(action, errorAction = err => {
180 throw err;
181}, finalAction = () => { }) {
182 let result;
183 try {
184 result = action();
185 }
186 catch (err) {
187 result = reject(err);
188 }
189 if (isPromiseLike(result)) {
190 return result.then(resolve, reject);
191 }
192 return resolve(result);
193 function resolve(value) {
194 try {
195 return value;
196 }
197 finally {
198 finalAction();
199 }
200 }
201 function reject(err) {
202 try {
203 return errorAction(err);
204 }
205 finally {
206 finalAction();
207 }
208 }
209}
210exports.tryCatchFinally = tryCatchFinally;
211/**
212 * Resolve an iterator of source values into a result until the evaluator
213 * returns `true`
214 * @param source - The iterator of source values
215 * @param resolver - The resolve function that maps the source value to a result
216 * @param evaluator - The evaluate function that decides when to stop
217 */
218function resolveUntil(source, resolver, evaluator) {
219 // Do iteration in loop for synchronous values to avoid stack overflow
220 // eslint-disable-next-line no-constant-condition
221 while (true) {
222 const next = source.next();
223 if (next.done)
224 return undefined; // End of the iterator
225 const sourceVal = next.value;
226 const valueOrPromise = resolver(sourceVal);
227 if (isPromiseLike(valueOrPromise)) {
228 return valueOrPromise.then(v => {
229 if (evaluator(sourceVal, v)) {
230 return v;
231 }
232 else {
233 return resolveUntil(source, resolver, evaluator);
234 }
235 });
236 }
237 else {
238 if (evaluator(sourceVal, valueOrPromise)) {
239 return valueOrPromise;
240 }
241 // Continue with the while loop
242 }
243 }
244}
245exports.resolveUntil = resolveUntil;
246/**
247 * Transform a value or promise with a function that produces a new value or
248 * promise
249 * @param valueOrPromise - The value or promise
250 * @param transformer - A function that maps the source value to a value or promise
251 */
252function transformValueOrPromise(valueOrPromise, transformer) {
253 if (isPromiseLike(valueOrPromise)) {
254 return valueOrPromise.then(transformer);
255 }
256 else {
257 return transformer(valueOrPromise);
258 }
259}
260exports.transformValueOrPromise = transformValueOrPromise;
261/**
262 * A utility to generate uuid v4
263 *
264 * @deprecated Use `generateUniqueId`, [uuid](https://www.npmjs.com/package/uuid)
265 * or [hyperid](https://www.npmjs.com/package/hyperid) instead.
266 */
267function uuid() {
268 return (0, uuid_1.v4)();
269}
270exports.uuid = uuid;
271/**
272 * A regular expression for testing uuid v4 PATTERN
273 * @deprecated This pattern is an internal helper used by unit-tests, we are no
274 * longer using it.
275 */
276exports.UUID_PATTERN = /[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/i;
277//# sourceMappingURL=value-promise.js.map
\No newline at end of file