Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Components into ES6 class syntax #1398

Merged
merged 6 commits into from
Nov 14, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
252 changes: 128 additions & 124 deletions lib/util/Components.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
});