Home Manual Reference Source Test Repository

src/ESComplexModule.js

import ASTWalker  from 'typhonjs-ast-walker/src/ASTWalker';

import Plugins    from './Plugins';

/**
 * Provides a runtime to invoke ESComplexModule plugins for processing / metrics calculations of independent modules.
 */
export default class ESComplexModule
{
   /**
    * Initializes ESComplexModule.
    *
    * @param {object}   options - module options including user plugins to load including:
    * ```
    * (boolean)         loadDefaultPlugins - When false ESComplexModule will not load any default plugins.
    * (Array<Object>)   plugins - A list of ESComplexModule plugins that have already been instantiated.
    * ```
    */
   constructor(options = {})
   {
      /* istanbul ignore if */
      if (typeof options !== 'object') { throw new TypeError('ctor error: `options` is not an `object`.'); }

      /**
       * Provides dispatch methods to all module plugins.
       * @type {Plugins}
       * @private
       */
      this._plugins = new Plugins(options);
   }

   /**
    * Processes the given ast and calculates metrics via plugins.
    *
    * @param {object|Array}   ast - Javascript AST.
    * @param {object}         options - (Optional) module analyze options.
    *
    * @returns {ModuleReport} - A single module report.
    */
   analyze(ast, options = {})
   {
      if (typeof ast !== 'object' || Array.isArray(ast))
      {
         throw new TypeError('analyze error: `ast` is not an `object` or `array`.');
      }

      /* istanbul ignore if */
      if (typeof options !== 'object') { throw new TypeError('analyze error: `options` is not an `object`.'); }

      const settings = this._plugins.onConfigure(options);

      const syntaxes = this._plugins.onLoadSyntax(settings);

      const report = this._plugins.onModuleStart(ast, syntaxes, settings);

      // Completely traverse the provided AST and defer to plugins to process node traversal.
      new ASTWalker().traverse(ast,
      {
         enterNode: (node, parent) => { return this._plugins.onEnterNode(report, node, parent); },
         exitNode: (node, parent) => { return this._plugins.onExitNode(report, node, parent); }
      });

      this._plugins.onModuleEnd(report);

      return report.finalize();
   }

   // Asynchronous Promise based methods ----------------------------------------------------------------------------

   /**
    * Wraps in a Promise processing the given ast and calculates metrics via plugins.
    *
    * @param {object|Array}   ast - Javascript AST.
    * @param {object}         options - (Optional) module analyze options.
    *
    * @returns {Promise<ModuleReport>} - A single module report.
    */
   analyzeAsync(ast, options = {})
   {
      return new Promise((resolve, reject) =>
      {
         try { resolve(this.analyze(ast, options)); }
         catch (err) { /* istanbul ignore next */ reject(err); }
      });
   }
}