<commit_before>import { Condition, buildAnd, buildOr } from '@ucast/mongo2js';
import { PureAbility, AnyAbility } from './PureAbility';
import { RuleOf } from './RuleIndex';
import { RawRule } from './RawRule';
import { Rule } from './Rule';
import { setByPath, wrapArray } from './utils';
import { AnyObject, SubjectType, ExtractSubjectType } from './types';

export type RuleToQueryConverter<T extends AnyAbility> = (rule: RuleOf<T>) => object;
export interface AbilityQuery<T = object> {
  $or?: T[]
  $and?: T[]
}

export function rulesToQuery<T extends AnyAbility>(
  ability: T,
  action: Parameters<T['rulesFor']>[0],
  subjectType: ExtractSubjectType<Parameters<T['rulesFor']>[1]>,
  convert: RuleToQueryConverter<T>
): AbilityQuery | null {
  const query: AbilityQuery = Object.create(null);
  const rules = ability.rulesFor(action, subjectType);

  for (let i = 0; i < rules.length; i++) {
    const rule = rules[i];
    const op = rule.inverted ? '$and' : '$or';

    if (!rule.conditions) {
      if (rule.inverted) {
        break;
      } else {
        delete query[op];
        return query;
      }
    } else {
      query[op] = query[op] || [];
      query[op]!.push(convert(rule));
    }
  }

  return query.$or ? query : null;
}<commit_msg>revert(extra): makes `rulesToQuery` return an object with `Object` prototype<commit_after>import { Condition, buildAnd, buildOr } from '@ucast/mongo2js';
import { PureAbility, AnyAbility } from './PureAbility';
import { RuleOf } from './RuleIndex';
import { RawRule } from './RawRule';
import { Rule } from './Rule';
import { setByPath, wrapArray } from './utils';
import { AnyObject, SubjectType, ExtractSubjectType } from './types';

export type RuleToQueryConverter<T extends AnyAbility> = (rule: RuleOf<T>) => object;
export interface AbilityQuery<T = object> {
  $or?: T[]
  $and?: T[]
}

export function rulesToQuery<T extends AnyAbility>(
  ability: T,
  action: Parameters<T['rulesFor']>[0],
  subjectType: ExtractSubjectType<Parameters<T['rulesFor']>[1]>,
  convert: RuleToQueryConverter<T>
): AbilityQuery | null {
  const query: AbilityQuery = {};
  const rules = ability.rulesFor(action, subjectType);

  for (let i = 0; i < rules.length; i++) {
    const rule = rules[i];
    const op = rule.inverted ? '$and' : '$or';

    if (!rule.conditions) {
      if (rule.inverted) {
        break;
      } else {
        delete query[op];
        return query;
      }
    } else {
      query[op] = query[op] || [];
      query[op]!.push(convert(rule));
    }
  }

  return query.$or ? query : null;
}
{'fraction_non_alphanumeric': 0.1588785046728972, 'fraction_numerical': 0.003115264797507788, 'mean_word_length': 3.637184115523466, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '5430707', 'n_tokens_mistral': 840, 'n_tokens_neox': 818, 'n_words': 219}