Skip to content

Instantly share code, notes, and snippets.

@wreulicke
Last active December 24, 2019 00:55
Show Gist options
  • Save wreulicke/413e0d84d8686007d57855873891d860 to your computer and use it in GitHub Desktop.
Save wreulicke/413e0d84d8686007d57855873891d860 to your computer and use it in GitHub Desktop.
console statementをESLint Pluginでfixするやつ
module.exports = {
rules: {
"no-console-use-mylogger": ["error", { "loggerName": "logger", "logger": "winston" }]
}
}
function getVariableByName(initScope, name) {
let scope = initScope
while (scope) {
const variable = scope.set.get(name)
if (variable) {
return variable
}
scope = scope.upper
}
return null
}
module.exports = {
meta: {
messages: {
unexpected: "Unexpected console statement."
},
fixable: "code"
},
create(context) {
const options = {
logger: context.options[0] ? context.options[0].logger : "winston",
loggerName: context.options[0] ? context.options[0].loggerName : "winston"
}
/**
* 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 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
}
/**
* Reports the given reference as a violation.
* @param {eslint-scope.Reference} reference The reference to report.
* @returns {void}
*/
function report(program, sourceCode, reference) {
const node = reference.identifier.parent
context.report({
node,
loc: node.loc,
messageId: "unexpected",
fix(fixer) {
const logLevel =
node.property.name === "log" ? "info" : node.property.name
return fixer.replaceText(
node.parent,
`${
options.loggerName
}.${logLevel}(${node.parent.arguments
.map(arg => sourceCode.getText(arg))
.join(", ")})`
)
}
})
}
return {
"Program:exit"(program) {
const scope = context.getScope()
const sourceCode = context.getSourceCode()
const consoleVar = 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(r => report(program, sourceCode, r))
const found = scope.childScopes.some(
s => getVariableByName(s, options.loggerName) != null
)
if (
references.filter(isMemberAccessExceptAllowed).length != 0 &&
!found
) {
context.report({
program,
loc: program.loc,
messageId: "unexpected",
fix(fixer) {
return fixer.insertTextBefore(
program,
`const ${options.loggerName} = require("${options.logger}")\n`
)
}
})
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment