text: // Copyright (c) 2021, João Paulo Carreiro
  //
  // Permission to use, copy, modify, and/or distribute this software 
  // for any purpose with or without fee is hereby granted, provided 
  // that the above copyright notice and this permission notice appear 
  // in all copies.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
  // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 
  // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 
  // THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 
  // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
  // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 
  // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
  // WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  
  const prelude = require('../prelude')
  const path = require('upath')
  const mustache = require('mustache')
  
  //
  // Regular expression for error identifiers.
  //
  
  const ERROR_IDENTIFIER_REGEX = '[A-Z][A-Z0-9_]*'
  
  //
  // Define a list of error codes based on the same 
  // module identifier. This function returns another
  // function that takes a list of codes and builds
  // an exportable object for error definition.
  //
  
  const set = (moduleID) => (...args) => args.filter(prelude.is.string).reduce((ac, code) => ({ ...ac, ...{ [code]: define(moduleID, code) } }), {})
  
  //
  // function that returns another function to build 
  // an error for a specific module, code and payload.
  //
  
  const define = (moduleID, code) => (...args) => {
  
      //
      // Build qualified error identifier.
      //
  
      let _id = `${moduleID}:${code}`
  
      //
      // Build qualified error message.
      //
  
      let _err = new Error(`${_id}[${args.map(arg => prelude.stringify(arg)).join(', ')}]`)
  
      //
      // Add internal error properties to the error object.
      // Clone the arguments just to be safe...
      //
  
      _err.id = _id
      _err.module = moduleID
      _err.code = code
      _err.args = prelude.extend(/* deep */ true, [], args)
  
      //
      // Return the augmented error object to caller.
      //
  
      return _err
  }
  
  //
  // Load from disk a error module definition.
  // Returns the exportable object with the error
  // constructor functions.
  //
  
  const load = (filePath, dirname) => {
  
      //
      // Load the object with the error set definition.
      //
  
      let def = require(path.resolve(dirname, filePath))
  
      //
      // Compute the module identifier value.
      // By default, the module identifier is empty.
      //
  
      let moduleID = def.module ? def.module : ''
  
      //
      // If module is not a string then we need to get 
      // its string value. the result of this operation
      // if a string value with the module identifier.
      //
  
      if (prelude.is.string(moduleID) || Array.isArray(moduleID)) {
  
          let package = def.package ? require(path.resolve(dirname, def.package)) : prelude.findp(dirname)
          let folder = path.basename(dirname)
          let filename = path.basename(path.changeExt(filePath))
  
          moduleID = prelude
              .toArray(moduleID)
              .map(parcel => {
                  if (prelude.is.string(parcel)) {
  
                      return mustache.render(parcel, { package, folder, filename, dirname })
                  }
                  else {
  
                      //
                      // ERROR: Invalid module identifier definition ( ... )
                      //
  
                      throw err.INVALID_MODULE_IDENTIFIER_DEFINITION(parcel)
                  }
              })
              .join(path.sep)
      }
      else {
  
          //
          // ERROR: Invalid module identifier definition ( ... )
          //
  
          throw err.INVALID_MODULE_IDENTIFIER_DEFINITION(moduleID)
      }
  
      //
      // Return an object with the error API for the definition.
      //
  
      return set(moduleID)(...(def.errors ? def.errors : []))
  }
  
  const parse = (str) => { }
  
  const unparse = (err) => prelude.is.string(err) ? err : err.message
  
  const err = load('err.json', __dirname)
  
  module.exports = {
      set,
      define,
      load,
      parse,
      unparse
  }
  
  //
  // Some resources related to errors:
  //    - https://stackoverflow.com/questions/18391212/is-it-not-possible-to-stringify-an-error-using-json-stringify
  //
  