100 Commits
Author SHA1 Message Date
Cameronandleaysgur 3a56e7c0c1 fix(formatter): keep closing HTML comments at the start of a line (#28064)
The three new Annex B declaration fixtures in #28057 parse successfully
but fail after formatting. A comment between `let` and its binding moves
onto the keyword's line: `let --> comment`. A closing HTML comment is
recognized only at the start of a line, so this changes the program or
produces invalid syntax.

Force a hard line break before closing HTML comments. Add a formatter
snapshot covering `let`, `const`, and destructuring declarations, and
document the divergence from Prettier 3.9.10, whose output is rejected
by `node --check`.

Based on the merged submodule update. `just submodules`, `just
coverage`, full `just test -p oxc_formatter` (including Prettier
conformance), `just lint -p oxc_formatter`, and the default-feature
check completed. All three upstream failures disappear: formatter Babel
positives improve from 2271/2280 to 2274/2280. Updated the coverage and
fixture snapshots; output is stable on a second formatting pass.

AI disclosure: prepared and verified with Codex assistance.

---------

Co-authored-by: leaysgur <6259812+leaysgur@users.noreply.github.com>
2026-10-26 13:40:01 +09:00
Cameron c993555ede docs(minifier): align guides with current implementation (#27584) 2026-10-12 19:39:25 +01:00
Cameron eec94b27e5 chore(codegen): revert remove unused minified-printing support (#27340)
This reverts commit b98722887c.
2026-10-05 09:07:58 +00:00
Cameron 7d60ae3ac1 fix(linter/valid-title): continue checks after allowed words (#27146)
With `disallowedWords` configured, `valid-title` returned before
checking patterns, spacing, and duplicate prefixes even when no word
matched. It now continues those checks unless a banned word matches,
matching the upstream Jest and Vitest rules. Regression cases cover both
plugins; `String.raw` titles use the raw quasi and template literal span
so validation matches runtime text and autofixes preserve valid syntax.

Fixes #27137
2026-09-28 15:41:38 +01:00
Cameron 171d8af71a docs(skills): simplify insta snapshot guidance for newer models (#26581)
GPT-6 Astra needs less step-by-step scaffolding, while explicit
completion criteria help it carry work through verification. Following
OpenAI's [guidance on rethinking skills and prompts for GPT-6
Astra](https://developers.openai.com/blog/rethinking-skills-and-prompts-for-gpt-6-astra),
this trims the Insta snapshot skill from 136 lines to 21 and removes
repeated workflows and blanket accept/reject examples.

The shorter skill keeps the important constraints: review expected
output before accepting, use the non-interactive CLI, accept only
snapshots from the current task, and rerun the affected test. It also
makes completion explicit without requiring a commit for every snapshot
update.
2026-09-17 04:14:49 +00:00
Cameronandcamc314 8c7ea7678d fix(ast_visit): account for trimmed source offsets (#26223)
## Summary

- keep UTF-8 translation offsets absolute when the converter is built
from source with a trimmed BOM or partial-source prefix
- extend the Oxlint BOM fixture with the reported comment-before-Unicode
case
- assert the JS plugin API returns the complete comment range and source
slice

Without the fix, the integration snapshot reports an end offset of 4 and
slices `"/*x*"`. With the fix, it reports an end offset of 5 and slices
`"/*x*/"`.

Fixes #26162

*Update*: #26173 fixed the same bug in the same way, and has been
merged. This PR adds more tests, so merging it on top.

Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com>
2026-09-03 13:58:10 +01:00
Cameron 8d94cd1635 fix(linter/eslint/no-useless-rename): preserve type modifiers (#26020)
Preserves inline `type` modifiers when `no-useless-rename` removes a
redundant import or export alias, avoiding semantic changes under
`verbatimModuleSyntax`.

fixes #26004
2026-08-23 17:43:25 +01:00
Cameron 77e318af2e chore(all): add .pnpm-store to .gitignore (#25563)
https://github.com/orgs/pnpm/discussions/6936

maybe this should be in my local gitignore?
2026-08-16 19:11:58 +08:00
Cameron 12937b3201 fix(parser): reject comma expressions in class fields (#25385)
## Summary

- parse ordinary class field initializers as `AssignmentExpression`
- reject unparenthesized comma expressions while preserving
parenthesized sequence expressions
- add paired misc conformance fixtures and update the generated
snapshots

## Root cause

Ordinary class field initializers used `parse_expr`, which accepts a
top-level comma and constructs a sequence expression. The ECMAScript
`Initializer` grammar requires an `AssignmentExpression`, so the
unparenthesized comma must remain for the class-element terminator check
to reject.
2026-08-08 10:59:23 +00:00
Cameron f0f7daeac9 fix(linter/eslint/no-unused-vars): report invalid regex options (#25380)
## Summary

- Return invalid `no-unused-vars` ignore patterns as configuration
errors instead of unwrapping the regex parser error.
- Preserve option-specific diagnostics for each ignore-pattern setting.
2026-08-08 10:55:18 +00:00
Cameron 0e36e21594 refactor(semantic): remove NodeFlags::HasYield (#25399)
## Summary

- Remove `NodeFlags::HasYield` and its accessor now that `require-yield`
detects yields locally.
- Delete the semantic-builder state that existed only to populate the
flag.
- Remove `AstNodeStore::current_node_flags`, which has no remaining
writers or non-empty values.
2026-08-08 10:28:44 +00:00
Cameron 535d0fe62f refactor(linter/eslint/require-yield): find yields with a visitor (#25398)
## Summary

- Replace the semantic `NodeFlags::HasYield` check in `require-yield`
with a rule-local AST visitor.
- Stop traversal at nested functions and arrow functions so only yields
belonging to the current generator count.
- Preserve syntactic handling of delegated, unreachable, and
computed-key yields.
2026-08-08 10:20:22 +00:00
Cameronandcamc314 44e73fde5f fix(linter/unicorn/prefer-array-flat): fix concat.apply suggestions (#25373)
## Summary

- Add fixes for identifier-backed `[].concat.apply([], array)` and
`Array.prototype.concat.apply([], array)` cases.
- Keep other `apply` and `call` patterns diagnostic-only.

---------

Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com>
2026-08-08 09:42:25 +00:00
Cameron f766c2187d test(formatter): cover export declaration shapes (#25096)
## Summary

- add focused formatter coverage for declaration-bearing exports, local
named exports, and source re-exports
- cover comment attachment and prettier-ignore behavior for each export
shape
- include TypeScript type exports and re-export attributes
- covers edge cases to prep for #25095
2026-07-30 14:38:21 +09:00
Connor Shea 6f2b933fa3 perf(linter/import/no-cycle): drop two Vec allocations per graph edge (#25004)
AI Disclosure: generated using Claude Code w/ Opus 5. It has been
reviewed and tested manually to ensure parity and that the improvement
is real and makes sense.

## What this does

`should_traverse_module` collected both matching entry lists into `Vec`s
only to test `!is_empty()` and `all(is_type)`. `ignoreTypes` defaults to
`true`, so this ran on every graph edge considered — and since the
acyclic prefilter in #25003 traverses each file's whole reachable
subgraph, it is now the hottest allocation site in the rule. Chaining
the two `is_type` iterators and peeking is the same predicate with
nothing materialized.

## Measurements

vscode `src`, 7,368 files, `import/no-cycle` as the only enabled rule,
release build. Note that the baseline is the target PR's HEAD, not
`main`.

| metric                  | before    | after    | delta      |
| ----------------------- | --------- | -------- | ---------- |
| rule allocations        | 86.78M    | 38.61M   | **-55.5%** |
| rule bytes              | 6.00 GB   | 4.29 GB  | -28.6%     |
| wall clock              | 1182.8 ms | 1063.0 ms | **-119.8 ms** |
| rule-attributable time  | 1083.0 ms | 963.8 ms | **-11.0%** |

Wall clock is paired interleaved runs with order alternation, n=20:
paired sd 14.7 ms, t=+36.4, faster in 20/20 rounds. The parse-only
control is flat (+0.6 ms, t=+1.45), so the delta is attributable to the
rule rather than to binary layout. Allocation counts come from a
counting global allocator, 2 reps, run-to-run spread 0.003%; both
metrics subtract the parse-only baseline.

## Correctness

- 1,566 `no-cycle` diagnostics on vscode, identical before and after
when sorted.
- All 41 `import::*` tests, the three `no_cycle` tests, and
`oxc/no_barrel_file` pass. Clippy clean.

Short-circuiting differs from the original — `all` stops at the first
`false` where the old code built both `Vec`s first — but only the return
value is observable, and the predicate is unchanged: the old code
required `all(is_type)` over each list separately, which is the same as
over the concatenation.

This change was taken out of #24961 as it was the most promising/best
change in that PR and was the most likely to still have an impact after
the acyclic fix in the target PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-28 11:27:49 +01:00
Connor Shea 79ddb181ce perf(linter/import/no-cycle): skip the graph walk for acyclic modules (#25003)
This is the change from #24963, but as its own PR to avoid dependency on
the larger refactor PR it was targeted at. Benchmarks have been re-run
to ensure that the info is correct, but I'm pretty confident in this
change now.

AI Disclosure: Generated with Claude Code, Opus 5. Reviewed and tested
manually be me.

## What

`run_once` walks the module graph once per direct import, and each walk
explores the module's whole reachable subgraph before concluding "no
cycle". On `vscode/src` that is 78,760 walks producing 1,566
diagnostics, so **98% of them are pure overhead**.

A module is in a cycle **if and only if** some module reachable from it
imports it back. So one traversal of that subgraph answers the question
for every direct import at once. When it says no, skip all the walks.

## Why it can't change what's reported

The prefilter only gates the walks — they still decide what is reported
and reconstruct the cycle path for the diagnostic. It cannot skip a
cycle a walk would have found:

- it traverses the same edges under the same `should_traverse_module`
filter;
- it is unbounded where the walks are bounded by `max_depth`, so its
reachable set is a strict superset;
- it compares by resolved path, not `Arc` identity, matching what the
walks report a cycle on — a file split into multiple sections has one
record per section but one path.

It runs only under the default unbounded `max_depth`, where the walks
cover the whole subgraph anyway and the prefilter replaces work rather
than adding to it. With a small `max_depth` the walks are shallow enough
that an unbounded prefilter could cost more than it saves, so behaviour
there is exactly as before.

## Measurements

`vscode/src` — 7,368 files, 81,512 direct imports, 78,760 walks — with
`import/no-cycle` as the only enabled rule (`number_of_rules: 1`).
Paired interleaved runs with per-round order alternation, n=15,
`--silent`, release builds with `--features allocator`.

### Wall clock

|                       | mean      | sd       |
| --------------------- | --------- | -------- |
| `main`                | 3217.3 ms | 169.3 ms |
| this PR               | 1178.3 ms | 56.1 ms  |
| **paired delta**      | **−2038.9 ms** | 127.6 ms |

t = +61.9, faster in **15/15** paired rounds. Subtracting the parse-only
baseline, rule-attributable time goes **3110.5 ms → 1073.3 ms, 2.9×
faster**.

The parse-only control (same binaries, no rules enabled) is flat — 106.8
ms vs 105.0 ms, paired delta +1.8 ms, t = +0.49 — so the delta is
attributable to the rule and not to binary layout or the harness.

### Allocations

Counted with a global-allocator shim; rule-attributable = total minus a
parse-only run on the same binary.

|         | allocations | bytes    |
| ------- | ----------- | -------- |
| `main`  | 331.0M      | 22.52 GB |
| this PR | 86.8M       | 6.05 GB  |
|         | **−73.8%**  | **−73.1%** |

Counts are stable to within 0.05% across repetitions, and the two
parse-only baselines (separately built binaries) agree to 0.003%, which
is what makes that subtraction meaningful.

## Correctness

- 1,566 diagnostics on `main`, 1,566 on this branch, **identical** after
sorting by `(filename, labels, message, code)`.
- Full `oxc_linter` test suite passes (1,175 tests) with no snapshot
changes; `cargo clippy -p oxc_linter --all-features --all-targets -D
warnings` is clean.

### Cross-codebase parity

Both binaries were also run over five TypeScript codebases, under the
default options plus two variants chosen to stress what is most likely
to break: `ignoreTypes: false` changes which edges
`should_traverse_module` admits, so the prefilter has to apply the
identical filter, and `maxDepth: 5` disables the prefilter entirely.

| codebase | files | config | `main` | this PR | identical |
| --- | --- | --- | --- | --- | --- |
| vscode | 11,674 | default | 2,789 | 2,789 | ✅ |
| actualbudget/actual | 1,789 | default | 188 | 188 | ✅ |
| actualbudget/actual | 1,789 | `ignoreTypes: false` | 591 | 591 | ✅ |
| actualbudget/actual | 1,789 | `maxDepth: 5` | 47 | 47 | ✅ |
| storybook | 4,050 | default | 96 | 96 | ✅ |
| storybook | 4,050 | `ignoreTypes: false` | 430 | 430 | ✅ |
| storybook | 4,050 | `maxDepth: 5` | 40 | 40 | ✅ |
| rolldown | 6,411 | default | 77 | 77 | ✅ |
| rolldown | 6,411 | `ignoreTypes: false` | 239 | 239 | ✅ |
| rolldown | 6,411 | `maxDepth: 5` | 73 | 73 | ✅ |
| microsoft/TypeScript | 39,333 | default | 729 | 729 | ✅ |
| microsoft/TypeScript | 39,333 | `ignoreTypes: false` | 729 | 729 | ✅ |
| microsoft/TypeScript | 39,333 | `maxDepth: 5` | 242 | 242 | ✅ |

Counts are `import(no-cycle)` diagnostics. The comparison is stricter
than the counts: in all 13 runs the **entire** diagnostic array is
element-wise identical after sorting by `(filename, labels, message,
code)` — including the 30,713 parse errors the TypeScript repo's test
fixtures produce — so no diagnostic changed span or cycle path either.
These are full repository checkouts, which is why vscode is 11,674 files
here rather than the 7,368 measured above.
2026-07-28 11:02:13 +01:00
Cameron 7f86fdf603 test(formatter): cover concise arrow parent contexts (#24991)
Adds formatter regression coverage for concise arrow bodies involving
nested `await` expressions, assignment chains, and AMD `define()` calls.
This locks existing parent-context behavior ahead of the
`ArrowFunctionBody` AST migration.

I may have caused a regression in #24987, so this PR adds test coverage
to make sure I don't break it.
2026-07-28 09:41:10 +09:00
Cameronandcamc314 7a8fd75364 refactor(linter/oxc): simplify bad-replace-all-arg (#24901)
## Summary

- rewrite BadReplaceAllArg::run as a single if-let condition chain
- preserve CallExpression-only rule dispatch and existing behavior

Stacked on #24900.

Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com>
2026-07-24 17:42:55 +01:00
Cameron 81e8ed9e9f chore(linter/eslint/no-case-declarations): disable invalid test case (#24799)
There's no point testing these - the parser/coverage handles this already.
2026-07-22 09:56:28 +01:00
Cameron 0e9b46079a fix(isolated-declarations): normalize accessor keys (#24690)
## Summary

- normalize equivalent static accessor keys before getter/setter pairing
- retain structural matching for computed symbol keys
- cover identifier/string and numeric/template accessor pairs

## Root cause

Accessor pairing compared the AST key nodes structurally, so equivalent
JavaScript property names expressed with different key syntax did not
match.

[TS
Playground](https://www.typescriptlang.org/play/?isolatedDeclarations=true#code/MYGwhgzhAEDCD2BbADgVwC4FMAmBldATgJYB2A5gOKbpYHQDeAUNNGddAG5giqYAUASgbMW0AtVQES0AERcemGQG4RAXxER2AbTndeMgLp8OQpi3XrGoSDAQoMOfMXK5qtAEzCWbdNB3B4VBJ0Q0EvUXF0SWkZEnh0AFp0AAtMBOxMawIwdCJ4EiSAT2RFFXMNdgCg9GMALmgSVEQAI0wCUzVGS2soOCQ0LGwAOSa2omAqGjaAZnCfPwBGIw7RMQkpaEJeMuh1Fk1fLQADBaOjE3CLRiA)

Current behaviour (oxc is before, ts (correct) is after.

```diff
@@ -1,12 +1,12 @@
 declare class ComputedStringGetter {
        get value(): string;
-       set ["value"](v);
+       set ["value"](v: string);
 }
 declare class ComputedStringSetter2 {
-       get ["count"](): string;
+       get ["count"](): number;
        set count(v: number);
 }
 declare class ComputedNumericGetter3 {
        get [1](): boolean;
-       set [`1`](v);
+       set [`1`](v: boolean);
 }
```
2026-07-20 11:13:55 +01:00
Cameron 561d14ab45 chore(deps): update oxc-schemars to 0.9.1 (#23281)
## Summary

Updates `oxc-schemars` from `0.9.0` to `0.9.1`.
2026-06-11 14:18:35 +01:00
Cameron f6f0fbf5d9 ci(ecosystem): share label trigger for app ci (#22906)
This is stacked on #22905.

The first PR moved Oxfmt ecosystem CI to a label-triggered workflow.
This follow-up keeps that approach, but avoids having one workflow file
per app. Instead, the Oxfmt-specific workflow is renamed to a shared
ecosystem CI dispatcher that handles both trigger labels:

- `run-oxlint-ecosystem-ci` dispatches `oxlint-ci.yml`
- `run-oxfmt-ecosystem-ci` dispatches `oxfmt-ci.yml`

The release-apps workflow now adds both labels to the generated release
PR, so Oxlint and Oxfmt take the same path: create or update the
tracking comment, dispatch the matching workflow in `oxc-ecosystem-ci`
with the PR ref, then remove the label that triggered the run.
2026-06-02 11:38:33 +09:00
Cameron 97e88a568f ci(oxfmt): trigger ecosystem ci via label (#22905)
The Oxfmt ecosystem CI trigger was still using `/oxfmt-ecosys` comment
command, while the newer monitor-oxc flow uses a short-lived PR label to
kick off the external workflow and then removes the label afterward.

This moves Oxfmt to the same pattern. Adding `run-oxfmt-ecosystem-ci` to
a PR now creates or updates the tracking comment, dispatches
`oxfmt-ci.yml` in `oxc-ecosystem-ci` with the PR ref, and removes the
trigger label after dispatch. The app release workflow now adds that
label to release PRs instead of directly creating the Oxfmt comment and
dispatching the external workflow itself.

Oxlint's release ecosystem dispatch is left as-is for now, since this
change is scoped to the Oxfmt workflow requested in the PR follow-up.
2026-06-02 11:14:36 +09:00
Cameron e1d064e498 fix(transformer/class-properties): reparent lifted private method helpers (#22716)
## Summary

Fixes semantic scope metadata for private method helper functions that
are lifted out of classes nested inside static field initializers.

The class-properties transform converts a private method into a helper
function declaration and emits that helper outside the class. For a
nested class inside a static field initializer, `current_scope_id()`
points at the nested class scope, but the helper is actually emitted
into the surrounding hoist scope. That made semantic rebuild disagree
with the transformed AST.

## Before

```js
class Outer {
  static value = class Inner {
    static #method() {}
  };
}
```

The helper function was reparented as if it still lived under the nested
class scope:

```mermaid
flowchart TD
  Program["enclosing hoist scope"] --> Outer["Outer class scope"]
  Outer --> Field["static field initializer"]
  Field --> Inner["Inner class scope"]
  Inner --> Helper["lifted helper function scope"]
  Helper -.-> Problem["incorrect parent + strict-mode source"]
```

In code, the old logic always used the current scope and current scope
flags:

```rust
let new_parent_id = ctx.current_scope_id();
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(new_parent_id));
let make_sloppy_mode = !ctx.current_scope_flags().is_strict_mode();
```

That is correct for normal private methods, but not for private methods
inside a class expression that appears in a static field initializer.

## After

When the transform is running under a static `PropertyDefinitionValue`,
the helper is parented to the current hoist scope instead:

```rust
let new_parent_id = if Self::is_inside_static_property_initializer(ctx) {
    ctx.current_hoist_scope_id()
} else {
    ctx.current_scope_id()
};
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(new_parent_id));
let make_sloppy_mode = !ctx.scoping().scope_flags(new_parent_id).is_strict_mode();
```

The predicate checks the field is actually static:

```rust
matches!(ancestor, Ancestor::PropertyDefinitionValue(property) if *property.r#static())
```

The resulting scope shape now matches where the helper is emitted:

```mermaid
flowchart TD
  Program["enclosing hoist scope"] --> Helper["lifted helper function scope"]
  Program --> Outer["Outer class scope"]
  Outer --> Field["static field initializer"]
  Field --> Inner["Inner class scope"]
```

The strict/sloppy adjustment also reads from the selected parent scope,
so the helper's flags match the output location rather than the original
nested class context.

## Validation

- `just fmt`
- `cargo test -p oxc_transformer`
- `just coverage` was run before review. It aborted later with a stack
overflow / signal 6 in `target/coverage/oxc_coverage`; before the abort,
the targeted `semantic_test262` failures were removed from the generated
snapshot output.

AI assistance: Codex was used to cherry-pick, review, test, and draft
this PR description.
2026-05-26 13:44:11 +08:00
Cameron 5a264798bc fix(formatter): preserve import phases (#22692)
Preserve import phases when formatting import declarations.

`oxfmt` was dropping `defer` and `source` from phase imports because the
formatter did not print `ImportDeclaration.phase`. This adds phase
printing after `import` and covers `import defer` plus `import source`
cases in formatter fixtures.

fixes #22691
2026-05-25 10:22:08 +09:00
Cameron 93a516011a refactor(ci/issue-labeled): use gh cli over external dependency (#22574) 2026-05-20 10:24:50 +09:00
Cameron f3bf89563f refactor(linter/no-use-before-define): remove unused initializer parameter (#22102) 2026-05-03 20:38:55 +01:00
Cameron 5967516b04 refactor(parser): use Span::sized for relative spans (#22026)
Replace parser Span::new calls whose end is start plus a size with
Span::sized.
2026-05-01 14:06:13 +01:00
Cameron bedffbe9bd refactor(linter): use Span::sized for relative spans (#22025)
Replace linter Span::new calls whose end is start plus a size with Span::sized.
2026-05-01 14:02:36 +01:00
Cameron f3a02cc493 fix(linter/no-non-null-assertion): improve diagnostic message (#21616) 2026-04-21 19:06:05 +01:00
Cameron 44b5b35b66 fix(linter): preserve vitest-compatible jest rules when applying overrides (#21389) 2026-04-13 17:40:05 +01:00
Cameronandcamc314 ae617f273c fix(ci/release-apps): enable long path support for windows (#20148)
Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com>
2026-03-09 19:26:11 +08:00
Cameron a2f58e5ea4 feat(parser): report error for implements clause in non-ts files (#19820) 2026-02-28 10:33:46 +08:00
Cameron 9cec27f8e5 fix(ci): avoid ENOBUFS error in conformance change filter (#19547)
example:
https://github.com/oxc-project/oxc/actions/runs/22186779233/job/64162682319?pr=19502
2026-02-24 14:24:48 +08:00
Cameron 1b2f3549df fix(ci): add missing riscv64/s390x napi targets for oxfmt and oxlint (#19217)
Refs: https://github.com/oxc-project/oxc/pull/19039
2026-02-10 20:11:23 +08:00
Cameron b4f7e7fa46 refactor(minifier): generate ancestor.rs and remove cross-crate #[path] include (#19213) 2026-02-10 19:07:02 +08:00
Cameron bcd0f6430f fix(napi): disable mimalloc global allocator on android targets (#19214) 2026-02-10 19:06:06 +08:00
Cameron 0441237182 fix(source-type): don't treat d.ts as a declaration file (#19185) 2026-02-10 17:33:37 +08:00
Cameron 80e28a3055 feat(ast_tools): add Cargo.lock to CI watch list (#19170) 2026-02-09 19:41:37 +08:00
Cameron a7b6824fe5 docs(copilot): add copilot review instructions for PRs (#19064)
cc @overlookmotel it should hopefully prevent copilot from reporting
errors on stuff like unused variables in test case files
2026-02-06 21:24:17 +08:00
Cameron b425a0cd9e docs(linter): document jsPlugins examples (#18671) 2026-02-03 15:56:49 +00:00
Cameron 7cd354ad4e chore(deps): add apps/oxfmt/test/**/fixtures/** to renovate ignore (#17875) 2026-01-12 08:24:30 +09:00
Cameronandoverlookmotel d209c216e5 feat(allocator): add cap to FixedSizeAllocatorPool and block when exhausted (#17023)
This PR adds a capacity limit to `FixedSizeAllocatorPool` to prevent
unbounded memory consumption.

Previously, each call to `get()` on an empty pool would create a new 4
GiB allocator without any limit, risking memory exhaustion in
multi-threaded scenarios. Now the pool caps the number of allocators at
`thread_count` and blocks threads using a `Condvar` when all allocators
are in use.

Key changes include:

* Eager creation of the first allocator during construction (fail-fast).
* Lock-free ID assignment with compare-and-swap.
* Blocking with condition variables when at capacity.
* Tracking allocation failures to avoid repeated attempts.

---------

Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2025-12-18 22:40:19 +00:00
Cameronandoverlookmotel 1e2d011da9 refactor(allocator/fixed-size): return Result from allocation instead of panicking (#17022)
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2025-12-18 22:23:16 +00:00
a0f74a0fb2 feat(linter/config): allow aliasing plugin names to allow names the same as builtin plugins (#15569)
fixes https://github.com/oxc-project/oxc/issues/15413

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2025-12-17 19:17:36 +00:00
Cameron d933cf0989 feat(ast_tools): add package.json and oxfmtrc.jsonc to CI watch list (#16097)
this change forces ast changes to run when package.json (oxfmt version)
OR oxfmtrc.jsonc (oxfmt config) changes, hopefully avoiding failing CI
due to this not running, and changes to either of those two happening
2025-11-25 20:35:57 +08:00
Cameron 2c7808feee fix(workflow): update NAPI bindings build commands for apps (#16042) 2025-11-24 10:46:40 +00:00
Cameron b8bf4041a6 feat(tasks/lint-rules): track rules with pending fixes in automated issues (#15989)
Add functionality to detect and display linter rules that have pending
auto-fixes in the automated GitHub tracking issues.

- Add readAllPendingFixRuleNames() to scan rule files for `pending`
keyword
- Update RuleEntry type to include isPendingFix field
- Add updatePendingFixStatus() to mark implemented rules with pending
fixes
- Update markdown renderer to show ⏳ emoji for pending fixes
- Add pending fix counts to summary and table headers
- Preserve isPendingFix status across plugin sync operations

Fixes #15977
2025-11-23 18:04:52 -07:00
Cameron c99da50c2d refactor(linter/consistent-indexed-object-style): improve diagnostic message wording (#15792)
in my opinion `such as` is slightly more formal than `like` in this
context.
2025-11-17 08:10:07 -07:00
CameronandBoshen 8b48a2cc74 fix(ci): restore OXC_VERSION env var injection in release_apps workflow (#15551)
Broke in fbd334b4bd

Fixes #15550

---------

Co-authored-by: Boshen <boshenc@gmail.com>
2025-11-10 23:32:53 +08:00
Cameron 75371c6580 fix(ci): remove checkout step from check-version action (#15090) 2025-10-30 10:30:37 +09:00
Cameron 414454c2cf fix(ci): checkout branch before running version check (#15089) 2025-10-30 09:16:53 +08:00
Cameron c794002134 perf(parser): optimize lexer checkpoint to avoid unnecessary error
cloning (#13537)

1pct perf improvement on some pf the parser benchmarks

![Screenshot 2025-09-04 at
13.52.11.png](https://app.graphite.dev/user-attachments/assets/86e6aa27-6da3-48d1-97cc-fb3119c68885.png)
2025-09-15 20:29:20 +08:00
Cameron d3712ab2e8 fix(ci/lint-rules): fix(workflow): update setup-node action to use oxc-project version (#13641)
to fix
[this](https://github.com/oxc-project/oxc/actions/runs/17604014167/job/50011184946)
failure
2025-09-10 16:52:19 +08:00
Cameron 13f0658f88 fix(tasks): propagate io::copy errors during benchmark file download (#12813)
Codspeed left this comment on my PR.

The perf increase is obviously wrong, the only way i could see this
happening is if it failed to copy. this PR updates it to propogate the
error so that we know when something fails, rather than having codspeed
log incorrect perf differences

![Screenshot 2025-08-04 at
20.03.10.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/8ASanJZ3iQ7b9iVhlds7/ff7af92c-a344-477b-862c-06b1ebebef4a.png)
2025-08-05 14:28:55 +08:00
Cameron e836e552f3 fix(parser): prevent panic when parsing invalid extends clause (#12551)
fixes #12546
2025-08-01 16:19:30 +08:00
Cameron f1c18d8db2 chore(napi/parser): remove undefined module.exports (#11968)
`parseWithoutReturn` doesn't exist anywhere, so attempting to assign it
to modules.exports does nothing:

Logging the value of `import * as k from 'oxc-parser'`

```
node example.mjs test.ts
[Module: null prototype] {
  ExportExportNameKind: { Name: 'Name', Default: 'Default', None: 'None' },
  ExportImportNameKind: {
    Name: 'Name',
    All: 'All',
    AllButDefault: 'AllButDefault',
    None: 'None'
  },
  ExportLocalNameKind: { Name: 'Name', Default: 'Default', None: 'None' },
  ImportNameKind: {
    Name: 'Name',
    NamespaceObject: 'NamespaceObject',
    Default: 'Default'
  },
  ParseResult: [Function: ParseResult],
  Severity: { Error: 'Error', Warning: 'Warning', Advice: 'Advice' },
  default: {
    ParseResult: [Function: ParseResult],
    ExportExportNameKind: { Name: 'Name', Default: 'Default', None: 'None' },
    ExportImportNameKind: {
      Name: 'Name',
      All: 'All',
      AllButDefault: 'AllButDefault',
      None: 'None'
    },
    ExportLocalNameKind: { Name: 'Name', Default: 'Default', None: 'None' },
    ImportNameKind: {
      Name: 'Name',
      NamespaceObject: 'NamespaceObject',
      Default: 'Default'
    },
    parseWithoutReturn: undefined,
    Severity: { Error: 'Error', Warning: 'Warning', Advice: 'Advice' },
    parseSync: [Function: parseSync],
    parseAsync: [AsyncFunction: parseAsync],
    experimentalGetLazyVisitor: [Function: experimentalGetLazyVisitor],
    rawTransferSupported: [Function: rawTransferSupported]
  },
  experimentalGetLazyVisitor: [Function: experimentalGetLazyVisitor],
  parseAsync: [AsyncFunction: parseAsync],
  parseSync: [Function: parseSync],
  parseWithoutReturn: undefined,
  rawTransferSupported: [Function: rawTransferSupported]
}
```
2025-06-30 13:19:14 +08:00
Cameron 0946dacf69 fix(linter): correctly inherit categories when plugins are enabled (#11353)
fixes #10394
fixes #9649
2025-06-05 20:41:45 +01:00
Cameron 311e506111 chore(just): remove broken javascript-globals command (#11269) 2025-05-24 20:19:33 +08:00
Cameron 368d05fabc fix(codegen): make source_text an option, avoid panic (#10790)
fixes panic in rolldown, hopefully there is no perf regression, by
making source_text an option
2025-05-05 00:29:19 +08:00
Cameron f89aec63c0 perf(parser): improve perf of checking for licence/legal comments (#10616) 2025-04-27 10:36:54 +08:00
Cameron 5dd8c10595 fix(rulegen): use get_inner_expression for getting rules (#10269) 2025-04-06 23:24:42 +08:00
Cameronandcamc314 8804555559 fix(linter): skip no-absolute-path tests on windows (#9435)
Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com>
2025-03-01 16:06:35 +08:00
Cameron f10a6daed9 refactor(mangler): move base54 into seperate mod (#9278) 2025-02-22 13:58:44 +08:00
Cameron 39353b22e9 feat(minifier): improve minimizing conditionals (#8238) 2025-01-04 08:36:54 +08:00
Cameron 0e168b8c19 feat(linter): catch more cases in const-comparisons (#8215) 2025-01-02 18:32:47 +08:00
Cameron cd274eeb02 feat(minifier): minimize logical exprs (#8209) 2025-01-02 18:32:20 +08:00
Cameron cb709c9d83 test(linter): fix some oxlint tests on windows (#8204) 2025-01-01 10:22:10 +08:00
Cameron bf266e13b0 feat(minifier): try collapse conditional to logical or expr (#8197) 2024-12-31 15:59:08 +08:00
Cameronandoverlookmotel 78d2e837f0 perf(sourcemap): improve perf of search_original_line_and_column (#7926)
this seems to show a decent speed up on perf.
the thinking behind this change is:
1. subsequent calls to `search_original_line_and_column` will **never**
look at back at lines it has already searched
2. binary search is faster in this case as typically `idx` is only
increased by a small amount

Given this, we can skip checking a bunch of lines (that will never
return true) improving performance.

This is a very hot path. 


```
$ hyperfine --warmup=3 ./target/release-with-debug/examples/sourcemap-main ./target/release-with-debug/examples/sourcemap
Benchmark 1: ./target/release-with-debug/examples/sourcemap-main
  Time (mean ± σ):      79.5 ms ±   5.5 ms    [User: 65.1 ms, System: 12.2 ms]
  Range (min … max):    76.8 ms … 111.7 ms    37 runs
 
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
 
Benchmark 2: ./target/release-with-debug/examples/sourcemap
  Time (mean ± σ):      72.9 ms ±   0.9 ms    [User: 59.2 ms, System: 12.2 ms]
  Range (min … max):    70.6 ms …  75.0 ms    40 runs
 
Summary
  ./target/release-with-debug/examples/sourcemap ran
    1.09 ± 0.08 times faster than ./target/release-with-debug/examples/sourcemap-main
```

---------

Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
2024-12-23 14:51:50 +08:00
Cameron 9c9b73dadb fix(linter): fix incorrect fixer for prefer-regexp-test (#7898)
closes #7793
2024-12-15 12:06:52 +08:00
Cameron 56fe5f8bb9 docs(linter): update rule documentation (#7680)
part of #6050
2024-12-05 20:14:42 +08:00
Cameron 3dc46a80c9 fix(linter): no-unused-expressions false positive with arrow fn expressions (#7585)
fixes https://github.com/oxc-project/oxc/issues/7584
2024-12-03 09:48:50 +08:00
Cameron 7da9a39b5d fix(rulegen): update lint rule template (#7502) 2024-11-27 17:40:38 +08:00
Cameron 8507464d5a fix(linter): hanging when source has syntax/is flow (#7432)
Closes #7406

See
https://github.com/oxc-project/oxc/issues/7406#issuecomment-2494981152
for why this is happening

not sure whether there's a better solve for this/
2024-11-23 23:20:19 +08:00
Cameron c6d790b287 fix(language-server): fix panic by building scope tree child ids (#7440)
closes #7434

i couldn't test this. but what's happening is semaitc is being build
without scope child ids. When exhaustive_deps tries to access it its an
empty vec - hence the panic
2024-11-23 23:19:11 +08:00
Cameron 147b37176b fix(linter) fix bug in fixer for func names when function is async (#5167) 2024-08-24 11:30:56 -04:00
Cameron 22d57f9e5e feat(linter/unicorn): add fixer to prefer-string-slice (#5150) 2024-08-23 21:37:35 -04:00
Cameron 2fe44153ac feat(linter/unicorn): add fixer to no-redundant-roles (#5146) 2024-08-23 17:38:24 -04:00
Cameron d35c6f5dfc feat(linter/unicorn): add fixer to prefer-regexp-test (#5151) 2024-08-23 17:34:06 -04:00
Cameron 27db769b8a feat(linter/unicorn): add fixer to text-encoding-identifier-case (#5154) 2024-08-23 17:29:19 -04:00
Cameron 7eb052e0d4 fix(linter): no-hex-escape fixer removing regex flags (#5137)
closes #5127
2024-08-23 20:32:34 +01:00
Cameron a61eef34a6 feat(linter) eslint-plugin-unicorn no magic array flat depth (#3411) 2024-05-26 12:16:24 +08:00
Cameron 07076d9765 feat(linter) improve prefer-string-starts-ends-with rule (#3176)
basically:
`^#/i.test(hex)` is the same as `/^#/.test(hex)`
so, in this case the `i` flag does nothing and we can safely ignore it


inspired by https://x.com/the_moisrex/status/1787444601571221892


---

This could potentially lead a new `oxc` rule called
`no_useless_case_insensitive_regex_flag` that reports if you have a
regex with the `i` flag with no ascii alphabetic chars.
2024-05-06 23:52:19 +08:00
Cameron 01e64bf64d feat(linter) eslint-plugin-unicorn no await in promise methods (#2963) 2024-04-14 10:44:36 +08:00
Cameron 98a3acd8b5 feat(linter) eslint-plugin-unicorn no single promise in promise methods (#2962)
part of #684
2024-04-14 10:39:12 +08:00
Cameron 66a64dfc48 feat(linter) eslint: no-useless-rename (#2648) 2024-03-09 21:37:48 +08:00
Cameron 51183b801c fix(linter) panic in prefer-native-coercion-function (#2100)
closes #2098
2024-01-21 01:52:00 +08:00
Cameron 107a32ea48 fix(linter): fix false positive for erasing-op in 0/0 case (#2009) 2024-01-13 10:32:26 +08:00
Cameron 64310fa9b1 refactor(linter): remove duplicate get_jsx_attribute_name (#1971) 2024-01-10 11:45:34 +08:00
Cameron 0bcc9e7e6b feat(linter) eslint-plugin-next no-head-import-in-document (#1957) 2024-01-09 11:41:31 +08:00
Cameron d9ca086eb6 feat(linter) add support for custom filenames in tests (#1955) 2024-01-09 11:35:34 +08:00
Cameron 18d1c29a62 feat(linter) eslint-plugin-next no-script-component-in-head (#1954) 2024-01-09 11:29:32 +08:00
Cameron 039e6fc9c5 feat(linter) eslint-plugin-next no-sync-scripts (#1953) 2024-01-09 11:22:27 +08:00
Cameron a3754e20ca feat(linter) eslint-plugin-next no-title-in-document-head (#1952) 2024-01-09 11:16:42 +08:00
Cameron bce9060095 feat(linter) eslint-plugin-next no-img-element (#1951) 2024-01-09 11:12:01 +08:00
Cameron ac3b44bd0c feat: nextjs plugin (#1948)
https://github.com/oxc-project/oxc/issues/1929#issuecomment-1880369624
2024-01-09 11:08:11 +08:00
Cameron 73a5b7f7da feat(linter) eslint-plugin-next no-css-tags (#1937) 2024-01-08 12:38:53 +08:00
Cameron 149f53edd6 feat(linter) eslint-plugin-next no-async-client-component (#1936) 2024-01-08 12:13:27 +08:00
Cameron c06d939460 feat(linter) eslint-plugin-next no-assign-module-variable (#1935) 2024-01-08 12:09:32 +08:00