Skip to content

Commit 2520b25

Browse files
leaysgurautofix-ci[bot]overlookmotel
authored
fix(estree): Align TSMappedType fields (#10392)
Part of #9705 In this PR, I've tried to align `TSMappedType` with TS-ESLint. > https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/ast-spec/src/type/TSMappedType/spec.ts ```js // BEFORE { type: "TSMappedType", typeParameter: { name: Identifier, constraint: TypeNode, }, // ... } // AFTER { type: "TSMappedType", key: Identifier, constraint: TypeNode, // ... } ``` And also fixed serializer for `optional` and `readonly` types. They are defined as `boolean | '+' | '-' | undefined`, but we use `true | '+' | '-' | null`. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
1 parent 50fd839 commit 2520b25

File tree

7 files changed

+73
-298
lines changed

7 files changed

+73
-298
lines changed

crates/oxc_ast/src/ast/ts.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,9 +1412,11 @@ pub struct TSConstructorType<'a> {
14121412
#[scope]
14131413
#[derive(Debug)]
14141414
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
1415+
#[estree(add_fields(key = TSMappedTypeKey, constraint = TSMappedTypeConstraint))]
14151416
pub struct TSMappedType<'a> {
14161417
pub span: Span,
14171418
/// Key type parameter, e.g. `P` in `[P in keyof T]`.
1419+
#[estree(skip)]
14181420
pub type_parameter: Box<'a, TSTypeParameter<'a>>,
14191421
pub name_type: Option<TSType<'a>>,
14201422
pub type_annotation: Option<TSType<'a>>,
@@ -1448,14 +1450,13 @@ pub struct TSMappedType<'a> {
14481450
#[ast]
14491451
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14501452
#[generate_derive(CloneIn, Dummy, ContentEq, ESTree)]
1453+
#[estree(via = TSMappedTypeModifierOperatorConverter)]
14511454
pub enum TSMappedTypeModifierOperator {
14521455
/// e.g. `?` in `{ [P in K]?: T }`
14531456
True = 0,
14541457
/// e.g. `+?` in `{ [P in K]+?: T }`
1455-
#[estree(rename = "+")]
14561458
Plus = 1,
14571459
/// e.g. `-?` in `{ [P in K]-?: T }`
1458-
#[estree(rename = "-")]
14591460
Minus = 2,
14601461
/// No modifier present
14611462
None = 3,

crates/oxc_ast/src/generated/derive_estree.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,23 +3159,19 @@ impl ESTree for TSMappedType<'_> {
31593159
state.serialize_field("type", &JsonSafeString("TSMappedType"));
31603160
state.serialize_field("start", &self.span.start);
31613161
state.serialize_field("end", &self.span.end);
3162-
state.serialize_field("typeParameter", &self.type_parameter);
31633162
state.serialize_field("nameType", &self.name_type);
31643163
state.serialize_field("typeAnnotation", &self.type_annotation);
31653164
state.serialize_field("optional", &self.optional);
31663165
state.serialize_field("readonly", &self.readonly);
3166+
state.serialize_field("key", &crate::serialize::TSMappedTypeKey(self));
3167+
state.serialize_field("constraint", &crate::serialize::TSMappedTypeConstraint(self));
31673168
state.end();
31683169
}
31693170
}
31703171

31713172
impl ESTree for TSMappedTypeModifierOperator {
31723173
fn serialize<S: Serializer>(&self, serializer: S) {
3173-
match self {
3174-
Self::True => JsonSafeString("true").serialize(serializer),
3175-
Self::Plus => JsonSafeString("+").serialize(serializer),
3176-
Self::Minus => JsonSafeString("-").serialize(serializer),
3177-
Self::None => JsonSafeString("none").serialize(serializer),
3178-
}
3174+
crate::serialize::TSMappedTypeModifierOperatorConverter(self).serialize(serializer)
31793175
}
31803176
}
31813177

crates/oxc_ast/src/serialize.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,58 @@ impl ESTree for TSModuleDeclarationGlobal<'_, '_> {
10211021
}
10221022
}
10231023

1024+
/// Serializer for `key` and `constraint` field of `TSMappedType`.
1025+
#[ast_meta]
1026+
#[estree(
1027+
ts_type = "TSTypeParameter['name']",
1028+
raw_deser = "
1029+
const typeParameter = DESER[Box<TSTypeParameter>](POS_OFFSET.type_parameter);
1030+
typeParameter.name
1031+
"
1032+
)]
1033+
pub struct TSMappedTypeKey<'a, 'b>(pub &'b TSMappedType<'a>);
1034+
1035+
impl ESTree for TSMappedTypeKey<'_, '_> {
1036+
fn serialize<S: Serializer>(&self, serializer: S) {
1037+
self.0.type_parameter.name.serialize(serializer);
1038+
}
1039+
}
1040+
1041+
// NOTE: Variable `typeParameter` in `raw_deser` is shared between `key` and `constraint` serializers.
1042+
// They will be concatenated in the generated code.
1043+
#[ast_meta]
1044+
#[estree(ts_type = "TSTypeParameter['constraint']", raw_deser = "typeParameter.constraint")]
1045+
pub struct TSMappedTypeConstraint<'a, 'b>(pub &'b TSMappedType<'a>);
1046+
1047+
impl ESTree for TSMappedTypeConstraint<'_, '_> {
1048+
fn serialize<S: Serializer>(&self, serializer: S) {
1049+
self.0.type_parameter.constraint.serialize(serializer);
1050+
}
1051+
}
1052+
1053+
#[ast_meta]
1054+
#[estree(
1055+
ts_type = "true | '+' | '-' | null",
1056+
raw_deser = "
1057+
const operator = DESER[u8](POS);
1058+
[true, '+', '-', null][operator]
1059+
"
1060+
)]
1061+
pub struct TSMappedTypeModifierOperatorConverter<'a>(pub &'a TSMappedTypeModifierOperator);
1062+
1063+
impl ESTree for TSMappedTypeModifierOperatorConverter<'_> {
1064+
fn serialize<S: Serializer>(&self, serializer: S) {
1065+
match self.0 {
1066+
TSMappedTypeModifierOperator::True => true.serialize(serializer),
1067+
TSMappedTypeModifierOperator::Plus => JsonSafeString("+").serialize(serializer),
1068+
TSMappedTypeModifierOperator::Minus => JsonSafeString("-").serialize(serializer),
1069+
// This is typed as `undefined` (= key is not present) in TS-ESTree.
1070+
// But we serialize it as `null` to align result in snapshot tests.
1071+
TSMappedTypeModifierOperator::None => Null(()).serialize(serializer),
1072+
}
1073+
}
1074+
}
1075+
10241076
// --------------------
10251077
// Comments
10261078
// --------------------

