Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
Things might be broken-er in this commit
Browse files Browse the repository at this point in the history
But we're going for the restructure. again. round four. this time,
with macros. because i'm sick of defining Lintable for all of these
structs
  • Loading branch information
caass committed Oct 18, 2020
1 parent 031329c commit ea1880e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 26 deletions.
19 changes: 18 additions & 1 deletion src/build/check/js/linter/expressions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{AstNodeLinterArgs, Lintable};
use swc_ecma_ast::Expr;
use swc_ecma_ast::{ArrayLit, Expr, ObjectLit};

/// [Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions)
/// are the things we actually care about linting. From MDN:
Expand Down Expand Up @@ -85,3 +85,20 @@ impl<'a> Lintable<AstNodeLinterArgs<'a>> for Expr {
}
}
}

impl<'a> Lintable<AstNodeLinterArgs<'a>> for ArrayLit {
fn lint(&self, args: AstNodeLinterArgs) -> Result<(), failure::Error> {
self.elems
.iter()
.filter_map(|elem| elem.as_ref())
.try_for_each(|expression_or_spread| expression_or_spread.expr.lint(args))
}
}

impl<'a> Lintable<AstNodeLinterArgs<'a>> for ObjectLit {
fn lint(&self, args: AstNodeLinterArgs<'a>) -> Result<(), failure::Error> {
self.props
.iter()
.try_for_each(|prop_or_spread| prop_or_spread.lint(args))
}
}
76 changes: 75 additions & 1 deletion src/build/check/js/linter/misc.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,82 @@
use super::{AstNodeLinterArgs, Lintable};
use swc_ecma_ast::{Decl, Pat, VarDecl, VarDeclOrPat};
use failure::format_err;
use swc_ecma_ast::{Decl, ModuleDecl, ModuleItem, Pat, VarDecl, VarDeclOrPat};

// other AstNodes that aren't expressions or statements

/// By implementing Lintable for Vec, we can call `ast.lint(args)`
/// at the top level and recurse through the whole AST. Plus it removes
/// a lot of other boilerplate code we'd otherwise have to write for other
/// expressions and statements that contain Vecs of lintable stuff.
///
/// Note: Ideally, the type signature would actually be more general, like
/// `impl<'a, T> Lintable<AstNodeLinterArgs<'a>> for T where T: Iterator<Item = dyn Lintable<AstNodeLinterArgs<'a>>>`,
/// but rustc is not happy about us implementing this when swc might potentially
/// implement Iterator for e.g. Stmt. Then we'd have conflicting implementations
/// of Lintable for any struct that also implemented Iterator.
/// For practical purposes though, this isn't a problem, as swc just uses Vec
/// for all groups of AstNodes
impl<'a, T> Lintable<AstNodeLinterArgs<'a>> for Vec<T>
where
T: Lintable<AstNodeLinterArgs<'a>>,
{
fn lint(&self, args: AstNodeLinterArgs<'a>) -> Result<(), failure::Error> {
self.iter().try_for_each(|t| t.lint(args))
}
}

/// This is similar to the implementation for Vec<T>, -- this
/// is mostly to prevent writing boilerplate.
impl<'a, T> Lintable<AstNodeLinterArgs<'a>> for Option<T>
where
T: Lintable<AstNodeLinterArgs<'a>>,
{
fn lint(&self, args: AstNodeLinterArgs<'a>) -> Result<(), failure::Error> {
match self {
Some(t) => t.lint(args),
None => Ok(()),
}
}
}

// this stuff is just other nodes that need to be linted that aren't expressions or statements

impl<'a> Lintable<AstNodeLinterArgs<'a>> for ModuleItem {
fn lint(&self, args: AstNodeLinterArgs<'a>) -> Result<(), failure::Error> {
match self {
ModuleItem::ModuleDecl(declaration) => declaration.lint(args),
ModuleItem::Stmt(statement) => statement.lint(args),
}
}
}

impl<'a> Lintable<AstNodeLinterArgs<'a>> for ModuleDecl {
fn lint(&self, args: AstNodeLinterArgs<'a>) -> Result<(), failure::Error> {
match self {
ModuleDecl::Import(import) => {
if let Some(assertions) = import.asserts {
assertions.lint(args)?;
};
import.specifiers.lint(args)
}
ModuleDecl::ExportDecl(export) => export.decl.lint(args),
ModuleDecl::ExportNamed(export) => export.specifiers.lint(args),
ModuleDecl::ExportDefaultDecl(export) => match export.decl {
swc_ecma_ast::DefaultDecl::Class(class) => class.lint(args),
swc_ecma_ast::DefaultDecl::Fn(function) => function.lint(args),
swc_ecma_ast::DefaultDecl::TsInterfaceDecl(interface) => {
format_err!("No typescript allowed!")
}
},
ModuleDecl::ExportDefaultExpr(_) => {}
ModuleDecl::ExportAll(_) => {}
ModuleDecl::TsImportEquals(_) => {}
ModuleDecl::TsExportAssignment(_) => {}
ModuleDecl::TsNamespaceExport(_) => {}
}
}
}

