Re-order enum variants of `AssignmentOperator`, `BinaryOperator` and `UnaryOperator`.
* `Exponential` moved to after `Remainder` (so with the rest of the arithmetic operators).
* `Shift*` operators follow arithmetic operators.
* `AssignmentOperator::Bitwise*` ops moved to before `Logical*` ops (so all ops which correspond to `BinaryOperator`s are together).
* `*Or` always before `*And`.
* Plus/Addition always before Minus/Subtraction.
The purpose is to make the various methods on these types maximally efficient:
1. Group together variants so that `AssignmentOperator::is_*` methods can be executed with the minimum number of operations (essentially `variant - min <= max`).
2. Align the variants of `AssignmentOperator` and `BinaryOperator` so that conversion methods added in #7350 become very cheap too (essentially `if variant - min <= max { Some(variant + offset) } else { None }`).
`impl GetAddress for Function` was added as a hack, in the absence of another way to get the `Address` of a `&Function` (https://github.com/oxc-project/backlog/issues/140).
Remove it, and use `Address:from_ptr` instead in JSX Refresh transform, which is only place using it.
Use `AstBuilder::vec_from_array` introduced in #7331 in the transformer, in place of creating a `Vec` with `Vec::with_capacity` and then pushing values to it.
Because we lack specialization in stable Rust, `Vec::from_iter_in` is unable to take advantage of the fact that `[T; N]` has a statically knowable size.
Introduce `Vec::from_array_in` for this case, which should be able to create the `Vec` with a single static-sized memcpy, or may allow the compiler to see that it can construct the array directly in the arena, rather than construct on stack and then copy to the arena.
Also add a corresponding `AstBuilder::vec_from_array` method, and use it in various places in codebase.
This function receives an owned `oxc_allocator::Vec`. No need to copy the contents to a new `Vec` with `AstBuilder::vec_from_iter`, can just use the original.
Move the cheap "does arguments need to be transformed" checks introduced in #7321 into `enter_identifier_reference` and `enter_binding_identifier`, and mark those methods `#[inline]`. These hot paths can then usually execute without a function call.
This wins back the other half of the perf hit of #7234.
Track whether `arguments` needs to be transformed. If it doesn't, can skip expensive checks for whether `IdentifierReference`s and `BindingIdentifier`s names are `arguments` or not.
This recovers about half the performance hit of #7234.
Key `super` getter/setter hash map with original property name `&str`, instead of generated binding name. This allows a couple of improvements:
* Generate binding names for `super` getters/setters lazily, only when they're created, rather than every time you encounter a `super`.
* Don't allocate strings into arena which are never used as part of AST. Use `CompactString` for building those strings instead.
Optimize this function in various ways:
* Return a static `Atom` (rather than allocating into arena) if no `property`.
* Reserve capacity for `ArenaString` at start.
* Make path for unicode identifiers (very rare case) `#[cold]` and `#[inline(never)]`.
* Slightly faster uppercase conversion.
Fix due to this plugin transforming the async method and async arrow function, it caused arguments no longer point the original function.
For example:
Before
```js
class Cls {
async method() {
() => {
console.log(arguments)
}
}
}
```
After:
```js
class Cls {
method() {
var _arguments = arguments;
return babelHelpers.asyncToGenerator(function* () {
() => {
console.log(_arguments);
};
})();
}
}
```
In this way, the `_arguments` is its original function's arguments
### For performance regression
It seems we need to check the IdentifierReference and BindingIdentifier if it's an `arguments`, that causes a significant regression, we may need a cheap way to do checking
- fixes https://github.com/oxc-project/oxc/issues/6896
When the `plugins` config property is specified, it will overwrite the default plugins array. This allows the plugins list to be easily customized and allows for disabling default plugins at the same time as enabling non-default ones.
- example: `{ "plugins": [] }` will enable no plugins.
- example: `{ }` will enable default plugins.
- example: `{ "plugins": ["typescript", "import"] }` will enable only the import and typescript plugins.
`TransformCtx::helper_call` and `TransformCtx::helper_call_expr` take a `Span`. Sometimes the helper call replaces some original code, and should have the same span as the original code.
It's a common pattern in transformer to call `ctx.create_ident_reference()` and then convert to an `Expression` with `Expression::Identifier(ctx.ast.alloc(ident))`.
Add methods to do this in a single method call.
Similar to #7289. Check if `span.end` is 0 before doing `span.end - 1`, to prevent arithmetic overflow.
Also changed all checks to `span.end > 0`, just for consistency.
`clone_expression` was unnecessarily looking up the `SymbolId` of references multiple times. Use `BoundIdentifier` instead to avoid that.
Notes:
* `create_conditional_expression` has to take all parts as `Expression`s just to support `this ?? something`.
* `TraverseCtx::is_static` also handles `Super`, but can skip that in this case as `super ?? something` is not valid syntax.
part of #4655
### Summary
Logic has been added to handle bind functions, unifying the
implementations of `unicorn/no-useless-promise-resolve-reject` and
`promise/no-return-wrap`.
This enables detection of the following code:
```javascript
foo().then((function() { return Promise.resolve(4) }).bind(this))
```
Merging this PR will allow this rule to pass all test cases of
promise/no-return-wrap without options. Additionally, merging #7274 will
ensure that all test cases are passed.
Remove `TraverseCtx::clone_identifier_reference`.
This API encourages unnecessary repeated lookups of the `SymbolId` for a reference. It is preferable to use `MaybeBoundIdentifier` which only looks up the `SymbolId` once.
`MaybeBoundIdentifier` is similar to `BoundIdentifier`, but can be used where the identifier may or may not have have a `SymbolId` (may or may not be bound).
Typical usage:
```rs
// Create `MaybeBoundIdentifier` from an existing `IdentifierReference`
let binding = MaybeBoundIdentifier::from_identifier_reference(ident, ctx);
// Generate `IdentifierReference`s and insert them into AST
assign_expr.left = binding.create_write_target(ctx);
assign_expr.right = binding.create_read_expression(ctx);
```
Pure refactor. `StringLiteral` definition was sandwiched in the middle of RegExp-related code. Move it higher up in `literal.rs`.
All the rest of the diff is just re-ordering generated code.
I had intended to leave this in until we could rework some of the rule/plugin name resolution code, however this is causing issues with merging https://github.com/oxc-project/oxc/pull/6974. The mutability of `self` is difficult to resolve in that PR without more drastic changes. Since this isn't currently helping us out, I am simply removing the code for now until we can revisit this.
Variants of `TSEnumMemberName` were previously only prefixed with `Static` to avoid naming conflicts with the variants inherited from `Expression` for non-static member names. #7219 removed the variants inherited from `Expression`, so all variants are now static. So we can shorten the names again (back to what they were before `inherit_variants!` was introduced).
#7219 removed all variants of `TSEnumMemberName` except `IdentifierName` and `StringLiteral`. It no longer inherits variants from `Expression`, so we can remove the `inherit_variants!` macro wrapper.
The discriminants no longer need to avoid clashes with `Expression`'s, so they can start at 0.
Firstly, a massive thanks to @alisnic for starting this (incredibly complicated) lint rule in https://github.com/oxc-project/oxc/pull/2637 !
still a draft. current state:
3x false positives (all todo with refs)
3x false negatives (TS will catch these
13x false negatvies todo with refs
1x false negative TODO
closes #2637
relates to #2174
For the test case, Closure Compiler doesn't handle this at all in the REPL! If it's necessary, I will turn it back.
This PR uses builtin `and_then` and `map` method, which is better instead of a lot of `if let Some`.
close#5530
This PR adds support for handling recursive JSX components, allowing
detect functions like the one below:
```javascript
function ListItem({ depth }) {
return <ListItem depth={depth} />
}
```
Some logic is duplicated with the non-JSX case. But the refactor will be
complicated and affects over-all, so we can make it in another PR.
cc: @DonIsaac @camc314
---------
Co-authored-by: Cam McHenry <camchenry@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
for convenience, I've added a new function called `ancestor_kinds` which loops overall `ancestors` and gets their `AstKind`. this is a common pattern in a couple of places. I also did some somewhat related refactoring to remove places where we were manually calling `AstNode::kind` instead of using `ancestor_kinds` or calling `parent_kind`.
for consistency with the `ancestor_ids` function, this changes it to use the same terminology but make it clear it actually returns the node, not just the ID.
this is pure refactor, no functional changes here.
After transformation, super expressions have moved to unexpected places. This PR replaces super expression to call expression, and then inserts the super methods to the top of the method body.
For example:
Before:
```js
class G {
async method() {
super.foo()
}
}
```
After:
```js
class G {
method() {
var _superprop_getFoo = () => super.foo,
_this = this;
return _asyncToGenerator(function* () {
_superprop_getFoo().call(_this);
})();
}
}```
Support for inferring function name from ObjectPropertyValue's key
For example:
```js
({ foo: async function() {} })
```
After this, we will able to infer `foo` for the object method
Adds some new estree macro directives:
- `#[estree(via = foo::Foo)`: Uses From to convert this struct to foo::Foo before serialization
- `#[estree(add_ts = "foo: string")]`: Adds additional fields to the typescript definitions
Used these to make all different literals estree-compatible.
Follow-on after stack up to #7148.
Split `is_inside_async_generator_function` into 2 functions `yield_is_inside_async_generator_function` and `async_is_inside_async_generator_function`.
There are a couple of differences between `yield` and `await`, which we can leverage to make both these functions simpler:
* `yield` cannot appear at top level (there's no such thing as "top level yield").
* `yield` cannot appear in an arrow function (there's no such thing as a "generator arrow function").
In addition:
* Because each function now handles a specific case, no need to check if function containing `async` is an async function. It must be. Ditto for `yield`.
* Remove the `if ctx.current_scope_flags().is_top()` check. Probably this check costs more than it saves because top level `await` is far less common than `await` within async functions. So this check was optimizing for an uncommon case, at a cost to the common case.
* Add more comments to explain the logic.
This is all quite small optimizations, but I was having difficulty understanding the logic, and found that splitting it up made it clearer (at least for me).
Follow-on after stack up to #7148.
Small optimization. `LabelIdentifier` is `Clone` so we can use `Clone::clone` to clone it, instead of `CloneIn::clone_in`.
The difference is that `clone_in` makes a 2nd copy of the `Atom`'s string in the arena, whereas `clone` creates a new `Atom` referencing the same string. This is an unfortunate shortcoming of `CloneIn` (https://github.com/oxc-project/backlog/issues/96), but the more we can avoid `CloneIn`, the better.
Follow-on after stack up to #7148.
Small optimization. `ArrowFunctionExpression` is 56 bytes, whereas `ArenaBox<ArrowFunctionExpression>` is 8 bytes. So it's preferable to pass the `ArenaBox<ArrowFunctionExpression>` to `transform_arrow_function_expression` and call `unbox` on it there instead of unboxing *before* passing to the function.
Follow-on after stack up to #7148. Remove 2 x `#[allow(clippy::unused_self)]` attrs where that lint isn't triggered because the functions do use their `&self` param.
Follow-on after stack up to #7148. Remove unused `&self` function param. This makes calling this function slightly cheaper, as unused data doesn't get passed to the function.
Follow-on after stack up to #7148. Remove unused `&mut self` function params. This makes calling these functions slightly cheaper, as unused data doesn't get passed to the function.
The scope can be moved or deleted, we need to check whether the scope id is the same as the container's scope id, if not, we need to move the `this_var` to the target scope id.
Part of https://github.com/oxc-project/oxc/pull/7074
In async-to-generator and async-generator-functions plugins, we may need to transform the async arrow function to a regular generator function, now we can reuse the ability of the ArrowFunction plugin by enabling `ArrowFunctionConverter`.
I will fix semantic errors in the follow-up PR
Add getter and setter methods to all AST types which have a `ScopeId`, `SymbolId` or `ReferenceId` field to get the contents of that field.
Before:
```rs
let symbol_id = ident.symbol_id.get().unwrap();
```
After:
```rs
let symbol_id = ident.symbol_id();
```
This allows removing boilerplate code from the transformer, and discouraging the anti-pattern of treating these fields as if they may contain either `Some` or `None` (after semantic, they will always be `Some`).
Alter `IdentifierReference::reference_id` to return `ReferenceId`, instead of `Option<ReferenceId>`.
This method is only useful on a post-semantic AST, where it will never return `None`. Returning `ReferenceId` discourages the anti-pattern of treating the result as if it could be either `Some` or `None`, and shortens code.
Part of #7074
In order can reuse the ability of the `ArrowFunction` plugin, we moved out the implementation to common, then we can use use in other plugins
Follow-on after #7105.
Correctly identify when a function is a method definition. `ctx.parent().is_method_definition()` would return `true` for this weird case where the function is the property key of the method, not the method itself:
```js
class C {
[async function() {}]() {}
}
```
`matches!(ctx.parent(), Ancestor::MethodDefinitionValue(_))` only returns `true` if the function *is* a method definition. Of course, no-one would write such ridiculous code, but we may as well handle whatever is thrown at us.
It's also slightly more performant to check for one specific ancestor type, rather than:
c2802e63fc/crates/oxc_traverse/src/generated/ancestor.rs (L1319-L1326)
Part of #7074
We need to handle this before the `arrow_function` plugin inserts `_this = this` because, in the `async-to-generator` plugin, we will move the body to an inner generator function. However, we don't want `_this = this` moved to the inner generator function as well. So as long as we move first, and then insert, we can fix this problem.
The new semantic error is related to another tricky problem, I will fix it in another PR
Preparation for #7073. Avoid using `AstBuilder::*_from_*` methods to construct enums, use explicit construction instead.
Before:
```rs
let ident = self.ast.binding_pattern_kind_from_binding_identifier(ident);
```
After:
```rs
let ident = BindingPatternKind::BindingIdentifier(ident);
```
Often this produces shorter code, as well as (in my opinion) being easier to read.
Preparation for #7073. Avoid using `AstBuilder::*_from_*` methods to construct enums, use explicit construction instead.
Before:
```rs
let ident = self.ast.binding_pattern_kind_from_binding_identifier(ident);
```
After:
```rs
let ident = BindingPatternKind::BindingIdentifier(ident);
```
Often this produces shorter code, as well as (in my opinion) being easier to read.
Preparation for #7073. Avoid using `AstBuilder::*_from_*` methods to construct enums, use explicit construction instead.
Before:
```rs
let ident = self.ast.binding_pattern_kind_from_binding_identifier(ident);
```
After:
```rs
let ident = BindingPatternKind::BindingIdentifier(ident);
```
Often this produces shorter code, as well as (in my opinion) being easier to read.
Preparation for #7073. Avoid using `AstBuilder::*_from_*` methods to construct enums, use explicit construction instead.
Before:
```rs
let ident = self.ast.binding_pattern_kind_from_binding_identifier(ident);
```
After:
```rs
let ident = BindingPatternKind::BindingIdentifier(ident);
```
Often this produces shorter code, as well as (in my opinion) being easier to read.
Preparation for #7073. Avoid using `AstBuilder::*_from_*` methods to construct enums, use explicit construction instead.
Before:
```rs
let ident = self.ast.binding_pattern_kind_from_binding_identifier(ident);
```
After:
```rs
let ident = BindingPatternKind::BindingIdentifier(ident);
```
Often this produces shorter code, as well as (in my opinion) being easier to read.
Pure refactor. Introduce `ParserImpl::alloc` method. Shorten `self.ast.alloc(...)` to `self.alloc(...)`.
Also reduce `alloc` calls by using `AstBuilder` methods which already allocate where possible.
Similar to #7055.
In transformer, use `AstBuilder::identifier_reference_with_reference_id` function, instead of creating an `IdentifierReference` and then setting the `reference_id` on it afterwards.
In transformer, use `AstBuilder::function_with_scope_id` and `AstBuilder::arrow_function_expression_with_scope_id` function where possible, rather than creating a function and then setting the `scope_id` on it afterwards.
Add ability for `VarDeclarations` to insert `let` declarations as well as `var` declarations. This is required for class properties transform.
Implementation note: `var` and `let` declarators are stored in 2 separate `ArenaVec`s. This allows using those `ArenaVec<Declarator<'a>>`s directly in the AST, rather storing all `Declarator`s in a single `Vec` and having to loop through it when inserting the `var` / `let` statements to split it into 2 `ArenaVec`s of `var` / `let` declarators. I'm not completely sure this is better than using a single `Vec` for both, but I think *probably* it is.
- closes https://github.com/oxc-project/oxc/issues/6988
we now return an error exit code when there are unmatched rules. previously, we would print an error to stderr and continue running. however, this masked errors in some tests that actually had unmatched rules in them. these test cases now trigger a panic (in tests only, not at runtime), and help ensure that we are reporting an error message to the user for unknown rules, which we did not have any tests cases for before.
- fixes https://github.com/oxc-project/oxc/issues/7025
this also fixes https://github.com/oxc-project/oxc/issues/7025, where we were reporting rules as unmatched simply because they had been disabled prior to being configured. similar to https://github.com/oxc-project/oxc/issues/7009.
Passed 15/19 tests. The remaining 4 failed tests related to `this` expression, the problem same as I mentioned in #6658. I will fix them in follow-up PRs.
This is a work towards https://github.com/oxc-project/oxc/issues/6982
Next PR will try and make sense of env options vs babel options vs targets and bugfixes, I'm super confused right now.
fixes https://github.com/oxc-project/oxc/issues/7009
allows rules to be replaced properly when the `rules_for_override` array is empty (e.g., if you initially disable all rules, then configure them) by checking the `all_rules` array if the first `find` call fails
The `AsyncGeneratorExecutor` contains many transform methods which both can used in `async-to-generator` and `async-generator-functions` plugins, because their implementations are almost the same. I am still not sure where is the best place to place it.
Pure refactor. Moves plugin settings from linter options (which control the linter's behavior on a global level) and linter config ("which may or may not get adjusted on each file).
Fixes a case where no-unused-vars incorectly reports a read as unused in edge
cases where a logical/binary expression is used as a conditional shorthand to
write a variable within sequence expressions.
Some code examples will make this more clear.
```js
function foo(a) {
let x = somePropertyIWantToCheck();
(x in a && x.hasPropA = true, console.log(a))
}
```
Since the logical expression is not in the last position within the sequence
expression list, it's getting discarded as unused. However, the right expression
(`x.hasPropA = true`) has side effects, so it _is_ being used.
Adds a new performance rule that disallows using object and array spreads in `map` and `flatMap` to modify/merge arrays and objects.
I've currently added it to `nursery` so we can battle-harden it before making it generally available as a `perf` rule.
```ts
// needless O(n) spread on `x`, making this an O(n^2) operation
const x = arr.map(x => {
return { ...x, foo: getFoo(x.id) }
})
// Object.assign is better here
const x = arr.map(x => {
return Object.assign(x, { foo: getFoo(x.id) })
})
```
Reduce `Comment` from 20 bytes to 16. Because `Comment` has `#[ast]` attr, it's `#[repr(C)]` which means the fields don't get re-ordered by the compiler, so it contains excess padding. Moving `attached_to: u32` field removes the padding.
I am in favour of using `oxc_ast_tools` to re-order fields the same way the compiler does, which will solve this problem for all AST types. But may as well fix this one in meantime. Unlike most AST types, field order doesn't matter for `Comment` - it is not visited, so the field order has no semantic meaning.
1. Reduce the amount of code in `define_derive!` and `define_generator!` macros. This makes the code easier to read, and gives type hints in IDE.
2. Remove `generated_header!` macro and insert header as a blanket action, instead of repeated code in every generator.
closes#6865
TypeScript plugin changes import / export statements so it needs to be turned off for non-typescript files. This should also give a little performance boost for non-typescript files.
`StatementInjectorStore::insert_before` etc take any `GetAddress`. This allows using them with an `Ancestor` as well as a `Statement`.
Split the implementation of each function into 2 parts - generic outer wrapper and non-generic inner function to allow compiler to make better inlining decisions, and reduced compile time.
In this PR, most of the async functions have transformed correctly. But the async arrow functions don't fully transform correctly yet, it is related to we need to transform the arrow function to the generator function. For example:
Input:
```js
function declaration() {
const asy = async () => {
console.log(this.name)
}
}
```
Output:
```js
function declaration() {
const asy = babelHelpers.asyncToGenerator(function* () {
console.log(this.name);
});
}
```
Expected Output:
```js
function declaration() {
var _this = this;
const asy = /*#__PURE__*/function () {
var _ref = babelHelpers.asyncToGenerator(function* () {
console.log(_this.name);
});
return function asy() {
return _ref.apply(this, arguments);
};
}();
}
```
From the expected output, we haven't handled `this` correctly, which means even if the `arrow-function` plugin doesn't enable, we still need to handle this correctly as the `arrow-function` plugin does, and further question if `arrow-function` plugin is enabled, how to avoid these making conflict?
I thought we may move out the implementation of `arrow-function` and as a common helper, this way every plugin can handle this well
Closes#6358
@preyneyv I know you've been working on this problem.
This is an implementation that has been dormant on my local for a while.
- All tests are passing
- However, the approach is simple but not general, so there might be some edge cases that were missed
- There's also room for improvement in terms of performance
For these reasons, it was marked as WIP for me.
I believe the test cases and other parts are usable, so feel free to fork and replace them with your implementation if you'd like.
> Closes#6750
Fixes a false positive in `react/iframe-missing-sandbox` on `document.createElement`, which is not react and has no way of passing a sandbox prop/attribute on creation.
- Added TypeScript annotation for `ParseResult.program`
- Modified the entrypoint for `oxc-parser` to allow wrapping the napi functions
- Updated `index.js` to parse the `program` string into a JSON object
- Updated tests
- Added a dependency on `@oxc/types`
This makes the use of `Address` an internal implementation detail of `StatementInjectorStore`. The caller shouldn't need to care about how `StatementInjectorStore` achieves its work. In future it might use `NodeId`, for instance.
We could broaden this in future so these methods take a `&A where A: GetAddress` if we need to, but for now taking a `&Statement` seems OK.
Follow-up after #6830.
Now that `generate_binding` doesn't need access to `AstBuilder`, it can move into `TraverseScoping`.
Occasionally this is helpful when you need to borrows 2 parts of `TraverseCtx` simultaneously. e.g.:
```rs
// This fails to compile because we try to mutably borrow `TraverseCtx`
// while it's already borrowed
if let Ancestor::ProgramBody(body) = ctx.parent() {
// ^^^ immutable borrow
let binding = ctx.generate_binding(name, scope_id, flags);
// ^^^ mutable borrow
}
// Borrow-checker allows this because we borrow fields of `TraverseCtx` separately
if let Ancestor::ProgramBody(body) = ctx.ancestry.parent() {
let binding = ctx.scoping.generate_binding(name, scope_id, flags);
}
```