Skip to content

Commit

Permalink
Merge branch 'main' into typescript-ctor-bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
srijan-paul authored Dec 23, 2024
2 parents 440c6fd + 618b6aa commit 3a6f28f
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 75 deletions.
79 changes: 57 additions & 22 deletions crates/oxc_codegen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ impl Gen for VariableDeclaration<'_> {
VariableDeclarationKind::AwaitUsing => "await using",
});
if !self.declarations.is_empty() {
p.print_hard_space();
p.print_soft_space();
}
p.print_list(&self.declarations, ctx);
}
Expand Down Expand Up @@ -1228,6 +1228,7 @@ impl Gen for IdentifierName<'_> {
impl Gen for BindingIdentifier<'_> {
fn gen(&self, p: &mut Codegen, _ctx: Context) {
let name = p.get_binding_identifier_name(self);
p.print_space_before_identifier();
p.add_source_mapping_for_name(self.span, name);
p.print_str(name);
}
Expand Down Expand Up @@ -1414,9 +1415,33 @@ impl Gen for StringLiteral<'_> {
fn gen(&self, p: &mut Codegen, _ctx: Context) {
p.add_source_mapping(self.span);
let s = self.value.as_str();
p.wrap_quote(|p, quote| {
print_unquoted_str(s, quote, p);
});

let quote = if p.options.minify {
let mut single_cost: u32 = 0;
let mut double_cost: u32 = 0;
for b in s.as_bytes() {
match b {
b'\'' => {
single_cost += 1;
}
b'"' => {
double_cost += 1;
}
_ => {}
}
}
if double_cost > single_cost {
b'\''
} else {
b'"'
}
} else {
p.quote
};

p.print_ascii_byte(quote);
print_unquoted_str(s, quote, p);
p.print_ascii_byte(quote);
}
}

Expand Down Expand Up @@ -1470,7 +1495,7 @@ impl GenExpr for StaticMemberExpression<'_> {

impl GenExpr for PrivateFieldExpression<'_> {
fn gen_expr(&self, p: &mut Codegen, _precedence: Precedence, ctx: Context) {
self.object.print_expr(p, Precedence::Prefix, ctx.intersection(Context::FORBID_CALL));
self.object.print_expr(p, Precedence::Postfix, ctx.intersection(Context::FORBID_CALL));
if self.optional {
p.print_str("?");
}
Expand Down Expand Up @@ -1640,18 +1665,22 @@ impl Gen for ObjectProperty<'_> {
PropertyKind::Init => false,
PropertyKind::Get => {
p.add_source_mapping(self.span);
p.print_str("get ");
p.print_str("get");
p.print_soft_space();
true
}
PropertyKind::Set => {
p.add_source_mapping(self.span);
p.print_str("set ");
p.print_str("set");
p.print_soft_space();
true
}
};
if self.method || is_accessor {
if func.r#async {
p.print_str("async ");
p.print_space_before_identifier();
p.print_str("async");
p.print_soft_space();
}
if func.generator {
p.print_str("*");
Expand Down Expand Up @@ -2216,23 +2245,29 @@ impl GenExpr for NewExpression<'_> {
p.print_annotation_comments(self.span.start);
p.print_space_before_identifier();
p.add_source_mapping(self.span);
p.print_str("new ");
p.print_str("new");
p.print_soft_space();
self.callee.print_expr(p, Precedence::New, Context::FORBID_CALL);
p.print_ascii_byte(b'(');
let has_comment = (self.span.end > 0 && p.has_comment(self.span.end - 1))
|| self.arguments.iter().any(|item| p.has_comment(item.span().start));
if has_comment {
p.indent();
p.print_list_with_comments(&self.arguments, ctx);
// Handle `/* comment */);`
if self.span.end > 0 && !p.print_expr_comments(self.span.end - 1) {
p.print_soft_newline();

// Omit the "()" when minifying, but only when safe to do so
if !p.options.minify || !self.arguments.is_empty() || precedence >= Precedence::Postfix
{
p.print_ascii_byte(b'(');
let has_comment = (self.span.end > 0 && p.has_comment(self.span.end - 1))
|| self.arguments.iter().any(|item| p.has_comment(item.span().start));
if has_comment {
p.indent();
p.print_list_with_comments(&self.arguments, ctx);
// Handle `/* comment */);`
if self.span.end > 0 && !p.print_expr_comments(self.span.end - 1) {
p.print_soft_newline();
}
p.dedent();
} else {
p.print_list(&self.arguments, ctx);
}
p.dedent();
} else {
p.print_list(&self.arguments, ctx);
p.print_ascii_byte(b')');
}
p.print_ascii_byte(b')');
});
}
}
Expand Down
22 changes: 10 additions & 12 deletions crates/oxc_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,22 +600,27 @@ impl<'a> Codegen<'a> {
candidates.push(format!("0x{:x}", num as u128));
}

