deno_lint 0.84.0

lint for deno
Documentation
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use super::{Context, LintRule};
use crate::handler::{Handler, Traverse};
use crate::tags::{self, Tags};
use crate::Program;
use deno_ast::view::NodeTrait;
use deno_ast::{view as ast_view, SourceRanged};

#[derive(Debug)]
pub struct NoAwaitInSyncFn;

const CODE: &str = "no-await-in-sync-fn";
const MESSAGE: &str = "Unexpected `await` inside a non-async function.";
const HINT: &str = "Remove `await` in the function body or change the function to an async function.";

impl LintRule for NoAwaitInSyncFn {
  fn tags(&self) -> Tags {
    &[tags::RECOMMENDED]
  }

  fn code(&self) -> &'static str {
    CODE
  }

  fn lint_program_with_ast_view(
    &self,
    context: &mut Context,
    program: Program<'_>,
  ) {
    NoAwaitInSyncFnHandler.traverse(program, context);
  }
}

struct NoAwaitInSyncFnHandler;

impl Handler for NoAwaitInSyncFnHandler {
  fn await_expr(
    &mut self,
    await_expr: &ast_view::AwaitExpr,
    ctx: &mut Context,
  ) {
    fn inside_sync_fn(node: ast_view::Node) -> bool {
      use deno_ast::view::Node::*;
      match node {
        FnDecl(decl) => !decl.function.is_async(),
        FnExpr(decl) => !decl.function.is_async(),
        ArrowExpr(decl) => !decl.is_async(),
        MethodProp(decl) => !decl.function.is_async(),
        ClassMethod(decl) => !decl.function.is_async(),
        PrivateMethod(decl) => !decl.function.is_async(),
        _ => {
          let parent = match node.parent() {
            Some(p) => p,
            None => return false,
          };
          inside_sync_fn(parent)
        }
      }
    }

    if inside_sync_fn(await_expr.as_node()) {
      ctx.add_diagnostic_with_hint(await_expr.range(), CODE, MESSAGE, HINT);
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn no_await_in_sync_fn_valid() {
    assert_lint_ok! {
      NoAwaitInSyncFn,
      r#"
      async function foo(things) {
        await bar();
      }
      "#,
      r#"
      const foo = async (things) => {
        await bar();
      }
      "#,
      r#"
      const foo = async function(things) {
        await bar();
      }
      "#,
      r#"
      const foo = {
        async foo(things) {
          await bar();
        }
      }
      "#,
      r#"
      class Foo {
        async foo(things) {
          await bar();
        }
      }
      "#,
      r#"
      class Foo {
        async #foo(things) {
          await bar();
        }
      }
      "#,
    }
  }

  #[test]
  fn no_await_in_sync_fn_invalid() {
    assert_lint_err! {
      NoAwaitInSyncFn,
      MESSAGE,
      HINT,
      r#"
      function foo(things) {
        await bar();
      }
      "#: [{ line: 3, col: 8 }],
      r#"
      const foo = things => {
        await bar();
      }
      "#: [{ line: 3, col: 8 }],
      r#"
      const foo = function (things) {
        await bar();
      }
      "#: [{ line: 3, col: 8 }],
      r#"
      const foo = {
        foo(things) {
          await bar();
        }
      }
      "#: [{ line: 4, col: 10 }],
      r#"
      class Foo {
        foo(things) {
          await bar();
        }
      }
      "#: [{ line: 4, col: 10 }],
      r#"
      class Foo {
        #foo(things) {
          await bar();
        }
      }
      "#: [{ line: 4, col: 10 }],
    }
  }
}