Commit Graph

229 Commits

Author SHA1 Message Date
overlookmotel b4f6593c4f ci(lexer): run lint, tests and conformance on both lexer implementations (#26298)
#26263 added the ability to run tests and conformance for both versions of `oxc_lexer` (SIMD and scalar fallback) on any platform.

Run tests and conformance on CI (both SIMD and scalar) on any PR which touches `oxc_lexer` crate or other files which affect conformance runner.

Additionally, run Clippy on the SIMD version (main Lint CI task doesn't lint it, due to the `target_feature = "avx2"` gate on the code).

All of this sets up `oxc_lexer` crate for further development, catching any regressions in CI.
2026-09-03 16:40:21 +00:00
overlookmotel 0aa2fff2eb docs(tools): add comment to lexer just recipe about running x86 version on Mac (#26297)
Follow-on after #26263. That PR added `just` commands to run `oxc_lexer` tests and conformance on any platform. Add a comment to the justfile pointing to solution for the cryptic error you get if `x86_64-apple-darwin` target is not installed on an M-chip Mac (it's not by default).
2026-09-03 16:40:20 +00:00
overlookmotel 6365db964b test(lexer): enable oxc_lexer conformance tests on all platforms (#26263)
`oxc_lexer` has 2 implementations:

1\. SIMD-based on x86_64 with AVX2.
2\. Scalar/SWAR fallback which works on all platforms.

Both produce the same output.

This PR enables running the lexer conformance on either implementation. Which implementation is tested depends on what build flags are passed to `cargo coverage`.

It turns out that it's possible to test the SIMD implementation on Mac by compiling as x86_64, and running it under Rosetta 2.

This PR also adds `just` recipes to run tests and conformance on either implementation:

- `just test-lexer`
- `just test-lexer-simd`
- `just conformance-lexer`
- `just conformance-lexer-simd`

These commands should work correctly on any of Linux x86, Windows x86, Mac aarch64.
2026-09-03 10:59:05 +00:00
leaysgur 0fa91283fd refactor(formatter,formatter_tests): move out prettier JS,TS,JSDoc conformance from tasks/ (#25477)
Migration from tasks/prettier_conformance to each crate test using oxc_formatter_tests, for JS/TS and JSDoc.
2026-08-12 00:48:32 +00:00
overlookmotel 8da040290c feat(tools): just commands check, test, lint, doc take args (#24367)
Sometimes it can be useful to run a command just for a specific crate.

Alter `just` commands to support e.g. `just test -p oxc_parser`, `just doc -p oxc_semantic`.
2026-07-10 21:12:30 +00:00
Boshen 18da3a2f91 chore(ci): use CARGO_BUILD_WARNINGS=deny instead of clippy -D warnings (#24344)
Rust 1.97 stabilized [`build.warnings`](https://blog.rust-lang.org/2026/07/09/Rust-1.97.0/#cargo-support-for-denying-warnings) / `CARGO_BUILD_WARNINGS`, which denies warnings at the cargo level instead of via clippy args.

Unlike `-D warnings`, the env var is not part of the build fingerprint, so `just lint`, plain `cargo lint`, and rust-analyzer now share one check cache instead of re-linting the workspace whenever the flags alternate. Cached warnings are still replayed and denied, so warm caches leave no enforcement hole.

Verified on cargo 1.97: clippy-only lints are denied (exit 101) despite the cargo reference only mentioning "rustc lints", and denial fires from a fully cached run. The justfile recipe exports the variable via a just parameter (cross-platform, and overridable with `just lint warn`).

rustdoc keeps `RUSTDOCFLAGS='-D warnings'` — `build.warnings` does not cover rustdoc lints.
2026-07-10 08:33:52 +00:00
camc314 98fe16f7b1 refactor(transform): migrate fixture updater to TypeScript (#24213)
## Summary
- migrate the transform fixture updater from JavaScript to TypeScript using Node native type stripping
- update the just recipe to execute the TypeScript file
2026-07-06 08:56:35 +00:00
camchenry a685927916 feat(ci): add lint timings tracking (#24162)
Adds linter call count tracking to provide some durable evidence of call count reductions. This does not include the actual rule timings so that it is consistent across machines.
2026-07-04 17:43:39 +00:00
Boshen 529152d222 chore(deps): bump cargo-shear to 1.13.1 (#23808)
Bumps the cargo-shear setup pin to 1.13.1.
2026-06-27 23:24:00 +08:00
Sysix 49e5649653 test(website): don't snapshot on schema validation (#23387)
It sounds stupid to create a snapshot from an already existing file.
Works on https://github.com/oxc-project/oxc/issues/22955 showed they will always match.

The PR changes the tests so it just checks if the existing file matches the output, without snapshots.
2026-06-13 21:14:05 +00:00
Boshen d1cd344b5a chore(deps): update cargo-shear to 1.12.4 (#22706)
## Summary

- Bump `cargo-shear` from `1.11.2` to `1.12.4` in `justfile`,
`.github/workflows/autofix.yml`, and
`.github/workflows/copilot-setup-steps.yml`.
- Enable `--check-test-targets` (new in 1.12.0) in `just fmt` and the
autofix CI step to flag `test`/`doctest` target settings that don't
match source content; pairs with `--fix` to auto-reconcile.
- Enable `--deny-warnings` and `--format=github` in the autofix CI step
so warnings fail the job (triggering the existing autofix push) and
findings surface as inline PR annotations.
2026-05-25 13:33:54 +08:00
Sysix f44b6c84af feat(linter): fill schemas DummyRuleMap with built-in rules (#22288)
> This PR enhances Oxlint configuration schema fidelity by expanding `DummyRuleMap` to explicitly list all built-in rules as schema properties (improving editor autocomplete), while adding markdown-renderer filtering to avoid generating massive documentation sections for `rules`.

<img width="632" height="391" alt="grafik" src="https://github.com/user-attachments/assets/732bf81b-b090-429a-8bcd-20f0a6a54aa6" />
2026-05-12 18:51:48 +00:00
Sysix d58f5948ca docs(oxlint/lsp): auto generate docs for LSP options (#22082)
> ## Pull request overview

> This PR adds automated generation of website documentation for oxlint’s LSP linting options by exposing the LSP options schema, rendering it to markdown, and snapshot-testing the output.

An PR on `oxc-project/website` is needed. Will wait for the next release to improve the LSP & Editor docs too :)
2026-05-02 20:00:17 +00:00
overlookmotel eb89608c60 ci(tools): run rustdoc with --all-features (#21427)
`just doc` run rustdoc with `--all-features` flag.

I discovered that `just doc` was not, for example, catching errors in doc comments in #21425, because the code is behind a feature which is not enabled by default.
2026-04-22 01:03:34 +00:00
Boshen b293ea8d4e chore(rust): bump cargo-shear to 1.11.2 (#20403)
## Summary
- Bump `cargo-shear` from 1.10.0 to 1.11.2 in justfile and CI workflows
- Apply `cargo shear --fix`: set `doctest = false` on 6 crates with no
doc tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 23:10:12 +08:00
Boshen 3e54818821 chore(rust): use cargo-shear to toggle Cargo.toml [lib] test = bool (#20195)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-03-10 22:59:09 +08:00
Connor Shea 78f9504939 chore(linter,formatter): Add dev build commands to Justfile for oxlint and oxfmt. (#20106)
These build significantly faster for me while letting me still test the
app locally. I remember discussing these a while ago, but we never added
anything to the Justfile for easily using them.

I'm not sure if there are any downsides to this beyond potential
edge-case differences from the release build, but I figure it's probably
worth considering?

---------

Signed-off-by: Connor Shea <connor.james.shea@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-08 12:01:12 +08:00
leaysgur ec91dce7b3 refactor(oxfmt): Generate TS types from schema (#19901)
Like oxlint does.

No public definition change.
It also prepares for dynamic configuration files.
2026-03-02 23:51:22 +00:00
camc314 88a20819b6 feat(coverage): add estree token conformance scaffolding (#19496)
Add conformance tests for ESTree tokens. Currently all failing, because we've not implemented tokens yet.
2026-02-23 20:52:34 +00:00
Boshen 7d19c65c24 chore(ci): update cargo-shear in CI/local and fix shear warnings (#19302)
## Summary
- pin `cargo-shear` to `1.9.1` in local setup (`just init`)
- pin `cargo-shear` to `1.9.1` in CI workflows (`autofix`, `update_submodules`, `copilot-setup-steps`)
- add `cargo-shear` ignore metadata for `schemars` in `crates/oxc_span` to avoid a known optional-dependency false-positive

## Validation
- `cargo shear`
- `cargo shear --fix`

## AI Usage Disclosure
This PR was prepared with assistance from an AI coding tool (Codex).
I have reviewed the generated changes and take full responsibility for this PR.
2026-02-12 07:52:47 +00:00
Boshen 4179e4f85a chore(editors): remove VS Code extension (moved to oxc-vscode repo) (#18982)
## Summary

- Removes `editors/vscode` directory - code has been moved to
https://github.com/nicholasrice/oxc-vscode
- Removes `tasks/vscode_docs` crate (no longer needed)
- Removes CI and release workflows for VS Code extension
- Updates `editors/README.md` to point to the new repository
- Cleans up references in `.gitignore`, `justfile`, `oxc_release.toml`,
`oxfmtrc.jsonc`, `oxlintrc.json`, and `pnpm-workspace.yaml`

closes #17484

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 21:14:03 +08:00
camc314 da32203a60 feat(linter): auto generate oxlint.config.ts types (#18597) 2026-02-01 23:50:25 +00:00
connorshea 8166f80b41 chore(linter): Misc improvements to help prevent merge conflicts for generated files in oxlint (#18813)
- The header on rules_enum.rs was being stripped by accident, which was confusing for users. So I fixed that.
- Mark the generated files as generated in `.gitattributes`, for GitHub to understand the diffs are mostly pointless and can be collapsed by default (the CI job enforces that these files be up to date anyway).
- Mark the generated rule files as `merge=ours`. See https://git-scm.com/book/ms/v2/Customizing-Git-Git-Attributes for more info on what that means, but it should make the merge conflicts less problematic.
- Updated `just ready` to include the lintgen command.
- Added `cargo lintgen` to the AGENTS.md file.

AI Disclosure: Used Claude to find the reason for the lack of header comment because I had no idea why it was happening.
2026-02-01 20:18:39 +00:00
connorshea 7fcc59441a chore(all): update references from oxc-project.github.io to oxc/website. (#18608)
Just a cleanup since the repo was renamed.
2026-01-26 23:49:51 +00:00
sapphi-red 1bf4c1c08c chore(infra): fix just submodules on Windows (#18285)
`just submodules` was not working on Windows.
2026-01-23 12:17:50 +00:00
sapphi-red 8b498f0d5e chore(infra): fix just ast on Windows (#18286)
`just ast` was not working on Windows.
2026-01-20 14:29:36 +00:00
Connor Shea d838e0ba26 chore(docs): Update justfile with a comment about running oxlint after building it (#18049)
I always forget the path for this after building it, so I'm writing it
down :D
2026-01-16 12:17:37 +08:00
connorshea e7631dd39b feat(website): Update website generation flow for JSON rules output (#17973)
This builds on #15763 to change the rules generation for the website repo to emit a JSON file. This will support https://github.com/oxc-project/oxc-project.github.io/pull/782

I have removed the ability to have a link prefix for the generated markdown table, as it was only used for the generated-rules.md file.
2026-01-14 12:27:42 +00:00
connorshea f71243f80f chore(linter): Fix the phrasing of the issue instructions. (#17913)
And also update the justfile to have a `new-eslint-rule` alias. This is what is rendered in the relevant issue for eslint core rules, so we should support it.

Split out of #17620.
2026-01-12 05:57:13 +00:00
leaysgur 1aea211424 refactor(oxfmt): Move Oxfmtrc to apps/oxfmt (#17824)
Before this PR, `Oxfmtrc` was defined in `oxc_formatter` to avoid the circular reference `oxc_language_server` > `oxfmt` > `oxc_language_server`....

But now, `oxc_language_server` does not depend on `Oxfmtrc` since LSP implementation has moved to `apps/oxfmt`.

Therefore, by this PR, `Oxfmtrc` is moved to its proper location, in `apps/oxfmt`.

- Moved `Oxfmtrc` from `oxc_formatter` to `apps/oxfmt`
- Re-exposed from `apps/oxfmt`
- Now only `tasks/website_formatter` depends on it
- Also aligned JSON schema generation with `oxlint` by `just formatter-schema-json`

NOTE: In `oxc_formatter`, there are 2 places (`ir_transform` and `fixtures` tests) where we manually convert options from JSON. I'd like to fix this too in the future.
2026-01-09 15:11:36 +00:00
connorshea b12606d70b docs(website): Add a rules count value to the website to keep it updated automatically. (#17583)
Just like `version.data.js`. Maybe we should unify these cli flags for the website generator and just assume the structure of the website repo? Feels silly to specify all the paths like this.

See https://github.com/oxc-project/oxc-project.github.io/pull/758 for the companion PR in the actual website repo.

This will allow us to update the rule count automatically using JS, and pull it into the website docs like this:

```html
<script setup>
import { data } from './rule-count.data.js';
const ruleCount = data;
// or we can do some basic math to round the ruleCount to the nearest multiple of 5 and then show `645+ rules`
// const ruleCount = Math.ceil(data / 5) * 5;
</script>

# Oxlint

## A large and growing rule set

Oxlint includes [{{ ruleCount }} rules](/docs/guide/usage/linter/rules.md), with coverage across the plugins most teams already use, including:
```
2026-01-09 11:48:34 +00:00
camc314 624a7209d3 feat(rulegen): add --update-tests flag to update only test block in existing rules (#17669)
This allows updating test cases from upstream without overwriting the rule implementation. Useful for PR validation workflows.
2026-01-05 12:59:33 +00:00
Copilot 95f3691bcd chore: add pnpm install to just ready command (#17186) 2025-12-21 11:22:59 +08:00
connorshea fd57ec3112 chore(rulegen): Improve the rule template and config json handling (#17117)
The rule configs often came out weird previously, and now the config objects in the tests look a bit less bad for generated rules :)

Done with help from Copilot + Claude Opus.

Also run `just fmt` after generating a rule, to avoid some problems with the sort order of defined rules by default, and update the template.txt to use some common patterns.

Example generated rule:

<details>
<summary>Before</summary>

```rs
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{
    AstNode,
    context::LintContext,
    fixer::{RuleFix, RuleFixer},
    rule::Rule,
};

fn explicit_member_accessibility_diagnostic(span: Span) -> OxcDiagnostic {
    // See <https://oxc.rs/docs/contribute/linter/adding-rules.html#diagnostics> for details
    OxcDiagnostic::warn("Should be an imperative statement about what is wrong")
        .with_help("Should be a command-like statement that tells the user how to fix the issue")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct ExplicitMemberAccessibility;

// See <https://github.com/oxc-project/oxc/issues/6050> for documentation details.
declare_oxc_lint!(
    /// ### What it does
    ///
    /// Briefly describe the rule's purpose.
    ///
    /// ### Why is this bad?
    ///
    /// Explain why violating this rule is problematic.
    ///
    /// ### Examples
    ///
    /// Examples of **incorrect** code for this rule:
    /// ```ts
    /// FIXME: Tests will fail if examples are missing or syntactically incorrect.
    /// ```
    ///
    /// Examples of **correct** code for this rule:
    /// ```ts
    /// FIXME: Tests will fail if examples are missing or syntactically incorrect.
    /// ```
    ExplicitMemberAccessibility,
    typescript,
    nursery, // TODO: change category to `correctness`, `suspicious`, `pedantic`, `perf`, `restriction`, or `style`
             // See <https://oxc.rs/docs/contribute/linter.html#rule-category> for details
    pending, // TODO: describe fix capabilities. Remove if no fix can be done,
             // keep at 'pending' if you think one could be added but don't know how.
             // Options are 'fix', 'fix_dangerous', 'suggestion', and 'conditional_fix_suggestion'
);

impl Rule for ExplicitMemberAccessibility {
    fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {}
}

#[test]
fn test() {
    use crate::tester::Tester;

    let pass = vec![
        (
            "
			class Test {
			  public constructor(private foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "explicit" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(private readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "explicit" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(private foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "off" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(protected foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "off" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(public foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "off" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "off" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(private readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "off" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  protected name: string;
			  private x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public 'foo-bar'?: string;
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  public constructor({ x, y }: { x: number; y: number }) {}
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  name: string;
			  foo?: string;
			  getX() {
			    return this.x;
			  }
			  get fooName(): string {
			    return this.foo + ' ' + this.name;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  private x: number;
			  constructor(x: number) {
			    this.x = x;
			  }
			  get internalValue() {
			    return this.x;
			  }
			  private set internalValue(value: number) {
			    this.x = value;
			  }
			  public square(): number {
			    return this.x * this.x;
			  }
			}
			      ",
            Some(
                serde_json::json!([{ "overrides": { "accessors": "off", "constructors": "off" } }]),
            ),
        ),
        (
            "
			class Test {
			  private x: number;
			  public constructor(x: number) {
			    this.x = x;
			  }
			  public get internalValue() {
			    return this.x;
			  }
			  public set internalValue(value: number) {
			    this.x = value;
			  }
			  public square(): number {
			    return this.x * this.x;
			  }
			  half(): number {
			    return this.x / 2;
			  }
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "methods": "off" } }])),
        ),
        (
            "
			class Test {
			  constructor(private x: number) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  constructor(public x: number) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "off" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public foo: number) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  public static getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  get getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  x = 2;
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "properties": "off" } }])),
        ),
        (
            "
			class Test {
			  private x = 2;
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "properties": "explicit" } }])),
        ),
        (
            "
			class Test {
			  x = 2;
			  private x = 2;
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "properties": "no-public" } }])),
        ),
        (
            "
			class Test {
			  #foo = 1;
			  #bar() {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class Test {
			  private accessor foo = 1;
			}
			      ",
            None,
        ),
        (
            "
			abstract class Test {
			  private abstract accessor foo: number;
			}
			      ",
            None,
        ),
    ];

    let fail = vec![
        (
            "
			export class XXXX {
			  public constructor(readonly value: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": {            "parameterProperties": "explicit",          },        },      ]),
            ),
        ),
        (
            "
			export class WithParameterProperty {
			  public constructor(readonly value: string) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			export class XXXX {
			  public constructor(readonly samosa: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": {            "constructors": "explicit",            "parameterProperties": "explicit",          },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "explicit",          "overrides": { "parameterProperties": "explicit" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  private x: number;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  x?: number;
			  getX?() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  protected name: string;
			  public foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  public x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  private x: number;
			  constructor(x: number) {
			    this.x = x;
			  }
			  get internalValue() {
			    return this.x;
			  }
			  set internalValue(value: number) {
			    this.x = value;
			  }
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "constructors": "no-public" } }])),
        ),
        (
            "
			class Test {
			  private x: number;
			  constructor(x: number) {
			    this.x = x;
			  }
			  get internalValue() {
			    return this.x;
			  }
			  set internalValue(value: number) {
			    this.x = value;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  constructor(public x: number) {}
			  public foo(): string {
			    return 'foo';
			  }
			}
			      ",
            Some(
                serde_json::json!([        {          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public x: number) {}
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  constructor(public readonly x: number) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  x = 2;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": { "properties": "explicit" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public x = 2;
			  private x = 2;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": { "properties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public x: any[]) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class Test {
			  public /*public*/constructor(private foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  @public
			  public foo() {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  @public
			  public foo;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public foo = '';
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public/* Hi there */ readonly foo) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public constructor() {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public /* */ constructor() {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public 'foo' = 1;
			  public 'foo foo' = 2;
			  public 'bar'() {}
			  public 'bar bar'() {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			abstract class SomeClass {
			  abstract method(): string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract method(): string;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			abstract class SomeClass {
			  abstract x: string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract x: string;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class SomeClass {
			  accessor foo = 1;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			abstract class SomeClass {
			  abstract accessor foo: string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class DecoratedClass {
			  constructor(@foo @bar() readonly arg: string) {}
			  @foo @bar() x: string;
			  @foo @bar() getX() {
			    return this.x;
			  }
			  @foo
			  @bar()
			  get y() {
			    return this.x;
			  }
			  @foo @bar() set z(@foo @bar() value: x) {
			    this.x = x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			abstract class SomeClass {
			  abstract ['computed-method-name'](): string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
    ];

    let fix = vec![
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  protected name: string;
			  public foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            "
			class Test {
			  protected name: string;
			  foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  public x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            "
			class Test {
			  x: number;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  constructor(public readonly x: number) {}
			}
			      ",
            "
			class Test {
			  constructor(readonly x: number) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public x = 2;
			  private x = 2;
			}
			      ",
            "
			class Test {
			  x = 2;
			  private x = 2;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "off",          "overrides": { "properties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public /*public*/constructor(private foo: string) {}
			}
			      ",
            "
			class Test {
			  /*public*/constructor(private foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  @public
			  public foo() {}
			}
			      ",
            "
			class Test {
			  @public
			  foo() {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  @public
			  public foo;
			}
			      ",
            "
			class Test {
			  @public
			  foo;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public foo = '';
			}
			      ",
            "
			class Test {
			  foo = '';
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public/* Hi there */ readonly foo) {}
			}
			      ",
            "
			class Test {
			  constructor(/* Hi there */ readonly foo) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public readonly foo: string) {}
			}
			      ",
            "
			class Test {
			  constructor(readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",        },      ]),
            ),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public constructor() {}
			}
			      ",
            "
			class EnsureWhiteSPaceSpan {
			  constructor() {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public /* */ constructor() {}
			}
			      ",
            "
			class EnsureWhiteSPaceSpan {
			  /* */ constructor() {}
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			class Test {
			  public 'foo' = 1;
			  public 'foo foo' = 2;
			  public 'bar'() {}
			  public 'bar bar'() {}
			}
			      ",
            "
			class Test {
			  'foo' = 1;
			  'foo foo' = 2;
			  'bar'() {}
			  'bar bar'() {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract method(): string;
			}
			      ",
            "
			abstract class SomeClass {
			  abstract method(): string;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract x: string;
			}
			      ",
            "
			abstract class SomeClass {
			  abstract x: string;
			}
			      ",
            Some(
                serde_json::json!([        {          "accessibility": "no-public",          "overrides": { "parameterProperties": "no-public" },        },      ]),
            ),
        ),
    ];
    Tester::new(ExplicitMemberAccessibility::NAME, ExplicitMemberAccessibility::PLUGIN, pass, fail)
        .expect_fix(fix)
        .test_and_snapshot();
}
```
</details>

<details>
<summary>After</summary>

```rs
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{
    AstNode,
    context::LintContext,
    fixer::{RuleFix, RuleFixer},
    rule::Rule,
};

fn explicit_member_accessibility_diagnostic(span: Span) -> OxcDiagnostic {
    // See <https://oxc.rs/docs/contribute/linter/adding-rules.html#diagnostics> for details
    OxcDiagnostic::warn("Should be an imperative statement about what is wrong.")
        .with_help("Should be a command-like statement that tells the user how to fix the issue.")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct ExplicitMemberAccessibility;

// See <https://github.com/oxc-project/oxc/issues/6050> for documentation details.
declare_oxc_lint!(
    /// ### What it does
    ///
    /// Briefly describe the rule's purpose.
    ///
    /// ### Why is this bad?
    ///
    /// Explain why violating this rule is problematic.
    ///
    /// ### Examples
    ///
    /// Examples of **incorrect** code for this rule:
    /// ```ts
    /// FIXME: Tests will fail if examples are missing or syntactically incorrect.
    /// ```
    ///
    /// Examples of **correct** code for this rule:
    /// ```ts
    /// FIXME: Tests will fail if examples are missing or syntactically incorrect.
    /// ```
    ExplicitMemberAccessibility,
    typescript,
    nursery, // TODO: change category to `correctness`, `suspicious`, `pedantic`, `perf`, `restriction`, or `style`
             // See <https://oxc.rs/docs/contribute/linter.html#rule-category> for details
    pending, // TODO: describe fix capabilities. Remove if no fix can be done,
             // keep at 'pending' if you think one could be added but don't know how.
             // Options are 'fix', 'fix_dangerous', 'suggestion', and 'conditional_fix_suggestion'
);

impl Rule for ExplicitMemberAccessibility {
    fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {}
}

#[test]
fn test() {
    use crate::tester::Tester;

    let pass = vec![
        (
            "
			class Test {
			  public constructor(private foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "explicit" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(private readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "explicit" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(private foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "off" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(protected foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "off" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(public foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "off" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "off" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(private readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "off" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  protected name: string;
			  private x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public 'foo-bar'?: string;
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  public constructor({ x, y }: { x: number; y: number }) {}
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  name: string;
			  foo?: string;
			  getX() {
			    return this.x;
			  }
			  get fooName(): string {
			    return this.foo + ' ' + this.name;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  private x: number;
			  constructor(x: number) {
			    this.x = x;
			  }
			  get internalValue() {
			    return this.x;
			  }
			  private set internalValue(value: number) {
			    this.x = value;
			  }
			  public square(): number {
			    return this.x * this.x;
			  }
			}
			      ",
            Some(
                serde_json::json!([{ "overrides": { "accessors": "off", "constructors": "off" } }]),
            ),
        ),
        (
            "
			class Test {
			  private x: number;
			  public constructor(x: number) {
			    this.x = x;
			  }
			  public get internalValue() {
			    return this.x;
			  }
			  public set internalValue(value: number) {
			    this.x = value;
			  }
			  public square(): number {
			    return this.x * this.x;
			  }
			  half(): number {
			    return this.x / 2;
			  }
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "methods": "off" } }])),
        ),
        (
            "
			class Test {
			  constructor(private x: number) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  constructor(public x: number) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "off" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public foo: number) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  public static getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  get getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "ignoredMethodNames": ["getX"] }])),
        ),
        (
            "
			class Test {
			  x = 2;
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "properties": "off" } }])),
        ),
        (
            "
			class Test {
			  private x = 2;
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "properties": "explicit" } }])),
        ),
        (
            "
			class Test {
			  x = 2;
			  private x = 2;
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "properties": "no-public" } }])),
        ),
        (
            "
			class Test {
			  #foo = 1;
			  #bar() {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class Test {
			  private accessor foo = 1;
			}
			      ",
            None,
        ),
        (
            "
			abstract class Test {
			  private abstract accessor foo: number;
			}
			      ",
            None,
        ),
    ];

    let fail = vec![
        (
            "
			export class XXXX {
			  public constructor(readonly value: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": {  "parameterProperties": "explicit",  },  },  ]),
            ),
        ),
        (
            "
			export class WithParameterProperty {
			  public constructor(readonly value: string) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			export class XXXX {
			  public constructor(readonly samosa: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": {  "constructors": "explicit",  "parameterProperties": "explicit",  },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public constructor(readonly foo: string) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "explicit",  "overrides": { "parameterProperties": "explicit" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  private x: number;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  x?: number;
			  getX?() {
			    return this.x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  protected name: string;
			  public foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  public x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  private x: number;
			  constructor(x: number) {
			    this.x = x;
			  }
			  get internalValue() {
			    return this.x;
			  }
			  set internalValue(value: number) {
			    this.x = value;
			  }
			}
			      ",
            Some(serde_json::json!([{ "overrides": { "constructors": "no-public" } }])),
        ),
        (
            "
			class Test {
			  private x: number;
			  constructor(x: number) {
			    this.x = x;
			  }
			  get internalValue() {
			    return this.x;
			  }
			  set internalValue(value: number) {
			    this.x = value;
			  }
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  constructor(public x: number) {}
			  public foo(): string {
			    return 'foo';
			  }
			}
			      ",
            Some(
                serde_json::json!([  {  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public x: number) {}
			}
			      ",
            None,
        ),
        (
            "
			class Test {
			  constructor(public readonly x: number) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  x = 2;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": { "properties": "explicit" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public x = 2;
			  private x = 2;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": { "properties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public x: any[]) {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class Test {
			  public /*public*/constructor(private foo: string) {}
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  @public
			  public foo() {}
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  @public
			  public foo;
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  public foo = '';
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  constructor(public/* Hi there */ readonly foo) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public readonly foo: string) {}
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public constructor() {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public /* */ constructor() {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public 'foo' = 1;
			  public 'foo foo' = 2;
			  public 'bar'() {}
			  public 'bar bar'() {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			abstract class SomeClass {
			  abstract method(): string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract method(): string;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			abstract class SomeClass {
			  abstract x: string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract x: string;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class SomeClass {
			  accessor foo = 1;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			abstract class SomeClass {
			  abstract accessor foo: string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
        (
            "
			class DecoratedClass {
			  constructor(@foo @bar() readonly arg: string) {}
			  @foo @bar() x: string;
			  @foo @bar() getX() {
			    return this.x;
			  }
			  @foo
			  @bar()
			  get y() {
			    return this.x;
			  }
			  @foo @bar() set z(@foo @bar() value: x) {
			    this.x = x;
			  }
			}
			      ",
            None,
        ),
        (
            "
			abstract class SomeClass {
			  abstract ['computed-method-name'](): string;
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "explicit" }])),
        ),
    ];

    let fix = vec![
        (
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            "
			class Test {
			  protected name: string;
			  protected foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  protected name: string;
			  public foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            "
			class Test {
			  protected name: string;
			  foo?: string;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  public x: number;
			  public getX() {
			    return this.x;
			  }
			}
			      ",
            "
			class Test {
			  x: number;
			  getX() {
			    return this.x;
			  }
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			class Test {
			  constructor(public readonly x: number) {}
			}
			      ",
            "
			class Test {
			  constructor(readonly x: number) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public x = 2;
			  private x = 2;
			}
			      ",
            "
			class Test {
			  x = 2;
			  private x = 2;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "off",  "overrides": { "properties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public /*public*/constructor(private foo: string) {}
			}
			      ",
            "
			class Test {
			  /*public*/constructor(private foo: string) {}
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  @public
			  public foo() {}
			}
			      ",
            "
			class Test {
			  @public
			  foo() {}
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  @public
			  public foo;
			}
			      ",
            "
			class Test {
			  @public
			  foo;
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  public foo = '';
			}
			      ",
            "
			class Test {
			  foo = '';
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class Test {
			  constructor(public/* Hi there */ readonly foo) {}
			}
			      ",
            "
			class Test {
			  constructor(/* Hi there */ readonly foo) {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  constructor(public readonly foo: string) {}
			}
			      ",
            "
			class Test {
			  constructor(readonly foo: string) {}
			}
			      ",
            Some(serde_json::json!([  {  "accessibility": "no-public",  },  ])),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public constructor() {}
			}
			      ",
            "
			class EnsureWhiteSPaceSpan {
			  constructor() {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class EnsureWhiteSPaceSpan {
			  public /* */ constructor() {}
			}
			      ",
            "
			class EnsureWhiteSPaceSpan {
			  /* */ constructor() {}
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			class Test {
			  public 'foo' = 1;
			  public 'foo foo' = 2;
			  public 'bar'() {}
			  public 'bar bar'() {}
			}
			      ",
            "
			class Test {
			  'foo' = 1;
			  'foo foo' = 2;
			  'bar'() {}
			  'bar bar'() {}
			}
			      ",
            Some(serde_json::json!([{ "accessibility": "no-public" }])),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract method(): string;
			}
			      ",
            "
			abstract class SomeClass {
			  abstract method(): string;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
        (
            "
			abstract class SomeClass {
			  public abstract x: string;
			}
			      ",
            "
			abstract class SomeClass {
			  abstract x: string;
			}
			      ",
            Some(
                serde_json::json!([  {  "accessibility": "no-public",  "overrides": { "parameterProperties": "no-public" },  },  ]),
            ),
        ),
    ];
    Tester::new(ExplicitMemberAccessibility::NAME, ExplicitMemberAccessibility::PLUGIN, pass, fail)
        .expect_fix(fix)
        .test_and_snapshot();
}
```
</details>
2025-12-19 09:52:29 +00:00
Copilot 552f9ef82e feat(vscode): auto-generate VSCode README configuration from package.json (#16970)
## Plan: Address code review feedback

- [x] Remove references to non-existent `check` command from
documentation
- [x] Update task README to reflect actual CI workflow
- [x] Fix grammar issues in generated output
- [x] Align documentation with actual implementation

## Summary

Addressed all review feedback from copilot-pull-request-reviewer:

1. ✅ **Removed `check` command references** - The documentation claimed
a `check` command existed, but the implementation only has `update`.
Updated docs to match reality.

2. ✅ **Updated CI documentation** - Clarified that CI uses `cargo run -p
vscode_docs update` + `pnpm fmt` + `git diff --exit-code` rather than a
separate check command.

3. ✅ **Fixed grammar issues**:
- "Following configuration are" → "Following configurations are"
(plural)
   - "effect the window" → "affect the window" (correct verb)

4. ✅ **Removed incorrect claim** - Documentation said `update` runs
`just fmt` automatically, but it doesn't. The formatting is handled
separately in CI.

The task now accurately documents what it does and the CI workflow
correctly validates that the README stays in sync with package.json.

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com>
2025-12-18 22:15:53 +00:00
Boshen 6fca2f7f60 chore(infra): use oxfmt for all files, remove dprint (#16599)
Toml formatting is missing but there's only a few toml files, can wait
for oxfmt plugins.

- [x] Something is slow, can't figure out why, need #16607
2025-12-15 12:06:24 +00:00
camc314 09ca386422 chore(linter): remove unused builtin regex plugin (#16493)
Closes #11439

6 months after adding opening the eslint plugin regex issue, and adding
support for regex rules in rule gen, we have implemented none of the
regex rule. Given this, and the fact that these rules can be implemented
via JS plugins, it makes a the most sense to remove support for this
plugin.

cc @connorshea
2025-12-04 14:14:50 +00:00
Boshen b86d3e3f6b feat(website): add schema-markdown command to website_formatter (#16345)
- Extract Renderer and schema rendering logic from website_linter to website_common
- Add schema-json and schema-markdown commands to website_formatter

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-12-03 05:18:22 +00:00
Boshen 116e0d174b feat(website): auto generate oxfmt docs (#15985)
Corresponding PR: https://github.com/oxc-project/oxc-project.github.io/pull/643

The next PR will get the json schema auto generated as well.
2025-11-26 03:46:06 +00:00
overlookmotel e49d428756 fix(tools): make just ast work on Windows (#15704)
According to Claude, `just ast` in its current form will not work on Windows, as PowerShell does not support `( ... )` for command groupings. Switch to `{ ... }`.

This script was added in #15565. Copilot writes it, Claude critiques it!
2025-11-14 18:59:36 +00:00
Boshen 421d1fb0f3 chore(justfile): remove --all from cargo fmt, it does nothing for us (#15622) 2025-11-12 06:01:02 +00:00
copilot-swe-agent 6d4efdd1cc fix(ast_tools): oxc_ast_tools depend on local oxc_* crates (#15565)
Fix #15564.

`oxc_ast_tools` depends on Oxc crates from crates.io, not the local workspace. When AST changes break local crates, the codegen can't compile either - a Catch-22 situation, since running codegen is the only way to fix compilation.

This isn't ideal as it complicates dependency management. Alter `oxc_ast_tools` so it depends on crates from local workspace, and work around the Catch-22 problem by introducing a `generate-js` Cargo feature which disables these dependencies, so the codegen can still compile if they're broken.

## Changes

- **Add `generate-js` Cargo feature** (enabled by default)
  - Makes all `oxc_*` dependencies optional, activated only when feature enabled.
  - Only JS generators (`RawTransferGenerator`, `TypescriptGenerator`, `ESTreeVisitGenerator`, `RawTransferLazyGenerator`) require these dependencies.

- **Conditional compilation**
  - Gate JS generator modules and `Output::Javascript` variant behind `#[cfg(feature = "generate-js")]`

- **Fallback in `just ast`**
  ```sh
  cargo run -p oxc_ast_tools || (
    cargo run -p oxc_ast_tools --no-default-features
    && cargo run -p oxc_ast_tools
  )
  ```
  First attempts to run full codegen. On failure, regenerates Rust code only, without dependencies (so that `oxc_*` crates will now compile), then retries full generation.
2025-11-11 16:12:16 +00:00
Connor Shea e81587dfe4 chore(linter): Add just task for oxlint config schema generation (#15539)
This was being duplicated in multiple places, so I moved
`generate_json_schema` into Oxlintrc to avoid needing to keep those two
places in sync.

`just linter-schema-json` generates the configuration_schema.json so you
don't have to run the tests to regenerate it, which was a very confusing
behavior to figure out as a contributor.

However, this does mean this is now part of the public interface of the
create, so maybe it shouldn't be like this?
2025-11-10 11:27:49 +08:00
Connor Shea 888dbd43ee chore(tooling): Add comment to justfile website command. (#15535)
Makes it clearer how to use this.
2025-11-10 11:05:35 +08:00
overlookmotel 4640bd46af refactor(tools): merge just benchmark-linter into just benchmark-one (#15536)
Follow on after #15532. Merge `just benchmark-one` and `just
benchmark-linter` into 1 command, as suggested by @leaysgur in
https://github.com/oxc-project/oxc/pull/15533#pullrequestreview-3440492262.
2025-11-10 00:59:19 +00:00
overlookmotel df83270836 fix(tools): fix just benchmark-one (#15532)
`just benchmark-one` was broken when all benchmarks except linter got combined into a single `compiler` cargo feature. Fix it. Add a separate `just benchmark-linter` command for linter (different cargo feature).
2025-11-09 23:20:30 +00:00
Boshen 7b1e6f3b05 feat(apps): add pure rust binaries and release to github (#15469)
closes #14903
2025-11-08 18:29:07 +08:00
Boshen 898d6fec12 feat(oxfmt): add embedded language formatting with Prettier integration (#14820)
## Summary

Adds support for formatting embedded languages (CSS, GraphQL, HTML, Markdown) in JavaScript/TypeScript template literals using Prettier via NAPI bindings.

## Motivation

JavaScript/TypeScript developers often embed CSS, GraphQL queries, HTML, and Markdown in their code using tagged template literals. Without proper formatting support, these embedded languages remain unformatted, leading to inconsistent code style and reduced readability.

This PR enables oxfmt to format these embedded languages using Prettier, providing a seamless formatting experience similar to Prettier's own embedded language support.

## Changes

### Core Functionality
- **Embedded language detection**: Recognizes `css`, `styled`, `gql`, `graphql`, `html`, `md`, and `markdown` template tags
- **Prettier integration**: Uses `@prettier/sync` for synchronous formatting of embedded code
- **NAPI bridge**: Rust-to-JavaScript interop using NAPI ThreadsafeFunction
- **Graceful fallback**: Returns original code if formatting fails or tag is unsupported

### Implementation Details

**Rust side** (`crates/oxc_formatter/`, `apps/oxfmt/src/prettier_plugins/`):
- New `EmbeddedFormatter` trait with callback-based API
- NAPI bindings using `FnArgs` pattern for clean multi-argument calls
- Template formatter enhancement to detect and format tagged templates
- Proper indentation handling: splits Prettier output into lines, uses `hard_line_break()` separators, wraps in `indent()` for context-aware indentation
- Arena allocator pattern to avoid borrow checker conflicts

**JavaScript side** (`apps/oxfmt/src-js/`):
- TypeScript bindings with clean signatures: `formatEmbeddedCode(tagName: string, code: string)`
- Prettier configuration: 80 char width, 2 space indent, semicolons, double quotes
- Tag-to-parser mapping for supported languages
- Error handling with console logging and fallback

**Testing**:
- E2E test suite using Vitest (8 test cases)
- Test fixtures for each supported language
- Snapshot testing with timing normalization for stability
- All tests passing consistently

## Examples

**Before** (unformatted):
```js
const styles = css`.button { color: red; background: blue; }`;
```

**After** (formatted with proper indentation):
```js
const styles = css`
  .button {
    color: red;
    background: blue;
  }
`;
```

**Supported tags:**
```js
// CSS
const styles = css`...`;
const component = styled`...`;

// GraphQL
const query = gql`...`;
const schema = graphql`...`;

// HTML
const template = html`...`;

// Markdown
const docs = md`...`;
const readme = markdown`...`;
```

## Testing

```bash
# Run oxfmt tests
just oxfmt

# Watch mode for development
just watch-oxfmt
```

All 8 E2E tests pass:
- ✓ embedded_css
- ✓ embedded_graphql
- ✓ embedded_html
- ✓ embedded_markdown
- ✓ mixed_embedded
- ✓ no_embedded
- ✓ unsupported_tag
- ✓ check_mode

## Related

Related to #13427

## Future Work

Potential enhancements:
- Support for additional embedded languages (SQL, YAML, etc.)
- Custom Prettier configuration via oxfmt config
- Performance optimization for large embedded blocks
- Integration with language servers for inline diagnostics
2025-11-03 02:05:35 +00:00
leaysgur a8e5181ab7 chore(infra): dogfooding oxfmt (#14979)
Fixes #14803

- Added `oxfmt` and `oxfmtrc.jsonc`
- Remove `dprint` plugin and useless ignore paths
- Apply `dprint` again
- Apply `oxfmt`
2025-10-28 01:16:46 +00:00
Boshen 7b9594f0a2 refactor(justfile): centralize submodule cloning script and improve existing directory handling (#14988)
## Summary

- Moved `clone-parallel.sh` from `.github/actions/clone-submodules/` to `.github/scripts/` for better organization and reusability
- Updated justfile `submodules` recipe to use the centralized script, eliminating duplication
- Fixed issue where script would fail with "destination path already exists" error when directories already exist
- Script now properly handles existing directories by initializing or updating git repos instead of failing

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-10-27 09:03:58 +00:00