<commit_before>import noop from 'lodash/noop';
import isEqual from 'lodash/isEqual';
import {
  Renderer,
  RenderOptions,
  WidgetFactory,
  Helper,
  HelperState,
} from '../../types';
import {
  checkRendering,
  createDocumentationMessageGenerator,
  warning,
  getRefinements,
} from '../../lib/utils';
import {
  Refinement as InternalRefinement,
  NumericRefinement as InternalNumericRefinement,
} from '../../lib/utils/getRefinements';

export type ParamTrackedFilters = {
  [facetName: string]: (
    facetValues: Array<string | number>
  ) => Array<string | number>;
};
export type ParamTransformRuleContexts = (ruleContexts: string[]) => string[];
type ParamTransformItems = (items: object[]) => any;

export type QueryRulesConnectorParams = {
  trackedFilters?: ParamTrackedFilters;
  transformRuleContexts?: ParamTransformRuleContexts;
  transformItems?: ParamTransformItems;
};

export interface QueryRulesRenderOptions<T> extends RenderOptions<T> {
  items: object[];
}

export type QueryRulesRenderer<T> = Renderer<
  QueryRulesRenderOptions<QueryRulesConnectorParams & T>
>;

export type QueryRulesWidgetFactory<T> = WidgetFactory<
  QueryRulesConnectorParams & T
>;

export type QueryRulesConnector = <T>(
  render: QueryRulesRenderer<T>,
  unmount?: () => void
) => QueryRulesWidgetFactory<T>;

const withUsage = createDocumentationMessageGenerator({
  name: 'query-rules',
  connector: true,
});

function hasStateRefinements({
  disjunctiveFacetsRefinements,
  facetsRefinements,
  hierarchicalFacetsRefinements,
  numericRefinements,
}) {
  return [
    disjunctiveFacetsRefinements,
    facetsRefinements,
    hierarchicalFacetsRefinements,
    numericRefinements,
  ].some(refinement => Object.keys(refinement).length > 0);
}

// A context rule must consist only of alphanumeric characters, hyphens, and underscores.
// See https://www.algolia.com/doc/guides/managing-results/refine-results/merchandising-and-promoting/in-depth/implementing-query-rules/#context
function escapeRuleContext(ruleName: string) {
  return ruleName.replace(/[^a-z0-9-_]+/gi, '_');
}

function getRuleContextsFromTrackedFilters({
  helper,
  sharedHelperState,
  trackedFilters,
}: {
  helper: Helper;
  sharedHelperState: HelperState;
  trackedFilters: ParamTrackedFilters;
}) {
  const ruleContexts = Object.keys(trackedFilters).reduce<string[]>(
    (facets, facetName) => {
      const facetRefinements: Array<string | number> = getRefinements(
        helper.lastResults || {},
        sharedHelperState
      )
        .filter(
          (refinement: InternalRefinement) =>
            refinement.attributeName === facetName<commit_msg>fix(connectQueryRules): improve tracked refinement type (#3648)<commit_after>import noop from 'lodash/noop';
import isEqual from 'lodash/isEqual';
import {
  Renderer,
  RenderOptions,
  WidgetFactory,
  Helper,
  HelperState,
} from '../../types';
import {
  checkRendering,
  createDocumentationMessageGenerator,
  warning,
  getRefinements,
} from '../../lib/utils';
import {
  Refinement as InternalRefinement,
  NumericRefinement as InternalNumericRefinement,
} from '../../lib/utils/getRefinements';

type TrackedFilterRefinement = string | number | boolean;

export type ParamTrackedFilters = {
  [facetName: string]: (
    facetValues: TrackedFilterRefinement[]
  ) => TrackedFilterRefinement[];
};
export type ParamTransformRuleContexts = (ruleContexts: string[]) => string[];
type ParamTransformItems = (items: object[]) => any;

export type QueryRulesConnectorParams = {
  trackedFilters?: ParamTrackedFilters;
  transformRuleContexts?: ParamTransformRuleContexts;
  transformItems?: ParamTransformItems;
};

export interface QueryRulesRenderOptions<T> extends RenderOptions<T> {
  items: object[];
}

export type QueryRulesRenderer<T> = Renderer<
  QueryRulesRenderOptions<QueryRulesConnectorParams & T>
>;

export type QueryRulesWidgetFactory<T> = WidgetFactory<
  QueryRulesConnectorParams & T
>;

export type QueryRulesConnector = <T>(
  render: QueryRulesRenderer<T>,
  unmount?: () => void
) => QueryRulesWidgetFactory<T>;

const withUsage = createDocumentationMessageGenerator({
  name: 'query-rules',
  connector: true,
});

function hasStateRefinements({
  disjunctiveFacetsRefinements,
  facetsRefinements,
  hierarchicalFacetsRefinements,
  numericRefinements,
}) {
  return [
    disjunctiveFacetsRefinements,
    facetsRefinements,
    hierarchicalFacetsRefinements,
    numericRefinements,
  ].some(refinement => Object.keys(refinement).length > 0);
}

// A context rule must consist only of alphanumeric characters, hyphens, and underscores.
// See https://www.algolia.com/doc/guides/managing-results/refine-results/merchandising-and-promoting/in-depth/implementing-query-rules/#context
function escapeRuleContext(ruleName: string) {
  return ruleName.replace(/[^a-z0-9-_]+/gi, '_');
}

function getRuleContextsFromTrackedFilters({
  helper,
  sharedHelperState,
  trackedFilters,
}: {
  helper: Helper;
  sharedHelperState: HelperState;
  trackedFilters: ParamTrackedFilters;
}) {
  const ruleContexts = Object.keys(trackedFilters).reduce<string[]>(
    (facets, facetName) => {
      const facetRefinements: TrackedFilterRefinement[] = getRefinements(
        helper.lastResults || {},
        sharedHelperState
      )
        .filter(
          (refinement: InternalRefinement) =>
            refinement.attributeName === facetName
{'fraction_non_alphanumeric': 0.11343449296817172, 'fraction_numerical': 0.001850481125092524, 'mean_word_length': 4.9988901220865705, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 46, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4931839', 'n_tokens_mistral': 1628, 'n_tokens_neox': 1650, 'n_words': 322}