<commit_before>import { updateOrRemove } from '../../lib/util/knex'
import { differenceBy, isEmpty, pick, uniqBy } from 'lodash'
import { map } from 'lodash/fp'

const tagsInText = (text = '') => {
  // TODO alphanumeric and underscore
  return (text.match(/#[\w-]+/g) || []).map(str => str.substr(1))
}

const addToTaggable = (taggable, tagName, selected, trx) => {
  var association, communities
  var isPost = !taggable.post
  if (isPost) {
    // taggable is a post
    association = 'communities'
    communities = post => post.relations.communities.models
  } else {
    // taggable is a comment
    association = 'post.communities'
    communities = comment => comment.relations.post.relations.communities.models
  }
  return taggable.load(association, {transacting: trx})
  .then(() => Tag.find(tagName, {transacting: trx}))
  .then(tag => {
    if (tag) return tag
    return new Tag({
      name: tagName,
      created_at: new Date()
    }).save({}, {transacting: trx})
    .catch(() => Tag.find(tagName, {transacting: trx}))
  })
  .tap(tag => {
    var attachment = {tag_id: tag.id}
    if (isPost) attachment.selected = selected
    return taggable.tags().attach(attachment, {transacting: trx})
  })<commit_msg>hashtags may not start with a number<commit_after>import { updateOrRemove } from '../../lib/util/knex'
import { differenceBy, isEmpty, pick, uniqBy } from 'lodash'
import { map } from 'lodash/fp'

const tagsInText = (text = '') => {
  // TODO alphanumeric and underscore
  return (text.match(/#[A-Za-z][\w-]+/g) || []).map(str => str.substr(1))
}

const addToTaggable = (taggable, tagName, selected, trx) => {
  var association, communities
  var isPost = !taggable.post
  if (isPost) {
    // taggable is a post
    association = 'communities'
    communities = post => post.relations.communities.models
  } else {
    // taggable is a comment
    association = 'post.communities'
    communities = comment => comment.relations.post.relations.communities.models
  }
  return taggable.load(association, {transacting: trx})
  .then(() => Tag.find(tagName, {transacting: trx}))
  .then(tag => {
    if (tag) return tag
    return new Tag({
      name: tagName,
      created_at: new Date()
    }).save({}, {transacting: trx})
    .catch(() => Tag.find(tagName, {transacting: trx}))
  })
  .tap(tag => {
    var attachment = {tag_id: tag.id}
    if (isPost) attachment.selected = selected
    return taggable.tags().attach(attachment, {transacting: trx})
  })
{'fraction_non_alphanumeric': 0.1596130592503023, 'fraction_numerical': 0.0008061265618702137, 'mean_word_length': 3.4242424242424243, 'pattern_counts': {'":': 0, '<': 3, '<?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': '1499521', 'n_tokens_mistral': 848, 'n_tokens_neox': 837, 'n_words': 206}