// create `1e-2`
if s.starts_with(".0") {
// create `1e-2`
if let Some((i, _)) = s[1..].bytes().enumerate().find(|(_, c)| *c != b'0') {
let len = i + 1; // `+1` to include the dot.
let digits = &s[len..];
candidates.push(format!("{digits}e-{}", digits.len() + len - 1));
}
} else if s.ends_with('0') {
// create 1e2
}

// create 1e2
if s.ends_with('0') {
if let Some((len, _)) = s.bytes().rev().enumerate().find(|(_, c)| *c != b'0') {
candidates.push(format!("{}e{len}", &s[0..s.len() - len]));
}
} else if let Some((integer, point, exponent)) =
}

// `1.2e101` -> ("1", "2", "101")
// `1.3415205933077406e300` -> `13415205933077406e284;`
if let Some((integer, point, exponent)) =
s.split_once('.').and_then(|(a, b)| b.split_once('e').map(|e| (a, e.0, e.1)))
{
// `1.2e101` -> ("1", "2", "101")
candidates.push(format!(
"{integer}{point}e{}",
exponent.parse::<isize>().unwrap() - point.len() as isize
Expand All @@ -636,13 +641,6 @@ impl<'a> Codegen<'a> {
}
}

#[inline]
fn wrap_quote<F: FnMut(&mut Self, u8)>(&mut self, mut f: F) {
self.print_ascii_byte(self.quote);
f(self, self.quote);
self.print_ascii_byte(self.quote);
}

fn add_source_mapping(&mut self, span: Span) {
if span == SPAN {
return;
Expand Down
14 changes: 8 additions & 6 deletions crates/oxc_codegen/tests/integration/esbuild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,12 @@ fn test_new() {
test("new (import('foo')[bar])", "new (import(\"foo\"))[bar]();\n");
test("new (import('foo'))[bar]", "new (import(\"foo\"))[bar]();\n");

// test_minify("new x", "new x;");
// test_minify("new x.y", "new x.y;");
// test_minify("(new x).y", "new x().y;");
// test_minify("new x().y", "new x().y;");
// test_minify("new x() + y", "new x+y;");
// test_minify("new x() ** 2", "new x**2;");
test_minify("new x", "new x;");
test_minify("new x.y", "new x.y;");
test_minify("(new x).y", "new x().y;");
test_minify("new x().y", "new x().y;");
test_minify("new x() + y", "new x+y;");
test_minify("new x() ** 2", "new x**2;");

// Test preservation of Webpack-specific comments
test(
Expand Down Expand Up @@ -298,6 +298,8 @@ fn test_call() {
fn test_member() {
test("x.y[z]", "x.y[z];\n");
test("((x+1).y+1)[z]", "((x + 1).y + 1)[z];\n");

test_minify("1.3415205933077406e300", "13415205933077406e284;");
}

#[test]
Expand Down
32 changes: 16 additions & 16 deletions crates/oxc_codegen/tests/integration/snapshots/minify.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,71 +11,71 @@ function foo<T extends string>(x: T, y: string, ...restOfParams: Omit<T, 'x'>):
return x;
}
----------
function foo<T extends string>(x:T,y:string,...restOfParams:Omit<T,'x'>): T{return x}
function foo<T extends string>(x:T,y:string,...restOfParams:Omit<T,"x">): T{return x}
########## 2
let x: string[] = ['abc', 'def', 'ghi'];
----------
let x:string[]=['abc','def','ghi'];
let x:string[]=["abc","def","ghi"];
########## 3
let x: Array<string> = ['abc', 'def', 'ghi',];
----------
let x:Array<string>=['abc','def','ghi'];
let x:Array<string>=["abc","def","ghi"];
########## 4
let x: [string, number] = ['abc', 123];
----------
let x:[string,number]=['abc',123];
let x:[string,number]=["abc",123];
########## 5
let x: string | number = 'abc';
----------
let x:string|number='abc';
let x:string|number="abc";
########## 6
let x: string & number = 'abc';
----------
let x:string&number='abc';
let x:string&number="abc";
########## 7
let x: typeof String = 'string';
----------
let x:typeof String='string';
let x:typeof String="string";
########## 8
let x: keyof string = 'length';
----------
let x:keyof string='length';
let x:keyof string="length";
########## 9
let x: keyof typeof String = 'length';
----------
let x:keyof typeof String='length';
let x:keyof typeof String="length";
########## 10
let x: string['length'] = 123;
----------
let x:string['length']=123;
let x:string["length"]=123;
########## 11
function isString(value: unknown): asserts value is string {
if (typeof value !== 'string') {
throw new Error('Not a string');
}
}
----------
function isString(value:unknown): asserts value is string{if(typeof value!=='string'){throw new Error('Not a string')}}
function isString(value:unknown): asserts value is string{if(typeof value!=="string"){throw new Error("Not a string")}}
########## 12
import type { Foo } from 'foo';
----------
import type{Foo}from'foo';
import type{Foo}from"foo";
########## 13
import { Foo, type Bar } from 'foo';
----------
import{Foo,type Bar}from'foo';
import{Foo,type Bar}from"foo";
########## 14
export { Foo, type Bar } from 'foo';
----------
export{Foo,type Bar}from'foo';
export{Foo,type Bar}from"foo";
########## 15
type A<T> = { [K in keyof T as K extends string ? B<K> : K ]: T[K] }
----------
type A<T>={[K in keyof T as K extends string ? B<K> : K]:T[K]};
########## 16
class A {readonly type = 'frame'}
----------
class A{readonly type='frame'}
class A{readonly type="frame"}
########## 17
let foo: { <T>(t: T): void }
----------
Expand Down Expand Up @@ -196,4 +196,4 @@ export { default, /* …, */ } from "module-name";
export { default as name16 } from "module-name";

----------
import defaultExport from'module-name';import*as name from'module-name';import{export1}from'module-name';import{export1 as alias1}from'module-name';import{default as alias}from'module-name';import{export1,export2}from'module-name';import{export1,export2 as alias2}from'module-name';import{'string name' as alias}from'module-name';import defaultExport,{export1}from'module-name';import defaultExport,*as name from'module-name';import'module-name';import{}from"mod";export let name1,name2;export const name3=1,name4=2;export function functionName(){}export class ClassName{}export function*generatorFunctionName(){}export const {name5,name2:bar}=o;export const [name6,name7]=array;export{name8,name81};export{variable1 as name9,variable2 as name10,name82};export{variable1 as 'string name'};export{name1 as default1};export*from'module-name';export*as name11 from'module-name';export{name12,nameN}from'module-name';export{import1 as name13,import2 as name14,name15}from'module-name';export{default}from'module-name';export{default as name16}from'module-name';
import defaultExport from"module-name";import*as name from"module-name";import{export1}from"module-name";import{export1 as alias1}from"module-name";import{default as alias}from"module-name";import{export1,export2}from"module-name";import{export1,export2 as alias2}from"module-name";import{"string name" as alias}from"module-name";import defaultExport,{export1}from"module-name";import defaultExport,*as name from"module-name";import"module-name";import{}from"mod";export let name1,name2;export const name3=1,name4=2;export function functionName(){}export class ClassName{}export function*generatorFunctionName(){}export const{name5,name2:bar}=o;export const[name6,name7]=array;export{name8,name81};export{variable1 as name9,variable2 as name10,name82};export{variable1 as "string name"};export{name1 as default1};export*from"module-name";export*as name11 from"module-name";export{name12,nameN}from"module-name";export{import1 as name13,import2 as name14,name15}from"module-name";export{default}from"module-name";export{default as name16}from"module-name";
15 changes: 14 additions & 1 deletion crates/oxc_codegen/tests/integration/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ use oxc_codegen::CodegenOptions;

use crate::tester::{test, test_minify, test_minify_same, test_options};

#[test]
fn decl() {
test_minify("const [foo] = bar", "const[foo]=bar;");
test_minify("const {foo} = bar", "const{foo}=bar;");
test_minify("const foo = bar", "const foo=bar;");
}

#[test]
fn module_decl() {
test("export * as foo from 'foo'", "export * as foo from \"foo\";\n");
Expand All @@ -13,7 +20,7 @@ fn module_decl() {
#[test]
fn expr() {
test("new (foo()).bar();", "new (foo()).bar();\n");
test_minify("x in new Error()", "x in new Error();");
test_minify("x in new Error()", "x in new Error;");

test("1000000000000000128.0.toFixed(0)", "0xde0b6b3a7640080.toFixed(0);\n");
test_minify("1000000000000000128.0.toFixed(0)", "0xde0b6b3a7640080.toFixed(0);");
Expand Down Expand Up @@ -398,3 +405,9 @@ fn directive() {
test_options("'\"'", "'\"';\n", double_quote.clone());
test_options(r#""'\"""#, "\"'\\\"\";\n", double_quote);
}

#[test]
fn getter_setter() {
test_minify("({ get [foo]() {} })", "({get[foo](){}});");
test_minify("({ set [foo]() {} })", "({set[foo](){}});");
}
16 changes: 12 additions & 4 deletions crates/oxc_ecmascript/src/constant_evaluation/value_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@ pub enum ValueType {
}

impl ValueType {
pub fn is_undefined(self) -> bool {
self == Self::Undefined
}

pub fn is_null(self) -> bool {
self == Self::Null
}

pub fn is_string(self) -> bool {
matches!(self, Self::String)
self == Self::String
}

pub fn is_number(self) -> bool {
matches!(self, Self::Number)
self == Self::Number
}

pub fn is_bigint(self) -> bool {
matches!(self, Self::BigInt)
self == Self::BigInt
}

pub fn is_boolean(self) -> bool {
matches!(self, Self::Boolean)
self == Self::Boolean
}
}

Expand Down
3 changes: 2 additions & 1 deletion crates/oxc_linter/src/rules/import/named.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ declare_oxc_lint!(
/// import { SomeNonsenseThatDoesntExist } from 'react'
/// ```
Named,
correctness
nursery // There are race conditions in the runtime which may cause the module to
// not find any exports from `exported_bindings_from_star_export`.
);

impl Rule for Named {
Expand Down
Loading

0 comments on commit 3a6f28f

Please sign in to comment.