Home Manual Reference Source Test Repository

src/module/report/ClassReport.js

import AbstractReport         from './AbstractReport';
import AggregateMethodReport  from './AggregateMethodReport';
import ClassMethodReport      from './ClassMethodReport';
import MethodAverage          from './averages/MethodAverage';

import AnalyzeError           from '../../analyze/AnalyzeError';
import ReportType             from '../../types/ReportType';
import ObjectUtil             from '../../utils/ObjectUtil';
import TransformFormat        from '../../transform/TransformFormat';

/**
 * Provides the class report object which stores data pertaining to a single ES6 class.
 *
 * Methods that are stored as ClassMethodReport instances in the `methods` member variable.
 */
export default class ClassReport extends AbstractReport
{
   /**
    * Returns the enum for the report type.
    * @returns {ReportType}
    */
   get type() { return ReportType.CLASS; }

   /**
    * Initializes class report.
    *
    * @param {string}   name - Name of the class.
    * @param {number}   lineStart - Start line of class.
    * @param {number}   lineEnd - End line of class.
    */
   constructor(name = '', lineStart = 0, lineEnd = 0)
   {
      super(new AggregateMethodReport(lineStart, lineEnd));

      /**
       * Stores any analysis errors.
       * @type {Array}
       */
      this.errors = [];

      /**
       * Stores the end line for the class.
       * @type {number}
       */
      this.lineEnd = lineEnd;

      /**
       * Stores the start line for the class.
       * @type {number}
       */
      this.lineStart = lineStart;

      /**
       * Stores all method data.
       * @type {Array<ClassMethodReport>}
       */
      this.methods = [];

      /**
       * Stores the average method metric data.
       * @type {HalsteadAverage}
       */
      this.methodAverage = new MethodAverage();

      /**
       * The name of the class.
       * @type {string}
       */
      this.name = name;
   }

   /**
    * Clears all errors stored in the class report and by default any class methods.
    *
    * @param {boolean}  clearChildren - (Optional) If false then class method errors are not cleared; default (true).
    */
   clearErrors(clearChildren = true)
   {
      this.errors = [];

      if (clearChildren)
      {
         this.methods.forEach((report) => { report.clearErrors(); });
      }
   }

   /**
    * Gets all errors stored in the class report and by default any class methods.
    *
    * @param {object}   options - Optional parameters.
    * @property {boolean}  includeChildren - If false then module errors are not included; default (true).
    * @property {boolean}  includeReports - If true then results will be an array of object hashes containing `source`
    *                                      (the source report object of the error) and `error`
    *                                      (an AnalyzeError instance) keys; default (false).
    *
    * @returns {Array<AnalyzeError|{error: AnalyzeError, source: *}>}
    */
   getErrors(options = { includeChildren: true, includeReports: false })
   {
      /* istanbul ignore if */
      if (typeof options !== 'object') { throw new TypeError(`getErrors error: 'options' is not an 'object'.`); }

      // By default set includeChildren to true.
      /* istanbul ignore if */
      if (typeof options.includeChildren !== 'boolean') { options.includeChildren = true; }

      // If `includeReports` is true then return an object hash with the source and error otherwise return the error.
      let errors = options.includeReports ? this.errors.map((entry) => { return { error: entry, source: this }; }) :
       [].concat(...this.errors);

      // If `includeChildren` is true then traverse all children reports for errors.
      if (options.includeChildren)
      {
         // Add class to all children errors.
         if (options.includeReports)
         {
            const childErrors = [];

            this.methods.forEach((report) => { childErrors.push(...report.getErrors(options)); });

            // Add module to object hash.
            childErrors.forEach((error) => { error.class = this; });

            // Push to all module errors.
            errors.push(...childErrors);
         }
         else
         {
            this.methods.forEach((report) => { errors.push(...report.getErrors(options)); });
         }
      }

      // If `options.query` is defined then filter errors against the query object.
      if (typeof options.query === 'object')
      {
         errors = errors.filter((error) => ObjectUtil.safeEqual(options.query, error));
      }

      return errors;
   }

   /**
    * Returns the supported transform formats.
    *
    * @returns {Object[]}
    */
   static getFormats()
   {
      return TransformFormat.getFormats(ReportType.CLASS);
   }

   /**
    * Returns the name / id associated with this report.
    * @returns {string}
    */
   getName()
   {
      return this.name;
   }

   /**
    * Deserializes a JSON object representing a ClassReport.
    *
    * @param {object}   object - A JSON object of a ClassReport that was previously serialized.
    *
    * @returns {ClassReport}
    */
   static parse(object)
   {
      /* istanbul ignore if */
      if (typeof object !== 'object') { throw new TypeError(`parse error: 'object' is not an 'object'.`); }

      const classReport = Object.assign(new ClassReport(), object);

      if (classReport.errors.length > 0)
      {
         classReport.errors = classReport.errors.map((error) => AnalyzeError.parse(error));
      }

      if (classReport.methods.length > 0)
      {
         classReport.methods = classReport.methods.map((methodReport) => ClassMethodReport.parse(methodReport));
      }

      return classReport;
   }
}