You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.2 KiB
134 lines
4.2 KiB
/** |
|
* @fileoverview Rule to flag use of console object |
|
* @author Nicholas C. Zakas |
|
*/ |
|
|
|
"use strict"; |
|
|
|
//------------------------------------------------------------------------------ |
|
// Requirements |
|
//------------------------------------------------------------------------------ |
|
|
|
const astUtils = require("./utils/ast-utils"); |
|
|
|
//------------------------------------------------------------------------------ |
|
// Rule Definition |
|
//------------------------------------------------------------------------------ |
|
|
|
/** @type {import('../shared/types').Rule} */ |
|
module.exports = { |
|
meta: { |
|
type: "suggestion", |
|
|
|
docs: { |
|
description: "Disallow the use of `console`", |
|
recommended: false, |
|
url: "https://eslint.org/docs/rules/no-console" |
|
}, |
|
|
|
schema: [ |
|
{ |
|
type: "object", |
|
properties: { |
|
allow: { |
|
type: "array", |
|
items: { |
|
type: "string" |
|
}, |
|
minItems: 1, |
|
uniqueItems: true |
|
} |
|
}, |
|
additionalProperties: false |
|
} |
|
], |
|
|
|
messages: { |
|
unexpected: "Unexpected console statement." |
|
} |
|
}, |
|
|
|
create(context) { |
|
const options = context.options[0] || {}; |
|
const allowed = options.allow || []; |
|
|
|
/** |
|
* Checks whether the given reference is 'console' or not. |
|
* @param {eslint-scope.Reference} reference The reference to check. |
|
* @returns {boolean} `true` if the reference is 'console'. |
|
*/ |
|
function isConsole(reference) { |
|
const id = reference.identifier; |
|
|
|
return id && id.name === "console"; |
|
} |
|
|
|
/** |
|
* Checks whether the property name of the given MemberExpression node |
|
* is allowed by options or not. |
|
* @param {ASTNode} node The MemberExpression node to check. |
|
* @returns {boolean} `true` if the property name of the node is allowed. |
|
*/ |
|
function isAllowed(node) { |
|
const propertyName = astUtils.getStaticPropertyName(node); |
|
|
|
return propertyName && allowed.includes(propertyName); |
|
} |
|
|
|
/** |
|
* Checks whether the given reference is a member access which is not |
|
* allowed by options or not. |
|
* @param {eslint-scope.Reference} reference The reference to check. |
|
* @returns {boolean} `true` if the reference is a member access which |
|
* is not allowed by options. |
|
*/ |
|
function isMemberAccessExceptAllowed(reference) { |
|
const node = reference.identifier; |
|
const parent = node.parent; |
|
|
|
return ( |
|
parent.type === "MemberExpression" && |
|
parent.object === node && |
|
!isAllowed(parent) |
|
); |
|
} |
|
|
|
/** |
|
* Reports the given reference as a violation. |
|
* @param {eslint-scope.Reference} reference The reference to report. |
|
* @returns {void} |
|
*/ |
|
function report(reference) { |
|
const node = reference.identifier.parent; |
|
|
|
context.report({ |
|
node, |
|
loc: node.loc, |
|
messageId: "unexpected" |
|
}); |
|
} |
|
|
|
return { |
|
"Program:exit"() { |
|
const scope = context.getScope(); |
|
const consoleVar = astUtils.getVariableByName(scope, "console"); |
|
const shadowed = consoleVar && consoleVar.defs.length > 0; |
|
|
|
/* |
|
* 'scope.through' includes all references to undefined |
|
* variables. If the variable 'console' is not defined, it uses |
|
* 'scope.through'. |
|
*/ |
|
const references = consoleVar |
|
? consoleVar.references |
|
: scope.through.filter(isConsole); |
|
|
|
if (!shadowed) { |
|
references |
|
.filter(isMemberAccessExceptAllowed) |
|
.forEach(report); |
|
} |
|
} |
|
}; |
|
} |
|
};
|
|
|