\n{\n \"query\": \"\",\n \"disjunctiveFacets\": [\n \"customerReviewCount\",\n \"category\",\n \"salePrice_range\",\n \"manufacturer\"\n ],\n \"maxValuesPerFacet\": 30,\n \"page\": 0,\n \"hitsPerPage\": 10,\n \"facets\": [\n \"type\",\n \"shipping\"\n ]\n}\n */\n\n\nfunction SearchParameters(newParameters) {\n var params = newParameters ? SearchParameters._parseNumbers(newParameters) : {};\n\n if (params.userToken !== undefined && !isValidUserToken(params.userToken)) {\n console.warn('[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\\n - Format: [a-zA-Z0-9_-]{1,64}');\n }\n /**\n * This attribute contains the list of all the conjunctive facets\n * used. This list will be added to requested facets in the\n * [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.\n * @member {string[]}\n */\n\n\n this.facets = params.facets || [];\n /**\n * This attribute contains the list of all the disjunctive facets\n * used. This list will be added to requested facets in the\n * [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.\n * @member {string[]}\n */\n\n this.disjunctiveFacets = params.disjunctiveFacets || [];\n /**\n * This attribute contains the list of all the hierarchical facets\n * used. This list will be added to requested facets in the\n * [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.\n * Hierarchical facets are a sub type of disjunctive facets that\n * let you filter faceted attributes hierarchically.\n * @member {string[]|object[]}\n */\n\n this.hierarchicalFacets = params.hierarchicalFacets || []; // Refinements\n\n /**\n * This attribute contains all the filters that need to be\n * applied on the conjunctive facets. Each facet must be properly\n * defined in the `facets` attribute.\n *\n * The key is the name of the facet, and the `FacetList` contains all\n * filters selected for the associated facet name.\n *\n * When querying algolia, the values stored in this attribute will\n * be translated into the `facetFilters` attribute.\n * @member {Object.}\n */\n\n this.facetsRefinements = params.facetsRefinements || {};\n /**\n * This attribute contains all the filters that need to be\n * excluded from the conjunctive facets. Each facet must be properly\n * defined in the `facets` attribute.\n *\n * The key is the name of the facet, and the `FacetList` contains all\n * filters excluded for the associated facet name.\n *\n * When querying algolia, the values stored in this attribute will\n * be translated into the `facetFilters` attribute.\n * @member {Object.}\n */\n\n this.facetsExcludes = params.facetsExcludes || {};\n /**\n * This attribute contains all the filters that need to be\n * applied on the disjunctive facets. Each facet must be properly\n * defined in the `disjunctiveFacets` attribute.\n *\n * The key is the name of the facet, and the `FacetList` contains all\n * filters selected for the associated facet name.\n *\n * When querying algolia, the values stored in this attribute will\n * be translated into the `facetFilters` attribute.\n * @member {Object.}\n */\n\n this.disjunctiveFacetsRefinements = params.disjunctiveFacetsRefinements || {};\n /**\n * This attribute contains all the filters that need to be\n * applied on the numeric attributes.\n *\n * The key is the name of the attribute, and the value is the\n * filters to apply to this attribute.\n *\n * When querying algolia, the values stored in this attribute will\n * be translated into the `numericFilters` attribute.\n * @member {Object.}\n */\n\n this.numericRefinements = params.numericRefinements || {};\n /**\n * This attribute contains all the tags used to refine the query.\n *\n * When querying algolia, the values stored in this attribute will\n * be translated into the `tagFilters` attribute.\n * @member {string[]}\n */\n\n this.tagRefinements = params.tagRefinements || [];\n /**\n * This attribute contains all the filters that need to be\n * applied on the hierarchical facets. Each facet must be properly\n * defined in the `hierarchicalFacets` attribute.\n *\n * The key is the name of the facet, and the `FacetList` contains all\n * filters selected for the associated facet name. The FacetList values\n * are structured as a string that contain the values for each level\n * separated by the configured separator.\n *\n * When querying algolia, the values stored in this attribute will\n * be translated into the `facetFilters` attribute.\n * @member {Object.}\n */\n\n this.hierarchicalFacetsRefinements = params.hierarchicalFacetsRefinements || {};\n var self = this;\n Object.keys(params).forEach(function (paramName) {\n var isKeyKnown = SearchParameters.PARAMETERS.indexOf(paramName) !== -1;\n var isValueDefined = params[paramName] !== undefined;\n\n if (!isKeyKnown && isValueDefined) {\n self[paramName] = params[paramName];\n }\n });\n}\n/**\n * List all the properties in SearchParameters and therefore all the known Algolia properties\n * This doesn't contain any beta/hidden features.\n * @private\n */\n\n\nSearchParameters.PARAMETERS = Object.keys(new SearchParameters());\n/**\n * @private\n * @param {object} partialState full or part of a state\n * @return {object} a new object with the number keys as number\n */\n\nSearchParameters._parseNumbers = function (partialState) {\n // Do not reparse numbers in SearchParameters, they ought to be parsed already\n if (partialState instanceof SearchParameters) return partialState;\n var numbers = {};\n var numberKeys = ['aroundPrecision', 'aroundRadius', 'getRankingInfo', 'minWordSizefor2Typos', 'minWordSizefor1Typo', 'page', 'maxValuesPerFacet', 'distinct', 'minimumAroundRadius', 'hitsPerPage', 'minProximity'];\n numberKeys.forEach(function (k) {\n var value = partialState[k];\n\n if (typeof value === 'string') {\n var parsedValue = parseFloat(value); // global isNaN is ok to use here, value is only number or NaN\n\n numbers[k] = isNaN(parsedValue) ? value : parsedValue;\n }\n }); // there's two formats of insideBoundingBox, we need to parse\n // the one which is an array of float geo rectangles\n\n if (Array.isArray(partialState.insideBoundingBox)) {\n numbers.insideBoundingBox = partialState.insideBoundingBox.map(function (geoRect) {\n if (Array.isArray(geoRect)) {\n return geoRect.map(function (value) {\n return parseFloat(value);\n });\n }\n\n return geoRect;\n });\n }\n\n if (partialState.numericRefinements) {\n var numericRefinements = {};\n Object.keys(partialState.numericRefinements).forEach(function (attribute) {\n var operators = partialState.numericRefinements[attribute] || {};\n numericRefinements[attribute] = {};\n Object.keys(operators).forEach(function (operator) {\n var values = operators[operator];\n var parsedValues = values.map(function (v) {\n if (Array.isArray(v)) {\n return v.map(function (vPrime) {\n if (typeof vPrime === 'string') {\n return parseFloat(vPrime);\n }\n\n return vPrime;\n });\n } else if (typeof v === 'string') {\n return parseFloat(v);\n }\n\n return v;\n });\n numericRefinements[attribute][operator] = parsedValues;\n });\n });\n numbers.numericRefinements = numericRefinements;\n }\n\n return merge({}, partialState, numbers);\n};\n/**\n * Factory for SearchParameters\n * @param {object|SearchParameters} newParameters existing parameters or partial\n * object for the properties of a new SearchParameters\n * @return {SearchParameters} frozen instance of SearchParameters\n */\n\n\nSearchParameters.make = function makeSearchParameters(newParameters) {\n var instance = new SearchParameters(newParameters);\n var hierarchicalFacets = newParameters.hierarchicalFacets || [];\n hierarchicalFacets.forEach(function (facet) {\n if (facet.rootPath) {\n var currentRefinement = instance.getHierarchicalRefinement(facet.name);\n\n if (currentRefinement.length > 0 && currentRefinement[0].indexOf(facet.rootPath) !== 0) {\n instance = instance.clearRefinements(facet.name);\n } // get it again in case it has been cleared\n\n\n currentRefinement = instance.getHierarchicalRefinement(facet.name);\n\n if (currentRefinement.length === 0) {\n instance = instance.toggleHierarchicalFacetRefinement(facet.name, facet.rootPath);\n }\n }\n });\n return instance;\n};\n/**\n * Validates the new parameters based on the previous state\n * @param {SearchParameters} currentState the current state\n * @param {object|SearchParameters} parameters the new parameters to set\n * @return {Error|null} Error if the modification is invalid, null otherwise\n */\n\n\nSearchParameters.validate = function (currentState, parameters) {\n var params = parameters || {};\n\n if (currentState.tagFilters && params.tagRefinements && params.tagRefinements.length > 0) {\n return new Error('[Tags] Cannot switch from the managed tag API to the advanced API. It is probably ' + 'an error, if it is really what you want, you should first clear the tags with clearTags method.');\n }\n\n if (currentState.tagRefinements.length > 0 && params.tagFilters) {\n return new Error('[Tags] Cannot switch from the advanced tag API to the managed API. It is probably ' + 'an error, if it is not, you should first clear the tags with clearTags method.');\n }\n\n if (currentState.numericFilters && params.numericRefinements && objectHasKeys(params.numericRefinements)) {\n return new Error(\"[Numeric filters] Can't switch from the advanced to the managed API. It\" + ' is probably an error, if this is really what you want, you have to first' + ' clear the numeric filters.');\n }\n\n if (objectHasKeys(currentState.numericRefinements) && params.numericFilters) {\n return new Error(\"[Numeric filters] Can't switch from the managed API to the advanced. It\" + ' is probably an error, if this is really what you want, you have to first' + ' clear the numeric filters.');\n }\n\n return null;\n};\n\nSearchParameters.prototype = {\n constructor: SearchParameters,\n\n /**\n * Remove all refinements (disjunctive + conjunctive + excludes + numeric filters)\n * @method\n * @param {undefined|string|SearchParameters.clearCallback} [attribute] optional string or function\n * - If not given, means to clear all the filters.\n * - If `string`, means to clear all refinements for the `attribute` named filter.\n * - If `function`, means to clear all the refinements that return truthy values.\n * @return {SearchParameters}\n */\n clearRefinements: function clearRefinements(attribute) {\n var patch = {\n numericRefinements: this._clearNumericRefinements(attribute),\n facetsRefinements: RefinementList.clearRefinement(this.facetsRefinements, attribute, 'conjunctiveFacet'),\n facetsExcludes: RefinementList.clearRefinement(this.facetsExcludes, attribute, 'exclude'),\n disjunctiveFacetsRefinements: RefinementList.clearRefinement(this.disjunctiveFacetsRefinements, attribute, 'disjunctiveFacet'),\n hierarchicalFacetsRefinements: RefinementList.clearRefinement(this.hierarchicalFacetsRefinements, attribute, 'hierarchicalFacet')\n };\n\n if (patch.numericRefinements === this.numericRefinements && patch.facetsRefinements === this.facetsRefinements && patch.facetsExcludes === this.facetsExcludes && patch.disjunctiveFacetsRefinements === this.disjunctiveFacetsRefinements && patch.hierarchicalFacetsRefinements === this.hierarchicalFacetsRefinements) {\n return this;\n }\n\n return this.setQueryParameters(patch);\n },\n\n /**\n * Remove all the refined tags from the SearchParameters\n * @method\n * @return {SearchParameters}\n */\n clearTags: function clearTags() {\n if (this.tagFilters === undefined && this.tagRefinements.length === 0) return this;\n return this.setQueryParameters({\n tagFilters: undefined,\n tagRefinements: []\n });\n },\n\n /**\n * Set the index.\n * @method\n * @param {string} index the index name\n * @return {SearchParameters}\n */\n setIndex: function setIndex(index) {\n if (index === this.index) return this;\n return this.setQueryParameters({\n index: index\n });\n },\n\n /**\n * Query setter\n * @method\n * @param {string} newQuery value for the new query\n * @return {SearchParameters}\n */\n setQuery: function setQuery(newQuery) {\n if (newQuery === this.query) return this;\n return this.setQueryParameters({\n query: newQuery\n });\n },\n\n /**\n * Page setter\n * @method\n * @param {number} newPage new page number\n * @return {SearchParameters}\n */\n setPage: function setPage(newPage) {\n if (newPage === this.page) return this;\n return this.setQueryParameters({\n page: newPage\n });\n },\n\n /**\n * Facets setter\n * The facets are the simple facets, used for conjunctive (and) faceting.\n * @method\n * @param {string[]} facets all the attributes of the algolia records used for conjunctive faceting\n * @return {SearchParameters}\n */\n setFacets: function setFacets(facets) {\n return this.setQueryParameters({\n facets: facets\n });\n },\n\n /**\n * Disjunctive facets setter\n * Change the list of disjunctive (or) facets the helper chan handle.\n * @method\n * @param {string[]} facets all the attributes of the algolia records used for disjunctive faceting\n * @return {SearchParameters}\n */\n setDisjunctiveFacets: function setDisjunctiveFacets(facets) {\n return this.setQueryParameters({\n disjunctiveFacets: facets\n });\n },\n\n /**\n * HitsPerPage setter\n * Hits per page represents the number of hits retrieved for this query\n * @method\n * @param {number} n number of hits retrieved per page of results\n * @return {SearchParameters}\n */\n setHitsPerPage: function setHitsPerPage(n) {\n if (this.hitsPerPage === n) return this;\n return this.setQueryParameters({\n hitsPerPage: n\n });\n },\n\n /**\n * typoTolerance setter\n * Set the value of typoTolerance\n * @method\n * @param {string} typoTolerance new value of typoTolerance (\"true\", \"false\", \"min\" or \"strict\")\n * @return {SearchParameters}\n */\n setTypoTolerance: function setTypoTolerance(typoTolerance) {\n if (this.typoTolerance === typoTolerance) return this;\n return this.setQueryParameters({\n typoTolerance: typoTolerance\n });\n },\n\n /**\n * Add a numeric filter for a given attribute\n * When value is an array, they are combined with OR\n * When value is a single value, it will combined with AND\n * @method\n * @param {string} attribute attribute to set the filter on\n * @param {string} operator operator of the filter (possible values: =, >, >=, <, <=, !=)\n * @param {number | number[]} value value of the filter\n * @return {SearchParameters}\n * @example\n * // for price = 50 or 40\n * searchparameter.addNumericRefinement('price', '=', [50, 40]);\n * @example\n * // for size = 38 and 40\n * searchparameter.addNumericRefinement('size', '=', 38);\n * searchparameter.addNumericRefinement('size', '=', 40);\n */\n addNumericRefinement: function addNumericRefinement(attribute, operator, v) {\n var value = valToNumber(v);\n if (this.isNumericRefined(attribute, operator, value)) return this;\n var mod = merge({}, this.numericRefinements);\n mod[attribute] = merge({}, mod[attribute]);\n\n if (mod[attribute][operator]) {\n // Array copy\n mod[attribute][operator] = mod[attribute][operator].slice(); // Add the element. Concat can't be used here because value can be an array.\n\n mod[attribute][operator].push(value);\n } else {\n mod[attribute][operator] = [value];\n }\n\n return this.setQueryParameters({\n numericRefinements: mod\n });\n },\n\n /**\n * Get the list of conjunctive refinements for a single facet\n * @param {string} facetName name of the attribute used for faceting\n * @return {string[]} list of refinements\n */\n getConjunctiveRefinements: function getConjunctiveRefinements(facetName) {\n if (!this.isConjunctiveFacet(facetName)) {\n return [];\n }\n\n return this.facetsRefinements[facetName] || [];\n },\n\n /**\n * Get the list of disjunctive refinements for a single facet\n * @param {string} facetName name of the attribute used for faceting\n * @return {string[]} list of refinements\n */\n getDisjunctiveRefinements: function getDisjunctiveRefinements(facetName) {\n if (!this.isDisjunctiveFacet(facetName)) {\n return [];\n }\n\n return this.disjunctiveFacetsRefinements[facetName] || [];\n },\n\n /**\n * Get the list of hierarchical refinements for a single facet\n * @param {string} facetName name of the attribute used for faceting\n * @return {string[]} list of refinements\n */\n getHierarchicalRefinement: function getHierarchicalRefinement(facetName) {\n // we send an array but we currently do not support multiple\n // hierarchicalRefinements for a hierarchicalFacet\n return this.hierarchicalFacetsRefinements[facetName] || [];\n },\n\n /**\n * Get the list of exclude refinements for a single facet\n * @param {string} facetName name of the attribute used for faceting\n * @return {string[]} list of refinements\n */\n getExcludeRefinements: function getExcludeRefinements(facetName) {\n if (!this.isConjunctiveFacet(facetName)) {\n return [];\n }\n\n return this.facetsExcludes[facetName] || [];\n },\n\n /**\n * Remove all the numeric filter for a given (attribute, operator)\n * @method\n * @param {string} attribute attribute to set the filter on\n * @param {string} [operator] operator of the filter (possible values: =, >, >=, <, <=, !=)\n * @param {number} [number] the value to be removed\n * @return {SearchParameters}\n */\n removeNumericRefinement: function removeNumericRefinement(attribute, operator, paramValue) {\n if (paramValue !== undefined) {\n if (!this.isNumericRefined(attribute, operator, paramValue)) {\n return this;\n }\n\n return this.setQueryParameters({\n numericRefinements: this._clearNumericRefinements(function (value, key) {\n return key === attribute && value.op === operator && isEqualNumericRefinement(value.val, valToNumber(paramValue));\n })\n });\n } else if (operator !== undefined) {\n if (!this.isNumericRefined(attribute, operator)) return this;\n return this.setQueryParameters({\n numericRefinements: this._clearNumericRefinements(function (value, key) {\n return key === attribute && value.op === operator;\n })\n });\n }\n\n if (!this.isNumericRefined(attribute)) return this;\n return this.setQueryParameters({\n numericRefinements: this._clearNumericRefinements(function (value, key) {\n return key === attribute;\n })\n });\n },\n\n /**\n * Get the list of numeric refinements for a single facet\n * @param {string} facetName name of the attribute used for faceting\n * @return {SearchParameters.OperatorList} list of refinements\n */\n getNumericRefinements: function getNumericRefinements(facetName) {\n return this.numericRefinements[facetName] || {};\n },\n\n /**\n * Return the current refinement for the (attribute, operator)\n * @param {string} attribute attribute in the record\n * @param {string} operator operator applied on the refined values\n * @return {Array.} refined values\n */\n getNumericRefinement: function getNumericRefinement(attribute, operator) {\n return this.numericRefinements[attribute] && this.numericRefinements[attribute][operator];\n },\n\n /**\n * Clear numeric filters.\n * @method\n * @private\n * @param {string|SearchParameters.clearCallback} [attribute] optional string or function\n * - If not given, means to clear all the filters.\n * - If `string`, means to clear all refinements for the `attribute` named filter.\n * - If `function`, means to clear all the refinements that return truthy values.\n * @return {Object.}\n */\n _clearNumericRefinements: function _clearNumericRefinements(attribute) {\n if (attribute === undefined) {\n if (!objectHasKeys(this.numericRefinements)) {\n return this.numericRefinements;\n }\n\n return {};\n } else if (typeof attribute === 'string') {\n return omit(this.numericRefinements, [attribute]);\n } else if (typeof attribute === 'function') {\n var hasChanged = false;\n var numericRefinements = this.numericRefinements;\n var newNumericRefinements = Object.keys(numericRefinements).reduce(function (memo, key) {\n var operators = numericRefinements[key];\n var operatorList = {};\n operators = operators || {};\n Object.keys(operators).forEach(function (operator) {\n var values = operators[operator] || [];\n var outValues = [];\n values.forEach(function (value) {\n var predicateResult = attribute({\n val: value,\n op: operator\n }, key, 'numeric');\n if (!predicateResult) outValues.push(value);\n });\n\n if (outValues.length !== values.length) {\n hasChanged = true;\n }\n\n operatorList[operator] = outValues;\n });\n memo[key] = operatorList;\n return memo;\n }, {});\n if (hasChanged) return newNumericRefinements;\n return this.numericRefinements;\n }\n },\n\n /**\n * Add a facet to the facets attribute of the helper configuration, if it\n * isn't already present.\n * @method\n * @param {string} facet facet name to add\n * @return {SearchParameters}\n */\n addFacet: function addFacet(facet) {\n if (this.isConjunctiveFacet(facet)) {\n return this;\n }\n\n return this.setQueryParameters({\n facets: this.facets.concat([facet])\n });\n },\n\n /**\n * Add a disjunctive facet to the disjunctiveFacets attribute of the helper\n * configuration, if it isn't already present.\n * @method\n * @param {string} facet disjunctive facet name to add\n * @return {SearchParameters}\n */\n addDisjunctiveFacet: function addDisjunctiveFacet(facet) {\n if (this.isDisjunctiveFacet(facet)) {\n return this;\n }\n\n return this.setQueryParameters({\n disjunctiveFacets: this.disjunctiveFacets.concat([facet])\n });\n },\n\n /**\n * Add a hierarchical facet to the hierarchicalFacets attribute of the helper\n * configuration.\n * @method\n * @param {object} hierarchicalFacet hierarchical facet to add\n * @return {SearchParameters}\n * @throws will throw an error if a hierarchical facet with the same name was already declared\n */\n addHierarchicalFacet: function addHierarchicalFacet(hierarchicalFacet) {\n if (this.isHierarchicalFacet(hierarchicalFacet.name)) {\n throw new Error('Cannot declare two hierarchical facets with the same name: `' + hierarchicalFacet.name + '`');\n }\n\n return this.setQueryParameters({\n hierarchicalFacets: this.hierarchicalFacets.concat([hierarchicalFacet])\n });\n },\n\n /**\n * Add a refinement on a \"normal\" facet\n * @method\n * @param {string} facet attribute to apply the faceting on\n * @param {string} value value of the attribute (will be converted to string)\n * @return {SearchParameters}\n */\n addFacetRefinement: function addFacetRefinement(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the facets attribute of the helper configuration');\n }\n\n if (RefinementList.isRefined(this.facetsRefinements, facet, value)) return this;\n return this.setQueryParameters({\n facetsRefinements: RefinementList.addRefinement(this.facetsRefinements, facet, value)\n });\n },\n\n /**\n * Exclude a value from a \"normal\" facet\n * @method\n * @param {string} facet attribute to apply the exclusion on\n * @param {string} value value of the attribute (will be converted to string)\n * @return {SearchParameters}\n */\n addExcludeRefinement: function addExcludeRefinement(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the facets attribute of the helper configuration');\n }\n\n if (RefinementList.isRefined(this.facetsExcludes, facet, value)) return this;\n return this.setQueryParameters({\n facetsExcludes: RefinementList.addRefinement(this.facetsExcludes, facet, value)\n });\n },\n\n /**\n * Adds a refinement on a disjunctive facet.\n * @method\n * @param {string} facet attribute to apply the faceting on\n * @param {string} value value of the attribute (will be converted to string)\n * @return {SearchParameters}\n */\n addDisjunctiveFacetRefinement: function addDisjunctiveFacetRefinement(facet, value) {\n if (!this.isDisjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the disjunctiveFacets attribute of the helper configuration');\n }\n\n if (RefinementList.isRefined(this.disjunctiveFacetsRefinements, facet, value)) return this;\n return this.setQueryParameters({\n disjunctiveFacetsRefinements: RefinementList.addRefinement(this.disjunctiveFacetsRefinements, facet, value)\n });\n },\n\n /**\n * addTagRefinement adds a tag to the list used to filter the results\n * @param {string} tag tag to be added\n * @return {SearchParameters}\n */\n addTagRefinement: function addTagRefinement(tag) {\n if (this.isTagRefined(tag)) return this;\n var modification = {\n tagRefinements: this.tagRefinements.concat(tag)\n };\n return this.setQueryParameters(modification);\n },\n\n /**\n * Remove a facet from the facets attribute of the helper configuration, if it\n * is present.\n * @method\n * @param {string} facet facet name to remove\n * @return {SearchParameters}\n */\n removeFacet: function removeFacet(facet) {\n if (!this.isConjunctiveFacet(facet)) {\n return this;\n }\n\n return this.clearRefinements(facet).setQueryParameters({\n facets: this.facets.filter(function (f) {\n return f !== facet;\n })\n });\n },\n\n /**\n * Remove a disjunctive facet from the disjunctiveFacets attribute of the\n * helper configuration, if it is present.\n * @method\n * @param {string} facet disjunctive facet name to remove\n * @return {SearchParameters}\n */\n removeDisjunctiveFacet: function removeDisjunctiveFacet(facet) {\n if (!this.isDisjunctiveFacet(facet)) {\n return this;\n }\n\n return this.clearRefinements(facet).setQueryParameters({\n disjunctiveFacets: this.disjunctiveFacets.filter(function (f) {\n return f !== facet;\n })\n });\n },\n\n /**\n * Remove a hierarchical facet from the hierarchicalFacets attribute of the\n * helper configuration, if it is present.\n * @method\n * @param {string} facet hierarchical facet name to remove\n * @return {SearchParameters}\n */\n removeHierarchicalFacet: function removeHierarchicalFacet(facet) {\n if (!this.isHierarchicalFacet(facet)) {\n return this;\n }\n\n return this.clearRefinements(facet).setQueryParameters({\n hierarchicalFacets: this.hierarchicalFacets.filter(function (f) {\n return f.name !== facet;\n })\n });\n },\n\n /**\n * Remove a refinement set on facet. If a value is provided, it will clear the\n * refinement for the given value, otherwise it will clear all the refinement\n * values for the faceted attribute.\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {string} [value] value used to filter\n * @return {SearchParameters}\n */\n removeFacetRefinement: function removeFacetRefinement(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the facets attribute of the helper configuration');\n }\n\n if (!RefinementList.isRefined(this.facetsRefinements, facet, value)) return this;\n return this.setQueryParameters({\n facetsRefinements: RefinementList.removeRefinement(this.facetsRefinements, facet, value)\n });\n },\n\n /**\n * Remove a negative refinement on a facet\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {string} value value used to filter\n * @return {SearchParameters}\n */\n removeExcludeRefinement: function removeExcludeRefinement(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the facets attribute of the helper configuration');\n }\n\n if (!RefinementList.isRefined(this.facetsExcludes, facet, value)) return this;\n return this.setQueryParameters({\n facetsExcludes: RefinementList.removeRefinement(this.facetsExcludes, facet, value)\n });\n },\n\n /**\n * Remove a refinement on a disjunctive facet\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {string} value value used to filter\n * @return {SearchParameters}\n */\n removeDisjunctiveFacetRefinement: function removeDisjunctiveFacetRefinement(facet, value) {\n if (!this.isDisjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the disjunctiveFacets attribute of the helper configuration');\n }\n\n if (!RefinementList.isRefined(this.disjunctiveFacetsRefinements, facet, value)) return this;\n return this.setQueryParameters({\n disjunctiveFacetsRefinements: RefinementList.removeRefinement(this.disjunctiveFacetsRefinements, facet, value)\n });\n },\n\n /**\n * Remove a tag from the list of tag refinements\n * @method\n * @param {string} tag the tag to remove\n * @return {SearchParameters}\n */\n removeTagRefinement: function removeTagRefinement(tag) {\n if (!this.isTagRefined(tag)) return this;\n var modification = {\n tagRefinements: this.tagRefinements.filter(function (t) {\n return t !== tag;\n })\n };\n return this.setQueryParameters(modification);\n },\n\n /**\n * Generic toggle refinement method to use with facet, disjunctive facets\n * and hierarchical facets\n * @param {string} facet the facet to refine\n * @param {string} value the associated value\n * @return {SearchParameters}\n * @throws will throw an error if the facet is not declared in the settings of the helper\n * @deprecated since version 2.19.0, see {@link SearchParameters#toggleFacetRefinement}\n */\n toggleRefinement: function toggleRefinement(facet, value) {\n return this.toggleFacetRefinement(facet, value);\n },\n\n /**\n * Generic toggle refinement method to use with facet, disjunctive facets\n * and hierarchical facets\n * @param {string} facet the facet to refine\n * @param {string} value the associated value\n * @return {SearchParameters}\n * @throws will throw an error if the facet is not declared in the settings of the helper\n */\n toggleFacetRefinement: function toggleFacetRefinement(facet, value) {\n if (this.isHierarchicalFacet(facet)) {\n return this.toggleHierarchicalFacetRefinement(facet, value);\n } else if (this.isConjunctiveFacet(facet)) {\n return this.toggleConjunctiveFacetRefinement(facet, value);\n } else if (this.isDisjunctiveFacet(facet)) {\n return this.toggleDisjunctiveFacetRefinement(facet, value);\n }\n\n throw new Error('Cannot refine the undeclared facet ' + facet + '; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets');\n },\n\n /**\n * Switch the refinement applied over a facet/value\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {value} value value used for filtering\n * @return {SearchParameters}\n */\n toggleConjunctiveFacetRefinement: function toggleConjunctiveFacetRefinement(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the facets attribute of the helper configuration');\n }\n\n return this.setQueryParameters({\n facetsRefinements: RefinementList.toggleRefinement(this.facetsRefinements, facet, value)\n });\n },\n\n /**\n * Switch the refinement applied over a facet/value\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {value} value value used for filtering\n * @return {SearchParameters}\n */\n toggleExcludeFacetRefinement: function toggleExcludeFacetRefinement(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the facets attribute of the helper configuration');\n }\n\n return this.setQueryParameters({\n facetsExcludes: RefinementList.toggleRefinement(this.facetsExcludes, facet, value)\n });\n },\n\n /**\n * Switch the refinement applied over a facet/value\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {value} value value used for filtering\n * @return {SearchParameters}\n */\n toggleDisjunctiveFacetRefinement: function toggleDisjunctiveFacetRefinement(facet, value) {\n if (!this.isDisjunctiveFacet(facet)) {\n throw new Error(facet + ' is not defined in the disjunctiveFacets attribute of the helper configuration');\n }\n\n return this.setQueryParameters({\n disjunctiveFacetsRefinements: RefinementList.toggleRefinement(this.disjunctiveFacetsRefinements, facet, value)\n });\n },\n\n /**\n * Switch the refinement applied over a facet/value\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {value} value value used for filtering\n * @return {SearchParameters}\n */\n toggleHierarchicalFacetRefinement: function toggleHierarchicalFacetRefinement(facet, value) {\n if (!this.isHierarchicalFacet(facet)) {\n throw new Error(facet + ' is not defined in the hierarchicalFacets attribute of the helper configuration');\n }\n\n var separator = this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(facet));\n\n var mod = {};\n var upOneOrMultipleLevel = this.hierarchicalFacetsRefinements[facet] !== undefined && this.hierarchicalFacetsRefinements[facet].length > 0 && ( // remove current refinement:\n // refinement was 'beer > IPA', call is toggleRefine('beer > IPA'), refinement should be `beer`\n this.hierarchicalFacetsRefinements[facet][0] === value || // remove a parent refinement of the current refinement:\n // - refinement was 'beer > IPA > Flying dog'\n // - call is toggleRefine('beer > IPA')\n // - refinement should be `beer`\n this.hierarchicalFacetsRefinements[facet][0].indexOf(value + separator) === 0);\n\n if (upOneOrMultipleLevel) {\n if (value.indexOf(separator) === -1) {\n // go back to root level\n mod[facet] = [];\n } else {\n mod[facet] = [value.slice(0, value.lastIndexOf(separator))];\n }\n } else {\n mod[facet] = [value];\n }\n\n return this.setQueryParameters({\n hierarchicalFacetsRefinements: defaultsPure({}, mod, this.hierarchicalFacetsRefinements)\n });\n },\n\n /**\n * Adds a refinement on a hierarchical facet.\n * @param {string} facet the facet name\n * @param {string} path the hierarchical facet path\n * @return {SearchParameter} the new state\n * @throws Error if the facet is not defined or if the facet is refined\n */\n addHierarchicalFacetRefinement: function addHierarchicalFacetRefinement(facet, path) {\n if (this.isHierarchicalFacetRefined(facet)) {\n throw new Error(facet + ' is already refined.');\n }\n\n if (!this.isHierarchicalFacet(facet)) {\n throw new Error(facet + ' is not defined in the hierarchicalFacets attribute of the helper configuration.');\n }\n\n var mod = {};\n mod[facet] = [path];\n return this.setQueryParameters({\n hierarchicalFacetsRefinements: defaultsPure({}, mod, this.hierarchicalFacetsRefinements)\n });\n },\n\n /**\n * Removes the refinement set on a hierarchical facet.\n * @param {string} facet the facet name\n * @return {SearchParameter} the new state\n * @throws Error if the facet is not defined or if the facet is not refined\n */\n removeHierarchicalFacetRefinement: function removeHierarchicalFacetRefinement(facet) {\n if (!this.isHierarchicalFacetRefined(facet)) {\n return this;\n }\n\n var mod = {};\n mod[facet] = [];\n return this.setQueryParameters({\n hierarchicalFacetsRefinements: defaultsPure({}, mod, this.hierarchicalFacetsRefinements)\n });\n },\n\n /**\n * Switch the tag refinement\n * @method\n * @param {string} tag the tag to remove or add\n * @return {SearchParameters}\n */\n toggleTagRefinement: function toggleTagRefinement(tag) {\n if (this.isTagRefined(tag)) {\n return this.removeTagRefinement(tag);\n }\n\n return this.addTagRefinement(tag);\n },\n\n /**\n * Test if the facet name is from one of the disjunctive facets\n * @method\n * @param {string} facet facet name to test\n * @return {boolean}\n */\n isDisjunctiveFacet: function isDisjunctiveFacet(facet) {\n return this.disjunctiveFacets.indexOf(facet) > -1;\n },\n\n /**\n * Test if the facet name is from one of the hierarchical facets\n * @method\n * @param {string} facetName facet name to test\n * @return {boolean}\n */\n isHierarchicalFacet: function isHierarchicalFacet(facetName) {\n return this.getHierarchicalFacetByName(facetName) !== undefined;\n },\n\n /**\n * Test if the facet name is from one of the conjunctive/normal facets\n * @method\n * @param {string} facet facet name to test\n * @return {boolean}\n */\n isConjunctiveFacet: function isConjunctiveFacet(facet) {\n return this.facets.indexOf(facet) > -1;\n },\n\n /**\n * Returns true if the facet is refined, either for a specific value or in\n * general.\n * @method\n * @param {string} facet name of the attribute for used for faceting\n * @param {string} value, optional value. If passed will test that this value\n * is filtering the given facet.\n * @return {boolean} returns true if refined\n */\n isFacetRefined: function isFacetRefined(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n return false;\n }\n\n return RefinementList.isRefined(this.facetsRefinements, facet, value);\n },\n\n /**\n * Returns true if the facet contains exclusions or if a specific value is\n * excluded.\n *\n * @method\n * @param {string} facet name of the attribute for used for faceting\n * @param {string} [value] optional value. If passed will test that this value\n * is filtering the given facet.\n * @return {boolean} returns true if refined\n */\n isExcludeRefined: function isExcludeRefined(facet, value) {\n if (!this.isConjunctiveFacet(facet)) {\n return false;\n }\n\n return RefinementList.isRefined(this.facetsExcludes, facet, value);\n },\n\n /**\n * Returns true if the facet contains a refinement, or if a value passed is a\n * refinement for the facet.\n * @method\n * @param {string} facet name of the attribute for used for faceting\n * @param {string} value optional, will test if the value is used for refinement\n * if there is one, otherwise will test if the facet contains any refinement\n * @return {boolean}\n */\n isDisjunctiveFacetRefined: function isDisjunctiveFacetRefined(facet, value) {\n if (!this.isDisjunctiveFacet(facet)) {\n return false;\n }\n\n return RefinementList.isRefined(this.disjunctiveFacetsRefinements, facet, value);\n },\n\n /**\n * Returns true if the facet contains a refinement, or if a value passed is a\n * refinement for the facet.\n * @method\n * @param {string} facet name of the attribute for used for faceting\n * @param {string} value optional, will test if the value is used for refinement\n * if there is one, otherwise will test if the facet contains any refinement\n * @return {boolean}\n */\n isHierarchicalFacetRefined: function isHierarchicalFacetRefined(facet, value) {\n if (!this.isHierarchicalFacet(facet)) {\n return false;\n }\n\n var refinements = this.getHierarchicalRefinement(facet);\n\n if (!value) {\n return refinements.length > 0;\n }\n\n return refinements.indexOf(value) !== -1;\n },\n\n /**\n * Test if the triple (attribute, operator, value) is already refined.\n * If only the attribute and the operator are provided, it tests if the\n * contains any refinement value.\n * @method\n * @param {string} attribute attribute for which the refinement is applied\n * @param {string} [operator] operator of the refinement\n * @param {string} [value] value of the refinement\n * @return {boolean} true if it is refined\n */\n isNumericRefined: function isNumericRefined(attribute, operator, value) {\n if (value === undefined && operator === undefined) {\n return !!this.numericRefinements[attribute];\n }\n\n var isOperatorDefined = this.numericRefinements[attribute] && this.numericRefinements[attribute][operator] !== undefined;\n\n if (value === undefined || !isOperatorDefined) {\n return isOperatorDefined;\n }\n\n var parsedValue = valToNumber(value);\n var isAttributeValueDefined = findArray(this.numericRefinements[attribute][operator], parsedValue) !== undefined;\n return isOperatorDefined && isAttributeValueDefined;\n },\n\n /**\n * Returns true if the tag refined, false otherwise\n * @method\n * @param {string} tag the tag to check\n * @return {boolean}\n */\n isTagRefined: function isTagRefined(tag) {\n return this.tagRefinements.indexOf(tag) !== -1;\n },\n\n /**\n * Returns the list of all disjunctive facets refined\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {value} value value used for filtering\n * @return {string[]}\n */\n getRefinedDisjunctiveFacets: function getRefinedDisjunctiveFacets() {\n var self = this; // attributes used for numeric filter can also be disjunctive\n\n var disjunctiveNumericRefinedFacets = intersection(Object.keys(this.numericRefinements).filter(function (facet) {\n return Object.keys(self.numericRefinements[facet]).length > 0;\n }), this.disjunctiveFacets);\n return Object.keys(this.disjunctiveFacetsRefinements).filter(function (facet) {\n return self.disjunctiveFacetsRefinements[facet].length > 0;\n }).concat(disjunctiveNumericRefinedFacets).concat(this.getRefinedHierarchicalFacets());\n },\n\n /**\n * Returns the list of all disjunctive facets refined\n * @method\n * @param {string} facet name of the attribute used for faceting\n * @param {value} value value used for filtering\n * @return {string[]}\n */\n getRefinedHierarchicalFacets: function getRefinedHierarchicalFacets() {\n var self = this;\n return intersection( // enforce the order between the two arrays,\n // so that refinement name index === hierarchical facet index\n this.hierarchicalFacets.map(function (facet) {\n return facet.name;\n }), Object.keys(this.hierarchicalFacetsRefinements).filter(function (facet) {\n return self.hierarchicalFacetsRefinements[facet].length > 0;\n }));\n },\n\n /**\n * Returned the list of all disjunctive facets not refined\n * @method\n * @return {string[]}\n */\n getUnrefinedDisjunctiveFacets: function getUnrefinedDisjunctiveFacets() {\n var refinedFacets = this.getRefinedDisjunctiveFacets();\n return this.disjunctiveFacets.filter(function (f) {\n return refinedFacets.indexOf(f) === -1;\n });\n },\n managedParameters: ['index', 'facets', 'disjunctiveFacets', 'facetsRefinements', 'hierarchicalFacets', 'facetsExcludes', 'disjunctiveFacetsRefinements', 'numericRefinements', 'tagRefinements', 'hierarchicalFacetsRefinements'],\n getQueryParams: function getQueryParams() {\n var managedParameters = this.managedParameters;\n var queryParams = {};\n var self = this;\n Object.keys(this).forEach(function (paramName) {\n var paramValue = self[paramName];\n\n if (managedParameters.indexOf(paramName) === -1 && paramValue !== undefined) {\n queryParams[paramName] = paramValue;\n }\n });\n return queryParams;\n },\n\n /**\n * Let the user set a specific value for a given parameter. Will return the\n * same instance if the parameter is invalid or if the value is the same as the\n * previous one.\n * @method\n * @param {string} parameter the parameter name\n * @param {any} value the value to be set, must be compliant with the definition\n * of the attribute on the object\n * @return {SearchParameters} the updated state\n */\n setQueryParameter: function setParameter(parameter, value) {\n if (this[parameter] === value) return this;\n var modification = {};\n modification[parameter] = value;\n return this.setQueryParameters(modification);\n },\n\n /**\n * Let the user set any of the parameters with a plain object.\n * @method\n * @param {object} params all the keys and the values to be updated\n * @return {SearchParameters} a new updated instance\n */\n setQueryParameters: function setQueryParameters(params) {\n if (!params) return this;\n var error = SearchParameters.validate(this, params);\n\n if (error) {\n throw error;\n }\n\n var self = this;\n\n var nextWithNumbers = SearchParameters._parseNumbers(params);\n\n var previousPlainObject = Object.keys(this).reduce(function (acc, key) {\n acc[key] = self[key];\n return acc;\n }, {});\n var nextPlainObject = Object.keys(nextWithNumbers).reduce(function (previous, key) {\n var isPreviousValueDefined = previous[key] !== undefined;\n var isNextValueDefined = nextWithNumbers[key] !== undefined;\n\n if (isPreviousValueDefined && !isNextValueDefined) {\n return omit(previous, [key]);\n }\n\n if (isNextValueDefined) {\n previous[key] = nextWithNumbers[key];\n }\n\n return previous;\n }, previousPlainObject);\n return new this.constructor(nextPlainObject);\n },\n\n /**\n * Returns a new instance with the page reset. Two scenarios possible:\n * the page is omitted -> return the given instance\n * the page is set -> return a new instance with a page of 0\n * @return {SearchParameters} a new updated instance\n */\n resetPage: function resetPage() {\n if (this.page === undefined) {\n return this;\n }\n\n return this.setPage(0);\n },\n\n /**\n * Helper function to get the hierarchicalFacet separator or the default one (`>`)\n * @param {object} hierarchicalFacet\n * @return {string} returns the hierarchicalFacet.separator or `>` as default\n */\n _getHierarchicalFacetSortBy: function _getHierarchicalFacetSortBy(hierarchicalFacet) {\n return hierarchicalFacet.sortBy || ['isRefined:desc', 'name:asc'];\n },\n\n /**\n * Helper function to get the hierarchicalFacet separator or the default one (`>`)\n * @private\n * @param {object} hierarchicalFacet\n * @return {string} returns the hierarchicalFacet.separator or `>` as default\n */\n _getHierarchicalFacetSeparator: function _getHierarchicalFacetSeparator(hierarchicalFacet) {\n return hierarchicalFacet.separator || ' > ';\n },\n\n /**\n * Helper function to get the hierarchicalFacet prefix path or null\n * @private\n * @param {object} hierarchicalFacet\n * @return {string} returns the hierarchicalFacet.rootPath or null as default\n */\n _getHierarchicalRootPath: function _getHierarchicalRootPath(hierarchicalFacet) {\n return hierarchicalFacet.rootPath || null;\n },\n\n /**\n * Helper function to check if we show the parent level of the hierarchicalFacet\n * @private\n * @param {object} hierarchicalFacet\n * @return {string} returns the hierarchicalFacet.showParentLevel or true as default\n */\n _getHierarchicalShowParentLevel: function _getHierarchicalShowParentLevel(hierarchicalFacet) {\n if (typeof hierarchicalFacet.showParentLevel === 'boolean') {\n return hierarchicalFacet.showParentLevel;\n }\n\n return true;\n },\n\n /**\n * Helper function to get the hierarchicalFacet by it's name\n * @param {string} hierarchicalFacetName\n * @return {object} a hierarchicalFacet\n */\n getHierarchicalFacetByName: function getHierarchicalFacetByName(hierarchicalFacetName) {\n return find(this.hierarchicalFacets, function (f) {\n return f.name === hierarchicalFacetName;\n });\n },\n\n /**\n * Get the current breadcrumb for a hierarchical facet, as an array\n * @param {string} facetName Hierarchical facet name\n * @return {array.} the path as an array of string\n */\n getHierarchicalFacetBreadcrumb: function getHierarchicalFacetBreadcrumb(facetName) {\n if (!this.isHierarchicalFacet(facetName)) {\n return [];\n }\n\n var refinement = this.getHierarchicalRefinement(facetName)[0];\n if (!refinement) return [];\n\n var separator = this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(facetName));\n\n var path = refinement.split(separator);\n return path.map(function (part) {\n return part.trim();\n });\n },\n toString: function toString() {\n return JSON.stringify(this, null, 2);\n }\n};\n/**\n * Callback used for clearRefinement method\n * @callback SearchParameters.clearCallback\n * @param {OperatorList|FacetList} value the value of the filter\n * @param {string} key the current attribute name\n * @param {string} type `numeric`, `disjunctiveFacet`, `conjunctiveFacet`, `hierarchicalFacet` or `exclude`\n * depending on the type of facet\n * @return {boolean} `true` if the element should be removed. `false` otherwise.\n */\n\nmodule.exports = SearchParameters;","'use strict';\n\nfunction intersection(arr1, arr2) {\n return arr1.filter(function (value, index) {\n return arr2.indexOf(value) > -1 && arr1.indexOf(value) === index\n /* skips duplicates */\n ;\n });\n}\n\nmodule.exports = intersection;","export default function _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n _typeof = function _typeof(obj) {\n return typeof obj;\n };\n } else {\n _typeof = function _typeof(obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n };\n }\n\n return _typeof(obj);\n}","import _defineProperty from \"@babel/runtime/helpers/esm/defineProperty\";\n\nfunction ownKeys(object, enumerableOnly) {\n var keys = Object.keys(object);\n\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(object);\n\n if (enumerableOnly) {\n symbols = symbols.filter(function (sym) {\n return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n });\n }\n\n keys.push.apply(keys, symbols);\n }\n\n return keys;\n}\n\nfunction _objectSpread(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i] != null ? arguments[i] : {};\n\n if (i % 2) {\n ownKeys(Object(source), true).forEach(function (key) {\n _defineProperty(target, key, source[key]);\n });\n } else if (Object.getOwnPropertyDescriptors) {\n Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));\n } else {\n ownKeys(Object(source)).forEach(function (key) {\n Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n });\n }\n }\n\n return target;\n}\n\nimport { omit } from './utils';\nexport function getIndexId(context) {\n return hasMultipleIndices(context) ? context.multiIndexContext.targetedIndex : context.ais.mainTargetedIndex;\n}\n/**\n * @returns {import('algoliasearch-helper').SearchResults} results\n */\n\nexport function getResults(searchResults, context) {\n if (searchResults.results) {\n if (searchResults.results.hits) {\n return searchResults.results;\n }\n\n var indexId = getIndexId(context);\n\n if (searchResults.results[indexId]) {\n return searchResults.results[indexId];\n }\n }\n\n return null;\n}\nexport function hasMultipleIndices(context) {\n return context && context.multiIndexContext;\n}\nexport function refineValue(searchState, nextRefinement, context, resetPage, namespace) {\n if (hasMultipleIndices(context)) {\n var indexId = getIndexId(context);\n return namespace ? refineMultiIndexWithNamespace(searchState, nextRefinement, indexId, resetPage, namespace) : refineMultiIndex(searchState, nextRefinement, indexId, resetPage);\n } else {\n // When we have a multi index page with shared widgets we should also\n // reset their page to 1 if the resetPage is provided. Otherwise the\n // indices will always be reset\n // see: https://github.com/algolia/react-instantsearch/issues/310\n // see: https://github.com/algolia/react-instantsearch/issues/637\n if (searchState.indices && resetPage) {\n Object.keys(searchState.indices).forEach(function (targetedIndex) {\n searchState = refineValue(searchState, {\n page: 1\n }, {\n multiIndexContext: {\n targetedIndex: targetedIndex\n }\n }, true, namespace);\n });\n }\n\n return namespace ? refineSingleIndexWithNamespace(searchState, nextRefinement, resetPage, namespace) : refineSingleIndex(searchState, nextRefinement, resetPage);\n }\n}\n\nfunction refineMultiIndex(searchState, nextRefinement, indexId, resetPage) {\n var page = resetPage ? {\n page: 1\n } : undefined;\n var state = searchState.indices && searchState.indices[indexId] ? _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread(_objectSpread({}, searchState.indices[indexId]), nextRefinement), page))) : _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread({}, nextRefinement), page)));\n return _objectSpread(_objectSpread({}, searchState), {}, {\n indices: state\n });\n}\n\nfunction refineSingleIndex(searchState, nextRefinement, resetPage) {\n var page = resetPage ? {\n page: 1\n } : undefined;\n return _objectSpread(_objectSpread(_objectSpread({}, searchState), nextRefinement), page);\n}\n\nfunction refineMultiIndexWithNamespace(searchState, nextRefinement, indexId, resetPage, namespace) {\n var _objectSpread4;\n\n var page = resetPage ? {\n page: 1\n } : undefined;\n var state = searchState.indices && searchState.indices[indexId] ? _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread({}, searchState.indices[indexId]), {}, (_objectSpread4 = {}, _defineProperty(_objectSpread4, namespace, _objectSpread(_objectSpread({}, searchState.indices[indexId][namespace]), nextRefinement)), _defineProperty(_objectSpread4, \"page\", 1), _objectSpread4)))) : _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_defineProperty({}, namespace, nextRefinement), page)));\n return _objectSpread(_objectSpread({}, searchState), {}, {\n indices: state\n });\n}\n\nfunction refineSingleIndexWithNamespace(searchState, nextRefinement, resetPage, namespace) {\n var page = resetPage ? {\n page: 1\n } : undefined;\n return _objectSpread(_objectSpread({}, searchState), {}, _defineProperty({}, namespace, _objectSpread(_objectSpread({}, searchState[namespace]), nextRefinement)), page);\n}\n\nfunction getNamespaceAndAttributeName(id) {\n var parts = id.match(/^([^.]*)\\.(.*)/);\n var namespace = parts && parts[1];\n var attributeName = parts && parts[2];\n return {\n namespace: namespace,\n attributeName: attributeName\n };\n}\n\nfunction hasRefinements(_ref) {\n var multiIndex = _ref.multiIndex,\n indexId = _ref.indexId,\n namespace = _ref.namespace,\n attributeName = _ref.attributeName,\n id = _ref.id,\n searchState = _ref.searchState;\n\n if (multiIndex && namespace) {\n return searchState.indices && searchState.indices[indexId] && searchState.indices[indexId][namespace] && Object.hasOwnProperty.call(searchState.indices[indexId][namespace], attributeName);\n }\n\n if (multiIndex) {\n return searchState.indices && searchState.indices[indexId] && Object.hasOwnProperty.call(searchState.indices[indexId], id);\n }\n\n if (namespace) {\n return searchState[namespace] && Object.hasOwnProperty.call(searchState[namespace], attributeName);\n }\n\n return Object.hasOwnProperty.call(searchState, id);\n}\n\nfunction getRefinements(_ref2) {\n var multiIndex = _ref2.multiIndex,\n indexId = _ref2.indexId,\n namespace = _ref2.namespace,\n attributeName = _ref2.attributeName,\n id = _ref2.id,\n searchState = _ref2.searchState;\n\n if (multiIndex && namespace) {\n return searchState.indices[indexId][namespace][attributeName];\n }\n\n if (multiIndex) {\n return searchState.indices[indexId][id];\n }\n\n if (namespace) {\n return searchState[namespace][attributeName];\n }\n\n return searchState[id];\n}\n\nexport function getCurrentRefinementValue(props, searchState, context, id, defaultValue) {\n var indexId = getIndexId(context);\n\n var _getNamespaceAndAttri = getNamespaceAndAttributeName(id),\n namespace = _getNamespaceAndAttri.namespace,\n attributeName = _getNamespaceAndAttri.attributeName;\n\n var multiIndex = hasMultipleIndices(context);\n var args = {\n multiIndex: multiIndex,\n indexId: indexId,\n namespace: namespace,\n attributeName: attributeName,\n id: id,\n searchState: searchState\n };\n var hasRefinementsValue = hasRefinements(args);\n\n if (hasRefinementsValue) {\n return getRefinements(args);\n }\n\n if (props.defaultRefinement) {\n return props.defaultRefinement;\n }\n\n return defaultValue;\n}\nexport function cleanUpValue(searchState, context, id) {\n var indexId = getIndexId(context);\n\n var _getNamespaceAndAttri2 = getNamespaceAndAttributeName(id),\n namespace = _getNamespaceAndAttri2.namespace,\n attributeName = _getNamespaceAndAttri2.attributeName;\n\n if (hasMultipleIndices(context) && Boolean(searchState.indices)) {\n return cleanUpValueWithMultiIndex({\n attribute: attributeName,\n searchState: searchState,\n indexId: indexId,\n id: id,\n namespace: namespace\n });\n }\n\n return cleanUpValueWithSingleIndex({\n attribute: attributeName,\n searchState: searchState,\n id: id,\n namespace: namespace\n });\n}\n\nfunction cleanUpValueWithSingleIndex(_ref3) {\n var searchState = _ref3.searchState,\n id = _ref3.id,\n namespace = _ref3.namespace,\n attribute = _ref3.attribute;\n\n if (namespace) {\n return _objectSpread(_objectSpread({}, searchState), {}, _defineProperty({}, namespace, omit(searchState[namespace], [attribute])));\n }\n\n return omit(searchState, [id]);\n}\n\nfunction cleanUpValueWithMultiIndex(_ref4) {\n var searchState = _ref4.searchState,\n indexId = _ref4.indexId,\n id = _ref4.id,\n namespace = _ref4.namespace,\n attribute = _ref4.attribute;\n var indexSearchState = searchState.indices[indexId];\n\n if (namespace && indexSearchState) {\n return _objectSpread(_objectSpread({}, searchState), {}, {\n indices: _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread({}, indexSearchState), {}, _defineProperty({}, namespace, omit(indexSearchState[namespace], [attribute])))))\n });\n }\n\n if (indexSearchState) {\n return _objectSpread(_objectSpread({}, searchState), {}, {\n indices: _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, omit(indexSearchState, [id])))\n });\n }\n\n return searchState;\n}","import createConnector from '../core/createConnector';\nimport { getResults } from '../core/indexUtils';\nimport { addAbsolutePositions, addQueryID } from '../core/utils';\n/**\n * connectHits connector provides the logic to create connected\n * components that will render the results retrieved from\n * Algolia.\n *\n * To configure the number of hits retrieved, use [HitsPerPage widget](widgets/HitsPerPage.html),\n * [connectHitsPerPage connector](connectors/connectHitsPerPage.html) or pass the hitsPerPage\n * prop to a [Configure](guide/Search_parameters.html) widget.\n *\n * **Warning:** you will need to use the **objectID** property available on every hit as a key\n * when iterating over them. This will ensure you have the best possible UI experience\n * especially on slow networks.\n * @name connectHits\n * @kind connector\n * @providedPropType {array.