refactor(codegen): improve print API (#4196)

This commit is contained in:
Boshen 2024-07-11 08:41:04 +00:00
parent 4f26e51b74
commit aa22073736
14 changed files with 470 additions and 469 deletions

File diff suppressed because it is too large Load diff

View file

@ -175,13 +175,15 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
}
/// Push a single character into the buffer
pub fn print(&mut self, ch: u8) {
#[inline]
pub fn print_char(&mut self, ch: u8) {
self.code.push(ch);
}
/// Push a single character into the buffer
pub fn print_str<T: AsRef<[u8]>>(&mut self, s: T) {
self.code.extend_from_slice(s.as_ref());
#[inline]
pub fn print_str(&mut self, s: &str) {
self.code.extend(s.as_bytes());
}
}
@ -198,30 +200,30 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
#[inline]
fn print_soft_space(&mut self) {
if !MINIFY {
self.print(b' ');
self.print_char(b' ');
}
}
#[inline]
pub fn print_hard_space(&mut self) {
self.print(b' ');
self.print_char(b' ');
}
#[inline]
fn print_soft_newline(&mut self) {
if !MINIFY {
self.print(b'\n');
self.print_char(b'\n');
}
}
#[inline]
fn print_semicolon(&mut self) {
self.print(b';');
self.print_char(b';');
}
#[inline]
fn print_comma(&mut self) {
self.print(b',');
self.print_char(b',');
}
#[inline]
@ -273,7 +275,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
if MINIFY {
self.needs_semicolon = true;
} else {
self.print_str(b";\n");
self.print_str(";\n");
}
}
@ -287,17 +289,17 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
#[inline]
fn print_ellipsis(&mut self) {
self.print_str(b"...");
self.print_str("...");
}
#[inline]
pub fn print_colon(&mut self) {
self.print(b':');
self.print_char(b':');
}
#[inline]
fn print_equal(&mut self) {
self.print(b'=');
self.print_char(b'=');
}
fn print_sequence<T: Gen<MINIFY>>(&mut self, items: &[T], ctx: Context) {
@ -309,7 +311,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
fn print_curly_braces<F: FnOnce(&mut Self)>(&mut self, span: Span, single_line: bool, op: F) {
self.add_source_mapping(span.start);
self.print(b'{');
self.print_char(b'{');
if !single_line {
self.print_soft_newline();
self.indent();
@ -320,12 +322,12 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
self.print_indent();
}
self.add_source_mapping(span.end);
self.print(b'}');
self.print_char(b'}');
}
fn print_block_start(&mut self, position: u32) {
self.add_source_mapping(position);
self.print(b'{');
self.print_char(b'{');
self.print_soft_newline();
self.indent();
}
@ -334,7 +336,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
self.dedent();
self.print_indent();
self.add_source_mapping(position);
self.print(b'}');
self.print_char(b'}');
}
fn print_body(&mut self, stmt: &Statement<'_>, need_space: bool, ctx: Context) {
@ -400,12 +402,12 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
// if let Some(mangler) = &self.mangler {
// if let Some(symbol_id) = symbol_id {
// let name = mangler.get_symbol_name(symbol_id);
// self.print_str(name.clone().as_bytes());
// self.print_str(name.clone());
// return;
// }
// }
self.add_source_mapping_for_name(span, fallback);
self.print_str(fallback.as_bytes());
self.print_str(fallback);
}
fn print_space_before_operator(&mut self, next: Operator) {
@ -454,9 +456,9 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
#[inline]
fn wrap_quote<F: FnMut(&mut Self, char)>(&mut self, s: &str, mut f: F) {
let quote = Self::choose_quote(s);
self.print(quote as u8);
self.print_char(quote as u8);
f(self, quote);
self.print(quote as u8);
self.print_char(quote as u8);
}
fn print_directives_and_statements(

View file

@ -83,13 +83,13 @@ impl NoUnsafeNegation {
// modify `!a instance of B` to `!(a instanceof B)`
let modified_code = {
let mut codegen = fixer.codegen();
codegen.print(b'!');
codegen.print_char(b'!');
let Expression::UnaryExpression(left) = &expr.left else { unreachable!() };
codegen.print(b'(');
codegen.print_char(b'(');
codegen.print_expression(&left.argument);
expr.operator.gen(&mut codegen, Context::default());
codegen.print_expression(&expr.right);
codegen.print(b')');
codegen.print_char(b')');
codegen.into_source_text()
};
fixer.replace(expr.span, modified_code)

View file

@ -141,9 +141,9 @@ impl NoUntypedMockFactory {
),
|fixer| {
let mut content = fixer.codegen();
content.print_str(b"<typeof import('");
content.print_str(string_literal.value.as_bytes());
content.print_str(b"')>(");
content.print_str("<typeof import('");
content.print_str(string_literal.value.as_str());
content.print_str("')>(");
let span = Span::sized(string_literal.span.start - 1, 1);
fixer.replace(span, content)

View file

@ -127,7 +127,7 @@ impl PreferComparisonMatcher {
binary_expr,
call_span_end,
arg_span_end,
parse_expect_jest_fn.local.as_bytes(),
&parse_expect_jest_fn.local,
&parse_expect_jest_fn.modifiers(),
prefer_matcher_name,
fixer,
@ -175,31 +175,31 @@ impl PreferComparisonMatcher {
binary_expr: &BinaryExpression<'a>,
call_span_end: &str,
arg_span_end: &str,
local_name: &[u8],
local_name: &str,
modifiers: &[&KnownMemberExpressionProperty<'a>],
prefer_matcher_name: &str,
fixer: RuleFixer<'_, 'a>,
) -> String {
let mut content = fixer.codegen();
content.print_str(local_name);
content.print(b'(');
content.print_char(b'(');
content.print_expression(&binary_expr.left);
content.print_str(call_span_end.as_bytes());
content.print(b'.');
content.print_str(call_span_end);
content.print_char(b'.');
for modifier in modifiers {
let Some(modifier_name) = modifier.name() else {
continue;
};
if !modifier_name.eq("not") {
content.print_str(modifier_name.as_bytes());
content.print(b'.');
content.print_str(&modifier_name);
content.print_char(b'.');
}
}
content.print_str(prefer_matcher_name.as_bytes());
content.print(b'(');
content.print_str(prefer_matcher_name);
content.print_char(b'(');
content.print_expression(&binary_expr.right);
content.print_str(arg_span_end.as_bytes());
content.print_str(arg_span_end);
content.into_source_text()
}
}

View file

@ -135,12 +135,12 @@ impl PreferExpectResolves {
call_expr.span.end,
);
formatter.print_str(b"await");
formatter.print_str("await");
formatter.print_hard_space();
formatter.print_str(jest_expect_fn_call.local.as_bytes());
formatter.print(b'(');
formatter.print_str(&jest_expect_fn_call.local);
formatter.print_char(b'(');
formatter.print_str(fixer.source_range(arg_span));
formatter.print_str(b".resolves");
formatter.print_str(".resolves");
fixer.replace(call_expr.span, formatter)
}
}

View file

@ -167,9 +167,9 @@ impl PreferMockPromiseShorthand {
) -> String {
let mut content = fixer.codegen();
content.print_str(prefer_name);
content.print(b'(');
content.print_char(b'(');
if call_expr.arguments.is_empty() {
content.print_str(b"undefined");
content.print_str("undefined");
} else {
for argument in &call_expr.arguments {
if let Some(expr) = argument.as_expression() {

View file

@ -139,38 +139,38 @@ impl PreferSpyOn {
fixer: RuleFixer<'_, 'a>,
) -> String {
let mut formatter = fixer.codegen();
formatter.print_str(b"jest.spyOn(");
formatter.print_str("jest.spyOn(");
match left_assign {
MemberExpression::ComputedMemberExpression(cmp_mem_expr) => {
formatter.print_expression(&cmp_mem_expr.object);
formatter.print(b',');
formatter.print_char(b',');
formatter.print_hard_space();
formatter.print_expression(&cmp_mem_expr.expression);
}
MemberExpression::StaticMemberExpression(static_mem_expr) => {
let name = &static_mem_expr.property.name;
formatter.print_expression(&static_mem_expr.object);
formatter.print(b',');
formatter.print_char(b',');
formatter.print_hard_space();
formatter.print_str(format!("\'{name}\'").as_bytes());
formatter.print_str(format!("\'{name}\'").as_str());
}
MemberExpression::PrivateFieldExpression(_) => (),
}
formatter.print(b')');
formatter.print_char(b')');
if has_mock_implementation {
return formatter.into_source_text();
}
formatter.print_str(b".mockImplementation(");
formatter.print_str(".mockImplementation(");
if let Some(expr) = Self::get_jest_fn_call(call_expr) {
formatter.print_expression(expr);
}
formatter.print(b')');
formatter.print_char(b')');
formatter.into_source_text()
}

View file

@ -167,24 +167,24 @@ impl PreferToHaveLength {
return formatter.into_source_text();
};
formatter.print_str(b"expect(");
formatter.print_str(prop_ident.name.as_bytes());
formatter.print_str(b")");
formatter.print_str("expect(");
formatter.print_str(prop_ident.name.as_str());
formatter.print_str(")");
if let Some(kind_val) = kind {
if kind_val == "ComputedMember" {
let property = property_name.unwrap();
formatter.print_str(b"[\"");
formatter.print_str(property.as_bytes());
formatter.print_str(b"\"]");
formatter.print_str("[\"");
formatter.print_str(property);
formatter.print_str("\"]");
} else if kind_val == "StaticMember" {
formatter.print_str(b".");
formatter.print_str(".");
let property = property_name.unwrap();
formatter.print_str(property.as_bytes());
formatter.print_str(property);
}
}
formatter.print_str(b".toHaveLength");
formatter.print_str(".toHaveLength");
formatter.into_source_text()
}
}

View file

@ -142,21 +142,21 @@ fn build_code<'a>(fixer: RuleFixer<'_, 'a>, expr: &CallExpression<'a>) -> Fix<'a
match &expr.callee {
Expression::Identifier(ident) => {
formatter.print_str(ident.name.as_bytes());
formatter.print_str(b".todo(");
formatter.print_str(ident.name.as_str());
formatter.print_str(".todo(");
}
Expression::ComputedMemberExpression(expr) => {
if let Expression::Identifier(ident) = &expr.object {
formatter.print_str(ident.name.as_bytes());
formatter.print_str(b"[");
formatter.print_str(b"'todo'");
formatter.print_str(b"](");
formatter.print_str(ident.name.as_str());
formatter.print_str("[");
formatter.print_str("'todo'");
formatter.print_str("](");
}
}
Expression::StaticMemberExpression(expr) => {
if let Expression::Identifier(ident) = &expr.object {
formatter.print_str(ident.name.as_bytes());
formatter.print_str(b".todo(");
formatter.print_str(ident.name.as_str());
formatter.print_str(".todo(");
}
}
_ => {}
@ -164,17 +164,17 @@ fn build_code<'a>(fixer: RuleFixer<'_, 'a>, expr: &CallExpression<'a>) -> Fix<'a
if let Argument::StringLiteral(ident) = &expr.arguments[0] {
// Todo: this punctuation should read from the config
formatter.print(b'\'');
formatter.print_str(ident.value.as_bytes());
formatter.print(b'\'');
formatter.print(b')');
formatter.print_char(b'\'');
formatter.print_str(ident.value.as_str());
formatter.print_char(b'\'');
formatter.print_char(b')');
} else if let Argument::TemplateLiteral(temp) = &expr.arguments[0] {
formatter.print(b'`');
formatter.print_char(b'`');
for q in &temp.quasis {
formatter.print_str(q.value.raw.as_bytes());
formatter.print_str(q.value.raw.as_str());
}
formatter.print(b'`');
formatter.print(b')');
formatter.print_char(b'`');
formatter.print_char(b')');
}
fixer.replace(expr.span, formatter)

View file

@ -198,7 +198,7 @@ impl ExplicitLengthCheck {
let start = ctx.source_text().as_bytes()[span.start as usize - 1];
need_pad_start = start.is_ascii_alphabetic() || !start.is_ascii();
}
if (span.end as usize) < ctx.source_text().as_bytes().len() {
if (span.end as usize) < ctx.source_text().len() {
let end = ctx.source_text().as_bytes()[span.end as usize];
need_pad_end = end.is_ascii_alphabetic() || !end.is_ascii();
}

View file

@ -224,18 +224,18 @@ fn diagnose_array_in_array_spread<'a>(
// [ ...[a, b, c], ...[d, e, f] ] -> [a, b, c, d, e, f]
ctx.diagnostic_with_fix(diagnostic, |fixer| {
let mut codegen = fixer.codegen();
codegen.print(b'[');
codegen.print_char(b'[');
let elements =
spreads.iter().flat_map(|arr| arr.elements.iter()).collect::<Vec<_>>();
let n = elements.len();
for (i, el) in elements.into_iter().enumerate() {
codegen.print_expression(el.to_expression());
if i < n - 1 {
codegen.print(b',');
codegen.print_char(b',');
codegen.print_hard_space();
}
}
codegen.print(b']');
codegen.print_char(b']');
fixer.replace(outer_array.span, codegen)
});
}

View file

@ -70,8 +70,8 @@ impl Rule for RequireNumberToFixedDigitsArgument {
let span_source_code =
fixer.source_range(parenthesis_span_without_right_one);
formatter.print_str(span_source_code.as_bytes());
formatter.print_str(b"0)");
formatter.print_str(span_source_code);
formatter.print_str("0)");
formatter.into_source_text()
};

View file

@ -77,19 +77,19 @@ impl Rule for SwitchCaseBraces {
let mut formatter = fixer.codegen();
if let Some(case_test) = &case.test {
formatter.print_str(b"case ");
formatter.print_str("case ");
formatter.print_expression(case_test);
} else {
formatter.print_str(b"default");
formatter.print_str("default");
}
formatter.print_colon();
formatter.print_hard_space();
formatter.print(b'{');
formatter.print_char(b'{');
case.consequent
.iter()
.for_each(|x| x.gen(&mut formatter, Context::default()));
formatter.print(b'}');
formatter.print_char(b'}');
formatter.into_source_text()
};