@thirstie/thirstieservices 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +41 -0
- package/dist/bundle.cjs +2851 -0
- package/dist/bundle.iife.js +1 -0
- package/dist/bundle.mjs +2848 -0
- package/package.json +37 -0
- package/rollup.config.mjs +28 -0
- package/src/geoservice/index.js +232 -0
- package/src/index.js +7 -0
- package/src/thirstieapi/index.js +331 -0
- package/src/thirstieapi/utils/apirequest.js +34 -0
- package/tests/env.json.tpl +5 -0
- package/tests/fixtures/catalog.json +757 -0
- package/tests/fixtures/catalog_productline_offerings.json +689 -0
- package/tests/fixtures/google_autocomplete_response.json +281 -0
- package/tests/fixtures/google_autocomplete_response_withzip.json +75 -0
- package/tests/fixtures/google_placeid_details.json +104 -0
- package/tests/fixtures/guest_user.json +20 -0
- package/tests/fixtures/session_anonymous.json +8 -0
- package/tests/fixtures/user_addressbook.json +22 -0
- package/tests/fixtures/user_guest.json +20 -0
- package/tests/fixtures/user_loggedin.json +23 -0
- package/tests/fixtures/user_wallet.json +194 -0
- package/tests/functional/apirequest.func.test.js +46 -0
- package/tests/functional/geoservice.func.test.js +53 -0
- package/tests/integration/thirstieapi.int.test.js +89 -0
- package/tests/unit/geoservice.unit.test.js +367 -0
package/dist/bundle.mjs
ADDED
|
@@ -0,0 +1,2848 @@
|
|
|
1
|
+
async function apiRequest (url, requestConfig) {
|
|
2
|
+
const apiResponse = {
|
|
3
|
+
ok: null,
|
|
4
|
+
status: null,
|
|
5
|
+
statusText: null,
|
|
6
|
+
data: {}
|
|
7
|
+
};
|
|
8
|
+
try {
|
|
9
|
+
const response = await fetch(url, requestConfig);
|
|
10
|
+
|
|
11
|
+
let responseBody = {};
|
|
12
|
+
const headers = response.headers;
|
|
13
|
+
const hasBody = headers && headers.get('content-type')?.indexOf('application/json') > -1 && parseInt(headers.get('content-length')) > 0;
|
|
14
|
+
if (hasBody) {
|
|
15
|
+
responseBody = await response.json();
|
|
16
|
+
}
|
|
17
|
+
return Object.assign(apiResponse, {
|
|
18
|
+
ok: response.ok,
|
|
19
|
+
status: response.status,
|
|
20
|
+
statusText: response.statusText,
|
|
21
|
+
data: responseBody,
|
|
22
|
+
url
|
|
23
|
+
});
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error('apiRequest error: ', error);
|
|
26
|
+
return Object.assign(apiResponse, {
|
|
27
|
+
ok: false,
|
|
28
|
+
status: 500,
|
|
29
|
+
statusText: 'ERROR',
|
|
30
|
+
data: { message: 'Network error', error },
|
|
31
|
+
url
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Access Thirstie API and manage session information.
|
|
38
|
+
*/
|
|
39
|
+
class ThirstieAPI {
|
|
40
|
+
// private fields
|
|
41
|
+
#apiKey;
|
|
42
|
+
#thirstieApiBaseUrl;
|
|
43
|
+
#_apiState;
|
|
44
|
+
#emptyState;
|
|
45
|
+
#environment;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize Thirstie API with public api key
|
|
49
|
+
* @param {string} apiKey - The public basic auth key, defines application access
|
|
50
|
+
* @param {Object=} config - Optional config settings
|
|
51
|
+
* @param {Object} config.env - Set to 'prod' to use production environment
|
|
52
|
+
* @param {Object} config.initState - Values to initialize session state
|
|
53
|
+
*/
|
|
54
|
+
constructor (apiKey, config = {}) {
|
|
55
|
+
const { env, initState } = config;
|
|
56
|
+
this.#environment = env;
|
|
57
|
+
this.#emptyState = {
|
|
58
|
+
sessionToken: null,
|
|
59
|
+
application: null,
|
|
60
|
+
applicationRef: null,
|
|
61
|
+
sessionRef: null,
|
|
62
|
+
userRef: null,
|
|
63
|
+
user: {},
|
|
64
|
+
message: null
|
|
65
|
+
};
|
|
66
|
+
this.#apiKey = apiKey;
|
|
67
|
+
this.#thirstieApiBaseUrl =
|
|
68
|
+
env === 'prod'
|
|
69
|
+
? 'https://api.thirstie.com'
|
|
70
|
+
: 'https://api.next.thirstie.com';
|
|
71
|
+
|
|
72
|
+
this.#_apiState = Object.seal(this.#emptyState);
|
|
73
|
+
const { sessionToken, application, applicationRef, sessionRef, userRef } = initState || {};
|
|
74
|
+
if (sessionToken || application || applicationRef || sessionRef || userRef) {
|
|
75
|
+
const apiInitState = { sessionToken, application, applicationRef, sessionRef, userRef };
|
|
76
|
+
this.apiState = apiInitState;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get sessionToken () {
|
|
81
|
+
return this.#_apiState.sessionToken;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get sessionRef () {
|
|
85
|
+
return this.#_apiState.sessionRef;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get userRef () {
|
|
89
|
+
return this.#_apiState.userRef;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get applicationRef () {
|
|
93
|
+
return this.#_apiState.applicationRef;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get application () {
|
|
97
|
+
return this.#_apiState.application;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Getter for session state
|
|
102
|
+
* This is safe to use for persisting state in localstorage
|
|
103
|
+
* because it does not contain user information.
|
|
104
|
+
*/
|
|
105
|
+
get sessionState () {
|
|
106
|
+
const {
|
|
107
|
+
sessionToken, application, applicationRef, sessionRef, userRef
|
|
108
|
+
} = this.#_apiState;
|
|
109
|
+
return { sessionToken, application, applicationRef, sessionRef, userRef };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Getter for general api state, contains user information
|
|
114
|
+
* Only use for internal comparison.
|
|
115
|
+
*/
|
|
116
|
+
get apiState () {
|
|
117
|
+
return this.#_apiState;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
set apiState (props) {
|
|
121
|
+
try {
|
|
122
|
+
return Object.assign(this.#_apiState, props);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error('set apiState', error);
|
|
125
|
+
return this.#_apiState;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
#handleSession (data) {
|
|
130
|
+
const sessionData = {
|
|
131
|
+
application: data.application_name,
|
|
132
|
+
applicationRef: data.uuid,
|
|
133
|
+
sessionToken: data.token,
|
|
134
|
+
sessionRef: data.session_uuid
|
|
135
|
+
};
|
|
136
|
+
if (data.user) {
|
|
137
|
+
sessionData.userRef = data.user.id;
|
|
138
|
+
const {
|
|
139
|
+
birthday, email, prefix, guest,
|
|
140
|
+
first_name: firstName, last_name: lastName, phone_number: phoneNumber,
|
|
141
|
+
last_login: lastLogin
|
|
142
|
+
} = data.user;
|
|
143
|
+
sessionData.user = {
|
|
144
|
+
email, birthday, prefix, firstName, lastName, phoneNumber, guest, lastLogin
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
this.apiState = sessionData;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#handleSessionError (err) {
|
|
151
|
+
this.apiState = this.#emptyState;
|
|
152
|
+
console.log('session error', err);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create a new session and retrieve a bearer token.
|
|
157
|
+
*
|
|
158
|
+
* Defaults to creating an anonymous session. If userCredentials are
|
|
159
|
+
* provided, then a user session will be returned.
|
|
160
|
+
*
|
|
161
|
+
* @param {Object=} userCredentials - user email & password
|
|
162
|
+
* @param {string} userCredentials.email
|
|
163
|
+
* @param {string} userCredentials.password
|
|
164
|
+
* @param {boolean} [basicAuth=true] - force use of application basic auth
|
|
165
|
+
* @returns {response}
|
|
166
|
+
*/
|
|
167
|
+
async getNewSession (userCredentials = {}, basicAuth = true) {
|
|
168
|
+
const { email, password } = userCredentials;
|
|
169
|
+
const options = { basicAuth };
|
|
170
|
+
if (email && password) {
|
|
171
|
+
options.data = { email, password };
|
|
172
|
+
}
|
|
173
|
+
const url = '/a/v2/sessions';
|
|
174
|
+
const response = await this.apiCaller('POST', url, options);
|
|
175
|
+
if (response && response.ok && response.data) {
|
|
176
|
+
return response.data;
|
|
177
|
+
} else {
|
|
178
|
+
return { code: response.status, message: response.message || 'unknown error', response };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Validate an existing session
|
|
184
|
+
* @param {string} sessionToken - Session JWT to validate
|
|
185
|
+
* @returns {object} session response
|
|
186
|
+
*/
|
|
187
|
+
async validateSession (sessionToken) {
|
|
188
|
+
if (sessionToken) {
|
|
189
|
+
this.apiState = { sessionToken };
|
|
190
|
+
}
|
|
191
|
+
if (!this.sessionToken) {
|
|
192
|
+
return {};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const url = '/a/v2/sessions';
|
|
196
|
+
const response = await this.apiCaller('GET', url);
|
|
197
|
+
if (response && response.ok && response.data) {
|
|
198
|
+
return response.data;
|
|
199
|
+
} else {
|
|
200
|
+
return await this.getNewSession();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create new session, or validates existing session and set apiState
|
|
206
|
+
* @param {string} [existingToken] If provided, session JWT to be validated
|
|
207
|
+
* @returns {object} API State
|
|
208
|
+
*/
|
|
209
|
+
async fetchSession (existingToken = null) {
|
|
210
|
+
let sessionData = {};
|
|
211
|
+
if (!this.sessionToken && !existingToken) {
|
|
212
|
+
sessionData = await this.getNewSession();
|
|
213
|
+
} else {
|
|
214
|
+
sessionData = await this.validateSession(existingToken);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (sessionData.token) {
|
|
218
|
+
this.#handleSession(sessionData);
|
|
219
|
+
} else {
|
|
220
|
+
this.#handleSessionError(sessionData);
|
|
221
|
+
}
|
|
222
|
+
return this.apiState;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Convert an anonymous session to a user session
|
|
227
|
+
* @param {object} userCredentials - { email, password }
|
|
228
|
+
* @returns {object} - api state
|
|
229
|
+
*/
|
|
230
|
+
async loginUser (userCredentials) {
|
|
231
|
+
const { email, password } = userCredentials;
|
|
232
|
+
|
|
233
|
+
// force use of existing anonymous session token if a token exists
|
|
234
|
+
const basicAuth = !this.sessionToken;
|
|
235
|
+
if (email && password) ; else {
|
|
236
|
+
throw new Error('Invalid credential payload');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const responseData = await this.getNewSession(userCredentials, basicAuth);
|
|
240
|
+
if (responseData.token) {
|
|
241
|
+
this.#handleSession(responseData);
|
|
242
|
+
} else {
|
|
243
|
+
this.#handleSessionError(responseData);
|
|
244
|
+
const { response } = responseData;
|
|
245
|
+
const { data } = response;
|
|
246
|
+
if (data?.message) {
|
|
247
|
+
this.apiState.message = data?.message;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return this.apiState;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create a new user
|
|
255
|
+
* @param {object} userData - { email, password, birthday, prefix, firstName, lastName, phoneNumber, guestCheck }
|
|
256
|
+
* @param {Function} [errorHandler] - optional error callback
|
|
257
|
+
* @returns {object} - api state
|
|
258
|
+
*/
|
|
259
|
+
async createUser (userData, errorHandler = null) {
|
|
260
|
+
const options = {};
|
|
261
|
+
const { email, password } = userData;
|
|
262
|
+
const { birthday, prefix, firstName, lastName, phoneNumber, guestCheck, emailOptIn } = userData;
|
|
263
|
+
const requestPayload = {
|
|
264
|
+
email,
|
|
265
|
+
birthday,
|
|
266
|
+
prefix,
|
|
267
|
+
first_name: firstName,
|
|
268
|
+
last_name: lastName,
|
|
269
|
+
phone_number: phoneNumber,
|
|
270
|
+
guest_check: !!guestCheck // "allow guest checkout for existing user" if set to True
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
if (emailOptIn) {
|
|
274
|
+
requestPayload.aux_data = {
|
|
275
|
+
thirstieaccess_email_opt_in: emailOptIn
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// force use of existing anonymous session token if a token exists
|
|
280
|
+
const basicAuth = !this.sessionToken;
|
|
281
|
+
if (email && password) {
|
|
282
|
+
requestPayload.password = password;
|
|
283
|
+
} else {
|
|
284
|
+
requestPayload.guest = true;
|
|
285
|
+
}
|
|
286
|
+
options.data = requestPayload;
|
|
287
|
+
options.basicAuth = basicAuth;
|
|
288
|
+
|
|
289
|
+
const responseData = await this.apiCaller('POST', '/a/v2/users', options, errorHandler);
|
|
290
|
+
if (responseData.data.token) {
|
|
291
|
+
this.#handleSession(responseData.data);
|
|
292
|
+
} else {
|
|
293
|
+
this.#handleSessionError(responseData);
|
|
294
|
+
}
|
|
295
|
+
return this.apiState;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Invoke Thirstie API Endpoint
|
|
300
|
+
* @param {string} method - 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'
|
|
301
|
+
* @param {string} url - api endpoint url
|
|
302
|
+
* @param {object} [options] - { data, params, basicAuth }
|
|
303
|
+
* @param {callback} [errorHandler] - error callback
|
|
304
|
+
* @returns {object} - api response
|
|
305
|
+
*/
|
|
306
|
+
async apiCaller (method, url, options = {}, errorHandler = null) {
|
|
307
|
+
const { data, params, basicAuth } = options;
|
|
308
|
+
const { sessionRef, application, applicationRef, userRef } = this.apiState;
|
|
309
|
+
|
|
310
|
+
if (!this.sessionToken && !basicAuth) {
|
|
311
|
+
throw new Error('Invalid Authorization');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const authHeader = (this.sessionToken && !basicAuth)
|
|
315
|
+
? `Bearer ${this.sessionToken}`
|
|
316
|
+
: `Basic ${btoa(this.#apiKey)}`;
|
|
317
|
+
|
|
318
|
+
const requestConfig = {
|
|
319
|
+
method,
|
|
320
|
+
headers: {
|
|
321
|
+
Authorization: authHeader,
|
|
322
|
+
Accept: 'application/json',
|
|
323
|
+
'Content-Type': 'application/json'
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
if ([ 'POST', 'PUT', 'PATCH' ].includes(method) && !!data) {
|
|
327
|
+
requestConfig.body = JSON.stringify(data);
|
|
328
|
+
}
|
|
329
|
+
let queryString = '';
|
|
330
|
+
if (params) {
|
|
331
|
+
const searchParams = new URLSearchParams(params);
|
|
332
|
+
queryString = searchParams.toString();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const telemetryContext = {
|
|
336
|
+
environment: this.#environment,
|
|
337
|
+
sessionRef,
|
|
338
|
+
application,
|
|
339
|
+
applicationRef,
|
|
340
|
+
userRef,
|
|
341
|
+
data,
|
|
342
|
+
queryString,
|
|
343
|
+
url
|
|
344
|
+
};
|
|
345
|
+
const requestUrl = `${this.#thirstieApiBaseUrl}${url}${queryString}`;
|
|
346
|
+
try {
|
|
347
|
+
const response = await apiRequest(requestUrl, requestConfig);
|
|
348
|
+
if (response) {
|
|
349
|
+
if (!response.ok && errorHandler) {
|
|
350
|
+
errorHandler({ code: response.status, message: response.statusText || 'unknown error', response, telemetryContext });
|
|
351
|
+
}
|
|
352
|
+
return response;
|
|
353
|
+
}
|
|
354
|
+
} catch (error) {
|
|
355
|
+
if (errorHandler) {
|
|
356
|
+
errorHandler({ code: 500, message: 'unknown error', error, telemetryContext });
|
|
357
|
+
}
|
|
358
|
+
return error;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function _isPlaceholder(a) {
|
|
364
|
+
return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Optimized internal one-arity curry function.
|
|
369
|
+
*
|
|
370
|
+
* @private
|
|
371
|
+
* @category Function
|
|
372
|
+
* @param {Function} fn The function to curry.
|
|
373
|
+
* @return {Function} The curried function.
|
|
374
|
+
*/
|
|
375
|
+
|
|
376
|
+
function _curry1(fn) {
|
|
377
|
+
return function f1(a) {
|
|
378
|
+
if (arguments.length === 0 || _isPlaceholder(a)) {
|
|
379
|
+
return f1;
|
|
380
|
+
} else {
|
|
381
|
+
return fn.apply(this, arguments);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Optimized internal two-arity curry function.
|
|
388
|
+
*
|
|
389
|
+
* @private
|
|
390
|
+
* @category Function
|
|
391
|
+
* @param {Function} fn The function to curry.
|
|
392
|
+
* @return {Function} The curried function.
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
function _curry2(fn) {
|
|
396
|
+
return function f2(a, b) {
|
|
397
|
+
switch (arguments.length) {
|
|
398
|
+
case 0:
|
|
399
|
+
return f2;
|
|
400
|
+
|
|
401
|
+
case 1:
|
|
402
|
+
return _isPlaceholder(a) ? f2 : _curry1(function (_b) {
|
|
403
|
+
return fn(a, _b);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
default:
|
|
407
|
+
return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) {
|
|
408
|
+
return fn(_a, b);
|
|
409
|
+
}) : _isPlaceholder(b) ? _curry1(function (_b) {
|
|
410
|
+
return fn(a, _b);
|
|
411
|
+
}) : fn(a, b);
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function _arity(n, fn) {
|
|
417
|
+
/* eslint-disable no-unused-vars */
|
|
418
|
+
switch (n) {
|
|
419
|
+
case 0:
|
|
420
|
+
return function () {
|
|
421
|
+
return fn.apply(this, arguments);
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
case 1:
|
|
425
|
+
return function (a0) {
|
|
426
|
+
return fn.apply(this, arguments);
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
case 2:
|
|
430
|
+
return function (a0, a1) {
|
|
431
|
+
return fn.apply(this, arguments);
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
case 3:
|
|
435
|
+
return function (a0, a1, a2) {
|
|
436
|
+
return fn.apply(this, arguments);
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
case 4:
|
|
440
|
+
return function (a0, a1, a2, a3) {
|
|
441
|
+
return fn.apply(this, arguments);
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
case 5:
|
|
445
|
+
return function (a0, a1, a2, a3, a4) {
|
|
446
|
+
return fn.apply(this, arguments);
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
case 6:
|
|
450
|
+
return function (a0, a1, a2, a3, a4, a5) {
|
|
451
|
+
return fn.apply(this, arguments);
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
case 7:
|
|
455
|
+
return function (a0, a1, a2, a3, a4, a5, a6) {
|
|
456
|
+
return fn.apply(this, arguments);
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
case 8:
|
|
460
|
+
return function (a0, a1, a2, a3, a4, a5, a6, a7) {
|
|
461
|
+
return fn.apply(this, arguments);
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
case 9:
|
|
465
|
+
return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) {
|
|
466
|
+
return fn.apply(this, arguments);
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
case 10:
|
|
470
|
+
return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
|
|
471
|
+
return fn.apply(this, arguments);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
default:
|
|
475
|
+
throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Internal curryN function.
|
|
481
|
+
*
|
|
482
|
+
* @private
|
|
483
|
+
* @category Function
|
|
484
|
+
* @param {Number} length The arity of the curried function.
|
|
485
|
+
* @param {Array} received An array of arguments received thus far.
|
|
486
|
+
* @param {Function} fn The function to curry.
|
|
487
|
+
* @return {Function} The curried function.
|
|
488
|
+
*/
|
|
489
|
+
|
|
490
|
+
function _curryN(length, received, fn) {
|
|
491
|
+
return function () {
|
|
492
|
+
var combined = [];
|
|
493
|
+
var argsIdx = 0;
|
|
494
|
+
var left = length;
|
|
495
|
+
var combinedIdx = 0;
|
|
496
|
+
var hasPlaceholder = false;
|
|
497
|
+
|
|
498
|
+
while (combinedIdx < received.length || argsIdx < arguments.length) {
|
|
499
|
+
var result;
|
|
500
|
+
|
|
501
|
+
if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) {
|
|
502
|
+
result = received[combinedIdx];
|
|
503
|
+
} else {
|
|
504
|
+
result = arguments[argsIdx];
|
|
505
|
+
argsIdx += 1;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
combined[combinedIdx] = result;
|
|
509
|
+
|
|
510
|
+
if (!_isPlaceholder(result)) {
|
|
511
|
+
left -= 1;
|
|
512
|
+
} else {
|
|
513
|
+
hasPlaceholder = true;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
combinedIdx += 1;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return !hasPlaceholder && left <= 0 ? fn.apply(this, combined) : _arity(Math.max(0, left), _curryN(length, combined, fn));
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Returns a curried equivalent of the provided function, with the specified
|
|
525
|
+
* arity. The curried function has two unusual capabilities. First, its
|
|
526
|
+
* arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the
|
|
527
|
+
* following are equivalent:
|
|
528
|
+
*
|
|
529
|
+
* - `g(1)(2)(3)`
|
|
530
|
+
* - `g(1)(2, 3)`
|
|
531
|
+
* - `g(1, 2)(3)`
|
|
532
|
+
* - `g(1, 2, 3)`
|
|
533
|
+
*
|
|
534
|
+
* Secondly, the special placeholder value [`R.__`](#__) may be used to specify
|
|
535
|
+
* "gaps", allowing partial application of any combination of arguments,
|
|
536
|
+
* regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
|
|
537
|
+
* the following are equivalent:
|
|
538
|
+
*
|
|
539
|
+
* - `g(1, 2, 3)`
|
|
540
|
+
* - `g(_, 2, 3)(1)`
|
|
541
|
+
* - `g(_, _, 3)(1)(2)`
|
|
542
|
+
* - `g(_, _, 3)(1, 2)`
|
|
543
|
+
* - `g(_, 2)(1)(3)`
|
|
544
|
+
* - `g(_, 2)(1, 3)`
|
|
545
|
+
* - `g(_, 2)(_, 3)(1)`
|
|
546
|
+
*
|
|
547
|
+
* @func
|
|
548
|
+
* @memberOf R
|
|
549
|
+
* @since v0.5.0
|
|
550
|
+
* @category Function
|
|
551
|
+
* @sig Number -> (* -> a) -> (* -> a)
|
|
552
|
+
* @param {Number} length The arity for the returned function.
|
|
553
|
+
* @param {Function} fn The function to curry.
|
|
554
|
+
* @return {Function} A new, curried function.
|
|
555
|
+
* @see R.curry
|
|
556
|
+
* @example
|
|
557
|
+
*
|
|
558
|
+
* const sumArgs = (...args) => R.sum(args);
|
|
559
|
+
*
|
|
560
|
+
* const curriedAddFourNumbers = R.curryN(4, sumArgs);
|
|
561
|
+
* const f = curriedAddFourNumbers(1, 2);
|
|
562
|
+
* const g = f(3);
|
|
563
|
+
* g(4); //=> 10
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
var curryN =
|
|
567
|
+
/*#__PURE__*/
|
|
568
|
+
_curry2(function curryN(length, fn) {
|
|
569
|
+
if (length === 1) {
|
|
570
|
+
return _curry1(fn);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return _arity(length, _curryN(length, [], fn));
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Optimized internal three-arity curry function.
|
|
578
|
+
*
|
|
579
|
+
* @private
|
|
580
|
+
* @category Function
|
|
581
|
+
* @param {Function} fn The function to curry.
|
|
582
|
+
* @return {Function} The curried function.
|
|
583
|
+
*/
|
|
584
|
+
|
|
585
|
+
function _curry3(fn) {
|
|
586
|
+
return function f3(a, b, c) {
|
|
587
|
+
switch (arguments.length) {
|
|
588
|
+
case 0:
|
|
589
|
+
return f3;
|
|
590
|
+
|
|
591
|
+
case 1:
|
|
592
|
+
return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) {
|
|
593
|
+
return fn(a, _b, _c);
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
case 2:
|
|
597
|
+
return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) {
|
|
598
|
+
return fn(_a, b, _c);
|
|
599
|
+
}) : _isPlaceholder(b) ? _curry2(function (_b, _c) {
|
|
600
|
+
return fn(a, _b, _c);
|
|
601
|
+
}) : _curry1(function (_c) {
|
|
602
|
+
return fn(a, b, _c);
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
default:
|
|
606
|
+
return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) {
|
|
607
|
+
return fn(_a, _b, c);
|
|
608
|
+
}) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) {
|
|
609
|
+
return fn(_a, b, _c);
|
|
610
|
+
}) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) {
|
|
611
|
+
return fn(a, _b, _c);
|
|
612
|
+
}) : _isPlaceholder(a) ? _curry1(function (_a) {
|
|
613
|
+
return fn(_a, b, c);
|
|
614
|
+
}) : _isPlaceholder(b) ? _curry1(function (_b) {
|
|
615
|
+
return fn(a, _b, c);
|
|
616
|
+
}) : _isPlaceholder(c) ? _curry1(function (_c) {
|
|
617
|
+
return fn(a, b, _c);
|
|
618
|
+
}) : fn(a, b, c);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Tests whether or not an object is an array.
|
|
625
|
+
*
|
|
626
|
+
* @private
|
|
627
|
+
* @param {*} val The object to test.
|
|
628
|
+
* @return {Boolean} `true` if `val` is an array, `false` otherwise.
|
|
629
|
+
* @example
|
|
630
|
+
*
|
|
631
|
+
* _isArray([]); //=> true
|
|
632
|
+
* _isArray(null); //=> false
|
|
633
|
+
* _isArray({}); //=> false
|
|
634
|
+
*/
|
|
635
|
+
var _isArray = Array.isArray || function _isArray(val) {
|
|
636
|
+
return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]';
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
function _isTransformer(obj) {
|
|
640
|
+
return obj != null && typeof obj['@@transducer/step'] === 'function';
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Returns a function that dispatches with different strategies based on the
|
|
645
|
+
* object in list position (last argument). If it is an array, executes [fn].
|
|
646
|
+
* Otherwise, if it has a function with one of the given method names, it will
|
|
647
|
+
* execute that function (functor case). Otherwise, if it is a transformer,
|
|
648
|
+
* uses transducer created by [transducerCreator] to return a new transformer
|
|
649
|
+
* (transducer case).
|
|
650
|
+
* Otherwise, it will default to executing [fn].
|
|
651
|
+
*
|
|
652
|
+
* @private
|
|
653
|
+
* @param {Array} methodNames properties to check for a custom implementation
|
|
654
|
+
* @param {Function} transducerCreator transducer factory if object is transformer
|
|
655
|
+
* @param {Function} fn default ramda implementation
|
|
656
|
+
* @return {Function} A function that dispatches on object in list position
|
|
657
|
+
*/
|
|
658
|
+
|
|
659
|
+
function _dispatchable(methodNames, transducerCreator, fn) {
|
|
660
|
+
return function () {
|
|
661
|
+
if (arguments.length === 0) {
|
|
662
|
+
return fn();
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
var obj = arguments[arguments.length - 1];
|
|
666
|
+
|
|
667
|
+
if (!_isArray(obj)) {
|
|
668
|
+
var idx = 0;
|
|
669
|
+
|
|
670
|
+
while (idx < methodNames.length) {
|
|
671
|
+
if (typeof obj[methodNames[idx]] === 'function') {
|
|
672
|
+
return obj[methodNames[idx]].apply(obj, Array.prototype.slice.call(arguments, 0, -1));
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
idx += 1;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (_isTransformer(obj)) {
|
|
679
|
+
var transducer = transducerCreator.apply(null, Array.prototype.slice.call(arguments, 0, -1));
|
|
680
|
+
return transducer(obj);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return fn.apply(this, arguments);
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function _reduced(x) {
|
|
689
|
+
return x && x['@@transducer/reduced'] ? x : {
|
|
690
|
+
'@@transducer/value': x,
|
|
691
|
+
'@@transducer/reduced': true
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
var _xfBase = {
|
|
696
|
+
init: function () {
|
|
697
|
+
return this.xf['@@transducer/init']();
|
|
698
|
+
},
|
|
699
|
+
result: function (result) {
|
|
700
|
+
return this.xf['@@transducer/result'](result);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
function _arrayFromIterator(iter) {
|
|
705
|
+
var list = [];
|
|
706
|
+
var next;
|
|
707
|
+
|
|
708
|
+
while (!(next = iter.next()).done) {
|
|
709
|
+
list.push(next.value);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
return list;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function _includesWith(pred, x, list) {
|
|
716
|
+
var idx = 0;
|
|
717
|
+
var len = list.length;
|
|
718
|
+
|
|
719
|
+
while (idx < len) {
|
|
720
|
+
if (pred(x, list[idx])) {
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
idx += 1;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function _functionName(f) {
|
|
731
|
+
// String(x => x) evaluates to "x => x", so the pattern may not match.
|
|
732
|
+
var match = String(f).match(/^function (\w*)/);
|
|
733
|
+
return match == null ? '' : match[1];
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function _has(prop, obj) {
|
|
737
|
+
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
|
741
|
+
function _objectIs(a, b) {
|
|
742
|
+
// SameValue algorithm
|
|
743
|
+
if (a === b) {
|
|
744
|
+
// Steps 1-5, 7-10
|
|
745
|
+
// Steps 6.b-6.e: +0 != -0
|
|
746
|
+
return a !== 0 || 1 / a === 1 / b;
|
|
747
|
+
} else {
|
|
748
|
+
// Step 6.a: NaN == NaN
|
|
749
|
+
return a !== a && b !== b;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
var _objectIs$1 = typeof Object.is === 'function' ? Object.is : _objectIs;
|
|
754
|
+
|
|
755
|
+
var toString$1 = Object.prototype.toString;
|
|
756
|
+
|
|
757
|
+
var _isArguments =
|
|
758
|
+
/*#__PURE__*/
|
|
759
|
+
function () {
|
|
760
|
+
return toString$1.call(arguments) === '[object Arguments]' ? function _isArguments(x) {
|
|
761
|
+
return toString$1.call(x) === '[object Arguments]';
|
|
762
|
+
} : function _isArguments(x) {
|
|
763
|
+
return _has('callee', x);
|
|
764
|
+
};
|
|
765
|
+
}();
|
|
766
|
+
|
|
767
|
+
var hasEnumBug = !
|
|
768
|
+
/*#__PURE__*/
|
|
769
|
+
{
|
|
770
|
+
toString: null
|
|
771
|
+
}.propertyIsEnumerable('toString');
|
|
772
|
+
var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; // Safari bug
|
|
773
|
+
|
|
774
|
+
var hasArgsEnumBug =
|
|
775
|
+
/*#__PURE__*/
|
|
776
|
+
function () {
|
|
777
|
+
|
|
778
|
+
return arguments.propertyIsEnumerable('length');
|
|
779
|
+
}();
|
|
780
|
+
|
|
781
|
+
var contains = function contains(list, item) {
|
|
782
|
+
var idx = 0;
|
|
783
|
+
|
|
784
|
+
while (idx < list.length) {
|
|
785
|
+
if (list[idx] === item) {
|
|
786
|
+
return true;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
idx += 1;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
return false;
|
|
793
|
+
};
|
|
794
|
+
/**
|
|
795
|
+
* Returns a list containing the names of all the enumerable own properties of
|
|
796
|
+
* the supplied object.
|
|
797
|
+
* Note that the order of the output array is not guaranteed to be consistent
|
|
798
|
+
* across different JS platforms.
|
|
799
|
+
*
|
|
800
|
+
* @func
|
|
801
|
+
* @memberOf R
|
|
802
|
+
* @since v0.1.0
|
|
803
|
+
* @category Object
|
|
804
|
+
* @sig {k: v} -> [k]
|
|
805
|
+
* @param {Object} obj The object to extract properties from
|
|
806
|
+
* @return {Array} An array of the object's own properties.
|
|
807
|
+
* @see R.keysIn, R.values, R.toPairs
|
|
808
|
+
* @example
|
|
809
|
+
*
|
|
810
|
+
* R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c']
|
|
811
|
+
*/
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
var keys = typeof Object.keys === 'function' && !hasArgsEnumBug ?
|
|
815
|
+
/*#__PURE__*/
|
|
816
|
+
_curry1(function keys(obj) {
|
|
817
|
+
return Object(obj) !== obj ? [] : Object.keys(obj);
|
|
818
|
+
}) :
|
|
819
|
+
/*#__PURE__*/
|
|
820
|
+
_curry1(function keys(obj) {
|
|
821
|
+
if (Object(obj) !== obj) {
|
|
822
|
+
return [];
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
var prop, nIdx;
|
|
826
|
+
var ks = [];
|
|
827
|
+
|
|
828
|
+
var checkArgsLength = hasArgsEnumBug && _isArguments(obj);
|
|
829
|
+
|
|
830
|
+
for (prop in obj) {
|
|
831
|
+
if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
|
|
832
|
+
ks[ks.length] = prop;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
if (hasEnumBug) {
|
|
837
|
+
nIdx = nonEnumerableProps.length - 1;
|
|
838
|
+
|
|
839
|
+
while (nIdx >= 0) {
|
|
840
|
+
prop = nonEnumerableProps[nIdx];
|
|
841
|
+
|
|
842
|
+
if (_has(prop, obj) && !contains(ks, prop)) {
|
|
843
|
+
ks[ks.length] = prop;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
nIdx -= 1;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return ks;
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Gives a single-word string description of the (native) type of a value,
|
|
855
|
+
* returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not
|
|
856
|
+
* attempt to distinguish user Object types any further, reporting them all as
|
|
857
|
+
* 'Object'.
|
|
858
|
+
*
|
|
859
|
+
* @func
|
|
860
|
+
* @memberOf R
|
|
861
|
+
* @since v0.8.0
|
|
862
|
+
* @category Type
|
|
863
|
+
* @sig * -> String
|
|
864
|
+
* @param {*} val The value to test
|
|
865
|
+
* @return {String}
|
|
866
|
+
* @example
|
|
867
|
+
*
|
|
868
|
+
* R.type({}); //=> "Object"
|
|
869
|
+
* R.type(1); //=> "Number"
|
|
870
|
+
* R.type(false); //=> "Boolean"
|
|
871
|
+
* R.type('s'); //=> "String"
|
|
872
|
+
* R.type(null); //=> "Null"
|
|
873
|
+
* R.type([]); //=> "Array"
|
|
874
|
+
* R.type(/[A-z]/); //=> "RegExp"
|
|
875
|
+
* R.type(() => {}); //=> "Function"
|
|
876
|
+
* R.type(async () => {}); //=> "AsyncFunction"
|
|
877
|
+
* R.type(undefined); //=> "Undefined"
|
|
878
|
+
*/
|
|
879
|
+
|
|
880
|
+
var type =
|
|
881
|
+
/*#__PURE__*/
|
|
882
|
+
_curry1(function type(val) {
|
|
883
|
+
return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* private _uniqContentEquals function.
|
|
888
|
+
* That function is checking equality of 2 iterator contents with 2 assumptions
|
|
889
|
+
* - iterators lengths are the same
|
|
890
|
+
* - iterators values are unique
|
|
891
|
+
*
|
|
892
|
+
* false-positive result will be returned for comparison of, e.g.
|
|
893
|
+
* - [1,2,3] and [1,2,3,4]
|
|
894
|
+
* - [1,1,1] and [1,2,3]
|
|
895
|
+
* */
|
|
896
|
+
|
|
897
|
+
function _uniqContentEquals(aIterator, bIterator, stackA, stackB) {
|
|
898
|
+
var a = _arrayFromIterator(aIterator);
|
|
899
|
+
|
|
900
|
+
var b = _arrayFromIterator(bIterator);
|
|
901
|
+
|
|
902
|
+
function eq(_a, _b) {
|
|
903
|
+
return _equals(_a, _b, stackA.slice(), stackB.slice());
|
|
904
|
+
} // if *a* array contains any element that is not included in *b*
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
return !_includesWith(function (b, aItem) {
|
|
908
|
+
return !_includesWith(eq, aItem, b);
|
|
909
|
+
}, b, a);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
function _equals(a, b, stackA, stackB) {
|
|
913
|
+
if (_objectIs$1(a, b)) {
|
|
914
|
+
return true;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
var typeA = type(a);
|
|
918
|
+
|
|
919
|
+
if (typeA !== type(b)) {
|
|
920
|
+
return false;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') {
|
|
924
|
+
return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
if (typeof a.equals === 'function' || typeof b.equals === 'function') {
|
|
928
|
+
return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
switch (typeA) {
|
|
932
|
+
case 'Arguments':
|
|
933
|
+
case 'Array':
|
|
934
|
+
case 'Object':
|
|
935
|
+
if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') {
|
|
936
|
+
return a === b;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
break;
|
|
940
|
+
|
|
941
|
+
case 'Boolean':
|
|
942
|
+
case 'Number':
|
|
943
|
+
case 'String':
|
|
944
|
+
if (!(typeof a === typeof b && _objectIs$1(a.valueOf(), b.valueOf()))) {
|
|
945
|
+
return false;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
break;
|
|
949
|
+
|
|
950
|
+
case 'Date':
|
|
951
|
+
if (!_objectIs$1(a.valueOf(), b.valueOf())) {
|
|
952
|
+
return false;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
break;
|
|
956
|
+
|
|
957
|
+
case 'Error':
|
|
958
|
+
return a.name === b.name && a.message === b.message;
|
|
959
|
+
|
|
960
|
+
case 'RegExp':
|
|
961
|
+
if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) {
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
var idx = stackA.length - 1;
|
|
969
|
+
|
|
970
|
+
while (idx >= 0) {
|
|
971
|
+
if (stackA[idx] === a) {
|
|
972
|
+
return stackB[idx] === b;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
idx -= 1;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
switch (typeA) {
|
|
979
|
+
case 'Map':
|
|
980
|
+
if (a.size !== b.size) {
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b]));
|
|
985
|
+
|
|
986
|
+
case 'Set':
|
|
987
|
+
if (a.size !== b.size) {
|
|
988
|
+
return false;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b]));
|
|
992
|
+
|
|
993
|
+
case 'Arguments':
|
|
994
|
+
case 'Array':
|
|
995
|
+
case 'Object':
|
|
996
|
+
case 'Boolean':
|
|
997
|
+
case 'Number':
|
|
998
|
+
case 'String':
|
|
999
|
+
case 'Date':
|
|
1000
|
+
case 'Error':
|
|
1001
|
+
case 'RegExp':
|
|
1002
|
+
case 'Int8Array':
|
|
1003
|
+
case 'Uint8Array':
|
|
1004
|
+
case 'Uint8ClampedArray':
|
|
1005
|
+
case 'Int16Array':
|
|
1006
|
+
case 'Uint16Array':
|
|
1007
|
+
case 'Int32Array':
|
|
1008
|
+
case 'Uint32Array':
|
|
1009
|
+
case 'Float32Array':
|
|
1010
|
+
case 'Float64Array':
|
|
1011
|
+
case 'ArrayBuffer':
|
|
1012
|
+
break;
|
|
1013
|
+
|
|
1014
|
+
default:
|
|
1015
|
+
// Values of other types are only equal if identical.
|
|
1016
|
+
return false;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
var keysA = keys(a);
|
|
1020
|
+
|
|
1021
|
+
if (keysA.length !== keys(b).length) {
|
|
1022
|
+
return false;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
var extendedStackA = stackA.concat([a]);
|
|
1026
|
+
var extendedStackB = stackB.concat([b]);
|
|
1027
|
+
idx = keysA.length - 1;
|
|
1028
|
+
|
|
1029
|
+
while (idx >= 0) {
|
|
1030
|
+
var key = keysA[idx];
|
|
1031
|
+
|
|
1032
|
+
if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) {
|
|
1033
|
+
return false;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
idx -= 1;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Returns `true` if its arguments are equivalent, `false` otherwise. Handles
|
|
1044
|
+
* cyclical data structures.
|
|
1045
|
+
*
|
|
1046
|
+
* Dispatches symmetrically to the `equals` methods of both arguments, if
|
|
1047
|
+
* present.
|
|
1048
|
+
*
|
|
1049
|
+
* @func
|
|
1050
|
+
* @memberOf R
|
|
1051
|
+
* @since v0.15.0
|
|
1052
|
+
* @category Relation
|
|
1053
|
+
* @sig a -> b -> Boolean
|
|
1054
|
+
* @param {*} a
|
|
1055
|
+
* @param {*} b
|
|
1056
|
+
* @return {Boolean}
|
|
1057
|
+
* @example
|
|
1058
|
+
*
|
|
1059
|
+
* R.equals(1, 1); //=> true
|
|
1060
|
+
* R.equals(1, '1'); //=> false
|
|
1061
|
+
* R.equals([1, 2, 3], [1, 2, 3]); //=> true
|
|
1062
|
+
*
|
|
1063
|
+
* const a = {}; a.v = a;
|
|
1064
|
+
* const b = {}; b.v = b;
|
|
1065
|
+
* R.equals(a, b); //=> true
|
|
1066
|
+
*/
|
|
1067
|
+
|
|
1068
|
+
var equals =
|
|
1069
|
+
/*#__PURE__*/
|
|
1070
|
+
_curry2(function equals(a, b) {
|
|
1071
|
+
return _equals(a, b, [], []);
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
function _indexOf(list, a, idx) {
|
|
1075
|
+
var inf, item; // Array.prototype.indexOf doesn't exist below IE9
|
|
1076
|
+
|
|
1077
|
+
if (typeof list.indexOf === 'function') {
|
|
1078
|
+
switch (typeof a) {
|
|
1079
|
+
case 'number':
|
|
1080
|
+
if (a === 0) {
|
|
1081
|
+
// manually crawl the list to distinguish between +0 and -0
|
|
1082
|
+
inf = 1 / a;
|
|
1083
|
+
|
|
1084
|
+
while (idx < list.length) {
|
|
1085
|
+
item = list[idx];
|
|
1086
|
+
|
|
1087
|
+
if (item === 0 && 1 / item === inf) {
|
|
1088
|
+
return idx;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
idx += 1;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
return -1;
|
|
1095
|
+
} else if (a !== a) {
|
|
1096
|
+
// NaN
|
|
1097
|
+
while (idx < list.length) {
|
|
1098
|
+
item = list[idx];
|
|
1099
|
+
|
|
1100
|
+
if (typeof item === 'number' && item !== item) {
|
|
1101
|
+
return idx;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
idx += 1;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
return -1;
|
|
1108
|
+
} // non-zero numbers can utilise Set
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
return list.indexOf(a, idx);
|
|
1112
|
+
// all these types can utilise Set
|
|
1113
|
+
|
|
1114
|
+
case 'string':
|
|
1115
|
+
case 'boolean':
|
|
1116
|
+
case 'function':
|
|
1117
|
+
case 'undefined':
|
|
1118
|
+
return list.indexOf(a, idx);
|
|
1119
|
+
|
|
1120
|
+
case 'object':
|
|
1121
|
+
if (a === null) {
|
|
1122
|
+
// null can utilise Set
|
|
1123
|
+
return list.indexOf(a, idx);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
}
|
|
1127
|
+
} // anything else not covered above, defer to R.equals
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
while (idx < list.length) {
|
|
1131
|
+
if (equals(list[idx], a)) {
|
|
1132
|
+
return idx;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
idx += 1;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
return -1;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function _includes(a, list) {
|
|
1142
|
+
return _indexOf(list, a, 0) >= 0;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
function _map(fn, functor) {
|
|
1146
|
+
var idx = 0;
|
|
1147
|
+
var len = functor.length;
|
|
1148
|
+
var result = Array(len);
|
|
1149
|
+
|
|
1150
|
+
while (idx < len) {
|
|
1151
|
+
result[idx] = fn(functor[idx]);
|
|
1152
|
+
idx += 1;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
return result;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
function _quote(s) {
|
|
1159
|
+
var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace
|
|
1160
|
+
.replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0');
|
|
1161
|
+
return '"' + escaped.replace(/"/g, '\\"') + '"';
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Polyfill from <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>.
|
|
1166
|
+
*/
|
|
1167
|
+
var pad = function pad(n) {
|
|
1168
|
+
return (n < 10 ? '0' : '') + n;
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) {
|
|
1172
|
+
return d.toISOString();
|
|
1173
|
+
} : function _toISOString(d) {
|
|
1174
|
+
return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z';
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
function _complement(f) {
|
|
1178
|
+
return function () {
|
|
1179
|
+
return !f.apply(this, arguments);
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
function _arrayReduce(reducer, acc, list) {
|
|
1184
|
+
var index = 0;
|
|
1185
|
+
var length = list.length;
|
|
1186
|
+
|
|
1187
|
+
while (index < length) {
|
|
1188
|
+
acc = reducer(acc, list[index]);
|
|
1189
|
+
index += 1;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
return acc;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
function _filter(fn, list) {
|
|
1196
|
+
var idx = 0;
|
|
1197
|
+
var len = list.length;
|
|
1198
|
+
var result = [];
|
|
1199
|
+
|
|
1200
|
+
while (idx < len) {
|
|
1201
|
+
if (fn(list[idx])) {
|
|
1202
|
+
result[result.length] = list[idx];
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
idx += 1;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
return result;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
function _isObject(x) {
|
|
1212
|
+
return Object.prototype.toString.call(x) === '[object Object]';
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
var XFilter =
|
|
1216
|
+
/*#__PURE__*/
|
|
1217
|
+
function () {
|
|
1218
|
+
function XFilter(f, xf) {
|
|
1219
|
+
this.xf = xf;
|
|
1220
|
+
this.f = f;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
XFilter.prototype['@@transducer/init'] = _xfBase.init;
|
|
1224
|
+
XFilter.prototype['@@transducer/result'] = _xfBase.result;
|
|
1225
|
+
|
|
1226
|
+
XFilter.prototype['@@transducer/step'] = function (result, input) {
|
|
1227
|
+
return this.f(input) ? this.xf['@@transducer/step'](result, input) : result;
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1230
|
+
return XFilter;
|
|
1231
|
+
}();
|
|
1232
|
+
|
|
1233
|
+
function _xfilter(f) {
|
|
1234
|
+
return function (xf) {
|
|
1235
|
+
return new XFilter(f, xf);
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* Takes a predicate and a `Filterable`, and returns a new filterable of the
|
|
1241
|
+
* same type containing the members of the given filterable which satisfy the
|
|
1242
|
+
* given predicate. Filterable objects include plain objects or any object
|
|
1243
|
+
* that has a filter method such as `Array`.
|
|
1244
|
+
*
|
|
1245
|
+
* Dispatches to the `filter` method of the second argument, if present.
|
|
1246
|
+
*
|
|
1247
|
+
* Acts as a transducer if a transformer is given in list position.
|
|
1248
|
+
*
|
|
1249
|
+
* @func
|
|
1250
|
+
* @memberOf R
|
|
1251
|
+
* @since v0.1.0
|
|
1252
|
+
* @category List
|
|
1253
|
+
* @category Object
|
|
1254
|
+
* @sig Filterable f => (a -> Boolean) -> f a -> f a
|
|
1255
|
+
* @param {Function} pred
|
|
1256
|
+
* @param {Array} filterable
|
|
1257
|
+
* @return {Array} Filterable
|
|
1258
|
+
* @see R.reject, R.transduce, R.addIndex
|
|
1259
|
+
* @example
|
|
1260
|
+
*
|
|
1261
|
+
* const isEven = n => n % 2 === 0;
|
|
1262
|
+
*
|
|
1263
|
+
* R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4]
|
|
1264
|
+
*
|
|
1265
|
+
* R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
|
|
1266
|
+
*/
|
|
1267
|
+
|
|
1268
|
+
var filter =
|
|
1269
|
+
/*#__PURE__*/
|
|
1270
|
+
_curry2(
|
|
1271
|
+
/*#__PURE__*/
|
|
1272
|
+
_dispatchable(['fantasy-land/filter', 'filter'], _xfilter, function (pred, filterable) {
|
|
1273
|
+
return _isObject(filterable) ? _arrayReduce(function (acc, key) {
|
|
1274
|
+
if (pred(filterable[key])) {
|
|
1275
|
+
acc[key] = filterable[key];
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
return acc;
|
|
1279
|
+
}, {}, keys(filterable)) : // else
|
|
1280
|
+
_filter(pred, filterable);
|
|
1281
|
+
}));
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* The complement of [`filter`](#filter).
|
|
1285
|
+
*
|
|
1286
|
+
* Acts as a transducer if a transformer is given in list position. Filterable
|
|
1287
|
+
* objects include plain objects or any object that has a filter method such
|
|
1288
|
+
* as `Array`.
|
|
1289
|
+
*
|
|
1290
|
+
* @func
|
|
1291
|
+
* @memberOf R
|
|
1292
|
+
* @since v0.1.0
|
|
1293
|
+
* @category List
|
|
1294
|
+
* @sig Filterable f => (a -> Boolean) -> f a -> f a
|
|
1295
|
+
* @param {Function} pred
|
|
1296
|
+
* @param {Array} filterable
|
|
1297
|
+
* @return {Array}
|
|
1298
|
+
* @see R.filter, R.transduce, R.addIndex
|
|
1299
|
+
* @example
|
|
1300
|
+
*
|
|
1301
|
+
* const isOdd = (n) => n % 2 !== 0;
|
|
1302
|
+
*
|
|
1303
|
+
* R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4]
|
|
1304
|
+
*
|
|
1305
|
+
* R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
|
|
1306
|
+
*/
|
|
1307
|
+
|
|
1308
|
+
var reject =
|
|
1309
|
+
/*#__PURE__*/
|
|
1310
|
+
_curry2(function reject(pred, filterable) {
|
|
1311
|
+
return filter(_complement(pred), filterable);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
function _toString(x, seen) {
|
|
1315
|
+
var recur = function recur(y) {
|
|
1316
|
+
var xs = seen.concat([x]);
|
|
1317
|
+
return _includes(y, xs) ? '<Circular>' : _toString(y, xs);
|
|
1318
|
+
}; // mapPairs :: (Object, [String]) -> [String]
|
|
1319
|
+
|
|
1320
|
+
|
|
1321
|
+
var mapPairs = function (obj, keys) {
|
|
1322
|
+
return _map(function (k) {
|
|
1323
|
+
return _quote(k) + ': ' + recur(obj[k]);
|
|
1324
|
+
}, keys.slice().sort());
|
|
1325
|
+
};
|
|
1326
|
+
|
|
1327
|
+
switch (Object.prototype.toString.call(x)) {
|
|
1328
|
+
case '[object Arguments]':
|
|
1329
|
+
return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))';
|
|
1330
|
+
|
|
1331
|
+
case '[object Array]':
|
|
1332
|
+
return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) {
|
|
1333
|
+
return /^\d+$/.test(k);
|
|
1334
|
+
}, keys(x)))).join(', ') + ']';
|
|
1335
|
+
|
|
1336
|
+
case '[object Boolean]':
|
|
1337
|
+
return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString();
|
|
1338
|
+
|
|
1339
|
+
case '[object Date]':
|
|
1340
|
+
return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')';
|
|
1341
|
+
|
|
1342
|
+
case '[object Map]':
|
|
1343
|
+
return 'new Map(' + recur(Array.from(x)) + ')';
|
|
1344
|
+
|
|
1345
|
+
case '[object Null]':
|
|
1346
|
+
return 'null';
|
|
1347
|
+
|
|
1348
|
+
case '[object Number]':
|
|
1349
|
+
return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10);
|
|
1350
|
+
|
|
1351
|
+
case '[object Set]':
|
|
1352
|
+
return 'new Set(' + recur(Array.from(x).sort()) + ')';
|
|
1353
|
+
|
|
1354
|
+
case '[object String]':
|
|
1355
|
+
return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x);
|
|
1356
|
+
|
|
1357
|
+
case '[object Undefined]':
|
|
1358
|
+
return 'undefined';
|
|
1359
|
+
|
|
1360
|
+
default:
|
|
1361
|
+
if (typeof x.toString === 'function') {
|
|
1362
|
+
var repr = x.toString();
|
|
1363
|
+
|
|
1364
|
+
if (repr !== '[object Object]') {
|
|
1365
|
+
return repr;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return '{' + mapPairs(x, keys(x)).join(', ') + '}';
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
/**
|
|
1374
|
+
* Returns the string representation of the given value. `eval`'ing the output
|
|
1375
|
+
* should result in a value equivalent to the input value. Many of the built-in
|
|
1376
|
+
* `toString` methods do not satisfy this requirement.
|
|
1377
|
+
*
|
|
1378
|
+
* If the given value is an `[object Object]` with a `toString` method other
|
|
1379
|
+
* than `Object.prototype.toString`, this method is invoked with no arguments
|
|
1380
|
+
* to produce the return value. This means user-defined constructor functions
|
|
1381
|
+
* can provide a suitable `toString` method. For example:
|
|
1382
|
+
*
|
|
1383
|
+
* function Point(x, y) {
|
|
1384
|
+
* this.x = x;
|
|
1385
|
+
* this.y = y;
|
|
1386
|
+
* }
|
|
1387
|
+
*
|
|
1388
|
+
* Point.prototype.toString = function() {
|
|
1389
|
+
* return 'new Point(' + this.x + ', ' + this.y + ')';
|
|
1390
|
+
* };
|
|
1391
|
+
*
|
|
1392
|
+
* R.toString(new Point(1, 2)); //=> 'new Point(1, 2)'
|
|
1393
|
+
*
|
|
1394
|
+
* @func
|
|
1395
|
+
* @memberOf R
|
|
1396
|
+
* @since v0.14.0
|
|
1397
|
+
* @category String
|
|
1398
|
+
* @sig * -> String
|
|
1399
|
+
* @param {*} val
|
|
1400
|
+
* @return {String}
|
|
1401
|
+
* @example
|
|
1402
|
+
*
|
|
1403
|
+
* R.toString(42); //=> '42'
|
|
1404
|
+
* R.toString('abc'); //=> '"abc"'
|
|
1405
|
+
* R.toString([1, 2, 3]); //=> '[1, 2, 3]'
|
|
1406
|
+
* R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}'
|
|
1407
|
+
* R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")'
|
|
1408
|
+
*/
|
|
1409
|
+
|
|
1410
|
+
var toString =
|
|
1411
|
+
/*#__PURE__*/
|
|
1412
|
+
_curry1(function toString(val) {
|
|
1413
|
+
return _toString(val, []);
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1416
|
+
var XMap =
|
|
1417
|
+
/*#__PURE__*/
|
|
1418
|
+
function () {
|
|
1419
|
+
function XMap(f, xf) {
|
|
1420
|
+
this.xf = xf;
|
|
1421
|
+
this.f = f;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
XMap.prototype['@@transducer/init'] = _xfBase.init;
|
|
1425
|
+
XMap.prototype['@@transducer/result'] = _xfBase.result;
|
|
1426
|
+
|
|
1427
|
+
XMap.prototype['@@transducer/step'] = function (result, input) {
|
|
1428
|
+
return this.xf['@@transducer/step'](result, this.f(input));
|
|
1429
|
+
};
|
|
1430
|
+
|
|
1431
|
+
return XMap;
|
|
1432
|
+
}();
|
|
1433
|
+
|
|
1434
|
+
var _xmap = function _xmap(f) {
|
|
1435
|
+
return function (xf) {
|
|
1436
|
+
return new XMap(f, xf);
|
|
1437
|
+
};
|
|
1438
|
+
};
|
|
1439
|
+
|
|
1440
|
+
/**
|
|
1441
|
+
* Takes a function and
|
|
1442
|
+
* a [functor](https://github.com/fantasyland/fantasy-land#functor),
|
|
1443
|
+
* applies the function to each of the functor's values, and returns
|
|
1444
|
+
* a functor of the same shape.
|
|
1445
|
+
*
|
|
1446
|
+
* Ramda provides suitable `map` implementations for `Array` and `Object`,
|
|
1447
|
+
* so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`.
|
|
1448
|
+
*
|
|
1449
|
+
* Dispatches to the `map` method of the second argument, if present.
|
|
1450
|
+
*
|
|
1451
|
+
* Acts as a transducer if a transformer is given in list position.
|
|
1452
|
+
*
|
|
1453
|
+
* Also treats functions as functors and will compose them together.
|
|
1454
|
+
*
|
|
1455
|
+
* @func
|
|
1456
|
+
* @memberOf R
|
|
1457
|
+
* @since v0.1.0
|
|
1458
|
+
* @category List
|
|
1459
|
+
* @sig Functor f => (a -> b) -> f a -> f b
|
|
1460
|
+
* @param {Function} fn The function to be called on every element of the input `list`.
|
|
1461
|
+
* @param {Array} list The list to be iterated over.
|
|
1462
|
+
* @return {Array} The new list.
|
|
1463
|
+
* @see R.transduce, R.addIndex, R.pluck, R.project
|
|
1464
|
+
* @example
|
|
1465
|
+
*
|
|
1466
|
+
* const double = x => x * 2;
|
|
1467
|
+
*
|
|
1468
|
+
* R.map(double, [1, 2, 3]); //=> [2, 4, 6]
|
|
1469
|
+
*
|
|
1470
|
+
* R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6}
|
|
1471
|
+
* @symb R.map(f, [a, b]) = [f(a), f(b)]
|
|
1472
|
+
* @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) }
|
|
1473
|
+
* @symb R.map(f, functor_o) = functor_o.map(f)
|
|
1474
|
+
*/
|
|
1475
|
+
|
|
1476
|
+
var map =
|
|
1477
|
+
/*#__PURE__*/
|
|
1478
|
+
_curry2(
|
|
1479
|
+
/*#__PURE__*/
|
|
1480
|
+
_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) {
|
|
1481
|
+
switch (Object.prototype.toString.call(functor)) {
|
|
1482
|
+
case '[object Function]':
|
|
1483
|
+
return curryN(functor.length, function () {
|
|
1484
|
+
return fn.call(this, functor.apply(this, arguments));
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
case '[object Object]':
|
|
1488
|
+
return _arrayReduce(function (acc, key) {
|
|
1489
|
+
acc[key] = fn(functor[key]);
|
|
1490
|
+
return acc;
|
|
1491
|
+
}, {}, keys(functor));
|
|
1492
|
+
|
|
1493
|
+
default:
|
|
1494
|
+
return _map(fn, functor);
|
|
1495
|
+
}
|
|
1496
|
+
}));
|
|
1497
|
+
|
|
1498
|
+
/**
|
|
1499
|
+
* Determine if the passed argument is an integer.
|
|
1500
|
+
*
|
|
1501
|
+
* @private
|
|
1502
|
+
* @param {*} n
|
|
1503
|
+
* @category Type
|
|
1504
|
+
* @return {Boolean}
|
|
1505
|
+
*/
|
|
1506
|
+
var _isInteger = Number.isInteger || function _isInteger(n) {
|
|
1507
|
+
return n << 0 === n;
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1510
|
+
function _isString(x) {
|
|
1511
|
+
return Object.prototype.toString.call(x) === '[object String]';
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* Returns the nth element of the given list or string. If n is negative the
|
|
1516
|
+
* element at index length + n is returned.
|
|
1517
|
+
*
|
|
1518
|
+
* @func
|
|
1519
|
+
* @memberOf R
|
|
1520
|
+
* @since v0.1.0
|
|
1521
|
+
* @category List
|
|
1522
|
+
* @sig Number -> [a] -> a | Undefined
|
|
1523
|
+
* @sig Number -> String -> String
|
|
1524
|
+
* @param {Number} offset
|
|
1525
|
+
* @param {*} list
|
|
1526
|
+
* @return {*}
|
|
1527
|
+
* @example
|
|
1528
|
+
*
|
|
1529
|
+
* const list = ['foo', 'bar', 'baz', 'quux'];
|
|
1530
|
+
* R.nth(1, list); //=> 'bar'
|
|
1531
|
+
* R.nth(-1, list); //=> 'quux'
|
|
1532
|
+
* R.nth(-99, list); //=> undefined
|
|
1533
|
+
*
|
|
1534
|
+
* R.nth(2, 'abc'); //=> 'c'
|
|
1535
|
+
* R.nth(3, 'abc'); //=> ''
|
|
1536
|
+
* @symb R.nth(-1, [a, b, c]) = c
|
|
1537
|
+
* @symb R.nth(0, [a, b, c]) = a
|
|
1538
|
+
* @symb R.nth(1, [a, b, c]) = b
|
|
1539
|
+
*/
|
|
1540
|
+
|
|
1541
|
+
var nth =
|
|
1542
|
+
/*#__PURE__*/
|
|
1543
|
+
_curry2(function nth(offset, list) {
|
|
1544
|
+
var idx = offset < 0 ? list.length + offset : offset;
|
|
1545
|
+
return _isString(list) ? list.charAt(idx) : list[idx];
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
/**
|
|
1549
|
+
* Returns a function that when supplied an object returns the indicated
|
|
1550
|
+
* property of that object, if it exists.
|
|
1551
|
+
*
|
|
1552
|
+
* @func
|
|
1553
|
+
* @memberOf R
|
|
1554
|
+
* @since v0.1.0
|
|
1555
|
+
* @category Object
|
|
1556
|
+
* @typedefn Idx = String | Int | Symbol
|
|
1557
|
+
* @sig Idx -> {s: a} -> a | Undefined
|
|
1558
|
+
* @param {String|Number} p The property name or array index
|
|
1559
|
+
* @param {Object} obj The object to query
|
|
1560
|
+
* @return {*} The value at `obj.p`.
|
|
1561
|
+
* @see R.path, R.props, R.pluck, R.project, R.nth
|
|
1562
|
+
* @example
|
|
1563
|
+
*
|
|
1564
|
+
* R.prop('x', {x: 100}); //=> 100
|
|
1565
|
+
* R.prop('x', {}); //=> undefined
|
|
1566
|
+
* R.prop(0, [100]); //=> 100
|
|
1567
|
+
* R.compose(R.inc, R.prop('x'))({ x: 3 }) //=> 4
|
|
1568
|
+
*/
|
|
1569
|
+
|
|
1570
|
+
var prop =
|
|
1571
|
+
/*#__PURE__*/
|
|
1572
|
+
_curry2(function prop(p, obj) {
|
|
1573
|
+
if (obj == null) {
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
return _isInteger(p) ? nth(p, obj) : obj[p];
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
/**
|
|
1581
|
+
* Tests whether or not an object is similar to an array.
|
|
1582
|
+
*
|
|
1583
|
+
* @private
|
|
1584
|
+
* @category Type
|
|
1585
|
+
* @category List
|
|
1586
|
+
* @sig * -> Boolean
|
|
1587
|
+
* @param {*} x The object to test.
|
|
1588
|
+
* @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise.
|
|
1589
|
+
* @example
|
|
1590
|
+
*
|
|
1591
|
+
* _isArrayLike([]); //=> true
|
|
1592
|
+
* _isArrayLike(true); //=> false
|
|
1593
|
+
* _isArrayLike({}); //=> false
|
|
1594
|
+
* _isArrayLike({length: 10}); //=> false
|
|
1595
|
+
* _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true
|
|
1596
|
+
* _isArrayLike({nodeType: 1, length: 1}) // => false
|
|
1597
|
+
*/
|
|
1598
|
+
|
|
1599
|
+
var _isArrayLike =
|
|
1600
|
+
/*#__PURE__*/
|
|
1601
|
+
_curry1(function isArrayLike(x) {
|
|
1602
|
+
if (_isArray(x)) {
|
|
1603
|
+
return true;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
if (!x) {
|
|
1607
|
+
return false;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
if (typeof x !== 'object') {
|
|
1611
|
+
return false;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
if (_isString(x)) {
|
|
1615
|
+
return false;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
if (x.length === 0) {
|
|
1619
|
+
return true;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
if (x.length > 0) {
|
|
1623
|
+
return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
return false;
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator';
|
|
1630
|
+
function _createReduce(arrayReduce, methodReduce, iterableReduce) {
|
|
1631
|
+
return function _reduce(xf, acc, list) {
|
|
1632
|
+
if (_isArrayLike(list)) {
|
|
1633
|
+
return arrayReduce(xf, acc, list);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
if (list == null) {
|
|
1637
|
+
return acc;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
if (typeof list['fantasy-land/reduce'] === 'function') {
|
|
1641
|
+
return methodReduce(xf, acc, list, 'fantasy-land/reduce');
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
if (list[symIterator] != null) {
|
|
1645
|
+
return iterableReduce(xf, acc, list[symIterator]());
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
if (typeof list.next === 'function') {
|
|
1649
|
+
return iterableReduce(xf, acc, list);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
if (typeof list.reduce === 'function') {
|
|
1653
|
+
return methodReduce(xf, acc, list, 'reduce');
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
throw new TypeError('reduce: list must be array or iterable');
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
function _xArrayReduce(xf, acc, list) {
|
|
1661
|
+
var idx = 0;
|
|
1662
|
+
var len = list.length;
|
|
1663
|
+
|
|
1664
|
+
while (idx < len) {
|
|
1665
|
+
acc = xf['@@transducer/step'](acc, list[idx]);
|
|
1666
|
+
|
|
1667
|
+
if (acc && acc['@@transducer/reduced']) {
|
|
1668
|
+
acc = acc['@@transducer/value'];
|
|
1669
|
+
break;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
idx += 1;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
return xf['@@transducer/result'](acc);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
/**
|
|
1679
|
+
* Creates a function that is bound to a context.
|
|
1680
|
+
* Note: `R.bind` does not provide the additional argument-binding capabilities of
|
|
1681
|
+
* [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
|
|
1682
|
+
*
|
|
1683
|
+
* @func
|
|
1684
|
+
* @memberOf R
|
|
1685
|
+
* @since v0.6.0
|
|
1686
|
+
* @category Function
|
|
1687
|
+
* @category Object
|
|
1688
|
+
* @sig (* -> *) -> {*} -> (* -> *)
|
|
1689
|
+
* @param {Function} fn The function to bind to context
|
|
1690
|
+
* @param {Object} thisObj The context to bind `fn` to
|
|
1691
|
+
* @return {Function} A function that will execute in the context of `thisObj`.
|
|
1692
|
+
* @see R.partial
|
|
1693
|
+
* @example
|
|
1694
|
+
*
|
|
1695
|
+
* const log = R.bind(console.log, console);
|
|
1696
|
+
* R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3}
|
|
1697
|
+
* // logs {a: 2}
|
|
1698
|
+
* @symb R.bind(f, o)(a, b) = f.call(o, a, b)
|
|
1699
|
+
*/
|
|
1700
|
+
|
|
1701
|
+
var bind =
|
|
1702
|
+
/*#__PURE__*/
|
|
1703
|
+
_curry2(function bind(fn, thisObj) {
|
|
1704
|
+
return _arity(fn.length, function () {
|
|
1705
|
+
return fn.apply(thisObj, arguments);
|
|
1706
|
+
});
|
|
1707
|
+
});
|
|
1708
|
+
|
|
1709
|
+
function _xIterableReduce(xf, acc, iter) {
|
|
1710
|
+
var step = iter.next();
|
|
1711
|
+
|
|
1712
|
+
while (!step.done) {
|
|
1713
|
+
acc = xf['@@transducer/step'](acc, step.value);
|
|
1714
|
+
|
|
1715
|
+
if (acc && acc['@@transducer/reduced']) {
|
|
1716
|
+
acc = acc['@@transducer/value'];
|
|
1717
|
+
break;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
step = iter.next();
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
return xf['@@transducer/result'](acc);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
function _xMethodReduce(xf, acc, obj, methodName) {
|
|
1727
|
+
return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc));
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
var _xReduce =
|
|
1731
|
+
/*#__PURE__*/
|
|
1732
|
+
_createReduce(_xArrayReduce, _xMethodReduce, _xIterableReduce);
|
|
1733
|
+
|
|
1734
|
+
var XWrap =
|
|
1735
|
+
/*#__PURE__*/
|
|
1736
|
+
function () {
|
|
1737
|
+
function XWrap(fn) {
|
|
1738
|
+
this.f = fn;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
XWrap.prototype['@@transducer/init'] = function () {
|
|
1742
|
+
throw new Error('init not implemented on XWrap');
|
|
1743
|
+
};
|
|
1744
|
+
|
|
1745
|
+
XWrap.prototype['@@transducer/result'] = function (acc) {
|
|
1746
|
+
return acc;
|
|
1747
|
+
};
|
|
1748
|
+
|
|
1749
|
+
XWrap.prototype['@@transducer/step'] = function (acc, x) {
|
|
1750
|
+
return this.f(acc, x);
|
|
1751
|
+
};
|
|
1752
|
+
|
|
1753
|
+
return XWrap;
|
|
1754
|
+
}();
|
|
1755
|
+
|
|
1756
|
+
function _xwrap(fn) {
|
|
1757
|
+
return new XWrap(fn);
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* Returns a single item by iterating through the list, successively calling
|
|
1762
|
+
* the iterator function and passing it an accumulator value and the current
|
|
1763
|
+
* value from the array, and then passing the result to the next call.
|
|
1764
|
+
*
|
|
1765
|
+
* The iterator function receives two values: *(acc, value)*. It may use
|
|
1766
|
+
* [`R.reduced`](#reduced) to shortcut the iteration.
|
|
1767
|
+
*
|
|
1768
|
+
* The arguments' order of [`reduceRight`](#reduceRight)'s iterator function
|
|
1769
|
+
* is *(value, acc)*.
|
|
1770
|
+
*
|
|
1771
|
+
* Note: `R.reduce` does not skip deleted or unassigned indices (sparse
|
|
1772
|
+
* arrays), unlike the native `Array.prototype.reduce` method. For more details
|
|
1773
|
+
* on this behavior, see:
|
|
1774
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
|
|
1775
|
+
*
|
|
1776
|
+
* Be cautious of mutating and returning the accumulator. If you reuse it across
|
|
1777
|
+
* invocations, it will continue to accumulate onto the same value. The general
|
|
1778
|
+
* recommendation is to always return a new value. If you can't do so for
|
|
1779
|
+
* performance reasons, then be sure to reinitialize the accumulator on each
|
|
1780
|
+
* invocation.
|
|
1781
|
+
*
|
|
1782
|
+
* Dispatches to the `reduce` method of the third argument, if present. When
|
|
1783
|
+
* doing so, it is up to the user to handle the [`R.reduced`](#reduced)
|
|
1784
|
+
* shortcuting, as this is not implemented by `reduce`.
|
|
1785
|
+
*
|
|
1786
|
+
* @func
|
|
1787
|
+
* @memberOf R
|
|
1788
|
+
* @since v0.1.0
|
|
1789
|
+
* @category List
|
|
1790
|
+
* @sig ((a, b) -> a) -> a -> [b] -> a
|
|
1791
|
+
* @param {Function} fn The iterator function. Receives two values, the accumulator and the
|
|
1792
|
+
* current element from the array.
|
|
1793
|
+
* @param {*} acc The accumulator value.
|
|
1794
|
+
* @param {Array} list The list to iterate over.
|
|
1795
|
+
* @return {*} The final, accumulated value.
|
|
1796
|
+
* @see R.reduced, R.addIndex, R.reduceRight
|
|
1797
|
+
* @example
|
|
1798
|
+
*
|
|
1799
|
+
* R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10
|
|
1800
|
+
* // - -10
|
|
1801
|
+
* // / \ / \
|
|
1802
|
+
* // - 4 -6 4
|
|
1803
|
+
* // / \ / \
|
|
1804
|
+
* // - 3 ==> -3 3
|
|
1805
|
+
* // / \ / \
|
|
1806
|
+
* // - 2 -1 2
|
|
1807
|
+
* // / \ / \
|
|
1808
|
+
* // 0 1 0 1
|
|
1809
|
+
*
|
|
1810
|
+
* @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d)
|
|
1811
|
+
*/
|
|
1812
|
+
|
|
1813
|
+
var reduce =
|
|
1814
|
+
/*#__PURE__*/
|
|
1815
|
+
_curry3(function (xf, acc, list) {
|
|
1816
|
+
return _xReduce(typeof xf === 'function' ? _xwrap(xf) : xf, acc, list);
|
|
1817
|
+
});
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* Makes a shallow clone of an object, setting or overriding the specified
|
|
1821
|
+
* property with the given value. Note that this copies and flattens prototype
|
|
1822
|
+
* properties onto the new object as well. All non-primitive properties are
|
|
1823
|
+
* copied by reference.
|
|
1824
|
+
*
|
|
1825
|
+
* @private
|
|
1826
|
+
* @param {String|Number} prop The property name to set
|
|
1827
|
+
* @param {*} val The new value
|
|
1828
|
+
* @param {Object|Array} obj The object to clone
|
|
1829
|
+
* @return {Object|Array} A new object equivalent to the original except for the changed property.
|
|
1830
|
+
*/
|
|
1831
|
+
|
|
1832
|
+
function _assoc(prop, val, obj) {
|
|
1833
|
+
if (_isInteger(prop) && _isArray(obj)) {
|
|
1834
|
+
var arr = [].concat(obj);
|
|
1835
|
+
arr[prop] = val;
|
|
1836
|
+
return arr;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
var result = {};
|
|
1840
|
+
|
|
1841
|
+
for (var p in obj) {
|
|
1842
|
+
result[p] = obj[p];
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
result[prop] = val;
|
|
1846
|
+
return result;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
/**
|
|
1850
|
+
* Checks if the input value is `null` or `undefined`.
|
|
1851
|
+
*
|
|
1852
|
+
* @func
|
|
1853
|
+
* @memberOf R
|
|
1854
|
+
* @since v0.9.0
|
|
1855
|
+
* @category Type
|
|
1856
|
+
* @sig * -> Boolean
|
|
1857
|
+
* @param {*} x The value to test.
|
|
1858
|
+
* @return {Boolean} `true` if `x` is `undefined` or `null`, otherwise `false`.
|
|
1859
|
+
* @example
|
|
1860
|
+
*
|
|
1861
|
+
* R.isNil(null); //=> true
|
|
1862
|
+
* R.isNil(undefined); //=> true
|
|
1863
|
+
* R.isNil(0); //=> false
|
|
1864
|
+
* R.isNil([]); //=> false
|
|
1865
|
+
*/
|
|
1866
|
+
|
|
1867
|
+
var isNil =
|
|
1868
|
+
/*#__PURE__*/
|
|
1869
|
+
_curry1(function isNil(x) {
|
|
1870
|
+
return x == null;
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1873
|
+
/**
|
|
1874
|
+
* Makes a shallow clone of an object, setting or overriding the nodes required
|
|
1875
|
+
* to create the given path, and placing the specific value at the tail end of
|
|
1876
|
+
* that path. Note that this copies and flattens prototype properties onto the
|
|
1877
|
+
* new object as well. All non-primitive properties are copied by reference.
|
|
1878
|
+
*
|
|
1879
|
+
* @func
|
|
1880
|
+
* @memberOf R
|
|
1881
|
+
* @since v0.8.0
|
|
1882
|
+
* @category Object
|
|
1883
|
+
* @typedefn Idx = String | Int | Symbol
|
|
1884
|
+
* @sig [Idx] -> a -> {a} -> {a}
|
|
1885
|
+
* @param {Array} path the path to set
|
|
1886
|
+
* @param {*} val The new value
|
|
1887
|
+
* @param {Object} obj The object to clone
|
|
1888
|
+
* @return {Object} A new object equivalent to the original except along the specified path.
|
|
1889
|
+
* @see R.dissocPath
|
|
1890
|
+
* @example
|
|
1891
|
+
*
|
|
1892
|
+
* R.assocPath(['a', 'b', 'c'], 42, {a: {b: {c: 0}}}); //=> {a: {b: {c: 42}}}
|
|
1893
|
+
*
|
|
1894
|
+
* // Any missing or non-object keys in path will be overridden
|
|
1895
|
+
* R.assocPath(['a', 'b', 'c'], 42, {a: 5}); //=> {a: {b: {c: 42}}}
|
|
1896
|
+
*/
|
|
1897
|
+
|
|
1898
|
+
var assocPath =
|
|
1899
|
+
/*#__PURE__*/
|
|
1900
|
+
_curry3(function assocPath(path, val, obj) {
|
|
1901
|
+
if (path.length === 0) {
|
|
1902
|
+
return val;
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
var idx = path[0];
|
|
1906
|
+
|
|
1907
|
+
if (path.length > 1) {
|
|
1908
|
+
var nextObj = !isNil(obj) && _has(idx, obj) && typeof obj[idx] === 'object' ? obj[idx] : _isInteger(path[1]) ? [] : {};
|
|
1909
|
+
val = assocPath(Array.prototype.slice.call(path, 1), val, nextObj);
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
return _assoc(idx, val, obj);
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1915
|
+
function _isFunction(x) {
|
|
1916
|
+
var type = Object.prototype.toString.call(x);
|
|
1917
|
+
return type === '[object Function]' || type === '[object AsyncFunction]' || type === '[object GeneratorFunction]' || type === '[object AsyncGeneratorFunction]';
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
function _pipe(f, g) {
|
|
1921
|
+
return function () {
|
|
1922
|
+
return g.call(this, f.apply(this, arguments));
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* This checks whether a function has a [methodname] function. If it isn't an
|
|
1928
|
+
* array it will execute that function otherwise it will default to the ramda
|
|
1929
|
+
* implementation.
|
|
1930
|
+
*
|
|
1931
|
+
* @private
|
|
1932
|
+
* @param {Function} fn ramda implementation
|
|
1933
|
+
* @param {String} methodname property to check for a custom implementation
|
|
1934
|
+
* @return {Object} Whatever the return value of the method is.
|
|
1935
|
+
*/
|
|
1936
|
+
|
|
1937
|
+
function _checkForMethod(methodname, fn) {
|
|
1938
|
+
return function () {
|
|
1939
|
+
var length = arguments.length;
|
|
1940
|
+
|
|
1941
|
+
if (length === 0) {
|
|
1942
|
+
return fn();
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
var obj = arguments[length - 1];
|
|
1946
|
+
return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1));
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* Returns the elements of the given list or string (or object with a `slice`
|
|
1952
|
+
* method) from `fromIndex` (inclusive) to `toIndex` (exclusive).
|
|
1953
|
+
*
|
|
1954
|
+
* Dispatches to the `slice` method of the third argument, if present.
|
|
1955
|
+
*
|
|
1956
|
+
* @func
|
|
1957
|
+
* @memberOf R
|
|
1958
|
+
* @since v0.1.4
|
|
1959
|
+
* @category List
|
|
1960
|
+
* @sig Number -> Number -> [a] -> [a]
|
|
1961
|
+
* @sig Number -> Number -> String -> String
|
|
1962
|
+
* @param {Number} fromIndex The start index (inclusive).
|
|
1963
|
+
* @param {Number} toIndex The end index (exclusive).
|
|
1964
|
+
* @param {*} list
|
|
1965
|
+
* @return {*}
|
|
1966
|
+
* @example
|
|
1967
|
+
*
|
|
1968
|
+
* R.slice(1, 3, ['a', 'b', 'c', 'd']); //=> ['b', 'c']
|
|
1969
|
+
* R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd']
|
|
1970
|
+
* R.slice(0, -1, ['a', 'b', 'c', 'd']); //=> ['a', 'b', 'c']
|
|
1971
|
+
* R.slice(-3, -1, ['a', 'b', 'c', 'd']); //=> ['b', 'c']
|
|
1972
|
+
* R.slice(0, 3, 'ramda'); //=> 'ram'
|
|
1973
|
+
*/
|
|
1974
|
+
|
|
1975
|
+
var slice =
|
|
1976
|
+
/*#__PURE__*/
|
|
1977
|
+
_curry3(
|
|
1978
|
+
/*#__PURE__*/
|
|
1979
|
+
_checkForMethod('slice', function slice(fromIndex, toIndex, list) {
|
|
1980
|
+
return Array.prototype.slice.call(list, fromIndex, toIndex);
|
|
1981
|
+
}));
|
|
1982
|
+
|
|
1983
|
+
/**
|
|
1984
|
+
* Returns all but the first element of the given list or string (or object
|
|
1985
|
+
* with a `tail` method).
|
|
1986
|
+
*
|
|
1987
|
+
* Dispatches to the `slice` method of the first argument, if present.
|
|
1988
|
+
*
|
|
1989
|
+
* @func
|
|
1990
|
+
* @memberOf R
|
|
1991
|
+
* @since v0.1.0
|
|
1992
|
+
* @category List
|
|
1993
|
+
* @sig [a] -> [a]
|
|
1994
|
+
* @sig String -> String
|
|
1995
|
+
* @param {*} list
|
|
1996
|
+
* @return {*}
|
|
1997
|
+
* @see R.head, R.init, R.last
|
|
1998
|
+
* @example
|
|
1999
|
+
*
|
|
2000
|
+
* R.tail([1, 2, 3]); //=> [2, 3]
|
|
2001
|
+
* R.tail([1, 2]); //=> [2]
|
|
2002
|
+
* R.tail([1]); //=> []
|
|
2003
|
+
* R.tail([]); //=> []
|
|
2004
|
+
*
|
|
2005
|
+
* R.tail('abc'); //=> 'bc'
|
|
2006
|
+
* R.tail('ab'); //=> 'b'
|
|
2007
|
+
* R.tail('a'); //=> ''
|
|
2008
|
+
* R.tail(''); //=> ''
|
|
2009
|
+
*/
|
|
2010
|
+
|
|
2011
|
+
var tail =
|
|
2012
|
+
/*#__PURE__*/
|
|
2013
|
+
_curry1(
|
|
2014
|
+
/*#__PURE__*/
|
|
2015
|
+
_checkForMethod('tail',
|
|
2016
|
+
/*#__PURE__*/
|
|
2017
|
+
slice(1, Infinity)));
|
|
2018
|
+
|
|
2019
|
+
/**
|
|
2020
|
+
* Performs left-to-right function composition. The first argument may have
|
|
2021
|
+
* any arity; the remaining arguments must be unary.
|
|
2022
|
+
*
|
|
2023
|
+
* In some libraries this function is named `sequence`.
|
|
2024
|
+
*
|
|
2025
|
+
* **Note:** The result of pipe is not automatically curried.
|
|
2026
|
+
*
|
|
2027
|
+
* @func
|
|
2028
|
+
* @memberOf R
|
|
2029
|
+
* @since v0.1.0
|
|
2030
|
+
* @category Function
|
|
2031
|
+
* @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z)
|
|
2032
|
+
* @param {...Function} functions
|
|
2033
|
+
* @return {Function}
|
|
2034
|
+
* @see R.compose
|
|
2035
|
+
* @example
|
|
2036
|
+
*
|
|
2037
|
+
* const f = R.pipe(Math.pow, R.negate, R.inc);
|
|
2038
|
+
*
|
|
2039
|
+
* f(3, 4); // -(3^4) + 1
|
|
2040
|
+
* @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b)))
|
|
2041
|
+
* @symb R.pipe(f, g, h)(a)(b) = h(g(f(a)))(b)
|
|
2042
|
+
*/
|
|
2043
|
+
|
|
2044
|
+
function pipe() {
|
|
2045
|
+
if (arguments.length === 0) {
|
|
2046
|
+
throw new Error('pipe requires at least one argument');
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments)));
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
/**
|
|
2053
|
+
* Returns a new list or string with the elements or characters in reverse
|
|
2054
|
+
* order.
|
|
2055
|
+
*
|
|
2056
|
+
* @func
|
|
2057
|
+
* @memberOf R
|
|
2058
|
+
* @since v0.1.0
|
|
2059
|
+
* @category List
|
|
2060
|
+
* @sig [a] -> [a]
|
|
2061
|
+
* @sig String -> String
|
|
2062
|
+
* @param {Array|String} list
|
|
2063
|
+
* @return {Array|String}
|
|
2064
|
+
* @example
|
|
2065
|
+
*
|
|
2066
|
+
* R.reverse([1, 2, 3]); //=> [3, 2, 1]
|
|
2067
|
+
* R.reverse([1, 2]); //=> [2, 1]
|
|
2068
|
+
* R.reverse([1]); //=> [1]
|
|
2069
|
+
* R.reverse([]); //=> []
|
|
2070
|
+
*
|
|
2071
|
+
* R.reverse('abc'); //=> 'cba'
|
|
2072
|
+
* R.reverse('ab'); //=> 'ba'
|
|
2073
|
+
* R.reverse('a'); //=> 'a'
|
|
2074
|
+
* R.reverse(''); //=> ''
|
|
2075
|
+
*/
|
|
2076
|
+
|
|
2077
|
+
var reverse =
|
|
2078
|
+
/*#__PURE__*/
|
|
2079
|
+
_curry1(function reverse(list) {
|
|
2080
|
+
return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse();
|
|
2081
|
+
});
|
|
2082
|
+
|
|
2083
|
+
/**
|
|
2084
|
+
* Performs right-to-left function composition. The last argument may have
|
|
2085
|
+
* any arity; the remaining arguments must be unary.
|
|
2086
|
+
*
|
|
2087
|
+
* **Note:** The result of compose is not automatically curried.
|
|
2088
|
+
*
|
|
2089
|
+
* @func
|
|
2090
|
+
* @memberOf R
|
|
2091
|
+
* @since v0.1.0
|
|
2092
|
+
* @category Function
|
|
2093
|
+
* @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z)
|
|
2094
|
+
* @param {...Function} ...functions The functions to compose
|
|
2095
|
+
* @return {Function}
|
|
2096
|
+
* @see R.pipe
|
|
2097
|
+
* @example
|
|
2098
|
+
*
|
|
2099
|
+
* const classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName
|
|
2100
|
+
* const yellGreeting = R.compose(R.toUpper, classyGreeting);
|
|
2101
|
+
* yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND"
|
|
2102
|
+
*
|
|
2103
|
+
* R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7
|
|
2104
|
+
*
|
|
2105
|
+
* @symb R.compose(f, g, h)(a, b) = f(g(h(a, b)))
|
|
2106
|
+
* @symb R.compose(f, g, h)(a)(b) = f(g(h(a)))(b)
|
|
2107
|
+
*/
|
|
2108
|
+
|
|
2109
|
+
function compose() {
|
|
2110
|
+
if (arguments.length === 0) {
|
|
2111
|
+
throw new Error('compose requires at least one argument');
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
return pipe.apply(this, reverse(arguments));
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
/**
|
|
2118
|
+
* Returns a curried equivalent of the provided function. The curried function
|
|
2119
|
+
* has two unusual capabilities. First, its arguments needn't be provided one
|
|
2120
|
+
* at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the
|
|
2121
|
+
* following are equivalent:
|
|
2122
|
+
*
|
|
2123
|
+
* - `g(1)(2)(3)`
|
|
2124
|
+
* - `g(1)(2, 3)`
|
|
2125
|
+
* - `g(1, 2)(3)`
|
|
2126
|
+
* - `g(1, 2, 3)`
|
|
2127
|
+
*
|
|
2128
|
+
* Secondly, the special placeholder value [`R.__`](#__) may be used to specify
|
|
2129
|
+
* "gaps", allowing partial application of any combination of arguments,
|
|
2130
|
+
* regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
|
|
2131
|
+
* the following are equivalent:
|
|
2132
|
+
*
|
|
2133
|
+
* - `g(1, 2, 3)`
|
|
2134
|
+
* - `g(_, 2, 3)(1)`
|
|
2135
|
+
* - `g(_, _, 3)(1)(2)`
|
|
2136
|
+
* - `g(_, _, 3)(1, 2)`
|
|
2137
|
+
* - `g(_, 2)(1)(3)`
|
|
2138
|
+
* - `g(_, 2)(1, 3)`
|
|
2139
|
+
* - `g(_, 2)(_, 3)(1)`
|
|
2140
|
+
*
|
|
2141
|
+
* Please note that default parameters don't count towards a [function arity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length)
|
|
2142
|
+
* and therefore `curry` won't work well with those.
|
|
2143
|
+
*
|
|
2144
|
+
* @func
|
|
2145
|
+
* @memberOf R
|
|
2146
|
+
* @since v0.1.0
|
|
2147
|
+
* @category Function
|
|
2148
|
+
* @sig (* -> a) -> (* -> a)
|
|
2149
|
+
* @param {Function} fn The function to curry.
|
|
2150
|
+
* @return {Function} A new, curried function.
|
|
2151
|
+
* @see R.curryN, R.partial
|
|
2152
|
+
* @example
|
|
2153
|
+
*
|
|
2154
|
+
* const addFourNumbers = (a, b, c, d) => a + b + c + d;
|
|
2155
|
+
* const curriedAddFourNumbers = R.curry(addFourNumbers);
|
|
2156
|
+
* const f = curriedAddFourNumbers(1, 2);
|
|
2157
|
+
* const g = f(3);
|
|
2158
|
+
* g(4); //=> 10
|
|
2159
|
+
*
|
|
2160
|
+
* // R.curry not working well with default parameters
|
|
2161
|
+
* const h = R.curry((a, b, c = 2) => a + b + c);
|
|
2162
|
+
* h(1)(2)(7); //=> Error! (`3` is not a function!)
|
|
2163
|
+
*/
|
|
2164
|
+
|
|
2165
|
+
var curry =
|
|
2166
|
+
/*#__PURE__*/
|
|
2167
|
+
_curry1(function curry(fn) {
|
|
2168
|
+
return curryN(fn.length, fn);
|
|
2169
|
+
});
|
|
2170
|
+
|
|
2171
|
+
/**
|
|
2172
|
+
* Tests whether or not an object is a typed array.
|
|
2173
|
+
*
|
|
2174
|
+
* @private
|
|
2175
|
+
* @param {*} val The object to test.
|
|
2176
|
+
* @return {Boolean} `true` if `val` is a typed array, `false` otherwise.
|
|
2177
|
+
* @example
|
|
2178
|
+
*
|
|
2179
|
+
* _isTypedArray(new Uint8Array([])); //=> true
|
|
2180
|
+
* _isTypedArray(new Float32Array([])); //=> true
|
|
2181
|
+
* _isTypedArray([]); //=> false
|
|
2182
|
+
* _isTypedArray(null); //=> false
|
|
2183
|
+
* _isTypedArray({}); //=> false
|
|
2184
|
+
*/
|
|
2185
|
+
function _isTypedArray(val) {
|
|
2186
|
+
var type = Object.prototype.toString.call(val);
|
|
2187
|
+
return type === '[object Uint8ClampedArray]' || type === '[object Int8Array]' || type === '[object Uint8Array]' || type === '[object Int16Array]' || type === '[object Uint16Array]' || type === '[object Int32Array]' || type === '[object Uint32Array]' || type === '[object Float32Array]' || type === '[object Float64Array]' || type === '[object BigInt64Array]' || type === '[object BigUint64Array]';
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
/**
|
|
2191
|
+
* Returns the empty value of its argument's type. Ramda defines the empty
|
|
2192
|
+
* value of Array (`[]`), Object (`{}`), String (`''`),
|
|
2193
|
+
* TypedArray (`Uint8Array []`, `Float32Array []`, etc), and Arguments. Other
|
|
2194
|
+
* types are supported if they define `<Type>.empty`,
|
|
2195
|
+
* `<Type>.prototype.empty` or implement the
|
|
2196
|
+
* [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid).
|
|
2197
|
+
*
|
|
2198
|
+
* Dispatches to the `empty` method of the first argument, if present.
|
|
2199
|
+
*
|
|
2200
|
+
* @func
|
|
2201
|
+
* @memberOf R
|
|
2202
|
+
* @since v0.3.0
|
|
2203
|
+
* @category Function
|
|
2204
|
+
* @sig a -> a
|
|
2205
|
+
* @param {*} x
|
|
2206
|
+
* @return {*}
|
|
2207
|
+
* @example
|
|
2208
|
+
*
|
|
2209
|
+
* R.empty(Just(42)); //=> Nothing()
|
|
2210
|
+
* R.empty([1, 2, 3]); //=> []
|
|
2211
|
+
* R.empty('unicorns'); //=> ''
|
|
2212
|
+
* R.empty({x: 1, y: 2}); //=> {}
|
|
2213
|
+
* R.empty(Uint8Array.from('123')); //=> Uint8Array []
|
|
2214
|
+
*/
|
|
2215
|
+
|
|
2216
|
+
var empty =
|
|
2217
|
+
/*#__PURE__*/
|
|
2218
|
+
_curry1(function empty(x) {
|
|
2219
|
+
return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () {
|
|
2220
|
+
return arguments;
|
|
2221
|
+
}() : _isTypedArray(x) ? x.constructor.from('') : void 0 // else
|
|
2222
|
+
;
|
|
2223
|
+
});
|
|
2224
|
+
|
|
2225
|
+
var XFind =
|
|
2226
|
+
/*#__PURE__*/
|
|
2227
|
+
function () {
|
|
2228
|
+
function XFind(f, xf) {
|
|
2229
|
+
this.xf = xf;
|
|
2230
|
+
this.f = f;
|
|
2231
|
+
this.found = false;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
XFind.prototype['@@transducer/init'] = _xfBase.init;
|
|
2235
|
+
|
|
2236
|
+
XFind.prototype['@@transducer/result'] = function (result) {
|
|
2237
|
+
if (!this.found) {
|
|
2238
|
+
result = this.xf['@@transducer/step'](result, void 0);
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
return this.xf['@@transducer/result'](result);
|
|
2242
|
+
};
|
|
2243
|
+
|
|
2244
|
+
XFind.prototype['@@transducer/step'] = function (result, input) {
|
|
2245
|
+
if (this.f(input)) {
|
|
2246
|
+
this.found = true;
|
|
2247
|
+
result = _reduced(this.xf['@@transducer/step'](result, input));
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
return result;
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2253
|
+
return XFind;
|
|
2254
|
+
}();
|
|
2255
|
+
|
|
2256
|
+
function _xfind(f) {
|
|
2257
|
+
return function (xf) {
|
|
2258
|
+
return new XFind(f, xf);
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
/**
|
|
2263
|
+
* Returns the first element of the list which matches the predicate, or
|
|
2264
|
+
* `undefined` if no element matches.
|
|
2265
|
+
*
|
|
2266
|
+
* Dispatches to the `find` method of the second argument, if present.
|
|
2267
|
+
*
|
|
2268
|
+
* Acts as a transducer if a transformer is given in list position.
|
|
2269
|
+
*
|
|
2270
|
+
* @func
|
|
2271
|
+
* @memberOf R
|
|
2272
|
+
* @since v0.1.0
|
|
2273
|
+
* @category List
|
|
2274
|
+
* @sig (a -> Boolean) -> [a] -> a | undefined
|
|
2275
|
+
* @param {Function} fn The predicate function used to determine if the element is the
|
|
2276
|
+
* desired one.
|
|
2277
|
+
* @param {Array} list The array to consider.
|
|
2278
|
+
* @return {Object} The element found, or `undefined`.
|
|
2279
|
+
* @see R.transduce
|
|
2280
|
+
* @example
|
|
2281
|
+
*
|
|
2282
|
+
* const xs = [{a: 1}, {a: 2}, {a: 3}];
|
|
2283
|
+
* R.find(R.propEq(2, 'a'))(xs); //=> {a: 2}
|
|
2284
|
+
* R.find(R.propEq(4, 'a'))(xs); //=> undefined
|
|
2285
|
+
*/
|
|
2286
|
+
|
|
2287
|
+
var find =
|
|
2288
|
+
/*#__PURE__*/
|
|
2289
|
+
_curry2(
|
|
2290
|
+
/*#__PURE__*/
|
|
2291
|
+
_dispatchable(['find'], _xfind, function find(fn, list) {
|
|
2292
|
+
var idx = 0;
|
|
2293
|
+
var len = list.length;
|
|
2294
|
+
|
|
2295
|
+
while (idx < len) {
|
|
2296
|
+
if (fn(list[idx])) {
|
|
2297
|
+
return list[idx];
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
idx += 1;
|
|
2301
|
+
}
|
|
2302
|
+
}));
|
|
2303
|
+
|
|
2304
|
+
/**
|
|
2305
|
+
* Returns `true` if the specified value is equal, in [`R.equals`](#equals)
|
|
2306
|
+
* terms, to at least one element of the given list; `false` otherwise.
|
|
2307
|
+
* Also works with strings.
|
|
2308
|
+
*
|
|
2309
|
+
* @func
|
|
2310
|
+
* @memberOf R
|
|
2311
|
+
* @since v0.26.0
|
|
2312
|
+
* @category List
|
|
2313
|
+
* @sig a -> [a] -> Boolean
|
|
2314
|
+
* @param {Object} a The item to compare against.
|
|
2315
|
+
* @param {Array} list The array to consider.
|
|
2316
|
+
* @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
|
|
2317
|
+
* @see R.any
|
|
2318
|
+
* @example
|
|
2319
|
+
*
|
|
2320
|
+
* R.includes(3, [1, 2, 3]); //=> true
|
|
2321
|
+
* R.includes(4, [1, 2, 3]); //=> false
|
|
2322
|
+
* R.includes({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
|
|
2323
|
+
* R.includes([42], [[42]]); //=> true
|
|
2324
|
+
* R.includes('ba', 'banana'); //=>true
|
|
2325
|
+
*/
|
|
2326
|
+
|
|
2327
|
+
var includes =
|
|
2328
|
+
/*#__PURE__*/
|
|
2329
|
+
_curry2(_includes);
|
|
2330
|
+
|
|
2331
|
+
/**
|
|
2332
|
+
* Given an `arity` (Number) and a `name` (String) the `invoker` function
|
|
2333
|
+
* returns a curried function that takes `arity` arguments and a `context`
|
|
2334
|
+
* object. It will "invoke" the `name`'d function (a method) on the `context`
|
|
2335
|
+
* object.
|
|
2336
|
+
*
|
|
2337
|
+
* @func
|
|
2338
|
+
* @memberOf R
|
|
2339
|
+
* @since v0.1.0
|
|
2340
|
+
* @category Function
|
|
2341
|
+
* @sig Number -> String -> (a -> b -> ... -> n -> Object -> *)
|
|
2342
|
+
* @param {Number} arity Number of arguments the returned function should take
|
|
2343
|
+
* before the target object.
|
|
2344
|
+
* @param {String} method Name of any of the target object's methods to call.
|
|
2345
|
+
* @return {Function} A new curried function.
|
|
2346
|
+
* @see R.construct
|
|
2347
|
+
* @example
|
|
2348
|
+
* // A function with no arguments
|
|
2349
|
+
* const asJson = invoker(0, "json")
|
|
2350
|
+
* // Just like calling .then((response) => response.json())
|
|
2351
|
+
* fetch("http://example.com/index.json").then(asJson)
|
|
2352
|
+
*
|
|
2353
|
+
* // A function with one argument
|
|
2354
|
+
* const sliceFrom = invoker(1, 'slice');
|
|
2355
|
+
* sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm'
|
|
2356
|
+
*
|
|
2357
|
+
* // A function with two arguments
|
|
2358
|
+
* const sliceFrom6 = invoker(2, 'slice')(6);
|
|
2359
|
+
* sliceFrom6(8, 'abcdefghijklm'); //=> 'gh'
|
|
2360
|
+
*
|
|
2361
|
+
* // NOTE: You can't simply pass some of the arguments to the initial invoker function.
|
|
2362
|
+
* const firstCreditCardSection = invoker(2, "slice", 0, 4)
|
|
2363
|
+
* firstCreditCardSection("4242 4242 4242 4242") // => Function<...>
|
|
2364
|
+
*
|
|
2365
|
+
* // Since invoker returns a curried function, you may partially apply it to create the function you need.
|
|
2366
|
+
* const firstCreditCardSection = invoker(2, "slice")(0, 4)
|
|
2367
|
+
* firstCreditCardSection("4242 4242 4242 4242") // => "4242"
|
|
2368
|
+
*
|
|
2369
|
+
* @symb R.invoker(0, 'method')(o) = o['method']()
|
|
2370
|
+
* @symb R.invoker(1, 'method')(a, o) = o['method'](a)
|
|
2371
|
+
* @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b)
|
|
2372
|
+
*/
|
|
2373
|
+
|
|
2374
|
+
var invoker =
|
|
2375
|
+
/*#__PURE__*/
|
|
2376
|
+
_curry2(function invoker(arity, method) {
|
|
2377
|
+
return curryN(arity + 1, function () {
|
|
2378
|
+
var target = arguments[arity];
|
|
2379
|
+
|
|
2380
|
+
if (target != null && _isFunction(target[method])) {
|
|
2381
|
+
return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity));
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
throw new TypeError(toString(target) + ' does not have a method named "' + method + '"');
|
|
2385
|
+
});
|
|
2386
|
+
});
|
|
2387
|
+
|
|
2388
|
+
/**
|
|
2389
|
+
* Returns `true` if the given value is its type's empty value; `false`
|
|
2390
|
+
* otherwise.
|
|
2391
|
+
*
|
|
2392
|
+
* @func
|
|
2393
|
+
* @memberOf R
|
|
2394
|
+
* @since v0.1.0
|
|
2395
|
+
* @category Logic
|
|
2396
|
+
* @sig a -> Boolean
|
|
2397
|
+
* @param {*} x
|
|
2398
|
+
* @return {Boolean}
|
|
2399
|
+
* @see R.empty
|
|
2400
|
+
* @example
|
|
2401
|
+
*
|
|
2402
|
+
* R.isEmpty([1, 2, 3]); //=> false
|
|
2403
|
+
* R.isEmpty([]); //=> true
|
|
2404
|
+
* R.isEmpty(''); //=> true
|
|
2405
|
+
* R.isEmpty(null); //=> false
|
|
2406
|
+
* R.isEmpty({}); //=> true
|
|
2407
|
+
* R.isEmpty({length: 0}); //=> false
|
|
2408
|
+
* R.isEmpty(Uint8Array.from('')); //=> true
|
|
2409
|
+
*/
|
|
2410
|
+
|
|
2411
|
+
var isEmpty =
|
|
2412
|
+
/*#__PURE__*/
|
|
2413
|
+
_curry1(function isEmpty(x) {
|
|
2414
|
+
return x != null && equals(x, empty(x));
|
|
2415
|
+
});
|
|
2416
|
+
|
|
2417
|
+
/**
|
|
2418
|
+
* Returns a string made by inserting the `separator` between each element and
|
|
2419
|
+
* concatenating all the elements into a single string.
|
|
2420
|
+
*
|
|
2421
|
+
* @func
|
|
2422
|
+
* @memberOf R
|
|
2423
|
+
* @since v0.1.0
|
|
2424
|
+
* @category List
|
|
2425
|
+
* @sig String -> [a] -> String
|
|
2426
|
+
* @param {Number|String} separator The string used to separate the elements.
|
|
2427
|
+
* @param {Array} xs The elements to join into a string.
|
|
2428
|
+
* @return {String} str The string made by concatenating `xs` with `separator`.
|
|
2429
|
+
* @see R.split
|
|
2430
|
+
* @example
|
|
2431
|
+
*
|
|
2432
|
+
* const spacer = R.join(' ');
|
|
2433
|
+
* spacer(['a', 2, 3.4]); //=> 'a 2 3.4'
|
|
2434
|
+
* R.join('|', [1, 2, 3]); //=> '1|2|3'
|
|
2435
|
+
*/
|
|
2436
|
+
|
|
2437
|
+
var join =
|
|
2438
|
+
/*#__PURE__*/
|
|
2439
|
+
invoker(1, 'join');
|
|
2440
|
+
|
|
2441
|
+
/**
|
|
2442
|
+
* Returns a lens for the given getter and setter functions. The getter "gets"
|
|
2443
|
+
* the value of the focus; the setter "sets" the value of the focus. The setter
|
|
2444
|
+
* should not mutate the data structure.
|
|
2445
|
+
*
|
|
2446
|
+
* @func
|
|
2447
|
+
* @memberOf R
|
|
2448
|
+
* @since v0.8.0
|
|
2449
|
+
* @category Object
|
|
2450
|
+
* @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
|
|
2451
|
+
* @sig (s -> a) -> ((a, s) -> s) -> Lens s a
|
|
2452
|
+
* @param {Function} getter
|
|
2453
|
+
* @param {Function} setter
|
|
2454
|
+
* @return {Lens}
|
|
2455
|
+
* @see R.view, R.set, R.over, R.lensIndex, R.lensProp
|
|
2456
|
+
* @example
|
|
2457
|
+
*
|
|
2458
|
+
* const xLens = R.lens(R.prop('x'), R.assoc('x'));
|
|
2459
|
+
*
|
|
2460
|
+
* R.view(xLens, {x: 1, y: 2}); //=> 1
|
|
2461
|
+
* R.set(xLens, 4, {x: 1, y: 2}); //=> {x: 4, y: 2}
|
|
2462
|
+
* R.over(xLens, R.negate, {x: 1, y: 2}); //=> {x: -1, y: 2}
|
|
2463
|
+
*/
|
|
2464
|
+
|
|
2465
|
+
var lens =
|
|
2466
|
+
/*#__PURE__*/
|
|
2467
|
+
_curry2(function lens(getter, setter) {
|
|
2468
|
+
return function (toFunctorFn) {
|
|
2469
|
+
return function (target) {
|
|
2470
|
+
return map(function (focus) {
|
|
2471
|
+
return setter(focus, target);
|
|
2472
|
+
}, toFunctorFn(getter(target)));
|
|
2473
|
+
};
|
|
2474
|
+
};
|
|
2475
|
+
});
|
|
2476
|
+
|
|
2477
|
+
/**
|
|
2478
|
+
* Retrieves the values at given paths of an object.
|
|
2479
|
+
*
|
|
2480
|
+
* @func
|
|
2481
|
+
* @memberOf R
|
|
2482
|
+
* @since v0.27.1
|
|
2483
|
+
* @category Object
|
|
2484
|
+
* @typedefn Idx = [String | Int | Symbol]
|
|
2485
|
+
* @sig [Idx] -> {a} -> [a | Undefined]
|
|
2486
|
+
* @param {Array} pathsArray The array of paths to be fetched.
|
|
2487
|
+
* @param {Object} obj The object to retrieve the nested properties from.
|
|
2488
|
+
* @return {Array} A list consisting of values at paths specified by "pathsArray".
|
|
2489
|
+
* @see R.path
|
|
2490
|
+
* @example
|
|
2491
|
+
*
|
|
2492
|
+
* R.paths([['a', 'b'], ['p', 0, 'q']], {a: {b: 2}, p: [{q: 3}]}); //=> [2, 3]
|
|
2493
|
+
* R.paths([['a', 'b'], ['p', 'r']], {a: {b: 2}, p: [{q: 3}]}); //=> [2, undefined]
|
|
2494
|
+
*/
|
|
2495
|
+
|
|
2496
|
+
var paths =
|
|
2497
|
+
/*#__PURE__*/
|
|
2498
|
+
_curry2(function paths(pathsArray, obj) {
|
|
2499
|
+
return pathsArray.map(function (paths) {
|
|
2500
|
+
var val = obj;
|
|
2501
|
+
var idx = 0;
|
|
2502
|
+
var p;
|
|
2503
|
+
|
|
2504
|
+
while (idx < paths.length) {
|
|
2505
|
+
if (val == null) {
|
|
2506
|
+
return;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
p = paths[idx];
|
|
2510
|
+
val = _isInteger(p) ? nth(p, val) : val[p];
|
|
2511
|
+
idx += 1;
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
return val;
|
|
2515
|
+
});
|
|
2516
|
+
});
|
|
2517
|
+
|
|
2518
|
+
/**
|
|
2519
|
+
* Retrieves the value at a given path. The nodes of the path can be arbitrary strings or non-negative integers.
|
|
2520
|
+
* For anything else, the value is unspecified. Integer paths are meant to index arrays, strings are meant for objects.
|
|
2521
|
+
*
|
|
2522
|
+
* @func
|
|
2523
|
+
* @memberOf R
|
|
2524
|
+
* @since v0.2.0
|
|
2525
|
+
* @category Object
|
|
2526
|
+
* @typedefn Idx = String | Int | Symbol
|
|
2527
|
+
* @sig [Idx] -> {a} -> a | Undefined
|
|
2528
|
+
* @sig Idx = String | NonNegativeInt
|
|
2529
|
+
* @param {Array} path The path to use.
|
|
2530
|
+
* @param {Object} obj The object or array to retrieve the nested property from.
|
|
2531
|
+
* @return {*} The data at `path`.
|
|
2532
|
+
* @see R.prop, R.nth, R.assocPath, R.dissocPath
|
|
2533
|
+
* @example
|
|
2534
|
+
*
|
|
2535
|
+
* R.path(['a', 'b'], {a: {b: 2}}); //=> 2
|
|
2536
|
+
* R.path(['a', 'b'], {c: {b: 2}}); //=> undefined
|
|
2537
|
+
* R.path(['a', 'b', 0], {a: {b: [1, 2, 3]}}); //=> 1
|
|
2538
|
+
* R.path(['a', 'b', -2], {a: {b: [1, 2, 3]}}); //=> 2
|
|
2539
|
+
* R.path([2], {'2': 2}); //=> 2
|
|
2540
|
+
* R.path([-2], {'-2': 'a'}); //=> undefined
|
|
2541
|
+
*/
|
|
2542
|
+
|
|
2543
|
+
var path =
|
|
2544
|
+
/*#__PURE__*/
|
|
2545
|
+
_curry2(function path(pathAr, obj) {
|
|
2546
|
+
return paths([pathAr], obj)[0];
|
|
2547
|
+
});
|
|
2548
|
+
|
|
2549
|
+
/**
|
|
2550
|
+
* Returns a lens whose focus is the specified path.
|
|
2551
|
+
*
|
|
2552
|
+
* @func
|
|
2553
|
+
* @memberOf R
|
|
2554
|
+
* @since v0.19.0
|
|
2555
|
+
* @category Object
|
|
2556
|
+
* @typedefn Idx = String | Int | Symbol
|
|
2557
|
+
* @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
|
|
2558
|
+
* @sig [Idx] -> Lens s a
|
|
2559
|
+
* @param {Array} path The path to use.
|
|
2560
|
+
* @return {Lens}
|
|
2561
|
+
* @see R.view, R.set, R.over
|
|
2562
|
+
* @example
|
|
2563
|
+
*
|
|
2564
|
+
* const xHeadYLens = R.lensPath(['x', 0, 'y']);
|
|
2565
|
+
*
|
|
2566
|
+
* R.view(xHeadYLens, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
|
|
2567
|
+
* //=> 2
|
|
2568
|
+
* R.set(xHeadYLens, 1, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
|
|
2569
|
+
* //=> {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
|
|
2570
|
+
* R.over(xHeadYLens, R.negate, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
|
|
2571
|
+
* //=> {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
|
|
2572
|
+
*/
|
|
2573
|
+
|
|
2574
|
+
var lensPath =
|
|
2575
|
+
/*#__PURE__*/
|
|
2576
|
+
_curry1(function lensPath(p) {
|
|
2577
|
+
return lens(path(p), assocPath(p));
|
|
2578
|
+
});
|
|
2579
|
+
|
|
2580
|
+
var Const = function (x) {
|
|
2581
|
+
return {
|
|
2582
|
+
value: x,
|
|
2583
|
+
'fantasy-land/map': function () {
|
|
2584
|
+
return this;
|
|
2585
|
+
}
|
|
2586
|
+
};
|
|
2587
|
+
};
|
|
2588
|
+
/**
|
|
2589
|
+
* Returns a "view" of the given data structure, determined by the given lens.
|
|
2590
|
+
* The lens's focus determines which portion of the data structure is visible.
|
|
2591
|
+
*
|
|
2592
|
+
* @func
|
|
2593
|
+
* @memberOf R
|
|
2594
|
+
* @since v0.16.0
|
|
2595
|
+
* @category Object
|
|
2596
|
+
* @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
|
|
2597
|
+
* @sig Lens s a -> s -> a
|
|
2598
|
+
* @param {Lens} lens
|
|
2599
|
+
* @param {*} x
|
|
2600
|
+
* @return {*}
|
|
2601
|
+
* @see R.set, R.over, R.lens, R.lensIndex, R.lensProp, R.lensPath
|
|
2602
|
+
* @example
|
|
2603
|
+
*
|
|
2604
|
+
* const xLens = R.lensProp('x');
|
|
2605
|
+
*
|
|
2606
|
+
* R.view(xLens, {x: 1, y: 2}); //=> 1
|
|
2607
|
+
* R.view(xLens, {x: 4, y: 2}); //=> 4
|
|
2608
|
+
*/
|
|
2609
|
+
|
|
2610
|
+
|
|
2611
|
+
var view =
|
|
2612
|
+
/*#__PURE__*/
|
|
2613
|
+
_curry2(function view(lens, x) {
|
|
2614
|
+
// Using `Const` effectively ignores the setter function of the `lens`,
|
|
2615
|
+
// leaving the value returned by the getter function unmodified.
|
|
2616
|
+
return lens(Const)(x).value;
|
|
2617
|
+
});
|
|
2618
|
+
|
|
2619
|
+
// helper functions
|
|
2620
|
+
const findValueBy = curry((src, filterKey, searchStr, key) => {
|
|
2621
|
+
const found = (obj) => includes(searchStr, obj[filterKey]);
|
|
2622
|
+
return compose(prop(key), find(found))(src);
|
|
2623
|
+
});
|
|
2624
|
+
const addressLens = lensPath([ 'results', '0', 'address_components' ]);
|
|
2625
|
+
|
|
2626
|
+
const transformPredictionResponse = (predictions, options = {}) => {
|
|
2627
|
+
const { requestCity, requestState, requestZipcode } = options;
|
|
2628
|
+
|
|
2629
|
+
const extractPrediction = (prediction) => {
|
|
2630
|
+
return { description: prediction.description, placeId: prediction.place_id };
|
|
2631
|
+
};
|
|
2632
|
+
|
|
2633
|
+
let scoredPredictions = null;
|
|
2634
|
+
if (!(requestCity || requestState || requestZipcode)) {
|
|
2635
|
+
scoredPredictions = predictions.map(extractPrediction);
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
scoredPredictions = predictions.map((row) => {
|
|
2639
|
+
const result = {
|
|
2640
|
+
description: row.description,
|
|
2641
|
+
place_id: row.place_id
|
|
2642
|
+
};
|
|
2643
|
+
const cityMatch = row.terms.filter((term) => requestCity && term.value === requestCity).length > 0 ? 1 : 0;
|
|
2644
|
+
const stateMatch = row.terms.filter((term) => requestState && term.value === requestState).length > 0 ? 1 : 0;
|
|
2645
|
+
const zipMatch = row.terms.filter((term) => requestZipcode && term.value === requestZipcode).length > 0 ? 1 : 0;
|
|
2646
|
+
|
|
2647
|
+
result.score = cityMatch + stateMatch + zipMatch;
|
|
2648
|
+
result.stateMatch = !requestState || (requestState && stateMatch);
|
|
2649
|
+
result.zipCodeMatch = !requestZipcode || (requestZipcode && zipMatch);
|
|
2650
|
+
|
|
2651
|
+
return result;
|
|
2652
|
+
}).filter(
|
|
2653
|
+
rec => !!rec.stateMatch && !!rec.zipCodeMatch
|
|
2654
|
+
).sort((a, b) => {
|
|
2655
|
+
if (a.score === b.score) {
|
|
2656
|
+
return 0;
|
|
2657
|
+
}
|
|
2658
|
+
return a.score < b.score ? 1 : -1;
|
|
2659
|
+
}).map(extractPrediction);
|
|
2660
|
+
|
|
2661
|
+
return scoredPredictions;
|
|
2662
|
+
};
|
|
2663
|
+
|
|
2664
|
+
const parsePlacesAddress = (res) => {
|
|
2665
|
+
const placeResult = res.results ? res.results[0] : res.result;
|
|
2666
|
+
if (!placeResult || isEmpty(placeResult)) {
|
|
2667
|
+
return {};
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
let addressComponents = null;
|
|
2671
|
+
if (res.results) {
|
|
2672
|
+
addressComponents = view(addressLens)(res);
|
|
2673
|
+
} else {
|
|
2674
|
+
addressComponents = placeResult.address_components;
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
const findAddressComponentByType = findValueBy(addressComponents, 'types');
|
|
2678
|
+
|
|
2679
|
+
const formattedAddress = placeResult.formatted_address;
|
|
2680
|
+
const latitude =
|
|
2681
|
+
placeResult.geometry &&
|
|
2682
|
+
placeResult.geometry.location &&
|
|
2683
|
+
placeResult.geometry.location.lat
|
|
2684
|
+
? placeResult.geometry.location.lat
|
|
2685
|
+
: null;
|
|
2686
|
+
const longitude =
|
|
2687
|
+
placeResult.geometry &&
|
|
2688
|
+
placeResult.geometry.location &&
|
|
2689
|
+
placeResult.geometry.location.lng
|
|
2690
|
+
? placeResult.geometry.location.lng
|
|
2691
|
+
: null;
|
|
2692
|
+
|
|
2693
|
+
const streetNumber = findAddressComponentByType('street_number', 'short_name') || '';
|
|
2694
|
+
const streetRoute = findAddressComponentByType('route', 'long_name') || '';
|
|
2695
|
+
const street1 =
|
|
2696
|
+
(streetNumber || streetRoute) && `${streetNumber} ${streetRoute}`;
|
|
2697
|
+
|
|
2698
|
+
const address = {
|
|
2699
|
+
state: findAddressComponentByType('administrative_area_level_1', 'short_name'),
|
|
2700
|
+
city:
|
|
2701
|
+
findAddressComponentByType('locality', 'short_name') ||
|
|
2702
|
+
findAddressComponentByType('sublocality', 'short_name') ||
|
|
2703
|
+
findAddressComponentByType('neighborhood', 'long_name') ||
|
|
2704
|
+
findAddressComponentByType('administrative_area_level_3', 'long_name') ||
|
|
2705
|
+
findAddressComponentByType('administrative_area_level_2', 'short_name'),
|
|
2706
|
+
street_1: street1.trim(),
|
|
2707
|
+
country: findAddressComponentByType('country', 'short_name'),
|
|
2708
|
+
zipcode: findAddressComponentByType('postal_code', 'long_name'),
|
|
2709
|
+
latitude: latitude && Number(latitude),
|
|
2710
|
+
longitude: longitude && Number(longitude),
|
|
2711
|
+
formattedAddress
|
|
2712
|
+
};
|
|
2713
|
+
return filter(Boolean)(address);
|
|
2714
|
+
};
|
|
2715
|
+
|
|
2716
|
+
class GeoService {
|
|
2717
|
+
constructor (mapsKey) {
|
|
2718
|
+
this.mapsKey = mapsKey;
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2721
|
+
async geocode (address) {
|
|
2722
|
+
const res = await fetch(
|
|
2723
|
+
`https://maps.googleapis.com/maps/api/geocode/json?address=${address}&key=${this.mapsKey}`
|
|
2724
|
+
);
|
|
2725
|
+
const response = await res.json();
|
|
2726
|
+
return parsePlacesAddress(response);
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
async geocodeZip (zipCode) {
|
|
2730
|
+
const res = await fetch(
|
|
2731
|
+
`https://maps.googleapis.com/maps/api/geocode/json?components=country:US|postal_code:${zipCode}&key=${this.mapsKey}`
|
|
2732
|
+
);
|
|
2733
|
+
const response = await res.json();
|
|
2734
|
+
return parsePlacesAddress(response);
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
async reverseGeocode (lat, lng) {
|
|
2738
|
+
const res = await fetch(
|
|
2739
|
+
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${this.mapsKey}`
|
|
2740
|
+
);
|
|
2741
|
+
const response = await res.json();
|
|
2742
|
+
return parsePlacesAddress(response);
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
async geoLocate () {
|
|
2746
|
+
// https://developers.google.com/maps/documentation/geolocation/overview
|
|
2747
|
+
// NOTE: also returns accuracy (95% confidence of lat, lng in meters)
|
|
2748
|
+
const url = `https://www.googleapis.com/geolocation/v1/geolocate?key=${this.mapsKey}`;
|
|
2749
|
+
const requestConfig = {
|
|
2750
|
+
method: 'POST',
|
|
2751
|
+
headers: {
|
|
2752
|
+
Accept: 'application/json',
|
|
2753
|
+
'Content-Type': 'application/json'
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
const request = await fetch(url, requestConfig);
|
|
2757
|
+
const response = await request.json();
|
|
2758
|
+
const { lat, lng } = response.location;
|
|
2759
|
+
return this.reverseGeocode(lat, lng);
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
async getLocationSuggestions (payload) {
|
|
2763
|
+
/*
|
|
2764
|
+
https://developers.google.com/maps/documentation/places/web-service/autocomplete
|
|
2765
|
+
Component should use session token: https://developers.google.com/maps/documentation/places/web-service/autocomplete#sessiontoken
|
|
2766
|
+
**/
|
|
2767
|
+
const { input, latitude, longitude, radius } = payload;
|
|
2768
|
+
const { requestCity, requestState, requestZipcode } = payload;
|
|
2769
|
+
const location = join(',', filter(Boolean, [ latitude, longitude ]));
|
|
2770
|
+
|
|
2771
|
+
let { sessiontoken } = payload;
|
|
2772
|
+
if (!sessiontoken) {
|
|
2773
|
+
sessiontoken = crypto.randomUUID().replaceAll('-', '');
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
const params = filter(Boolean, {
|
|
2777
|
+
input,
|
|
2778
|
+
sessiontoken,
|
|
2779
|
+
location, // The point around which to retrieve place information.
|
|
2780
|
+
radius, // The radius parameter must also be provided when specifying a location
|
|
2781
|
+
components: 'country:US',
|
|
2782
|
+
types: 'address',
|
|
2783
|
+
key: this.mapsKey
|
|
2784
|
+
});
|
|
2785
|
+
|
|
2786
|
+
let queryString = '';
|
|
2787
|
+
if (params) {
|
|
2788
|
+
const searchParams = new URLSearchParams(params);
|
|
2789
|
+
queryString = searchParams.toString();
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?${queryString}`;
|
|
2793
|
+
const requestConfig = {
|
|
2794
|
+
method: 'GET',
|
|
2795
|
+
headers: {
|
|
2796
|
+
Accept: 'application/json'
|
|
2797
|
+
}
|
|
2798
|
+
};
|
|
2799
|
+
const request = await fetch(url, requestConfig);
|
|
2800
|
+
const response = await request.json();
|
|
2801
|
+
|
|
2802
|
+
let autocompletePredictions = [];
|
|
2803
|
+
if (response.predictions && response.status === 'OK') {
|
|
2804
|
+
const options = { requestCity, requestState, requestZipcode };
|
|
2805
|
+
autocompletePredictions = transformPredictionResponse(response.predictions, options);
|
|
2806
|
+
}
|
|
2807
|
+
return { autocompletePredictions, sessiontoken };
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
async getPlaceId (payload) {
|
|
2811
|
+
const { placeId, sessiontoken } = payload;
|
|
2812
|
+
|
|
2813
|
+
const params = filter(Boolean, {
|
|
2814
|
+
place_id: placeId,
|
|
2815
|
+
sessiontoken,
|
|
2816
|
+
key: this.mapsKey
|
|
2817
|
+
});
|
|
2818
|
+
let queryString = '';
|
|
2819
|
+
if (params) {
|
|
2820
|
+
const searchParams = new URLSearchParams(params);
|
|
2821
|
+
queryString = searchParams.toString();
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
const url = `https://maps.googleapis.com/maps/api/place/details/json?${queryString}`;
|
|
2825
|
+
const res = await fetch(url);
|
|
2826
|
+
const response = await res.json();
|
|
2827
|
+
return parsePlacesAddress(response);
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
async getNavigatorPosition () {
|
|
2831
|
+
// check if navigator is available
|
|
2832
|
+
// NOTE: also returns accuracy (95% confidence of lat, lng in meters)
|
|
2833
|
+
// TODO: check accuracy and only return if within acceptable limit, provided in payload
|
|
2834
|
+
const handleError = (error) => {
|
|
2835
|
+
console.error(error);
|
|
2836
|
+
};
|
|
2837
|
+
(navigator.geolocation && navigator.geolocation.getCurrentPosition(
|
|
2838
|
+
(position) => {
|
|
2839
|
+
const lat = position.coords.latitude;
|
|
2840
|
+
const lng = position.coords.longitude;
|
|
2841
|
+
return this.reverseGeocode(lat, lng);
|
|
2842
|
+
},
|
|
2843
|
+
handleError
|
|
2844
|
+
)) || handleError({ message: 'geolocation is not enabled.' });
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
export { GeoService, ThirstieAPI };
|