Commit graph

124 commits

Author SHA1 Message Date
camc314
a9544ae3eb feat(minifier): partially implement minification for some known string methods (#6424)
- implements minification for `toLowerCase`, `toUpperCase` and `trim`
2024-10-10 15:23:03 +00:00
camc314
9dc4ee9c98 feat(minifier): implement block stmt support for StatementFusion (#6422) 2024-10-10 14:41:04 +00:00
7086cmd
c5deb3235e test(minifier): port the rest of tests (#6420) 2024-10-10 12:28:00 +00:00
dalaoshu
e59da61755
test(minifier): add all test cases for collapse_variable_declarations (#6421)
closes #6227

I noticed that the implementation of `collapse-variable-declarations`
seems incomplete and appears quite simple. Therefore, I would like to
quickly add all the test cases to work on this.

Previously, I saw that `DonIsaac` had also submitted a related PR, but
he might have been too busy to respond for a long time. I want to
apologize for closing his PR.
2024-10-10 20:27:31 +08:00
7086cmd
73d6a4a3cf test(minifier): port all replace_known_methods tests. (#6418) 2024-10-10 10:20:55 +00:00
7086cmd
994b60b420 refactor(minifier): use builtin get_number_value. (#6335) 2024-10-09 12:55:34 +00:00
7086cmd
97ac179320 feat(minifier): arithmetic operations for infinity. (#6332)
I do not anticipate that this will be utilized in production 😂 .
2024-10-09 12:55:33 +00:00
dalaoshu
13b0b0b07e
feat(minifier): fold literal object constructors on window (#6379)
Fold literal object constructors on window: `window.Object()` -> `{}` or
`window.Object?.()` -> `Object?.()`


92d42692bb/src/com/google/javascript/jscomp/PeepholeSubstituteAlternateSyntax.java (L98-L99)
2024-10-09 09:04:43 +08:00
dalaoshu
87f700fa24
chore(minifier): align test name with closure-compiler (#6359)
Keep consistency in test naming.
2024-10-08 16:35:14 +08:00
7086cmd
e304e8cd2b feat(minifier): minify exponential arithmetic operation. (#6281) 2024-10-07 12:59:27 +00:00
7086cmd
ac5a23fd34 refactor(minifier): use ctx.ast.vec instead of Vec::new. (#6331) 2024-10-07 12:25:35 +00:00
7086cmd
f9ae70c74a feat(minifier): minify basic arithmetic calculations. (#6280)
It uses to_string to check which is shorter, which is extremely tough. Waiting for further refactor.
2024-10-07 10:41:06 +00:00
7086cmd
964d71e1d2 test(minifier): add arithmetic tests for fold constants. (#6269) 2024-10-07 09:37:30 +00:00
camchenry
4008afe512 feat(minifier): fold array and object constructors (#6257)
This will fold expressions like `new Object()` to `{}`, and `new Array()` to `[]`. Based on the closure compiler tests: b7e380b632/test/com/google/javascript/jscomp/PeepholeSubstituteAlternateSyntaxTest.java (L78).

This is outside my usual area, so feedback is welcome.

NOTE: this was previously a full stack of PRs, but Graphite decided to stop working completely for some reason and only gave me this error when I submitted a PR:
```
ERROR: Failed to submit PR for 10-02-feat_minifier_fold_single_arg_new_array_expressions:
{}
```
so I decided to just completely remake this stack and submit as 1 PR.
2024-10-07 06:02:07 +00:00
dalaoshu
d953a6be02
fix(minifier): correct the reference link (#6283)
These are minor changes, and recently I’ve been learning and trying to
implement some features of `oxc_minifier`, which feels a bit complex.

By the way, I’m wondering whether we should gradually add test cases
during the feature implementation process or just copy all the
corresponding tests directly? Perhaps we could implement something like
`rulegen` similar to `linter`?
2024-10-05 08:54:59 +08:00
7086cmd
37cbabbac4 fix(minifier): should not handle the strict operation for bool comparison. (#6261) 2024-10-03 12:16:10 +00:00
7086cmd
fcb4651819 test(minifier): enable null comparison with bigint. (#6252) 2024-10-03 12:16:09 +00:00
7086cmd
e29c0676d6 fix(minifier): handle exceeded shifts. (#6237)
Related: #6161, the last situation.

```js
// https://github.com/tc39/test262/blob/main/test/language/expressions/unsigned-right-shift/S9.6_A2.2.js
test((-2147483649 >>> 0) !== 2147483647)
```
2024-10-03 02:52:05 +00:00
7086cmd
115ccc941e feat(minifier): bitwise not in exceeded value. (#6235)
```rs
        test("x = ~2147483658.0", "x = 2147483637");
        test("x = ~-2147483658", "x = -2147483639");
```

Used `wrapping_neg`, and maybe it is a great solution for #6161.
2024-10-03 00:16:05 +00:00
7086cmd
ee6c85003d feat(minifier): scaffold peephole replace known methods. (#6245) 2024-10-02 14:06:05 +00:00
7086cmd
c32af57e13 feat(minifier): fold demical bitwise not for bigint. (#6233)
Only demical first, because the rest bases are not natively supported by transforming from raw str.
2024-10-02 13:44:20 +00:00
7086cmd
23b646484c feat(minifier): fold true / false comparison. (#6225)
Input:
```js
a == false
```
Previous:
```js
a == !1
```
Current:
```js
a == 0
```

Only handle it when it is non-plus, non-relation binary expressions. Align with [Closure Compiler](https://closure-compiler.appspot.com/home#code%3D%252F%252F%2520%253D%253DClosureCompiler%253D%253D%250A%252F%252F%2520%2540compilation_level%2520SIMPLE_OPTIMIZATIONS%250A%252F%252F%2520%2540output_file_name%2520default.js%250A%252F%252F%2520%2540formatting%2520pretty_print%250A%252F%252F%2520%253D%253D%252FClosureCompiler%253D%253D%250Ax%2520%253C%253C%2520true%253B%250A%250Ax%2520%252B%2520true%253B%250A%250Ax%2520-%2520true%253B%250A%250Ax%2520%257C%2520true%253B%250A%250Ax%2520%2525%2520true%253B%250A%250Ay%2520!%253D%2520false%253B%250A%250Af()%2520%253D%253D%2520false%253B%250A%250Ax%2520instanceof%2520true%250A%250Ax%2520**%2520true%250A%250Ax%2520%2526%2520true%250A%250Ax%2520%255E%2520false%250A%250Ax%2520%253D%253D%2520(x%2520instanceof%2520false)%250A%250Ax%2520instanceof%2520(x%2520%253C%253C%2520true)%250A%250Ax%2520%253D%253D%2520fake(false)).
2024-10-02 13:37:17 +00:00
7086cmd
585ccdad8c feat(minifier): support subtraction assignment. (#6214)
Due to the potential for string concatenation when using the `+=` operator, we should only handle the scenario when using the `-=` operator.
2024-10-02 01:42:56 +00:00
7086cmd
cca0034e8b feat(minifier): handle positive NaN and Infinity. (#6207)
`+NaN` -> `NaN`, `+Infinity` -> `Infinity`.
2024-10-01 10:12:19 +00:00
7086cmd
dac8f09232 feat(minifier): minify unary plus negation. (#6203)
resolves #6201.
It is uncertain whether this applies to other situations, so let us eliminate it in negation first, and after I have conducted a comprehensive investigation of the Closure Compiler, we can make a definitive decision.
2024-10-01 07:13:39 +00:00
Boshen
3b79e1bc9d feat(minifier): evaluate bigint in fold constant (#6178)
relates #6161
2024-09-30 12:53:42 +00:00
Boshen
1cee207050 refactor(minifier): some boilerplate work for PeepholeFoldConstants (#6054) 2024-09-29 15:22:12 +00:00
Dunqing
60c52ba2b9 feat(ast): allow passing span to void_0 method (#6065)
unblock #6021

Keep the original expression's `span` to insert comments correctly. Have tested in #6021 and it worked
2024-09-26 05:46:40 +00:00
Boshen
e0a895962d fix(minifier): compute void number as undefined (#6028) 2024-09-24 14:39:44 +00:00
Boshen
5c323a2105 feat(minifier): loop compressor passes (#6013) 2024-09-24 03:09:35 +00:00
Boshen
0a2f68756f refactor(minifier): move dce conditional expression to RemoveDeadCode (#5971)
This is aligned to closure compiler
2024-09-23 10:22:00 +00:00
Boshen
9076deefca feat(minifier): implement part of StatementFusion (#5936) 2024-09-21 09:24:01 +00:00
Boshen
9b3cc36643 chore(minifier): add boilerplate for StatementFusion and ExploitAssigns (#5914) 2024-09-20 08:51:10 +00:00
Boshen
943bd76679 refactor(minifier): move tests to their src files (#5912) 2024-09-20 07:56:37 +00:00
Boshen
144611ef49 refactor(minifier): align ast pass names with closure compiler (#5908) 2024-09-20 05:20:07 +00:00
Boshen
e968e9ffd0 feat(minifier): constant fold nullish coalescing operator (#5761) 2024-09-13 13:25:58 +00:00
Boshen
8ff013ada1 fix(minifier): handle dce CallExpression::callee (#5752) 2024-09-13 10:46:14 +00:00
Boshen
2890c98d62 refactor(minifier): add tests for remove_syntax (#5749) 2024-09-13 08:59:45 +00:00
Boshen
9a9d8f61d4 refactor(minifier): replace self.ast with ctx.ast (#5748) 2024-09-13 08:49:45 +00:00
Boshen
6bc13f6cd4 feat(minifier): add MinimizeConditions pass (#5747)
I expect small performance regression.

But managed to improve the following case from react.developmement.js

```
oxc  main ❯ diff before.js after.js
670c670
< 		if (!(dispatcher !== null)) throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.");
---
> 		if (dispatcher === null) throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.");
```
2024-09-13 08:31:45 +00:00
Boshen
746f7b3a02 refactor(minifier): align code with closure compiler (#5717)
also fixes #4341
2024-09-12 04:18:41 +00:00
Boshen
68c3cf544f feat(minifier): fold void 1 -> void 0 (#5670) 2024-09-10 08:11:10 +00:00
Boshen
c6bbf94f4c feat(minifier): constant fold unary expression (#5669) 2024-09-10 07:18:54 +00:00
Boshen
86256ea238 feat(minifier): constant fold typeof (#5666)
closes #5628
2024-09-10 04:43:00 +00:00
Boshen
1bed5ce2a5 chore: run cargo +nightly fmt to sort imports (#5503)
They are never going to be stable are they ... cedf7a4daa/.rustfmt.toml (L8-L16)
2024-09-06 04:04:26 +00:00
IWANABETHATGUY
0f64d106a0 refactor(minifier): remove duplicated helper move_out_expression (#5007) 2024-08-20 14:00:33 +00:00
Boshen
46cb1c1b7b fix(minifier): handle Object.definedPropert(exports for @babel/types/lib/index.js (#4933)
Discoverd in `monitor-oxc`

```javascript
Object.keys(_index6).forEach(function(key) {
	if (key === "default" || key === "__esModule") return;
	if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
	if (key in exports && exports[key] === _index6[key]) return;
	Object.defineProperty(exports, key, {
		enumerable: true,
		get: function() {
			return _index6[key];
		}
	});
});
```

🙃
2024-08-16 06:48:15 +00:00
Boshen
81fd6379e8 fix(minifier): do not fold 0 && (module.exports = {}) for cjs-module-lexer (#4878) 2024-08-13 12:54:59 +00:00
Boshen
879a271d47 fix(minifier): do not join require calls for cjs-module-lexer (#4875) 2024-08-13 12:21:37 +00:00
Boshen
fae8a62a62 fix(minifier): temporarily bail constant folding for tagged template (#4842)
closes #4341
2024-08-12 07:38:25 +00:00
Boshen
fbfd852cf8 refactor(minifier): add NodeUtil trait for accessing symbols on ast nodes (#4734) 2024-08-08 02:48:25 +00:00
Boshen
e0832f8e18 refactor(minifier): use oxc_traverse for AST passes (#4725) 2024-08-07 13:26:29 +00:00
Boshen
17602db6de
refactor(minifier): move tests and files around 2024-08-07 20:01:55 +08:00
Boshen
94d3c31933 fix(minifier): avoid removing function declaration from KeepVar (#4722) 2024-08-07 05:09:32 +00:00
Boshen
bf48c7f02a fix(minifier): fix keep_var keeping vars from arrow functions (#4680) 2024-08-06 07:04:25 +00:00
Boshen
451ac4d0e3
chore: s/elimintation/elimination/ 2024-08-06 14:18:44 +08:00
Boshen
0f5e982d19 perf(minifier): only visit arrow expression after dropping console.log (#4677) 2024-08-06 04:20:41 +00:00
Boshen
e8b662a314 fix(minifier): various fixes to pass minifier conformance (#4667) 2024-08-05 16:31:19 +00:00
camc314
229a0e9c45 feat(minifier): implement dot define for member expressions (#3959)
adds the ability to transform

`process.env.NODE_ENV`

into

`"development"`

when that config is passed in
2024-08-05 12:04:13 +00:00
Boshen
e78cba6464 refactor(minifier): ast passes infrastructure (#4625)
After studying google closure compiler, I'm leaning towards a multi-ast-pass infrastructure for the minifier.

This is one of the few places where we are going to trade maintainability over performance, given the goal of the minifier is compression size not performance.

All of the terminologies and separation of concerns are aligned with google closure compiler.

Infrastructure of `terser` and `esbuild` are not suitable for us to study nor pursuit. Their code are so tightly coupled - I failed to comprehend any of them every time I try to walk through a piece of optmization. Google closure compiler despite being written in Java, it's actually the most readable minifier out there.

To improve performance between ast passes, I envision a change detection system over a portion of the code.

The benchmark will demonstrate the performance regression of running 5 ast passes instead of 2.

To complete this PR, I need to figure out "fix-point" and order of these ast passes.
2024-08-04 11:58:39 +00:00
Boshen
0deb027e6b
feat(minfier): dce if (xxx) else if (false) { REMOVE } (#4407) 2024-07-22 19:57:35 +08:00
overlookmotel
2c7bb9f6c8 refactor(ast): pass final ScopeFlags into visit_function (#4283)
We have a strange workaround for `visit_function` where we pass in `ScopeFlags`, to support creating the scope inside `Function`, but setting different flags for `MethodDefinition`s.

Previously `visit_function` took `Option<ScopeFlags>` and then did `flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function` to it. Personally, I found this confusing. When I was looking at `MethodDefinition`, I was wondering "It's a function, why doesn't it set Function flag too?"

This changes makes it more explicit and clear what `ScopeFlags` everything has.
2024-07-16 07:22:07 +00:00
underfin
f144082a60
fix(minifier): RemoveDeadCode should visit nested expression (#4268) 2024-07-15 19:37:12 +08:00
Boshen
c8184723f4 feat(minifier): dce conditional expression && or || (#4190) 2024-07-11 04:40:23 +00:00
Boshen
54cd04aead feat(minifier): implement dce with var hoisting (#4160) 2024-07-10 11:03:21 +00:00
Boshen
44a894a2f9 feat(minifier): implement return statement dce (#4155)
This isn't complete, I need to figure out `var` hoisting 🙃
2024-07-10 11:03:14 +00:00
Boshen
c6c16a5fc9
feat(minifier): dce all conditional expressions (#4135) 2024-07-09 18:28:33 +08:00
rzvxa
d347aedfda feat(ast)!: generate ast_builder.rs. (#3890)
### Every structure has 2 builder methods:

1. `xxx` e.g. `block_statement`
```rust
    #[inline]
    pub fn block_statement(self, span: Span, body: Vec<'a, Statement<'a>>) -> BlockStatement<'a> {
        BlockStatement { span, body, scope_id: Default::default() }
    }
```
2. `alloc_xxx` e.g. `alloc_block_statement`
```rust
    #[inline]
    pub fn alloc_block_statement(
        self,
        span: Span,
        body: Vec<'a, Statement<'a>>,
    ) -> Box<'a, BlockStatement<'a>> {
        self.block_statement(span, body).into_in(self.allocator)
    }
```

### We generate 3 types of methods for enums:

1. `yyy_xxx` e.g. `statement_block`
```rust
    #[inline]
    pub fn statement_block(self, span: Span, body: Vec<'a, Statement<'a>>) -> Statement<'a> {
        Statement::BlockStatement(self.alloc(self.block_statement(span, body)))
    }
```
2. `yyy_from_xxx` e.g. `statement_from_block`
```rust
    #[inline]
    pub fn statement_from_block<T>(self, inner: T) -> Statement<'a>
    where
        T: IntoIn<'a, Box<'a, BlockStatement<'a>>>,
    {
        Statement::BlockStatement(inner.into_in(self.allocator))
    }
```
3. `yyy_xxx` where `xxx` is inherited e.g. `statement_declaration`
```rust
    #[inline]
    pub fn statement_declaration(self, inner: Declaration<'a>) -> Statement<'a> {
        Statement::from(inner)
    }
```

------------

### Generic parameters:

We no longer accept `Box<'a, ADT>`, `Atom` or `&'a str`, Instead we use `IntoIn<'a, Box<'a, ADT>>`, `IntoIn<'a, Atom<'a>>` and `IntoIn<'a, &'a str>` respectively.
It allows us to rewrite things like this:
```rust
let ident = IdentifierReference::new(SPAN, Atom::from("require"));
let number_literal_expr = self.ast.expression_numeric_literal(
    right_expr.span(),
    num,
    raw,
    self.ast.new_str(num.to_string().as_str()),
    NumberBase::Decimal,
);
```
As this:
```rust
let ident = IdentifierReference::new(SPAN, "require");
let number_literal_expr = self.ast.expression_numeric_literal(
    right_expr.span(),
    num,
    raw,
    num.to_string(),
    NumberBase::Decimal,
);
```
2024-07-09 00:57:26 +00:00
Boshen
0da9dfbf09
feat(minifier): add constant folding to remove dead code (#4058) 2024-07-05 15:44:01 +08:00
rzvxa
cd1e9bde7f improvement(ast): generate visit_mut.rs. (#4007) 2024-07-02 10:18:51 +00:00
camc314
77a4a0b77c feat(minifier) minify conditional expressions (#3907) 2024-06-26 05:06:53 +00:00
Boshen
dd540c8f0f feat(minifier): add skeleton for ReplaceGlobalDefines ast pass (#3803) 2024-06-21 13:53:59 +00:00
Boshen
f3c3970131 feat(minifier): add skeleton for RemoveDeadCode ast pass (#3802) 2024-06-21 07:18:14 +00:00
Boshen
8027b1e894 refactor(minifier): change prepass to ast_passes::remove_parens (#3801) 2024-06-21 07:18:08 +00:00