1- import { CallExpression , Statement } from '@babel/types'
1+ import type { ExportNamedDeclaration , ExportSpecifier , Expression , Statement } from '@babel/types'
22
3+ import type { BindingMethod } from './bindings.js'
34import { isModuleExports } from './helpers.js'
45
56import type { ISCExport } from './index.js'
67
78// Finds the main handler export in an AST.
8- export const getMainExport = ( nodes : Statement [ ] ) => {
9+ export const getMainExport = ( nodes : Statement [ ] , getAllBindings : BindingMethod ) => {
910 let handlerExport : ISCExport [ ] = [ ]
1011
1112 nodes . find ( ( node ) => {
12- const esmExports = getMainExportFromESM ( node )
13+ const esmExports = getMainExportFromESM ( node , getAllBindings )
1314
1415 if ( esmExports . length !== 0 ) {
1516 handlerExport = esmExports
@@ -39,24 +40,27 @@ const getMainExportFromCJS = (node: Statement) => {
3940 ]
4041
4142 return handlerPaths . flatMap ( ( handlerPath ) => {
42- if ( ! isModuleExports ( node , handlerPath ) || node . expression . right . type !== 'CallExpression' ) {
43+ if ( ! isModuleExports ( node , handlerPath ) ) {
4344 return [ ]
4445 }
4546
46- return getExportsFromCallExpression ( node . expression . right )
47+ return getExportsFromExpression ( node . expression . right )
4748 } )
4849}
4950
5051// Finds the main handler export in an ESM AST.
51- // eslint-disable-next-line complexity
52- const getMainExportFromESM = ( node : Statement ) => {
52+ const getMainExportFromESM = ( node : Statement , getAllBindings : BindingMethod ) => {
5353 if ( node . type !== 'ExportNamedDeclaration' || node . exportKind !== 'value' ) {
5454 return [ ]
5555 }
5656
57- const { declaration } = node
57+ const { declaration, specifiers } = node
5858
59- if ( ! declaration || declaration . type !== 'VariableDeclaration' ) {
59+ if ( specifiers ?. length > 0 ) {
60+ return getExportsFromBindings ( specifiers , getAllBindings )
61+ }
62+
63+ if ( declaration ?. type !== 'VariableDeclaration' ) {
6064 return [ ]
6165 }
6266
@@ -66,16 +70,47 @@ const getMainExportFromESM = (node: Statement) => {
6670 return type === 'VariableDeclarator' && id . type === 'Identifier' && id . name === 'handler'
6771 } )
6872
69- if ( handlerDeclaration ?. init ?. type !== 'CallExpression' ) {
73+ const exports = getExportsFromExpression ( handlerDeclaration ?. init )
74+
75+ return exports
76+ }
77+
78+ // Check if the Node is an ExportSpecifier that has a named export called `handler`
79+ // either with Identifier `export { handler }`
80+ // or with StringLiteral `export { x as "handler" }`
81+ const isHandlerExport = ( node : ExportNamedDeclaration [ 'specifiers' ] [ number ] ) : node is ExportSpecifier => {
82+ const { type, exported } = node
83+
84+ return (
85+ type === 'ExportSpecifier' &&
86+ ( ( exported . type === 'Identifier' && exported . name === 'handler' ) ||
87+ ( exported . type === 'StringLiteral' && exported . value === 'handler' ) )
88+ )
89+ }
90+
91+ // Tries to resolve the export from a binding (variable)
92+ // for example `let handler; handler = () => {}; export { handler }` would
93+ // resolve correctly to the handler function
94+ const getExportsFromBindings = ( specifiers : ExportNamedDeclaration [ 'specifiers' ] , getAllBindings : BindingMethod ) => {
95+ const specifier = specifiers . find ( isHandlerExport )
96+
97+ if ( ! specifier ) {
7098 return [ ]
7199 }
72100
73- const exports = getExportsFromCallExpression ( handlerDeclaration . init )
101+ const binding = getAllBindings ( ) . get ( specifier . local . name )
102+ const exports = getExportsFromExpression ( binding )
74103
75104 return exports
76105}
77106
78- const getExportsFromCallExpression = ( node : CallExpression ) => {
107+ const getExportsFromExpression = ( node : Expression | undefined | null ) => {
108+ // We're only interested in expressions representing function calls, because
109+ // the ISC patterns we implement at the moment are all helper functions.
110+ if ( node ?. type !== 'CallExpression' ) {
111+ return [ ]
112+ }
113+
79114 const { arguments : args , callee } = node
80115
81116 if ( callee . type !== 'Identifier' ) {
0 commit comments