Use JSDoc comments in `build.mjs` and related scripts to provide type hints and better intellisense. I was having a hard time knowing what fields are available in different methods, and I found this quite helpful. I'm sure other newcomers to this part of our codegen infrastructure will find it helpful as well.
Closes#5008.
There are no longer any nodes with conditional scopes. Remove support for `#[scope(if(...))]` attr from `oxc_traverse` codegen - it's no longer needed.
Separate out attributes which communicate info to codegen related to scopes into `#[scope]` attr.
Before:
```rs
#[visited_node(scope(ScopeFlags::empty()))]
pub struct BlockStatement<'a> { /* ... */ }
```
After:
```rs
#[visited_node]
#[scope]
pub struct BlockStatement<'a> { /* ... */ }
```
I think this is clearer.
Improve annotation of AST types for codegen.
Currently:
```rs
#[visited_node(
scope(ScopeFlags::empty()),
enter_scope_before(cases),
)]
pub struct SwitchStatement<'a> {
pub span: Span,
pub discriminant: Expression<'a>,
pub cases: Vec<'a, SwitchCase<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
```
After this PR:
```rs
#[visited_node(scope(ScopeFlags::empty()))]
pub struct SwitchStatement<'a> {
pub span: Span,
pub discriminant: Expression<'a>,
#[scope(enter_before)]
pub cases: Vec<'a, SwitchCase<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
```
I think this is easier to read.
In order to enable use of `#[scope]` attr, this introduces a dummy `VisitedNode` derive macro. Like the `visited_node` macro, `VisitedNode` derive macro is designed to do very minimal work and have no heavy dependencies, so it should be almost 0 cost in terms of compile time.
Add scope flags to `TraverseCtx`.
Closes#3189.
`walk_*` functions build a stack of `ScopeFlags` as AST is traversed, and they can be queried from within visitors with `ctx.scope()`, `ctx.ancestor_scope()` and `ctx.find_scope()`.
The codegen which generates `walk_*` functions gets the info about which AST types have scopes, and how to check for strict mode from the `#[visited_node]` attrs on AST type definitions in `oxc_ast`.
A few notes:
Each scope inherits the strict mode flag from the level before it in the stack, so if you need to know "am I in strict mode context here?", `ctx.scope().is_strict_mode()` will tell you - no need to travel back up the stack to find out.
Scopes do *not* inherit any other flags from level before it. So `ctx.scope()` in a block nested in a function will return `ScopeFlags::empty()` not `ScopeFlags::Function`.
I had to add an extra flag `ScopeFlags::Method`. The reason for this is to deal with when a `Function` is actually a `MethodDefinition`, and to avoid creating 2 scopes in this case. The principle I'm trying to follow is to encode as little logic in the codegen as possible, as it's rather hidden away. Instead the codegen follows a standard logic for every node, guided by attributes which are visible next to the types in `oxc_ast`. This hopefully makes how `Traverse`'s visitors are generated less mysterious, and easier to change.
The case of `Function` within `MethodDefinition` is a weird one and would not be possible to implement without encoding a magic "special case" within the codegen without this extra `ScopeFlags::Method` variant. Its existence does not alter the operation of any other code in Oxc which uses `ScopeFlags`.
In my view `ScopeFlags` might benefit from a little bit of an overhaul anyway. I believe we could pack more information into the bits and make it more useful.
First part of #3152.
This adds a crate `oxc_traverse`, but doesn't connect it up to the
transformer or anything else yet.
I think we could merge this now - as it doesn't affect any code that's
in use - and then iterate on it to add scopes before using it in
transformer. Please see
https://github.com/oxc-project/oxc/pull/3152#issuecomment-2094965406 for
the broader picture.