Skip to content

Commit

Permalink
fix: modify module loader to look in parent directories (#144)
Browse files Browse the repository at this point in the history
This resolves issues where function source may be in a subdirectory, for
example `./build` in a TypeScript project.

Fixes: #143

Signed-off-by: Lance Ball <lball@redhat.com>
  • Loading branch information
lance committed Jan 5, 2023
1 parent 14297d2 commit 2a1e618
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 8 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ on:

jobs:
lts:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand All @@ -23,7 +24,10 @@ jobs:
- run: npm test

current:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js 18.x
Expand All @@ -36,6 +40,6 @@ jobs:
- uses: codecov/codecov-action@v3
with:
files: coverage/lcov.info
name: ${{ matrix.node-version }}
name: lts ${{ matrix.os }}
fail_ci_if_error: true
verbose: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
.nyc_output
coverage
test/fixtures/*/package-lock.json
30 changes: 25 additions & 5 deletions lib/function-loader.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
const fs = require('fs');
const path = require('path');

// This is the way to import es modules inside a CJS module
const dynamicImport = new Function('modulePath', 'return import(modulePath)');

async function loadFunction(filePath) {
if (isESM(filePath)) {
if (process.platform === 'win32') {
// Windows requires the file path to be a URL
filePath = `file:///${filePath}`;
}
code = await dynamicImport(filePath);
} else {
code = require(filePath);
Expand All @@ -25,14 +30,29 @@ function isESM(filePath) {
}

// find the functions package.json and see if it has a type field
const functionPkg = require(path.join(pathParsed.dir, 'package.json'));
if (functionPkg.type === 'module') {
return true;
// look in the parent directory if the function is in a subdirectory
let dir = pathParsed.dir;
const rootDir = path.parse(process.cwd()).root;
while (!hasPackageJson(dir)) {
if (dir === rootDir) return false;
dir = path.dirname(dir);
}

// Should default to CJS
return false;
// Load the package.json and check the type field
// Put this in a try/catch in case the package.json is invalid
let pkgPath = path.join(dir, 'package.json');
try {
const functionPkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
return functionPkg.type === 'module';
} catch(e) {
console.warn(e);
return false;
}
}

function hasPackageJson(dir) {
const pkgPath = path.join(dir, 'package.json');
return fs.existsSync(pkgPath);
}

module.exports = exports = { loadFunction };
2 changes: 2 additions & 0 deletions test/fixtures/esm-module-type-up-dir/build/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const handle = async _ => 'ok';
export { handle };
5 changes: 5 additions & 0 deletions test/fixtures/esm-module-type-up-dir/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "esm-module-type-module",
"version": "1.0.0",
"type": "module"
}
6 changes: 6 additions & 0 deletions test/test-function-loading.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ test('Loads an ESM function with the type=module in the package.json', async t =
t.equal(typeof fn.handle, 'function');
t.pass('ESM module with a type=module in the package.json');
});

test('Loads an ESM function with the type=module in package.json in a parent dir and a .js extension', async t => {
const fn = await loadFunction(path.join(fixtureDir, 'esm-module-type-up-dir', 'build', 'index.js'));
t.equal(typeof fn.handle, 'function');
t.pass('ESM module with a type=module in a package.json in parent directory');
});

0 comments on commit 2a1e618

Please sign in to comment.