This commit is contained in:
2024-03-22 03:47:51 +05:30
parent 8bcf3d211e
commit 89819f6fe2
28440 changed files with 3211033 additions and 2 deletions

View File

@@ -0,0 +1,41 @@
'use strict';
var EventEmitter = require('@algolia/events');
var inherits = require('../functions/inherits');
/**
* A DerivedHelper is a way to create sub requests to
* Algolia from a main helper.
* @class
* @classdesc The DerivedHelper provides an event based interface for search callbacks:
* - search: when a search is triggered using the `search()` method.
* - result: when the response is retrieved from Algolia and is processed.
* This event contains a {@link SearchResults} object and the
* {@link SearchParameters} corresponding to this answer.
* @param {AlgoliaSearchHelper} mainHelper the main helper
* @param {function} fn the function to create the derived state
*/
function DerivedHelper(mainHelper, fn) {
this.main = mainHelper;
this.fn = fn;
this.lastResults = null;
}
inherits(DerivedHelper, EventEmitter);
/**
* Detach this helper from the main helper
* @return {undefined}
* @throws Error if the derived helper is already detached
*/
DerivedHelper.prototype.detach = function () {
this.removeAllListeners();
this.main.detachDerivedHelper(this);
};
DerivedHelper.prototype.getModifiedState = function (parameters) {
return this.fn(parameters);
};
module.exports = DerivedHelper;

View File

