1+ const fs = require ( 'node:fs/promises' ) ;
12const path = require ( 'path' )
23const readline = require ( 'readline' )
3- const WRITE_CHUNK_SIZE = parseInt ( process . env . WRITE_CHUNK_SIZE , 10 )
44
5+ const WRITE_CHUNK_SIZE = parseInt ( process . env . WRITE_CHUNK_SIZE , 10 )
6+ const NODE_PATHS = ( process . env . NODE_PATH || '' ) . split ( path . delimiter ) . filter ( Boolean )
57const PREFIX = "__elixirnodejs__UOSBsDUP6bp9IF5__" ;
68
9+ async function fileExists ( file ) {
10+ return await fs . access ( file , fs . constants . R_OK ) . then ( ( ) => true ) . catch ( ( ) => false ) ;
11+ }
12+
713function requireModule ( modulePath ) {
814 // When not running in production mode, refresh the cache on each call.
915 if ( process . env . NODE_ENV !== 'production' ) {
@@ -13,6 +19,23 @@ function requireModule(modulePath) {
1319 return require ( modulePath )
1420}
1521
22+ async function importModuleRespectingNodePath ( modulePath ) {
23+ // to be compatible with cjs require, we simulate resolution using NODE_PATH
24+ for ( const nodePath of NODE_PATHS ) {
25+ // Try to resolve the module in the current path
26+ const modulePathToTry = path . join ( nodePath , modulePath )
27+ if ( fileExists ( modulePathToTry ) ) {
28+ // imports are cached. To bust that cache, add unique query string to module name
29+ // eg NodeJS.call({"esm-module.mjs?q=#{System.unique_integer()}", :fn})
30+ // it will leak memory, so I'm not doing it by default!
31+ // see more: https://ar.al/2021/02/22/cache-busting-in-node.js-dynamic-esm-imports/#cache-invalidation-in-esm-with-dynamic-imports
32+ return await import ( modulePathToTry )
33+ }
34+ }
35+
36+ throw new Error ( `Could not find module '${ modulePath } '. Hint: File extensions are required in ESM. Tried ${ NODE_PATHS . join ( ", " ) } ` )
37+ }
38+
1639function getAncestor ( parent , [ key , ...keys ] ) {
1740 if ( typeof key === 'undefined' ) {
1841 return parent
@@ -21,28 +44,15 @@ function getAncestor(parent, [key, ...keys]) {
2144 return getAncestor ( parent [ key ] , keys )
2245}
2346
24- function requireModuleFunction ( [ modulePath , ...keys ] ) {
25- const mod = requireModule ( modulePath )
26-
27- return getAncestor ( mod , keys )
28- }
29-
30- async function callModuleFunction ( moduleFunction , args ) {
31- const fn = requireModuleFunction ( moduleFunction )
32- const returnValue = fn ( ...args )
33-
34- if ( returnValue instanceof Promise ) {
35- return await returnValue
36- }
37-
38- return returnValue
39- }
40-
4147async function getResponse ( string ) {
4248 try {
43- const [ moduleFunction , args ] = JSON . parse ( string )
44- const result = await callModuleFunction ( moduleFunction , args )
45-
49+ const [ [ modulePath , ...keys ] , args , useImport ] = JSON . parse ( string )
50+ const importFn = useImport ? importModuleRespectingNodePath : requireModule
51+ const mod = await importFn ( modulePath )
52+ const fn = await getAncestor ( mod , keys )
53+ if ( ! fn ) throw new Error ( `Could not find function '${ keys . join ( "." ) } ' in module '${ modulePath } '` )
54+ const returnValue = fn ( ...args )
55+ const result = returnValue instanceof Promise ? await returnValue : returnValue
4656 return JSON . stringify ( [ true , result ] )
4757 } catch ( { message, stack } ) {
4858 return JSON . stringify ( [ false , `${ message } \n${ stack } ` ] )
0 commit comments