mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-15 06:39:17 +00:00
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
This commit is contained in:
1 parent
6e040e494e
commit
0c68b7ff8b
11 files changed
+12
-15
No files matched your search
@@ -2388,6 +2388,7 @@ function deserializeFormalParameters(pos) {
|
||||
parent: previousParent,
|
||||
});
|
||||
rest.argument = deserializeBindingPattern(pos + 56);
|
||||
rest.decorators = deserializeVecDecorator(pos + 16);
|
||||
rest.typeAnnotation = deserializeOptionBoxTSTypeAnnotation(pos + 72);
|
||||
if (rest.typeAnnotation !== null) {
|
||||
end = rest.typeAnnotation.end;
|
||||
|
||||
+1
-1
@@ -673,7 +673,7 @@ export type FunctionType =
|
||||
export interface FormalParameterRest extends Span {
|
||||
type: "RestElement";
|
||||
argument: BindingPattern;
|
||||
decorators?: [];
|
||||
decorators?: Array<Decorator>;
|
||||
optional?: boolean;
|
||||
typeAnnotation?: TSTypeAnnotation | null;
|
||||
value?: null;
|
||||
|
||||
@@ -1869,7 +1869,7 @@ pub enum FunctionType {
|
||||
interface FormalParameterRest extends Span {
|
||||
type: 'RestElement';
|
||||
argument: BindingPattern;
|
||||
decorators?: [],
|
||||
decorators?: Array<Decorator>;
|
||||
optional?: boolean;
|
||||
typeAnnotation?: TSTypeAnnotation | null;
|
||||
value?: null;
|
||||
|
||||
@@ -379,6 +379,7 @@ impl ESTree for CatchParameterConverter<'_, '_> {
|
||||
};
|
||||
rest.argument = DESER[BindingPattern]( POS_OFFSET<FormalParameterRest>.rest.argument );
|
||||
if (IS_TS) {
|
||||
rest.decorators = DESER[Vec<Decorator>](POS_OFFSET<FormalParameterRest>.decorators);
|
||||
rest.typeAnnotation = DESER[Option<Box<TSTypeAnnotation>>](
|
||||
POS_OFFSET<FormalParameterRest>.type_annotation
|
||||
);
|
||||
@@ -418,7 +419,7 @@ impl ESTree for FormalParameterRest<'_> {
|
||||
let rest = self;
|
||||
let mut state = serializer.serialize_struct();
|
||||
state.serialize_field("type", &JsonSafeString("RestElement"));
|
||||
state.serialize_ts_field("decorators", &EmptyArray(()));
|
||||
state.serialize_ts_field("decorators", &rest.decorators);
|
||||
state.serialize_field("argument", &rest.rest.argument);
|
||||
state.serialize_ts_field("optional", &false);
|
||||
state.serialize_ts_field("typeAnnotation", &rest.type_annotation);
|
||||
|
||||
@@ -1917,6 +1917,7 @@ function deserializeFormalParameters(pos) {
|
||||
end: (end = deserializeI32(pos + 44)),
|
||||
};
|
||||
rest.argument = deserializeBindingPattern(pos + 56);
|
||||
rest.decorators = deserializeVecDecorator(pos + 16);
|
||||
rest.typeAnnotation = deserializeOptionBoxTSTypeAnnotation(pos + 72);
|
||||
if (rest.typeAnnotation !== null) {
|
||||
end = rest.typeAnnotation.end;
|
||||
|
||||
@@ -2121,6 +2121,7 @@ function deserializeFormalParameters(pos) {
|
||||
parent: previousParent,
|
||||
});
|
||||
rest.argument = deserializeBindingPattern(pos + 56);
|
||||
rest.decorators = deserializeVecDecorator(pos + 16);
|
||||
rest.typeAnnotation = deserializeOptionBoxTSTypeAnnotation(pos + 72);
|
||||
if (rest.typeAnnotation !== null) {
|
||||
end = rest.typeAnnotation.end;
|
||||
|
||||
@@ -2124,6 +2124,7 @@ function deserializeFormalParameters(pos) {
|
||||
range: [start, end],
|
||||
};
|
||||
rest.argument = deserializeBindingPattern(pos + 56);
|
||||
rest.decorators = deserializeVecDecorator(pos + 16);
|
||||
rest.typeAnnotation = deserializeOptionBoxTSTypeAnnotation(pos + 72);
|
||||
if (rest.typeAnnotation !== null) {
|
||||
end = rest.typeAnnotation.end;
|
||||
|
||||
@@ -2327,6 +2327,7 @@ function deserializeFormalParameters(pos) {
|
||||
parent: previousParent,
|
||||
});
|
||||
rest.argument = deserializeBindingPattern(pos + 56);
|
||||
rest.decorators = deserializeVecDecorator(pos + 16);
|
||||
rest.typeAnnotation = deserializeOptionBoxTSTypeAnnotation(pos + 72);
|
||||
if (rest.typeAnnotation !== null) {
|
||||
end = rest.typeAnnotation.end;
|
||||
|
||||
Vendored
+1
-1
@@ -666,7 +666,7 @@ export type FunctionType =
|
||||
export interface FormalParameterRest extends Span {
|
||||
type: "RestElement";
|
||||
argument: BindingPattern;
|
||||
decorators?: [];
|
||||
decorators?: Array<Decorator>;
|
||||
optional?: boolean;
|
||||
typeAnnotation?: TSTypeAnnotation | null;
|
||||
value?: null;
|
||||
|
||||
@@ -564,7 +564,6 @@ so that arm can run.
|
||||
- `import "m";` versus `import {} from "m";`
|
||||
- An absent `with` clause versus an empty `with {}`
|
||||
- `assert {...}` versus `with {...}`
|
||||
- A rest parameter's decorators (a deficiency in `oxc-parser`, fixable, not blocked by ESTree spec)
|
||||
|
||||
The conformance harness normalizes the Rust AST down to what ESTree can express before printing,
|
||||
rather than expecting the JS side to reproduce information it was never given.
|
||||
|
||||
@@ -15,8 +15,8 @@ use napi_derive::napi;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::ast::{
|
||||
ArrowFunctionExpression, ExportAllDeclaration, ExportFromDeclaration, FormalParameterRest,
|
||||
Function, ImportDeclaration, WithClauseKeyword,
|
||||
ArrowFunctionExpression, ExportAllDeclaration, ExportFromDeclaration, Function,
|
||||
ImportDeclaration, WithClauseKeyword,
|
||||
};
|
||||
use oxc_ast_visit::{VisitMut, walk_mut};
|
||||
use oxc_codegen::{Codegen, CodegenOptions, CommentOptions};
|
||||
@@ -146,14 +146,6 @@ impl<'a> VisitMut<'a> for Normalize {
|
||||
walk_mut::walk_arrow_function_expression(self, arrow);
|
||||
}
|
||||
|
||||
/// A rest parameter's decorators are `#[estree(skip)]`ped - ESTree types them as
|
||||
/// an always-empty array on `RestElement` - so the JS side never sees them.
|
||||
/// Decorators on the other parameters do come through, and are left alone.
|
||||
fn visit_formal_parameter_rest(&mut self, rest: &mut FormalParameterRest<'a>) {
|
||||
rest.decorators.clear();
|
||||
walk_mut::walk_formal_parameter_rest(self, rest);
|
||||
}
|
||||
|
||||
/// ESTree cannot distinguish `import "m"` from `import {} from "m"` - `specifiers` is `[]` for both.
|
||||
/// It also cannot distinguish an attribute-less import from one with an empty `with {}` clause -
|
||||
/// `attributes` is `[]` for both.
|
||||
|
||||
Reference in new issue
Block a user