hypothesis: profiling shows that Regex creation takes a decent amount of time. the `regex` crate uses `aho-corasick` internally for string matching, which is all we need in some cases. in theory, we could save time by using the lib directly and not needing the full regex syntax.
Follow on after #5873.
Rename lifetime. I generally consider `'a` in AST types as short for `'ast`, so using `'ast` to mean something else is confusing. Rename lifetime to `'n` (short for `'nodes`).
`transform_jsx` branches on the type of each attribute, and then passes each attribute to `transform_jsx_attribute_item`, which branches on the type again. Instead, inline the two arms of `transform_jsx_attribute_item` into the match arms of `transform_jsx`.
This does make `transform_jsx` even bigger than it was already. I'll break it up in a later PR.
Look at first: #5864
the only merge conflict for this PR should then be the ts snap file.
If you want, you can also skip the other PR and merge this one directly
:)
- part of https://github.com/oxc-project/oxc/issues/479
This implements the `no-extend-native` rule from the ESLint core
ruleset. This was translated based on the rule source code from the
ESLint codebase. That means some oddity, such as treating any
capitalized identifier (like `Math`) as a global object, is preserved.
So even though `Math.prototype` doesn't exist in reality, we still
report it as an error. This is probably okay given that such code
doesn't make sense anyway.
`SymbolFlags::ArrowFunction` is an oddity, as whether a symbol is an arrow function is not statically knowable. In the following cases, `f` symbol did not have `ArrowFunction` flag set:
```js
const {f} = {f: () => {}};
```
```js
let f = 123;
f = () => {};
```
`SymbolFlags::ArrowFunction` is therefore not particularly useful, and possibly misleading. Having it complicates the transformer, and it's not used anywhere in Oxc.
This PR removes it.
I am unable to print all comments correctly. Comments have way too much semantic meaning in JavaScript.
This PR reduces the scope to only print jsdoc comments that are attached to statements and class elements, in order to get isolated declarations shipped.
Previously it included a newline in the value
```
"hashbang": {
"type": "Hashbang",
"start": 0,
"end": 16,
"value": "/usr/bin/node\n"
},
```
This change will also make the lexer emit a `\n` token, which will make comment position detection correct.
`Codegen::with_source_text` gives us enough information to use `Codegen::with_capacity`. This change makes the API cleaner as users have to provide less redundant information.
Micro-optimization. Rather than `inside_arrow_function_stack` sometimes being run down to empty, initialize it with a single entry which is never popped off. This means that `self.inside_arrow_function_stack.last()` *always* returns `Some` - so the branch is completely predictable.
Push/pop to stacks in matching `enter_*` / `exit_*` visitors.
The reason why there was a bug here is a little bit subtle.
Between `enter_expression` and `exit_expression`, another transform can replace the `Expression` with something else. Ditto `enter_declaration` + `exit_declaration`.
So pushing+popping from stacks in `enter_expression` + `exit_expression` can make the stack get out of sync. e.g.:
```rs
impl<'a> Traverse for TransformerWithStack {
fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: TraverseCtx<'a>) {
if let Expression::FunctionExpression(_) = expr {
self.stack.push(true);
}
}
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: TraverseCtx<'a>) {
if let Expression::FunctionExpression(_) = expr {
self.stack.pop();
}
}
}
// Transformer that replaces `null` with a function expression (!)
impl<'a> Traverse for SomeOtherTransformer {
fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: TraverseCtx<'a>) {
if let Expression::NullLiteral(_) = expr {
*expr = ctx.ast.expression_function( /* ... */ );
}
}
}
```
`TransformerWithStack` is assuming in `exit_expression` that it previously saw a `FunctionExpression` in `enter_expression`. But `SomeOtherTransformer` has created a *new* `FunctionExpression` after `TransformerWithStack::enter_expression` ran. So in `TransformerWithStack`, `exit_expression` is called 1 more time than `enter_expression`. When `exit_expression` calls `self.stack.pop()`, `self.stack` is empty, and it panics.
This example is silly, but real cases of this do exist. e.g. TS transformer creates a new functions when transforming `enum`s.
`enter_function` + `exit_function` / `enter_arrow_function_expression` + `exit_arrow_function_expression` not have this problem. As we cannot mutate upwards, there are always the same number of calls to `enter_*` and `exit_*` (same for all `enter_*` / `exit_*` pairs which operate on a struct, *not an enum*).