@@ -0,0 +1,172 @@
'use strict';
/**
* Functions to manipulate refinement lists
*
* The RefinementList is not formally defined through a prototype but is based
* on a specific structure.
*
* @module SearchParameters.refinementList
*
* @typedef {string[]} SearchParameters.refinementList.Refinements
* @typedef {Object.<string, SearchParameters.refinementList.Refinements>} SearchParameters.refinementList.RefinementList
*/
var defaultsPure = require('../functions/defaultsPure');
var objectHasKeys = require('../functions/objectHasKeys');
var omit = require('../functions/omit');
var lib = {
/**
* Adds a refinement to a RefinementList
* @param {RefinementList} refinementList the initial list
* @param {string} attribute the attribute to refine
* @param {string} value the value of the refinement, if the value is not a string it will be converted
* @return {RefinementList} a new and updated refinement list
*/
addRefinement: function addRefinement(refinementList, attribute, value) {
if (lib.isRefined(refinementList, attribute, value)) {
return refinementList;
}
var valueAsString = '' + value;
var facetRefinement = !refinementList[attribute]
? [valueAsString]
: refinementList[attribute].concat(valueAsString);
var mod = {};
mod[attribute] = facetRefinement;
return defaultsPure({}, mod, refinementList);
},
/**
* Removes refinement(s) for an attribute:
* - if the value is specified removes the refinement for the value on the attribute
* - if no value is specified removes all the refinements for this attribute
* @param {RefinementList} refinementList the initial list
* @param {string} attribute the attribute to refine
* @param {string} [value] the value of the refinement
* @return {RefinementList} a new and updated refinement lst
*/
removeRefinement: function removeRefinement(
refinementList,
attribute,
value
) {
if (value === undefined) {
// we use the "filter" form of clearRefinement, since it leaves empty values as-is
// the form with a string will remove the attribute completely
return lib.clearRefinement(refinementList, function (v, f) {
return attribute === f;
});
}
var valueAsString = '' + value;
return lib.clearRefinement(refinementList, function (v, f) {
return attribute === f && valueAsString === v;
});
},
/**
* Toggles the refinement value for an attribute.
* @param {RefinementList} refinementList the initial list
* @param {string} attribute the attribute to refine
* @param {string} value the value of the refinement
* @return {RefinementList} a new and updated list
*/
toggleRefinement: function toggleRefinement(
refinementList,
attribute,
value
) {
if (value === undefined)
throw new Error('toggleRefinement should be used with a value');
if (lib.isRefined(refinementList, attribute, value)) {
return lib.removeRefinement(refinementList, attribute, value);
}
return lib.addRefinement(refinementList, attribute, value);
},
/**
* Clear all or parts of a RefinementList. Depending on the arguments, three
* kinds of behavior can happen:
* - if no attribute is provided: clears the whole list
* - if an attribute is provided as a string: clears the list for the specific attribute
* - if an attribute is provided as a function: discards the elements for which the function returns true
* @param {RefinementList} refinementList the initial list
* @param {string} [attribute] the attribute or function to discard
* @param {string} [refinementType] optional parameter to give more context to the attribute function
* @return {RefinementList} a new and updated refinement list
*/
clearRefinement: function clearRefinement(
refinementList,
attribute,
refinementType
) {
if (attribute === undefined) {
// return the same object if the list is already empty
// this is mainly for tests, as it doesn't have much impact on performance
if (!objectHasKeys(refinementList)) {
return refinementList;
}
return {};
} else if (typeof attribute === 'string') {
return omit(refinementList, [attribute]);
} else if (typeof attribute === 'function') {
var hasChanged = false;
var newRefinementList = Object.keys(refinementList).reduce(function (
memo,
key
) {
var values = refinementList[key] || [];
var facetList = values.filter(function (value) {
return !attribute(value, key, refinementType);
});
if (facetList.length !== values.length) {
hasChanged = true;
}
memo[key] = facetList;
return memo;
},
{});
if (hasChanged) return newRefinementList;
return refinementList;
}
// We return nothing if the attribute is not undefined, a string or a function,
// as it is not a valid value for a refinement
return undefined;
},
/**
* Test if the refinement value is used for the attribute. If no refinement value
* is provided, test if the refinementList contains any refinement for the
* given attribute.
* @param {RefinementList} refinementList the list of refinement
* @param {string} attribute name of the attribute
* @param {string} [refinementValue] value of the filter/refinement
* @return {boolean} true if the attribute is refined, false otherwise
*/
isRefined: function isRefined(refinementList, attribute, refinementValue) {
var containsRefinements =
Boolean(refinementList[attribute]) &&
refinementList[attribute].length > 0;
if (refinementValue === undefined || !containsRefinements) {
return containsRefinements;
}
var refinementValueAsString = '' + refinementValue;
return refinementList[attribute].indexOf(refinementValueAsString) !== -1;
},
};
module.exports = lib;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
'use strict';
module.exports = generateTrees;
var fv = require('../functions/escapeFacetValue');
var find = require('../functions/find');
var prepareHierarchicalFacetSortBy = require('../functions/formatSort');
var orderBy = require('../functions/orderBy');
var escapeFacetValue = fv.escapeFacetValue;
var unescapeFacetValue = fv.unescapeFacetValue;
function generateTrees(state) {
return function generate(hierarchicalFacetResult, hierarchicalFacetIndex) {
var hierarchicalFacet = state.hierarchicalFacets[hierarchicalFacetIndex];
var hierarchicalFacetRefinement =
(state.hierarchicalFacetsRefinements[hierarchicalFacet.name] &&
state.hierarchicalFacetsRefinements[hierarchicalFacet.name][0]) ||
'';
var hierarchicalSeparator =
state._getHierarchicalFacetSeparator(hierarchicalFacet);
var hierarchicalRootPath =
state._getHierarchicalRootPath(hierarchicalFacet);
var hierarchicalShowParentLevel =
state._getHierarchicalShowParentLevel(hierarchicalFacet);
var sortBy = prepareHierarchicalFacetSortBy(
state._getHierarchicalFacetSortBy(hierarchicalFacet)
);
var rootExhaustive = hierarchicalFacetResult.every(function (facetResult) {
return facetResult.exhaustive;
});
var generateTreeFn = generateHierarchicalTree(
sortBy,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel,
hierarchicalFacetRefinement
);
var results = hierarchicalFacetResult;
if (hierarchicalRootPath) {
results = hierarchicalFacetResult.slice(
hierarchicalRootPath.split(hierarchicalSeparator).length
);
}
return results.reduce(generateTreeFn, {
name: state.hierarchicalFacets[hierarchicalFacetIndex].name,
count: null, // root level, no count
isRefined: true, // root level, always refined
path: null, // root level, no path
escapedValue: null,
exhaustive: rootExhaustive,
data: null,
});
};
}
function generateHierarchicalTree(
sortBy,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel,
currentRefinement
) {
return function generateTree(
hierarchicalTree,
hierarchicalFacetResult,
currentHierarchicalLevel
) {
var parent = hierarchicalTree;
if (currentHierarchicalLevel > 0) {
var level = 0;
parent = hierarchicalTree;
while (level < currentHierarchicalLevel) {
/**
* @type {object[]]} hierarchical data
*/
var data = parent && Array.isArray(parent.data) ? parent.data : [];
parent = find(data, function (subtree) {
return subtree.isRefined;
});
level++;
}
}
// we found a refined parent, let's add current level data under it
if (parent) {
// filter values in case an object has multiple categories:
// {
// categories: {
// level0: ['beers', 'bières'],
// level1: ['beers > IPA', 'bières > Belges']
// }
// }
//
// If parent refinement is `beers`, then we do not want to have `bières > Belges`
// showing up
var picked = Object.keys(hierarchicalFacetResult.data)
.map(function (facetValue) {
return [facetValue, hierarchicalFacetResult.data[facetValue]];
})
.filter(function (tuple) {
var facetValue = tuple[0];
return onlyMatchingTree(
facetValue,
parent.path || hierarchicalRootPath,
currentRefinement,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel
);
});
parent.data = orderBy(
picked.map(function (tuple) {
var facetValue = tuple[0];
var facetCount = tuple[1];
return format(
facetCount,
facetValue,
hierarchicalSeparator,
unescapeFacetValue(currentRefinement),
hierarchicalFacetResult.exhaustive
);
}),
sortBy[0],
sortBy[1]
);
}
return hierarchicalTree;
};
}
// eslint-disable-next-line max-params
function onlyMatchingTree(
facetValue,
parentPath,
currentRefinement,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel
) {
// we want the facetValue is a child of hierarchicalRootPath
if (
hierarchicalRootPath &&
(facetValue.indexOf(hierarchicalRootPath) !== 0 ||
hierarchicalRootPath === facetValue)
) {
return false;
}
// we always want root levels (only when there is no prefix path)
return (
(!hierarchicalRootPath &&
facetValue.indexOf(hierarchicalSeparator) === -1) ||
// if there is a rootPath, being root level mean 1 level under rootPath
(hierarchicalRootPath &&
facetValue.split(hierarchicalSeparator).length -
hierarchicalRootPath.split(hierarchicalSeparator).length ===
1) ||
// if current refinement is a root level and current facetValue is a root level,
// keep the facetValue
(facetValue.indexOf(hierarchicalSeparator) === -1 &&
currentRefinement.indexOf(hierarchicalSeparator) === -1) ||
// currentRefinement is a child of the facet value
currentRefinement.indexOf(facetValue) === 0 ||
// facetValue is a child of the current parent, add it
(facetValue.indexOf(parentPath + hierarchicalSeparator) === 0 &&
(hierarchicalShowParentLevel ||
facetValue.indexOf(currentRefinement) === 0))
);
}
function format(
facetCount,
facetValue,
hierarchicalSeparator,
currentRefinement,
exhaustive
) {
var parts = facetValue.split(hierarchicalSeparator);
return {
name: parts[parts.length - 1].trim(),
path: facetValue,
escapedValue: escapeFacetValue(facetValue),
count: facetCount,
isRefined:
currentRefinement === facetValue ||
currentRefinement.indexOf(facetValue + hierarchicalSeparator) === 0,
exhaustive: exhaustive,
data: null,
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
'use strict';
module.exports = function compact(array) {
if (!Array.isArray(array)) {
return [];
}
return array.filter(Boolean);
};

View File

@@ -0,0 +1,21 @@
'use strict';
// NOTE: this behaves like lodash/defaults, but doesn't mutate the target
// it also preserve keys order
module.exports = function defaultsPure() {
var sources = Array.prototype.slice.call(arguments);
return sources.reduceRight(function (acc, source) {
Object.keys(Object(source)).forEach(function (key) {
if (source[key] === undefined) {
return;
}
if (acc[key] !== undefined) {
// remove if already added, so that we can add it in correct order
delete acc[key];
}
acc[key] = source[key];
});
return acc;
}, {});
};

View File

@@ -0,0 +1,30 @@
'use strict';
/**
* Replaces a leading - with \-
* @private
* @param {any} value the facet value to replace
* @returns {any} the escaped facet value or the value if it was not a string
*/
function escapeFacetValue(value) {
if (typeof value !== 'string') return value;
return String(value).replace(/^-/, '\\-');
}
/**
* Replaces a leading \- with -
* @private
* @param {any} value the escaped facet value
* @returns {any} the unescaped facet value or the value if it was not a string
*/
function unescapeFacetValue(value) {
if (typeof value !== 'string') return value;
return value.replace(/^\\-/, '-');
}
module.exports = {
escapeFacetValue: escapeFacetValue,
unescapeFacetValue: unescapeFacetValue,
};

View File

@@ -0,0 +1,16 @@
'use strict';
// @MAJOR can be replaced by native Array#find when we change support
module.exports = function find(array, comparator) {
if (!Array.isArray(array)) {
return undefined;
}
for (var i = 0; i < array.length; i++) {
if (comparator(array[i])) {
return array[i];
}
}
return undefined;
};

View File

@@ -0,0 +1,15 @@
'use strict';
// @MAJOR can be replaced by native Array#findIndex when we change support
module.exports = function find(array, comparator) {
if (!Array.isArray(array)) {
return -1;
}
for (var i = 0; i < array.length; i++) {
if (comparator(array[i])) {
return i;
}
}
return -1;
};

View File

@@ -0,0 +1,39 @@
'use strict';
var find = require('./find');
/**
* Transform sort format from user friendly notation to lodash format
* @param {string[]} sortBy array of predicate of the form "attribute:order"
* @param {string[]} [defaults] array of predicate of the form "attribute:order"
* @return {array.<string[]>} array containing 2 elements : attributes, orders
*/
module.exports = function formatSort(sortBy, defaults) {
var defaultInstructions = (defaults || []).map(function (sort) {
return sort.split(':');
});
return sortBy.reduce(
function preparePredicate(out, sort) {
var sortInstruction = sort.split(':');
var matchingDefault = find(
defaultInstructions,
function (defaultInstruction) {
return defaultInstruction[0] === sortInstruction[0];
}
);
if (sortInstruction.length > 1 || !matchingDefault) {
out[0].push(sortInstruction[0]);
out[1].push(sortInstruction[1]);
return out;
}
out[0].push(matchingDefault[0]);
out[1].push(matchingDefault[1]);
return out;
},
[[], []]
);
};

View File

@@ -0,0 +1,14 @@
'use strict';
function inherits(ctor, superCtor) {
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true,
},
});
}
module.exports = inherits;

