json-fetchfy
Version:
A lightweight Node.js module to fetch, validate, and manipulate JSON data from various sources seamlessly.
106 lines (93 loc) • 3.78 kB
JavaScript
/**
* @typedef {Object} FindInObjectOptions
* @property {boolean} [deep=false] - If true, performs deep comparison for object queries.
* @property {boolean} [caseSensitive=true] - If false, performs case-insensitive string comparisons.
* @property {boolean} [returnFullPath=false] - If true, returns the full path to the matching values.
* @property {boolean} [searchArrays=true] - If true, searches inside arrays.
* @property {boolean} [includeArrayIndices=true] - If true, includes array indices in paths.
*/
/**
* Finds values in an object or nested arrays based on a query.
* @param {Object} obj - The object to search.
* @param {*} query - The query to match against values.
* @param {(string|string[])} [path=null] - Specific path(s) to search.
* @param {FindInObjectOptions} [options] - Additional options for the search.
* @returns {Object} An object containing matches with their paths as keys.
*/
function findInObject(obj, query, path = null, options = {}) {
if (typeof obj !== 'object' || obj === null) {
throw new TypeError("The first argument must be a non-null object");
}
const {
deep = false,
caseSensitive = true,
returnFullPath = false,
searchArrays = true,
includeArrayIndices = true
} = options;
const results = {};
const compareValues = (a, b) => {
if (!caseSensitive && typeof a === 'string' && typeof b === 'string') {
return a.toLowerCase() === b.toLowerCase();
}
if (deep && typeof a === 'object' && a !== null && typeof b === 'object' && b !== null) {
return JSON.stringify(a) === JSON.stringify(b);
}
return a === b;
};
const getNestedValue = (obj, path) => {
const keys = Array.isArray(path) ? path : path.split('.');
return keys.reduce((acc, key) => (acc && acc[key] !== undefined) ? acc[key] : undefined, obj);
};
const searchInValue = (value, currentPath, isArrayItem = false) => {
// Si es una función de búsqueda personalizada
if (typeof query === "function") {
if (query(value, currentPath, obj)) {
results[currentPath] = value;
}
}
// Si el valor coincide directamente con la búsqueda
else if (compareValues(value, query)) {
results[currentPath] = value;
}
// Buscar en objetos anidados y arrays
if (value && typeof value === 'object') {
searchObject(value, currentPath);
}
};
const searchObject = (currentObj, currentPath = '') => {
// Si es un array
if (Array.isArray(currentObj)) {
if (searchArrays) {
currentObj.forEach((item, index) => {
const newPath = includeArrayIndices
? `${currentPath}[${index}]`
: currentPath;
searchInValue(item, newPath, true);
});
}
return;
}
// Si es un objeto
for (const key in currentObj) {
const value = currentObj[key];
const newPath = currentPath
? `${currentPath}.${key}`
: key;
// Si se especificó una ruta, verificar si debemos buscar en esta ruta
if (path) {
const pathsToSearch = Array.isArray(path) ? path : [path];
if (!pathsToSearch.some(p =>
newPath.startsWith(p) ||
p.startsWith(newPath)
)) {
continue;
}
}
searchInValue(value, newPath);
}
};
searchObject(obj);
return results;
}
export default findInObject;