@@ -148,18 +148,29 @@ export function transformContextualCallExpression(
148148 node : ts . CallExpression | ts . TaggedTemplateExpression ,
149149 args : ts . Expression [ ] | ts . NodeArray < ts . Expression > ,
150150 signature ?: ts . Signature
151- ) : lua . Expression {
151+ ) : lua . CallExpression | lua . MethodCallExpression {
152152 const left = ts . isCallExpression ( node ) ? node . expression : node . tag ;
153153 if ( ts . isPropertyAccessExpression ( left ) && ts . isIdentifier ( left . name ) && isValidLuaIdentifier ( left . name . text ) ) {
154154 // table:name()
155155 const table = context . transformExpression ( left . expression ) ;
156156
157- return lua . createMethodCallExpression (
158- table ,
159- lua . createIdentifier ( left . name . text , left . name ) ,
160- transformArguments ( context , args , signature ) ,
161- node
162- ) ;
157+ if ( ts . isOptionalChain ( node ) ) {
158+ return transformLuaLibFunction (
159+ context ,
160+ LuaLibFeature . OptionalMethodCall ,
161+ node ,
162+ table ,
163+ lua . createStringLiteral ( left . name . text , left . name ) ,
164+ ...transformArguments ( context , args , signature )
165+ ) ;
166+ } else {
167+ return lua . createMethodCallExpression (
168+ table ,
169+ lua . createIdentifier ( left . name . text , left . name ) ,
170+ transformArguments ( context , args , signature ) ,
171+ node
172+ ) ;
173+ }
163174 } else if ( ts . isElementAccessExpression ( left ) || ts . isPropertyAccessExpression ( left ) ) {
164175 if ( isExpressionWithEvaluationEffect ( left . expression ) ) {
165176 return transformToImmediatelyInvokedFunctionExpression (
@@ -183,7 +194,10 @@ export function transformContextualCallExpression(
183194 }
184195}
185196
186- function transformPropertyCall ( context : TransformationContext , node : PropertyCallExpression ) : lua . Expression {
197+ function transformPropertyCall (
198+ context : TransformationContext ,
199+ node : PropertyCallExpression
200+ ) : lua . CallExpression | lua . MethodCallExpression {
187201 const signature = context . checker . getResolvedSignature ( node ) ;
188202
189203 if ( node . expression . expression . kind === ts . SyntaxKind . SuperKeyword ) {
@@ -197,17 +211,22 @@ function transformPropertyCall(context: TransformationContext, node: PropertyCal
197211 // table:name()
198212 return transformContextualCallExpression ( context , node , node . arguments , signature ) ;
199213 } else {
200- const table = context . transformExpression ( node . expression . expression ) ;
201-
202214 // table.name()
203- const name = node . expression . name . text ;
204- const callPath = lua . createTableIndexExpression ( table , lua . createStringLiteral ( name ) , node . expression ) ;
215+ const callPath = context . transformExpression ( node . expression ) ;
205216 const parameters = transformArguments ( context , node . arguments , signature ) ;
206- return lua . createCallExpression ( callPath , parameters , node ) ;
217+
218+ if ( ts . isOptionalChain ( node ) ) {
219+ return transformLuaLibFunction ( context , LuaLibFeature . OptionalFunctionCall , node , callPath , ...parameters ) ;
220+ } else {
221+ return lua . createCallExpression ( callPath , parameters , node ) ;
222+ }
207223 }
208224}
209225
210- function transformElementCall ( context : TransformationContext , node : ts . CallExpression ) : lua . Expression {
226+ function transformElementCall (
227+ context : TransformationContext ,
228+ node : ts . CallExpression
229+ ) : lua . CallExpression | lua . MethodCallExpression {
211230 const signature = context . checker . getResolvedSignature ( node ) ;
212231 const signatureDeclaration = signature ?. getDeclaration ( ) ;
213232 if ( ! signatureDeclaration || getDeclarationContextType ( context , signatureDeclaration ) !== ContextType . Void ) {
@@ -229,11 +248,12 @@ export const transformCallExpression: FunctionVisitor<ts.CallExpression> = (node
229248 const returnValueIsUsed = node . parent && ! ts . isExpressionStatement ( node . parent ) ;
230249 const wrapTupleReturn =
231250 isTupleReturn && ! isTupleReturnForward && ! isInDestructingAssignment ( node ) && ! isInSpread && returnValueIsUsed ;
232- const wrapResult = wrapTupleReturn || shouldMultiReturnCallBeWrapped ( context , node ) ;
251+ const wrapResultInTable = wrapTupleReturn || shouldMultiReturnCallBeWrapped ( context , node ) ;
252+ const wrapResultInOptional = ts . isOptionalChain ( node ) ;
233253
234254 const builtinResult = transformBuiltinCallExpression ( context , node ) ;
235255 if ( builtinResult ) {
236- return wrapResult ? wrapInTable ( builtinResult ) : builtinResult ;
256+ return wrapResultInTable ? wrapInTable ( builtinResult ) : builtinResult ;
237257 }
238258
239259 if ( isOperatorMapping ( context , node ) ) {
@@ -274,12 +294,13 @@ export const transformCallExpression: FunctionVisitor<ts.CallExpression> = (node
274294 }
275295
276296 const result = transformPropertyCall ( context , node as PropertyCallExpression ) ;
277- return wrapResult ? wrapInTable ( result ) : result ;
297+ // transformPropertyCall already wraps optional so no need to do so here
298+ return wrapResultInTable ? wrapInTable ( result ) : result ;
278299 }
279300
280301 if ( ts . isElementAccessExpression ( node . expression ) ) {
281302 const result = transformElementCall ( context , node ) ;
282- return wrapResult ? wrapInTable ( result ) : result ;
303+ return wrapIfRequired ( context , wrapResultInTable , wrapResultInOptional , result , node ) ;
283304 }
284305
285306 const signature = context . checker . getResolvedSignature ( node ) ;
@@ -309,5 +330,41 @@ export const transformCallExpression: FunctionVisitor<ts.CallExpression> = (node
309330 }
310331
311332 const callExpression = lua . createCallExpression ( callPath , parameters , node ) ;
312- return wrapResult ? wrapInTable ( callExpression ) : callExpression ;
333+ return wrapIfRequired ( context , wrapResultInTable , wrapResultInOptional , callExpression , node ) ;
313334} ;
335+
336+ function wrapIfRequired (
337+ context : TransformationContext ,
338+ shouldWrapInTable : boolean ,
339+ shouldWrapOptional : boolean ,
340+ call : lua . CallExpression | lua . MethodCallExpression ,
341+ node : ts . Node
342+ ) : lua . Expression {
343+ const wrappedOptional = shouldWrapOptional ? wrapOptionalCall ( context , call , node ) : call ;
344+ return shouldWrapInTable ? wrapInTable ( wrappedOptional ) : wrappedOptional ;
345+ }
346+
347+ function wrapOptionalCall (
348+ context : TransformationContext ,
349+ call : lua . CallExpression | lua . MethodCallExpression ,
350+ node : ts . Node
351+ ) : lua . CallExpression {
352+ if ( lua . isMethodCallExpression ( call ) ) {
353+ return transformLuaLibFunction (
354+ context ,
355+ LuaLibFeature . OptionalMethodCall ,
356+ node ,
357+ call . prefixExpression ,
358+ lua . createStringLiteral ( call . name . text ) ,
359+ ...call . params
360+ ) ;
361+ } else {
362+ return transformLuaLibFunction (
363+ context ,
364+ LuaLibFeature . OptionalFunctionCall ,
365+ node ,
366+ call . expression ,
367+ ...call . params
368+ ) ;
369+ }
370+ }
0 commit comments