napi/parser/deserialize-js.js

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,15 +1844,17 @@ function deserializeTSConstructorType(pos) {
18441844
}
18451845

18461846
function deserializeTSMappedType(pos) {
1847+
const typeParameter = deserializeBoxTSTypeParameter(pos + 8);
18471848
return {
18481849
type: 'TSMappedType',
18491850
start: deserializeU32(pos),
18501851
end: deserializeU32(pos + 4),
1851-
typeParameter: deserializeBoxTSTypeParameter(pos + 8),
18521852
nameType: deserializeOptionTSType(pos + 16),
18531853
typeAnnotation: deserializeOptionTSType(pos + 32),
18541854
optional: deserializeTSMappedTypeModifierOperator(pos + 48),
18551855
readonly: deserializeTSMappedTypeModifierOperator(pos + 49),
1856+
key: typeParameter.name,
1857+
constraint: typeParameter.constraint,
18561858
};
18571859
}
18581860

@@ -3882,18 +3884,8 @@ function deserializeTSTypeQueryExprName(pos) {
38823884
}
38833885

38843886
function deserializeTSMappedTypeModifierOperator(pos) {
3885-
switch (uint8[pos]) {
3886-
case 0:
3887-
return 'true';
3888-
case 1:
3889-
return '+';
3890-
case 2:
3891-
return '-';
3892-
case 3:
3893-
return 'none';
3894-
default:
3895-
throw new Error(`Unexpected discriminant ${uint8[pos]} for TSMappedTypeModifierOperator`);
3896-
}
3887+
const operator = deserializeU8(pos);
3888+
return [true, '+', '-', null][operator];
38973889
}
38983890

38993891
function deserializeTSModuleReference(pos) {

napi/parser/deserialize-ts.js

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,15 +1920,17 @@ function deserializeTSConstructorType(pos) {
19201920
}
19211921

19221922
function deserializeTSMappedType(pos) {
1923+
const typeParameter = deserializeBoxTSTypeParameter(pos + 8);
19231924
return {
19241925
type: 'TSMappedType',
19251926
start: deserializeU32(pos),
19261927
end: deserializeU32(pos + 4),
1927-
typeParameter: deserializeBoxTSTypeParameter(pos + 8),
19281928
nameType: deserializeOptionTSType(pos + 16),
19291929
typeAnnotation: deserializeOptionTSType(pos + 32),
19301930
optional: deserializeTSMappedTypeModifierOperator(pos + 48),
19311931
readonly: deserializeTSMappedTypeModifierOperator(pos + 49),
1932+
key: typeParameter.name,
1933+
constraint: typeParameter.constraint,
19321934
};
19331935
}
19341936

@@ -3958,18 +3960,8 @@ function deserializeTSTypeQueryExprName(pos) {
39583960
}
39593961

39603962
function deserializeTSMappedTypeModifierOperator(pos) {
3961-
switch (uint8[pos]) {
3962-
case 0:
3963-
return 'true';
3964-
case 1:
3965-
return '+';
3966-
case 2:
3967-
return '-';
3968-
case 3:
3969-
return 'none';
3970-
default:
3971-
throw new Error(`Unexpected discriminant ${uint8[pos]} for TSMappedTypeModifierOperator`);
3972-
}
3963+
const operator = deserializeU8(pos);
3964+
return [true, '+', '-', null][operator];
39733965
}
39743966

39753967
function deserializeTSModuleReference(pos) {

npm/oxc-types/types.d.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,15 +1344,14 @@ export interface TSConstructorType extends Span {
13441344

13451345
export interface TSMappedType extends Span {
13461346
type: 'TSMappedType';
1347-
typeParameter: TSTypeParameter;
13481347
nameType: TSType | null;
13491348
typeAnnotation: TSType | null;
1350-
optional: TSMappedTypeModifierOperator;
1351-
readonly: TSMappedTypeModifierOperator;
1349+
optional: true | '+' | '-' | null;
1350+
readonly: true | '+' | '-' | null;
1351+
key: TSTypeParameter['name'];
1352+
constraint: TSTypeParameter['constraint'];
13521353
}
13531354

1354-
export type TSMappedTypeModifierOperator = 'true' | '+' | '-' | 'none';
1355-
13561355
export interface TSTemplateLiteralType extends Span {
13571356
type: 'TSTemplateLiteralType';
13581357
quasis: Array<TemplateElement>;

0 commit comments

Comments
 (0)