mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
agent/react-compiler-dynamic-import
1113 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
892238149b |
refactor(linter): remove inactive react config rule (#25740)
Remove the inactive `react/config` rule and its generated metadata. Oxlint uses fixed, valid React Compiler options, so the rule cannot produce actionable diagnostics. AI-assisted: Codex was used to implement and validate this change. |
||
|
|
8c4552dfa6 |
feat(linter)!: split react/react-compiler into per-category rules (#25500)
Splits the experimental `react/react-compiler` rule into 24 category-specific rules matching `eslint-plugin-react-hooks` v7. - Runs React Compiler once per file and routes structured diagnostics to each enabled rule. - Removes `react/react-compiler` and `reportAllBailouts`, with rules categorized by user-facing lint intent. - Adds per-rule documentation and deduplicates shared React lint URLs. - Preserves standardized compiler diagnostics while reporting each finding under its Oxlint rule name. Breaking change: configurations using `react/react-compiler` must migrate to the category-specific rules. Written with Claude Code and Codex. |
||
|
|
36f845168c |
fix(linter/eslint/no-eval): align indirect default with ESLint (#25656)
## Summary - default `allowIndirect` to `false`, matching ESLint's `no-eval` behavior - report bare global `eval` references and declared global-object member access by default - avoid duplicate diagnostics for direct global calls while preserving `allowIndirect: true` - add regression coverage, including an ESLint disable-next-line directive Closes #25619. |
||
|
|
beb724dce2 |
fix(linter/eslint/no-unused-vars): report bare underscore parameters (#25663)
## Summary - report a bare underscore parameter when no args ignore pattern is configured - preserve the optimized underscore-prefix behavior for explicit argsIgnorePattern configuration - update focused rule coverage and generated documentation Closes #25626 |
||
|
|
4004c101ca |
fix(linter/eslint/no-irregular-whitespace): check comments by default (#25660)
## Summary - align the skipComments default with ESLint - report irregular whitespace in line and block comments by default - preserve the skipComments: true opt-out - verify suppressed comment diagnostics count disable directives as used - regenerate the published configuration schema Fixes #25616. |
||
|
|
285820eed6 |
fix(linter/no-large-snapshots): precompile and document allowed snapshot matchers (#25611)
issue #23594 - Move regex compilation to configuration parsing to avoid recompiling patterns for every snapshot entry - Document the matching behavior of allowedSnapshots (first interpret as regex, if not valid match as string) - Fix a small typo where both example sections were labeled “incorrect" - Replace manual config parsing with DefaultRuleConfig |
||
|
|
c07fe7c217 |
feat(oxfmt): support experimentalOperatorPosition (#25643)
Fixes #16366 --- Option name requires `experimental` prefix for now. Values are: - `"start"` - `"end"`(default) This is also available on playground. |
||
|
|
0c68b7ff8b |
fix(estree): emit decorators on FormalParameterRest (#25582)
This PR adds support for emitting `decorators` when serializing an ast to ESTree (both with/without raw transfer).
Given the following code:
```
class C { method(@dec ...args) {} }
```
Before we emitted the following ESTree shape:
```json
"params": [
{
"type": "RestElement",
"decorators": [],
"argument": {
"type": "Identifier",
"decorators": [],
"name": "args",
"optional": false,
"typeAnnotation": null,
},
"optional": false,
"typeAnnotation": null,
"value": null,
}
],
```
Now we emit:
```json
"params": [
{
"type": "RestElement",
"decorators": [
{
"type": "Decorator",
"expression": { "type": "Identifier", "name": "dec" }
}
],
"argument": {
"type": "Identifier",
"decorators": [],
"name": "args",
"optional": false,
"typeAnnotation": null,
},
"optional": false,
"typeAnnotation": null,
"value": null,
},
],
```
fixes https://github.com/oxc-project/oxc/issues/18981
closes https://github.com/oxc-project/oxc/pull/24736
|
||
|
|
fed6681eda |
docs(oxfmt): skip expanding overrides options (#25572)
Follow up on #25544. Oxlint also omits `overrides[].rules`. |
||
|
|
4df5835fc3 |
fix(linter): allow capitalized built-in calls (#25516)
Fixes #24405. The React Compiler global registry omitted `BigInt` and `Symbol`, causing `CapitalizedCalls` false positives. Register both primitives and expose the upstream-compatible `environment.validateNoCapitalizedCalls` option. Validated with `just ready`. AI-assisted: Codex was used to investigate and implement this change. |
||
|
|
c42d6397ea |
release(apps): oxlint v1.78.0 && oxfmt v0.63.0 (#25473)
# Oxlint ### 💥 BREAKING CHANGES - |
||
|
|
b6f1458dec |
release(crates): oxc v0.144.0 (#25474)
### 💥 BREAKING CHANGES - |
||
|
|
00f490d7f7 |
refactor(oxfmt,formatter): split sortImports validation and use type enum (#25432)
Reduce runtime validation. Also, by using type `enum`, IDE and TS types are also covered. |
||
|
|
ccb8fe89db |
feat(linter/jsdoc): implement no-blank-blocks rule (#25207)
this PR implements `jsdoc/no-blank-blocks` rule, issue #1170 |
||
|
|
9573937df3 |
fix(linter/typescript): validate ban-ts-comment description_format (#25320)
adds validation for the `descriptionFormat` regex option from #23594 and replaces manual config parsing with `DefaultRuleConfig` |
||
|
|
44fd320324 |
feat(ast)!: split TS external modules & Namespace Declarations (#25284)
## Summary
- Splits `TSModuleDeclaration` into two dedicated declaration nodes:
- `TSExternalModuleDeclaration` for string-literal modules and module augmentations.
- `TSNamespaceDeclaration` for identifier-based `module` and `namespace` declarations.
- Removes `TSModuleDeclaration`, `TSModuleDeclarationName`, `TSModuleDeclarationBody`, and `TSModuleDeclarationKind`.
- Makes invalid combinations of names, bodies, and declaration kinds unrepresentable.
- Ensures only namespace declarations introduce a normal binding.
- Updates all AST consumers, generators, traversal, formatting, code generation, semantic analysis, lint rules, transforms, and serialization.
- Keeps normal and eager-raw ESTree output compatible: both declarations remain `TSModuleDeclaration` nodes.
- Allows experimental lazy raw deserialization to expose the two new node types directly.
## Breaking Change
The Rust AST changes from:
```rust
pub enum Declaration<'a> {
VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32,
FunctionDeclaration(Box<'a, Function<'a>>) = 33,
ClassDeclaration(Box<'a, Class<'a>>) = 34,
TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 35,
TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 36,
TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 37,
TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>) = 38,
TSGlobalDeclaration(Box<'a, TSGlobalDeclaration<'a>>) = 39,
TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 40,
}
pub struct TSModuleDeclaration<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub id: TSModuleDeclarationName<'a>,
pub body: Option<TSModuleDeclarationBody<'a>>,
pub kind: TSModuleDeclarationKind,
pub declare: bool,
pub scope_id: Cell<Option<ScopeId>>,
}
```
to:
```rust
pub enum Declaration<'a> {
VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32,
FunctionDeclaration(Box<'a, Function<'a>>) = 33,
ClassDeclaration(Box<'a, Class<'a>>) = 34,
TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 35,
TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 36,
TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 37,
TSExternalModuleDeclaration(Box<'a, TSExternalModuleDeclaration<'a>>) = 38,
TSNamespaceDeclaration(Box<'a, TSNamespaceDeclaration<'a>>) = 39,
TSGlobalDeclaration(Box<'a, TSGlobalDeclaration<'a>>) = 40,
TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 41,
}
pub struct TSExternalModuleDeclaration<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub id: StringLiteral<'a>,
pub body: Option<Box<'a, TSModuleBlock<'a>>>,
pub declare: bool,
pub scope_id: Cell<Option<ScopeId>>,
}
pub struct TSNamespaceDeclaration<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub id: BindingIdentifier<'a>,
pub body: TSNamespaceDeclarationBody<'a>,
pub kind: TSNamespaceDeclarationKind,
pub declare: bool,
pub scope_id: Cell<Option<ScopeId>>,
}
pub enum TSNamespaceDeclarationBody<'a> {
TSNamespaceDeclaration(Box<'a, TSNamespaceDeclaration<'a>>) = 0,
TSModuleBlock(Box<'a, TSModuleBlock<'a>>) = 1,
}
pub enum TSNamespaceDeclarationKind {
Module = 0,
Namespace = 1,
}
```
The corresponding inherited `Statement` variants, `AstKind` variants, builders, and visitor methods have also changed.
## Why?
`TSModuleDeclaration` previously represented two declaration families with different syntax and semantics:
```ts
declare module "foo" {}
declare module "*.css";
module Foo {}
namespace Foo {}
namespace Foo.Bar {}
```
The shared representation allowed invalid states such as:
- A namespace with a string-literal name.
- An external module with an identifier name.
- An identifier namespace without a body.
- A dotted external module.
- An external module containing another module declaration as its body.
- A declaration whose `kind` disagreed with its name.
Consumers also had to inspect `id` before determining whether the node introduced a binding or represented an external module.
The two declaration families have stronger independent invariants:
### External modules
- Always have a string-literal name.
- Never introduce a normal binding identifier.
- May omit their body.
- Cannot use dotted names.
- Use module-body import and export rules.
### Namespace declarations
- Always have a binding identifier.
- Always have a body.
- May contain nested namespace declarations for dotted names.
- Explicitly preserve the `module` or `namespace` spelling.
- Introduce a namespace/module symbol.
- Use namespace-body restrictions.
Dedicated nodes encode these differences directly.
## Declaration forms
External modules use `TSExternalModuleDeclaration`:
```ts
declare module "foo" {}
declare module "*.css";
module "foo" {}
```
Identifier-based declarations use `TSNamespaceDeclaration`:
```ts
module Foo {}
namespace Foo {}
```
Dotted namespaces are represented as nested namespace declarations:
```ts
namespace Foo.Bar {}
```
```rust
TSNamespaceDeclaration {
id: Foo,
body: TSNamespaceDeclarationBody::TSNamespaceDeclaration(
TSNamespaceDeclaration {
id: Bar,
body: TSNamespaceDeclarationBody::TSModuleBlock(...),
// ...
}
),
// ...
}
```
Only `TSExternalModuleDeclaration::body` is optional.
## ESTree compatibility
Normal serialization and eager raw deserialization continue to emit the existing ESTree shape:
```ts
interface TSModuleDeclaration {
type: "TSModuleDeclaration";
id: BindingIdentifier | StringLiteral | TSQualifiedName;
body: TSModuleBlock | null;
kind: "module" | "namespace";
declare: boolean;
global: false;
}
```
Dotted namespaces continue to serialize as a single `TSModuleDeclaration` with a `TSQualifiedName`.
Experimental lazy raw deserialization is not compatibility-preserving. It now exposes `TSExternalModuleDeclaration` and `TSNamespaceDeclaration` directly, with separate constructors, layouts, and visitor type IDs.
## How to migrate
Code that previously matched all forms through one variant:
```rust
if let Declaration::TSModuleDeclaration(declaration) = declaration {
// ...
}
```
should now match the required declaration family:
```rust
match declaration {
Declaration::TSExternalModuleDeclaration(declaration) => {
// String-literal external module
}
Declaration::TSNamespaceDeclaration(declaration) => {
// Identifier-based module or namespace
}
_ => {}
}
```
The same applies to `Statement` and `AstKind`:
```rust
Statement::TSExternalModuleDeclaration(declaration)
Statement::TSNamespaceDeclaration(declaration)
AstKind::TSExternalModuleDeclaration(declaration)
AstKind::TSNamespaceDeclaration(declaration)
```
Common field migrations:
| Previous representation | New representation |
| --- | --- |
| `TSModuleDeclarationName::StringLiteral(id)` | `TSExternalModuleDeclaration::id` |
| `TSModuleDeclarationName::Identifier(id)` | `TSNamespaceDeclaration::id` |
| `body: None` | Only valid on `TSExternalModuleDeclaration` |
| `TSModuleDeclarationBody::TSModuleBlock` | External `body` or `TSNamespaceDeclarationBody::TSModuleBlock` |
| `TSModuleDeclarationBody::TSModuleDeclaration` | `TSNamespaceDeclarationBody::TSNamespaceDeclaration` |
| `TSModuleDeclarationKind::Module` | External module, or `TSNamespaceDeclarationKind::Module` |
| `TSModuleDeclarationKind::Namespace` | `TSNamespaceDeclarationKind::Namespace` |
| Inspect `id` to determine binding behavior | Match `TSNamespaceDeclaration` |
| `declaration.id()` for string modules | Now returns `None` |
| `visit_ts_module_declaration` | `visit_ts_external_module_declaration` or `visit_ts_namespace_declaration` |
When constructing nodes, use the generated `TSExternalModuleDeclaration` or `TSNamespaceDeclaration` builders rather than recreating the previous shared representation.
fixes https://github.com/oxc-project/backlog/issues/218
|
||
|
|
d4a897ce22 |
feat(linter/eslint): implement one-var rule (#24470)
## Summary Adds a native Oxlint implementation of [ESLint's `one-var` rule](https://eslint.org/docs/latest/rules/one-var). This implementation is a port of the [eslint rule source](https://github.com/eslint/eslint/blob/main/lib/rules/one-var.js), test suite, and autofix logic. Related #479 ## AI Disclosure GPT 5.6 Sol was used to assist with implementation of this rule. --------- Co-authored-by: Cameron <cameron.clark@hey.com> |
||
|
|
5ab9340637 |
feat(linter/jsx-a11y/anchor-has-content): add options to match eslint (#24571)
## Description Eslint supports [a `components` option](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-has-content.md) for `jsx-a11y/anchor-has-content` that specified additional components to treat as anchor elements. This adds equivalent support for that option. Note: I am not certain if this is something that should instead be read off of [`settings.jsx-a11y.components`](https://oxc.rs/docs/guide/usage/linter/config-file-reference.html#settings-jsx-a11y-components), as that could list `{ MyAnchor: 'a' }`. Doing that would enable implicit application of rules to custom components based on rendered entity, but that may be the wrong use case, as the custom component definition itself could be responsible for rendering required children. ## AI disclosure I used GPT 5.6 Sol to assist in implementation of this fix. I've reviewed all generated code and test coverage. --------- Signed-off-by: Cameron <cameron.clark@hey.com> Co-authored-by: Cameron <cameron.clark@hey.com> |
||
|
|
9a423f2f48 |
release(apps): oxlint v1.77.0 && oxfmt v0.62.0 (#25251)
# Oxlint ### 💥 BREAKING CHANGES - |
||
|
|
45a17c25d1 |
release(crates): oxc v0.143.0 (#25250)
### 💥 BREAKING CHANGES - |
||
|
|
5c0fa61ddb |
fix(linter/eslint/no-warning-comments): unify config structs and remove manual options docs (#25151)
this PR unifies 2 config structs for `eslint/no-warning-comments` and removes the manually written options doc, related issue: #14743. Doc after fix: <img width="919" height="1295" alt="image" src="https://github.com/user-attachments/assets/dab8f999-fffa-4a77-8d6d-39746cfa3860" /> |
||
|
|
9dc7756729 |
docs(linter/typescript/no-unnecessary-condition): clarify options (#25110)
## Summary - document the exact allowConstantLoopConditions behavior, including the four directly allowed literals - explain how always differs from only-allowed-literals - add a checkTypePredicates example and regenerate the published configuration schema Closes #25098 |
||
|
|
e6e584b9be |
fix(oxfmt): type jsdoc. enum options (#25008)
Fixes #24999 |
||
|
|
65fe65d842 |
release(apps): oxlint v1.76.0 && oxfmt v0.61.0 (#24976)
# Oxlint ### 🚀 Features - |
||
|
|
fc702c1fa9 |
release(crates): oxc v0.142.0 (#24977)
### 💥 BREAKING CHANGES - |
||
|
|
3ff2e0e6fa |
docs(linter): clarify config extends types (#24936)
The generated config reference only described the JSON schema's `string[]` form. Clarify that `oxlint.config.ts` accepts imported `OxlintConfig[]`, add an example and public JSDoc, and regenerate the derived artifacts. Closes #20238. Validated with the website generator suite, targeted TypeScript checks, and the relevant Oxlint tests. The full `just ready` run reached an unrelated parallel suppression-fixture cleanup race; the failing test passes in isolation. AI-assisted. |
||
|
|
8d31dfa393 |
feat(linter): verify eslint/no-restricted-globals config schema (#24598)
Part of #22955. Follow-up to the resolved #23617. ## What `eslint/no-restricted-globals` stayed in `NO_VERIFIED_VALID_SCHEMA` after #23617 was resolved, because the derived schema described the internal `NoRestrictedGlobalsConfig` struct (a `globals` hash map) rather than the user-facing positional-array format the rule actually parses. This PR adds a hand-written `JsonSchema` following the existing `no-restricted-imports` pattern, describing the three accepted positional item forms: 1. `"event"` — a global name string 2. `{ "name": "event", "message": "…" }` — a name/message object 3. `{ "globals": [ … ], "checkGlobalObject": true, "globalObjects": [ … ] }` — the object form added in #23617 Generated TS declaration: ```ts "no-restricted-globals"?: RuleNoConfig | [AllowWarnDeny, NoRestrictedGlobalsConfigEnum, ...NoRestrictedGlobalsConfigEnum[]]; export type NoRestrictedGlobalsConfigEnum = string | RestrictedGlobal | NoRestrictedGlobalsObjectConfig; ``` Verified against the #22955 checklist: reflects all accepted user configuration forms, denies unknown fields on object forms, and produces no `[k: string]: unknown` in the TS declaration. `from_configuration` and rule behavior are unchanged; rule tests pass. Note: this branch removes only the `no-restricted-globals` entry from `NO_VERIFIED_VALID_SCHEMA`; #24586 (separate PR) removes the `filename-case` entry, so whichever merges second will have a trivial conflict in that array. ## Disclosure This contribution was developed with assistance from Claude Code (Anthropic); I have reviewed and tested all changes. --------- Signed-off-by: Alexander S. <sysix@sysix-coding.de> Co-authored-by: Alexander S. <sysix@sysix-coding.de> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> |
||
|
|
7069621199 |
feat(linter): verify jest/vitest prefer-lowercase-title config schema (#24724)
## Summary - Unskip `jest/prefer-lowercase-title` and `vitest/prefer-lowercase-title` from `NO_VERIFIED_VALID_SCHEMA`. - PreferLowercaseTitleConfig already derives `Deserialize` + `JsonSchema` with `deny_unknown_fields` and docs for all public options, so the generated schema/types can describe the real config. - Regenerates `npm/oxlint/configuration_schema.json` and `apps/oxlint/src-js/package/config.generated.ts`. ## Motivation Part of #22955. These two plugin names shared a clean config struct already used at runtime; they were still emit-as-`DummyRule` only because of the broader #23186 split note (mainly about `valid-title` option divergence). Leaving `valid-title` skipped. Generated config now exposes: - `allowedPrefixes: string[]` (default `[]`) - `ignore: string[]` (default `[]`) - `ignoreTopLevelDescribe: boolean` (default `false`) - `lowercaseFirstCharacterOnly: boolean` (default `true`) - `additionalProperties: false` / no `[k: string]: unknown` ## Verification - `cargo test -p website_linter` — 8 passed - `cargo test -p oxc_linter --features ruledocs test_rules_with_custom_configuration_have_schema` — passed - `cargo test -p oxc_linter prefer_lowercase_title --lib` — 2 passed (jest + vitest) - Inspected generated schema/TS: not DummyRule; no index signature ## AI disclosure Assisted by AI (Hermes/Sera). I reviewed the existing PreferLowercaseTitleConfig against the GFI checklist, regenerated schema/types locally, and ran the tests above. --- **Agent-Owner:** `sera` · **Platform:** hermes · **Claim:** `sera` --- <!-- fleet-pr-claim: agent_id=sera platform=hermes --> **Agent-Owner:** `sera` · **Platform:** hermes · **Claim-TTL:** 24h --------- Co-authored-by: Bartok9 <259807879+Bartok9@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> |
||
|
|
016cf2acd6 |
feat(linter/oxc): add bad-match-all-arg rule (#24900)
## Summary - add oxc/bad-match-all-arg for non-global regular expressions passed to matchAll - share cycle-safe RegExp flag resolution with bad-replace-all-arg - support callable and global-qualified RegExp constructors - update generated metadata, diagnostics, timings, and CLI rule-count snapshots Closes #24823. |
||
|
|
cdc941e5f8 |
feat(linter/n): implement exports-style rule (#24087)
this PR implements `n/exports-style` rule. Issue #493 --------- Co-authored-by: Cameron <cameron.clark@hey.com> |
||
|
|
1ad6f6c823 |
feat(linter/eslint): implement id-denylist rule (#24632)
this PR implements `eslint/id-denylist`, issue #479 |
||
|
|
83abe3b49c |
release(apps): oxlint v1.75.0 && oxfmt v0.60.0 (#24713)
# Oxlint ### 💥 BREAKING CHANGES - |
||
|
|
14533a3dc1 |
release(crates): oxc v0.141.0 (#24714)
### 💥 BREAKING CHANGES - |
||
|
|
6ce51d3ff3 | chore(deps): update dependency oxlint-tsgolint to v7.0.2000 (#24763) | ||
|
|
dd18383ee1 |
feat(linter/node): implement no-top-level-await rule (#24634)
This implements
[`no-top-level-await`](https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-top-level-await.md)
from the Node ESLint plugin (#493).
AI Disclosure: Generated with Claude Code. Reviewed and tested by me.
I have an alternative implementation using a Program visitor but it made
no difference performance-wise on vscode or in benchmarking outside
extreme cases, so I don't think it's really worth the trouble vs the
simpler implementation here. It's still in the commit history if that
implementation is preferred.
There is one notable difference between this and the original
implementation, which is that the `convertPath` option is not
implemented, and the checking of `package.json`/`.npmignore` is not
implemented (it was used for checking if the given module was actually
exposed in the library) as there's no way to check against those in
oxlint. There's an argument to be made that this makes the rule not
worth implementing, and I'm open to that argument if we'd prefer to mark
this rule as unsupported instead.
All tests were ported from the original rule (excluding those reliant on
the mentioned config options/checks that were skipped). I've also had
Claude add a few additional test cases (see commit
|
||
|
|
8694167be7 |
fix(linter/eslint/prefer-destructuring): handle typed declarations (#24616)
## Summary - skip prefer-destructuring diagnostics for variable declarations with type annotations by default - add enforceForDeclarationWithTypeAnnotation for typescript-eslint compatibility - report without an autofix when annotated declarations are explicitly enforced, preserving the declared type - cover object, computed-property, array, renamed-property, and reporter configuration cases This matches the current `@typescript-eslint/prefer-`destructuring behavior. Fixes #24615. |
||
|
|
e2e0f94253 |
chore(docs): update sponsor section (#24588)
Point sponsorship url to organization instead of my own. |
||
|
|
54cc121250 |
feat(ast)!: split MetaProperty into ImportMeta and NewTarget (#24557)
## Summary
- replace the generic Rust MetaProperty AST node with dedicated ImportMeta and NewTarget nodes
- preserve the ESTree MetaProperty shape and generated public TypeScript types
- update parser, formatter, codegen, lint, transform, minifier, traversal, and React compiler consumers
## Summary
Remove `MetaProperty` AST node, in favour of two separate nodes (`ImportMeta` and `NewTarget`)
## Breaking Change
The Rust AST field changes from:
```rust
pub struct MetaProperty<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub meta: IdentifierName<'a>,
pub property: IdentifierName<'a>,
}
```
to:
```rust
/// /// `import.meta` in `console.log(import.meta);`.
pub struct ImportMeta {
pub node_id: Cell<NodeId>,
pub span: Span,
}
/// `new.target` in `function F() { return new.target; }`.
pub struct NewTarget {
pub node_id: Cell<NodeId>,
pub span: Span,
}
```
## Why?
The current AST could represent shapes such as:
```
foo.bar
```
By constructing the node manually. However this doesn't make sense, and is invalid.
## How to migrate?
1. Replace any `Expression::MetaProperty` matches/checks with the dedicated `Expression::ImportMeta` and `Expression::NewTarget` varients
2. Replace any `new_meta_property` construction with the new `new_import_meta` or `new_new_target` APIs.
3. Inspecting the `meta`/`property` identifier names is no longer required.
|
||
|
|
16a65f269c |
feat(linter/react): implement function-component-definition rule (#24471)
## Summary Adds a native Oxlint implementation of the [`eslint-plugin-react` `function-component-definition` rule](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md). This implementation is a port of the [rule source](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/lib/rules/function-component-definition.js), test suite, and autofix logic. Related #1022 ## AI Disclosure GPT 5.6 Sol was used to assist with implementation of this rule. --------- Co-authored-by: Cameron <cameron.clark@hey.com> |
||
|
|
7f1f585b86 |
feat(linter): reuse jest/padding-around-test-blocks for vitest/padding-around-test-blocks (#24519)
this PR moves `jest/padding-around-test-blocks` to the shared jest_vitest rules, so it can be reused by both the jest and vitest rules. issue #4656 --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> |
||
|
|
99978a8bbb |
feat(linter/import/consistent-type-specifier-style): support prefer-top-level-if-only-type-imports option (#24502)
## Summary - Re-port upstream support for prefer-top-level-if-only-type-imports. - Allow mixed value/type imports while requiring top-level syntax for imports containing only types. - Preserve Oxlint's existing default and declaration-file behavior. - Regenerate the JSON schema and TypeScript configuration types. ## Reference https://github.com/oxc-project/oxc/issues/1117#issuecomment-4966827537 |
||
|
|
8e0ed2ebb9 |
release(crates): oxc v0.140.0 (#24453)
### 🚀 Features - |
||
|
|
2d4e8d2064 |
release(apps): oxlint v1.74.0 && oxfmt v0.59.0 (#24454)
# Oxlint ### 🚀 Features - |
||
|
|
7f80cac4fd |
perf(linter/vue/prop-name-casing): precompile ignoreProps regex pattern (#24413)
`is_ignored` in `vue/prop-name-casing` recompiled each slash-wrapped `ignoreProps` pattern with `Regex::new` for every prop it checked. This compiles the patterns once in `from_configuration` into an `Exact`/`Pattern(Regex)` matcher enum stored on the options (`serde`/`schemars`-skipped field), and matches against that. Invalid regex patterns are dropped at compile time, which preserves the previous behavior (they could never match before either, and were not compared as literals). ### Benchmark Interleaved paired-sample benchmark (N=40, alternating order, `--silent`), release binaries built from this branch and its merge-base. Fixture: 220 Vue SFCs / 35,200 props / 36.5K lines, single-rule oxlintrc with `ignoreProps: ["ignored_prop", "/^legacy/", "/_deprecated$/", "/^(alpha|beta)_/", "/[/"]` (one exact pattern, three regexes, one invalid regex). | | baseline | this branch | |---|---|---| | rule on | 66.87 ms | 16.69 ms | | parse only | 8.47 ms | 8.41 ms | Paired Δ of **+50.17 ms** (sd 2.18, t=146, faster in 40/40 pairs). The parse-only differential is null (+0.06 ms, t=0.2), so the saving is attributable to the rule and not to binary layout. That works out to 4.0× on this fixture, but the multiplier is fixture-dependent — the work removed scales with `regex_pattern_count × prop_count`, so denser configs show a larger ratio. The ~50 ms saved across 35K props is the more transferable number. ### Correctness Verified with `--format=json` (**without** `--silent`, which empties the JSON reporter's `diagnostics` array): both binaries emit the same 10,560 diagnostics, identical after sorting — the array order varies between runs because files are linted in parallel. The fixture includes canary props that are only ignored via the regex patterns, plus an invalid regex; the ignore semantics are unchanged. ### Disclosure This change was implemented and benchmarked with AI assistance (Claude Code), and has been reviewed by the submitter. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
6272051fcd |
perf(linter/typescript/no-require-imports): compile allow patterns once (#24417)
`match_argument_value_with_regex` recompiled every `allow` pattern with `Regex::new` for each `require()` call and `TSImportEqualsDeclaration` it checked. This compiles the patterns once in `from_configuration` into a `serde`/`schemars`-skipped `Vec<Regex>` on the config and matches against that. Same shape as #24412 and #24413. ### Benchmark **Fixture:** a generated `requires.ts` with 30,000 one-line require calls of the form ```ts const lib12345 = require('./lib12345'); ``` None of the paths match an `allow` pattern, so every call pays the full allow-matching path and reports on both binaries (the common case for this rule: mostly-disallowed requires with a small allowlist). The allow/skip path itself was parity-checked separately with a canary mixing allowed string literals, an allowed template literal, an allowed `import ... = require(...)`, and reported requires. **Config:** single-rule `.oxlintrc.json` so nothing else contributes to the timing: ```json { "plugins": ["typescript"], "categories": { "correctness": "off" }, "rules": { "typescript/no-require-imports": ["warn", { "allow": ["/package\\.json$", "^some-package$", "\\.jsonc$"] }] } } ``` **Method:** two release binaries (baseline from `main`, this branch), run interleaved in alternating order for 40 paired samples with warmup, timed with `time.monotonic_ns()`. A parse-only config on the same fixture showed no meaningful difference between the binaries (1.018×, t=1.7), so the delta is attributable to the rule rather than binary-layout noise. | | mean | |---|---| | before | 410.80 ms | | after | 32.26 ms | **12.7× faster** (paired t=229, 40/40 wins). The magnitude scales with require-call count × number of `allow` patterns; configs that don't set `allow` are unaffected (the matching path is already guarded by `allow.is_empty()`). Diagnostics output is identical between the two binaries on the fixture (30,000 diagnostics) and the canary. It is very unlikely that this will have much of an impact in most cases, as the option is rare and so are `require()` calls these days. But it's a simple enough improvement. ### Behavior note An invalid `allow` pattern previously panicked (`.unwrap()`) at the first `require()` call in a linted file; it now panics when the configuration is loaded — same panic, strictly earlier. ### Disclosure This change was implemented and benchmarked with AI assistance (Claude Code), and has been reviewed by the submitter. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
33805b9691 |
perf(linter/jsdoc/require-param): compile checkTypesPattern regex once (#24420)
AI Disclosure: Generated with Claude Code, reviewed and tested by me. I don't think there's a particularly good reason to use a RwLock like this?
This can be split into separate PRs if preferred, as it also adds the type for this rule to the generated definitions and JSON Schema.
The rule kept compiled `checkTypesPattern` regexes in a global `OnceLock<RwLock<FxHashMap<String, Regex>>>`. Every `run()` on a JSDoc-documented function:
- cloned the pattern `String` to use as the map key,
- took the RwLock **write** lock even on cache hits, serializing all linter threads through a single lock, and
- held the guard across the entire parameter check.
The pattern is fixed at configuration time, so the cache is unnecessary: this PR deserializes the option directly into a `Regex` field on the config (same approach as #24412 / #24417) and deletes the cache entirely.
## Benchmark
Paired interleaved samples (N=40), release builds, fixture of 64 files × 400 fully-documented JSDoc functions (25,600 `run()` calls, all hitting the regex path, zero violations) with only `jsdoc/require-param` enabled:
| Run | Baseline (
|
||
|
|
0433a8376a |
feat(linter/eslint/no-inner-declarations): add namespaces option (#24044)
Adds a `namespaces` option to `eslint/no-inner-declarations`:
```json
["error", "both", { "namespaces": "allow" }]
```
With `namespaces: "allow"`, `function`/`var` declarations placed directly inside a TypeScript `namespace`/`module` body are no longer reported. Declarations nested inside blocks within a namespace (e.g. `namespace N { if (x) { function f() {} } }`) are still reported. The default (`disallow`) is unchanged.
Closes #21143
|
||
|
|
83378351e4 |
fix(linter): error on ignorePatterns that cannot match files aoutside the config directory (#24341)
Follow up on #24339 - Added the same guard as Oxfmt - Since they are identical, I moved them into `oxc_config` so they can be shared |
||
|
|
2ce5a33ecc |
fix(linter): resolve ignorePatterns relative to the config dir (#24339)
Fixes #24310 Root config's `ignorePatterns` are now resolved relative to the directory containing the config file, instead of CWD. Also fixes a latent issue: a `--config <path>` containing `..` silently disabled all `ignorePatterns` (the unnormalized parent dir never prefix-matches lint target paths). Explicit config paths are now lexically normalized, same as Oxfmt. ### Behavior change The new anchoring applies in all cases, including `--config` / LSP `configPath`. This intentionally differs from ESLint, which resolves alternate-config ignore patterns relative to CWD: - `extends`, `overrides[].files`, and JS plugin specifiers are already config-file-relative, including via `--config` - rooting only `ignorePatterns` at CWD would give one file two coordinate systems - Wrappers like Vite+ pass `--config <workspace-root config>` as an implementation detail while CWD stays at the invocation directory, so "`--config` means CWD-relative" does not hold in practice - #24276 Impact should be small: bare names (`dist`, `*.min.js`) and `**/`-prefixed patterns are unaffected by the anchor. The updated `config_ignore_patterns/with_oxlintrc` snapshot shows the `--config` case. |
||
|
|
415fe1e7bb |
fix(oxfmt): error on ignorePatterns that cannot match files outside the config directory (#24286)
Patterns in `ignorePatterns` use gitignore-style matching rooted at the config file's directory, so a `..` component can never match anything. Reject such patterns at config load time instead of silently accepting them, and document the scoping. Refs: #24276 |