Skip to content

Commit e643258

Browse files
authored
fix(transform): correct chained optional expression (#17)
input ```js a ?. b . c a ?. b . c ( ) a ?. b ( ) . c a ?. b ( ) . c ( ) ``` before ```json5 { type: "MemberExpression" } { type: "CallExpression" } { type: "MemberExpression" } { type: "CallExpression" } ``` after ```json5 { type: "OptionalMemberExpression" } { type: "OptionalCallExpression" } { type: "OptionalMemberExpression" } { type: "OptionalCallExpression" } ```
1 parent fe241a0 commit e643258

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

src/transform.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ export const transform = (node: InputNode, context: Context): OutputNode => {
184184
);
185185
} else {
186186
const object = _t<b.Expression>(receiver);
187+
const isObjectOptionalExpression =
188+
object.type === 'OptionalMemberExpression' ||
189+
object.type === 'OptionalCallExpression';
187190
const propertyStart = _findBackChar(
188191
/\S/,
189192
_findBackChar(/\./, object.end) + 1,
@@ -196,15 +199,24 @@ export const transform = (node: InputNode, context: Context): OutputNode => {
196199
callExpression.callee = _c<
197200
b.MemberExpression | b.OptionalMemberExpression
198201
>(
199-
isOptional ? 'OptionalMemberExpression' : 'MemberExpression',
202+
isOptional || isObjectOptionalExpression
203+
? 'OptionalMemberExpression'
204+
: 'MemberExpression',
200205
{
201206
computed: false,
202207
object,
203208
property,
204-
...(isOptional && { optional: true }),
209+
...(isOptional
210+
? { optional: true }
211+
: isObjectOptionalExpression
212+
? { optional: false }
213+
: null),
205214
},
206215
{ start: object.start, end: property.end },
207216
);
217+
if (callExpression.callee.type === 'OptionalMemberExpression') {
218+
callExpression.type = 'OptionalCallExpression';
219+
}
208220
}
209221
return callExpression;
210222
}
@@ -239,13 +251,26 @@ export const transform = (node: InputNode, context: Context): OutputNode => {
239251
),
240252
});
241253
}
254+
const object = _t<b.Expression>(receiver);
255+
const isObjectOptionalExpression =
256+
object.type === 'OptionalMemberExpression' ||
257+
object.type === 'OptionalCallExpression';
242258
const memberExpression = _c<
243259
b.MemberExpression | b.OptionalMemberExpression
244-
>(isOptional ? 'OptionalMemberExpression' : 'MemberExpression', {
245-
computed: false,
246-
object: _t<b.Expression>(receiver),
247-
...(isOptional && { optional: true }),
248-
});
260+
>(
261+
isOptional || isObjectOptionalExpression
262+
? 'OptionalMemberExpression'
263+
: 'MemberExpression',
264+
{
265+
computed: false,
266+
object,
267+
...(isOptional
268+
? { optional: true }
269+
: isObjectOptionalExpression
270+
? { optional: false }
271+
: null),
272+
},
273+
);
249274
memberExpression.property = _c<b.Identifier>(
250275
'Identifier',
251276
{ name },

tests/trasnform.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,17 @@ describe.each`
4444
${'LiteralPrimitive'} | ${'StringLiteral'} | ${' "hello" '} | ${true} | ${true} | ${true} | ${true}
4545
${'MethodCall'} | ${'CallExpression'} | ${' a . b ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
4646
${'MethodCall'} | ${'CallExpression'} | ${' a ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
47+
${'MethodCall'} | ${'OptionalCallExpression'} | ${' a ?. b . c ( ) '} | ${true} | ${true} | ${true} | ${true}
48+
${'MethodCall'} | ${'OptionalCallExpression'} | ${' a ?. b ( ) . c ( ) '} | ${true} | ${true} | ${true} | ${true}
4749
${'NonNullAssert'} | ${'TSNonNullExpression'} | ${' x ! '} | ${true} | ${true} | ${true} | ${true}
4850
${'PrefixNot'} | ${'UnaryExpression'} | ${' ! x '} | ${true} | ${true} | ${true} | ${true}
4951
${'PropertyRead'} | ${'Identifier'} | ${' ( ( a ) ) '} | ${true} | ${true} | ${true} | ${true}
5052
${'PropertyRead'} | ${'Identifier'} | ${' a '} | ${true} | ${true} | ${true} | ${true}
5153
${'PropertyRead'} | ${'Identifier'} | ${' a // hello '} | ${true} | ${true} | ${true} | ${true}
5254
${'PropertyRead'} | ${'MemberExpression'} | ${' a . b '} | ${true} | ${true} | ${true} | ${true}
5355
${'PropertyRead'} | ${'MemberExpression'} | ${' this . a '} | ${true} | ${true} | ${true} | ${true}
56+
${'PropertyRead'} | ${'OptionalMemberExpression'} | ${' a ?. b . c '} | ${true} | ${true} | ${true} | ${true}
57+
${'PropertyRead'} | ${'OptionalMemberExpression'} | ${' a ?. b ( ) . c '} | ${true} | ${true} | ${true} | ${true}
5458
${'PropertyWrite'} | ${'AssignmentExpression'} | ${' a . b = 1 '} | ${true} | ${false} | ${false} | ${false}
5559
${'PropertyWrite'} | ${'AssignmentExpression'} | ${' a = 1 '} | ${true} | ${false} | ${false} | ${false}
5660
${'Quote'} | ${'NGQuotedExpression'} | ${' javascript : void(0) '} | ${false} | ${true} | ${true} | ${false}

0 commit comments

Comments
 (0)