Commit graph

7865 commits

Author SHA1 Message Date
Boshen
3d64cefe10
feat(allocator): add Send + Sync to HashMap 2025-01-18 14:24:12 +08:00
Boshen
6c4081e148
chore: update pnpm lock file 2025-01-18 14:05:58 +08:00
Boshen
2f0314eec2
feat(npm/oxc-minify): npm package and publish script (#8579) 2025-01-18 12:12:42 +08:00
Boshen
7f4b302508
chore: vitest 3.0.0 (#8578) 2025-01-18 12:10:01 +08:00
overlookmotel
fcbca322d7 refactor(ast): rename #[estree(with)] to #[estree(via)] (#8564)
Follow-on after #8560. Rename `#[estree(with)]` attr introduced in #8560 for struct fields to `#[estree(via)]`. This is to match the attr which does the same thing on struct itself. e.g.:

869bc73e67/crates/oxc_ast/src/ast/literal.rs (L23-L29)
2025-01-18 03:59:59 +00:00
camc314
4d4e805691 feat(minifier): collapse if stmt with empty consequent (#8577) 2025-01-18 03:51:40 +00:00
Alexander S.
41f2070895
fix(linter): rule no-restricted-imports support missing options (#8076)
> The regex property is used to specify the regex patterns for
restricting modules.
> Note: regex cannot be used in combination with group.

_https://eslint.org/docs/latest/rules/no-restricted-imports#regex_

> This option allows you to use regex patterns to restrict import names:


_https://eslint.org/docs/latest/rules/no-restricted-imports#importnamepattern_

> This is a string option. Inverse of importNamePattern, this option
allows imports that matches the specified regex pattern. So it restricts
all imports from a module, except specified allowed patterns.
> Note: allowImportNamePattern cannot be used in combination with
importNames, importNamePattern or allowImportNames.


_https://eslint.org/docs/latest/rules/no-restricted-imports#allowimportnamepattern_

Needed to install `regress` to support JS Sntax like Lookaheads and
Lookbehinds

Next Goals:
- https://github.com/oxc-project/oxc/pull/7894
- Improve spans
- Error for wrong configurations
- update documentation
- Output messages like
[eslint](https://github.com/eslint/eslint/blob/main/lib/rules/no-restricted-imports.js#L140-L184)
2025-01-18 11:50:36 +08:00
Alexander S.
8c6e0a6fa3
refactor(language_server): simplify IsolatedLintHandler (#8183)
the `PathBuf` is only leeded in line 47. I do not know why the other
methods should handle it and return the result.
And a simple fast return.
2025-01-18 11:49:21 +08:00
overlookmotel
63eb29868d perf(span): compare Spans as single u64s (#8300)
#8298 made `Span` aligned on 8 on 64-bit platforms. Utilize this property to compare `Span`s as a single `u64` instead of 2 x `u32`s. This removes some really weird assembly which compiler otherwise produces, using expensive SIMD operations for a simple comparison: https://godbolt.org/z/sEf9MGvsr

Note: This only affects comparing `&Span`s. Makes no difference when comparing owned `Span`s.
2025-01-18 01:47:10 +00:00
overlookmotel
a43560c056 perf(span): hash Span as a single u64 (#8299)
#8298 made `Span` aligned on 8 on 64-bit platforms. Utilize this property to hash `Span` as a single `u64` instead of 2 x `u32`s. This reduces hashing a `Span` with `FxHash` to 3 instructions (down from 7), and 1 register (down from 3). https://godbolt.org/z/4q36xrWG8
2025-01-18 01:47:10 +00:00
overlookmotel
b5ed58e237 refactor(span): all methods take owned Span (#8297)
`Span` is `Copy` and 8 bytes. There is no point in the extra indirection of passing `&Span` to functions (`&Span` is also 8 bytes).
2025-01-18 01:47:09 +00:00
overlookmotel
3fff7d293b perf(span): align Span same as usize (#8298)
`Span` consists of 2 x `u32` (8 bytes total). Align `Span` on 8 bytes on 64-bit platforms. This means that, on 64-bit platforms, `Span` can be treated as equivalent to a `u64` and stored in a single register (instead of requiring 2).

A side-effect is that all AST structs also become aligned on 8. This will be a useful property later on as we can remove alignment calculations from `Allocator::alloc` (since everything now has same alignment).

`BooleanLiteral` (and `BoundaryAssertion`, `CharacterClassEscape` and `IndexedReference` from `oxc_regular_expression` crate) increase from 12 bytes to 16 bytes due to the higher alignment. But this makes no practical difference as they'd almost always end up with padding around them in arena anyway, as they'll be surrounded by 8-aligned types.
2025-01-18 01:47:08 +00:00
overlookmotel
bfd0b0da17 ci(benchmark): make lexer benchmark more realistic (#8573)
The lexer benchmarks had a problem. The lexer alone cannot make sense of regexp literals, template literals, or JSX text elements - it needs the parser "driving" it.

So lexer was producing plenty of errors on some benchmarks. This is unrealistic - when driven by the parser, the lexer produces no errors. Generating diagnostics is relatively expensive, so this was skewing the benchmarks somewhat.

Solve this by cleaning up the input source text to replace these syntaxes with string literals prior to running the benchmarks.

Unfortunately lexer benchmarks don't exercise the code paths for these syntaxes, but there isn't much we can do about that. We can judge by the parser benchmarks, which are the more important ones anyway.
2025-01-18 01:47:07 +00:00
overlookmotel
76ea52babe perf(allocator): inline Box methods (#8572)
Add `#[inline]` or `#[inline(always)]` to many of `Box`'s methods. In particular, `Box::new_in` should absolutely always be inlined, for the same reasons that `Allocator::alloc` should be.
2025-01-18 01:23:57 +00:00
overlookmotel
fae4cd22ee refactor(allocator)!: remove Vec::into_string (#8571)
We can use `String::from_utf8` instead (introduced in #8568). This matches `std::str::String`s method.
2025-01-18 01:23:56 +00:00
overlookmotel
e87c0014b4 fix(allocator): statically prevent memory leaks in allocator (#8570)
Prevent memory leaks by statically preventing `Drop` types from being allocated in the arena.

Attempting to allocate any `Drop` type in the arena now produces a compilation failure.

The stabilization of `const {}` blocks in Rust 1.79.0 gave the mechanism required to enforce this at compile time without a mess of generics and traits, and in a way which should not hurt compile times (and zero runtime cost).

This PR is what discovered `CompactString`s being stored in arena in the mangler (fixed in #8557).

Note: The compilation failure occurs in `cargo build` not `cargo check`. So unfortunately errors don't appear in Rust Analyser, only when you run `cargo build`. From what I've read, stable Rust does not offer any solution to this at present. But the errors are reasonably clear what the problem is, and point to the line where it occurs.
2025-01-18 01:23:56 +00:00
overlookmotel
95bc0d7d96 refactor(allocator)!: Allocator do not deref to bumpalo::Bump (#8569)
Do not expose that our arena allocator is based on Bumpalo, by removing `Deref` and `DerefMut` impls. Instead implement the methods we use on `Allocator` itself.

That our allocator is based on Bumpalo is now an internal implementation detail. This will allow us to replace the allocator in future, and enables statically preventing `Drop` types from being stored in the arena (next PR in this stack).

I've intentionally only implemented a small subset of `Bump`'s methods - only `alloc`, `alloc_str`, and `reset`. This will make it simpler to implement a new allocator in future, without having to cover all of bumpalo's large API surface. In the meantime, if it turns out we need additional methods, it will be simple to add them, by just delegating to that method on `Bump`.
2025-01-18 01:23:55 +00:00
overlookmotel
ac05134a6d refactor(allocator): String type (#8568)
Wrap `bumpalo::collections::String` in a new type instead of exporting it directly. This opens the door to:

1. Replacing it with our own `String` type which wraps our `Vec` type, rather than having 2 different implementations of `Vec` (`String` is just a wrapper around `Vec`, but a *different* `Vec` implementation).
2. Adding additional methods to `String` (`String::from_utf8` added in this PR).
2025-01-18 01:23:54 +00:00
overlookmotel
93df57f4c0 perf(allocator): #[inline(always)] methods of Vec which just delegate to allocator_api2 (#8567)
This probably makes little difference, but it's good practice.
2025-01-17 14:27:40 +00:00
overlookmotel
68fab817f1 refactor(allocator): rename inner Vec type (#8566)
Pure refactor. Using a named type `InnerVec` is clearer than having `Vec` and `vec::Vec` (which `Vec` is which?).
2025-01-17 14:27:39 +00:00
overlookmotel
5a28d680f9 perf(allocator): #[inline(always)] methods of HashMap which just delegate to hashbrown (#8565)
This probably makes little difference, but it's good practice.
2025-01-17 14:27:38 +00:00
sapphi-red
19d36771af
fix(ast)!: always return Array<ImportDeclarationSpecifier> for ImportDeclaration.specifiers (#8560)
refs https://github.com/oxc-project/oxc/issues/2854#issuecomment-2595115817
2025-01-17 13:04:59 +00:00
Tapan Prakash
869bc73e67
fix(linter): enhance default_param_last rule to handle optional parameters (#8563)
- Enhanced default_param_last to handle optional parameters based on the
corresponding typescript-eslint rule.
- Added additional test cases from the typescript-eslint rule.

Closes https://github.com/oxc-project/oxc/issues/8556
2025-01-17 11:35:27 +00:00
Boshen
5cb9e979fe
feat(tasks/e2e): transformer + minifier runtime tests for popular npm packages (#8552)
Code extracted from
https://github.com/privatenumber/minification-benchmarks
2025-01-17 19:13:59 +08:00
sapphi-red
8f57929419
refactor(minifier): merge try_compress_type_of_equal_string into try_minimize_binary (#8561)
This compression can be handled by `try_minimize_binary`.
2025-01-17 11:01:54 +00:00
overlookmotel
007e8c017c refactor(ast, regular_expression): shorten ContentEq implementations (#8519)
Shorten codegen-ed implementations of `ContentEq` for enums, matching what Rust produces for `#[derive(PartialEq)]` (inspired by #8517).
2025-01-17 06:24:08 +00:00
overlookmotel
1d4c7a1099 ci(lint): run clippy in release mode (#8541)
CI Clippy task catch lint errors which only appear in release mode (e.g. the one fixed in #8539).

Add a profile for this. `cargo clippy --profile dev-no-debug-assertions` is about 35% faster than `cargo clippy --release` (and is slightly faster than plain `cargo clippy`) but catches the same problems.

This slows down the Clippy CI task, but it still remains faster than running conformance, so I don't think it's likely to slow down CI overall.
2025-01-17 06:14:35 +00:00
overlookmotel
72f425f074 refactor(transformer/class-properties): fix lint warning in release mode (#8539)
Fix a lint warning which only occurs in release mode.
2025-01-17 06:14:34 +00:00
sapphi-red
991a22f907
feat(minifier): fold Array::concat into literal (#8442)
Compress `[].concat(a, [b])` into `[a, b]`.

**References**
- [Spec of `Array::concat`](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.concat)
2025-01-17 06:00:07 +00:00
sapphi-red
3dc2d8b8e9
feat(minifier): fold string concat chaining (#8441)
Compress `"".concat(a).concat(b)` into `"".concat(a, b)`.

**References**
- [Spec of `String::concat`](https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.concat)
2025-01-17 06:00:06 +00:00
Anson Heung
7ab14cc41c
feat(linter): add more Vitest compatible Jest rules (#8445)
There are many `eslint-plugin-vitest` rules that have an equivalent Rust
implementation for the Jest plugin. This PR ports all Jest rules that
passes the Vitest plugin's unit tests.

Some existing Jest rule implementations are not included in the
compatible list, for example:
- `no-large-snapshots` - difference in config initial values
- `no-mocks-import` - mention of the word "Jest" in diagnostics
- `prefer-called-with` - Vitest plugin implements a fix but Jest plugin
didn't
- `prefer-spy-on` - mention of the word "Jest" in diagnostics
- `prefer-to-contain` - the fix is missing
- `valid-title` - configuration options are slightly different

To get a list of already implemented Jest rules, simply run:
```bash
ls crates/oxc_linter/src/rules/jest | sed 's/\.rs$//;s/_/-/g'
```
2025-01-17 13:59:37 +08:00
sapphi-red
a4ae4505f1
feat(minifier): fold array concat chaining (#8440)
Compress `[].concat(a).concat(b)` into `[].concat(a, b)`.

**References**
- [Spec of `Array::concat`](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.concat)

---

### The new assumption

I added a new assumption description in `crates/oxc_minifier/README.md`: "Errors thrown when creating a String or an Array that exceeds the maximum length can disappear or moved".
This is an assumption held by other minifiers. Without this assumption, we have to treat `+` and array creation/update to have a sideeffect and that limits the minification.

For input:
```js
[...Array(Number(2n ** 32n - 1n)),""]
" ".repeat(Number(2n ** 29n - 24n - 1n)) + ' '
export {}
```
(Note that `2 ** 32 - 1` is the max array length and `2 ** 29 - 24` is the max string length on V8.)
This code errors with too long array and too long string on V8 based runtimes.

terser outputs:
```js
Array(Number(2n**32n-1n))," ".repeat(Number(536870887n));export{};
```
No error will happen with this code.

SWC outputs:
```js
[...Array(Number(2n**32n-1n))]," ".repeat(Number(2n**29n-24n-1n));export{};
```
No error will happen with this code.
[playground](https://play.swc.rs/?version=1.10.7&code=H4sIAAAAAAAAA4vW09NzLCpKrNTwK81NSi3SMMpT0NJSMAZSugqGeZqaOkpKsbxcSgpKekWpBamJJajqjCxB6oxMYKoVtBXUFdR5uVIrCvKLShSqa3m5AGRqy%2FBiAAAA&config=H4sIAAAAAAAAA32UO3LjMAyG%2B5zCozrFjostcoDtcgYOTYIyvXxoCNCxJuO7L0RJtjeG3En48AMkAOL7bbfrTmi6j903f%2FLPoAtCuf2zBcdE%2BsKWDkzUaIofqHtf6Qkn5HRAaKbrTDrSpQdqKtz%2F2u8XRRdyRlgViy365N34mNPkOBRAfLCxlUPWCInwf%2F3CSv6aAJX6aD%2FkHECnF0RpVD4R9FCkwCaHoAcEddZFiDKdVBePWUoxwUpg1VDyIPJkPfmcOOcztaCtMtmCgHwBQ%2F4MkoxzsSwhX0%2B4T8MWDrXvW59%2FqOGsQ9Uk5IRLawmfVoh6zB5JuZqkEs5wowYzXIr7U%2BmdKkC1pGfdKfu00ZO%2FAFyBoBGTjiDFbR6O52lL7V4qfXI8sjQKnOdbumWCnouqvHdCZafKQCEvdbOArQamyhrpOAveKB96Cwqc41kRQuOXJ3OUktI4QHYC4P5qJ03VDNTtFW7w6UG8wH%2F4liQP2OIRNR23KY7xkMOLBBHomO0LB24F5W1ceEtchm1ekwUeDbCiS8UGnpcAPwDKKrR9%2BTQb%2FDw4oupDPtzXxOJwve3hqFN%2Ff%2B%2FzKn5bHLqYbW1wWfJTf%2BfV%2FLu7O61beD1B5%2FFzFbac13%2FKOhgeLwYAAA%3D%3D)

esbuild outputs:
```js
[...Array(Number(2n**32n-1n))]," ".repeat(Number(2n**29n-24n-1n))+"";export{};
```
No error will happen with this code.
[esbuild try](https://esbuild.github.io/try/#dAAwLjI0LjIALS1taW5pZnkAWy4uLkFycmF5KE51bWJlcigybiAqKiAzMm4gLSAxbikpLCIiXQoiICIucmVwZWF0KE51bWJlcigybiAqKiAyOW4gLSAyNG4gLSAxbikpICsgJyAnCmV4cG9ydCB7fQ)

OXC outputs:
```js
[...Array(Number(2n**32n-1n))]," ".repeat(Number(2n**29n-24n-1n))+" ";export{};
```
The array error won't happen and the String error will happen with this code.
[playground](https://playground.oxc.rs/#eNpVT71OwzAQfhXrlv4QIhpgIBtLR8SOGZxwCUH22To7baMo746dNEVMd5/u+7sRaijhI8/zV2Y1bN96UyFvCxL7vXiM414caLfLJEj4lCRBSMgZHarwn1u8JG7xtCrEndiIjSS8OMtBjJMkyMBCOQL3lIYfKKgLlIF7zEB3FKBslPYR+No6XC9+MJXVKwqsyDeWzZU8ZeAUe+TZ0vZc47HTSMpEAwjoQ/7jY7JjjKQTvitG8n/ilDuL437zXtyC4hZjKUBfPByeITJq+4UtpvoRmI66plu4tTUpIRovNc/fXcx2qr69YRS1+opmJwps9VHbc9KfkCvr43npNU2/v/WIsw==)
2025-01-17 05:53:54 +00:00
overlookmotel
d17021c834 perf(mangler): optimize base54 function (#8557)
Optimize mangler by creating identifiers in an inline array, instead of using the more expensive `CompactString`, and optimize `base54` function.

There's an unfortunate workaround necessary because of debug mode. In "normal" mode, identifiers are maximum 11 bytes (`usize::MAX` -> `ZrN6rN6rN6r`) but in debug mode they can be up to 25 bytes (`usize::MAX` -> `slot_18446744073709551615`). So this PR splits `build_with_symbols_and_scopes` into 2 branches for "normal" and "debug" modes with a generic function parameterized by max length of the string.

This is not ideal - it will increase binary size a bit, but everything else I tried (e.g. allocating strings into arena) was much slower.

The main motivation for this change wasn't actually performance. While working on allocator, I discovered that `CompactString`s were being allocated in arena (`reserved_names: ArenaVec<CompactStr>`), and wanted to remove them.
2025-01-17 05:47:28 +00:00
Yuji Sugiura
64d38b86b6
refactor(prettier): Verify printing class related nodes (#8559)
Part of #5068
2025-01-17 13:46:07 +08:00
overlookmotel
30a869ead2 perf(semantic): use oxc_allocator::HashMap in ScopeTree (#8554)
Use `oxc_allocator::HashMap` in `ScopeTree`, replacing `hashbrown::HashMap`. `oxc_allocator::HashMap` is non-drop, so it may reduce drop time of `ScopeTree` a little.
2025-01-16 23:29:58 +00:00
overlookmotel
bf4e5e1c18 feat(allocator): add HashMap (#8553)
Add `HashMap` type to `oxc_allocator`. `HashMap` is a thin wrapper around `hashbrown::HashMap`, which allocates in the arena. The inner map is wrapped in `ManuallyDrop`, so `HashMap` is non-`Drop` (same as `oxc_allocator::Vec`).

We use `FxHasher` for all hash maps, so I figured just make that part of the type, rather than having to specify the hasher everywhere we use `HashMap`.
2025-01-16 23:29:57 +00:00
overlookmotel
fa1a6d5ede docs(allocator): update docs for Vec (#8555)
Remove line from `oxc_allocator::Vec` docs saying "Should only be used for storing AST types.". We are now using `Vec` in `Semantic` too, and there's no problem with that.
2025-01-16 19:18:16 +00:00
overlookmotel
a04833787d fix(transformer/class-static-blocks): static block converted to IIFE use span of original block (#8549)
Fix spans in class static blocks and class properties transforms. When a static block is converted to an IIFE, the IIFE should take the span of the static block.
2025-01-16 14:55:53 +00:00
overlookmotel
712633f0bc refactor(transformer): wrap_statements_in_arrow_function_iife utility function (#8548)
Move utility function for creating an IIFE from `ClassStaticBlock` transform to utils module.
2025-01-16 14:55:52 +00:00
overlookmotel
b552f5cfd3 fix(transformer): wrap_in_arrow_function_iife take span of input Expression (#8547)
#8530 introduced a small change. Previously the IIFE had the span of the original expression which is being wrapped, but after that PR it got a dummy `SPAN`. Fix that.
2025-01-16 14:55:51 +00:00
overlookmotel
5206c6ae06 refactor(transformer): rename wrap_in_arrow_function_iife (#8546)
Pure refactor. Rename this function to be more descriptive.
2025-01-16 14:55:51 +00:00
overlookmotel
61077cae9f refactor(transformer): wrap_arrow_function_iife receive an owned Expression (#8545)
Follow-on after #8529. Pure refactor. `wrap_arrow_function_iife` receive an owned `Expression`, instead of `&mut Expression`.

This does require a bit more repeated code in the caller, but still I think it's more appropriate for a utility function. If we use it again elsewhere, it's non-obvious if it replaces the input `&mut Expression` with a `NullLiteral` via `move_expression`. Better to leave that to the caller.
2025-01-16 14:55:50 +00:00
camc314
65c596d002 fix(minifer): keep idents if not in scope when minimizing array exprs (#8551) 2025-01-16 14:26:37 +00:00
camc314
7cc81ef5ef feat(minifier): fold invalid typeof comparisons (#8550) 2025-01-16 14:26:36 +00:00
Boshen
c479a58718
feat(napi/parser): expose dynamic import expressions (#8540)
closes #8369
2025-01-16 22:25:22 +08:00
camc314
f57aac2aee fix(minifier): incorrect folding of expr in bool ctx (#8542)
esbuild code comment is wrong.

8f1faf7d4a/internal/js_ast/js_ast_helpers.go (L2127-L2128)

https://esbuild.github.io/try/#dAAwLjI0LjIALS1taW5pZnkAaWYgKGFueXRoaW5nMSA/ICgwLCBmYWxzZSkgOiBhbnl0aGluZzIpOw
2025-01-16 14:18:03 +00:00
Dunqing
c30654a793 refactor(transformer/arrow-function): wrapping arrow function iife by using wrap_arrow_function_iife (#8530) 2025-01-16 12:49:28 +00:00
Dunqing
6820d24c4a refactor(transformer): move wrap_arrow_function_iife to root utils module (#8529) 2025-01-16 12:42:14 +00:00
Dunqing
f413bb5c64 feat(transformer/optional-chaining): change parent scope for expression when it wrapped with an arrow function (#8511) 2025-01-16 12:21:44 +00:00
overlookmotel
8dd0013e72 refactor(linter/consistent-function-scoping): remove Visit::enter_node usage (#8538)
Use `Visit::visit_*` method instead of `Visit::enter_node` / `leave_node`. A step towards solving #8461, but also may improve performance.
2025-01-16 11:00:11 +00:00