typhonjs-escomplex-project
Version:
Provides project oriented AST processing for typhonjs-escomplex complexity reports.
329 lines (255 loc) • 12.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _ESComplexModule = require('typhonjs-escomplex-module/dist/ESComplexModule');
var _ESComplexModule2 = _interopRequireDefault(_ESComplexModule);
var _ModuleReport = require('typhonjs-escomplex-commons/dist/module/report/ModuleReport');
var _ModuleReport2 = _interopRequireDefault(_ModuleReport);
var _ProjectReport = require('typhonjs-escomplex-commons/dist/project/report/ProjectReport');
var _ProjectReport2 = _interopRequireDefault(_ProjectReport);
var _Plugins = require('./Plugins');
var _Plugins2 = _interopRequireDefault(_Plugins);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Provides a runtime to invoke ESComplexProject plugins for processing / metrics calculations of projects.
*/
var ESComplexProject = function () {
/**
* Initializes ESComplexProject.
*
* @param {object} pathModule - Provides an object which matches the Node path module. In particular the following
* entries must be provided:
* ```
* (string) sep - Provides the platform-specific path segment separator: `/` on POSIX & `\` on Windows.
*
* (function) dirname - Returns the directory name of a path, similar to the Unix dirname command.
*
* (function) extname - Returns the extension of the path, from the last occurance of the . (period) character to
* end of string in the last portion of the path.
*
* (function) relative - Returns the relative path from from to to.
*
* (function) resolve - Resolves a sequence of paths or path segments into an absolute path.
* ```
*
* @param {object} options - module and project options including user plugins to load including:
* ```
* (object) module - Provides an object hash of the following options for the module runtime:
* (boolean) loadDefaultPlugins - When false ESComplexModule will not load any default plugins.
* (Array<Object>) plugins - A list of ESComplexModule plugins that have already been instantiated.
*
* (object) project - Provides an object hash of the following options for the project runtime:
* (boolean) loadDefaultPlugins - When false ESComplexProject will not load any default plugins.
* (Array<Object>) plugins - A list of ESComplexProject plugins that have already been instantiated.
* ```
*
* @see https://nodejs.org/api/path.html
*/
function ESComplexProject(pathModule) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
(0, _classCallCheck3.default)(this, ESComplexProject);
// Verify essential Node path module API.
/* istanbul ignore if */
if ((typeof pathModule === 'undefined' ? 'undefined' : (0, _typeof3.default)(pathModule)) !== 'object') {
throw new TypeError('ctor error: `pathModule` is not an `object`.');
}
/* istanbul ignore if */
if (typeof pathModule.sep !== 'string') {
throw new TypeError('ctor error: `pathModule.sep` is not a `string`.');
}
/* istanbul ignore if */
if (typeof pathModule.dirname !== 'function') {
throw new TypeError('ctor error: `pathModule.dirname` is not a `function`.');
}
/* istanbul ignore if */
if (typeof pathModule.extname !== 'function') {
throw new TypeError('ctor error: `pathModule.extname` is not a `function`.');
}
/* istanbul ignore if */
if (typeof pathModule.relative !== 'function') {
throw new TypeError('ctor error: `pathModule.relative` is not a `function`.');
}
/* istanbul ignore if */
if (typeof pathModule.resolve !== 'function') {
throw new TypeError('ctor error: `pathModule.resolve` is not a `function`.');
}
/* istanbul ignore if */
if ((typeof options === 'undefined' ? 'undefined' : (0, _typeof3.default)(options)) !== 'object') {
throw new TypeError('ctor error: `options` is not an `object`.');
}
/**
* Stores a module which matches the NodeJS path module API.
* @type {Object}
* @private
*/
this._pathModule = pathModule;
/**
* Provides dispatch methods to all module plugins.
* @type {Plugins}
* @private
*/
this._plugins = new _Plugins2.default(options.project);
/**
* Stores the ESComplexModule instance used for generating module reports.
* @type {ESComplexModule}
* @private
*/
this._escomplexModule = new _ESComplexModule2.default(options.module);
}
/**
* Processes the given modules and calculates project metrics via plugins.
*
* @param {Array<object>} modules - Array of object hashes containing `ast` and `srcPath` entries. Optionally
* `srcPathAlias` and `filePath` entries may also be provided.
*
* @param {object} options - (Optional) project processing options.
*
* @returns {ProjectReport}
*/
(0, _createClass3.default)(ESComplexProject, [{
key: 'analyze',
value: function analyze(modules) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!Array.isArray(modules)) {
throw new TypeError('analyze error: `modules` is not an `array`.');
}
/* istanbul ignore if */
if ((typeof options === 'undefined' ? 'undefined' : (0, _typeof3.default)(options)) !== 'object') {
throw new TypeError('analyze error: `options` is not an `object`.');
}
var settings = this._plugins.onConfigure(options);
this._plugins.onProjectStart(this._pathModule, settings);
var moduleReports = modules.map(function (m) {
var moduleReport = void 0;
if (typeof m.srcPath !== 'string' || m.srcPath === '') {
throw new Error('analyze error: Invalid `srcPath`');
}
try {
moduleReport = _this._escomplexModule.analyze(m.ast, options);
// Set any supplied filePath / srcPath / srcPathAlias data.
moduleReport.filePath = m.filePath;
moduleReport.srcPath = m.srcPath;
moduleReport.srcPathAlias = m.srcPathAlias;
return moduleReport;
} catch (error) {
// Include the module srcPath to distinguish the actual offending entry.
/* istanbul ignore next */
error.message = m.srcPath + ': ' + error.message;
/* istanbul ignore next */
throw error;
}
}, []);
var projectReport = new _ProjectReport2.default(moduleReports, settings);
if (settings.skipCalculation) {
return projectReport;
}
// Allow all plugins to have a calculation pass at the project report.
this._plugins.onProjectCalculate(projectReport, this._pathModule, settings);
// Allow all plugins to have a pass at the project report to calculate any averaged data.
this._plugins.onProjectAverage(projectReport, this._pathModule, settings);
// Allow all plugins to have a pass at the project report to calculate any metrics that depend on averaged data.
this._plugins.onProjectPostAverage(projectReport, this._pathModule, settings);
// Allow all plugins to clean up any resources as necessary.
this._plugins.onProjectEnd(projectReport, this._pathModule, settings);
return projectReport.finalize();
}
/**
* Processes an existing ProjectReport instance and calculates metrics via plugins.
*
* @param {ProjectReport} projectReport - An instance of ProjectReport with a `modules` entry that is an Array of
* ModuleReports.
*
* @param {object} options - (Optional) project processing options.
*
* @returns {ProjectReport}
*/
}, {
key: 'process',
value: function process(projectReport) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
/* istanbul ignore if */
if (!(projectReport instanceof _ProjectReport2.default)) {
throw new TypeError('process error: `projectReport` is not an instance of ProjectReport.');
}
/* istanbul ignore if */
if ((typeof options === 'undefined' ? 'undefined' : (0, _typeof3.default)(options)) !== 'object') {
throw new TypeError('process error: `options` is not an `object`.');
}
/* istanbul ignore if */
if (projectReport.modules.length > 0 && !(projectReport.modules[0] instanceof _ModuleReport2.default)) {
throw new TypeError('process error: `projectReport.modules` does not appear to contain `ModuleReport` entries.');
}
var settings = this._plugins.onConfigure(options);
// Override any stored settings given new options / settings set during processing reports.
projectReport.settings = settings;
this._plugins.onProjectStart(this._pathModule, settings);
// Allow all plugins to have a calculation pass at the project report.
this._plugins.onProjectCalculate(projectReport, this._pathModule, settings);
// Allow all plugins to have a pass at the project report to calculate any averaged data.
this._plugins.onProjectAverage(projectReport, this._pathModule, settings);
// Allow all plugins to have a pass at the project report to calculate any metrics that depend on averaged data.
this._plugins.onProjectPostAverage(projectReport, this._pathModule, settings);
// Allow all plugins to clean up any resources as necessary.
this._plugins.onProjectEnd(projectReport, this._pathModule, settings);
return projectReport.finalize();
}
// Asynchronous Promise based methods ----------------------------------------------------------------------------
/**
* Wraps in a Promise processing the given modules and calculates metrics via plugins.
*
* @param {Array<object>} modules - Array of object hashes containing `ast` and `srcPath` entries. Optionally
* `srcPathAlias` and `filePath` entries may also be provided.
*
* @param {object} options - project processing options
*
* @returns {Promise<ProjectReport>}
*/
}, {
key: 'analyzeAsync',
value: function analyzeAsync(modules) {
var _this2 = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new _promise2.default(function (resolve, reject) {
try {
resolve(_this2.analyze(modules, options));
} catch (err) {
/* istanbul ignore next */reject(err);
}
});
}
/**
* Wraps in a Promise processing of existing ProjectReport instance and calculates metrics via plugins.
*
* @param {ProjectReport} projectReport - An instance of ProjectReport.
* @param {object} options - (Optional) project processing options.
*
* @returns {Promise<ProjectReport>}
*/
}, {
key: 'processAsync',
value: function processAsync(projectReport) {
var _this3 = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new _promise2.default(function (resolve, reject) {
try {
resolve(_this3.process(projectReport, options));
} catch (err) {
/* istanbul ignore next */reject(err);
}
});
}
}]);
return ESComplexProject;
}();
exports.default = ESComplexProject;
module.exports = exports['default'];