View File

@@ -0,0 +1,12 @@
'use strict';
function intersection(arr1, arr2) {
return arr1.filter(function (value, index) {
return (
arr2.indexOf(value) > -1 &&
arr1.indexOf(value) === index /* skips duplicates */
);
});
}
module.exports = intersection;

View File

@@ -0,0 +1,84 @@
'use strict';
function clone(value) {
if (typeof value === 'object' && value !== null) {
return _merge(Array.isArray(value) ? [] : {}, value);
}
return value;
}
function isObjectOrArrayOrFunction(value) {
return (
typeof value === 'function' ||
Array.isArray(value) ||
Object.prototype.toString.call(value) === '[object Object]'
);
}
function _merge(target, source) {
if (target === source) {
return target;
}
// eslint-disable-next-line no-restricted-syntax
for (var key in source) {
if (
!Object.prototype.hasOwnProperty.call(source, key) ||
key === '__proto__' ||
key === 'constructor'
) {
// eslint-disable-next-line no-continue
continue;
}
var sourceVal = source[key];
var targetVal = target[key];
if (typeof targetVal !== 'undefined' && typeof sourceVal === 'undefined') {
// eslint-disable-next-line no-continue
continue;
}
if (
isObjectOrArrayOrFunction(targetVal) &&
isObjectOrArrayOrFunction(sourceVal)
) {
target[key] = _merge(targetVal, sourceVal);
} else {
target[key] = clone(sourceVal);
}
}
return target;
}
/**
* This method is like Object.assign, but recursively merges own and inherited
* enumerable keyed properties of source objects into the destination object.
*
* NOTE: this behaves like lodash/merge, but:
* - does mutate functions if they are a source
* - treats non-plain objects as plain
* - does not work for circular objects
* - treats sparse arrays as sparse
* - does not convert Array-like objects (Arguments, NodeLists, etc.) to arrays
*
* @param {Object} target The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
*/
function merge(target) {
if (!isObjectOrArrayOrFunction(target)) {
target = {};
}
for (var i = 1, l = arguments.length; i < l; i++) {
var source = arguments[i];
if (isObjectOrArrayOrFunction(source)) {
_merge(target, source);
}
}
return target;
}
module.exports = merge;

