@@ -1125,6 +1125,135 @@ impl ESTree for ExpressionStatementDirective<'_, '_> {
11251125 }
11261126}
11271127
1128+ /// Converter for `TSModuleDeclaration`.
1129+ ///
1130+ /// Our AST represents `module X.Y.Z {}` as 3 x nested `TSModuleDeclaration`s.
1131+ /// TS-ESTree represents it as a single `TSModuleDeclaration`,
1132+ /// with a nested tree of `TSQualifiedName`s as `id`.
1133+ #[ ast_meta]
1134+ #[ estree( raw_deser = "
1135+ const kind = DESER[TSModuleDeclarationKind](POS_OFFSET.kind),
1136+ global = kind === 'global',
1137+ start = DESER[u32](POS_OFFSET.span.start),
1138+ end = DESER[u32](POS_OFFSET.span.end),
1139+ declare = DESER[bool](POS_OFFSET.declare);
1140+ let id = DESER[TSModuleDeclarationName](POS_OFFSET.id),
1141+ body = DESER[Option<TSModuleDeclarationBody>](POS_OFFSET.body);
1142+
1143+ // Flatten `body`, and nest `id`
1144+ if (body !== null && body.type === 'TSModuleDeclaration') {
1145+ id = {
1146+ type: 'TSQualifiedName',
1147+ start: body.id.start,
1148+ end: id.end,
1149+ left: body.id,
1150+ right: id,
1151+ };
1152+ body = Object.hasOwn(body, 'body') ? body.body : null;
1153+ }
1154+
1155+ // Skip `body` field if `null`
1156+ const node = body === null
1157+ ? { type: 'TSModuleDeclaration', start, end, id, kind, declare, global }
1158+ : { type: 'TSModuleDeclaration', start, end, id, body, kind, declare, global };
1159+ node
1160+ " ) ]
1161+ pub struct TSModuleDeclarationConverter < ' a , ' b > ( pub & ' b TSModuleDeclaration < ' a > ) ;
1162+
1163+ impl ESTree for TSModuleDeclarationConverter < ' _ , ' _ > {
1164+ fn serialize < S : Serializer > ( & self , serializer : S ) {
1165+ let module = self . 0 ;
1166+
1167+ let mut state = serializer. serialize_struct ( ) ;
1168+ state. serialize_field ( "type" , & JsonSafeString ( "TSModuleDeclaration" ) ) ;
1169+ state. serialize_field ( "start" , & module. span . start ) ;
1170+ state. serialize_field ( "end" , & module. span . end ) ;
1171+
1172+ match & module. body {
1173+ Some ( TSModuleDeclarationBody :: TSModuleDeclaration ( inner_module) ) => {
1174+ // Nested modules e.g. `module X.Y.Z {}`.
1175+ // Collect all IDs in a `Vec`, in order they appear (i.e. [`X`, `Y`, `Z`]).
1176+ // Also get the inner `TSModuleBlock`.
1177+ let mut parts = Vec :: with_capacity ( 4 ) ;
1178+
1179+ let TSModuleDeclarationName :: Identifier ( id) = & module. id else { unreachable ! ( ) } ;
1180+ parts. push ( id) ;
1181+
1182+ let mut body = None ;
1183+ let mut inner_module = inner_module. as_ref ( ) ;
1184+ loop {
1185+ let TSModuleDeclarationName :: Identifier ( id) = & inner_module. id else {
1186+ unreachable ! ( )
1187+ } ;
1188+ parts. push ( id) ;
1189+
1190+ match & inner_module. body {
1191+ Some ( TSModuleDeclarationBody :: TSModuleDeclaration ( inner_inner_module) ) => {
1192+ inner_module = inner_inner_module. as_ref ( ) ;
1193+ }
1194+ Some ( TSModuleDeclarationBody :: TSModuleBlock ( block) ) => {
1195+ body = Some ( block. as_ref ( ) ) ;
1196+ break ;
1197+ }
1198+ None => break ,
1199+ }
1200+ }
1201+
1202+ // Serialize `parts` as a nested tree of `TSQualifiedName`s
1203+ state. serialize_field ( "id" , & TSModuleDeclarationIdParts ( & parts) ) ;
1204+
1205+ // Skip `body` field if it's `None`
1206+ if let Some ( body) = body {
1207+ state. serialize_field ( "body" , body) ;
1208+ }
1209+ }
1210+ Some ( TSModuleDeclarationBody :: TSModuleBlock ( block) ) => {
1211+ // No nested modules.
1212+ // Serialize as usual, with `id` being either a `BindingIdentifier` or `StringLiteral`.
1213+ state. serialize_field ( "id" , & module. id ) ;
1214+ state. serialize_field ( "body" , block) ;
1215+ }
1216+ None => {
1217+ // No body. Skip `body` field.
1218+ state. serialize_field ( "id" , & module. id ) ;
1219+ }
1220+ }
1221+
1222+ state. serialize_field ( "kind" , & module. kind ) ;
1223+ state. serialize_field ( "declare" , & module. declare ) ;
1224+ state. serialize_field ( "global" , & crate :: serialize:: TSModuleDeclarationGlobal ( module) ) ;
1225+ state. end ( ) ;
1226+ }
1227+ }
1228+
1229+ struct TSModuleDeclarationIdParts < ' a , ' b > ( & ' b [ & ' b BindingIdentifier < ' a > ] ) ;
1230+
1231+ impl ESTree for TSModuleDeclarationIdParts < ' _ , ' _ > {
1232+ fn serialize < S : Serializer > ( & self , serializer : S ) {
1233+ let parts = self . 0 ;
1234+ assert ! ( !parts. is_empty( ) ) ;
1235+
1236+ let span_start = parts[ 0 ] . span . start ;
1237+ let ( & last, rest) = parts. split_last ( ) . unwrap ( ) ;
1238+
1239+ let mut state = serializer. serialize_struct ( ) ;
1240+ state. serialize_field ( "type" , & JsonSafeString ( "TSQualifiedName" ) ) ;
1241+ state. serialize_field ( "start" , & span_start) ;
1242+ state. serialize_field ( "end" , & last. span . end ) ;
1243+
1244+ if rest. len ( ) == 1 {
1245+ // Only one part remaining (e.g. `X`). Serialize as `Identifier`.
1246+ state. serialize_field ( "left" , & rest[ 0 ] ) ;
1247+ } else {
1248+ // Multiple parts remaining (e.g. `X.Y`). Recurse to serialize as `TSQualifiedName`.
1249+ state. serialize_field ( "left" , & TSModuleDeclarationIdParts ( rest) ) ;
1250+ }
1251+
1252+ state. serialize_field ( "right" , last) ;
1253+ state. end ( ) ;
1254+ }
1255+ }
1256+
11281257/// Serializer for `global` field of `TSModuleDeclaration`.
11291258#[ ast_meta]
11301259#[ estree( ts_type = "boolean" , raw_deser = "THIS.kind === 'global'" ) ]
0 commit comments