diff --git a/docs/rules/no_console.md b/docs/rules/no_console.md new file mode 100644 index 000000000..a277d0e5d --- /dev/null +++ b/docs/rules/no_console.md @@ -0,0 +1,38 @@ +# no_console + +Disallows the use of the `console` global. + +Oftentimes, developers accidentally commit `console.log`/`console.error` +statements, left in particularly after debugging. Moreover, using these in code +may leak sensitive information to the output or clutter the console with +unnecessary information. This rule helps maintain clean and secure code by +disallowing the use of `console`. + +This rule is especially useful in libraries where you almost never want to +output to the console. + +### Invalid + +```typescript +console.log("Debug message"); +console.error("Debug message"); +console.debug(obj); + +if (debug) console.log("Debugging"); + +function log() { + console.log("Log"); +} +``` + +### Valid + +It is recommended to explicitly enable the console via a `deno-lint-ignore` +comment for any calls where you actually want to use it. + +```typescript +function logWarning(message: string) { + // deno-lint-ignore no-console + console.warn(message); +} +``` diff --git a/docs/rules/no_console_log.md b/docs/rules/no_console_log.md deleted file mode 100644 index d0fe71ae1..000000000 --- a/docs/rules/no_console_log.md +++ /dev/null @@ -1,31 +0,0 @@ -# no_console_log - -Disallows the use of `console.log`. - -Oftentimes, developers accidentally commit `console.log` statements, left in -particularly after debugging. Moreover, using `console.log` in code may leak -sensitive information to the output or clutter the console with unnecessary -information. This rule helps maintain clean and secure code by disallowing the -use of `console.log`. - -### Invalid - -```typescript -console.log("Debug message"); - -if (debug) console.log("Debugging"); - -function log() { - console.log("Log"); -} -``` - -### Valid - -```typescript -console.error("Error message"); - -function log_error(message: string) { - console.warn(message); -} -``` diff --git a/src/rules.rs b/src/rules.rs index 1512a52df..ac1c0ea61 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -31,7 +31,7 @@ pub mod no_case_declarations; pub mod no_class_assign; pub mod no_compare_neg_zero; pub mod no_cond_assign; -pub mod no_console_log; +pub mod no_console; pub mod no_const_assign; pub mod no_constant_condition; pub mod no_control_regex; diff --git a/src/rules/no_console.rs b/src/rules/no_console.rs new file mode 100644 index 000000000..1b72a28f3 --- /dev/null +++ b/src/rules/no_console.rs @@ -0,0 +1,92 @@ +use super::{Context, LintRule}; +use crate::handler::{Handler, Traverse}; +use crate::Program; +use deno_ast::view::Ident; +use deno_ast::SourceRanged; + +#[derive(Debug)] +pub struct NoConsole; + +const MESSAGE: &str = "`console` usage is not allowed."; +const CODE: &str = "no-console"; + +impl LintRule for NoConsole { + fn tags(&self) -> &'static [&'static str] { + &[] + } + + fn code(&self) -> &'static str { + CODE + } + + fn lint_program_with_ast_view( + &self, + context: &mut Context, + program: Program, + ) { + NoConsoleHandler.traverse(program, context); + } + + #[cfg(feature = "docs")] + fn docs(&self) -> &'static str { + include_str!("../../docs/rules/no_console.md") + } +} + +struct NoConsoleHandler; + +impl Handler for NoConsoleHandler { + fn ident(&mut self, id: &Ident, ctx: &mut Context) { + if id.sym().as_ref() == "console" && ctx.scope().is_global(&id.to_id()) { + ctx.add_diagnostic(id.range(), CODE, MESSAGE); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn console_allowed() { + assert_lint_ok!( + NoConsole, + // ignored + r#"// deno-lint-ignore no-console\nconsole.error('Error message');"#, + // not global + r#"const console = { log() {} } console.log('Error message');"#, + ); + } + + #[test] + fn no_console_invalid() { + // Test cases where console is present + assert_lint_err!( + NoConsole, + r#"console.log('Debug message');"#: [{ + col: 0, + message: MESSAGE, + }], + r#"if (debug) { console.log('Debugging'); }"#: [{ + col: 13, + message: MESSAGE, + }], + r#"function log() { console.log('Log'); }"#: [{ + col: 17, + message: MESSAGE, + }], + r#"function log() { console.debug('Log'); }"#: [{ + col: 17, + message: MESSAGE, + }], + r#"console;"#: [{ + col: 0, + message: MESSAGE, + }], + r#"console.warn("test");"#: [{ + col: 0, + message: MESSAGE, + }], + ); + } +} diff --git a/src/rules/no_console_log.rs b/src/rules/no_console_log.rs deleted file mode 100644 index 6b5beb0ab..000000000 --- a/src/rules/no_console_log.rs +++ /dev/null @@ -1,89 +0,0 @@ -use super::{Context, LintRule}; -use crate::handler::{Handler, Traverse}; -use crate::Program; -use deno_ast::view::{CallExpr, Expr, MemberProp}; -use deno_ast::SourceRanged; - -#[derive(Debug)] -pub struct NoConsoleLog; - -const MESSAGE: &str = "'console.log` calls are not allowed."; -const CODE: &str = "no-console"; - -impl LintRule for NoConsoleLog { - fn tags(&self) -> &'static [&'static str] { - &["recommended"] - } - - fn code(&self) -> &'static str { - CODE - } - - fn lint_program_with_ast_view( - &self, - context: &mut Context, - program: Program, - ) { - NoConsoleLogHandler.traverse(program, context); - } - - #[cfg(feature = "docs")] - fn docs(&self) -> &'static str { - include_str!("../../docs/rules/no_console_log.md") - } -} - -struct NoConsoleLogHandler; - -impl Handler for NoConsoleLogHandler { - fn call_expr(&mut self, call_expr: &CallExpr, ctx: &mut Context) { - if let deno_ast::view::Callee::Expr(Expr::Member(member_expr)) = - &call_expr.callee - { - if let Expr::Ident(obj_ident) = &member_expr.obj { - if obj_ident.sym().as_ref() == "console" { - if let MemberProp::Ident(prop_ident) = &member_expr.prop { - if prop_ident.sym().as_ref() == "log" { - ctx.add_diagnostic(call_expr.range(), CODE, MESSAGE); - } - } - } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn no_console_log_valid() { - // Test cases where a console.log call is not present - assert_lint_ok!( - NoConsoleLog, - r#"let foo = 0; const bar = 1;"#, - r#"console.error('Error message');"# - ); - } - - #[test] - fn no_console_log_invalid() { - // Test cases where console.log is present - assert_lint_err!( - NoConsoleLog, - r#"console.log('Debug message');"#: [{ - col: 0, - message: MESSAGE, - }], - r#"if (debug) { console.log('Debugging'); }"#: [{ - col: 13, - message: MESSAGE, - }], - r#"function log() { console.log('Log'); }"#: [{ - col: 17, - message: MESSAGE, - }] - ); - } -}