<commit_before>import escapeStringRegexp from 'escape-string-regexp'
import traverse from 'babel-traverse'

const traverseTemplateExpressions = {
  TaggedTemplateExpression: (path, { source, templates, groupName, templatePatterns }) => {
    const node = path.node
    if (node.scanned) return
    node.scanned = true
    if (node.tag.name === 'i18n' || (node.tag.callee && (node.tag.callee.name === 'i18n' || (node.tag.callee.property && node.tag.callee.property.name === 'i18n'))) || (node.tag.property && node.tag.property.name === 'i18n')) {
      if (node.tag.arguments && node.tag.arguments.length) {
        groupName = node.tag.arguments[0].value || node.tag.arguments[0].name
      }
      let match = source.substring(node.quasi.start + 1, node.quasi.end - 1)
      let count = 0
      node.quasi.expressions.forEach((exp) => {
        const expression = source.substring(exp.start, exp.end)
        const expExpression = escapeStringRegexp(expression).replace(/\r/gm, '\\r').replace(/\n/gm, '\\n').replace(/\t/gm, '\\t').replace(/\s/gm, '\\s').replace(/"/gm, '\\"')
        const regExp = new RegExp(`\\\${\\s*${expExpression}\\s*}(:([a-z])(\\((.+)\\))?)?`, 'gm')
        match = match.replace(regExp, `\${${count}}`)
        count++
      })
      let template = match.replace(/\r\n/g, '\n')
      if (count) {
        let regex = ''
        for (let i = 0; i < count; i++) {
          regex += `(?=.*?\\\$\\\{${i}\\\})`
        }
        templatePatterns[template] = regex
      }
      if (groupName && !node.tag.name) {
        template = { group: groupName, value: template }
      }
      if (templates.indexOf(template) === -1 && templates.findIndex((t) => t.group && t.group === template.group && t.value && t.value === template.value) === -1) templates.push(template)
    }
  }
}

const traverseClassDeclarations = {
  ClassDeclaration: (path, { source, templates, groups, templatePatterns }) => {
    const node = path.node
    if (node.decorators && node.decorators.length) {
      const groupNames = node.decorators.map((d) => d.expression).filter((e) => e.callee && e.callee.name === 'i18nGroup' && e.arguments && e.arguments.length).map((d) => d.arguments.map((a) => a.name || a.value)).reduce((p, n) => p.concat(n), [])
      const groupName = (groupNames.length) ? groupNames[0] : null
      path.traverse(traverseTemplateExpressions, { source, templates, groupName, templatePatterns })
    } else {
      path.traverse(traverseTemplateExpressions, { source, templates, groupName: groups[node.id.name], templatePatterns })
    }
  }<commit_msg>fix(template): empty strings should not be exported as keys<commit_after>import escapeStringRegexp from 'escape-string-regexp'
import traverse from 'babel-traverse'

const traverseTemplateExpressions = {
  TaggedTemplateExpression: (path, { source, templates, groupName, templatePatterns }) => {
    const node = path.node
    if (node.scanned) return
    node.scanned = true
    if (node.tag.name === 'i18n' || (node.tag.callee && (node.tag.callee.name === 'i18n' || (node.tag.callee.property && node.tag.callee.property.name === 'i18n'))) || (node.tag.property && node.tag.property.name === 'i18n')) {
      if (node.tag.arguments && node.tag.arguments.length) {
        groupName = node.tag.arguments[0].value || node.tag.arguments[0].name
      }
      let match = source.substring(node.quasi.start + 1, node.quasi.end - 1)
      let count = 0
      node.quasi.expressions.forEach((exp) => {
        const expression = source.substring(exp.start, exp.end)
        const expExpression = escapeStringRegexp(expression).replace(/\r/gm, '\\r').replace(/\n/gm, '\\n').replace(/\t/gm, '\\t').replace(/\s/gm, '\\s').replace(/"/gm, '\\"')
        const regExp = new RegExp(`\\\${\\s*${expExpression}\\s*}(:([a-z])(\\((.+)\\))?)?`, 'gm')
        match = match.replace(regExp, `\${${count}}`)
        count++
      })
      let template = match.replace(/\r\n/g, '\n')
      if(template) {
        if (count) {
          let regex = ''
          for (let i = 0; i < count; i++) {
            regex += `(?=.*?\\\$\\\{${i}\\\})`
          }
          templatePatterns[template] = regex
        }
        if (groupName && !node.tag.name) {
          template = { group: groupName, value: template }
        }
        if (templates.indexOf(template) === -1 && templates.findIndex((t) => t.group && t.group === template.group && t.value && t.value === template.value) === -1) templates.push(template)
      }
    }
  }
}

const traverseClassDeclarations = {
  ClassDeclaration: (path, { source, templates, groups, templatePatterns }) => {
    const node = path.node
    if (node.decorators && node.decorators.length) {
      const groupNames = node.decorators.map((d) => d.expression).filter((e) => e.callee && e.callee.name === 'i18nGroup' && e.arguments && e.arguments.length).map((d) => d.arguments.map((a) => a.name || a.value)).reduce((p, n) => p.concat(n), [])
      const groupName = (groupNames.length) ? groupNames[0] : null
      path.traverse(traverseTemplateExpressions, { source, templates, groupName, templatePatterns })
    } else {
      path.traverse(traverseTemplateExpressions, { source, templates, groupName: groups[node.id.name], templatePatterns })
    }
  }
{'fraction_non_alphanumeric': 0.19679328116052683, 'fraction_numerical': 0.007253292613094102, 'mean_word_length': 2.9577039274924473, 'pattern_counts': {'":': 0, '<': 5, '<?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': '1727073', 'n_tokens_mistral': 1749, 'n_tokens_neox': 1696, 'n_words': 321}