<commit_before># TODO: we should try to eliminate this dependency
synth = require 'data-synth'

class Origin

  constructor: (@origin) -> @map = {}

  set: (keys..., value) ->
    obj = @objectify (keys.join '.'), value
    @copy @map, obj if obj instanceof Object;
    return this

  # returns the 'updated' defined object
  define: (keys..., value) ->
    exists = @resolve keys[0], keys[1], warn: false
    definition = @objectify (keys.join '.'), switch
      when not exists?             then value
      when synth.instanceof exists then exists.merge value
      when synth.instanceof value  then value.override exists
      when exists.constructor is Object
        @copy exists, value
      else
        throw @error "unable to define #{keys.join '.'} due to conflict with existing definition", exists
    @set definition
    return definition

  # TODO: enable resolve to merge nested definitions when only one key...
  resolve: (keys..., opts={}) ->
    unless opts instanceof Object
      keys.push opts
      opts = {}
    return unless keys.length > 0

    # setup default opts
    opts.warn ?= true
    opts.recurse ?= true

    [ type, key ] = keys
    [ prefix..., key ] = (key?.split ':') ? []
    match = switch
      when not key? then @map[type]
      when prefix.length > 0 then @map[prefix[0]]?[type]?[key]
      else @map[type]?[key]
    match ?= @origin?.resolve? arguments... if opts.recurse is true
    unless match?
      console.debug? "[Origin:resolve] unable to find #{type}:#{key}" if opts.warn
    return match

  # convenience function
  copy:      synth.copy
  objectify: synth.objectify

  error: (msg, context) ->
    res = new Error msg
    res.context = context ? @map
    return res

  locate: (inside, path) ->
    return unless inside? and typeof path is 'string'
    if /^\//.test path
      console.warn "[Origin:locate] absolute-schema-nodeid is not yet supported, ignoring #{path}"
      return
    [ target, rest... ] = path.split '/'

    console.debug? "[Origin:locate] locating #{path}"
    if inside.access instanceof Function
      return switch
        when target is '..'
          if (inside.parent.meta 'synth') is 'list'
            @locate inside.parent.parent, rest.join '/'
          else
            @locate inside.parent, rest.join '/'
        when rest.length > 0 then @locate (inside.access target), rest.join '/'
        else inside.access target

    for key, val of inside when val.hasOwnProperty target
      return switch
        when rest.length > 0 then @locate val[target], rest.join '/'
        else val[target]
    console.warn "[Origin:locate] unable to find '#{path}' within #{Object.keys inside}"
    return

module.exports = Origin
<commit_msg>remove dependency to data-synth from origin, enhance resolve to return merged definition<commit_after># origin - cascading symbol definitions

class Origin

  constructor: (@origin) -> @map = {}

  # returns the 'updated' defined object
  define: (keys..., value) ->
    exists = @resolve keys..., warn: false
    definition = @objectify (keys.join '.'), switch
      when not exists?             then value
      when exists.constructor is Object
        @copy exists, value
      else
        throw @error "unable to define #{keys.join '.'} due to conflict with existing definition", exists
    @set definition
    return definition

  # returns merged nested definitions
  resolve: (keys..., opts={}) ->
    unless opts instanceof Object
      keys.push opts
      opts = {}
    return unless keys.length > 0

    # setup default opts
    opts.warn ?= true
    opts.recurse ?= true

    exists = @origin?.resolve? arguments... if opts.recurse is true

    [ keys..., key ] = keys
    [ prefix..., key ] = key.split ':'
    keys.unshift prefix...
    keys.push key

    extract = (obj={}, key, rest...) ->
      if (key of obj) and rest.length
        extract obj[key], rest...
      else
        obj[key]

    match = extract @map, keys...
    match = @copy exists, match if exists?
    unless match?
      console.debug? "[Origin:resolve] unable to find #{keys.join ':'}" if opts.warn
    return match

  # explicitly 'set' a value into the internal 'map'
  set: (keys..., value) ->
    obj = @objectify (keys.join '.'), value
    @copy @map, obj if obj instanceof Object;
    return this

  copy: (dest={}, src, append=false) ->
    for p of src
      switch
        when src[p]?.constructor is Object
          dest[p] ?= {}
          unless dest[p] instanceof Object
            k = dest[p]
            dest[p] = {}
            dest[p][k] = null
          arguments.callee dest[p], src[p], append
        when append is true and dest[p]?
          unless dest[p] instanceof Object
            k = dest[p]
            dest[p] = {}
            dest[p][k] = null
          dest[p][src[p]] = null
        else dest[p] = src[p]
    return dest

  tokenize = (key) -> ((key?.split? '.')?.filter (e) -> !!e) ? []

  objectify: (key, val) ->
    return key if key instanceof Object
    composite = tokenize key
    unless composite.length
      return val ? {}

    obj = root = {}
    while (k = composite.shift())
      last = r: root, k: k
      root = root[k] = {}
    last.r[last.k] = val
    obj

  error: (msg, context) ->
    res = new Error msg
    res.context = context ? @map
    return res

  # TODO: should consider a more generic operation for this function...
  locate: (inside, path) ->
    return unless inside? and typeof path is 'string'
    if /^\//.test path
      console.warn "[Origin:locate] absolute-schema-nodeid is not yet supported, ignoring #{path}"
      return
    [ target, rest... ] = path.split '/'

    console.debug? "[Origin:locate] locating #{path}"
    if inside.access instanceof Function
      return switch
        when target is '..'
          if (inside.parent.meta 'synth') is 'list'
            @locate inside.parent.parent, rest.join '/'
          else
            @locate inside.parent, rest.join '/'
        when rest.length > 0 then @locate (inside.access target), rest.join '/'
        else inside.access target

    for key, val of inside when val.hasOwnProperty target
      return switch
        when rest.length > 0 then @locate val[target], rest.join '/'
        else val[target]
    console.warn "[Origin:locate] unable to find '#{path}' within #{Object.keys inside}"
    return

module.exports = Origin

{'fraction_non_alphanumeric': 0.12427519197617928, 'fraction_numerical': 0.001567152483936687, 'mean_word_length': 2.3050233039875714, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 27, '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': '1730182', 'n_tokens_mistral': 1849, 'n_tokens_neox': 1807, 'n_words': 649}