Last active
December 24, 2019 00:55
-
-
Save wreulicke/413e0d84d8686007d57855873891d860 to your computer and use it in GitHub Desktop.
console statementをESLint Pluginでfixするやつ
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
module.exports = { | |
rules: { | |
"no-console-use-mylogger": ["error", { "loggerName": "logger", "logger": "winston" }] | |
} | |
} |
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
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