diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..0da8f80f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_size = 2 +indent_style = space diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..41da105b --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +test/fixtures \ No newline at end of file diff --git a/.mocharc.json b/.mocharc.json index 9c55803b..b2cf2654 100644 --- a/.mocharc.json +++ b/.mocharc.json @@ -1,5 +1,10 @@ { "require": ["./env.js"], "extension": ["ts"], - "recursive": true + "recursive": true, + "exclude": "test/fixtures/**", + "node-option": [ + "experimental-specifier-resolution=node", + "loader=ts-node/esm" + ] } diff --git a/src/asyncAssignTasks.ts b/src/asyncAssignTasks.ts index 485ff752..33d2a391 100644 --- a/src/asyncAssignTasks.ts +++ b/src/asyncAssignTasks.ts @@ -1,5 +1,6 @@ import { readdirSync } from 'fs' import path from 'path' +import { pathToFileURL } from 'url' export default async function asyncAssignTasks(thisObj: T, tasksDir: string): Promise { if (!tasksDir) throw new Error(`tasksDir was ${tasksDir}`) @@ -16,16 +17,19 @@ export default async function asyncAssignTasks(thisObj: T, tasksDir: string): } async function loadTask(name: string) { - const path = `${tasksDir}/${name}` - try { - // Typescript has issues with dynamic imports, even though node supports them - // for both commonjs and esmodules. see: https://github.com/microsoft/TypeScript/issues/43329 - const task = await Function(`return import("${path}")`)() - return task[name] - } catch (err) { - return () => { - throw new Error(`No task in: ${path}.{ts,js,tsx,jsx}`) - } + // this is needed for Windows, or you get ERR_UNSUPPORTED_ESM_URL_SCHEME + const path = pathToFileURL(`${tasksDir}/${name}`).href + + // Typescript has issues with dynamic imports, even though node supports them + // for both commonjs and esmodules. see: https://github.com/microsoft/TypeScript/issues/43329 + const task = await Function(`return import("${path}")`)() + + // if typescript is using commonjs modules + if (task.default) { + return task.default[name] } + + // if typescript is using es modules + return task[name] } } diff --git a/test/asyncTasks.test.ts b/test/asyncTasks.test.ts new file mode 100644 index 00000000..5e2b34b6 --- /dev/null +++ b/test/asyncTasks.test.ts @@ -0,0 +1,38 @@ +import assert = require('assert') +import { Action, ActorWorld } from '../src' +import type { IActorWorldOptions } from '../src/ActorWorld' +import asyncAssignTasks from '../src/asyncAssignTasks' + +describe(asyncAssignTasks.name, () => { + const options: IActorWorldOptions = { parameters: {} } as IActorWorldOptions + + // success + it('successfully loads a task', async () => { + class TestWorld extends ActorWorld { + public goodtask: () => Action + } + + const world = new TestWorld(options) + + // Load the task + await asyncAssignTasks(world, `${__dirname}/fixtures/tasks/goodtasks`) + + // Execute the task + world.goodtask() + }) + + // error compiling + it('fails with a helpful error message if the task could not be compiled', async () => { + class TestWorld extends ActorWorld { + public brokentask: () => Action + } + + const world = new TestWorld(options) + + // Try to load the task + await assert.rejects(asyncAssignTasks(world, `${__dirname}/fixtures/tasks/brokentask`), { + name: 'TSError', + message: /Cannot find module '\.\/src'/, + }) + }) +}) diff --git a/test/fixtures/tasks/brokentask/brokentask.ts b/test/fixtures/tasks/brokentask/brokentask.ts new file mode 100644 index 00000000..a7183239 --- /dev/null +++ b/test/fixtures/tasks/brokentask/brokentask.ts @@ -0,0 +1,7 @@ +// this import will fail +import { type Action } from './src' + +export const badtask = (): Action => { + // eslint-disable-next-line @typescript-eslint/no-empty-function + return () => {} +} diff --git a/test/fixtures/tasks/goodtasks/goodtask.ts b/test/fixtures/tasks/goodtasks/goodtask.ts new file mode 100644 index 00000000..2f764a82 --- /dev/null +++ b/test/fixtures/tasks/goodtasks/goodtask.ts @@ -0,0 +1,6 @@ +import { type Action } from '../../../../src' + +export const goodtask = (): Action => { + // eslint-disable-next-line @typescript-eslint/no-empty-function + return () => {} +} diff --git a/tsconfig.json b/tsconfig.json index 974cd221..4f23e21c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,5 +20,6 @@ "strictNullChecks": true, "noImplicitReturns": true }, - "include": ["src", "test"] + "include": ["src", "test"], + "exclude": ["test/fixtures"] }