impl<'a> Lintable<AstNodeLinterArgs<'a>> for Decl {
fn lint(&self, args: AstNodeLinterArgs) -> Result<(), failure::Error> {
todo!()
Expand Down
21 changes: 20 additions & 1 deletion src/build/check/js/linter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use sourcemap::SourceMap;
use swc_ecma_ast::Script;
use swc_ecma_ast::{Module, Script};

use super::{ExpressionList, Lintable};

Expand Down Expand Up @@ -34,6 +34,25 @@ impl<'a> Lintable<ScriptLinterArgs<'a>> for Script {
}
}

impl<'a> Lintable<ScriptLinterArgs<'a>> for Module {
fn lint(
&self,
(source_map, unavailable, available_in_request_context): ScriptLinterArgs<'a>,
) -> Result<(), failure::Error> {
if let Err(error) = self
.body
.lint((false, &unavailable, &available_in_request_context))
{
Err(match source_map {
Some(map) => match_error_to_source_map(error, map)?,
None => error,
})
} else {
Ok(())
}
}
}

// TODO: it would be cool to have line numbers in the errors
// and i don't think it would be like extremely hard to do,
// since every statement has its own associated byte position.
Expand Down
17 changes: 0 additions & 17 deletions src/build/check/js/linter/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,6 @@ use swc_ecma_ast::{

use super::{AstNodeLinterArgs, Lintable};

/// By implementing Lintable for Vec<Stmt>, we can call `ast.lint(args)`
/// at the top level and recurse through the whole AST
///
/// Note: Ideally, the type signature would actually be more general, like
/// `impl<'a, T> Lintable<AstNodeLinterArgs<'a>> for T where T: Iterator<Item = dyn Lintable<AstNodeLinterArgs<'a>>>`,
/// but rustc is not happy about us implementing this when swc might potentially
/// implement Iterator for e.g. Stmt. Then we'd have conflicting implementations
/// of Lintable for any struct that also implemented Iterator.
/// For practical purposes though, this isn't a problem, as swc just uses Vec
/// for all groups of AstNodes
impl<'a> Lintable<AstNodeLinterArgs<'a>> for Vec<Stmt> {
fn lint(&self, args: AstNodeLinterArgs) -> Result<(), failure::Error> {
// this would be cool if it was par_iter...rayon when?
self.iter().try_for_each(|statement| statement.lint(args))
}
}

impl<'a> Lintable<AstNodeLinterArgs<'a>> for Stmt {
fn lint(&self, args: AstNodeLinterArgs) -> Result<(), failure::Error> {
// tremendous shoutout to MDN, shame they shut it down
Expand Down
12 changes: 6 additions & 6 deletions src/build/check/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::PathBuf;

use sourcemap::SourceMap;
use swc_common::{sync::Lrc, SourceMap as SwcSourceMap};
use swc_ecma_ast::{Expr, Script};
use swc_ecma_ast::{Expr, Module};
use swc_ecma_parser::{Parser, StringInput};

use super::{Lintable, Parseable, Validate};
Expand All @@ -17,7 +17,7 @@ use super::config::{
};

pub struct JavaScript {
script: Script,
module: Module,
source_map: Option<SourceMap>,
}

Expand All @@ -31,7 +31,7 @@ impl Lintable<JavaScriptLinterArgs> for JavaScript {
&self,
(unavailable, available_in_request_context): JavaScriptLinterArgs,
) -> Result<(), failure::Error> {
self.script.lint((
self.module.lint((
self.source_map.as_ref(),
unavailable,
available_in_request_context,
Expand Down Expand Up @@ -81,9 +81,9 @@ impl Parseable<(PathBuf, Option<PathBuf>)> for JavaScript {
// dollar company and swc is one guy
let _ = parser.take_errors();

match parser.parse_script() {
Ok(script) => Ok(JavaScript {
script,
match parser.parse_module() {
Ok(module) => Ok(JavaScript {
module,
// TODO: parse source map
source_map: None,
}),
Expand Down

0 comments on commit ea1880e

Please sign in to comment.