Skip to content
19 changes: 16 additions & 3 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1679,7 +1679,7 @@ pub struct BindingRestElement<'a> {
// https://github.com/estree/estree/blob/master/es5.md#patterns
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/cd61c555bfc93e985b313263a42ed78074570d08/types/estree/index.d.ts#L411
#[estree(
add_ts_def = "type ParamPattern = FormalParameter | FormalParameterRest",
add_ts_def = "type ParamPattern = FormalParameter | TSParameterProperty | FormalParameterRest",
add_fields(expression = False),
field_order(
r#type, span, id, expression, generator, r#async, params, body,
Expand Down Expand Up @@ -1780,7 +1780,7 @@ pub enum FunctionType {
pub struct FormalParameters<'a> {
pub span: Span,
pub kind: FormalParameterKind,
#[estree(ts_type = "Array<FormalParameter | FormalParameterRest>")]
#[estree(ts_type = "Array<FormalParameter | TSParameterProperty | FormalParameterRest>")]
pub items: Vec<'a, FormalParameter<'a>>,
#[estree(skip)]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
Expand All @@ -1791,7 +1791,20 @@ pub struct FormalParameters<'a> {
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
// Pluralize as `FormalParameterList` to avoid naming clash with `FormalParameters`.
#[plural(FormalParameterList)]
#[estree(no_type)]
#[estree(
no_type,
add_ts_def = "
interface TSParameterProperty extends Span {
type: 'TSParameterProperty';
accessibility: TSAccessibility | null;
decorators: Array<Decorator>;
override: boolean;
parameter: FormalParameter;
readonly: boolean;
static: boolean;
}
"
)]
pub struct FormalParameter<'a> {
#[estree(skip)]
pub span: Span,
Expand Down
35 changes: 32 additions & 3 deletions crates/oxc_ast/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ impl ESTree for ElisionConverter<'_> {
ts_type = "ParamPattern[]",
raw_deser = "
const params = DESER[Vec<FormalParameter>](POS_OFFSET.items);
// TODO: Serialize items
if (uint32[(POS_OFFSET.rest) >> 2] !== 0 && uint32[(POS_OFFSET.rest + 4) >> 2] !== 0) {
pos = uint32[(POS_OFFSET.rest) >> 2];
params.push({
Expand All @@ -605,7 +606,7 @@ impl ESTree for FormalParametersConverter<'_, '_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut seq = serializer.serialize_sequence();
for item in &self.0.items {
seq.serialize_element(item);
seq.serialize_element(&FormalParameterItem(item));
}

if let Some(rest) = &self.0.rest {
Expand Down Expand Up @@ -634,6 +635,31 @@ impl ESTree for FormalParametersRest<'_, '_> {
}
}

struct FormalParameterItem<'a, 'b>(&'b FormalParameter<'a>);

impl ESTree for FormalParameterItem<'_, '_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let param = self.0;

if S::INCLUDE_TS_FIELDS && param.has_modifier() {
let mut state = serializer.serialize_struct();
state.serialize_field("type", &JsonSafeString("TSParameterProperty"));
state.serialize_field("start", &param.span.start);
state.serialize_field("end", &param.span.end);
state.serialize_field("accessibility", &param.accessibility);
state.serialize_field("decorators", &param.decorators);
state.serialize_field("override", &param.r#override);
state.serialize_field("parameter", &param.pattern);
state.serialize_field("readonly", &param.readonly);
state.serialize_field("static", &False(()));
state.end();
return;
}

param.serialize(serializer);
}
}

/// Serializer for `params` field of `Function`.
///
/// In TS-ESTree, this adds `this_param` to start of the `params` array.
Expand All @@ -646,6 +672,7 @@ impl ESTree for FormalParametersRest<'_, '_> {
const thisParam = DESER[Option<Box<TSThisParameter>>](POS_OFFSET.this_param)
if (thisParam !== null) params.unshift(thisParam);
/* END_IF_TS */
// TODO: Serialize items, rest
params
"
)]
Expand All @@ -662,7 +689,7 @@ impl ESTree for FunctionFormalParameters<'_, '_> {
}

for item in &self.0.params.items {
seq.serialize_element(item);
seq.serialize_element(&FormalParameterItem(item));
}

if let Some(rest) = &self.0.params.rest {
Expand Down Expand Up @@ -1146,6 +1173,7 @@ impl ESTree for TSCallSignatureDeclarationFormalParameters<'_, '_> {
const params = DESER[Box<FormalParameters>](POS_OFFSET.params);
const thisParam = DESER[Option<Box<TSThisParameter>>](POS_OFFSET.this_param)
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
params
"
)]
Expand All @@ -1168,6 +1196,7 @@ impl ESTree for TSMethodSignatureFormalParameters<'_, '_> {
const params = DESER[Box<FormalParameters>](POS_OFFSET.params);
const thisParam = DESER[Option<Box<TSThisParameter>>](POS_OFFSET.this_param)
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
params
"
)]
Expand Down Expand Up @@ -1196,7 +1225,7 @@ fn serialize_formal_params_with_this_param<'a, S: Serializer>(
}