View File

@@ -0,0 +1,7 @@
'use strict';
function objectHasKeys(obj) {
return obj && Object.keys(obj).length > 0;
}
module.exports = objectHasKeys;

View File

@@ -0,0 +1,19 @@
'use strict';
// https://github.com/babel/babel/blob/3aaafae053fa75febb3aa45d45b6f00646e30ba4/packages/babel-helpers/src/helpers.js#L604-L620
function _objectWithoutPropertiesLoose(source, excluded) {
if (source === null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key;
var i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
// eslint-disable-next-line no-continue
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
module.exports = _objectWithoutPropertiesLoose;

View File

@@ -0,0 +1,80 @@
'use strict';
function compareAscending(value, other) {
if (value !== other) {
var valIsDefined = value !== undefined;
var valIsNull = value === null;
var othIsDefined = other !== undefined;
var othIsNull = other === null;
if (
(!othIsNull && value > other) ||
(valIsNull && othIsDefined) ||
!valIsDefined
) {
return 1;
}
if (
(!valIsNull && value < other) ||
(othIsNull && valIsDefined) ||
!othIsDefined
) {
return -1;
}
}
return 0;
}
/**
* @param {Array<object>} collection object with keys in attributes
* @param {Array<string>} iteratees attributes
* @param {Array<string>} orders asc | desc
* @return {Array<object>} sorted collection
*/
function orderBy(collection, iteratees, orders) {
if (!Array.isArray(collection)) {
return [];
}
if (!Array.isArray(orders)) {
orders = [];
}
var result = collection.map(function (value, index) {
return {
criteria: iteratees.map(function (iteratee) {
return value[iteratee];
}),
index: index,
value: value,
};
});
result.sort(function comparer(object, other) {
var index = -1;
while (++index < object.criteria.length) {
var res = compareAscending(object.criteria[index], other.criteria[index]);
if (res) {
if (index >= orders.length) {
return res;
}
if (orders[index] === 'desc') {
return -res;
}
return res;
}
}
// This 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;
});
return result.map(function (res) {
return res.value;
});
}
module.exports = orderBy;

View File

@@ -0,0 +1,17 @@
'use strict';
function valToNumber(v) {
if (typeof v === 'number') {
return v;
} else if (typeof v === 'string') {
return parseFloat(v);
} else if (Array.isArray(v)) {
return v.map(valToNumber);
}
throw new Error(
'The value should be a number, a parsable string or an array of those.'
);
}
module.exports = valToNumber;

448
node_modules/algoliasearch-helper/src/requestBuilder.js generated vendored Normal file
View File

@@ -0,0 +1,448 @@
'use strict';
var merge = require('./functions/merge');
function sortObject(obj) {
return Object.keys(obj)
.sort()
.reduce(function (acc, curr) {
acc[curr] = obj[curr];
return acc;
}, {});
}
var requestBuilder = {
/**
* Get all the queries to send to the client, those queries can used directly
* with the Algolia client.
* @private
* @param {string} index The name of the index
* @param {SearchParameters} state The state from which to get the queries
* @return {object[]} The queries
*/
_getQueries: function getQueries(index, state) {
var queries = [];
// One query for the hits
queries.push({
indexName: index,
params: requestBuilder._getHitsSearchParams(state),
});
// One for each disjunctive facets
state.getRefinedDisjunctiveFacets().forEach(function (refinedFacet) {
queries.push({
indexName: index,
params: requestBuilder._getDisjunctiveFacetSearchParams(
state,
refinedFacet
),
});
});
// More to get the parent levels of the hierarchical facets when refined
state.getRefinedHierarchicalFacets().forEach(function (refinedFacet) {
var hierarchicalFacet = state.getHierarchicalFacetByName(refinedFacet);
var currentRefinement = state.getHierarchicalRefinement(refinedFacet);
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
// If we are deeper than level 0 (starting from `beer > IPA`)
// we want to get all parent values
if (
currentRefinement.length > 0 &&
currentRefinement[0].split(separator).length > 1
) {
// We generate a map of the filters we will use for our facet values queries
var filtersMap = currentRefinement[0]
.split(separator)
.slice(0, -1)
.reduce(function createFiltersMap(map, segment, level) {
return map.concat({
attribute: hierarchicalFacet.attributes[level],
value:
level === 0
? segment
: [map[map.length - 1].value, segment].join(separator),
});
}, []);
filtersMap.forEach(function (filter, level) {
var params = requestBuilder._getDisjunctiveFacetSearchParams(
state,
filter.attribute,
level === 0
);
// Keep facet filters unrelated to current hierarchical attributes
function hasHierarchicalFacetFilter(value) {
return hierarchicalFacet.attributes.some(function (attribute) {
return attribute === value.split(':')[0];
});
}
var filteredFacetFilters = (params.facetFilters || []).reduce(
function (acc, facetFilter) {
if (Array.isArray(facetFilter)) {
var filtered = facetFilter.filter(function (filterValue) {
return !hasHierarchicalFacetFilter(filterValue);
});
if (filtered.length > 0) {
acc.push(filtered);
}
}
if (
typeof facetFilter === 'string' &&
!hasHierarchicalFacetFilter(facetFilter)
) {
acc.push(facetFilter);
}
return acc;
},
[]
);
var parent = filtersMap[level - 1];
if (level > 0) {
params.facetFilters = filteredFacetFilters.concat(
parent.attribute + ':' + parent.value
);
} else {
params.facetFilters =
filteredFacetFilters.length > 0
? filteredFacetFilters
: undefined;
}
queries.push({ indexName: index, params: params });
});
}
});
return queries;
},
/**
* Build search parameters used to fetch hits
* @private
* @param {SearchParameters} state The state from which to get the queries
* @return {object.<string, any>} The search parameters for hits
*/
_getHitsSearchParams: function (state) {
var facets = state.facets
.concat(state.disjunctiveFacets)
.concat(requestBuilder._getHitsHierarchicalFacetsAttributes(state))
.sort();
var facetFilters = requestBuilder._getFacetFilters(state);
var numericFilters = requestBuilder._getNumericFilters(state);
var tagFilters = requestBuilder._getTagFilters(state);
var additionalParams = {
facets: facets.indexOf('*') > -1 ? ['*'] : facets,
tagFilters: tagFilters,
};
if (facetFilters.length > 0) {
additionalParams.facetFilters = facetFilters;
}
if (numericFilters.length > 0) {
additionalParams.numericFilters = numericFilters;
}
return sortObject(merge({}, state.getQueryParams(), additionalParams));
},
/**
* Build search parameters used to fetch a disjunctive facet
* @private
* @param {SearchParameters} state The state from which to get the queries
* @param {string} facet the associated facet name
* @param {boolean} hierarchicalRootLevel ?? FIXME
* @return {object} The search parameters for a disjunctive facet
*/
_getDisjunctiveFacetSearchParams: function (
state,
facet,
hierarchicalRootLevel
) {
var facetFilters = requestBuilder._getFacetFilters(
state,
facet,
hierarchicalRootLevel
);
var numericFilters = requestBuilder._getNumericFilters(state, facet);
var tagFilters = requestBuilder._getTagFilters(state);
var additionalParams = {
hitsPerPage: 0,
page: 0,
analytics: false,
clickAnalytics: false,
};
if (tagFilters.length > 0) {
additionalParams.tagFilters = tagFilters;
}
var hierarchicalFacet = state.getHierarchicalFacetByName(facet);
if (hierarchicalFacet) {
additionalParams.facets =
requestBuilder._getDisjunctiveHierarchicalFacetAttribute(
state,
hierarchicalFacet,
hierarchicalRootLevel
);
} else {
additionalParams.facets = facet;
}
if (numericFilters.length > 0) {
additionalParams.numericFilters = numericFilters;
}
if (facetFilters.length > 0) {
additionalParams.facetFilters = facetFilters;
}
return sortObject(merge({}, state.getQueryParams(), additionalParams));
},
/**
* Return the numeric filters in an algolia request fashion
* @private
* @param {SearchParameters} state the state from which to get the filters
* @param {string} [facetName] the name of the attribute for which the filters should be excluded
* @return {string[]} the numeric filters in the algolia format
*/
_getNumericFilters: function (state, facetName) {
if (state.numericFilters) {
return state.numericFilters;
}
var numericFilters = [];
Object.keys(state.numericRefinements).forEach(function (attribute) {
var operators = state.numericRefinements[attribute] || {};
Object.keys(operators).forEach(function (operator) {
var values = operators[operator] || [];
if (facetName !== attribute) {
values.forEach(function (value) {
if (Array.isArray(value)) {
var vs = value.map(function (v) {
return attribute + operator + v;
});
numericFilters.push(vs);
} else {
numericFilters.push(attribute + operator + value);
}
});
}
});
});
return numericFilters;
},
/**
* Return the tags filters depending on which format is used, either tagFilters or tagRefinements
* @private
* @param {SearchParameters} state the state from which to get the filters
* @return {string} Tag filters in a single string
*/
_getTagFilters: function (state) {
if (state.tagFilters) {
return state.tagFilters;
}
return state.tagRefinements.join(',');
},
/**
* Build facetFilters parameter based on current refinements. The array returned
* contains strings representing the facet filters in the algolia format.
* @private
* @param {SearchParameters} state The state from which to get the queries
* @param {string} [facet] if set, the current disjunctive facet
* @param {boolean} [hierarchicalRootLevel] ?? FIXME
* @return {array.<string>} The facet filters in the algolia format
*/
_getFacetFilters: function (state, facet, hierarchicalRootLevel) {
var facetFilters = [];
var facetsRefinements = state.facetsRefinements || {};
Object.keys(facetsRefinements)
.sort()
.forEach(function (facetName) {
var facetValues = facetsRefinements[facetName] || [];
facetValues
.slice()
.sort()
.forEach(function (facetValue) {
facetFilters.push(facetName + ':' + facetValue);
});
});
var facetsExcludes = state.facetsExcludes || {};
Object.keys(facetsExcludes)
.sort()
.forEach(function (facetName) {
var facetValues = facetsExcludes[facetName] || [];
facetValues.sort().forEach(function (facetValue) {
facetFilters.push(facetName + ':-' + facetValue);
});
});
var disjunctiveFacetsRefinements = state.disjunctiveFacetsRefinements || {};
Object.keys(disjunctiveFacetsRefinements)
.sort()
.forEach(function (facetName) {
var facetValues = disjunctiveFacetsRefinements[facetName] || [];
if (facetName === facet || !facetValues || facetValues.length === 0) {
return;
}
var orFilters = [];
facetValues
.slice()
.sort()
.forEach(function (facetValue) {
orFilters.push(facetName + ':' + facetValue);
});
facetFilters.push(orFilters);
});
var hierarchicalFacetsRefinements =
state.hierarchicalFacetsRefinements || {};
Object.keys(hierarchicalFacetsRefinements)
.sort()
.forEach(function (facetName) {
var facetValues = hierarchicalFacetsRefinements[facetName] || [];
var facetValue = facetValues[0];
if (facetValue === undefined) {
return;
}
var hierarchicalFacet = state.getHierarchicalFacetByName(facetName);
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
var rootPath = state._getHierarchicalRootPath(hierarchicalFacet);
var attributeToRefine;
var attributesIndex;
// we ask for parent facet values only when the `facet` is the current hierarchical facet
if (facet === facetName) {
// if we are at the root level already, no need to ask for facet values, we get them from
// the hits query
if (
facetValue.indexOf(separator) === -1 ||
(!rootPath && hierarchicalRootLevel === true) ||
(rootPath &&
rootPath.split(separator).length ===
facetValue.split(separator).length)
) {
return;
}
if (!rootPath) {
attributesIndex = facetValue.split(separator).length - 2;
facetValue = facetValue.slice(0, facetValue.lastIndexOf(separator));
} else {
attributesIndex = rootPath.split(separator).length - 1;
facetValue = rootPath;
}
attributeToRefine = hierarchicalFacet.attributes[attributesIndex];
} else {
attributesIndex = facetValue.split(separator).length - 1;
attributeToRefine = hierarchicalFacet.attributes[attributesIndex];
}
if (attributeToRefine) {
facetFilters.push([attributeToRefine + ':' + facetValue]);
}
});
return facetFilters;
},
_getHitsHierarchicalFacetsAttributes: function (state) {
var out = [];
return state.hierarchicalFacets.reduce(
// ask for as much levels as there's hierarchical refinements
function getHitsAttributesForHierarchicalFacet(
allAttributes,
hierarchicalFacet
) {
var hierarchicalRefinement = state.getHierarchicalRefinement(
hierarchicalFacet.name
)[0];
// if no refinement, ask for root level
if (!hierarchicalRefinement) {
allAttributes.push(hierarchicalFacet.attributes[0]);
return allAttributes;
}
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
var level = hierarchicalRefinement.split(separator).length;
var newAttributes = hierarchicalFacet.attributes.slice(0, level + 1);
return allAttributes.concat(newAttributes);
},
out
);
},
_getDisjunctiveHierarchicalFacetAttribute: function (
state,
hierarchicalFacet,
rootLevel
) {
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
if (rootLevel === true) {
var rootPath = state._getHierarchicalRootPath(hierarchicalFacet);
var attributeIndex = 0;
if (rootPath) {
attributeIndex = rootPath.split(separator).length;
}
return [hierarchicalFacet.attributes[attributeIndex]];
}
var hierarchicalRefinement =
state.getHierarchicalRefinement(hierarchicalFacet.name)[0] || '';
// if refinement is 'beers > IPA > Flying dog',
// then we want `facets: ['beers > IPA']` as disjunctive facet (parent level values)
var parentLevel = hierarchicalRefinement.split(separator).length - 1;
return hierarchicalFacet.attributes.slice(0, parentLevel + 1);
},
getSearchForFacetQuery: function (facetName, query, maxFacetHits, state) {
var stateForSearchForFacetValues = state.isDisjunctiveFacet(facetName)
? state.clearRefinements(facetName)
: state;
var searchForFacetSearchParameters = {
facetQuery: query,
facetName: facetName,
};
if (typeof maxFacetHits === 'number') {
searchForFacetSearchParameters.maxFacetHits = maxFacetHits;
}
return sortObject(
merge(
{},
requestBuilder._getHitsSearchParams(stateForSearchForFacetValues),
searchForFacetSearchParameters
)
);
},
};
module.exports = requestBuilder;

View File

@@ -0,0 +1,8 @@
'use strict';
module.exports = function isValidUserToken(userToken) {
if (userToken === null) {
return false;
}
return /^[a-zA-Z0-9_-]{1,64}$/.test(userToken);
};

3
node_modules/algoliasearch-helper/src/version.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
'use strict';
module.exports = '3.16.3';