refactor(ast): fix the lifetime annotations around Vist and VisitMut (#973)

This commit is contained in:
Boshen 2023-10-10 17:05:48 +08:00 committed by GitHub
parent c38a00b453
commit 903854dac0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 528 additions and 535 deletions

1
Cargo.lock generated
View file

@ -1820,6 +1820,7 @@ dependencies = [
"oxc_ast", "oxc_ast",
"oxc_formatter", "oxc_formatter",
"oxc_parser", "oxc_parser",
"oxc_semantic",
"oxc_span", "oxc_span",
"oxc_syntax", "oxc_syntax",
] ]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -84,7 +84,7 @@ impl<'a> Compressor<'a> {
Self { ast: AstBuilder::new(allocator), options, prepass: Prepass::new(allocator) } Self { ast: AstBuilder::new(allocator), options, prepass: Prepass::new(allocator) }
} }
pub fn build<'b>(mut self, program: &'b mut Program<'a>) { pub fn build(mut self, program: &mut Program<'a>) {
self.prepass.visit_program(program); self.prepass.visit_program(program);
self.visit_program(program); self.visit_program(program);
} }
@ -113,7 +113,7 @@ impl<'a> Compressor<'a> {
/// Remove block from single line blocks /// Remove block from single line blocks
/// `{ block } -> block` /// `{ block } -> block`
#[allow(clippy::only_used_in_recursion)] // `&self` is only used in recursion #[allow(clippy::only_used_in_recursion)] // `&self` is only used in recursion
fn compress_block<'b>(&self, stmt: &'b mut Statement<'a>) { fn compress_block(&self, stmt: &mut Statement<'a>) {
if let Statement::BlockStatement(block) = stmt { if let Statement::BlockStatement(block) = stmt {
// Avoid compressing `if (x) { var x = 1 }` to `if (x) var x = 1` due to different // Avoid compressing `if (x) { var x = 1 }` to `if (x) var x = 1` due to different
// semantics according to AnnexB, which lead to different semantics. // semantics according to AnnexB, which lead to different semantics.
@ -126,18 +126,18 @@ impl<'a> Compressor<'a> {
/// Drop `drop_debugger` statement. /// Drop `drop_debugger` statement.
/// Enabled by `compress.drop_debugger` /// Enabled by `compress.drop_debugger`
fn drop_debugger<'b>(&mut self, stmt: &'b Statement<'a>) -> bool { fn drop_debugger(&mut self, stmt: &Statement<'a>) -> bool {
matches!(stmt, Statement::DebuggerStatement(_)) && self.options.drop_debugger matches!(stmt, Statement::DebuggerStatement(_)) && self.options.drop_debugger
} }
/// Drop `console.*` expressions. /// Drop `console.*` expressions.
/// Enabled by `compress.drop_console /// Enabled by `compress.drop_console
fn drop_console<'b>(&mut self, stmt: &'b Statement<'a>) -> bool { fn drop_console(&mut self, stmt: &Statement<'a>) -> bool {
self.options.drop_console self.options.drop_console
&& matches!(stmt, Statement::ExpressionStatement(expr) if util::is_console(&expr.expression)) && matches!(stmt, Statement::ExpressionStatement(expr) if util::is_console(&expr.expression))
} }
fn compress_console<'b>(&mut self, expr: &'b mut Expression<'a>) -> bool { fn compress_console(&mut self, expr: &mut Expression<'a>) -> bool {
if self.options.drop_console && util::is_console(expr) { if self.options.drop_console && util::is_console(expr) {
*expr = self.create_void_0(); *expr = self.create_void_0();
true true
@ -147,7 +147,7 @@ impl<'a> Compressor<'a> {
} }
/// Join consecutive var statements /// Join consecutive var statements
fn join_vars<'b>(&mut self, stmts: &'b mut Vec<'a, Statement<'a>>) { fn join_vars(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
// Collect all the consecutive ranges that contain joinable vars. // Collect all the consecutive ranges that contain joinable vars.
// This is required because Rust prevents in-place vec mutation. // This is required because Rust prevents in-place vec mutation.
let mut ranges = vec![]; let mut ranges = vec![];
@ -201,7 +201,7 @@ impl<'a> Compressor<'a> {
} }
/// Transforms `while(expr)` to `for(;expr;)` /// Transforms `while(expr)` to `for(;expr;)`
fn compress_while<'b>(&mut self, stmt: &'b mut Statement<'a>) { fn compress_while(&mut self, stmt: &mut Statement<'a>) {
let Statement::WhileStatement(while_stmt) = stmt else { return }; let Statement::WhileStatement(while_stmt) = stmt else { return };
if self.options.loops { if self.options.loops {
let dummy_test = self.ast.this_expression(SPAN); let dummy_test = self.ast.this_expression(SPAN);
@ -214,7 +214,7 @@ impl<'a> Compressor<'a> {
/* Expressions */ /* Expressions */
/// Transforms `undefined` => `void 0` /// Transforms `undefined` => `void 0`
fn compress_undefined<'b>(&mut self, expr: &'b mut Expression<'a>) -> bool { fn compress_undefined(&mut self, expr: &mut Expression<'a>) -> bool {
let Expression::Identifier(ident) = expr else { return false }; let Expression::Identifier(ident) = expr else { return false };
if ident.name == "undefined" { if ident.name == "undefined" {
// if let Some(reference_id) = ident.reference_id.clone().into_inner() { // if let Some(reference_id) = ident.reference_id.clone().into_inner() {
@ -228,7 +228,7 @@ impl<'a> Compressor<'a> {
/// Transforms `Infinity` => `1/0` /// Transforms `Infinity` => `1/0`
#[allow(unused)] #[allow(unused)]
fn compress_infinity<'b>(&mut self, expr: &'b mut Expression<'a>) -> bool { fn compress_infinity(&mut self, expr: &mut Expression<'a>) -> bool {
let Expression::Identifier(ident) = expr else { return false }; let Expression::Identifier(ident) = expr else { return false };
if ident.name == "Infinity" { if ident.name == "Infinity" {
// if let Some(reference_id) = ident.reference_id.clone().into_inner() { // if let Some(reference_id) = ident.reference_id.clone().into_inner() {
@ -242,7 +242,7 @@ impl<'a> Compressor<'a> {
/// Transforms boolean expression `true` => `!0` `false` => `!1` /// Transforms boolean expression `true` => `!0` `false` => `!1`
/// Enabled by `compress.booleans` /// Enabled by `compress.booleans`
fn compress_boolean<'b>(&mut self, expr: &'b mut Expression<'a>) -> bool { fn compress_boolean(&mut self, expr: &mut Expression<'a>) -> bool {
let Expression::BooleanLiteral(lit) = expr else { return false }; let Expression::BooleanLiteral(lit) = expr else { return false };
if self.options.booleans { if self.options.booleans {
let num = self.ast.number_literal( let num = self.ast.number_literal(
@ -260,7 +260,7 @@ impl<'a> Compressor<'a> {
/// Transforms `typeof foo == "undefined"` into `foo === void 0` /// Transforms `typeof foo == "undefined"` into `foo === void 0`
/// Enabled by `compress.typeofs` /// Enabled by `compress.typeofs`
fn compress_typeof_undefined<'b>(&mut self, expr: &'b mut BinaryExpression<'a>) { fn compress_typeof_undefined(&mut self, expr: &mut BinaryExpression<'a>) {
if expr.operator.is_equality() && self.options.typeofs { if expr.operator.is_equality() && self.options.typeofs {
if let Expression::UnaryExpression(unary_expr) = &expr.left { if let Expression::UnaryExpression(unary_expr) = &expr.left {
if unary_expr.operator == UnaryOperator::Typeof { if unary_expr.operator == UnaryOperator::Typeof {
@ -281,13 +281,13 @@ impl<'a> Compressor<'a> {
/// ///
/// `return undefined` -> `return` /// `return undefined` -> `return`
/// `return void 0` -> `return` /// `return void 0` -> `return`
fn compress_return_statement<'b>(&mut self, stmt: &'b mut ReturnStatement<'a>) { fn compress_return_statement(&mut self, stmt: &mut ReturnStatement<'a>) {
if stmt.argument.as_ref().is_some_and(|expr| expr.is_undefined() || expr.is_void_0()) { if stmt.argument.as_ref().is_some_and(|expr| expr.is_undefined() || expr.is_void_0()) {
stmt.argument = None; stmt.argument = None;
} }
} }
fn compress_variable_declarator<'b>(&mut self, decl: &'b mut VariableDeclarator<'a>) { fn compress_variable_declarator(&mut self, decl: &mut VariableDeclarator<'a>) {
if decl.kind.is_const() { if decl.kind.is_const() {
return; return;
} }
@ -303,7 +303,7 @@ impl<'a> Compressor<'a> {
/// After reordering, expressions like 0 === x and 0 === y may have higher /// After reordering, expressions like 0 === x and 0 === y may have higher
/// compression together than their original counterparts. /// compression together than their original counterparts.
#[allow(unused)] #[allow(unused)]
fn reorder_constant_expression<'b>(&self, expr: &'b mut BinaryExpression<'a>) { fn reorder_constant_expression(&self, expr: &mut BinaryExpression<'a>) {
let operator = expr.operator; let operator = expr.operator;
if operator.is_equality() if operator.is_equality()
|| operator.is_compare() || operator.is_compare()
@ -322,8 +322,8 @@ impl<'a> Compressor<'a> {
} }
} }
impl<'a, 'b> VisitMut<'a, 'b> for Compressor<'a> { impl<'a> VisitMut<'a> for Compressor<'a> {
fn visit_statements(&mut self, stmts: &'b mut Vec<'a, Statement<'a>>) { fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
stmts.retain(|stmt| { stmts.retain(|stmt| {
if self.drop_debugger(stmt) { if self.drop_debugger(stmt) {
return false; return false;
@ -341,14 +341,14 @@ impl<'a, 'b> VisitMut<'a, 'b> for Compressor<'a> {
} }
} }
fn visit_statement(&mut self, stmt: &'b mut Statement<'a>) { fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
self.compress_block(stmt); self.compress_block(stmt);
self.compress_while(stmt); self.compress_while(stmt);
self.fold_condition(stmt); self.fold_condition(stmt);
self.visit_statement_match(stmt); self.visit_statement_match(stmt);
} }
fn visit_return_statement(&mut self, stmt: &'b mut ReturnStatement<'a>) { fn visit_return_statement(&mut self, stmt: &mut ReturnStatement<'a>) {
if let Some(arg) = &mut stmt.argument { if let Some(arg) = &mut stmt.argument {
self.visit_expression(arg); self.visit_expression(arg);
} }
@ -356,14 +356,14 @@ impl<'a, 'b> VisitMut<'a, 'b> for Compressor<'a> {
self.compress_return_statement(stmt); self.compress_return_statement(stmt);
} }
fn visit_variable_declaration(&mut self, decl: &'b mut VariableDeclaration<'a>) { fn visit_variable_declaration(&mut self, decl: &mut VariableDeclaration<'a>) {
for declarator in decl.declarations.iter_mut() { for declarator in decl.declarations.iter_mut() {
self.visit_variable_declarator(declarator); self.visit_variable_declarator(declarator);
self.compress_variable_declarator(declarator); self.compress_variable_declarator(declarator);
} }
} }
fn visit_expression(&mut self, expr: &'b mut Expression<'a>) { fn visit_expression(&mut self, expr: &mut Expression<'a>) {
self.visit_expression_match(expr); self.visit_expression_match(expr);
self.compress_console(expr); self.compress_console(expr);
self.fold_expression(expr); self.fold_expression(expr);
@ -372,7 +372,7 @@ impl<'a, 'b> VisitMut<'a, 'b> for Compressor<'a> {
} }
} }
fn visit_binary_expression(&mut self, expr: &'b mut BinaryExpression<'a>) { fn visit_binary_expression(&mut self, expr: &mut BinaryExpression<'a>) {
self.visit_expression(&mut expr.left); self.visit_expression(&mut expr.left);
self.visit_expression(&mut expr.right); self.visit_expression(&mut expr.right);

View file

@ -12,7 +12,7 @@ impl<'a> Prepass<'a> {
Self { ast: AstBuilder::new(allocator) } Self { ast: AstBuilder::new(allocator) }
} }
fn strip_parenthesized_expression<'b>(&self, expr: &'b mut Expression<'a>) { fn strip_parenthesized_expression(&self, expr: &mut Expression<'a>) {
if let Expression::ParenthesizedExpression(paren_expr) = expr { if let Expression::ParenthesizedExpression(paren_expr) = expr {
*expr = self.ast.move_expression(&mut paren_expr.expression); *expr = self.ast.move_expression(&mut paren_expr.expression);
self.strip_parenthesized_expression(expr); self.strip_parenthesized_expression(expr);
@ -20,15 +20,15 @@ impl<'a> Prepass<'a> {
} }
} }
impl<'a, 'b> VisitMut<'a, 'b> for Prepass<'a> { impl<'a> VisitMut<'a> for Prepass<'a> {
fn visit_statements(&mut self, stmts: &'b mut Vec<'a, Statement<'a>>) { fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
stmts.retain(|stmt| !matches!(stmt, Statement::EmptyStatement(_))); stmts.retain(|stmt| !matches!(stmt, Statement::EmptyStatement(_)));
for stmt in stmts.iter_mut() { for stmt in stmts.iter_mut() {
self.visit_statement(stmt); self.visit_statement(stmt);
} }
} }
fn visit_expression(&mut self, expr: &'b mut Expression<'a>) { fn visit_expression(&mut self, expr: &mut Expression<'a>) {
self.strip_parenthesized_expression(expr); self.strip_parenthesized_expression(expr);
self.visit_expression_match(expr); self.visit_expression_match(expr);
} }

View file

@ -150,7 +150,7 @@ impl<'a> SemanticBuilder<'a> {
self self
} }
pub fn build(mut self, program: &'a Program<'a>) -> SemanticBuilderReturn<'a> { pub fn build(mut self, program: &Program<'a>) -> SemanticBuilderReturn<'a> {
if !self.source_type.is_typescript_definition() { if !self.source_type.is_typescript_definition() {
self.visit_program(program); self.visit_program(program);

View file

@ -20,6 +20,7 @@ oxc_ast = { workspace = true }
oxc_span = { workspace = true } oxc_span = { workspace = true }
oxc_allocator = { workspace = true } oxc_allocator = { workspace = true }
oxc_syntax = { workspace = true } oxc_syntax = { workspace = true }
oxc_semantic = { workspace = true }
[dev-dependencies] [dev-dependencies]
oxc_parser = { workspace = true } oxc_parser = { workspace = true }

View file

@ -3,6 +3,7 @@ use std::{env, path::Path};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_formatter::{Formatter, FormatterOptions}; use oxc_formatter::{Formatter, FormatterOptions};
use oxc_parser::Parser; use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType; use oxc_span::SourceType;
use oxc_transformer::{TransformOptions, TransformReactOptions, TransformTarget, Transformer}; use oxc_transformer::{TransformOptions, TransformReactOptions, TransformTarget, Transformer};
@ -28,11 +29,12 @@ fn main() {
} }
let formatter_options = FormatterOptions::default(); let formatter_options = FormatterOptions::default();
let program = allocator.alloc(ret.program); let printed = Formatter::new(source_text.len(), formatter_options.clone()).build(&ret.program);
let printed = Formatter::new(source_text.len(), formatter_options.clone()).build(program);
println!("Original:\n"); println!("Original:\n");
println!("{printed}"); println!("{printed}");
let program = allocator.alloc(ret.program);
let _ = SemanticBuilder::new(&source_text, source_type).build(program);
let transform_options = TransformOptions { let transform_options = TransformOptions {
target: TransformTarget::ES2015, target: TransformTarget::ES2015,
react: Some(TransformReactOptions::default()), react: Some(TransformReactOptions::default()),

View file

@ -84,13 +84,13 @@ impl<'a> Transformer<'a> {
t t
} }
pub fn build<'b>(mut self, program: &'b mut Program<'a>) { pub fn build(mut self, program: &mut Program<'a>) {
self.visit_program(program); self.visit_program(program);
} }
} }
impl<'a, 'b> VisitMut<'a, 'b> for Transformer<'a> { impl<'a> VisitMut<'a> for Transformer<'a> {
fn visit_expression(&mut self, expr: &'b mut Expression<'a>) { fn visit_expression(&mut self, expr: &mut Expression<'a>) {
// self.typescript.as_mut().map(|t| t.transform_expression(expr)); // self.typescript.as_mut().map(|t| t.transform_expression(expr));
// self.react_jsx.as_mut().map(|t| t.transform_expression(expr)); // self.react_jsx.as_mut().map(|t| t.transform_expression(expr));
self.es2021_logical_assignment_operators.as_mut().map(|t| t.transform_expression(expr)); self.es2021_logical_assignment_operators.as_mut().map(|t| t.transform_expression(expr));
@ -100,7 +100,7 @@ impl<'a, 'b> VisitMut<'a, 'b> for Transformer<'a> {
self.visit_expression_match(expr); self.visit_expression_match(expr);
} }
fn visit_catch_clause(&mut self, clause: &'b mut CatchClause<'a>) { fn visit_catch_clause(&mut self, clause: &mut CatchClause<'a>) {
self.es2019_optional_catch_binding.as_mut().map(|t| t.transform_catch_clause(clause)); self.es2019_optional_catch_binding.as_mut().map(|t| t.transform_catch_clause(clause));
if let Some(param) = &mut clause.param { if let Some(param) = &mut clause.param {
@ -109,7 +109,7 @@ impl<'a, 'b> VisitMut<'a, 'b> for Transformer<'a> {
self.visit_statements(&mut clause.body.body); self.visit_statements(&mut clause.body.body);
} }
fn visit_object_property(&mut self, prop: &'b mut ObjectProperty<'a>) { fn visit_object_property(&mut self, prop: &mut ObjectProperty<'a>) {
self.es2015_shorthand_properties.as_mut().map(|t| t.transform_object_property(prop)); self.es2015_shorthand_properties.as_mut().map(|t| t.transform_object_property(prop));
self.visit_property_key(&mut prop.key); self.visit_property_key(&mut prop.key);
@ -119,7 +119,7 @@ impl<'a, 'b> VisitMut<'a, 'b> for Transformer<'a> {
} }
} }
fn visit_class_body(&mut self, class_body: &'b mut ClassBody<'a>) { fn visit_class_body(&mut self, class_body: &mut ClassBody<'a>) {
self.es2022_class_static_block.as_mut().map(|t| t.transform_class_body(class_body)); self.es2022_class_static_block.as_mut().map(|t| t.transform_class_body(class_body));
class_body.body.iter_mut().for_each(|class_element| { class_body.body.iter_mut().for_each(|class_element| {

View file

@ -37,7 +37,7 @@ const UNICORN_TEST_PATH: &str =
struct TestCase<'a> { struct TestCase<'a> {
source_text: &'a str, source_text: &'a str,
code: Option<Cow<'a, str>>, code: Option<String>,
test_code: Option<Cow<'a, str>>, test_code: Option<Cow<'a, str>>,
} }
@ -74,7 +74,7 @@ impl<'a> TestCase<'a> {
} }
impl<'a> Visit<'a> for TestCase<'a> { impl<'a> Visit<'a> for TestCase<'a> {
fn visit_expression(&mut self, expr: &'a Expression<'a>) { fn visit_expression(&mut self, expr: &Expression<'a>) {
match expr { match expr {
Expression::StringLiteral(lit) => self.visit_string_literal(lit), Expression::StringLiteral(lit) => self.visit_string_literal(lit),
Expression::TemplateLiteral(lit) => self.visit_template_literal(lit), Expression::TemplateLiteral(lit) => self.visit_template_literal(lit),
@ -87,7 +87,7 @@ impl<'a> Visit<'a> for TestCase<'a> {
} }
} }
fn visit_call_expression(&mut self, expr: &'a CallExpression<'a>) { fn visit_call_expression(&mut self, expr: &CallExpression<'a>) {
if let Expression::MemberExpression(member_expr) = &expr.callee { if let Expression::MemberExpression(member_expr) = &expr.callee {
if let Expression::ArrayExpression(array_expr) = member_expr.object() { if let Expression::ArrayExpression(array_expr) = member_expr.object() {
// ['class A {', '}'].join('\n') // ['class A {', '}'].join('\n')
@ -100,19 +100,19 @@ impl<'a> Visit<'a> for TestCase<'a> {
code.push_str(lit.value.as_str()); code.push_str(lit.value.as_str());
code.push('\n'); code.push('\n');
} }
self.code = Some(Cow::Owned(code)); self.code = Some(code);
self.test_code = None; self.test_code = None;
} }
} }
} }
fn visit_object_expression(&mut self, expr: &'a ObjectExpression<'a>) { fn visit_object_expression(&mut self, expr: &ObjectExpression<'a>) {
for obj_prop in &expr.properties { for obj_prop in &expr.properties {
match obj_prop { match obj_prop {
ObjectPropertyKind::ObjectProperty(prop) => match &prop.key { ObjectPropertyKind::ObjectProperty(prop) => match &prop.key {
PropertyKey::Identifier(ident) if ident.name == "code" => { PropertyKey::Identifier(ident) if ident.name == "code" => {
self.code = match &prop.value { self.code = match &prop.value {
Expression::StringLiteral(s) => Some(Cow::Borrowed(s.value.as_str())), Expression::StringLiteral(s) => Some(s.value.to_string()),
// eslint-plugin-jest use dedent to strips indentation from multi-line strings // eslint-plugin-jest use dedent to strips indentation from multi-line strings
Expression::TaggedTemplateExpression(tag_expr) => { Expression::TaggedTemplateExpression(tag_expr) => {
let Expression::Identifier(ident) = &tag_expr.tag else { let Expression::Identifier(ident) = &tag_expr.tag else {
@ -121,10 +121,10 @@ impl<'a> Visit<'a> for TestCase<'a> {
if ident.name != "dedent" { if ident.name != "dedent" {
continue; continue;
} }
tag_expr.quasi.quasi().map(|s| Cow::Borrowed(s.as_str())) tag_expr.quasi.quasi().map(ToString::to_string)
} }
Expression::TemplateLiteral(tag_expr) => { Expression::TemplateLiteral(tag_expr) => {
tag_expr.quasi().map(|s| Cow::Borrowed(s.as_str())) tag_expr.quasi().map(ToString::to_string)
} }
// handle code like ["{", "a: 1", "}"].join("\n") // handle code like ["{", "a: 1", "}"].join("\n")
Expression::CallExpression(call_expr) => { Expression::CallExpression(call_expr) => {
@ -146,7 +146,7 @@ impl<'a> Visit<'a> for TestCase<'a> {
let Expression::ArrayExpression(array_expr) = &member.object else { let Expression::ArrayExpression(array_expr) = &member.object else {
continue; continue;
}; };
Some(Cow::Owned( Some(
array_expr array_expr
.elements .elements
.iter() .iter()
@ -158,7 +158,7 @@ impl<'a> Visit<'a> for TestCase<'a> {
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"), .join("\n"),
)) )
} }
_ => continue, _ => continue,
} }
@ -176,24 +176,24 @@ impl<'a> Visit<'a> for TestCase<'a> {
} }
} }
fn visit_template_literal(&mut self, lit: &'a TemplateLiteral<'a>) { fn visit_template_literal(&mut self, lit: &TemplateLiteral<'a>) {
self.code = Some(Cow::Borrowed(lit.quasi().unwrap().as_str())); self.code = Some(lit.quasi().unwrap().to_string());
self.test_code = None; self.test_code = None;
} }
fn visit_string_literal(&mut self, lit: &'a StringLiteral) { fn visit_string_literal(&mut self, lit: &StringLiteral) {
self.code = Some(Cow::Borrowed(lit.value.as_str())); self.code = Some(lit.value.to_string());
self.test_code = None; self.test_code = None;
} }
fn visit_tagged_template_expression(&mut self, expr: &'a TaggedTemplateExpression<'a>) { fn visit_tagged_template_expression(&mut self, expr: &TaggedTemplateExpression<'a>) {
let Expression::Identifier(ident) = &expr.tag else { let Expression::Identifier(ident) = &expr.tag else {
return; return;
}; };
if ident.name != "dedent" { if ident.name != "dedent" {
return; return;
} }
self.code = expr.quasi.quasi().map(|s| Cow::Borrowed(s.as_str())); self.code = expr.quasi.quasi().map(std::string::ToString::to_string);
self.test_code = None; self.test_code = None;
} }
} }
@ -246,23 +246,23 @@ impl<'a> State<'a> {
} }
impl<'a> Visit<'a> for State<'a> { impl<'a> Visit<'a> for State<'a> {
fn visit_program(&mut self, program: &'a Program<'a>) { fn visit_program(&mut self, program: &Program<'a>) {
for stmt in &program.body { for stmt in &program.body {
self.visit_statement(stmt); self.visit_statement(stmt);
} }
} }
fn visit_statement(&mut self, stmt: &'a Statement<'a>) { fn visit_statement(&mut self, stmt: &Statement<'a>) {
if let Statement::ExpressionStatement(expr_stmt) = stmt { if let Statement::ExpressionStatement(expr_stmt) = stmt {
self.visit_expression_statement(expr_stmt); self.visit_expression_statement(expr_stmt);
} }
} }
fn visit_expression_statement(&mut self, stmt: &'a ExpressionStatement<'a>) { fn visit_expression_statement(&mut self, stmt: &ExpressionStatement<'a>) {
self.visit_expression(&stmt.expression); self.visit_expression(&stmt.expression);
} }
fn visit_expression(&mut self, expr: &'a Expression<'a>) { fn visit_expression(&mut self, expr: &Expression<'a>) {
if let Expression::CallExpression(call_expr) = expr { if let Expression::CallExpression(call_expr) = expr {
for arg in &call_expr.arguments { for arg in &call_expr.arguments {
self.visit_argument(arg); self.visit_argument(arg);
@ -270,7 +270,7 @@ impl<'a> Visit<'a> for State<'a> {
} }
} }
fn visit_argument(&mut self, arg: &'a Argument<'a>) { fn visit_argument(&mut self, arg: &Argument<'a>) {
if let Argument::Expression(Expression::ObjectExpression(obj_expr)) = arg { if let Argument::Expression(Expression::ObjectExpression(obj_expr)) = arg {
for obj_prop in &obj_expr.properties { for obj_prop in &obj_expr.properties {
let ObjectPropertyKind::ObjectProperty(prop) = obj_prop else { return }; let ObjectPropertyKind::ObjectProperty(prop) = obj_prop else { return };
@ -279,17 +279,17 @@ impl<'a> Visit<'a> for State<'a> {
} }
} }
fn visit_object_property(&mut self, prop: &'a ObjectProperty<'a>) { fn visit_object_property(&mut self, prop: &ObjectProperty<'a>) {
let PropertyKey::Identifier(ident) = &prop.key else { return }; let PropertyKey::Identifier(ident) = &prop.key else { return };
match ident.name.as_str() { match ident.name.as_str() {
"valid" => { "valid" => {
if let Expression::ArrayExpression(array_expr) = &prop.value { if let Expression::ArrayExpression(array_expr) = &prop.value {
self.valid_tests.push(array_expr); self.valid_tests.push(self.alloc(array_expr));
} }
} }
"invalid" => { "invalid" => {
if let Expression::ArrayExpression(array_expr) = &prop.value { if let Expression::ArrayExpression(array_expr) = &prop.value {
self.invalid_tests.push(array_expr); self.invalid_tests.push(self.alloc(array_expr));
} }
} }
_ => {} _ => {}