<commit_before>var flat = require('flat')
var flatten = flat.flatten
var unflatten = flat.unflatten
var extend = require('xtend')
var mutate = require('xtend/mutable')
var isArray = require('isarray')
var isFn = require('is-fn')

function context () {
  var _getAssetFns = []
  var _assets = []
  var _ids = {}

  function asset (type, opts, children) {
    var asset = {}

    if (!type) {
      throw new Error('Asset type must be defined')
    }

    if (!opts) {
      opts = {}
    }

    asset.type = type

    asset.key = _assets.length

    if (!isArray(children)) {
      children = [].slice.call(arguments, 2)
    }

    if (children && children.length) {
      asset = extend(opts, asset, {
        children: children
      })
    } else {
      asset = extend(opts, asset)
    }

    if (asset.id) {
      _ids[asset.id] = asset.key
    }

    _assets.push(asset)

    if (containsFns(opts)) {
      _getAssetFns.push(asset.key)
    }

    finalizeAssetRefs()

    return asset
  }

  asset.getAssetById = getAssetById

  return asset

  function finalizeAssetRefs () {
    if (!_getAssetFns.length) {
      return
    }

    _getAssetFns = _getAssetFns.filter(function getAssetFromId (id, index) {
      var asset = getAssetById(id)
      var flat = flatten(asset)
      var assetRefUpdated

      Object.keys(flat).forEach(function getRef (prop) {
        var asset

        if (isFn(flat[prop]) && (asset = flat[prop]())) {
          asset = extend({}, asset)

          // There's likely a better way to do this.
          // But basically this to prevent deeply nested links of links
          // in cases where assets link between one another.
          delete asset.link

          flat[prop] = asset

          if (!assetRefUpdated) {
            assetRefUpdated = true
          }
        }
      })

      if (assetRefUpdated) {
        mutate(_assets[id], unflatten(flat))
        return false
      }

      return true
    })
  }

  function getAssetById (id) {
    return getAssetFromCollection(id) || function futureAsset () {
      return getAssetFromCollection(id)
    }
  }

  function getAssetFromCollection (id) {
    var asset = _assets[id] || _assets[_ids[id]]
    if (asset) {
      asset = extend({}, asset)

      delete asset.children

      return asset
    }
  }

  function containsFns (obj) {
    var flat = flatten(obj)

    return Object.keys(flat).some(function testFn (prop) {
      return isFn(flat[prop])
    })
  }
}

var asset = module.exports = context()
asset.context = context
<commit_msg>Working out linking<commit_after>var flat = require('flat')
var flatten = flat.flatten
var unflatten = flat.unflatten
var extend = require('xtend')
var mutate = require('xtend/mutable')
var isArray = require('isarray')
var isFn = require('is-fn')

function context () {
  var _getAssetFns = []
  var _assets = []
  var _ids = {}

  function asset (type, opts, children) {
    var asset = {}
    var link = {}

    if (!type) {
      throw new Error('Asset type must be defined')
    }

    if (!opts) {
      opts = {}
    }

    // 'type_1' || [ 'type_1' ] || { type_1: true } || { type_1: 'value' }

    if (!opts.link || opts.link === 'type_1' || opts.link.type_1) {
      link['type_1'] = true
    }

    asset.type = type

    asset.key = _assets.length

    if (!isArray(children)) {
      children = [].slice.call(arguments, 2)
    }

    if (children && children.length) {
      asset = extend(opts, asset, {
        children: children
      })
    } else {
      asset = extend(opts, asset)
    }

    if (asset.id) {
      _ids[asset.id] = asset.key
    }

    _assets.push(asset)

    if (containsFns(opts)) {
      _getAssetFns.push(asset.key)
    }

    finalizeAssetRefs()

    return asset
  }

  asset.getAssetById = getAssetById

  return asset

  function finalizeAssetRefs () {
    if (!_getAssetFns.length) {
      return
    }

    _getAssetFns = _getAssetFns.filter(function getAssetFromId (id, index) {
      var asset = getAssetById(id)
      var flat = flatten(asset)
      var assetRefUpdated

      Object.keys(flat).forEach(function getRef (prop) {
        var asset

        if (isFn(flat[prop]) && (asset = flat[prop]())) {
          asset = extend({}, asset)

          // There's likely a better way to do this.
          // But basically this to prevent deeply nested links of links
          // in cases where assets link between one another.
          delete asset.link

          flat[prop] = asset

          if (!assetRefUpdated) {
            assetRefUpdated = true
          }
        }
      })

      if (assetRefUpdated) {
        mutate(_assets[id], unflatten(flat))
        return false
      }

      return true
    })
  }

  function getAssetById (id) {
    return getAssetFromCollection(id) || function futureAsset () {
      return getAssetFromCollection(id)
    }
  }

  function getAssetFromCollection (id) {
    var asset = _assets[id] || _assets[_ids[id]]
    if (asset) {
      asset = extend({}, asset)

      delete asset.children

      return asset
    }
  }

  function containsFns (obj) {
    var flat = flatten(obj)

    return Object.keys(flat).some(function testFn (prop) {
      return isFn(flat[prop])
    })
  }
}

var asset = module.exports = context()
asset.context = context

{'fraction_non_alphanumeric': 0.12067334972574238, 'fraction_numerical': 0.0017022886324947987, 'mean_word_length': 2.2362301101591187, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '429497', 'n_tokens_mistral': 1697, 'n_tokens_neox': 1634, 'n_words': 415}