-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is an almost complete rewrite of most of the rules. The goal started as a simple update to take advantage of some newer ES6 features but ended up being a complete refactor to make the code more concise and, hopefully, readable.
- Loading branch information
Casey Visco
committed
Sep 17, 2016
1 parent
7426782
commit f2bafa4
Showing
48 changed files
with
2,144 additions
and
2,287 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,110 @@ | ||
/** | ||
* @fileoverview Ensure AMD-style callbacks contain correct number of arguments | ||
* @author Kevin Partington | ||
* @file Rule to ensure AMD-style callbacks contain correct number of | ||
* arguments | ||
* @author Kevin Partington | ||
*/ | ||
|
||
"use strict"; | ||
|
||
const util = require("../util"); | ||
const rjs = require("../utils/rjs"); | ||
const ast = require("../utils/ast"); | ||
|
||
module.exports = { | ||
meta: { | ||
docs: {}, | ||
schema: [ | ||
{ | ||
"type": "object", | ||
"properties": { | ||
"allowExtraDependencies": { | ||
anyOf: [ | ||
{ | ||
"type": "boolean", | ||
"default": false | ||
}, | ||
{ | ||
"type": "array", | ||
"uniqueItems": true, | ||
"items": { | ||
"type": "string" | ||
} | ||
} | ||
] | ||
const hasCallback = ast.hasCallback; | ||
const getDependencyNodes = rjs.getDependencyNodes; | ||
const getModuleFunction = rjs.getModuleFunction; | ||
const isAmdDefine = rjs.isAmdDefine; | ||
const isRequireCall = rjs.isRequireCall; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Configuration | ||
// ----------------------------------------------------------------------------- | ||
|
||
const docs = { | ||
description: "Ensure AMD-style callbacks contain correct number of arguments", | ||
category: "Stylistic Choices", | ||
recommended: false | ||
}; | ||
|
||
const schema = [ | ||
{ | ||
type: "object", | ||
properties: { | ||
allowExtraDependencies: { | ||
anyOf: [ | ||
{ | ||
type: "boolean", | ||
default: false | ||
}, | ||
{ | ||
type: "array", | ||
uniqueItems: true, | ||
items: { | ||
type: "string" | ||
} | ||
} | ||
}, | ||
"additionalProperties": false | ||
] | ||
} | ||
] | ||
}, | ||
}, | ||
additionalProperties: false | ||
} | ||
]; | ||
|
||
create: function (context) { | ||
const allowExtraDependencies = (context.options && context.options[0] && context.options[0].allowExtraDependencies) || false; | ||
const TOO_MANY_PARAMS_MESSAGE = "Too many parameters in {{functionName}} callback (expected {{expected}}, found {{actual}})."; | ||
const TOO_FEW_PARAMS_MESSAGE = "Not enough parameters in {{functionName}} callback (expected {{expected}}, found {{actual}})."; | ||
const defaults = { | ||
allowExtraDependencies: false | ||
}; | ||
|
||
function allUnassignedPathsAreAllowed(dependencyNodes, callbackParams) { | ||
if (typeof allowExtraDependencies === "boolean") { | ||
return allowExtraDependencies; | ||
} | ||
// ----------------------------------------------------------------------------- | ||
// Helpers | ||
// ----------------------------------------------------------------------------- | ||
|
||
const unassignedPaths = dependencyNodes.slice(callbackParams.length); | ||
const isBoolean = (value) => typeof value === "boolean"; | ||
const unassigned = (paths, params) => paths.slice(params.length); | ||
const includes = (list) => (path) => list.indexOf(path.value) !== -1; | ||
|
||
return unassignedPaths.every(function (path) { | ||
return allowExtraDependencies.indexOf(path.value) !== -1; | ||
}); | ||
} | ||
const isAmdWithCallback = (node) => | ||
isAmdDefine(node) || isRequireCall(node) && hasCallback(node); | ||
|
||
const reportTooFew = (expected, actual) => | ||
`Not enough parameters in callback (expected ${expected}, found ${actual}).`; | ||
|
||
function checkArity(node, funcName) { | ||
const dependencyNodes = util.getDependencyNodes(node); | ||
const reportTooMany = (expected, actual) => | ||
`Too many parameters in callback (expected ${expected}, found ${actual}).`; | ||
|
||
if (!dependencyNodes) { | ||
return; | ||
// ----------------------------------------------------------------------------- | ||
// Rule Definition | ||
// ----------------------------------------------------------------------------- | ||
|
||
function create(context) { | ||
const opts = Object.assign({}, defaults, context.options[0]); | ||
const allowed = opts.allowExtraDependencies; | ||
|
||
const isAllowed = (paths) => | ||
isBoolean(allowed) ? allowed : paths.every(includes(allowed)); | ||
|
||
return { | ||
CallExpression(node) { | ||
if (!isAmdWithCallback(node)) return; | ||
|
||
const paths = getDependencyNodes(node); | ||
const pathCount = paths.length; | ||
|
||
if (!pathCount) return; | ||
|
||
const params = getModuleFunction(node).params; | ||
const paramCount = params.length; | ||
|
||
if (pathCount < paramCount) { | ||
context.report(node, reportTooMany(pathCount, paramCount)); | ||
} | ||
|
||
const dependencyCount = dependencyNodes.length; | ||
const callbackParams = util.getAmdCallback(node).params; | ||
const actualParamCount = callbackParams.length; | ||
|
||
if (dependencyCount < actualParamCount) { | ||
context.report(node, TOO_MANY_PARAMS_MESSAGE, { | ||
functionName: funcName, | ||
expected: dependencyCount, | ||
actual: actualParamCount | ||
}); | ||
} else if (dependencyCount > actualParamCount && !allUnassignedPathsAreAllowed(dependencyNodes, callbackParams)) { | ||
context.report(node, TOO_FEW_PARAMS_MESSAGE, { | ||
functionName: funcName, | ||
expected: dependencyCount, | ||
actual: actualParamCount | ||
}); | ||
if (pathCount > paramCount && !isAllowed(unassigned(paths, params))) { | ||
context.report(node, reportTooFew(pathCount, paramCount)); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
return { | ||
"CallExpression": function (node) { | ||
/* istanbul ignore else: correctly does nothing */ | ||
if (util.isDefineCall(node) && util.isAmdDefine(node)) { | ||
checkArity(node, "define"); | ||
} else if (util.isRequireCall(node) && ast.hasCallback(node)) { | ||
checkArity(node, node.callee.name); | ||
} | ||
} | ||
}; | ||
} | ||
module.exports = { | ||
meta: { docs, schema }, | ||
create | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +1,77 @@ | ||
/** | ||
* @fileoverview Disallow files that are not wrapped in a call to `define` | ||
* @author Casey Visco | ||
* @file Rule to disallow files that are not wrapped in a call to `define` | ||
* @author Casey Visco <cvisco@gmail.com> | ||
*/ | ||
|
||
"use strict"; | ||
|
||
const path = require("path"); | ||
const util = require("../util"); | ||
const rjs = require("../utils/rjs"); | ||
const ast = require("../utils/ast"); | ||
|
||
module.exports = { | ||
meta: { | ||
docs: {}, | ||
schema: [ | ||
const isDefineCall = rjs.isDefineCall; | ||
const isExprStatement = ast.isExprStatement; | ||
const basename = path.basename; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Configuration | ||
// ----------------------------------------------------------------------------- | ||
|
||
const docs = { | ||
description: "Disallow files that are not wrapped in a call to `define`", | ||
category: "Stylistic Choices", | ||
recommended: false | ||
}; | ||
|
||
const schema = [ | ||
{ | ||
anyOf: [ | ||
{ | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"type": "array", | ||
"uniqueItems": true, | ||
"items": { | ||
"type": "string" | ||
} | ||
} | ||
] | ||
type: "string" | ||
}, | ||
{ | ||
type: "array", | ||
uniqueItems: true, | ||
items: { | ||
type: "string" | ||
} | ||
} | ||
] | ||
}, | ||
|
||
create: function (context) { | ||
const MESSAGE = "File must be wrapped in a `define` call"; | ||
const ignoredFiles = context.options[0] || []; | ||
|
||
/** | ||
* Determine if supplied `filename` is allowed to not be wrapped in a | ||
* `define` call. | ||
* @private | ||
* @param {String} filename - filename to test | ||
* @returns {Boolean} true if filename is allowed | ||
*/ | ||
function isIgnoredFile(filename) { | ||
const basename = path.basename(filename); | ||
return ignoredFiles.indexOf(basename) !== -1; | ||
} | ||
} | ||
]; | ||
|
||
return { | ||
"Program": function (node) { | ||
const filename = context.getFilename(); | ||
const message = "File must be wrapped in a `define` call"; | ||
|
||
if (isIgnoredFile(filename)) { | ||
return; | ||
} | ||
// ----------------------------------------------------------------------------- | ||
// Helpers | ||
// ----------------------------------------------------------------------------- | ||
|
||
for (let i = 0, length = node.body.length; i < length; i += 1) { | ||
const child = node.body[i]; | ||
const includes = (list, item) => list.indexOf(item) !== -1; | ||
|
||
if (!(ast.isExprStatement(child) && util.isDefineCall(child.expression))) { | ||
context.report(node, MESSAGE); | ||
break; | ||
} | ||
} | ||
const isDefineExpr = (child) => | ||
isExprStatement(child) && isDefineCall(child.expression); | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Rule Definition | ||
// ----------------------------------------------------------------------------- | ||
|
||
function create(context) { | ||
const ignoredFiles = context.options[0] || []; | ||
|
||
return { | ||
Program(node) { | ||
const filename = basename(context.getFilename()); | ||
|
||
if (includes(ignoredFiles, filename)) return; | ||
|
||
if (!node.body.every(isDefineExpr)) { | ||
context.report(node, message); | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
} | ||
|
||
module.exports = { | ||
meta: { docs, schema }, | ||
create | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,43 @@ | ||
/** | ||
* @fileoverview Disallow use of AMD (dependency array) form of `define` | ||
* @author Casey Visco | ||
* @file Rule to disallow use of AMD (dependency array) form of `define` | ||
* @author Casey Visco <cvisco@gmail.com> | ||
*/ | ||
|
||
"use strict"; | ||
|
||
const util = require("../util"); | ||
const rjs = require("../utils/rjs"); | ||
|
||
module.exports = { | ||
meta: { | ||
docs: {}, | ||
schema: [] | ||
}, | ||
|
||
create: function (context) { | ||
const MESSAGE = "AMD form of `define` is not allowed."; | ||
|
||
return { | ||
"CallExpression": function (node) { | ||
if (util.isDefineCall(node) && util.isAmdDefine(node)) { | ||
context.report(node, MESSAGE); | ||
} | ||
const isAmdDefine = rjs.isAmdDefine; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Configuration | ||
// ----------------------------------------------------------------------------- | ||
|
||
const docs = { | ||
description: "Disallow use of AMD (dependency array) form of `define`", | ||
category: "Stylistic Choices", | ||
recommended: false | ||
}; | ||
|
||
const schema = []; | ||
|
||
const message = "AMD form of `define` is not allowed."; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Rule Definition | ||
// ----------------------------------------------------------------------------- | ||
|
||
function create(context) { | ||
return { | ||
CallExpression(node) { | ||
if (isAmdDefine(node)) { | ||
context.report(node, message); | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
} | ||
|
||
module.exports = { | ||
meta: { docs, schema }, | ||
create | ||
}; |
Oops, something went wrong.