<commit_before>import {h, Component} from 'preact'

const standardRenderers = {
    root: 'span',
    code: 'code',
    link: ({href, children}) => <a href={href} title={href} target="_blank">{children}</a>,
    strong: 'strong',
    em: 'em'
}

const markdownRules = [
    {name: 'code', regex: /^`([^`]*)`/},
    {name: 'link', regex: /^!?\[([^\]]*)\]\((((ht|f)tps?:|mailto:)[^)]*)\)/},
    {name: 'url', regex: /^((ht|f)tps?:\/\/[^\s<]+[^<.,:;"\')\]\s](\/\B|\b))/},
    {name: 'email', regex: /^([^\s@<]+@[^\s@<]+)\b/},
    {name: 'strong', regex: /^\*\*(\*?[^\*]([^\*](\*(?!\*))?)*\*?)\*\*/},
    {name: 'strong', regex: /^__(_?[^_]([^_](_(?!_))?)*_?)__/},
    {name: 'em', regex: /^\*(([^\*]|\*\*)+)\*/},
    {name: 'em', regex: /^_(([^_]|__)+)_/}
]

function inlineMarkdown2jsx(source, renderers) {
    let render = source => inlineMarkdown2jsx(source, renderers)
    let result = []

    while (source.length > 0) {
        let rule = null
        let match = null
        let quality = -Infinity

        for (let {name, regex} of markdownRules) {
            let ruleMatch = source.match(regex)

            if (ruleMatch != null && quality < ruleMatch[0].length) {
                rule = {name, regex}
                match = ruleMatch
                quality = ruleMatch[0].length
            }
        }

        if (match != null) {
            if (rule.name === 'code') {
                result.push(h(renderers.code, {}, match[1]))
            } else if (rule.name === 'link') {
                result.push(h(renderers.link, {href: match[2]}, render(match[1])))
            } else if (rule.name === 'url') {
                result.push(h(renderers.link, {href: match[1]}, match[1]))
            } else if (rule.name === 'email') {
                result.push(h(renderers.link, {href: `mailto:${match[1]}`}, match[1]))
            } else if (rule.name === 'strong' || rule.name === 'em') {
                result.push(h(renderers[rule.name], {}, render(match[1])))
            }

            source = source.slice(match[0].length)
        } else {
            let lastToken = result[result.length - 1]
            if (typeof lastToken !== 'string') result.push('')

            let match = source.match(/^[^`!\[\*_\w]+|\w+|./)
            result[result.length - 1] += source.slice(0, match[0].length)
 
            source = source.slice(match[0].length)
        }
    }

    return result
}

export default class InlineMarkdown extends Component {
    shouldComponentUpdate({source, renderers}) {
        return source !== this.props.source
            || renderers !== this.props.renderers 
            && Object.keys(standardRenderers).some(key => renderers[key] !== this.props.renderers[key])
    }

    render() {
        let {source = '', renderers = {}} = this.props

        return h(renderers.root, {}, inlineMarkdown2jsx(source, {...renderers, ...standardRenderers}))
    }
}<commit_msg>Don't allow same tag inside tag<commit_after>import {h, Component} from 'preact'

const standardRenderers = {
    root: 'span',
    code: 'code',
    link: ({href, children}) => <a href={href} title={href} target="_blank">{children}</a>,
    strong: 'strong',
    em: 'em'
}

const markdownRules = [
    {name: 'code', regex: /^`([^`]*)`/},
    {name: 'link', regex: /^!?\[([^\]]*)\]\((((ht|f)tps?:|mailto:)[^)]*)\)/},
    {name: 'url', regex: /^((ht|f)tps?:\/\/[^\s<]+[^<.,:;"\')\]\s](\/\B|\b))/},
    {name: 'email', regex: /^([^\s@<]+@[^\s@<]+)\b/},
    {name: 'strong', regex: /^\*\*(\*?[^\*]([^\*](\*(?!\*))?)*\*?)\*\*/},
    {name: 'strong', regex: /^__(_?[^_]([^_](_(?!_))?)*_?)__/},
    {name: 'em', regex: /^\*(([^\*]|\*\*)+)\*/},
    {name: 'em', regex: /^_(([^_]|__)+)_/}
]

function inlineMarkdown2jsx(source, renderers, ignore = []) {
    let render = (source, ignoreMore) => inlineMarkdown2jsx(source, renderers, [...ignore, ...ignoreMore])
    let result = []

    while (source.length > 0) {
        let rule = null
        let match = null
        let quality = -Infinity

        for (let {name, regex} of markdownRules) {
            if (ignore.includes(name)) continue
            let ruleMatch = source.match(regex)

            if (ruleMatch != null && quality < ruleMatch[0].length) {
                rule = {name, regex}
                match = ruleMatch
                quality = ruleMatch[0].length
            }
        }

        if (match != null) {
            if (rule.name === 'code') {
                result.push(h(renderers.code, {}, match[1]))
            } else if (rule.name === 'link') {
                result.push(h(renderers.link, {href: match[2]}, render(match[1], ['url', 'email'])))
            } else if (rule.name === 'url') {
                result.push(h(renderers.link, {href: match[1]}, match[1]))
            } else if (rule.name === 'email') {
                result.push(h(renderers.link, {href: `mailto:${match[1]}`}, match[1]))
            } else if (rule.name === 'strong' || rule.name === 'em') {
                result.push(h(renderers[rule.name], {}, render(match[1], [rule.name])))
            }

            source = source.slice(match[0].length)
        } else {
            let lastToken = result[result.length - 1]
            if (typeof lastToken !== 'string') result.push('')

            let match = source.match(/^[^`!\[\*_\w]+|\w+|./)
            result[result.length - 1] += source.slice(0, match[0].length)

            source = source.slice(match[0].length)
        }
    }

    return result
}

export default class InlineMarkdown extends Component {
    shouldComponentUpdate({source, renderers}) {
        return source !== this.props.source
            || renderers !== this.props.renderers
            && Object.keys(standardRenderers).some(key => renderers[key] !== this.props.renderers[key])
    }

    render() {
        let {source = '', renderers = {}} = this.props

        return h(renderers.root, {}, inlineMarkdown2jsx(source, {...renderers, ...standardRenderers}))
    }
}
{'fraction_non_alphanumeric': 0.23132328308207706, 'fraction_numerical': 0.006700167504187605, 'mean_word_length': 2.252178649237473, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, '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': '3082106', 'n_tokens_mistral': 2050, 'n_tokens_neox': 1988, 'n_words': 381}