<commit_before>KD = require './kd'
KDEventEmitter = require './eventemitter'

createSymbol = (key) ->
  (window.Symbol? key) || "__#{key}__"

createProxy = (data, handler) ->
  if window.Proxy?
    return new Proxy data, handler
  else
    console.warn 'Proxies are not supported on this platform!'
    return new Object data

module.exports = class KDData

  @EMITTER = createSymbol 'kddata'
  @NAME    = createSymbol 'name'

  constructor: (data = {}) ->

    emitter = new KDEventEmitter
    emitter.__data__ = data
    emitter.isArray  = Array.isArray data

    proxy = createProxy data, proxyHandler emitter
    Object.defineProperty proxy, KDData.EMITTER, value: emitter

    return proxy

  @isSupported = -> !!window.Proxy?

  @getEmitter = (data) ->

    return  unless data?
    return  emitter  if emitter = data[KDData.EMITTER]

    if typeof data.on is 'function' and typeof data.off is 'function'
      return data


  getFullPath = (parent, child) ->

    if root = parent[KDData.NAME]
      return "#{root}.#{child}"
    return child


  proxyHandler = (base) ->

    get: (target, key) ->

      value = target[key]
      return value  if typeof key isnt 'string'

      key = getFullPath target, key

      if value and dataValue = KD.utils.JsPath.getAt base.__data__, key
        if dataValue instanceof Object and value not instanceof Date
          proxy = createProxy value, proxyHandler base
          Object.defineProperty proxy, KDData.NAME, {
            value: key, configurable: yes
          }
          return proxy

      return value


    set: (target, key, value, receiver) ->

      if base.isArray
        currentLength = target.length

      target[key] = value

      if base.isArray
        lengthChanged = target.length isnt currentLength
        return true  if key is 'length' and not lengthChanged

      if root = receiver[KDData.NAME]
        key = "#{root}.#{key}"
      else
        root = ''

      return true  if typeof key is 'symbol' or /^__|__$/.test key

      if lengthChanged
        prefix = if key.indexOf('.') >= 0 then "#{root}." else ''
        base.emit 'update', [ "#{prefix}length" ]

      base.emit 'update', [ key ]
      return true


    getPrototypeOf: (target) ->

      return KDData.prototype<commit_msg>KDData: create proxy only on set<commit_after>KD = require './kd'
KDEventEmitter = require './eventemitter'

createSymbol = (key) ->
  (window.Symbol? key) || "__#{key}__"

createProxy = (data, handler) ->
  if window.Proxy?
    return new Proxy data, handler
  else
    console.warn 'Proxies are not supported on this platform!'
    return new Object data

module.exports = class KDData

  @EMITTER = createSymbol 'kddata'
  @NAME    = createSymbol 'name'

  constructor: (data = {}) ->

    emitter = new KDEventEmitter
    emitter.__data__ = data
    emitter.isArray  = Array.isArray data

    proxy = createProxy data, proxyHandler emitter
    Object.defineProperty proxy, KDData.EMITTER, value: emitter

    return proxy

  @isSupported = -> !!window.Proxy?

  @getEmitter = (data) ->

    return  unless data?
    return  emitter  if emitter = data[KDData.EMITTER]

    if typeof data.on is 'function' and typeof data.off is 'function'
      return data


  getFullPath = (parent, child) ->

    if root = parent[KDData.NAME]
      return "#{root}.#{child}"
    return child


  proxyHandler = (base) ->

    set: (target, key, value, receiver) ->

      if base.isArray
        currentLength = target.length

      if value instanceof Object and value not instanceof Date
        if root = receiver[KDData.NAME]
          key = "#{root}.#{key}"
        value = createProxy value, proxyHandler base
        Object.defineProperty value, KDData.NAME, {
          value: key, configurable: yes
        }

      target[key] = value

      if base.isArray
        lengthChanged = target.length isnt currentLength
        return true  if key is 'length' and not lengthChanged

      return true  if typeof key is 'symbol' or /^__|__$/.test key

      if root = receiver[KDData.NAME]
        key = "#{root}.#{key}"
      else
        root = ''

      if lengthChanged
        prefix = if key.indexOf('.') >= 0 then "#{root}." else ''
        base.emit 'update', [ "#{prefix}length" ]

      base.emit 'update', [ key ]
      return true
{'fraction_non_alphanumeric': 0.10714285714285714, 'fraction_numerical': 0.00046382189239332097, 'mean_word_length': 2.475423045930701, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, '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': '4970297', 'n_tokens_mistral': 1314, 'n_tokens_neox': 1249, 'n_words': 404}