Skip to content

Commit

Permalink
Merge pull request #907 from bmish/require-computed-property-dependen…
Browse files Browse the repository at this point in the history
…cies-check-imports

Check imports in `require-computed-property-dependencies` rule
  • Loading branch information
bmish committed Aug 7, 2020
2 parents b673ed6 + 298a1c7 commit 7467c37
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 66 deletions.
69 changes: 40 additions & 29 deletions lib/rules/require-computed-property-dependencies.js
Expand Up @@ -9,24 +9,21 @@ const utils = require('../utils/utils');
const propertyGetterUtils = require('../utils/property-getter');
const computedPropertyDependentKeyUtils = require('../utils/computed-property-dependent-keys');
const assert = require('assert');
const { getImportIdentifier } = require('../utils/import');

/**
* Checks whether the node is an identifier and optionally, its name.
* Checks whether the node is an identifier with the given name.
*
* @param {ASTNode} node
* @param {string=} name
* @param {string} name
* @returns {boolean}
*/
function isIdentifier(node, name) {
if (!types.isIdentifier(node)) {
return false;
}

if (name) {
return node.name === name;
}

return true;
return node.name === name;
}

/**
Expand All @@ -39,10 +36,6 @@ function isIdentifier(node, name) {
* @returns {boolean}
*/
function isMemberExpression(node, objectName, propertyName) {
if (!objectName && !propertyName) {
return node && types.isMemberExpression(node);
}

return (
node &&
types.isMemberExpression(node) &&
Expand All @@ -56,10 +49,15 @@ function isMemberExpression(node, objectName, propertyName) {

/**
* @param {ASTNode} node
* @param {string} importedEmberName
* @param {string} importedComputedName
* @returns {boolean}
*/
function isEmberComputed(node) {
return isIdentifier(node, 'computed') || isMemberExpression(node, 'Ember', 'computed');
function isEmberComputed(node, importedEmberName, importedComputedName) {
return (
isIdentifier(node, importedComputedName) ||
isMemberExpression(node, importedEmberName, 'computed')
);
}

/**
Expand Down Expand Up @@ -119,15 +117,16 @@ function parseComputedDependencies(args) {
* or `this.get(…)`.
*
* @param {ASTNode} node
* @param {string} importedEmberName
* @returns {Array<ASTNode>}
*/
function findEmberGetCalls(node) {
function findEmberGetCalls(node, importedEmberName) {
const results = [];

new Traverser().traverse(node, {
enter(child) {
if (types.isCallExpression(child)) {
const dependency = extractEmberGetDependencies(child);
const dependency = extractEmberGetDependencies(child, importedEmberName);

if (dependency.length > 0) {
results.push(child);
Expand Down Expand Up @@ -212,9 +211,10 @@ function getArrayOrRest(args) {
* Extracts all static property keys used in the various forms of `Ember.get`.
*
* @param {ASTNode} call
* @param {string} importedEmberName
* @returns {Array<string>}
*/
function extractEmberGetDependencies(call) {
function extractEmberGetDependencies(call, importedEmberName) {
if (
isMemberExpression(call.callee, 'this', 'get') ||
isMemberExpression(call.callee, 'this', 'getWithDefault')
Expand All @@ -225,8 +225,8 @@ function extractEmberGetDependencies(call) {
return [firstArg.value];
}
} else if (
isMemberExpression(call.callee, 'Ember', 'get') ||
isMemberExpression(call.callee, 'Ember', 'getWithDefault')
isMemberExpression(call.callee, importedEmberName, 'get') ||
isMemberExpression(call.callee, importedEmberName, 'getWithDefault')
) {
const firstArg = call.arguments[0];
const secondArgument = call.arguments[1];
Expand All @@ -238,7 +238,7 @@ function extractEmberGetDependencies(call) {
return getArrayOrRest(call.arguments)
.filter(types.isStringLiteral)
.map((arg) => arg.value);
} else if (isMemberExpression(call.callee, 'Ember', 'getProperties')) {
} else if (isMemberExpression(call.callee, importedEmberName, 'getProperties')) {
const firstArg = call.arguments[0];
const rest = call.arguments.slice(1);

Expand Down Expand Up @@ -311,7 +311,10 @@ module.exports = {

let serviceNames = [];

function checkComputedDependencies(node, nodeArguments) {
let importedEmberName;
let importedComputedName;

function checkComputedDependencies(node, nodeArguments, importedEmberName) {
const declaredDependencies = parseComputedDependencies(nodeArguments);

if (!allowDynamicKeys) {
Expand All @@ -328,14 +331,12 @@ module.exports = {
);

const usedKeys1 = javascriptUtils.flatMap(
findEmberGetCalls(computedPropertyFunctionBody),
extractEmberGetDependencies
findEmberGetCalls(computedPropertyFunctionBody, importedEmberName),
(node) => extractEmberGetDependencies(node, importedEmberName)
);
const usedKeys2 = javascriptUtils.flatMap(
findThisGetCalls(computedPropertyFunctionBody),
(node) => {
return extractThisGetDependencies(node, context);
}
(node) => extractThisGetDependencies(node, context)
);
const usedKeys = [...usedKeys1, ...usedKeys2];

Expand Down Expand Up @@ -451,15 +452,25 @@ module.exports = {
serviceNames = requireServiceNames ? [] : findInjectedServiceNames(node);
},

ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/object') {
importedComputedName =
importedComputedName || getImportIdentifier(node, '@ember/object', 'computed');
}
},

Identifier(node) {
if (isEmberComputed(node)) {
checkComputedDependencies(node, []);
if (isEmberComputed(node, importedEmberName, importedComputedName)) {
checkComputedDependencies(node, [], importedEmberName);
}
},

CallExpression(node) {
if (isEmberComputed(node.callee)) {
checkComputedDependencies(node, node.arguments);
if (isEmberComputed(node.callee, importedEmberName, importedComputedName)) {
checkComputedDependencies(node, node.arguments, importedEmberName);
}
},
};
Expand Down

0 comments on commit 7467c37

Please sign in to comment.