for item in &params.items {
seq.serialize_element(item);
seq.serialize_element(&FormalParameterItem(item));
}

if let Some(rest) = &params.rest {
Expand Down
4 changes: 4 additions & 0 deletions napi/parser/deserialize-js.js
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ function deserializeBindingRestElement(pos) {

function deserializeFunction(pos) {
const params = deserializeBoxFormalParameters(pos + 72);
// TODO: Serialize items, rest
return {
type: deserializeFunctionType(pos + 8),
start: deserializeU32(pos),
Expand All @@ -775,6 +776,7 @@ function deserializeFunction(pos) {

function deserializeFormalParameters(pos) {
const params = deserializeVecFormalParameter(pos + 16);
// TODO: Serialize items
if (uint32[(pos + 48) >> 2] !== 0 && uint32[(pos + 52) >> 2] !== 0) {
pos = uint32[(pos + 48) >> 2];
params.push({
Expand Down Expand Up @@ -1701,6 +1703,7 @@ function deserializeTSMethodSignature(pos) {
const params = deserializeBoxFormalParameters(pos + 48);
const thisParam = deserializeOptionBoxTSThisParameter(pos + 40);
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
return {
type: 'TSMethodSignature',
start: deserializeU32(pos),
Expand Down Expand Up @@ -1831,6 +1834,7 @@ function deserializeTSFunctionType(pos) {
const params = deserializeBoxFormalParameters(pos + 24);
const thisParam = deserializeOptionBoxTSThisParameter(pos + 16);
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
return {
type: 'TSFunctionType',
start: deserializeU32(pos),
Expand Down
4 changes: 4 additions & 0 deletions napi/parser/deserialize-ts.js
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,7 @@ function deserializeFunction(pos) {
const params = deserializeBoxFormalParameters(pos + 72);
const thisParam = deserializeOptionBoxTSThisParameter(pos + 64);
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
return {
type: deserializeFunctionType(pos + 8),
start: deserializeU32(pos),
Expand All @@ -849,6 +850,7 @@ function deserializeFunction(pos) {

function deserializeFormalParameters(pos) {
const params = deserializeVecFormalParameter(pos + 16);
// TODO: Serialize items
if (uint32[(pos + 48) >> 2] !== 0 && uint32[(pos + 52) >> 2] !== 0) {
pos = uint32[(pos + 48) >> 2];
params.push({
Expand Down Expand Up @@ -1828,6 +1830,7 @@ function deserializeTSMethodSignature(pos) {
const params = deserializeBoxFormalParameters(pos + 48);
const thisParam = deserializeOptionBoxTSThisParameter(pos + 40);
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
return {
type: 'TSMethodSignature',
start: deserializeU32(pos),
Expand Down Expand Up @@ -1958,6 +1961,7 @@ function deserializeTSFunctionType(pos) {
const params = deserializeBoxFormalParameters(pos + 24);
const thisParam = deserializeOptionBoxTSThisParameter(pos + 16);
if (thisParam !== null) params.unshift(thisParam);
// TODO: Serialize items, rest
return {
type: 'TSFunctionType',
start: deserializeU32(pos),
Expand Down
12 changes: 11 additions & 1 deletion npm/oxc-types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ export interface Function extends Span {
returnType?: TSTypeAnnotation | null;
}

export type ParamPattern = FormalParameter | FormalParameterRest;
export type ParamPattern = FormalParameter | TSParameterProperty | FormalParameterRest;

export type FunctionType =
| 'FunctionDeclaration'
Expand All @@ -608,6 +608,16 @@ export type FormalParameter =
})
& BindingPattern;

export interface TSParameterProperty extends Span {
type: 'TSParameterProperty';
accessibility: TSAccessibility | null;
decorators: Array<Decorator>;
override: boolean;
parameter: FormalParameter;
readonly: boolean;
static: boolean;
}

export interface FunctionBody extends Span {
type: 'BlockStatement';
body: Array<Directive | Statement>;
Expand Down
Loading
Loading