<commit_before>/**
 * @copyright   2016, <NAME>
 * @license     https://opensource.org/licenses/MIT
 * @flow
 */

/* eslint-disable no-cond-assign, no-undef */

import React from 'react';
import Matcher from './Matcher';
import Filter from './Filter';
import ElementComponent from './components/Element';
import {
  PARSER_DENY,
  PARSER_PASS_THROUGH,
  FILTER_DENY,
  FILTER_CAST_NUMBER,
  FILTER_CAST_BOOL,
  TAGS,
  TAGS_BLACKLIST,
  ATTRIBUTES,
  ATTRIBUTES_TO_PROPS,
  TYPE_INLINE,
  TYPE_BLOCK,
} from './constants';

import type {
  Attributes,
  PrimitiveType,
  ParsedNodes,
  NodeConfig,
  NodeInterface,
  ElementProps,
} from './types';

const ELEMENT_NODE: number = 1;
const TEXT_NODE: number = 3;

export default class Parser {
  doc: Document;
  content: ParsedNodes;
  props: Object;
  matchers: Matcher<*>[];
  filters: Filter[];
  keyIndex: number;

  constructor(
    markup: string,
    props: Object = {},
    matchers: Matcher<*>[] = [],
    filters: Filter[] = [],
  ) {
    if (!markup) {
      markup = '';
    } else if (typeof markup !== 'string') {
      throw new TypeError('Interweave parser requires a valid string.');
    }

    this.props = props;
    this.matchers = matchers;
    this.filters = filters;
    this.keyIndex = -1;
    this.doc = this.createDocument(markup);
  }

  /**
   * Loop through and apply all registered attribute filters to the
   * provided value.
   */
  applyFilters(attribute: string, value: string): string {
    return this.filters.reduce((newValue, filter) => (
      (filter.attribute === attribute) ? filter.filter(newValue) : newValue
    ), value);
  }

  /**
   * Loop through and apply all registered matchers to the string.
   * If a match is found, create a React element, and build a new array.
   * This array allows React to interpolate and render accordingly.
   */
  applyMatchers(
    string: string,
    parentConfig: NodeConfig,
  ): string | Array<string | React.Element<*>> {
    const elements = [];
    const props = this.props;
    let matchedString = string;
    let parts = {};

    this.matchers.forEach((matcher: Matcher<*>) => {
      const tagName = matcher.asTag().toLowerCase();

      // Skip matchers that have been disabled from props or are not supported
      if (props[matcher.inverseName] || !TAGS[tagName]) {
        return;
      }

      const config = {
        ...TAGS[tagName],
        tagName,
      };

      // Skip matchers in which the child cannot be rendered
      if (config.rule === PARSER_DENY || !this.canRenderChild(parentConfig, config)) {
        return;
      }

      // Continuously trigger the matcher until no matches are found
      while (parts = matcher.match(matchedString)) {
        const { match, ...partProps } = parts;

        // Replace the matched portion with a placeholder
        matchedString = matchedString.replace(match, `#{{${elements.length}}}#`);

        // Create an element through the matchers factory
        this.keyIndex += 1;

        elements.push(matcher.createElement(match, {
          ...props,
          ...(partProps || {}),<commit_msg>Update matchers to handle disableWhitelist.<commit_after>/**
 * @copyright   2016, <NAME>
 * @license     https://opensource.org/licenses/MIT
 * @flow
 */

/* eslint-disable no-cond-assign, no-undef */

import React from 'react';
import Matcher from './Matcher';
import Filter from './Filter';
import ElementComponent from './components/Element';
import {
  PARSER_DENY,
  PARSER_PASS_THROUGH,
  FILTER_DENY,
  FILTER_CAST_NUMBER,
  FILTER_CAST_BOOL,
  TAGS,
  TAGS_BLACKLIST,
  ATTRIBUTES,
  ATTRIBUTES_TO_PROPS,
  TYPE_INLINE,
  TYPE_BLOCK,
} from './constants';

import type {
  Attributes,
  PrimitiveType,
  ParsedNodes,
  NodeConfig,
  NodeInterface,
  ElementProps,
} from './types';

const ELEMENT_NODE: number = 1;
const TEXT_NODE: number = 3;

export default class Parser {
  doc: Document;
  content: ParsedNodes;
  props: Object;
  matchers: Matcher<*>[];
  filters: Filter[];
  keyIndex: number;

  constructor(
    markup: string,
    props: Object = {},
    matchers: Matcher<*>[] = [],
    filters: Filter[] = [],
  ) {
    if (!markup) {
      markup = '';
    } else if (typeof markup !== 'string') {
      throw new TypeError('Interweave parser requires a valid string.');
    }

    this.props = props;
    this.matchers = matchers;
    this.filters = filters;
    this.keyIndex = -1;
    this.doc = this.createDocument(markup);
  }

  /**
   * Loop through and apply all registered attribute filters to the
   * provided value.
   */
  applyFilters(attribute: string, value: string): string {
    return this.filters.reduce((newValue, filter) => (
      (filter.attribute === attribute) ? filter.filter(newValue) : newValue
    ), value);
  }

  /**
   * Loop through and apply all registered matchers to the string.
   * If a match is found, create a React element, and build a new array.
   * This array allows React to interpolate and render accordingly.
   */
  applyMatchers(
    string: string,
    parentConfig: NodeConfig,
  ): string | Array<string | React.Element<*>> {
    const elements = [];
    const props = this.props;
    let matchedString = string;
    let parts = {};

    this.matchers.forEach((matcher: Matcher<*>) => {
      const tagName = matcher.asTag().toLowerCase();
      const config = this.getTagConfig(tagName);

      // Skip matchers that have been disabled from props or are not supported
      if (
        props[matcher.inverseName] ||
        TAGS_BLACKLIST[tagName] ||
        (!props.disableWhitelist && !TAGS[tagName])
      ) {
        return;
      }

      // Skip matchers in which the child cannot be rendered
      if (config.rule === PARSER_DENY || !this.canRenderChild(parentConfig, config)) {
        return;
      }

      // Continuously trigger the matcher until no matches are found
      while (parts = matcher.match(matchedString)) {
        const { match, ...partProps } = parts;

        // Replace the matched portion with a placeholder
        matchedString = matchedString.replace(match, `#{{${elements.length}}}#`);

        // Create an element through the matchers factory
        this.keyIndex += 1;

        elements.push(matcher.createElement(match, {
          ...props,
          ...(partProps || {}),
{'fraction_non_alphanumeric': 0.1241850850691684, 'fraction_numerical': 0.002544124662108443, 'mean_word_length': 2.837705918242831, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 19, 'https://': 2, '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': '7409769', 'n_tokens_mistral': 1936, 'n_tokens_neox': 1875, 'n_words': 533}