Skip to content

Commit

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

Check imported get/getProperties/getWithDefault functions for missing dependencies in `require-computed-property-dependencies` rule
  • Loading branch information
bmish committed Aug 7, 2020
2 parents 7467c37 + 97011ec commit d7fadfe
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 12 deletions.
52 changes: 40 additions & 12 deletions lib/rules/require-computed-property-dependencies.js
Expand Up @@ -117,16 +117,16 @@ function parseComputedDependencies(args) {
* or `this.get(…)`.
*
* @param {ASTNode} node
* @param {string} importedEmberName
* @param {object} importedNames
* @returns {Array<ASTNode>}
*/
function findEmberGetCalls(node, importedEmberName) {
function findEmberGetCalls(node, importedNames) {
const results = [];

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

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

Expand Down Expand Up @@ -313,8 +321,11 @@ module.exports = {

let importedEmberName;
let importedComputedName;
let importedGetName;
let importedGetPropertiesName;
let importedGetWithDefaultName;

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

if (!allowDynamicKeys) {
Expand All @@ -331,8 +342,8 @@ module.exports = {
);

const usedKeys1 = javascriptUtils.flatMap(
findEmberGetCalls(computedPropertyFunctionBody, importedEmberName),
(node) => extractEmberGetDependencies(node, importedEmberName)
findEmberGetCalls(computedPropertyFunctionBody, importedNames),
(node) => extractEmberGetDependencies(node, importedNames)
);
const usedKeys2 = javascriptUtils.flatMap(
findThisGetCalls(computedPropertyFunctionBody),
Expand Down Expand Up @@ -459,18 +470,35 @@ module.exports = {
if (node.source.value === '@ember/object') {
importedComputedName =
importedComputedName || getImportIdentifier(node, '@ember/object', 'computed');
importedGetName = importedGetName || getImportIdentifier(node, '@ember/object', 'get');
importedGetPropertiesName =
importedGetPropertiesName ||
getImportIdentifier(node, '@ember/object', 'getProperties');
importedGetWithDefaultName =
importedGetWithDefaultName ||
getImportIdentifier(node, '@ember/object', 'getWithDefault');
}
},

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

CallExpression(node) {
if (isEmberComputed(node.callee, importedEmberName, importedComputedName)) {
checkComputedDependencies(node, node.arguments, importedEmberName);
checkComputedDependencies(node, node.arguments, {
importedEmberName,
importedGetName,
importedGetPropertiesName,
importedGetWithDefaultName,
});
}
},
};
Expand Down
39 changes: 39 additions & 0 deletions tests/lib/rules/require-computed-property-dependencies.js
Expand Up @@ -1043,5 +1043,44 @@ ruleTester.run('require-computed-property-dependencies', rule, {
},
],
},
{
// Renamed get import:
code:
"import { computed, get as g } from '@ember/object'; computed(function() { return g(this, 'foo'); });",
output:
"import { computed, get as g } from '@ember/object'; computed('foo', function() { return g(this, 'foo'); });",
errors: [
{
message: 'Use of undeclared dependencies in computed property: foo',
type: 'CallExpression',
},
],
},
{
// Renamed getProperties import:
code:
"import { computed, getProperties as gp } from '@ember/object'; computed(function() { return gp(this, 'foo'); });",
output:
"import { computed, getProperties as gp } from '@ember/object'; computed('foo', function() { return gp(this, 'foo'); });",
errors: [
{
message: 'Use of undeclared dependencies in computed property: foo',
type: 'CallExpression',
},
],
},
{
// Renamed getWithDefault import:
code:
"import { computed, getWithDefault as gwd } from '@ember/object'; computed(function() { return gwd(this, 'foo', 'bar'); });",
output:
"import { computed, getWithDefault as gwd } from '@ember/object'; computed('foo', function() { return gwd(this, 'foo', 'bar'); });",
errors: [
{
message: 'Use of undeclared dependencies in computed property: foo',
type: 'CallExpression',
},
],
},
],
});

0 comments on commit d7fadfe

Please sign in to comment.