Skip to content

Commit cdbeb2d

Browse files
committed
Support ESM files
Fixes #5.
1 parent 3debd9d commit cdbeb2d

File tree

10 files changed

+58
-10
lines changed

10 files changed

+58
-10
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ Output files are expected to have the `.js` extension.
3939

4040
AVA searches your entire project for `*.js`, `*.cjs`, `*.mjs` and `*.ts` files (or other extensions you've configured). It will ignore such files found in the `rewritePaths` targets (e.g. `build/`). If you use more specific paths, for instance `build/main/`, you may need to change AVA's `files` configuration to ignore other directories.
4141

42+
## ES Modules
43+
44+
When used with AVA 4, if your `package.json` has configured `"type": "module"`, or you've configured AVA to treat the `js` extension as `module`, then `@ava/typescript` will import the output file as an ES module. Note that this is based on the *output file*, not the `ts` extension.
45+
4246
## Add additional extensions
4347

4448
You can configure AVA to recognize additional file extensions. To add (partial†) JSX support:

index.js

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3+
import {pathToFileURL} from 'node:url';
34
import escapeStringRegexp from 'escape-string-regexp';
45
import execa from 'execa';
56

@@ -149,6 +150,7 @@ export default function typescriptProvider({negotiateProtocol}) {
149150
},
150151

151152
worker({extensionsToLoadAsModules, state: {extensions, rewritePaths}}) {
153+
const useImport = extensionsToLoadAsModules.includes('js');
152154
const testFileExtension = new RegExp(`\\.(${extensions.map(ext => escapeStringRegexp(ext)).join('|')})$`);
153155

154156
return {
@@ -157,16 +159,10 @@ export default function typescriptProvider({negotiateProtocol}) {
157159
},
158160

159161
async load(ref, {requireFn}) {
160-
for (const extension of extensionsToLoadAsModules) {
161-
if (ref.endsWith(`.${extension}`)) {
162-
throw new Error('@ava/typescript cannot yet load ESM files');
163-
}
164-
}
165-
166162
const [from, to] = rewritePaths.find(([from]) => ref.startsWith(from));
167163
// TODO: Support JSX preserve mode — https://www.typescriptlang.org/docs/handbook/jsx.html
168164
const rewritten = `${to}${ref.slice(from.length)}`.replace(testFileExtension, '.js');
169-
return requireFn(rewritten);
165+
return useImport ? import(pathToFileURL(rewritten)) : requireFn(rewritten); // eslint-disable-line node/no-unsupported-features/es-syntax
170166
},
171167
};
172168
},

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"files": [
4545
"!test/broken-fixtures/**"
4646
],
47+
"ignoredByWatcher": ["test/fixtures/**", "test/broken-fixtures/**"],
4748
"timeout": "60s"
4849
},
4950
"xo": {

test/compilation.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ test('worker(): load rewritten paths files', withProvider, async (t, provider) =
3030
const {state} = await compile(provider);
3131
const {stdout, stderr} = await execa.node(
3232
path.join(__dirname, 'fixtures/install-and-load'),
33-
[JSON.stringify(state), path.join(__dirname, 'fixtures/ts', 'file.ts')],
33+
[JSON.stringify({state}), path.join(__dirname, 'fixtures/ts', 'file.ts')],
3434
{cwd: path.join(__dirname, 'fixtures')},
3535
);
3636
if (stderr.length > 0) {
@@ -44,7 +44,7 @@ test('worker(): runs compiled files', withProvider, async (t, provider) => {
4444
const {state} = await compile(provider);
4545
const {stdout, stderr} = await execa.node(
4646
path.join(__dirname, 'fixtures/install-and-load'),
47-
[JSON.stringify(state), path.join(__dirname, 'fixtures/compiled', 'index.ts')],
47+
[JSON.stringify({state}), path.join(__dirname, 'fixtures/compiled', 'index.ts')],
4848
{cwd: path.join(__dirname, 'fixtures')},
4949
);
5050
if (stderr.length > 0) {

test/esm.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import path from 'node:path';
2+
import {fileURLToPath} from 'node:url';
3+
import test from 'ava';
4+
import execa from 'execa';
5+
import createProviderMacro from './_with-provider.js';
6+
7+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
8+
const withProvider = createProviderMacro('ava-3.2', '3.2.0', path.join(__dirname, 'fixtures'));
9+
10+
const setup = async provider => ({
11+
state: await provider.main({
12+
config: {
13+
rewritePaths: {
14+
'esm/': 'esm/',
15+
},
16+
compile: false,
17+
},
18+
}).compile(),
19+
});
20+
21+
test('worker(): import ESM', withProvider, async (t, provider) => {
22+
const {state} = await setup(provider);
23+
const {stdout, stderr} = await execa.node(
24+
path.join(__dirname, 'fixtures/install-and-load'),
25+
[JSON.stringify({extensionsToLoadAsModules: ['js'], state}), path.join(__dirname, 'fixtures/esm', 'index.ts')],
26+
{cwd: path.join(__dirname, 'fixtures')},
27+
);
28+
if (stderr.length > 0) {
29+
t.log(stderr);
30+
}
31+
32+
t.snapshot(stdout);
33+
});

test/fixtures/esm/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('logged in fixtures/esm/index.js');

test/fixtures/esm/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('logged in fixtures/esm/index.ts');

test/fixtures/install-and-load.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const provider = makeProvider({
1414

1515
const worker = provider.worker({
1616
extensionsToLoadAsModules: [],
17-
state: JSON.parse(process.argv[2]),
17+
state: {},
18+
...JSON.parse(process.argv[2]),
1819
});
1920

2021
const ref = path.resolve(process.argv[3]);

test/snapshots/esm.js.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Snapshot report for `test/esm.js`
2+
3+
The actual snapshot is saved in `esm.js.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## worker(): import ESM
8+
9+
> Snapshot 1
10+
11+
'logged in fixtures/esm/index.js'

test/snapshots/esm.js.snap

169 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)