first commit
This commit is contained in:
commit
8af364677b
|
|
@ -0,0 +1 @@
|
||||||
|
*.zip
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import IMAGE_EDITOR from "./background/image_editor.js";
|
||||||
|
import REMOVE_BG from "./background/remove_bg.js";
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||||
|
if (request.action && request.action.includes("image_editor")) {
|
||||||
|
return IMAGE_EDITOR._init(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.action && request.action.includes("remove_bg")) {
|
||||||
|
return REMOVE_BG._init(request);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import UTILS from "../background_utils.js";
|
||||||
|
import camelCase from "../libs/lodash/camelCase.js";
|
||||||
|
|
||||||
|
let ROOT_KEY = "image_editor";
|
||||||
|
|
||||||
|
const IMAGE_EDITOR = {
|
||||||
|
_init: function (request) {
|
||||||
|
if (request.action === ROOT_KEY) {
|
||||||
|
// contructor
|
||||||
|
}
|
||||||
|
if (request.action === ROOT_KEY + "__has_capcha") {
|
||||||
|
chrome.action.setBadgeBackgroundColor({ color: "red" });
|
||||||
|
chrome.action.setBadgeTextColor({ color: "white" });
|
||||||
|
chrome.action.setBadgeText({
|
||||||
|
text: "capcha",
|
||||||
|
});
|
||||||
|
return this.sendMessageContent(request);
|
||||||
|
}
|
||||||
|
if (request.action === ROOT_KEY + "__save_image") {
|
||||||
|
return this.sendMessageContent(request)
|
||||||
|
}
|
||||||
|
if (request.action === ROOT_KEY + "__loading") {
|
||||||
|
return this.sendMessageContent(request)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
sendMessageContent(request) {
|
||||||
|
UTILS.sendMessageToTabByURL("localhost", request);
|
||||||
|
UTILS.sendMessageToTabByURL("127.0.0.1", request);
|
||||||
|
UTILS.sendMessageToTabByURL("stage-editor.danielvu.com", request);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IMAGE_EDITOR;
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import UTILS from "../background_utils.js";
|
||||||
|
import camelCase from "../libs/lodash/camelCase.js";
|
||||||
|
import IMAGE_EDITOR from "./image_editor.js";
|
||||||
|
|
||||||
|
let ROOT_KEY = "remove_bg";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
_init: function (request) {
|
||||||
|
if (request.action === ROOT_KEY) {
|
||||||
|
// contructor
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.action === ROOT_KEY + "__execute") {
|
||||||
|
this.sendMessageContent(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.action === ROOT_KEY + "__loading") {
|
||||||
|
|
||||||
|
// to image editor to disable button
|
||||||
|
IMAGE_EDITOR.sendMessageContent({
|
||||||
|
action: "image_editor__loading",
|
||||||
|
status: request.status,
|
||||||
|
});
|
||||||
|
|
||||||
|
// handle more on icon extension chrome
|
||||||
|
if (request.status) {
|
||||||
|
chrome.action.setBadgeText({
|
||||||
|
text: "run",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
chrome.action.setBadgeText({
|
||||||
|
text: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
sendMessageContent(request) {
|
||||||
|
return UTILS.sendMessageToTabByURL("remove.bg", request);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import CONFIG from "./config.js";
|
||||||
|
import UTILS from "./background_utils.js";
|
||||||
|
|
||||||
|
const API = {
|
||||||
|
_get: async function (url, payload, token = null) {
|
||||||
|
try {
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
headers['Authorization'] = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload) {
|
||||||
|
url += '?' + new URLSearchParams(payload).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("background_api: _get", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_post: async function (url, payload, token = null) {
|
||||||
|
try {
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
headers['Authorization'] = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
headers
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("background_api: _post", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO examle
|
||||||
|
example: async function(buyer_id) {
|
||||||
|
const env = await UTILS.getStorage('env') ?? 'dev'
|
||||||
|
const url = CONFIG._ENV[env][url]
|
||||||
|
return await this._get(url, null, {
|
||||||
|
request
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default API;
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
const UTILS = {
|
||||||
|
getStorage: async function (key) {
|
||||||
|
const storage = await chrome.storage.local.get();
|
||||||
|
return storage[key] ?? null;
|
||||||
|
},
|
||||||
|
|
||||||
|
setStorage: async function (key, value) {
|
||||||
|
chrome.storage.local.set({
|
||||||
|
[key]: value,
|
||||||
|
});
|
||||||
|
return await this.getStorage(key);
|
||||||
|
},
|
||||||
|
|
||||||
|
sendMessageToFirstTab: function (data = {}) {
|
||||||
|
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
|
||||||
|
if (tabs.length) {
|
||||||
|
console.log({
|
||||||
|
tabs,
|
||||||
|
});
|
||||||
|
chrome.tabs.sendMessage(tabs[0].id, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sendMessageToTabByURL: function (url, data = {}) {
|
||||||
|
chrome.tabs.query({}, function (tabs) {
|
||||||
|
tabs
|
||||||
|
.filter((tab) => tab.url.includes(url))
|
||||||
|
.forEach((tab) => {
|
||||||
|
chrome.tabs.sendMessage(tab.id, data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UTILS;
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
if (
|
||||||
|
["127.0.0.1", "localhost", "stage-editor.danielvu.com"].includes(
|
||||||
|
location.hostname
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
let ROOT_KEY = "image_editor";
|
||||||
|
let _SELECTOR_BUTTON_ID = "btn_trigger_remove_bg_";
|
||||||
|
|
||||||
|
// INIT
|
||||||
|
window.addEventListener("load", async () => {
|
||||||
|
cloneButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// LISTEN event 🎧🎧🎧
|
||||||
|
chrome.runtime.onMessage.addListener(function (res, sendResponse) {
|
||||||
|
if (res.action === ROOT_KEY + "__has_capcha") {
|
||||||
|
alert("Has capcha! Please select it on remove.bg and go home remove.bg, Thanks!");
|
||||||
|
}
|
||||||
|
if (res.action === ROOT_KEY + "__save_image") {
|
||||||
|
const imageUrl = res.payload.url;
|
||||||
|
const filename = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
|
||||||
|
|
||||||
|
fetch(imageUrl)
|
||||||
|
.then(responseImage => responseImage.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const file = new File([blob], filename, { type: blob.type });
|
||||||
|
const fileList = new DataTransfer();
|
||||||
|
const fileInput = document.querySelector(`#file_${res.payload.id}`)
|
||||||
|
fileList.items.add(file);
|
||||||
|
fileInput.files = fileList.files;
|
||||||
|
fileInput.dispatchEvent(new Event('change'));
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error fetching the image:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (res.action === ROOT_KEY + "__loading") {
|
||||||
|
if (res.status) {
|
||||||
|
document
|
||||||
|
.querySelectorAll(`[id^=clone__${_SELECTOR_BUTTON_ID}]`)
|
||||||
|
?.forEach((btn) => (btn.disabled = true));
|
||||||
|
} else {
|
||||||
|
document
|
||||||
|
.querySelectorAll(`[id^=clone__${_SELECTOR_BUTTON_ID}]`)
|
||||||
|
?.forEach((btn) => (btn.disabled = false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function cloneButton() {
|
||||||
|
window.$intervalCloneButton = setInterval(() => {
|
||||||
|
const selector = `[id^="${_SELECTOR_BUTTON_ID}"]:not([data-has_clone="true"])`;
|
||||||
|
document.querySelectorAll(selector)?.forEach((btn) => {
|
||||||
|
const cloneEl = btn.cloneNode(true);
|
||||||
|
cloneEl.id = "clone__" + cloneEl.id;
|
||||||
|
cloneEl.classList.value = cloneEl.classList.value.replace(
|
||||||
|
"purple",
|
||||||
|
"blue"
|
||||||
|
);
|
||||||
|
cloneEl.querySelector(".q-btn__content ").textContent =
|
||||||
|
"remove.bg extension";
|
||||||
|
cloneEl.addEventListener("click", function () {
|
||||||
|
handleClick(this);
|
||||||
|
});
|
||||||
|
btn.after(cloneEl);
|
||||||
|
btn.setAttribute("data-has_clone", true);
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(btn) {
|
||||||
|
const id = btn.getAttribute("data-id");
|
||||||
|
const urlImg = btn.getAttribute("data-image");
|
||||||
|
|
||||||
|
btn.disabled = true;
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "remove_bg__execute",
|
||||||
|
payload: {
|
||||||
|
id: parseInt(id),
|
||||||
|
url: urlImg,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
if (location.hostname === "www.remove.bg") {
|
||||||
|
let ROOT_KEY = "remove_bg";
|
||||||
|
|
||||||
|
window.addEventListener("load", async () => {
|
||||||
|
// do something after ready page
|
||||||
|
});
|
||||||
|
|
||||||
|
// LISTEN event 🎧🎧🎧
|
||||||
|
chrome.runtime.onMessage.addListener(function (res, sendResponse) {
|
||||||
|
if (res.action === ROOT_KEY + "__execute") {
|
||||||
|
const idEl = "btn_" + new Date().getTime();
|
||||||
|
document.body.innerHTML += `
|
||||||
|
<button id="${idEl}" onclick="window.uploadUrl('${res.payload.url}')"></button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Wait to handle trigger "upload" button
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelector(`#${idEl}`).click();
|
||||||
|
document.querySelector(`#${idEl}`).remove();
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "remove_bg__loading",
|
||||||
|
status: true,
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
window.$getImageRm = setInterval(() => {
|
||||||
|
const imgEl = document.querySelector(
|
||||||
|
'img[src*="removebg-preview.png"]'
|
||||||
|
);
|
||||||
|
if (imgEl) {
|
||||||
|
clearInterval(window.$getImageRm);
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "remove_bg__loading",
|
||||||
|
status: false,
|
||||||
|
});
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "image_editor__save_image",
|
||||||
|
payload: {
|
||||||
|
id: res.payload.id,
|
||||||
|
url: imgEl.src,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Clear old data
|
||||||
|
document
|
||||||
|
.querySelectorAll(".image-result--delete-btn")
|
||||||
|
?.forEach((btn) => btn.click());
|
||||||
|
setTimeout(() => (location.href = "/"), 500);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
window.$checkCapcha = setInterval(() => {
|
||||||
|
const hasCapcha = document.querySelector(".checkbox-captcha");
|
||||||
|
if (hasCapcha) {
|
||||||
|
clearInterval(window.$checkCapcha);
|
||||||
|
// stop loading
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "image_editor__loading",
|
||||||
|
status: false,
|
||||||
|
});
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "image_editor__has_capcha",
|
||||||
|
payload: {
|
||||||
|
msg: "Has capcha!",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 527 B |
Binary file not shown.
|
After Width: | Height: | Size: 690 B |
|
|
@ -0,0 +1,88 @@
|
||||||
|
/** Used to stand-in for `undefined` hash values. */
|
||||||
|
const HASH_UNDEFINED = '__lodash_hash_undefined__'
|
||||||
|
|
||||||
|
class Hash {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a hash object.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} [entries] The key-value pairs to cache.
|
||||||
|
*/
|
||||||
|
constructor(entries) {
|
||||||
|
let index = -1
|
||||||
|
const length = entries == null ? 0 : entries.length
|
||||||
|
|
||||||
|
this.clear()
|
||||||
|
while (++index < length) {
|
||||||
|
const entry = entries[index]
|
||||||
|
this.set(entry[0], entry[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all key-value entries from the hash.
|
||||||
|
*
|
||||||
|
* @memberOf Hash
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.__data__ = Object.create(null)
|
||||||
|
this.size = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes `key` and its value from the hash.
|
||||||
|
*
|
||||||
|
* @memberOf Hash
|
||||||
|
* @param {string} key The key of the value to remove.
|
||||||
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||||||
|
*/
|
||||||
|
delete(key) {
|
||||||
|
const result = this.has(key) && delete this.__data__[key]
|
||||||
|
this.size -= result ? 1 : 0
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hash value for `key`.
|
||||||
|
*
|
||||||
|
* @memberOf Hash
|
||||||
|
* @param {string} key The key of the value to get.
|
||||||
|
* @returns {*} Returns the entry value.
|
||||||
|
*/
|
||||||
|
get(key) {
|
||||||
|
const data = this.__data__
|
||||||
|
const result = data[key]
|
||||||
|
return result === HASH_UNDEFINED ? undefined : result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a hash value for `key` exists.
|
||||||
|
*
|
||||||
|
* @memberOf Hash
|
||||||
|
* @param {string} key The key of the entry to check.
|
||||||
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||||||
|
*/
|
||||||
|
has(key) {
|
||||||
|
const data = this.__data__
|
||||||
|
return data[key] !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hash `key` to `value`.
|
||||||
|
*
|
||||||
|
* @memberOf Hash
|
||||||
|
* @param {string} key The key of the value to set.
|
||||||
|
* @param {*} value The value to set.
|
||||||
|
* @returns {Object} Returns the hash instance.
|
||||||
|
*/
|
||||||
|
set(key, value) {
|
||||||
|
const data = this.__data__
|
||||||
|
this.size += this.has(key) ? 0 : 1
|
||||||
|
data[key] = value === undefined ? HASH_UNDEFINED : value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Hash
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
import assocIndexOf from './assocIndexOf.js'
|
||||||
|
|
||||||
|
class ListCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an list cache object.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} [entries] The key-value pairs to cache.
|
||||||
|
*/
|
||||||
|
constructor(entries) {
|
||||||
|
let index = -1
|
||||||
|
const length = entries == null ? 0 : entries.length
|
||||||
|
|
||||||
|
this.clear()
|
||||||
|
while (++index < length) {
|
||||||
|
const entry = entries[index]
|
||||||
|
this.set(entry[0], entry[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all key-value entries from the list cache.
|
||||||
|
*
|
||||||
|
* @memberOf ListCache
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.__data__ = []
|
||||||
|
this.size = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes `key` and its value from the list cache.
|
||||||
|
*
|
||||||
|
* @memberOf ListCache
|
||||||
|
* @param {string} key The key of the value to remove.
|
||||||
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||||||
|
*/
|
||||||
|
delete(key) {
|
||||||
|
const data = this.__data__
|
||||||
|
const index = assocIndexOf(data, key)
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const lastIndex = data.length - 1
|
||||||
|
if (index == lastIndex) {
|
||||||
|
data.pop()
|
||||||
|
} else {
|
||||||
|
data.splice(index, 1)
|
||||||
|
}
|
||||||
|
--this.size
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list cache value for `key`.
|
||||||
|
*
|
||||||
|
* @memberOf ListCache
|
||||||
|
* @param {string} key The key of the value to get.
|
||||||
|
* @returns {*} Returns the entry value.
|
||||||
|
*/
|
||||||
|
get(key) {
|
||||||
|
const data = this.__data__
|
||||||
|
const index = assocIndexOf(data, key)
|
||||||
|
return index < 0 ? undefined : data[index][1]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a list cache value for `key` exists.
|
||||||
|
*
|
||||||
|
* @memberOf ListCache
|
||||||
|
* @param {string} key The key of the entry to check.
|
||||||
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||||||
|
*/
|
||||||
|
has(key) {
|
||||||
|
return assocIndexOf(this.__data__, key) > -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the list cache `key` to `value`.
|
||||||
|
*
|
||||||
|
* @memberOf ListCache
|
||||||
|
* @param {string} key The key of the value to set.
|
||||||
|
* @param {*} value The value to set.
|
||||||
|
* @returns {Object} Returns the list cache instance.
|
||||||
|
*/
|
||||||
|
set(key, value) {
|
||||||
|
const data = this.__data__
|
||||||
|
const index = assocIndexOf(data, key)
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
++this.size
|
||||||
|
data.push([key, value])
|
||||||
|
} else {
|
||||||
|
data[index][1] = value
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ListCache
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
|
||||||
|
import Hash from './Hash.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data for `map`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} map The map to query.
|
||||||
|
* @param {string} key The reference key.
|
||||||
|
* @returns {*} Returns the map data.
|
||||||
|
*/
|
||||||
|
function getMapData({ __data__ }, key) {
|
||||||
|
const data = __data__
|
||||||
|
return isKeyable(key)
|
||||||
|
? data[typeof key === 'string' ? 'string' : 'hash']
|
||||||
|
: data.map
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if `value` is suitable for use as unique object key.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
|
||||||
|
*/
|
||||||
|
function isKeyable(value) {
|
||||||
|
const type = typeof value
|
||||||
|
return (type === 'string' || type === 'number' || type === 'symbol' || type === 'boolean')
|
||||||
|
? (value !== '__proto__')
|
||||||
|
: (value === null)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MapCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a map cache object to store key-value pairs.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} [entries] The key-value pairs to cache.
|
||||||
|
*/
|
||||||
|
constructor(entries) {
|
||||||
|
let index = -1
|
||||||
|
const length = entries == null ? 0 : entries.length
|
||||||
|
|
||||||
|
this.clear()
|
||||||
|
while (++index < length) {
|
||||||
|
const entry = entries[index]
|
||||||
|
this.set(entry[0], entry[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all key-value entries from the map.
|
||||||
|
*
|
||||||
|
* @memberOf MapCache
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.size = 0
|
||||||
|
this.__data__ = {
|
||||||
|
'hash': new Hash,
|
||||||
|
'map': new Map,
|
||||||
|
'string': new Hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes `key` and its value from the map.
|
||||||
|
*
|
||||||
|
* @memberOf MapCache
|
||||||
|
* @param {string} key The key of the value to remove.
|
||||||
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||||||
|
*/
|
||||||
|
delete(key) {
|
||||||
|
const result = getMapData(this, key)['delete'](key)
|
||||||
|
this.size -= result ? 1 : 0
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the map value for `key`.
|
||||||
|
*
|
||||||
|
* @memberOf MapCache
|
||||||
|
* @param {string} key The key of the value to get.
|
||||||
|
* @returns {*} Returns the entry value.
|
||||||
|
*/
|
||||||
|
get(key) {
|
||||||
|
return getMapData(this, key).get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a map value for `key` exists.
|
||||||
|
*
|
||||||
|
* @memberOf MapCache
|
||||||
|
* @param {string} key The key of the entry to check.
|
||||||
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||||||
|
*/
|
||||||
|
has(key) {
|
||||||
|
return getMapData(this, key).has(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the map `key` to `value`.
|
||||||
|
*
|
||||||
|
* @memberOf MapCache
|
||||||
|
* @param {string} key The key of the value to set.
|
||||||
|
* @param {*} value The value to set.
|
||||||
|
* @returns {Object} Returns the map cache instance.
|
||||||
|
*/
|
||||||
|
set(key, value) {
|
||||||
|
const data = getMapData(this, key)
|
||||||
|
const size = data.size
|
||||||
|
|
||||||
|
data.set(key, value)
|
||||||
|
this.size += data.size == size ? 0 : 1
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapCache
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import MapCache from './MapCache.js'
|
||||||
|
|
||||||
|
/** Used to stand-in for `undefined` hash values. */
|
||||||
|
const HASH_UNDEFINED = '__lodash_hash_undefined__'
|
||||||
|
|
||||||
|
class SetCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array cache object to store unique values.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} [values] The values to cache.
|
||||||
|
*/
|
||||||
|
constructor(values) {
|
||||||
|
let index = -1
|
||||||
|
const length = values == null ? 0 : values.length
|
||||||
|
|
||||||
|
this.__data__ = new MapCache
|
||||||
|
while (++index < length) {
|
||||||
|
this.add(values[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds `value` to the array cache.
|
||||||
|
*
|
||||||
|
* @memberOf SetCache
|
||||||
|
* @alias push
|
||||||
|
* @param {*} value The value to cache.
|
||||||
|
* @returns {Object} Returns the cache instance.
|
||||||
|
*/
|
||||||
|
add(value) {
|
||||||
|
this.__data__.set(value, HASH_UNDEFINED)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if `value` is in the array cache.
|
||||||
|
*
|
||||||
|
* @memberOf SetCache
|
||||||
|
* @param {*} value The value to search for.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is found, else `false`.
|
||||||
|
*/
|
||||||
|
has(value) {
|
||||||
|
return this.__data__.has(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCache.prototype.push = SetCache.prototype.add
|
||||||
|
|
||||||
|
export default SetCache
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
import ListCache from './ListCache.js'
|
||||||
|
import MapCache from './MapCache.js'
|
||||||
|
|
||||||
|
/** Used as the size to enable large array optimizations. */
|
||||||
|
const LARGE_ARRAY_SIZE = 200
|
||||||
|
|
||||||
|
class Stack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a stack cache object to store key-value pairs.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} [entries] The key-value pairs to cache.
|
||||||
|
*/
|
||||||
|
constructor(entries) {
|
||||||
|
const data = this.__data__ = new ListCache(entries)
|
||||||
|
this.size = data.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all key-value entries from the stack.
|
||||||
|
*
|
||||||
|
* @memberOf Stack
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.__data__ = new ListCache
|
||||||
|
this.size = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes `key` and its value from the stack.
|
||||||
|
*
|
||||||
|
* @memberOf Stack
|
||||||
|
* @param {string} key The key of the value to remove.
|
||||||
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||||||
|
*/
|
||||||
|
delete(key) {
|
||||||
|
const data = this.__data__
|
||||||
|
const result = data['delete'](key)
|
||||||
|
|
||||||
|
this.size = data.size
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the stack value for `key`.
|
||||||
|
*
|
||||||
|
* @memberOf Stack
|
||||||
|
* @param {string} key The key of the value to get.
|
||||||
|
* @returns {*} Returns the entry value.
|
||||||
|
*/
|
||||||
|
get(key) {
|
||||||
|
return this.__data__.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a stack value for `key` exists.
|
||||||
|
*
|
||||||
|
* @memberOf Stack
|
||||||
|
* @param {string} key The key of the entry to check.
|
||||||
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||||||
|
*/
|
||||||
|
has(key) {
|
||||||
|
return this.__data__.has(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the stack `key` to `value`.
|
||||||
|
*
|
||||||
|
* @memberOf Stack
|
||||||
|
* @param {string} key The key of the value to set.
|
||||||
|
* @param {*} value The value to set.
|
||||||
|
* @returns {Object} Returns the stack cache instance.
|
||||||
|
*/
|
||||||
|
set(key, value) {
|
||||||
|
let data = this.__data__
|
||||||
|
if (data instanceof ListCache) {
|
||||||
|
const pairs = data.__data__
|
||||||
|
if (pairs.length < LARGE_ARRAY_SIZE - 1) {
|
||||||
|
pairs.push([key, value])
|
||||||
|
this.size = ++data.size
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
data = this.__data__ = new MapCache(pairs)
|
||||||
|
}
|
||||||
|
data.set(key, value)
|
||||||
|
this.size = data.size
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Stack
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Adds the key-value `pair` to `map`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} map The map to modify.
|
||||||
|
* @param {Array} pair The key-value pair to add.
|
||||||
|
* @returns {Object} Returns `map`.
|
||||||
|
*/
|
||||||
|
function addMapEntry(map, pair) {
|
||||||
|
// Don't return `map.set` because it's not chainable in IE 11.
|
||||||
|
map.set(pair[0], pair[1])
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
export default addMapEntry
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Adds `value` to `set`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} set The set to modify.
|
||||||
|
* @param {*} value The value to add.
|
||||||
|
* @returns {Object} Returns `set`.
|
||||||
|
*/
|
||||||
|
function addSetEntry(set, value) {
|
||||||
|
// Don't return `set.add` because it's not chainable in IE 11.
|
||||||
|
set.add(value)
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
export default addSetEntry
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
* A specialized version of `forEach` for arrays.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} [array] The array to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {Array} Returns `array`.
|
||||||
|
*/
|
||||||
|
function arrayEach(array, iteratee) {
|
||||||
|
let index = -1
|
||||||
|
const length = array.length
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
if (iteratee(array[index], index, array) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayEach
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* A specialized version of `forEachRight` for arrays.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} [array] The array to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {Array} Returns `array`.
|
||||||
|
*/
|
||||||
|
function arrayEachRight(array, iteratee) {
|
||||||
|
let length = array == null ? 0 : array.length
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
if (iteratee(array[length], length, array) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayEachRight
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import baseIndexOf from './baseIndexOf.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialized version of `includes` for arrays without support for
|
||||||
|
* specifying an index to search from.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} [array] The array to inspect.
|
||||||
|
* @param {*} target The value to search for.
|
||||||
|
* @returns {boolean} Returns `true` if `target` is found, else `false`.
|
||||||
|
*/
|
||||||
|
function arrayIncludes(array, value) {
|
||||||
|
const length = array == null ? 0 : array.length
|
||||||
|
return !!length && baseIndexOf(array, value, 0) > -1
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayIncludes
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* This function is like `arrayIncludes` except that it accepts a comparator.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} [array] The array to inspect.
|
||||||
|
* @param {*} target The value to search for.
|
||||||
|
* @param {Function} comparator The comparator invoked per element.
|
||||||
|
* @returns {boolean} Returns `true` if `target` is found, else `false`.
|
||||||
|
*/
|
||||||
|
function arrayIncludesWith(array, target, comparator) {
|
||||||
|
if (array == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const value of array) {
|
||||||
|
if (comparator(target, value)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayIncludesWith
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import isArguments from '../isArguments.js'
|
||||||
|
import isBuffer from '../isBuffer.js'
|
||||||
|
import isIndex from './isIndex.js'
|
||||||
|
import isTypedArray from '../isTypedArray.js'
|
||||||
|
|
||||||
|
/** Used to check objects for own properties. */
|
||||||
|
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array of the enumerable property names of the array-like `value`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to query.
|
||||||
|
* @param {boolean} inherited Specify returning inherited property names.
|
||||||
|
* @returns {Array} Returns the array of property names.
|
||||||
|
*/
|
||||||
|
function arrayLikeKeys(value, inherited) {
|
||||||
|
const isArr = Array.isArray(value)
|
||||||
|
const isArg = !isArr && isArguments(value)
|
||||||
|
const isBuff = !isArr && !isArg && isBuffer(value)
|
||||||
|
const isType = !isArr && !isArg && !isBuff && isTypedArray(value)
|
||||||
|
const skipIndexes = isArr || isArg || isBuff || isType
|
||||||
|
const length = value.length
|
||||||
|
const result = new Array(skipIndexes ? length : 0)
|
||||||
|
let index = skipIndexes ? -1 : length
|
||||||
|
while (++index < length) {
|
||||||
|
result[index] = `${index}`
|
||||||
|
}
|
||||||
|
for (const key in value) {
|
||||||
|
if ((inherited || hasOwnProperty.call(value, key)) &&
|
||||||
|
!(skipIndexes && (
|
||||||
|
// Safari 9 has enumerable `arguments.length` in strict mode.
|
||||||
|
(key === 'length' ||
|
||||||
|
// Skip index properties.
|
||||||
|
isIndex(key, length))
|
||||||
|
))) {
|
||||||
|
result.push(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayLikeKeys
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* A specialized version of `reduce` for arrays.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} [array] The array to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @param {*} [accumulator] The initial value.
|
||||||
|
* @param {boolean} [initAccum] Specify using the first element of `array` as
|
||||||
|
* the initial value.
|
||||||
|
* @returns {*} Returns the accumulated value.
|
||||||
|
*/
|
||||||
|
function arrayReduce(array, iteratee, accumulator, initAccum) {
|
||||||
|
let index = -1
|
||||||
|
const length = array == null ? 0 : array.length
|
||||||
|
|
||||||
|
if (initAccum && length) {
|
||||||
|
accumulator = array[++index]
|
||||||
|
}
|
||||||
|
while (++index < length) {
|
||||||
|
accumulator = iteratee(accumulator, array[index], index, array)
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayReduce
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* A specialized version of `reduceRight` for arrays.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} [array] The array to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @param {*} [accumulator] The initial value.
|
||||||
|
* @param {boolean} [initAccum] Specify using the last element of `array` as
|
||||||
|
* the initial value.
|
||||||
|
* @returns {*} Returns the accumulated value.
|
||||||
|
*/
|
||||||
|
function arrayReduceRight(array, iteratee, accumulator, initAccum) {
|
||||||
|
let length = array == null ? 0 : array.length
|
||||||
|
if (initAccum && length) {
|
||||||
|
accumulator = array[--length]
|
||||||
|
}
|
||||||
|
while (length--) {
|
||||||
|
accumulator = iteratee(accumulator, array[length], length, array)
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
export default arrayReduceRight
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* Gets the size of an ASCII `string`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} string The string inspect.
|
||||||
|
* @returns {number} Returns the string size.
|
||||||
|
*/
|
||||||
|
function asciiSize({ length }) {
|
||||||
|
return length
|
||||||
|
}
|
||||||
|
|
||||||
|
export default asciiSize
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* Converts an ASCII `string` to an array.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} string The string to convert.
|
||||||
|
* @returns {Array} Returns the converted array.
|
||||||
|
*/
|
||||||
|
function asciiToArray(string) {
|
||||||
|
return string.split('')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default asciiToArray
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import baseAssignValue from './baseAssignValue.js'
|
||||||
|
import eq from '../eq.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is like `assignValue` except that it doesn't assign
|
||||||
|
* `undefined` values.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to modify.
|
||||||
|
* @param {string} key The key of the property to assign.
|
||||||
|
* @param {*} value The value to assign.
|
||||||
|
*/
|
||||||
|
function assignMergeValue(object, key, value) {
|
||||||
|
if ((value !== undefined && !eq(object[key], value)) ||
|
||||||
|
(value === undefined && !(key in object))) {
|
||||||
|
baseAssignValue(object, key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default assignMergeValue
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import baseAssignValue from './baseAssignValue.js'
|
||||||
|
import eq from '../eq.js'
|
||||||
|
|
||||||
|
/** Used to check objects for own properties. */
|
||||||
|
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns `value` to `key` of `object` if the existing value is not equivalent.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to modify.
|
||||||
|
* @param {string} key The key of the property to assign.
|
||||||
|
* @param {*} value The value to assign.
|
||||||
|
*/
|
||||||
|
function assignValue(object, key, value) {
|
||||||
|
const objValue = object[key]
|
||||||
|
|
||||||
|
if (!(hasOwnProperty.call(object, key) && eq(objValue, value))) {
|
||||||
|
if (value !== 0 || (1 / value) === (1 / objValue)) {
|
||||||
|
baseAssignValue(object, key, value)
|
||||||
|
}
|
||||||
|
} else if (value === undefined && !(key in object)) {
|
||||||
|
baseAssignValue(object, key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default assignValue
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import eq from '../eq.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index at which the `key` is found in `array` of key-value pairs.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {*} key The key to search for.
|
||||||
|
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||||
|
*/
|
||||||
|
function assocIndexOf(array, key) {
|
||||||
|
let { length } = array
|
||||||
|
while (length--) {
|
||||||
|
if (eq(array[length][0], key)) {
|
||||||
|
return length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
export default assocIndexOf
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `assignValue` and `assignMergeValue` without
|
||||||
|
* value checks.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to modify.
|
||||||
|
* @param {string} key The key of the property to assign.
|
||||||
|
* @param {*} value The value to assign.
|
||||||
|
*/
|
||||||
|
function baseAssignValue(object, key, value) {
|
||||||
|
if (key == '__proto__') {
|
||||||
|
Object.defineProperty(object, key, {
|
||||||
|
'configurable': true,
|
||||||
|
'enumerable': true,
|
||||||
|
'value': value,
|
||||||
|
'writable': true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
object[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseAssignValue
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import get from '../get.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `at` without support for individual paths.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to iterate over.
|
||||||
|
* @param {string[]} paths The property paths to pick.
|
||||||
|
* @returns {Array} Returns the picked elements.
|
||||||
|
*/
|
||||||
|
function baseAt(object, paths) {
|
||||||
|
let index = -1
|
||||||
|
const length = paths.length
|
||||||
|
const result = new Array(length)
|
||||||
|
const skip = object == null
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
result[index] = skip ? undefined : get(object, paths[index])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseAt
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
import Stack from './Stack.js'
|
||||||
|
import arrayEach from './arrayEach.js'
|
||||||
|
import assignValue from './assignValue.js'
|
||||||
|
import cloneBuffer from './cloneBuffer.js'
|
||||||
|
import copyArray from './copyArray.js'
|
||||||
|
import copyObject from './copyObject.js'
|
||||||
|
import cloneArrayBuffer from './cloneArrayBuffer.js'
|
||||||
|
import cloneDataView from './cloneDataView.js'
|
||||||
|
import cloneRegExp from './cloneRegExp.js'
|
||||||
|
import cloneSymbol from './cloneSymbol.js'
|
||||||
|
import cloneTypedArray from './cloneTypedArray.js'
|
||||||
|
import copySymbols from './copySymbols.js'
|
||||||
|
import copySymbolsIn from './copySymbolsIn.js'
|
||||||
|
import getAllKeys from './getAllKeys.js'
|
||||||
|
import getAllKeysIn from './getAllKeysIn.js'
|
||||||
|
import getTag from './getTag.js'
|
||||||
|
import initCloneObject from './initCloneObject.js'
|
||||||
|
import isBuffer from '../isBuffer.js'
|
||||||
|
import isObject from '../isObject.js'
|
||||||
|
import isTypedArray from '../isTypedArray.js'
|
||||||
|
import keys from '../keys.js'
|
||||||
|
import keysIn from '../keysIn.js'
|
||||||
|
|
||||||
|
/** Used to compose bitmasks for cloning. */
|
||||||
|
const CLONE_DEEP_FLAG = 1
|
||||||
|
const CLONE_FLAT_FLAG = 2
|
||||||
|
const CLONE_SYMBOLS_FLAG = 4
|
||||||
|
|
||||||
|
/** `Object#toString` result references. */
|
||||||
|
const argsTag = '[object Arguments]'
|
||||||
|
const arrayTag = '[object Array]'
|
||||||
|
const boolTag = '[object Boolean]'
|
||||||
|
const dateTag = '[object Date]'
|
||||||
|
const errorTag = '[object Error]'
|
||||||
|
const mapTag = '[object Map]'
|
||||||
|
const numberTag = '[object Number]'
|
||||||
|
const objectTag = '[object Object]'
|
||||||
|
const regexpTag = '[object RegExp]'
|
||||||
|
const setTag = '[object Set]'
|
||||||
|
const stringTag = '[object String]'
|
||||||
|
const symbolTag = '[object Symbol]'
|
||||||
|
const weakMapTag = '[object WeakMap]'
|
||||||
|
|
||||||
|
const arrayBufferTag = '[object ArrayBuffer]'
|
||||||
|
const dataViewTag = '[object DataView]'
|
||||||
|
const float32Tag = '[object Float32Array]'
|
||||||
|
const float64Tag = '[object Float64Array]'
|
||||||
|
const int8Tag = '[object Int8Array]'
|
||||||
|
const int16Tag = '[object Int16Array]'
|
||||||
|
const int32Tag = '[object Int32Array]'
|
||||||
|
const uint8Tag = '[object Uint8Array]'
|
||||||
|
const uint8ClampedTag = '[object Uint8ClampedArray]'
|
||||||
|
const uint16Tag = '[object Uint16Array]'
|
||||||
|
const uint32Tag = '[object Uint32Array]'
|
||||||
|
|
||||||
|
/** Used to identify `toStringTag` values supported by `clone`. */
|
||||||
|
const cloneableTags = {}
|
||||||
|
cloneableTags[argsTag] = cloneableTags[arrayTag] =
|
||||||
|
cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
|
||||||
|
cloneableTags[boolTag] = cloneableTags[dateTag] =
|
||||||
|
cloneableTags[float32Tag] = cloneableTags[float64Tag] =
|
||||||
|
cloneableTags[int8Tag] = cloneableTags[int16Tag] =
|
||||||
|
cloneableTags[int32Tag] = cloneableTags[mapTag] =
|
||||||
|
cloneableTags[numberTag] = cloneableTags[objectTag] =
|
||||||
|
cloneableTags[regexpTag] = cloneableTags[setTag] =
|
||||||
|
cloneableTags[stringTag] = cloneableTags[symbolTag] =
|
||||||
|
cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
|
||||||
|
cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true
|
||||||
|
cloneableTags[errorTag] = cloneableTags[weakMapTag] = false
|
||||||
|
|
||||||
|
/** Used to check objects for own properties. */
|
||||||
|
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an object clone based on its `toStringTag`.
|
||||||
|
*
|
||||||
|
* **Note:** This function only supports cloning values with tags of
|
||||||
|
* `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to clone.
|
||||||
|
* @param {string} tag The `toStringTag` of the object to clone.
|
||||||
|
* @param {boolean} [isDeep] Specify a deep clone.
|
||||||
|
* @returns {Object} Returns the initialized clone.
|
||||||
|
*/
|
||||||
|
function initCloneByTag(object, tag, isDeep) {
|
||||||
|
const Ctor = object.constructor
|
||||||
|
switch (tag) {
|
||||||
|
case arrayBufferTag:
|
||||||
|
return cloneArrayBuffer(object)
|
||||||
|
|
||||||
|
case boolTag:
|
||||||
|
case dateTag:
|
||||||
|
return new Ctor(+object)
|
||||||
|
|
||||||
|
case dataViewTag:
|
||||||
|
return cloneDataView(object, isDeep)
|
||||||
|
|
||||||
|
case float32Tag: case float64Tag:
|
||||||
|
case int8Tag: case int16Tag: case int32Tag:
|
||||||
|
case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
|
||||||
|
return cloneTypedArray(object, isDeep)
|
||||||
|
|
||||||
|
case mapTag:
|
||||||
|
return new Ctor
|
||||||
|
|
||||||
|
case numberTag:
|
||||||
|
case stringTag:
|
||||||
|
return new Ctor(object)
|
||||||
|
|
||||||
|
case regexpTag:
|
||||||
|
return cloneRegExp(object)
|
||||||
|
|
||||||
|
case setTag:
|
||||||
|
return new Ctor
|
||||||
|
|
||||||
|
case symbolTag:
|
||||||
|
return cloneSymbol(object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an array clone.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to clone.
|
||||||
|
* @returns {Array} Returns the initialized clone.
|
||||||
|
*/
|
||||||
|
function initCloneArray(array) {
|
||||||
|
const { length } = array
|
||||||
|
const result = new array.constructor(length)
|
||||||
|
|
||||||
|
// Add properties assigned by `RegExp#exec`.
|
||||||
|
if (length && typeof array[0] === 'string' && hasOwnProperty.call(array, 'index')) {
|
||||||
|
result.index = array.index
|
||||||
|
result.input = array.input
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `clone` and `cloneDeep` which tracks
|
||||||
|
* traversed objects.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to clone.
|
||||||
|
* @param {number} bitmask The bitmask flags.
|
||||||
|
* 1 - Deep clone
|
||||||
|
* 2 - Flatten inherited properties
|
||||||
|
* 4 - Clone symbols
|
||||||
|
* @param {Function} [customizer] The function to customize cloning.
|
||||||
|
* @param {string} [key] The key of `value`.
|
||||||
|
* @param {Object} [object] The parent object of `value`.
|
||||||
|
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
|
||||||
|
* @returns {*} Returns the cloned value.
|
||||||
|
*/
|
||||||
|
function baseClone(value, bitmask, customizer, key, object, stack) {
|
||||||
|
let result
|
||||||
|
const isDeep = bitmask & CLONE_DEEP_FLAG
|
||||||
|
const isFlat = bitmask & CLONE_FLAT_FLAG
|
||||||
|
const isFull = bitmask & CLONE_SYMBOLS_FLAG
|
||||||
|
|
||||||
|
if (customizer) {
|
||||||
|
result = object ? customizer(value, key, object, stack) : customizer(value)
|
||||||
|
}
|
||||||
|
if (result !== undefined) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
if (!isObject(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
const isArr = Array.isArray(value)
|
||||||
|
const tag = getTag(value)
|
||||||
|
if (isArr) {
|
||||||
|
result = initCloneArray(value)
|
||||||
|
if (!isDeep) {
|
||||||
|
return copyArray(value, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const isFunc = typeof value === 'function'
|
||||||
|
|
||||||
|
if (isBuffer(value)) {
|
||||||
|
return cloneBuffer(value, isDeep)
|
||||||
|
}
|
||||||
|
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
|
||||||
|
result = (isFlat || isFunc) ? {} : initCloneObject(value)
|
||||||
|
if (!isDeep) {
|
||||||
|
return isFlat
|
||||||
|
? copySymbolsIn(value, copyObject(value, keysIn(value), result))
|
||||||
|
: copySymbols(value, Object.assign(result, value))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isFunc || !cloneableTags[tag]) {
|
||||||
|
return object ? value : {}
|
||||||
|
}
|
||||||
|
result = initCloneByTag(value, tag, isDeep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check for circular references and return its corresponding clone.
|
||||||
|
stack || (stack = new Stack)
|
||||||
|
const stacked = stack.get(value)
|
||||||
|
if (stacked) {
|
||||||
|
return stacked
|
||||||
|
}
|
||||||
|
stack.set(value, result)
|
||||||
|
|
||||||
|
if (tag == mapTag) {
|
||||||
|
value.forEach((subValue, key) => {
|
||||||
|
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack))
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == setTag) {
|
||||||
|
value.forEach((subValue) => {
|
||||||
|
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack))
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTypedArray(value)) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const keysFunc = isFull
|
||||||
|
? (isFlat ? getAllKeysIn : getAllKeys)
|
||||||
|
: (isFlat ? keysIn : keys)
|
||||||
|
|
||||||
|
const props = isArr ? undefined : keysFunc(value)
|
||||||
|
arrayEach(props || value, (subValue, key) => {
|
||||||
|
if (props) {
|
||||||
|
key = subValue
|
||||||
|
subValue = value[key]
|
||||||
|
}
|
||||||
|
// Recursively populate clone (susceptible to call stack limits).
|
||||||
|
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack))
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseClone
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import baseConformsTo from './baseConformsTo.js'
|
||||||
|
import keys from '../keys.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `conforms` which doesn't clone `source`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} source The object of property predicates to conform to.
|
||||||
|
* @returns {Function} Returns the new spec function.
|
||||||
|
*/
|
||||||
|
function baseConforms(source) {
|
||||||
|
const props = keys(source)
|
||||||
|
return (object) => baseConformsTo(object, source, props)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseConforms
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `conformsTo` which accepts `props` to check.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to inspect.
|
||||||
|
* @param {Object} source The object of property predicates to conform to.
|
||||||
|
* @returns {boolean} Returns `true` if `object` conforms, else `false`.
|
||||||
|
*/
|
||||||
|
function baseConformsTo(object, source, props) {
|
||||||
|
let length = props.length
|
||||||
|
if (object == null) {
|
||||||
|
return !length
|
||||||
|
}
|
||||||
|
object = Object(object)
|
||||||
|
while (length--) {
|
||||||
|
const key = props[length]
|
||||||
|
const predicate = source[key]
|
||||||
|
const value = object[key]
|
||||||
|
|
||||||
|
if ((value === undefined && !(key in object)) || !predicate(value)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseConformsTo
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
import SetCache from './SetCache.js'
|
||||||
|
import arrayIncludes from './arrayIncludes.js'
|
||||||
|
import arrayIncludesWith from './arrayIncludesWith.js'
|
||||||
|
import map from '../map.js'
|
||||||
|
import cacheHas from './cacheHas.js'
|
||||||
|
|
||||||
|
/** Used as the size to enable large array optimizations. */
|
||||||
|
const LARGE_ARRAY_SIZE = 200
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of methods like `difference` without support
|
||||||
|
* for excluding multiple arrays.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {Array} values The values to exclude.
|
||||||
|
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||||
|
* @param {Function} [comparator] The comparator invoked per element.
|
||||||
|
* @returns {Array} Returns the new array of filtered values.
|
||||||
|
*/
|
||||||
|
function baseDifference(array, values, iteratee, comparator) {
|
||||||
|
let includes = arrayIncludes
|
||||||
|
let isCommon = true
|
||||||
|
const result = []
|
||||||
|
const valuesLength = values.length
|
||||||
|
|
||||||
|
if (!array.length) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
if (iteratee) {
|
||||||
|
values = map(values, (value) => iteratee(value))
|
||||||
|
}
|
||||||
|
if (comparator) {
|
||||||
|
includes = arrayIncludesWith
|
||||||
|
isCommon = false
|
||||||
|
}
|
||||||
|
else if (values.length >= LARGE_ARRAY_SIZE) {
|
||||||
|
includes = cacheHas
|
||||||
|
isCommon = false
|
||||||
|
values = new SetCache(values)
|
||||||
|
}
|
||||||
|
outer:
|
||||||
|
for (let value of array) {
|
||||||
|
const computed = iteratee == null ? value : iteratee(value)
|
||||||
|
|
||||||
|
value = (comparator || value !== 0) ? value : 0
|
||||||
|
if (isCommon && computed === computed) {
|
||||||
|
let valuesIndex = valuesLength
|
||||||
|
while (valuesIndex--) {
|
||||||
|
if (values[valuesIndex] === computed) {
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(value)
|
||||||
|
}
|
||||||
|
else if (!includes(values, computed, comparator)) {
|
||||||
|
result.push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseDifference
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import baseForOwn from './baseForOwn.js'
|
||||||
|
import isArrayLike from '../isArrayLike.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `forEach`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array|Object} collection The collection to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {Array|Object} Returns `collection`.
|
||||||
|
*/
|
||||||
|
function baseEach(collection, iteratee) {
|
||||||
|
if (collection == null) {
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
if (!isArrayLike(collection)) {
|
||||||
|
return baseForOwn(collection, iteratee)
|
||||||
|
}
|
||||||
|
const length = collection.length
|
||||||
|
const iterable = Object(collection)
|
||||||
|
let index = -1
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
if (iteratee(iterable[index], index, iterable) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseEach
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import baseForOwnRight from './baseForOwnRight.js'
|
||||||
|
import isArrayLike from '../isArrayLike.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `forEachRight`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array|Object} collection The collection to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {Array|Object} Returns `collection`.
|
||||||
|
*/
|
||||||
|
function baseEachRight(collection, iteratee) {
|
||||||
|
if (collection == null) {
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
if (!isArrayLike(collection)) {
|
||||||
|
return baseForOwnRight(collection, iteratee)
|
||||||
|
}
|
||||||
|
const iterable = Object(collection)
|
||||||
|
let length = collection.length
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
if (iteratee(iterable[length], length, iterable) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseEachRight
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `findIndex` and `findLastIndex`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {Function} predicate The function invoked per iteration.
|
||||||
|
* @param {number} fromIndex The index to search from.
|
||||||
|
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||||||
|
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||||
|
*/
|
||||||
|
function baseFindIndex(array, predicate, fromIndex, fromRight) {
|
||||||
|
const { length } = array
|
||||||
|
let index = fromIndex + (fromRight ? 1 : -1)
|
||||||
|
|
||||||
|
while ((fromRight ? index-- : ++index < length)) {
|
||||||
|
if (predicate(array[index], index, array)) {
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseFindIndex
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of methods like `findKey` and `findLastKey`
|
||||||
|
* which iterates over `collection` using `eachFunc`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array|Object} collection The collection to inspect.
|
||||||
|
* @param {Function} predicate The function invoked per iteration.
|
||||||
|
* @param {Function} eachFunc The function to iterate over `collection`.
|
||||||
|
* @returns {*} Returns the found element or its key, else `undefined`.
|
||||||
|
*/
|
||||||
|
function baseFindKey(collection, predicate, eachFunc) {
|
||||||
|
let result
|
||||||
|
eachFunc(collection, (value, key, collection) => {
|
||||||
|
if (predicate(value, key, collection)) {
|
||||||
|
result = key
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseFindKey
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import isFlattenable from './isFlattenable.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `flatten` with support for restricting flattening.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to flatten.
|
||||||
|
* @param {number} depth The maximum recursion depth.
|
||||||
|
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
|
||||||
|
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
|
||||||
|
* @param {Array} [result=[]] The initial result value.
|
||||||
|
* @returns {Array} Returns the new flattened array.
|
||||||
|
*/
|
||||||
|
function baseFlatten(array, depth, predicate, isStrict, result) {
|
||||||
|
predicate || (predicate = isFlattenable)
|
||||||
|
result || (result = [])
|
||||||
|
|
||||||
|
if (array == null) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const value of array) {
|
||||||
|
if (depth > 0 && predicate(value)) {
|
||||||
|
if (depth > 1) {
|
||||||
|
// Recursively flatten arrays (susceptible to call stack limits).
|
||||||
|
baseFlatten(value, depth - 1, predicate, isStrict, result)
|
||||||
|
} else {
|
||||||
|
result.push(...value)
|
||||||
|
}
|
||||||
|
} else if (!isStrict) {
|
||||||
|
result[result.length] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseFlatten
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `baseForOwn` which iterates over `object`
|
||||||
|
* properties returned by `keysFunc` and invokes `iteratee` for each property.
|
||||||
|
* Iteratee functions may exit iteration early by explicitly returning `false`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @param {Function} keysFunc The function to get the keys of `object`.
|
||||||
|
* @returns {Object} Returns `object`.
|
||||||
|
*/
|
||||||
|
function baseFor(object, iteratee, keysFunc) {
|
||||||
|
const iterable = Object(object)
|
||||||
|
const props = keysFunc(object)
|
||||||
|
let { length } = props
|
||||||
|
let index = -1
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
const key = props[++index]
|
||||||
|
if (iteratee(iterable[key], key, iterable) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseFor
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import baseFor from './baseFor.js'
|
||||||
|
import keys from '../keys.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `forOwn`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {Object} Returns `object`.
|
||||||
|
*/
|
||||||
|
function baseForOwn(object, iteratee) {
|
||||||
|
return object && baseFor(object, iteratee, keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseForOwn
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import baseForRight from './baseForRight.js'
|
||||||
|
import keys from '../keys.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `forOwnRight`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {Object} Returns `object`.
|
||||||
|
*/
|
||||||
|
function baseForOwnRight(object, iteratee) {
|
||||||
|
return object && baseForRight(object, iteratee, keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseForOwnRight
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* This function is like `baseFor` except that it iterates over properties
|
||||||
|
* in the opposite order.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @param {Function} keysFunc The function to get the keys of `object`.
|
||||||
|
* @returns {Object} Returns `object`.
|
||||||
|
*/
|
||||||
|
function baseForRight(object, iteratee, keysFunc) {
|
||||||
|
const iterable = Object(object)
|
||||||
|
const props = keysFunc(object)
|
||||||
|
let { length } = props
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
const key = props[length]
|
||||||
|
if (iteratee(iterable[key], key, iterable) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseForRight
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import castPath from './castPath.js'
|
||||||
|
import toKey from './toKey.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `get` without support for default values.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to query.
|
||||||
|
* @param {Array|string} path The path of the property to get.
|
||||||
|
* @returns {*} Returns the resolved value.
|
||||||
|
*/
|
||||||
|
function baseGet(object, path) {
|
||||||
|
path = castPath(path, object)
|
||||||
|
|
||||||
|
let index = 0
|
||||||
|
const length = path.length
|
||||||
|
|
||||||
|
while (object != null && index < length) {
|
||||||
|
object = object[toKey(path[index++])]
|
||||||
|
}
|
||||||
|
return (index && index == length) ? object : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseGet
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `inRange` which doesn't coerce arguments.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {number} number The number to check.
|
||||||
|
* @param {number} start The start of the range.
|
||||||
|
* @param {number} end The end of the range.
|
||||||
|
* @returns {boolean} Returns `true` if `number` is in the range, else `false`.
|
||||||
|
*/
|
||||||
|
function baseInRange(number, start, end) {
|
||||||
|
return number >= Math.min(start, end) && number < Math.max(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseInRange
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import baseFindIndex from './baseFindIndex.js'
|
||||||
|
import baseIsNaN from './baseIsNaN.js'
|
||||||
|
import strictIndexOf from './strictIndexOf.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `indexOf` without `fromIndex` bounds checks.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {*} value The value to search for.
|
||||||
|
* @param {number} fromIndex The index to search from.
|
||||||
|
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||||
|
*/
|
||||||
|
function baseIndexOf(array, value, fromIndex) {
|
||||||
|
return value === value
|
||||||
|
? strictIndexOf(array, value, fromIndex)
|
||||||
|
: baseFindIndex(array, baseIsNaN, fromIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIndexOf
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* This function is like `baseIndexOf` except that it accepts a comparator.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {*} value The value to search for.
|
||||||
|
* @param {number} fromIndex The index to search from.
|
||||||
|
* @param {Function} comparator The comparator invoked per element.
|
||||||
|
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||||
|
*/
|
||||||
|
function baseIndexOfWith(array, value, fromIndex, comparator) {
|
||||||
|
let index = fromIndex - 1
|
||||||
|
const { length } = array
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
if (comparator(array[index], value)) {
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIndexOfWith
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
import SetCache from './SetCache.js'
|
||||||
|
import arrayIncludes from './arrayIncludes.js'
|
||||||
|
import arrayIncludesWith from './arrayIncludesWith.js'
|
||||||
|
import map from '../map.js'
|
||||||
|
import cacheHas from './cacheHas.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of methods like `intersection` that accepts an
|
||||||
|
* array of arrays to inspect.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} arrays The arrays to inspect.
|
||||||
|
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||||
|
* @param {Function} [comparator] The comparator invoked per element.
|
||||||
|
* @returns {Array} Returns the new array of shared values.
|
||||||
|
*/
|
||||||
|
function baseIntersection(arrays, iteratee, comparator) {
|
||||||
|
const includes = comparator ? arrayIncludesWith : arrayIncludes
|
||||||
|
const length = arrays[0].length
|
||||||
|
const othLength = arrays.length
|
||||||
|
const caches = new Array(othLength)
|
||||||
|
const result = []
|
||||||
|
|
||||||
|
let array
|
||||||
|
let maxLength = Infinity
|
||||||
|
let othIndex = othLength
|
||||||
|
|
||||||
|
while (othIndex--) {
|
||||||
|
array = arrays[othIndex]
|
||||||
|
if (othIndex && iteratee) {
|
||||||
|
array = map(array, (value) => iteratee(value))
|
||||||
|
}
|
||||||
|
maxLength = Math.min(array.length, maxLength)
|
||||||
|
caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
|
||||||
|
? new SetCache(othIndex && array)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
array = arrays[0]
|
||||||
|
|
||||||
|
let index = -1
|
||||||
|
const seen = caches[0]
|
||||||
|
|
||||||
|
outer:
|
||||||
|
while (++index < length && result.length < maxLength) {
|
||||||
|
let value = array[index]
|
||||||
|
const computed = iteratee ? iteratee(value) : value
|
||||||
|
|
||||||
|
value = (comparator || value !== 0) ? value : 0
|
||||||
|
if (!(seen
|
||||||
|
? cacheHas(seen, computed)
|
||||||
|
: includes(result, computed, comparator)
|
||||||
|
)) {
|
||||||
|
othIndex = othLength
|
||||||
|
while (--othIndex) {
|
||||||
|
const cache = caches[othIndex]
|
||||||
|
if (!(cache
|
||||||
|
? cacheHas(cache, computed)
|
||||||
|
: includes(arrays[othIndex], computed, comparator))
|
||||||
|
) {
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (seen) {
|
||||||
|
seen.push(computed)
|
||||||
|
}
|
||||||
|
result.push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIntersection
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import baseIsEqualDeep from './baseIsEqualDeep.js'
|
||||||
|
import isObjectLike from '../isObjectLike.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `isEqual` which supports partial comparisons
|
||||||
|
* and tracks traversed objects.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to compare.
|
||||||
|
* @param {*} other The other value to compare.
|
||||||
|
* @param {boolean} bitmask The bitmask flags.
|
||||||
|
* 1 - Unordered comparison
|
||||||
|
* 2 - Partial comparison
|
||||||
|
* @param {Function} [customizer] The function to customize comparisons.
|
||||||
|
* @param {Object} [stack] Tracks traversed `value` and `other` objects.
|
||||||
|
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
||||||
|
*/
|
||||||
|
function baseIsEqual(value, other, bitmask, customizer, stack) {
|
||||||
|
if (value === other) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
|
||||||
|
return value !== value && other !== other
|
||||||
|
}
|
||||||
|
return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIsEqual
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
import Stack from './Stack.js'
|
||||||
|
import equalArrays from './equalArrays.js'
|
||||||
|
import equalByTag from './equalByTag.js'
|
||||||
|
import equalObjects from './equalObjects.js'
|
||||||
|
import getTag from './getTag.js'
|
||||||
|
import isBuffer from '../isBuffer.js'
|
||||||
|
import isTypedArray from '../isTypedArray.js'
|
||||||
|
|
||||||
|
/** Used to compose bitmasks for value comparisons. */
|
||||||
|
const COMPARE_PARTIAL_FLAG = 1
|
||||||
|
|
||||||
|
/** `Object#toString` result references. */
|
||||||
|
const argsTag = '[object Arguments]'
|
||||||
|
const arrayTag = '[object Array]'
|
||||||
|
const objectTag = '[object Object]'
|
||||||
|
|
||||||
|
/** Used to check objects for own properties. */
|
||||||
|
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialized version of `baseIsEqual` for arrays and objects which performs
|
||||||
|
* deep comparisons and tracks traversed objects enabling objects with circular
|
||||||
|
* references to be compared.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to compare.
|
||||||
|
* @param {Object} other The other object to compare.
|
||||||
|
* @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
|
||||||
|
* @param {Function} customizer The function to customize comparisons.
|
||||||
|
* @param {Function} equalFunc The function to determine equivalents of values.
|
||||||
|
* @param {Object} [stack] Tracks traversed `object` and `other` objects.
|
||||||
|
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
|
||||||
|
*/
|
||||||
|
function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
|
||||||
|
let objIsArr = Array.isArray(object)
|
||||||
|
const othIsArr = Array.isArray(other)
|
||||||
|
let objTag = objIsArr ? arrayTag : getTag(object)
|
||||||
|
let othTag = othIsArr ? arrayTag : getTag(other)
|
||||||
|
|
||||||
|
objTag = objTag == argsTag ? objectTag : objTag
|
||||||
|
othTag = othTag == argsTag ? objectTag : othTag
|
||||||
|
|
||||||
|
let objIsObj = objTag == objectTag
|
||||||
|
const othIsObj = othTag == objectTag
|
||||||
|
const isSameTag = objTag == othTag
|
||||||
|
|
||||||
|
if (isSameTag && isBuffer(object)) {
|
||||||
|
if (!isBuffer(other)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
objIsArr = true
|
||||||
|
objIsObj = false
|
||||||
|
}
|
||||||
|
if (isSameTag && !objIsObj) {
|
||||||
|
stack || (stack = new Stack)
|
||||||
|
return (objIsArr || isTypedArray(object))
|
||||||
|
? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
|
||||||
|
: equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack)
|
||||||
|
}
|
||||||
|
if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
|
||||||
|
const objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__')
|
||||||
|
const othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__')
|
||||||
|
|
||||||
|
if (objIsWrapped || othIsWrapped) {
|
||||||
|
const objUnwrapped = objIsWrapped ? object.value() : object
|
||||||
|
const othUnwrapped = othIsWrapped ? other.value() : other
|
||||||
|
|
||||||
|
stack || (stack = new Stack)
|
||||||
|
return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isSameTag) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
stack || (stack = new Stack)
|
||||||
|
return equalObjects(object, other, bitmask, customizer, equalFunc, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIsEqualDeep
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
import Stack from './Stack.js'
|
||||||
|
import baseIsEqual from './baseIsEqual.js'
|
||||||
|
|
||||||
|
/** Used to compose bitmasks for value comparisons. */
|
||||||
|
const COMPARE_PARTIAL_FLAG = 1
|
||||||
|
const COMPARE_UNORDERED_FLAG = 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `isMatch`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to inspect.
|
||||||
|
* @param {Object} source The object of property values to match.
|
||||||
|
* @param {Array} matchData The property names, values, and compare flags to match.
|
||||||
|
* @param {Function} [customizer] The function to customize comparisons.
|
||||||
|
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
|
||||||
|
*/
|
||||||
|
function baseIsMatch(object, source, matchData, customizer) {
|
||||||
|
let index = matchData.length
|
||||||
|
const length = index
|
||||||
|
const noCustomizer = !customizer
|
||||||
|
|
||||||
|
if (object == null) {
|
||||||
|
return !length
|
||||||
|
}
|
||||||
|
let data
|
||||||
|
let result
|
||||||
|
object = Object(object)
|
||||||
|
while (index--) {
|
||||||
|
data = matchData[index]
|
||||||
|
if ((noCustomizer && data[2])
|
||||||
|
? data[1] !== object[data[0]]
|
||||||
|
: !(data[0] in object)
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (++index < length) {
|
||||||
|
data = matchData[index]
|
||||||
|
const key = data[0]
|
||||||
|
const objValue = object[key]
|
||||||
|
const srcValue = data[1]
|
||||||
|
|
||||||
|
if (noCustomizer && data[2]) {
|
||||||
|
if (objValue === undefined && !(key in object)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const stack = new Stack
|
||||||
|
if (customizer) {
|
||||||
|
result = customizer(objValue, srcValue, key, object, source, stack)
|
||||||
|
}
|
||||||
|
if (!(result === undefined
|
||||||
|
? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
|
||||||
|
: result
|
||||||
|
)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIsMatch
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `isNaN` without support for number objects.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
|
||||||
|
*/
|
||||||
|
function baseIsNaN(value) {
|
||||||
|
return value !== value
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseIsNaN
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import baseIsMatch from './baseIsMatch.js'
|
||||||
|
import getMatchData from './getMatchData.js'
|
||||||
|
import matchesStrictComparable from './matchesStrictComparable.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `matches` which doesn't clone `source`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} source The object of property values to match.
|
||||||
|
* @returns {Function} Returns the new spec function.
|
||||||
|
*/
|
||||||
|
function baseMatches(source) {
|
||||||
|
const matchData = getMatchData(source)
|
||||||
|
if (matchData.length === 1 && matchData[0][2]) {
|
||||||
|
return matchesStrictComparable(matchData[0][0], matchData[0][1])
|
||||||
|
}
|
||||||
|
return (object) => object === source || baseIsMatch(object, source, matchData)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseMatches
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import baseIsEqual from './baseIsEqual.js'
|
||||||
|
import get from '../get.js'
|
||||||
|
import hasIn from '../hasIn.js'
|
||||||
|
import isKey from './isKey.js'
|
||||||
|
import isStrictComparable from './isStrictComparable.js'
|
||||||
|
import matchesStrictComparable from './matchesStrictComparable.js'
|
||||||
|
import toKey from './toKey.js'
|
||||||
|
|
||||||
|
/** Used to compose bitmasks for value comparisons. */
|
||||||
|
const COMPARE_PARTIAL_FLAG = 1
|
||||||
|
const COMPARE_UNORDERED_FLAG = 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `matchesProperty` which doesn't clone `srcValue`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} path The path of the property to get.
|
||||||
|
* @param {*} srcValue The value to match.
|
||||||
|
* @returns {Function} Returns the new spec function.
|
||||||
|
*/
|
||||||
|
function baseMatchesProperty(path, srcValue) {
|
||||||
|
if (isKey(path) && isStrictComparable(srcValue)) {
|
||||||
|
return matchesStrictComparable(toKey(path), srcValue)
|
||||||
|
}
|
||||||
|
return (object) => {
|
||||||
|
const objValue = get(object, path)
|
||||||
|
return (objValue === undefined && objValue === srcValue)
|
||||||
|
? hasIn(object, path)
|
||||||
|
: baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseMatchesProperty
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import Stack from './Stack.js'
|
||||||
|
import assignMergeValue from './assignMergeValue.js'
|
||||||
|
import baseFor from './baseFor.js'
|
||||||
|
import baseMergeDeep from './baseMergeDeep.js'
|
||||||
|
import isObject from '../isObject.js'
|
||||||
|
import keysIn from '../keysIn.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `merge` without support for multiple sources.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The destination object.
|
||||||
|
* @param {Object} source The source object.
|
||||||
|
* @param {number} srcIndex The index of `source`.
|
||||||
|
* @param {Function} [customizer] The function to customize merged values.
|
||||||
|
* @param {Object} [stack] Tracks traversed source values and their merged
|
||||||
|
* counterparts.
|
||||||
|
*/
|
||||||
|
function baseMerge(object, source, srcIndex, customizer, stack) {
|
||||||
|
if (object === source) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
baseFor(source, (srcValue, key) => {
|
||||||
|
if (isObject(srcValue)) {
|
||||||
|
stack || (stack = new Stack)
|
||||||
|
baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let newValue = customizer
|
||||||
|
? customizer(object[key], srcValue, `${key}`, object, source, stack)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
if (newValue === undefined) {
|
||||||
|
newValue = srcValue
|
||||||
|
}
|
||||||
|
assignMergeValue(object, key, newValue)
|
||||||
|
}
|
||||||
|
}, keysIn)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseMerge
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
import assignMergeValue from './assignMergeValue.js'
|
||||||
|
import cloneBuffer from './cloneBuffer.js'
|
||||||
|
import cloneTypedArray from './cloneTypedArray.js'
|
||||||
|
import copyArray from './copyArray.js'
|
||||||
|
import initCloneObject from './initCloneObject.js'
|
||||||
|
import isArguments from '../isArguments.js'
|
||||||
|
import isArrayLikeObject from '../isArrayLikeObject.js'
|
||||||
|
import isBuffer from '../isBuffer.js'
|
||||||
|
import isObject from '../isObject.js'
|
||||||
|
import isPlainObject from '../isPlainObject.js'
|
||||||
|
import isTypedArray from '../isTypedArray.js'
|
||||||
|
import toPlainObject from '../toPlainObject.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialized version of `baseMerge` for arrays and objects which performs
|
||||||
|
* deep merges and tracks traversed objects enabling objects with circular
|
||||||
|
* references to be merged.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The destination object.
|
||||||
|
* @param {Object} source The source object.
|
||||||
|
* @param {string} key The key of the value to merge.
|
||||||
|
* @param {number} srcIndex The index of `source`.
|
||||||
|
* @param {Function} mergeFunc The function to merge values.
|
||||||
|
* @param {Function} [customizer] The function to customize assigned values.
|
||||||
|
* @param {Object} [stack] Tracks traversed source values and their merged
|
||||||
|
* counterparts.
|
||||||
|
*/
|
||||||
|
function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
|
||||||
|
const objValue = object[key]
|
||||||
|
const srcValue = source[key]
|
||||||
|
const stacked = stack.get(srcValue)
|
||||||
|
|
||||||
|
if (stacked) {
|
||||||
|
assignMergeValue(object, key, stacked)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let newValue = customizer
|
||||||
|
? customizer(objValue, srcValue, `${key}`, object, source, stack)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
let isCommon = newValue === undefined
|
||||||
|
|
||||||
|
if (isCommon) {
|
||||||
|
const isArr = Array.isArray(srcValue)
|
||||||
|
const isBuff = !isArr && isBuffer(srcValue)
|
||||||
|
const isTyped = !isArr && !isBuff && isTypedArray(srcValue)
|
||||||
|
|
||||||
|
newValue = srcValue
|
||||||
|
if (isArr || isBuff || isTyped) {
|
||||||
|
if (Array.isArray(objValue)) {
|
||||||
|
newValue = objValue
|
||||||
|
}
|
||||||
|
else if (isArrayLikeObject(objValue)) {
|
||||||
|
newValue = copyArray(objValue)
|
||||||
|
}
|
||||||
|
else if (isBuff) {
|
||||||
|
isCommon = false
|
||||||
|
newValue = cloneBuffer(srcValue, true)
|
||||||
|
}
|
||||||
|
else if (isTyped) {
|
||||||
|
isCommon = false
|
||||||
|
newValue = cloneTypedArray(srcValue, true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newValue = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isPlainObject(srcValue) || isArguments(srcValue)) {
|
||||||
|
newValue = objValue
|
||||||
|
if (isArguments(objValue)) {
|
||||||
|
newValue = toPlainObject(objValue)
|
||||||
|
}
|
||||||
|
else if (typeof objValue === 'function' || !isObject(objValue)) {
|
||||||
|
newValue = initCloneObject(srcValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isCommon = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isCommon) {
|
||||||
|
// Recursively merge objects and arrays (susceptible to call stack limits).
|
||||||
|
stack.set(srcValue, newValue)
|
||||||
|
mergeFunc(newValue, srcValue, srcIndex, customizer, stack)
|
||||||
|
stack['delete'](srcValue)
|
||||||
|
}
|
||||||
|
assignMergeValue(object, key, newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseMergeDeep
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import baseEach from './baseEach.js'
|
||||||
|
import baseSortBy from './baseSortBy.js'
|
||||||
|
import baseGet from './baseGet.js'
|
||||||
|
import compareMultiple from './compareMultiple.js'
|
||||||
|
import isArrayLike from '../isArrayLike.js'
|
||||||
|
|
||||||
|
const identity = (value) => value
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `orderBy` without param guards.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array|Object} collection The collection to iterate over.
|
||||||
|
* @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
|
||||||
|
* @param {string[]} orders The sort orders of `iteratees`.
|
||||||
|
* @returns {Array} Returns the new sorted array.
|
||||||
|
*/
|
||||||
|
function baseOrderBy(collection, iteratees, orders) {
|
||||||
|
if (iteratees.length) {
|
||||||
|
iteratees = iteratees.map((iteratee) => {
|
||||||
|
if (Array.isArray(iteratee)) {
|
||||||
|
return (value) => baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee)
|
||||||
|
}
|
||||||
|
|
||||||
|
return iteratee
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
iteratees = [identity]
|
||||||
|
}
|
||||||
|
|
||||||
|
let criteriaIndex = -1
|
||||||
|
let eachIndex = -1
|
||||||
|
|
||||||
|
const result = isArrayLike(collection) ? new Array(collection.length) : []
|
||||||
|
|
||||||
|
baseEach(collection, (value) => {
|
||||||
|
const criteria = iteratees.map((iteratee) => iteratee(value))
|
||||||
|
|
||||||
|
result[++eachIndex] = {
|
||||||
|
criteria,
|
||||||
|
index: ++criteriaIndex,
|
||||||
|
value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return baseSortBy(result, (object, other) => compareMultiple(object, other, orders))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseOrderBy
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import basePickBy from './basePickBy.js'
|
||||||
|
import hasIn from '../hasIn.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `pick` without support for individual
|
||||||
|
* property identifiers.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The source object.
|
||||||
|
* @param {string[]} paths The property paths to pick.
|
||||||
|
* @returns {Object} Returns the new object.
|
||||||
|
*/
|
||||||
|
function basePick(object, paths) {
|
||||||
|
return basePickBy(object, paths, (value, path) => hasIn(object, path))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default basePick
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import baseGet from './baseGet.js'
|
||||||
|
import baseSet from './baseSet.js'
|
||||||
|
import castPath from './castPath.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `pickBy`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The source object.
|
||||||
|
* @param {string[]} paths The property paths to pick.
|
||||||
|
* @param {Function} predicate The function invoked per property.
|
||||||
|
* @returns {Object} Returns the new object.
|
||||||
|
*/
|
||||||
|
function basePickBy(object, paths, predicate) {
|
||||||
|
let index = -1
|
||||||
|
const length = paths.length
|
||||||
|
const result = {}
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
const path = paths[index]
|
||||||
|
const value = baseGet(object, path)
|
||||||
|
if (predicate(value, path)) {
|
||||||
|
baseSet(result, castPath(path, object), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default basePickBy
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `property` without support for deep paths.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} key The key of the property to get.
|
||||||
|
* @returns {Function} Returns the new accessor function.
|
||||||
|
*/
|
||||||
|
function baseProperty(key) {
|
||||||
|
return (object) => object == null ? undefined : object[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseProperty
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import baseGet from './baseGet.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialized version of `baseProperty` which supports deep paths.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array|string} path The path of the property to get.
|
||||||
|
* @returns {Function} Returns the new accessor function.
|
||||||
|
*/
|
||||||
|
function basePropertyDeep(path) {
|
||||||
|
return (object) => baseGet(object, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default basePropertyDeep
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `propertyOf` without support for deep paths.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to query.
|
||||||
|
* @returns {Function} Returns the new accessor function.
|
||||||
|
*/
|
||||||
|
function basePropertyOf(object) {
|
||||||
|
return (key) => object == null ? undefined : object[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default basePropertyOf
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import map from '../map.js'
|
||||||
|
import baseIndexOf from './baseIndexOf.js'
|
||||||
|
import baseIndexOfWith from './baseIndexOfWith.js'
|
||||||
|
import copyArray from './copyArray.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `pullAllBy`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to modify.
|
||||||
|
* @param {Array} values The values to remove.
|
||||||
|
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||||
|
* @param {Function} [comparator] The comparator invoked per element.
|
||||||
|
* @returns {Array} Returns `array`.
|
||||||
|
*/
|
||||||
|
function basePullAll(array, values, iteratee, comparator) {
|
||||||
|
const indexOf = comparator ? baseIndexOfWith : baseIndexOf
|
||||||
|
const length = values.length
|
||||||
|
|
||||||
|
let index = -1
|
||||||
|
let seen = array
|
||||||
|
|
||||||
|
if (array === values) {
|
||||||
|
values = copyArray(values)
|
||||||
|
}
|
||||||
|
if (iteratee) {
|
||||||
|
seen = map(array, (value) => iteratee(value))
|
||||||
|
}
|
||||||
|
while (++index < length) {
|
||||||
|
let fromIndex = 0
|
||||||
|
const value = values[index]
|
||||||
|
const computed = iteratee ? iteratee(value) : value
|
||||||
|
|
||||||
|
while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
|
||||||
|
if (seen !== array) {
|
||||||
|
seen.splice(fromIndex, 1)
|
||||||
|
}
|
||||||
|
array.splice(fromIndex, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default basePullAll
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import baseUnset from './baseUnset.js'
|
||||||
|
import isIndex from './isIndex.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `pullAt` without support for individual
|
||||||
|
* indexes or capturing the removed elements.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to modify.
|
||||||
|
* @param {number[]} indexes The indexes of elements to remove.
|
||||||
|
* @returns {Array} Returns `array`.
|
||||||
|
*/
|
||||||
|
function basePullAt(array, indexes) {
|
||||||
|
let length = array ? indexes.length : 0
|
||||||
|
const lastIndex = length - 1
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
let previous
|
||||||
|
const index = indexes[length]
|
||||||
|
if (length === lastIndex || index !== previous) {
|
||||||
|
previous = index
|
||||||
|
if (isIndex(index)) {
|
||||||
|
array.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
baseUnset(array, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default basePullAt
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `range` and `rangeRight` which doesn't
|
||||||
|
* coerce arguments.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {number} start The start of the range.
|
||||||
|
* @param {number} end The end of the range.
|
||||||
|
* @param {number} step The value to increment or decrement by.
|
||||||
|
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||||||
|
* @returns {Array} Returns the range of numbers.
|
||||||
|
*/
|
||||||
|
function baseRange(start, end, step, fromRight) {
|
||||||
|
let index = -1
|
||||||
|
let length = Math.max(Math.ceil((end - start) / (step || 1)), 0)
|
||||||
|
const result = new Array(length)
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
result[fromRight ? length : ++index] = start
|
||||||
|
start += step
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseRange
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `reduce` and `reduceRight` which iterates
|
||||||
|
* over `collection` using `eachFunc`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array|Object} collection The collection to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @param {*} accumulator The initial value.
|
||||||
|
* @param {boolean} initAccum Specify using the first or last element of
|
||||||
|
* `collection` as the initial value.
|
||||||
|
* @param {Function} eachFunc The function to iterate over `collection`.
|
||||||
|
* @returns {*} Returns the accumulated value.
|
||||||
|
*/
|
||||||
|
function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
|
||||||
|
eachFunc(collection, (value, index, collection) => {
|
||||||
|
accumulator = initAccum
|
||||||
|
? (initAccum = false, value)
|
||||||
|
: iteratee(accumulator, value, index, collection)
|
||||||
|
})
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseReduce
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import assignValue from './assignValue.js'
|
||||||
|
import castPath from './castPath.js'
|
||||||
|
import isIndex from './isIndex.js'
|
||||||
|
import isObject from '../isObject.js'
|
||||||
|
import toKey from './toKey.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `set`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to modify.
|
||||||
|
* @param {Array|string} path The path of the property to set.
|
||||||
|
* @param {*} value The value to set.
|
||||||
|
* @param {Function} [customizer] The function to customize path creation.
|
||||||
|
* @returns {Object} Returns `object`.
|
||||||
|
*/
|
||||||
|
function baseSet(object, path, value, customizer) {
|
||||||
|
if (!isObject(object)) {
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
path = castPath(path, object)
|
||||||
|
|
||||||
|
const length = path.length
|
||||||
|
const lastIndex = length - 1
|
||||||
|
|
||||||
|
let index = -1
|
||||||
|
let nested = object
|
||||||
|
|
||||||
|
while (nested != null && ++index < length) {
|
||||||
|
const key = toKey(path[index])
|
||||||
|
let newValue = value
|
||||||
|
|
||||||
|
if (index != lastIndex) {
|
||||||
|
const objValue = nested[key]
|
||||||
|
newValue = customizer ? customizer(objValue, key, nested) : undefined
|
||||||
|
if (newValue === undefined) {
|
||||||
|
newValue = isObject(objValue)
|
||||||
|
? objValue
|
||||||
|
: (isIndex(path[index + 1]) ? [] : {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assignValue(nested, key, newValue)
|
||||||
|
nested = nested[key]
|
||||||
|
}
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseSet
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `sortBy` which uses `comparer` to define the
|
||||||
|
* sort order of `array` and replaces criteria objects with their corresponding
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to sort.
|
||||||
|
* @param {Function} comparer The function to define sort order.
|
||||||
|
* @returns {Array} Returns `array`.
|
||||||
|
*/
|
||||||
|
function baseSortBy(array, comparer) {
|
||||||
|
let { length } = array
|
||||||
|
|
||||||
|
array.sort(comparer)
|
||||||
|
while (length--) {
|
||||||
|
array[length] = array[length].value
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseSortBy
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
import baseSortedIndexBy from './baseSortedIndexBy.js'
|
||||||
|
import isSymbol from '../isSymbol.js'
|
||||||
|
|
||||||
|
/** Used as references for the maximum length and index of an array. */
|
||||||
|
const MAX_ARRAY_LENGTH = 4294967295
|
||||||
|
const HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `sortedIndex` and `sortedLastIndex` which
|
||||||
|
* performs a binary search of `array` to determine the index at which `value`
|
||||||
|
* should be inserted into `array` in order to maintain its sort order.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The sorted array to inspect.
|
||||||
|
* @param {*} value The value to evaluate.
|
||||||
|
* @param {boolean} [retHighest] Specify returning the highest qualified index.
|
||||||
|
* @returns {number} Returns the index at which `value` should be inserted
|
||||||
|
* into `array`.
|
||||||
|
*/
|
||||||
|
function baseSortedIndex(array, value, retHighest) {
|
||||||
|
let low = 0
|
||||||
|
let high = array == null ? low : array.length
|
||||||
|
|
||||||
|
if (typeof value === 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
|
||||||
|
while (low < high) {
|
||||||
|
const mid = (low + high) >>> 1
|
||||||
|
const computed = array[mid]
|
||||||
|
if (computed !== null && !isSymbol(computed) &&
|
||||||
|
(retHighest ? (computed <= value) : (computed < value))) {
|
||||||
|
low = mid + 1
|
||||||
|
} else {
|
||||||
|
high = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return high
|
||||||
|
}
|
||||||
|
return baseSortedIndexBy(array, value, (value) => value, retHighest)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseSortedIndex
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
import isSymbol from '../isSymbol.js'
|
||||||
|
|
||||||
|
/** Used as references for the maximum length and index of an array. */
|
||||||
|
const MAX_ARRAY_LENGTH = 4294967295
|
||||||
|
const MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `sortedIndexBy` and `sortedLastIndexBy`
|
||||||
|
* which invokes `iteratee` for `value` and each element of `array` to compute
|
||||||
|
* their sort ranking. The iteratee is invoked with one argument (value).
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The sorted array to inspect.
|
||||||
|
* @param {*} value The value to evaluate.
|
||||||
|
* @param {Function} iteratee The iteratee invoked per element.
|
||||||
|
* @param {boolean} [retHighest] Specify returning the highest qualified index.
|
||||||
|
* @returns {number} Returns the index at which `value` should be inserted
|
||||||
|
* into `array`.
|
||||||
|
*/
|
||||||
|
function baseSortedIndexBy(array, value, iteratee, retHighest) {
|
||||||
|
let low = 0
|
||||||
|
let high = array == null ? 0 : array.length
|
||||||
|
if (high == 0) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
value = iteratee(value)
|
||||||
|
|
||||||
|
const valIsNaN = value !== value
|
||||||
|
const valIsNull = value === null
|
||||||
|
const valIsSymbol = isSymbol(value)
|
||||||
|
const valIsUndefined = value === undefined
|
||||||
|
|
||||||
|
while (low < high) {
|
||||||
|
let setLow
|
||||||
|
const mid = Math.floor((low + high) / 2)
|
||||||
|
const computed = iteratee(array[mid])
|
||||||
|
const othIsDefined = computed !== undefined
|
||||||
|
const othIsNull = computed === null
|
||||||
|
const othIsReflexive = computed === computed
|
||||||
|
const othIsSymbol = isSymbol(computed)
|
||||||
|
|
||||||
|
if (valIsNaN) {
|
||||||
|
setLow = retHighest || othIsReflexive
|
||||||
|
} else if (valIsUndefined) {
|
||||||
|
setLow = othIsReflexive && (retHighest || othIsDefined)
|
||||||
|
} else if (valIsNull) {
|
||||||
|
setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull)
|
||||||
|
} else if (valIsSymbol) {
|
||||||
|
setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol)
|
||||||
|
} else if (othIsNull || othIsSymbol) {
|
||||||
|
setLow = false
|
||||||
|
} else {
|
||||||
|
setLow = retHighest ? (computed <= value) : (computed < value)
|
||||||
|
}
|
||||||
|
if (setLow) {
|
||||||
|
low = mid + 1
|
||||||
|
} else {
|
||||||
|
high = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.min(high, MAX_ARRAY_INDEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseSortedIndexBy
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import eq from '../eq.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `sortedUniq` and `sortedUniqBy`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||||
|
* @returns {Array} Returns the new duplicate free array.
|
||||||
|
*/
|
||||||
|
function baseSortedUniq(array, iteratee) {
|
||||||
|
let seen
|
||||||
|
let index = -1
|
||||||
|
let resIndex = 0
|
||||||
|
|
||||||
|
const { length } = array
|
||||||
|
const result = []
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
const value = array[index], computed = iteratee ? iteratee(value) : value
|
||||||
|
if (!index || !eq(computed, seen)) {
|
||||||
|
seen = computed
|
||||||
|
result[resIndex++] = value === 0 ? 0 : value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseSortedUniq
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `sum` and `sumBy`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to iterate over.
|
||||||
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
|
* @returns {number} Returns the sum.
|
||||||
|
*/
|
||||||
|
function baseSum(array, iteratee) {
|
||||||
|
let result
|
||||||
|
|
||||||
|
for (const value of array) {
|
||||||
|
const current = iteratee(value)
|
||||||
|
if (current !== undefined) {
|
||||||
|
result = result === undefined ? current : (result + current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseSum
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import isSymbol from '../isSymbol.js'
|
||||||
|
|
||||||
|
/** Used as references for various `Number` constants. */
|
||||||
|
const NAN = 0 / 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `toNumber` which doesn't ensure correct
|
||||||
|
* conversions of binary, hexadecimal, or octal string values.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to process.
|
||||||
|
* @returns {number} Returns the number.
|
||||||
|
*/
|
||||||
|
function baseToNumber(value) {
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (isSymbol(value)) {
|
||||||
|
return NAN
|
||||||
|
}
|
||||||
|
return +value
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseToNumber
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import isSymbol from '../isSymbol.js'
|
||||||
|
|
||||||
|
/** Used as references for various `Number` constants. */
|
||||||
|
const INFINITY = 1 / 0
|
||||||
|
|
||||||
|
/** Used to convert symbols to primitives and strings. */
|
||||||
|
const symbolToString = Symbol.prototype.toString
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `toString` which doesn't convert nullish
|
||||||
|
* values to empty strings.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to process.
|
||||||
|
* @returns {string} Returns the string.
|
||||||
|
*/
|
||||||
|
function baseToString(value) {
|
||||||
|
// Exit early for strings to avoid a performance hit in some environments.
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
// Recursively convert values (susceptible to call stack limits).
|
||||||
|
return `${value.map(baseToString)}`
|
||||||
|
}
|
||||||
|
if (isSymbol(value)) {
|
||||||
|
return symbolToString ? symbolToString.call(value) : ''
|
||||||
|
}
|
||||||
|
const result = `${value}`
|
||||||
|
return (result === '0' && (1 / value) === -INFINITY) ? '-0' : result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseToString
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
import SetCache from './SetCache.js'
|
||||||
|
import arrayIncludes from './arrayIncludes.js'
|
||||||
|
import arrayIncludesWith from './arrayIncludesWith.js'
|
||||||
|
import cacheHas from './cacheHas.js'
|
||||||
|
import createSet from './createSet.js'
|
||||||
|
import setToArray from './setToArray.js'
|
||||||
|
|
||||||
|
/** Used as the size to enable large array optimizations. */
|
||||||
|
const LARGE_ARRAY_SIZE = 200
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `uniqBy`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||||
|
* @param {Function} [comparator] The comparator invoked per element.
|
||||||
|
* @returns {Array} Returns the new duplicate free array.
|
||||||
|
*/
|
||||||
|
function baseUniq(array, iteratee, comparator) {
|
||||||
|
let index = -1
|
||||||
|
let includes = arrayIncludes
|
||||||
|
let isCommon = true
|
||||||
|
|
||||||
|
const { length } = array
|
||||||
|
const result = []
|
||||||
|
let seen = result
|
||||||
|
|
||||||
|
if (comparator) {
|
||||||
|
isCommon = false
|
||||||
|
includes = arrayIncludesWith
|
||||||
|
}
|
||||||
|
else if (length >= LARGE_ARRAY_SIZE) {
|
||||||
|
const set = iteratee ? null : createSet(array)
|
||||||
|
if (set) {
|
||||||
|
return setToArray(set)
|
||||||
|
}
|
||||||
|
isCommon = false
|
||||||
|
includes = cacheHas
|
||||||
|
seen = new SetCache
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seen = iteratee ? [] : result
|
||||||
|
}
|
||||||
|
outer:
|
||||||
|
while (++index < length) {
|
||||||
|
let value = array[index]
|
||||||
|
const computed = iteratee ? iteratee(value) : value
|
||||||
|
|
||||||
|
value = (comparator || value !== 0) ? value : 0
|
||||||
|
if (isCommon && computed === computed) {
|
||||||
|
let seenIndex = seen.length
|
||||||
|
while (seenIndex--) {
|
||||||
|
if (seen[seenIndex] === computed) {
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iteratee) {
|
||||||
|
seen.push(computed)
|
||||||
|
}
|
||||||
|
result.push(value)
|
||||||
|
}
|
||||||
|
else if (!includes(seen, computed, comparator)) {
|
||||||
|
if (seen !== result) {
|
||||||
|
seen.push(computed)
|
||||||
|
}
|
||||||
|
result.push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseUniq
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import castPath from './castPath.js'
|
||||||
|
import last from '../last.js'
|
||||||
|
import parent from './parent.js'
|
||||||
|
import toKey from './toKey.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `unset`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to modify.
|
||||||
|
* @param {Array|string} path The property path to unset.
|
||||||
|
* @returns {boolean} Returns `true` if the property is deleted, else `false`.
|
||||||
|
*/
|
||||||
|
function baseUnset(object, path) {
|
||||||
|
path = castPath(path, object)
|
||||||
|
object = parent(object, path)
|
||||||
|
return object == null || delete object[toKey(last(path))]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseUnset
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import baseGet from './baseGet.js'
|
||||||
|
import baseSet from './baseSet.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of `update`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to modify.
|
||||||
|
* @param {Array|string} path The path of the property to update.
|
||||||
|
* @param {Function} updater The function to produce the updated value.
|
||||||
|
* @param {Function} [customizer] The function to customize path creation.
|
||||||
|
* @returns {Object} Returns `object`.
|
||||||
|
*/
|
||||||
|
function baseUpdate(object, path, updater, customizer) {
|
||||||
|
return baseSet(object, path, updater(baseGet(object, path)), customizer)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseUpdate
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* The base implementation of `values` and `valuesIn` which creates an
|
||||||
|
* array of `object` property values corresponding to the property names
|
||||||
|
* of `props`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to query.
|
||||||
|
* @param {Array} props The property names to get values for.
|
||||||
|
* @returns {Object} Returns the array of property values.
|
||||||
|
*/
|
||||||
|
function baseValues(object, props) {
|
||||||
|
return props == null ? [] : props.map((key) => object[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseValues
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import slice from '../slice.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of methods like `dropWhile` and `takeWhile`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to query.
|
||||||
|
* @param {Function} predicate The function invoked per iteration.
|
||||||
|
* @param {boolean} [isDrop] Specify dropping elements instead of taking them.
|
||||||
|
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||||||
|
* @returns {Array} Returns the slice of `array`.
|
||||||
|
*/
|
||||||
|
function baseWhile(array, predicate, isDrop, fromRight) {
|
||||||
|
const { length } = array
|
||||||
|
let index = fromRight ? length : -1
|
||||||
|
|
||||||
|
while ((fromRight ? index-- : ++index < length) &&
|
||||||
|
predicate(array[index], index, array)) {}
|
||||||
|
|
||||||
|
return isDrop
|
||||||
|
? slice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
|
||||||
|
: slice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseWhile
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import baseDifference from './baseDifference.js'
|
||||||
|
import baseFlatten from './baseFlatten.js'
|
||||||
|
import baseUniq from './baseUniq.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base implementation of methods like `xor` which accepts an array of
|
||||||
|
* arrays to inspect.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} arrays The arrays to inspect.
|
||||||
|
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||||
|
* @param {Function} [comparator] The comparator invoked per element.
|
||||||
|
* @returns {Array} Returns the new array of values.
|
||||||
|
*/
|
||||||
|
function baseXor(arrays, iteratee, comparator) {
|
||||||
|
const length = arrays.length
|
||||||
|
if (length < 2) {
|
||||||
|
return length ? baseUniq(arrays[0]) : []
|
||||||
|
}
|
||||||
|
let index = -1
|
||||||
|
const result = new Array(length)
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
const array = arrays[index]
|
||||||
|
let othIndex = -1
|
||||||
|
|
||||||
|
while (++othIndex < length) {
|
||||||
|
if (othIndex != index) {
|
||||||
|
result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return baseUniq(baseFlatten(result, 1), iteratee, comparator)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseXor
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* This base implementation of `zipObject` which assigns values using `assignFunc`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} props The property identifiers.
|
||||||
|
* @param {Array} values The property values.
|
||||||
|
* @param {Function} assignFunc The function to assign values.
|
||||||
|
* @returns {Object} Returns the new object.
|
||||||
|
*/
|
||||||
|
function baseZipObject(props, values, assignFunc) {
|
||||||
|
let index = -1
|
||||||
|
const length = props.length
|
||||||
|
const valsLength = values.length
|
||||||
|
const result = {}
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
const value = index < valsLength ? values[index] : undefined
|
||||||
|
assignFunc(result, props[index], value)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseZipObject
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* Checks if a `cache` value for `key` exists.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} cache The cache to query.
|
||||||
|
* @param {string} key The key of the entry to check.
|
||||||
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||||||
|
*/
|
||||||
|
function cacheHas(cache, key) {
|
||||||
|
return cache.has(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cacheHas
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import isArrayLikeObject from '../isArrayLikeObject.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts `value` to an empty array if it's not an array like object.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to inspect.
|
||||||
|
* @returns {Array|Object} Returns the cast array-like object.
|
||||||
|
*/
|
||||||
|
function castArrayLikeObject(value) {
|
||||||
|
return isArrayLikeObject(value) ? value : []
|
||||||
|
}
|
||||||
|
|
||||||
|
export default castArrayLikeObject
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import isKey from './isKey.js'
|
||||||
|
import stringToPath from './stringToPath.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts `value` to a path array if it's not one.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to inspect.
|
||||||
|
* @param {Object} [object] The object to query keys on.
|
||||||
|
* @returns {Array} Returns the cast property path array.
|
||||||
|
*/
|
||||||
|
function castPath(value, object) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return isKey(value, object) ? [value] : stringToPath(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default castPath
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import slice from '../slice.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts `array` to a slice if it's needed.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} array The array to inspect.
|
||||||
|
* @param {number} start The start position.
|
||||||
|
* @param {number} [end=array.length] The end position.
|
||||||
|
* @returns {Array} Returns the cast slice.
|
||||||
|
*/
|
||||||
|
function castSlice(array, start, end) {
|
||||||
|
const { length } = array
|
||||||
|
end = end === undefined ? length : end
|
||||||
|
return (!start && end >= length) ? array : slice(array, start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default castSlice
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import baseIndexOf from './baseIndexOf.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by `trim` and `trimEnd` to get the index of the last string symbol
|
||||||
|
* that is not found in the character symbols.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} strSymbols The string symbols to inspect.
|
||||||
|
* @param {Array} chrSymbols The character symbols to find.
|
||||||
|
* @returns {number} Returns the index of the last unmatched string symbol.
|
||||||
|
*/
|
||||||
|
function charsEndIndex(strSymbols, chrSymbols) {
|
||||||
|
let index = strSymbols.length
|
||||||
|
|
||||||
|
while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
export default charsEndIndex
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import baseIndexOf from './baseIndexOf.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by `trim` and `trimStart` to get the index of the first string symbol
|
||||||
|
* that is not found in the character symbols.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} strSymbols The string symbols to inspect.
|
||||||
|
* @param {Array} chrSymbols The character symbols to find.
|
||||||
|
* @returns {number} Returns the index of the first unmatched string symbol.
|
||||||
|
*/
|
||||||
|
function charsStartIndex(strSymbols, chrSymbols) {
|
||||||
|
let index = -1
|
||||||
|
const length = strSymbols.length
|
||||||
|
|
||||||
|
while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
export default charsStartIndex
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* Creates a clone of `arrayBuffer`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {ArrayBuffer} arrayBuffer The array buffer to clone.
|
||||||
|
* @returns {ArrayBuffer} Returns the cloned array buffer.
|
||||||
|
*/
|
||||||
|
function cloneArrayBuffer(arrayBuffer) {
|
||||||
|
const result = new arrayBuffer.constructor(arrayBuffer.byteLength)
|
||||||
|
new Uint8Array(result).set(new Uint8Array(arrayBuffer))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cloneArrayBuffer
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import root from './root.js'
|
||||||
|
|
||||||
|
/** Detect free variable `exports`. */
|
||||||
|
const freeExports = typeof exports === 'object' && exports !== null && !exports.nodeType && exports
|
||||||
|
|
||||||
|
/** Detect free variable `module`. */
|
||||||
|
const freeModule = freeExports && typeof module === 'object' && module !== null && !module.nodeType && module
|
||||||
|
|
||||||
|
/** Detect the popular CommonJS extension `module.exports`. */
|
||||||
|
const moduleExports = freeModule && freeModule.exports === freeExports
|
||||||
|
|
||||||
|
/** Built-in value references. */
|
||||||
|
const Buffer = moduleExports ? root.Buffer : undefined, allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of `buffer`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} buffer The buffer to clone.
|
||||||
|
* @param {boolean} [isDeep] Specify a deep clone.
|
||||||
|
* @returns {Buffer} Returns the cloned buffer.
|
||||||
|
*/
|
||||||
|
function cloneBuffer(buffer, isDeep) {
|
||||||
|
if (isDeep) {
|
||||||
|
return buffer.slice()
|
||||||
|
}
|
||||||
|
const length = buffer.length
|
||||||
|
const result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length)
|
||||||
|
|
||||||
|
buffer.copy(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cloneBuffer
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import cloneArrayBuffer from './cloneArrayBuffer.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of `dataView`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} dataView The data view to clone.
|
||||||
|
* @param {boolean} [isDeep] Specify a deep clone.
|
||||||
|
* @returns {Object} Returns the cloned data view.
|
||||||
|
*/
|
||||||
|
function cloneDataView(dataView, isDeep) {
|
||||||
|
const buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer
|
||||||
|
return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cloneDataView
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
/** Used to match `RegExp` flags from their coerced string values. */
|
||||||
|
const reFlags = /\w*$/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of `regexp`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} regexp The regexp to clone.
|
||||||
|
* @returns {Object} Returns the cloned regexp.
|
||||||
|
*/
|
||||||
|
function cloneRegExp(regexp) {
|
||||||
|
const result = new regexp.constructor(regexp.source, reFlags.exec(regexp))
|
||||||
|
result.lastIndex = regexp.lastIndex
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cloneRegExp
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
/** Used to convert symbols to primitives and strings. */
|
||||||
|
const symbolValueOf = Symbol.prototype.valueOf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of the `symbol` object.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} symbol The symbol object to clone.
|
||||||
|
* @returns {Object} Returns the cloned symbol object.
|
||||||
|
*/
|
||||||
|
function cloneSymbol(symbol) {
|
||||||
|
return Object(symbolValueOf.call(symbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cloneSymbol
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import cloneArrayBuffer from './cloneArrayBuffer.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of `typedArray`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} typedArray The typed array to clone.
|
||||||
|
* @param {boolean} [isDeep] Specify a deep clone.
|
||||||
|
* @returns {Object} Returns the cloned typed array.
|
||||||
|
*/
|
||||||
|
function cloneTypedArray(typedArray, isDeep) {
|
||||||
|
const buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer
|
||||||
|
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cloneTypedArray
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import isSymbol from '../isSymbol.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares values to sort them in ascending order.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} value The value to compare.
|
||||||
|
* @param {*} other The other value to compare.
|
||||||
|
* @returns {number} Returns the sort order indicator for `value`.
|
||||||
|
*/
|
||||||
|
function compareAscending(value, other) {
|
||||||
|
if (value !== other) {
|
||||||
|
const valIsDefined = value !== undefined
|
||||||
|
const valIsNull = value === null
|
||||||
|
const valIsReflexive = value === value
|
||||||
|
const valIsSymbol = isSymbol(value)
|
||||||
|
|
||||||
|
const othIsDefined = other !== undefined
|
||||||
|
const othIsNull = other === null
|
||||||
|
const othIsReflexive = other === other
|
||||||
|
const othIsSymbol = isSymbol(other)
|
||||||
|
|
||||||
|
const val = typeof value === 'string'
|
||||||
|
? value.localeCompare(other)
|
||||||
|
: -other
|
||||||
|
|
||||||
|
if ((!othIsNull && !othIsSymbol && !valIsSymbol && val > 0) ||
|
||||||
|
(valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
|
||||||
|
(valIsNull && othIsDefined && othIsReflexive) ||
|
||||||
|
(!valIsDefined && othIsReflexive) ||
|
||||||
|
!valIsReflexive) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if ((!valIsNull && !valIsSymbol && !othIsSymbol && val < 0) ||
|
||||||
|
(othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
|
||||||
|
(othIsNull && valIsDefined && valIsReflexive) ||
|
||||||
|
(!othIsDefined && valIsReflexive) ||
|
||||||
|
!othIsReflexive) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compareAscending
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import compareAscending from './compareAscending.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by `orderBy` to compare multiple properties of a value to another
|
||||||
|
* and stable sort them.
|
||||||
|
*
|
||||||
|
* If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
|
||||||
|
* specify an order of "desc" for descending or "asc" for ascending sort order
|
||||||
|
* of corresponding values.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} object The object to compare.
|
||||||
|
* @param {Object} other The other object to compare.
|
||||||
|
* @param {(string|function)[]} orders The order to sort by for each property.
|
||||||
|
* @returns {number} Returns the sort order indicator for `object`.
|
||||||
|
*/
|
||||||
|
function compareMultiple(object, other, orders) {
|
||||||
|
let index = -1
|
||||||
|
const objCriteria = object.criteria
|
||||||
|
const othCriteria = other.criteria
|
||||||
|
const length = objCriteria.length
|
||||||
|
const ordersLength = orders.length
|
||||||
|
|
||||||
|
while (++index < length) {
|
||||||
|
const order = index < ordersLength ? orders[index] : null
|
||||||
|
const cmpFn = (order && typeof order === 'function') ? order: compareAscending
|
||||||
|
const result = cmpFn(objCriteria[index], othCriteria[index])
|
||||||
|
if (result) {
|
||||||
|
if (order && typeof order !== 'function') {
|
||||||
|
return result * (order == 'desc' ? -1 : 1)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
|
||||||
|
// that causes it, under certain circumstances, to provide the same value for
|
||||||
|
// `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
// This also ensures a stable sort in V8 and other engines.
|
||||||
|
// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
|
||||||
|
return object.index - other.index
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compareMultiple
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* Creates an array that is the composition of partially applied arguments,
|
||||||
|
* placeholders, and provided arguments into a single array of arguments.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} args The provided arguments.
|
||||||
|
* @param {Array} partials The arguments to prepend to those provided.
|
||||||
|
* @param {Array} holders The `partials` placeholder indexes.
|
||||||
|
* @params {boolean} [isCurried] Specify composing for a curried function.
|
||||||
|
* @returns {Array} Returns the new array of composed arguments.
|
||||||
|
*/
|
||||||
|
function composeArgs(args, partials, holders, isCurried) {
|
||||||
|
const argsLength = args.length
|
||||||
|
const holdersLength = holders.length
|
||||||
|
const leftLength = partials.length
|
||||||
|
|
||||||
|
let argsIndex = -1
|
||||||
|
let leftIndex = -1
|
||||||
|
let rangeLength = Math.max(argsLength - holdersLength, 0)
|
||||||
|
|
||||||
|
const result = new Array(leftLength + rangeLength)
|
||||||
|
const isUncurried = !isCurried
|
||||||
|
|
||||||
|
while (++leftIndex < leftLength) {
|
||||||
|
result[leftIndex] = partials[leftIndex]
|
||||||
|
}
|
||||||
|
while (++argsIndex < holdersLength) {
|
||||||
|
if (isUncurried || argsIndex < argsLength) {
|
||||||
|
result[holders[argsIndex]] = args[argsIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (rangeLength--) {
|
||||||
|
result[leftIndex++] = args[argsIndex++]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeArgs
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* This function is like `composeArgs` except that the arguments composition
|
||||||
|
* is tailored for `partialRight`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} args The provided arguments.
|
||||||
|
* @param {Array} partials The arguments to append to those provided.
|
||||||
|
* @param {Array} holders The `partials` placeholder indexes.
|
||||||
|
* @params {boolean} [isCurried] Specify composing for a curried function.
|
||||||
|
* @returns {Array} Returns the new array of composed arguments.
|
||||||
|
*/
|
||||||
|
function composeArgsRight(args, partials, holders, isCurried) {
|
||||||
|
let argsIndex = -1
|
||||||
|
let holdersIndex = -1
|
||||||
|
let rightIndex = -1
|
||||||
|
|
||||||
|
const argsLength = args.length
|
||||||
|
const holdersLength = holders.length
|
||||||
|
const rightLength = partials.length
|
||||||
|
const rangeLength = Math.max(argsLength - holdersLength, 0)
|
||||||
|
const result = new Array(rangeLength + rightLength)
|
||||||
|
const isUncurried = !isCurried
|
||||||
|
|
||||||
|
while (++argsIndex < rangeLength) {
|
||||||
|
result[argsIndex] = args[argsIndex]
|
||||||
|
}
|
||||||
|
const offset = argsIndex
|
||||||
|
while (++rightIndex < rightLength) {
|
||||||
|
result[offset + rightIndex] = partials[rightIndex]
|
||||||
|
}
|
||||||
|
while (++holdersIndex < holdersLength) {
|
||||||
|
if (isUncurried || argsIndex < argsLength) {
|
||||||
|
result[offset + holders[holdersIndex]] = args[argsIndex++]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeArgsRight
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* Copies the values of `source` to `array`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Array} source The array to copy values from.
|
||||||
|
* @param {Array} [array=[]] The array to copy values to.
|
||||||
|
* @returns {Array} Returns `array`.
|
||||||
|
*/
|
||||||
|
function copyArray(source, array) {
|
||||||
|
let index = -1
|
||||||
|
const length = source.length
|
||||||
|
|
||||||
|
array || (array = new Array(length))
|
||||||
|
while (++index < length) {
|
||||||
|
array[index] = source[index]
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default copyArray
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue