lib/configuration.js
function set(key, value, lineno, child) {
  // keys can be passed as buffers
  // we need a string
  key = '' + key;
  //console.error('%s=%s', key, value);

  var typedef = Types[key]
    , exists = this._data[key]
    , val = exists || {value: null, lineno: !child ? lineno : undefined}
    , changed = false;

  if(!lineno && !child) {
    changed = !exists || exists && exists.value !== value;
  }

  if(typedef && typedef.repeats) {
    // repeatable values always trigger a change
    // as they are created or appended
    if(!lineno && !child) changed = true;
    if(!exists) {
      val.value = [value];
      this._data[key] = val;
    }else{
      exists.value.push(value);
    }
  }else{
    val.value = value;
    this._data[key] = val;
  }

  if(lineno === undefined && !child) {
    // keep track of new keys, repeatable keys that are arrays
    // are always appended to the end of the file
    if(typedef.repeats || !exists) {
      if(!Object.keys(this._added).length) {
        this._lines.push(GENERATED);
      }
      this._added[key] = value;

      // add a line with the encoded value
      this._lines.push(this.encode(key, value));
    }

    // keep track of modified data for config rewrite (must come after added)
    if(exists && !this._added[key]) {
      this._modified[exists.lineno] = key;
      // line numbers are one-based but the array is zero
      this._lines[exists.lineno - 1] = this.encode(key, value);
    }
  }

  if(changed) {
    // emit change event with key, newval, oldval, newentry, oldentry
    this.emit('change',
      key, value, (exists ? exists.value : undefined), val, exists);

    // emit by key also, easier to consume
    this.emit(key,
      key, value, (exists ? exists.value : undefined), val, exists);
  }

  // merge include files synchronously
  // as we encounter them
  if(key === Types.INCLUDE && value) {
    this.emit('include', value, this._file, lineno);
  }
}
function set(key, value, lineno, child) {
  // keys can be passed as buffers
  // we need a string
  key = '' + key;
  //console.error('%s=%s', key, value);

  var typedef = Types[key]
    , exists = this._data[key]
    , val = exists || {value: null, lineno: !child ? lineno : undefined}
    , changed = false;

  if(!lineno && !child) {
    changed = !exists || exists && exists.value !== value;
  }

  if(typedef && typedef.repeats) {
    // repeatable values always trigger a change
    // as they are created or appended
    if(!lineno && !child) changed = true;
    if(!exists) {
      val.value = [value];
      this._data[key] = val;
    }else{
      exists.value.push(value);
    }
  }else{
    val.value = value;
    this._data[key] = val;
  }

  if(lineno === undefined && !child) {
    // keep track of new keys, repeatable keys that are arrays
    // are always appended to the end of the file
    if(typedef.repeats || !exists) {
      if(!Object.keys(this._added).length) {
        this._lines.push(GENERATED);
      }
      this._added[key] = value;

      // add a line with the encoded value
      this._lines.push(this.encode(key, value));
    }

    // keep track of modified data for config rewrite (must come after added)
    if(exists && !this._added[key]) {
      this._modified[exists.lineno] = key;
      // line numbers are one-based but the array is zero
      this._lines[exists.lineno - 1] = this.encode(key, value);
    }
  }

  if(changed) {
    // emit change event with key, newval, oldval, newentry, oldentry
    this.emit('change',
      key, value, (exists ? exists.value : undefined), val, exists);

    // emit by key also, easier to consume
    this.emit(key,
      key, value, (exists ? exists.value : undefined), val, exists);
  }

  // merge include files synchronously
  // as we encounter them
  if(key === Types.INCLUDE && value) {
    this.emit('include', value, this._file, lineno);
  }
}
function set ( key , value , lineno , child ) { // keys can be passed as buffers // we need a string key = '' + key ; //console.error('%s=%s', key, value); var typedef = Types [ key ] , exists = this . _data [ key ] , val = exists || { value : null , lineno : ! child ? lineno : undefined } , changed = false ; if ( ! lineno && ! child ) { changed = ! exists || exists && exists . value !== value ; } if ( typedef && typedef . repeats ) { // repeatable values always trigger a change // as they are created or appended if ( ! lineno && ! child ) changed = true ; if ( ! exists ) { val . value = [ value ] ; this . _data [ key ] = val ; } else { exists . value . push ( value ) ; } } else { val . value = value ; this . _data [ key ] = val ; } if ( lineno === undefined && ! child ) { // keep track of new keys, repeatable keys that are arrays // are always appended to the end of the file if ( typedef . repeats || ! exists ) { if ( ! Object . keys ( this . _added ) . length ) { this . _lines . push ( GENERATED ) ; } this . _added [ key ] = value ; // add a line with the encoded value this . _lines . push ( this . encode ( key , value ) ) ; } // keep track of modified data for config rewrite (must come after added) if ( exists && ! this . _added [ key ] ) { this . _modified [ exists . lineno ] = key ; // line numbers are one-based but the array is zero this . _lines [ exists . lineno - 1 ] = this . encode ( key , value ) ; } } if ( changed ) { // emit change event with key, newval, oldval, newentry, oldentry this . emit ( 'change' , key , value , ( exists ? exists . value : undefined ) , val , exists ) ; // emit by key also, easier to consume this . emit ( key , key , value , ( exists ? exists . value : undefined ) , val , exists ) ; } // merge include files synchronously // as we encounter them if ( key === Types . INCLUDE && value ) { this . emit ( 'include' , value , this . _file , lineno ) ; } }
Update the in-memory configuration.

Designed to be used by CONFIG SET the key should already
have been validated.

Internally when adding keys first time around a lineno specifies
where in the file the declaration is, otherwise when modifying via
CONFIG SET a lineno should not be specified and the key is tracked
as having been modified if the value changes, in which case a *change*
event is dispatched which will allow other modules to react to
configuration changes.

The final *child* parameter is used internally to track config values
being set by child configurations. It is used so that we can pass a lineno
value down to circular reference error handling for better error messages
but ensure that the set value does not pick up a new lineno when coming from
a child.
Update the in - memory configuration .