UNPKG

escomplex-plugin-syntax-estree

Version:

Provides a plugin for typhonjs-escomplex module processing which loads syntax definitions for trait resolution for ESTree AST.

1,239 lines (1,055 loc) 65.6 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _AbstractSyntaxLoader2 = require('typhonjs-escomplex-commons/dist/module/plugin/syntax/AbstractSyntaxLoader'); var _AbstractSyntaxLoader3 = _interopRequireDefault(_AbstractSyntaxLoader2); var _ASTGenerator = require('typhonjs-escomplex-commons/dist/utils/ast/ASTGenerator'); var _ASTGenerator2 = _interopRequireDefault(_ASTGenerator); var _HalsteadArray = require('typhonjs-escomplex-commons/dist/module/traits/HalsteadArray'); var _HalsteadArray2 = _interopRequireDefault(_HalsteadArray); var _TraitUtil = require('typhonjs-escomplex-commons/dist/module/traits/TraitUtil'); var _TraitUtil2 = _interopRequireDefault(_TraitUtil); var _actualize = require('typhonjs-escomplex-commons/dist/module/traits/actualize'); var _actualize2 = _interopRequireDefault(_actualize); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Provides an typhonjs-escomplex-module / ESComplexModule plugin which loads syntax definitions for trait resolution * for all ESTree AST nodes up to and including ES6. * * @see https://www.npmjs.com/package/typhonjs-escomplex-module */ var PluginSyntaxESTree = function (_AbstractSyntaxLoader) { (0, _inherits3.default)(PluginSyntaxESTree, _AbstractSyntaxLoader); function PluginSyntaxESTree() { (0, _classCallCheck3.default)(this, PluginSyntaxESTree); return (0, _possibleConstructorReturn3.default)(this, (PluginSyntaxESTree.__proto__ || (0, _getPrototypeOf2.default)(PluginSyntaxESTree)).apply(this, arguments)); } (0, _createClass3.default)(PluginSyntaxESTree, [{ key: 'onConfigure', // ESComplexModule plugin callbacks ------------------------------------------------------------------------------ /** * Loads any default settings that are not already provided by any user options. * * @param {object} ev - escomplex plugin event data. * * The following options are: * ``` * (boolean) commonjs - Boolean indicating that source code being processed is CommonJS; defaults to false. * * (function) dependencyResolver - Provides a function to resolve dynamic dependencies; defaults to undefined. * * (boolean|object) esmImportExport - As a boolean indicating whether ES Modules import / export statements * contribute to modules logical SLOC & Halstead operators / operands; defaults * to false. As an object separate boolean entries to set logical SLOC (lloc) * and operators / operands (halstead) are available to set these parameters * separately. * * (boolean) forin - Boolean indicating whether for...in / for...of loops should be considered a source of * cyclomatic complexity; defaults to false. * * (boolean) logicalor - Boolean indicating whether operator || should be considered a source of cyclomatic * complexity; defaults to true. * * (boolean) switchcase - Boolean indicating whether switch statements should be considered a source of cyclomatic * complexity; defaults to true. * * (boolean|object) templateExpressions - As a boolean indicating whether template literal expressions * contribute to logical SLOC & Halstead operators / operands; defaults * to `true`. As an object separate boolean entries to set logical SLOC (lloc) * and operators / operands (halstead) are available to set these parameters * separately. When `lloc` is true tagged template expressions * increment lloc by 1. If `halstead` is true then operators are added for '``' * and each instance of a `${...}` expression. * (boolean) trycatch - Boolean indicating whether catch clauses should be considered a source of cyclomatic * complexity; defaults to false. * ``` */ value: function onConfigure(ev) { ev.data.settings.commonjs = typeof ev.data.options.commonjs === 'boolean' ? ev.data.options.commonjs : false; ev.data.settings.dependencyResolver = typeof ev.data.options.dependencyResolver === 'function' ? ev.data.options.dependencyResolver : void 0; if ((0, _typeof3.default)(ev.data.options.esmImportExport) === 'object') { ev.data.settings.esmImportExport = { halstead: typeof ev.data.options.esmImportExport.halstead === 'boolean' ? ev.data.options.esmImportExport.halstead : false, lloc: typeof ev.data.options.esmImportExport.lloc === 'boolean' ? ev.data.options.esmImportExport.lloc : false }; } else { // Catch all boolean to set `esmImportExport.halstead` & `esmImportExport.lloc` if a boolean is supplied. var value = typeof ev.data.options.esmImportExport === 'boolean' ? ev.data.options.esmImportExport : false; ev.data.settings.esmImportExport = { halstead: value, lloc: value }; } ev.data.settings.forin = typeof ev.data.options.forin === 'boolean' ? ev.data.options.forin : false; ev.data.settings.logicalor = typeof ev.data.options.logicalor === 'boolean' ? ev.data.options.logicalor : true; ev.data.settings.switchcase = typeof ev.data.options.switchcase === 'boolean' ? ev.data.options.switchcase : true; if ((0, _typeof3.default)(ev.data.options.templateExpression) === 'object') { ev.data.settings.templateExpression = { halstead: typeof ev.data.options.templateExpression.halstead === 'boolean' ? ev.data.options.templateExpression.halstead : true, lloc: typeof ev.data.options.templateExpression.lloc === 'boolean' ? ev.data.options.templateExpression.lloc : true }; } else { // Catch all boolean to set `templateExpression.halstead` & `templateExpression.lloc` if a boolean is supplied. var _value = typeof ev.data.options.templateExpression === 'boolean' ? ev.data.options.templateExpression : true; ev.data.settings.templateExpression = { halstead: _value, lloc: _value }; } ev.data.settings.trycatch = typeof ev.data.options.trycatch === 'boolean' ? ev.data.options.trycatch : false; } // Core / ES5 ESTree AST nodes ----------------------------------------------------------------------------------- /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#arrayexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ArrayExpression', value: function ArrayExpression() { return (0, _actualize2.default)(0, 0, function (node) { var operators = ['[]']; if (Array.isArray(node.elements) && node.elements.length > 0) // Add length - 1 commas { operators.push.apply(operators, (0, _toConsumableArray3.default)(new Array(node.elements.length - 1).fill(','))); } return operators; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#assignmentexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'AssignmentExpression', value: function AssignmentExpression() { return (0, _actualize2.default)(function (node, parent) { // Handle multiple assignment such as `a = b = c = 1` which resolves logical SLOC of 3. // The top most `ExpressionStatement` already provides 1 lloc and `AssignmentExpression` for 'c' & '1' are // additionally counted as additional lloc. return parent && parent.type !== 'ExpressionStatement' ? 1 : 0; }, 0, function (node) { return node.operator; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#blockstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'BlockStatement', value: function BlockStatement() { return (0, _actualize2.default)(0, 0); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#binaryexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'BinaryExpression', value: function BinaryExpression() { return (0, _actualize2.default)(0, 0, function (node) { return node.operator; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#breakstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'BreakStatement', value: function BreakStatement() { return (0, _actualize2.default)(1, 0, 'break'); } /** * ES5 Node * * Processes CommonJS dependencies if settings.commonjs is set to true. An optional function * settings.dependencyResolver may be used to resolve dynamic dependencies. * @param {object} settings - escomplex settings * * @see https://github.com/estree/estree/blob/master/es5.md#callexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'CallExpression', value: function CallExpression(settings) { return (0, _actualize2.default)(function (node, parent) // lloc { // Handles nested CallExpression nodes. Since ExpressionStatement provides 1 lloc already the first // CallExpression ignores posting an additional lloc; subsequent CallExpression nodes do contribute 1 lloc. // Likewise the first CallExpression after a YieldExpression doesn't contribute 1 lloc. return parent && parent.type !== 'ExpressionStatement' && parent.type !== 'YieldExpression' ? 1 : 0; }, 0, // cyclomatic '()', // operators void 0, // operands void 0, // ignoreKeys void 0, // newScope function (node) { // Only process CJS dependencies if settings.commonjs is true. if (settings.commonjs && node.callee.type === 'Identifier' && node.callee.name === 'require' && node.arguments.length === 1) { var dependency = node.arguments[0]; var dependencyPath = '* dynamic dependency *'; if (dependency.type === 'Literal' || dependency.type === 'StringLiteral') { dependencyPath = typeof settings.dependencyResolver === 'function' ? settings.dependencyResolver(dependency.value) : dependency.value; } return { line: node.loc.start.line, path: dependencyPath, type: 'cjs' }; } }); } /** * ES5 Node * @param {object} settings - escomplex settings * @see https://github.com/estree/estree/blob/master/es5.md#catchclause * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'CatchClause', value: function CatchClause(settings) { return (0, _actualize2.default)(1, function () { return settings.trycatch ? 1 : 0; }, 'catch'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#conditionalexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ConditionalExpression', value: function ConditionalExpression() { return (0, _actualize2.default)(0, 1, ':?'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#continuestatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ContinueStatement', value: function ContinueStatement() { return (0, _actualize2.default)(1, 0, 'continue'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#dowhilestatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'DoWhileStatement', value: function DoWhileStatement() { return (0, _actualize2.default)(2, function (node) { return node.test ? 1 : 0; }, 'dowhile'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#emptystatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'EmptyStatement', value: function EmptyStatement() { return (0, _actualize2.default)(0, 0); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#expressionstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ExpressionStatement', value: function ExpressionStatement() { return (0, _actualize2.default)(function (node) { // Ignore adding 1 lloc when the child expression is an ArrowFunctionExpression which is invalid / no-op. return (0, _typeof3.default)(node.expression) === 'object' && node.expression.type !== 'ArrowFunctionExpression' ? 1 : 0; }, 0); } /** * ES5 Node * @param {object} settings - escomplex settings * @see https://github.com/estree/estree/blob/master/es5.md#forinstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ForInStatement', value: function ForInStatement(settings) { // return actualize(1, () => { return settings.forin ? 1 : 0; }, 'forin'); return (0, _actualize2.default)(1, function () { return settings.forin ? 1 : 0; }, function (node) { var operators = ['forin']; var childNodes = []; if (node.left) { childNodes.push(node.left); } if (node.right) { childNodes.push(node.right); } if (childNodes.length > 0) { operators.push.apply(operators, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parseNodes(childNodes).operators)); } return operators; }, function (node) { var operands = []; var childNodes = []; if (node.left) { childNodes.push(node.left); } if (node.right) { childNodes.push(node.right); } if (childNodes.length > 0) { operands.push.apply(operands, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parseNodes(childNodes).operands)); } return operands; }, ['left', 'right']); } /** * ES5 Node * * Note: ASTGenerator is necessary to pick up operators / operands of `init, test, update` child nodes while * excluding traversal / LLOC counts for these nodes. * * @see https://github.com/estree/estree/blob/master/es5.md#forstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ForStatement', value: function ForStatement() { return (0, _actualize2.default)(1, function (node) { return node.test ? 1 : 0; }, function (node) { var operators = ['for']; var childNodes = []; if (node.init) { childNodes.push(node.init); } if (node.test) { childNodes.push(node.test); } if (node.update) { childNodes.push(node.update); } if (childNodes.length > 0) { operators.push.apply(operators, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parseNodes(childNodes).operators)); } return operators; }, function (node) { var operands = []; var childNodes = []; if (node.init) { childNodes.push(node.init); } if (node.test) { childNodes.push(node.test); } if (node.update) { childNodes.push(node.update); } if (childNodes.length > 0) { operands.push.apply(operands, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parseNodes(childNodes).operands)); } return operands; }, ['init', 'test', 'update']); } /** * ES5 Node * * Note: The function name (node.id) is returned as an operand and excluded from traversal as to not be included in * the function operand calculations. * * @see https://github.com/estree/estree/blob/master/es5.md#functiondeclaration * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'FunctionDeclaration', value: function FunctionDeclaration() { return (0, _actualize2.default)(0, 0, void 0, void 0, ['id', 'params', 'defaults'], function (node, parent) { var name = s_SAFE_COMPUTED_NAME(node, parent); var operands = s_SAFE_COMPUTED_OPERANDS(node, parent); var operators = []; if (parent && parent.type === 'MethodDefinition') { if (typeof node.generator === 'boolean' && node.generator) { operators.push('function*'); } if (typeof parent.computed === 'boolean' && parent.computed) { operators.push.apply(operators, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parse(parent.key).operators)); } } else { operators.push(typeof node.generator === 'boolean' && node.generator ? 'function*' : 'function'); } var paramNames = []; // Parse params; must use ASTGenerator if (Array.isArray(node.params)) { node.params.forEach(function (param) { var parsedParams = _ASTGenerator2.default.parse(param); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsedParams.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsedParams.operators)); // For param names only the left hand node of AssignmentPattern must be considered. if (param.type === 'AssignmentPattern') { paramNames.push.apply(paramNames, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parse(param.left).operands)); } else { paramNames.push.apply(paramNames, (0, _toConsumableArray3.default)(parsedParams.operands)); } }); } // Esprima default values; param default values are stored in a non-standard `defaults` node. if (Array.isArray(node.defaults)) { node.defaults.forEach(function (value) { if (value !== null && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { var parsedParams = _ASTGenerator2.default.parse(value); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsedParams.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsedParams.operators)); operators.push('='); // Must also manually push '=' } }); } return { type: 'method', name: name, cyclomatic: 1, lineStart: node.loc.start.line, lineEnd: node.loc.end.line, lloc: 1, operands: new _HalsteadArray2.default('operands', operands), operators: new _HalsteadArray2.default('operators', operators), paramNames: paramNames }; }); } // FunctionDeclaration() // { // return actualize(1, 0, (node, parent) => // { // const operators = parent && parent.type === 'MethodDefinition' && typeof parent.computed === 'boolean' && // parent.computed ? [...ASTGenerator.parse(parent.key).operators] : []; // // if (parent && parent.type === 'MethodDefinition') // { // if (typeof node.generator === 'boolean' && node.generator) // { // operators.push('function*'); // } // } // else // { // operators.push(typeof node.generator === 'boolean' && node.generator ? 'function*' : 'function'); // } // // return operators; // }, // (node, parent) => { return s_SAFE_COMPUTED_OPERANDS(node, parent); }, // 'id', // (node, parent) => // { // return { // type: 'method', // name: s_SAFE_COMPUTED_NAME(node, parent), // lineStart: node.loc.start.line, // lineEnd: node.loc.end.line, // paramCount: node.params.length // }; // }); // } /** * ES5 Node * * Note: The function name (node.id) is returned as an operand and excluded from traversal as to not be included in * the function operand calculations. * * @see https://github.com/estree/estree/blob/master/es5.md#functionexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'FunctionExpression', value: function FunctionExpression() { return (0, _actualize2.default)(0, 0, void 0, void 0, ['id', 'params', 'defaults'], function (node, parent) { var name = s_SAFE_COMPUTED_NAME(node, parent); var operands = s_SAFE_COMPUTED_OPERANDS(node, parent); var operators = []; if (parent && parent.type === 'MethodDefinition') { if (typeof node.generator === 'boolean' && node.generator) { operators.push('function*'); } if (typeof parent.computed === 'boolean' && parent.computed) { operators.push.apply(operators, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parse(parent.key).operators)); } } else { operators.push(typeof node.generator === 'boolean' && node.generator ? 'function*' : 'function'); } var paramNames = []; // Parse params; must use ASTGenerator if (Array.isArray(node.params)) { node.params.forEach(function (param) { var parsedParams = _ASTGenerator2.default.parse(param); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsedParams.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsedParams.operators)); // For param names only the left hand node of AssignmentPattern must be considered. if (param.type === 'AssignmentPattern') { paramNames.push.apply(paramNames, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parse(param.left).operands)); } else { paramNames.push.apply(paramNames, (0, _toConsumableArray3.default)(parsedParams.operands)); } }); } // Esprima default values; param default values are stored in a non-standard `defaults` node. if (Array.isArray(node.defaults)) { node.defaults.forEach(function (value) { if (value !== null && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { var parsedParams = _ASTGenerator2.default.parse(value); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsedParams.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsedParams.operators)); operators.push('='); // Must also manually push '=' } }); } return { type: 'method', name: name, cyclomatic: 1, lineStart: node.loc.start.line, lineEnd: node.loc.end.line, lloc: 1, operands: new _HalsteadArray2.default('operands', operands), operators: new _HalsteadArray2.default('operators', operators), paramNames: paramNames }; }); } // FunctionExpression() // { // return actualize(1, 0, (node, parent) => // { // const operators = parent && parent.type === 'MethodDefinition' && typeof parent.computed === 'boolean' && // parent.computed ? [...ASTGenerator.parse(parent.key).operators] : []; // // if (parent && parent.type === 'MethodDefinition') // { // if (typeof node.generator === 'boolean' && node.generator) // { // operators.push('function*'); // } // } // else // { // operators.push(typeof node.generator === 'boolean' && node.generator ? 'function*' : 'function'); // } // // return operators; // }, // (node, parent) => // { // return s_SAFE_COMPUTED_OPERANDS(node, parent); // }, // 'id', // (node, parent) => // { // return { // type: 'method', // name: s_SAFE_COMPUTED_NAME(node, parent), // lineStart: node.loc.start.line, // lineEnd: node.loc.end.line, // paramCount: node.params.length // }; // }); // } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#identifier * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'Identifier', value: function Identifier() { return (0, _actualize2.default)(0, 0, void 0, function (node) { return node.name; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#ifstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'IfStatement', value: function IfStatement() { return (0, _actualize2.default)(function (node) { return node.alternate ? 2 : 1; }, 1, ['if', { identifier: 'else', filter: function filter(node) { return !!node.alternate; } }]); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#labeledstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'LabeledStatement', value: function LabeledStatement() { return (0, _actualize2.default)(0, 0); } /** * ES5 Node * * Avoid conflicts between string literals and identifiers. * * @see https://github.com/estree/estree/blob/master/es5.md#literal * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'Literal', value: function Literal() { return (0, _actualize2.default)(0, 0, void 0, function (node) { var operands = []; if ((0, _typeof3.default)(node.regex) === 'object' && typeof node.raw !== 'undefined') { operands.push(node.raw); } else { operands.push(typeof node.value === 'string' ? '"' + node.value + '"' : node.value); } return operands; }); } /** * ES5 Node * @param {object} settings - escomplex settings * @see https://github.com/estree/estree/blob/master/es5.md#logicalexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'LogicalExpression', value: function LogicalExpression(settings) { return (0, _actualize2.default)(0, function (node) { var isAnd = node.operator === '&&'; var isOr = node.operator === '||'; return isAnd || settings.logicalor && isOr ? 1 : 0; }, function (node) { return node.operator; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#memberexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'MemberExpression', value: function MemberExpression() { return (0, _actualize2.default)(0, 0, function (node) { return typeof node.computed === 'boolean' && node.computed ? '[]' : '.'; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#newexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'NewExpression', value: function NewExpression() { return (0, _actualize2.default)(function (node) { return node.callee.type === 'FunctionExpression' ? 1 : 0; }, 0, 'new'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#objectexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ObjectExpression', value: function ObjectExpression() { return (0, _actualize2.default)(0, 0, '{}'); } /** * ES5 Node * * Note that w/ ES6+ `:` may be omitted and the Property node defines `shorthand` to indicate this case. * * @see https://github.com/estree/estree/blob/master/es5.md#property * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'Property', value: function Property() { return (0, _actualize2.default)(1, 0, function (node) { return typeof node.shorthand === 'undefined' ? ':' : typeof node.shorthand === 'boolean' && !node.shorthand ? ':' : void 0; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#returnstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ReturnStatement', value: function ReturnStatement() { return (0, _actualize2.default)(1, 0, 'return'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#sequenceexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'SequenceExpression', value: function SequenceExpression() { return (0, _actualize2.default)(0, 0); } /** * ES5 Node * @param {object} settings - escomplex settings * @see https://github.com/estree/estree/blob/master/es5.md#switchcase * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'SwitchCase', value: function SwitchCase(settings) { return (0, _actualize2.default)(1, function (node) { return settings.switchcase && node.test ? 1 : 0; }, function (node) { return node.test ? 'case' : 'default'; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#switchstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'SwitchStatement', value: function SwitchStatement() { return (0, _actualize2.default)(1, 0, 'switch'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#thisexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ThisExpression', value: function ThisExpression() { return (0, _actualize2.default)(0, 0, 'this'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#throwstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ThrowStatement', value: function ThrowStatement() { return (0, _actualize2.default)(1, 0, 'throw'); } /** * ES5 Node * * Note: esprima has duplicate nodes the catch block; `handler` is the actual ESTree spec. * * @see https://github.com/estree/estree/blob/master/es5.md#trystatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'TryStatement', value: function TryStatement() { return (0, _actualize2.default)(1, 0, function (node) { return node.finalizer ? ['try', 'finally'] : ['try']; }, void 0, ['guardedHandlers', 'handlers']); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#unaryexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'UnaryExpression', value: function UnaryExpression() { return (0, _actualize2.default)(0, 0, function (node) { return node.operator + ' (' + (node.prefix ? 'pre' : 'post') + 'fix)'; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#updateexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'UpdateExpression', value: function UpdateExpression() { return (0, _actualize2.default)(0, 0, function (node) { return node.operator + ' (' + (node.prefix ? 'pre' : 'post') + 'fix)'; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#variabledeclaration * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'VariableDeclaration', value: function VariableDeclaration() { return (0, _actualize2.default)(0, 0, function (node) { return node.kind; }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#variabledeclarator * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'VariableDeclarator', value: function VariableDeclarator() { return (0, _actualize2.default)(1, 0, { identifier: '=', filter: function filter(node) { return !!node.init; } }); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#whilestatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'WhileStatement', value: function WhileStatement() { return (0, _actualize2.default)(1, function (node) { return node.test ? 1 : 0; }, 'while'); } /** * ES5 Node * @see https://github.com/estree/estree/blob/master/es5.md#withstatement * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'WithStatement', value: function WithStatement() { return (0, _actualize2.default)(1, 0, 'with'); } // ES6 ESTree AST nodes ------------------------------------------------------------------------------------------ /** * ES6 Node * @see https://github.com/estree/estree/blob/master/es2015.md#assignmentpattern * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'AssignmentPattern', value: function AssignmentPattern() { return (0, _actualize2.default)(1, 0, function (node) { return node.operator; }); } /** * ES6 Node * @see https://github.com/estree/estree/blob/master/es2015.md#arraypattern * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ArrayPattern', value: function ArrayPattern() { return (0, _actualize2.default)(0, 0, function (node) { var operators = ['[]']; if (Array.isArray(node.elements) && node.elements.length > 0) // Add length - 1 commas { operators.push.apply(operators, (0, _toConsumableArray3.default)(new Array(node.elements.length - 1).fill(','))); } return operators; }); } /** * ES6 Node * * Note: If the parent node is an ExpressionStatement the arrow function is essentially a no-op / invalid. In this * case no metrics are gathered, but a method is still registered with no data. Further analysis looking for methods * with no logical SLOC will reveal this case. * * @see https://github.com/estree/estree/blob/master/es2015.md#arrowfunctionexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ArrowFunctionExpression', value: function ArrowFunctionExpression() { return (0, _actualize2.default)(0, 0, void 0, void 0, function (node, parent) { // If not valid do not traverse any children. return parent && parent.type !== 'ExpressionStatement' ? ['id', 'params', 'defaults'] : null; }, function (node, parent) { var isValid = parent && parent.type !== 'ExpressionStatement'; var name = _TraitUtil2.default.safeName(node.id); var operands = []; var operators = isValid ? ['function=>'] : []; var paramNames = []; // Parse params; must use ASTGenerator if (isValid && Array.isArray(node.params)) { node.params.forEach(function (param) { var parsedParams = _ASTGenerator2.default.parse(param); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsedParams.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsedParams.operators)); // For param names only the left hand node of AssignmentPattern must be considered. if (param.type === 'AssignmentPattern') { paramNames.push.apply(paramNames, (0, _toConsumableArray3.default)(_ASTGenerator2.default.parse(param.left).operands)); } else { paramNames.push.apply(paramNames, (0, _toConsumableArray3.default)(parsedParams.operands)); } }); } // Esprima default values; param default values are stored in a non-standard `defaults` node. if (isValid && Array.isArray(node.defaults)) { node.defaults.forEach(function (value) { if (value !== null && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { var parsedParams = _ASTGenerator2.default.parse(value); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsedParams.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsedParams.operators)); operators.push('='); // Must also manually push '=' } }); } return { type: 'method', name: name, cyclomatic: isValid ? 1 : 0, lineStart: node.loc.start.line, lineEnd: node.loc.end.line, lloc: isValid ? 1 : 0, operands: isValid ? new _HalsteadArray2.default('operands', operands) : void 0, operators: isValid ? new _HalsteadArray2.default('operators', operators) : void 0, paramNames: paramNames, // ArrowFunctionExpressions without brackets have an implicit `return` expression so post increment lloc. postLloc: isValid && (0, _typeof3.default)(node.body) === 'object' && node.body.type !== 'BlockStatement' ? 1 : 0 // NOTE (altered 12/8/18): ESTree has expression entry which was removed in Babel Parser / 7.0 so // node.body.type must be checked to determine if an expression or block / return statement. // Reference: https://github.com/babel/babel/issues/6773 // postLloc: isValid && typeof node.expression === 'boolean' && node.expression ? 1 : 0 }; }); } /** * ES6 Node * @see https://github.com/estree/estree/blob/master/es2015.md#classbody * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ClassBody', value: function ClassBody() { return (0, _actualize2.default)(0, 0); } // /** // * ES6 Node // * @see https://github.com/estree/estree/blob/master/es2015.md#classdeclaration // * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} // */ // ClassDeclaration() // { // return actualize(1, 0, 'class', void 0, void 0, (node) => // { // return { // type: 'class', // name: TraitUtil.safeName(node.id), // lineStart: node.loc.start.line, // lineEnd: node.loc.end.line // }; // }); // } // // /** // * ES6 Node // * @see https://github.com/estree/estree/blob/master/es2015.md#classexpression // * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} // */ // ClassExpression() // { // return actualize(1, 0, 'class', void 0, void 0, (node) => // { // return { // type: 'class', // name: TraitUtil.safeName(node.id), // lineStart: node.loc.start.line, // lineEnd: node.loc.end.line // }; // }); // } /** * ES6 Node * @see https://github.com/estree/estree/blob/master/es2015.md#classdeclaration * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ClassDeclaration', value: function ClassDeclaration() { return (0, _actualize2.default)(0, 0, void 0, void 0, ['id', 'superClass'], function (node) { var name = _TraitUtil2.default.safeName(node.id); var operands = name !== '<anonymous>' ? [name] : []; var operators = ['class']; var superClassName = void 0; if (typeof node.superClass !== 'undefined' && node.superClass !== null) { var parsed = _ASTGenerator2.default.parse(node.superClass); operators.push('extends'); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsed.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsed.operators)); // The following will pick up a Identifier or a computed value (string); computed expressions return // `<computed~expression>`. superClassName = node.superClass.type === 'Identifier' ? _TraitUtil2.default.safeName(node.superClass) : '<computed~' + parsed.source + '>'; } return { type: 'class', name: name, superClassName: superClassName, lineStart: node.loc.start.line, lineEnd: node.loc.end.line, lloc: 1, operands: new _HalsteadArray2.default('operands', operands), operators: new _HalsteadArray2.default('operators', operators) }; }); } /** * ES6 Node * @see https://github.com/estree/estree/blob/master/es2015.md#classexpression * @returns {{lloc: *, cyclomatic: *, operators: *, operands: *, ignoreKeys: *, newScope: *, dependencies: *}} */ }, { key: 'ClassExpression', value: function ClassExpression() { return (0, _actualize2.default)(0, 0, void 0, void 0, ['id', 'superClass'], function (node) { var name = _TraitUtil2.default.safeName(node.id); var operands = name !== '<anonymous>' ? [name] : []; var operators = ['class']; var superClassName = void 0; if (typeof node.superClass !== 'undefined' && node.superClass !== null) { var parsed = _ASTGenerator2.default.parse(node.superClass); operators.push('extends'); operands.push.apply(operands, (0, _toConsumableArray3.default)(parsed.operands)); operators.push.apply(operators, (0, _toConsumableArray3.default)(parsed.operators)); // The following will pick up a Identifier or a computed value (string); computed expressions return // `<computed~expression>`. superClassName = node.superClass.type === 'Identifier' ? _TraitUtil2.default.safeName(node.superClass) : '<computed~' + parsed.source + '>'; } return { type: 'class', name: _TraitUtil2.default.safeName(node.id), superClassName: superClassName, lineStart: node.loc.start.line, lineEnd: node.loc.end.line, lloc: 1, operands: new _HalsteadArray2.default('operands', operands), operators: new _HalsteadArray2.default('operators', operators) }; }); } /** * ES6 Node * @param {object} settings - Runtime settings of escomplex. * @see https://github.com/estree/estree/blob/m