Commit graph

76 commits

Author SHA1 Message Date
DonIsaac
270fc53401 chore(bench): include fixers in linter benchmarks (#5307)
Fixing code is an important part of linter logic. We want to make sure fixers for each rule, and the code responsible for applying those fixes, are included in benchmarks.

As it currently stands, fixer closures are applied regardless of whether the user wants fixers to be applied. However, this is an implementation detail and is subject to change. I  also want to bench the performance of `Fixer`.
2024-08-28 23:19:43 +00:00
overlookmotel
b479afdafc ci: transformer benchmark measure transformer itself only (#5193)
Transformer benchmark measure only the transformer itself. Parse, generate `Semantic`, and drop `Semantic` outside of the measured section.

This should:

1. Give us greater visibility of how changes to transformer affect its performance.
2. Reduce variance in transformer benchmarks, since they will no longer include the variance introduced by `SemanticBuilder`.

Not ready to merge yet. We should first add an "end to end" benchmark testing the entire compilation process (parse - semantic - transform - minify - codegen).

This PR depends on https://github.com/Boshen/criterion2.rs/pull/49. This PR currently makes Oxc's dependency on `criterion2` a git dependency on that PR's branch. That can be changed once the upstream PR is merged.
2024-08-27 01:53:27 +00:00
overlookmotel
7c4f009521
refactor(ci): include drop in semantic benchmark (#5245)
Include dropping `Semantic` in semantic benchmark measure.

If you create a `Semantic`, you have to drop it, so the time it takes to
drop is part of the cost of using this API, and we should be working to
reduce it. Therefore I think it should be included in the benchmark.

It'll be interesting to see what effect a PR like #5232 which removes a
bunch of `Vec`s from `Semantic` has on the drop time.
2024-08-27 09:30:52 +08:00
Boshen
293668bebd
chore(tasks): parse regular expression in parser benchmark (#5212) 2024-08-26 13:11:09 +08:00
Boshen
4b49cf8ce4 feat(transformer): always pass in symbols and scopes (#5087)
We no longer need to build semantic data inside the transformer.

The caller should be responsible for handling semantic data and its
errors.

The best way to achieve this in via `CompilerInterface`.

closes #3565
2024-08-22 16:06:31 +00:00
overlookmotel
e42ac3a2a0
feat(sourcemap): add ConcatSourceMapBuilder::from_sourcemaps (#4639)
Introduce new method `ConcatSourceMapBuilder::from_sourcemaps`.

Where all the sourcemaps being concatenated exist at time that you
create `ConcatSourceMapBuilder`, it's faster to use `from_sourcemaps`,
because it pre-allocates enough space for the data it will hold and so
avoids memory copying.

Before:

```rs
let mut builder = ConcatSourceMapBuilder::default();
builder.add_sourcemap(&sourcemap1, 0);
builder.add_sourcemap(&sourcemap2, 100);
builder.add_sourcemap(&sourcemap3, 100);
let combined = builder.into_sourcemap();
```

After:

```rs
let builder = ConcatSourceMapBuilder::from_sourcemaps(&[
    (&sourcemap1, 0),
    (&sourcemap2, 100),
    (&sourcemap3, 200),
]);
let combined = builder.into_sourcemap();
```
2024-08-06 14:08:17 +08:00
Boshen
0f5e982d19 perf(minifier): only visit arrow expression after dropping console.log (#4677) 2024-08-06 04:20:41 +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
overlookmotel
27fd0628ef
refactor(sourcemap)!: avoid passing Results (#4541)
Refactor building sourcemap JSON to avoid passing `Result`s. `Serialize::serialize` is infallible here as writing to a `Vec<u8>` is infallible.
2024-07-30 04:23:49 +00:00
overlookmotel
affd7685de
fix(benchmark): sourcemap benchmark properly test ConcatSourceMapBuilder (#4528)
Make 2 changes to sourcemap benchmark:

1. Move counting line breaks in output text to outside of the measured loop. This operation is reasonably expensive, and isn't part of what we're trying to measure.

2. It looks like benchmark is trying to measure concatenating 2 source maps, but `for i in 0..1` was actually only concatenating 1.
2024-07-29 11:14:40 +00:00
cinchen
d8c2a836f0
feat(linter): eslint-plugin-vitest/no-import-node-test (#4440)
support
[eslint-plugin-vitest/no-import-node-test](https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-import-node-test.md)
2024-07-29 13:53:42 +08:00
DonIsaac
7a75e0f8a7 refactor(linter): use diagnostic codes in lint rules (#4349)
> This PR is (unfortunately) quite large, but all changes are needed in tandem for this to work properly.

## What This PR Does

Updates the linter to populate diagnostics reported by rules with error codes statically derived from `RuleMeta` + `RuleEnum`.

Doing so required changing how we handle vitest rules. I know @mysterven was hoping to refactor that part of the code, and I think this approach is an improvement (but could probably be cleaned up further).

## Changes

### 1. Auto-Populate Error Codes
`LintContext` now sets an error code scope + error code number for diagnostics reported by lint rules. `LintContext` will not clobber existing codes set by rules, allowing for rule-specific override behavior (e.g. to use `eslint-plugin-react-hooks` as an error scope).

In order to accomplish this, I had to update every diagnostic factory for every rule. While doing this I found some incorrect error messages, or messages that could be easily improved. This is where a large majority of the snapshot diffs come from. Additionally, I was able to reduce string allocations from `format!` usages in diagnostic factories, especially within jest rules.

### 2. Framework and Library Detection
This PR adds `FrameworkFlags`, which specify what (if any) set of libraries and frameworks are being used by a project and/or file. They are passed in two ways:

1. `LintOptions` can specify a set of `framework_hints` that apply to the entire target codebase. Right now these are always empty, but I'm thinking in the future we could sniff `package.json`. It may be helpful for enabling/disabling default rules.
2. When `Linter` gets run on a file, framework information is sniffed from the `LintContext`. Right now, we are only checking for `vitest` imports in `ModuleRecord` and test path prefixes from `source_path`. It may be useful to do something similar for React/NextJS rules in the future. I know that [next/no-html-link-for-pages](https://nextjs.org/docs/messages/no-html-link-for-pages) could benefit greatly from this.
2024-07-20 03:35:00 +00:00
Boshen
91dc0f7866
chore(benchmark): add codegen benchmark (#4207) 2024-07-11 23:58:37 +08:00
Dunqing
54b3b6c0da
chore(benchmark): add isolated declarations (#4078) 2024-07-07 17:14:48 +08:00
Boshen
09cc760475
chore(tasks/benchmark): turn on jsdoc parsing in semantic benchmark 2024-07-04 00:00:52 +08:00
Boshen
5845057bff refactor(transformer): pass in symbols and scopes (#3978)
This PR adds a new method `build_with_symbols_and_scopes` to make semantic building optional, there may be prior steps that has the semantic data already built.
2024-06-30 06:33:48 +00:00
Boshen
8027b1e894 refactor(minifier): change prepass to ast_passes::remove_parens (#3801) 2024-06-21 07:18:08 +00:00
Boshen
ebb6eb8c67
chore(coverage): add a prepass benchmark 2024-06-20 15:07:17 +08:00
Boshen
36de684fd1
chore(benchmark): use a more complated file for codegen_sourcemap 2024-06-19 13:31:21 +08:00
rzvxa
49d28c0dd2 chore(benchmark): enable cfg for linter benchmarks. (#3746)
The benchmark result on this PR - if we filter out the unstable benchmarks - can also be used to show the total impact of CFG enable rules.
2024-06-19 05:12:58 +00:00
Boshen
051ceb6539
chore: improve some format by running cargo +nightly fmt 2024-06-19 00:48:30 +08:00
Boshen
5c38a0fd69 feat(codegen)!: new code gen API (#3740)
This PR introduces two type alias to avoid the confusing const generic `pub struct Codegen<'a, const MINIFY: bool>`

* CodeGenerator - Code generator without whitespace removal.
* WhitespaceRemover - Code generator with whitespace removal.

Usage is changed to a builder pattern:

```rust
CodeGenerator::new()
  .enable_comment(...)
  .enable_sourcemap(...)
  .build(&program);
```
2024-06-18 15:50:12 +00:00
Boshen
b58d8eb88f fix!(codegen): remove the unecessary 4th argument from Codegen::new (#3640) 2024-06-12 07:58:54 +00:00
Boshen
f6752b482f
feat!(ast): make Trivias clonable by adding Arc (#3638)
This makes `Trivias` cloneable and stops us from using `Rc::new` and
`Rc::clone` everywhere.

`Trivias` is rarely cloned so an `Arc` should suffice.
2024-06-12 13:16:10 +08:00
Dunqing
5793ff1986
refactor(transformer): replace &’a Trivias with Rc<Trivias> (#3580)
`Transformer` needs to borrow `Trivias`.
8be1cc8052 (r1630711060)
2024-06-11 13:23:41 +08:00
overlookmotel
fa116448c9 refactor(linter): pass Rc by value (#3587)
Same as #3586.
2024-06-08 11:19:02 +00:00
IWANABETHATGUY
0cdb45a1ff
feat(oxc_codegen): preserve annotate comment (#3465)
1. Copy tests from
efa3dd2d8e/internal/bundler_tests/bundler_dce_test.go (L3833-L3971)
2. Add option to preserve annotate comment like `/* #__NO_SIDE_EFFECTS__
*/` and `/* #__PURE__ */`
2024-05-30 15:25:23 +08:00
overlookmotel
f0cbbbe28c
ci: build each benchmark only with deps it needs (#3221)
This PR builds on #3201 to further speed up the benchmarks and reduce CI
time.

* Build and run each benchmark as separate job (like before).
* But now each bench is only built with the dependencies it needs.
* For linter benchmarks, build benchmark in 1 job (like #3201 does).
* Run each linter fixture in a separate job as they're slow.

This reduces total time to complete benchmarks from between 6m-7m to
~4m40s.

All the individual jobs complete in under 1m30s, except for building
linter benchmark which takes 2m30s. So there won't be the problem of
blocking the CI queue that there was before.

NB: I did try this before, and didn't see a benefit. But I realized
today what I was doing wrong - it only works once the caches are
populated by a previous run on main branch.

So the CI times in this PR won't look good, but once it's merged to
main, it will take effect. Here it is running on main branch of my fork:

https://github.com/overlookmotel/oxc/actions/runs/9030511348

I also added a step to delete the temp artefacts which aren't needed
once the run has completed.
2024-05-10 22:01:24 +08:00
Boshen
5683aceae9
ci: improve benchmark build time by only building once (#3201)
relates #3200
2024-05-08 14:54:10 +08:00
Boshen
a63a45d5b2
refactor(transformer): remove the requirement of Semantic (#3140)
It seems like we need to rebuild the scopes and symbols while
traversing. We can't utilize the scopes and symbols built by semantic
because they are immutable.
2024-04-30 12:48:21 +08:00
Wang Wenzhe
8de7399b08
chore(tasks): observe nursery rule in benchmark (#3082) 2024-04-24 23:03:52 +08:00
overlookmotel
6bc18e15e0
refactor(bench): reuse allocator in parser + lexer benchmarks (#3053)
Re-use allocator in parser + lexer benchmarks.

I believe this is the recommended usage when parsing a bunch of files -
to re-use one allocator rather than create a fresh one for each run, so
it makes sense to me that this is what the benchmark should measure.

Doesn't show much difference on CodSpeed because it only runs the
benchmark once, and it treats allocations as free anyway. But I imagine
the difference may show up a bit more in a standard criterion benchmark.
2024-04-22 09:03:26 +08:00
Yuji Sugiura
ba2121f17d
feat(linter): Add --jsdoc-plugin flag (#2935)
Add flag to:

```sh
$ oxlint --jsdoc-plugin
```


![image](https://github.com/oxc-project/oxc/assets/6259812/0e12ceab-966f-47e1-b4b9-5bc2eb6bdb56)
2024-04-12 10:39:12 +08:00
Boshen
3419306ac0
feat(transformer): add filename (#2941) 2024-04-11 18:43:51 +08:00
Boshen
88270fe605
chore(benchmark): use a larger file for sourcemap benchmark 2024-04-11 15:11:26 +08:00
underfin
28fae2e80a
fix(sourcemap): using serde_json::to_string to quote sourcemap string (#2889) 2024-04-03 12:14:45 +08:00
underfin
b199cb89a2
feat: add oxc sourcemap crate (#2825)
The sourcemap implement port from
[rust-sourcemap](https://github.com/getsentry/rust-sourcemap), but has
some different with it.

- Encode sourcemap at parallel, including quote `sourceContent` and
encode token to `vlq` mappings.
- Avoid `Sourcemap` some methods overhead, like `SourceMap::tokens()`
caused extra overhead at common cases. Here using `SourceViewToken` to
instead of it.
2024-03-28 19:36:38 +08:00
underfin
d9b77d853b
refactor(sourcemap): change sourcemap name to take a reference (#2779) 2024-03-23 21:40:05 +08:00
overlookmotel
508091314f
feat(tasks): benchmark NodeJS parser (#2770)
Add NodeJS parser to benchmarks.

Previous attempt #2724 did not work due CodSpeed producing very
inaccurate results (https://github.com/CodSpeedHQ/action/issues/96).

This version runs the actual benchmarks without CodSpeed's
instrumentation. Then another faux-benchmark runs within Codspeed's
instrumented action and just performs meaningless calculations in a loop
for as long as is required to take same amount of time as the original
uninstrumented benchmarks took.

It's unfortunate that we therefore don't get flame graphs on CodSpeed,
but this seems to be the best we can do for now.
2024-03-20 05:06:09 +00:00
overlookmotel
68f304faa3
feat(tasks): shard linter benchmarks in CI (#2752)
Follow-on from #2751. Further shards linter benchmarks so each fixture runs in its own job.

This reduces total time to run benchmarks by another ~75 secs. So approx 2.5 mins shaved off in total.
2024-03-18 10:50:44 +08:00
Boshen
57bf9857d3
chore(benche): remove redundant black_box because we are using codspeed 2024-03-16 18:59:19 +08:00
Boshen
0f86333437
refactor(ast): refactor Trivias API - have less noise around it (#2692) 2024-03-12 20:16:36 +08:00
Boshen
ef932a3c27
refactor(codegen): clean up API around building sourcemaps (#2602)
closes #2564
2024-03-04 16:03:33 +08:00
Boshen
8bb1084863
feat(codegen): add sourcemap (#2565)
Co-authored-by: underfin <2218301630@qq.com>
2024-03-03 14:44:49 +08:00
overlookmotel
aef593fb50
parser(refactor): promise only one Source on a thread at a time (#2340)
Introduce invariant that only a single `lexer::Source` can exist on a thread at one time.

This is a preparatory step for #2341.

2 notes:

Restriction is only 1 x `ParserImpl` / `Lexer` / `Source` on 1 *thread* at a time, not globally. So this does not prevent parsing multiple files simultaneously on different threads.

Restriction does not apply to public type `Parser`, only `ParserImpl`. `ParserImpl`s are not created in created in `Parser::new`, but instead in `Parser::parse`, where they're created and then immediately consumed. So the end user is also free to create multiple `Parser` instances (if they want to for some reason) on the same thread.
2024-02-08 14:51:17 +08:00
overlookmotel
36c718ee82
feat(tasks): benchmarks for lexer (#2101)
This PR adds benchmarks for the lexer. I'm doing some work on optimizing
the lexer and I thought it'd be useful to see the effects of changes in
isolation, separate from the parser.

These benchmarks may not be ideal to keep long-term, but for now it'd be
useful.

In order to do so, it's necessary for `oxc_parser` crate to expose the
lexer, but have done that without adding it to the docs, and using an
alias `__lexer`.
2024-01-21 14:32:50 +00:00
Boshen
ae4e714713
refactor(linter): remove the LintSettings parameter from LintContext::new. (#2051) 2024-01-16 17:17:46 +08:00
Boshen
39f026f3e2
chore(benchmark): remove custom allocators because they are flaky (#2004) 2024-01-12 16:05:47 +08:00
Boshen
601153fe8f
refactor(benchmark): use more complicated files (#1811)
closes #1806

---------

Co-authored-by: Dunqing <dengqing0821@gmail.com>
2023-12-25 17:27:02 +08:00
msdlisper
6a90cd4af4
feat(linter): add jsx-a11y settings (#1668)
When we developed linter for #1141 , we needed to configure some
settings for `jsx-a11y`, which was not supported before, but I am trying
to support it now.
like this:
```
fn config() -> serde_json::Value {
    serde_json::json!([2,{
        "ignoreNonDOM": true
    }])
}

fn settings() -> serde_json::Value {
    serde_json::json!({
        "jsx-a11y": {
            "components": {
                "Button": "button",
            }
        }
    })
}

let pass = vec![
    ("<Button />", Some(config()), Some(settings())),
];
```
2023-12-16 13:45:14 +08:00