diff --git a/lib/util/Components.js b/lib/util/Components.js index 5e78e664fb..7ede07799a 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -11,7 +11,12 @@ const variableUtil = require('./variable'); const pragmaUtil = require('./pragma'); const astUtil = require('./ast'); -const usedPropTypesAreEquivalent = (propA, propB) => { +function getId(node) { + return node && node.range.join(':'); +} + + +function usedPropTypesAreEquivalent(propA, propB) { if (propA.name === propB.name) { if (!propA.allNames && !propB.allNames) { return true; @@ -21,9 +26,9 @@ const usedPropTypesAreEquivalent = (propA, propB) => { return false; } return false; -}; +} -const mergeUsedPropTypes = (propsList, newPropsList) => { +function mergeUsedPropTypes(propsList, newPropsList) { const propsToAdd = []; newPropsList.forEach(newProp => { const newPropisAlreadyInTheList = propsList.some(prop => usedPropTypesAreEquivalent(prop, newProp)); @@ -32,143 +37,142 @@ const mergeUsedPropTypes = (propsList, newPropsList) => { } }); return propsList.concat(propsToAdd); -}; - +} /** * Components - * @class */ -function Components() { - this._list = {}; - this._getId = function(node) { - return node && node.range.join(':'); - }; -} +class Components { + constructor() { + this._list = {}; + } -/** - * Add a node to the components list, or update it if it's already in the list - * - * @param {ASTNode} node The AST node being added. - * @param {Number} confidence Confidence in the component detection (0=banned, 1=maybe, 2=yes) - * @returns {Object} Added component object - */ -Components.prototype.add = function(node, confidence) { - const id = this._getId(node); - if (this._list[id]) { - if (confidence === 0 || this._list[id].confidence === 0) { - this._list[id].confidence = 0; - } else { - this._list[id].confidence = Math.max(this._list[id].confidence, confidence); + /** + * Add a node to the components list, or update it if it's already in the list + * + * @param {ASTNode} node The AST node being added. + * @param {Number} confidence Confidence in the component detection (0=banned, 1=maybe, 2=yes) + * @returns {Object} Added component object + */ + add(node, confidence) { + const id = getId(node); + if (this._list[id]) { + if (confidence === 0 || this._list[id].confidence === 0) { + this._list[id].confidence = 0; + } else { + this._list[id].confidence = Math.max(this._list[id].confidence, confidence); + } + return this._list[id]; } + this._list[id] = { + node: node, + confidence: confidence + }; return this._list[id]; } - this._list[id] = { - node: node, - confidence: confidence - }; - return this._list[id]; -}; - -/** - * Find a component in the list using its node - * - * @param {ASTNode} node The AST node being searched. - * @returns {Object} Component object, undefined if the component is not found - */ -Components.prototype.get = function(node) { - const id = this._getId(node); - return this._list[id]; -}; -/** - * Update a component in the list - * - * @param {ASTNode} node The AST node being updated. - * @param {Object} props Additional properties to add to the component. - */ -Components.prototype.set = function(node, props) { - while (node && !this._list[this._getId(node)]) { - node = node.parent; - } - if (!node) { - return; - } - const id = this._getId(node); - let copyUsedPropTypes; - if (this._list[id]) { - // usedPropTypes is an array. _extend replaces existing array with a new one which caused issue #1309. - // preserving original array so it can be merged later on. - copyUsedPropTypes = this._list[id].usedPropTypes && this._list[id].usedPropTypes.slice(); - } - this._list[id] = util._extend(this._list[id], props); - if (this._list[id] && props.usedPropTypes) { - this._list[id].usedPropTypes = mergeUsedPropTypes(copyUsedPropTypes || [], props.usedPropTypes); + /** + * Find a component in the list using its node + * + * @param {ASTNode} node The AST node being searched. + * @returns {Object} Component object, undefined if the component is not found + */ + get(node) { + const id = getId(node); + return this._list[id]; } -}; -/** - * Return the components list - * Components for which we are not confident are not returned - * - * @returns {Object} Components list - */ -Components.prototype.list = function() { - const list = {}; - const usedPropTypes = {}; - // Find props used in components for which we are not confident - for (const i in this._list) { - if (!has(this._list, i) || this._list[i].confidence >= 2) { - continue; - } - let component = null; - let node = null; - node = this._list[i].node; - while (!component && node.parent) { + /** + * Update a component in the list + * + * @param {ASTNode} node The AST node being updated. + * @param {Object} props Additional properties to add to the component. + */ + set(node, props) { + while (node && !this._list[getId(node)]) { node = node.parent; - // Stop moving up if we reach a decorator - if (node.type === 'Decorator') { - break; - } - component = this.get(node); } - if (component) { - const newUsedProps = (this._list[i].usedPropTypes || []).filter(propType => !propType.node || propType.node.kind !== 'init'); - - const componentId = this._getId(component.node); - usedPropTypes[componentId] = (usedPropTypes[componentId] || []).concat(newUsedProps); + if (!node) { + return; + } + const id = getId(node); + let copyUsedPropTypes; + if (this._list[id]) { + // usedPropTypes is an array. _extend replaces existing array with a new one which caused issue #1309. + // preserving original array so it can be merged later on. + copyUsedPropTypes = this._list[id].usedPropTypes && this._list[id].usedPropTypes.slice(); + } + this._list[id] = util._extend(this._list[id], props); + if (this._list[id] && props.usedPropTypes) { + this._list[id].usedPropTypes = mergeUsedPropTypes(copyUsedPropTypes || [], props.usedPropTypes); } } - // Assign used props in not confident components to the parent component - for (const j in this._list) { - if (!has(this._list, j) || this._list[j].confidence < 2) { - continue; + + /** + * Return the components list + * Components for which we are not confident are not returned + * + * @returns {Object} Components list + */ + list() { + const list = {}; + const usedPropTypes = {}; + + // Find props used in components for which we are not confident + for (const i in this._list) { + if (!has(this._list, i) || this._list[i].confidence >= 2) { + continue; + } + let component = null; + let node = null; + node = this._list[i].node; + while (!component && node.parent) { + node = node.parent; + // Stop moving up if we reach a decorator + if (node.type === 'Decorator') { + break; + } + component = this.get(node); + } + if (component) { + const newUsedProps = (this._list[i].usedPropTypes || []).filter(propType => !propType.node || propType.node.kind !== 'init'); + + const componentId = getId(component.node); + usedPropTypes[componentId] = (usedPropTypes[componentId] || []).concat(newUsedProps); + } } - const id = this._getId(this._list[j].node); - list[j] = this._list[j]; - if (usedPropTypes[id]) { - list[j].usedPropTypes = (list[j].usedPropTypes || []).concat(usedPropTypes[id]); + + // Assign used props in not confident components to the parent component + for (const j in this._list) { + if (!has(this._list, j) || this._list[j].confidence < 2) { + continue; + } + const id = getId(this._list[j].node); + list[j] = this._list[j]; + if (usedPropTypes[id]) { + list[j].usedPropTypes = (list[j].usedPropTypes || []).concat(usedPropTypes[id]); + } } + return list; } - return list; -}; -/** - * Return the length of the components list - * Components for which we are not confident are not counted - * - * @returns {Number} Components list length - */ -Components.prototype.length = function() { - let length = 0; - for (const i in this._list) { - if (!has(this._list, i) || this._list[i].confidence < 2) { - continue; + /** + * Return the length of the components list + * Components for which we are not confident are not counted + * + * @returns {Number} Components list length + */ + length() { + let length = 0; + for (const i in this._list) { + if (!has(this._list, i) || this._list[i].confidence < 2) { + continue; + } + length++; } - length++; + return length; } - return length; -}; +} function componentRule(rule, context) { const createClass = pragmaUtil.getCreateClassFromContext(context); @@ -654,8 +658,8 @@ function componentRule(rule, context) { return updatedRuleInstructions; } -Components.detect = function(rule) { - return componentRule.bind(this, rule); -}; - -module.exports = Components; +module.exports = Object.assign(Components, { + detect(rule) { + return componentRule.bind(this, rule); + } +});