Skip to content

Updates and ESM support #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
blank_issues_enabled: true
contact_links:
- name: AVA on Spectrum
url: https://spectrum.chat/ava
about: Ask questions and discuss in our Spectrum community
- name: Stack Overflow
url: https://stackoverflow.com/questions/tagged/ava
about: Tag your question on Stack Overflow
16 changes: 9 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Install and test @ava/typescript
on:
push:
branches:
- master
- main
pull_request:
paths-ignore:
- '*.md'
Expand All @@ -13,15 +13,17 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [^12.22, ^14.16, ^15]
node-version: [^12.22, ^14.17, ^16.4, ^17]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- uses: actions/setup-node@v1
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install --global npm@8
- run: npm install --no-audit
- run: npm test
- uses: codecov/codecov-action@v1
- uses: codecov/codecov-action@v2
with:
files: coverage/lcov.info
name: ${{ matrix.os }}/${{ matrix.node-version }}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ Output files are expected to have the `.js` extension.

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.

## ES Modules

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.

## Add additional extensions

You can configure AVA to recognize additional file extensions. To add (partial†) JSX support:
Expand Down
66 changes: 30 additions & 36 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use strict';
const path = require('path');
const escapeStringRegexp = require('escape-string-regexp');
const execa = require('execa');
const pkg = require('./package.json');
import fs from 'node:fs';
import path from 'node:path';
import {pathToFileURL} from 'node:url';
import escapeStringRegexp from 'escape-string-regexp';
import execa from 'execa';

const pkg = fs.readFileSync(new URL('package.json', import.meta.url));
const help = `See https://github.com/avajs/typescript/blob/v${pkg.version}/README.md`;

function isPlainObject(x) {
Expand Down Expand Up @@ -44,7 +45,7 @@ const configProperties = {
required: true,
isValid(compile) {
return compile === false || compile === 'tsc';
}
},
},
rewritePaths: {
required: true,
Expand All @@ -53,23 +54,21 @@ const configProperties = {
return false;
}

return Object.entries(rewritePaths).every(([from, to]) => {
return from.endsWith('/') && typeof to === 'string' && to.endsWith('/');
});
}
return Object.entries(rewritePaths).every(([from, to]) => from.endsWith('/') && typeof to === 'string' && to.endsWith('/'));
},
},
extensions: {
required: false,
isValid(extensions) {
return Array.isArray(extensions) &&
extensions.length > 0 &&
extensions.every(ext => typeof ext === 'string' && ext !== '') &&
new Set(extensions).size === extensions.length;
}
}
return Array.isArray(extensions)
&& extensions.length > 0
&& extensions.every(ext => typeof ext === 'string' && ext !== '')
&& new Set(extensions).size === extensions.length;
},
},
};

module.exports = ({negotiateProtocol}) => {
export default function typescriptProvider({negotiateProtocol}) {
const protocol = negotiateProtocol(['ava-3.2'], {version: pkg.version});
if (protocol === null) {
return;
Expand All @@ -86,12 +85,12 @@ module.exports = ({negotiateProtocol}) => {
const {
extensions = ['ts'],
rewritePaths: relativeRewritePaths,
compile
compile,
} = config;

const rewritePaths = Object.entries(relativeRewritePaths).map(([from, to]) => [
path.join(protocol.projectDir, from),
path.join(protocol.projectDir, to)
path.join(protocol.projectDir, to),
]);
const testFileExtension = new RegExp(`\\.(${extensions.map(ext => escapeStringRegexp(ext)).join('|')})$`);

Expand All @@ -102,13 +101,13 @@ module.exports = ({negotiateProtocol}) => {
}

return {
extensions: extensions.slice(),
rewritePaths: rewritePaths.slice()
extensions: [...extensions],
rewritePaths: [...rewritePaths],
};
},

get extensions() {
return extensions.slice();
return [...extensions];
},

ignoreChange(filePath) {
Expand Down Expand Up @@ -139,18 +138,19 @@ module.exports = ({negotiateProtocol}) => {
filePatterns: [
...filePatterns,
'!**/*.d.ts',
...Object.values(relativeRewritePaths).map(to => `!${to}**`)
...Object.values(relativeRewritePaths).map(to => `!${to}**`),
],
ignoredByWatcherPatterns: [
...ignoredByWatcherPatterns,
...Object.values(relativeRewritePaths).map(to => `${to}**/*.js.map`)
]
...Object.values(relativeRewritePaths).map(to => `${to}**/*.js.map`),
],
};
}
},
};
},

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

return {
Expand All @@ -159,18 +159,12 @@ module.exports = ({negotiateProtocol}) => {
},

async load(ref, {requireFn}) {
for (const extension of extensionsToLoadAsModules) {
if (ref.endsWith(`.${extension}`)) {
throw new Error('@ava/typescript cannot yet load ESM files');
}
}

const [from, to] = rewritePaths.find(([from]) => ref.startsWith(from));
// TODO: Support JSX preserve mode — https://www.typescriptlang.org/docs/handbook/jsx.html
const rewritten = `${to}${ref.slice(from.length)}`.replace(testFileExtension, '.js');
return requireFn(rewritten);
}
return useImport ? import(pathToFileURL(rewritten)) : requireFn(rewritten); // eslint-disable-line node/no-unsupported-features/es-syntax
},
};
}
},
};
};
}
27 changes: 16 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
"version": "2.0.0",
"description": "TypeScript provider for AVA",
"engines": {
"node": ">=12.22 <13 || >=14.16 <15 || >=15"
"node": ">=12.22 <13 || >=14.17 <15 || >=16.4 <17 || >=17"
},
"files": [
"index.js"
],
"exports": {
".": "./index.js"
},
"type": "module",
"author": "Mark Wubben (https://novemberborn.net)",
"repository": "avajs/typescript",
"license": "MIT",
Expand All @@ -19,15 +23,15 @@
"test": "xo && c8 ava"
},
"dependencies": {
"escape-string-regexp": "^4.0.0",
"execa": "^5.0.0"
"escape-string-regexp": "^5.0.0",
"execa": "^5.1.1"
},
"devDependencies": {
"ava": "^3.15.0",
"c8": "^7.7.1",
"ava": "4.0.0-rc.1",
"c8": "^7.10.0",
"del": "^6.0.0",
"typescript": "^4.2.4",
"xo": "^0.38.2"
"typescript": "^4.4.4",
"xo": "^0.46.3"
},
"c8": {
"reporter": [
Expand All @@ -40,14 +44,15 @@
"files": [
"!test/broken-fixtures/**"
],
"ignoredByWatcher": [
"test/fixtures/**",
"test/broken-fixtures/**"
],
"timeout": "60s"
},
"xo": {
"ignores": [
"test/broken-fixtures"
],
"rules": {
"import/order": "off"
}
]
}
}
44 changes: 23 additions & 21 deletions test/_with-provider.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
const path = require('path');
const pkg = require('../package.json');
const makeProvider = require('..');
import fs from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import makeProvider from '@ava/typescript';

const createProviderMacro = (identifier, avaVersion, projectDir = __dirname) => {
return (t, run) => run(t, makeProvider({
negotiateProtocol(identifiers, {version}) {
t.true(identifiers.includes(identifier));
t.is(version, pkg.version);
return {
ava: {avaVersion},
identifier,
normalizeGlobPatterns: patterns => patterns,
async findFiles({patterns}) {
return patterns.map(file => path.join(projectDir, file));
},
projectDir
};
}
}));
};
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pkg = fs.readFileSync(new URL('../package.json', import.meta.url));

module.exports = createProviderMacro;
const createProviderMacro = (identifier, avaVersion, projectDir = __dirname) => (t, run) => run(t, makeProvider({
negotiateProtocol(identifiers, {version}) {
t.true(identifiers.includes(identifier));
t.is(version, pkg.version);
return {
ava: {avaVersion},
identifier,
normalizeGlobPatterns: patterns => patterns,
async findFiles({patterns}) {
return patterns.map(file => path.join(projectDir, file));
},
projectDir,
};
},
}));

export default createProviderMacro;
4 changes: 2 additions & 2 deletions test/base.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const test = require('ava');
const makeProvider = require('..');
import test from 'ava';
import makeProvider from '@ava/typescript';

test('bails when negotiating protocol returns `null`', t => {
const provider = makeProvider({negotiateProtocol: () => null});
Expand Down
46 changes: 23 additions & 23 deletions test/compilation.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const path = require('path');
const test = require('ava');
const del = require('del');
const execa = require('execa');
const createProviderMacro = require('./_with-provider');

import path from 'node:path';
import {fileURLToPath} from 'node:url';
import test from 'ava';
import del from 'del';
import execa from 'execa';
import createProviderMacro from './_with-provider.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const withProvider = createProviderMacro('ava-3.2', '3.2.0', path.join(__dirname, 'fixtures'));
const withAltProvider = createProviderMacro('ava-3.2', '3.2.0', path.join(__dirname, 'broken-fixtures'));

Expand All @@ -12,26 +14,24 @@ test.before('deleting compiled files', async t => {
t.log(await del('test/broken-fixtures/typescript/compiled'));
});

const compile = async provider => {
return {
state: await provider.main({
config: {
rewritePaths: {
'ts/': 'typescript/',
'compiled/': 'typescript/compiled/'
},
compile: 'tsc'
}
}).compile()
};
};
const compile = async provider => ({
state: await provider.main({
config: {
rewritePaths: {
'ts/': 'typescript/',
'compiled/': 'typescript/compiled/',
},
compile: 'tsc',
},
}).compile(),
});

test('worker(): load rewritten paths files', withProvider, async (t, provider) => {
const {state} = await compile(provider);
const {stdout, stderr} = await execa.node(
path.join(__dirname, 'fixtures/install-and-load'),
[JSON.stringify(state), path.join(__dirname, 'fixtures/ts', 'file.ts')],
{cwd: path.join(__dirname, 'fixtures')}
[JSON.stringify({state}), path.join(__dirname, 'fixtures/ts', 'file.ts')],
{cwd: path.join(__dirname, 'fixtures')},
);
if (stderr.length > 0) {
t.log(stderr);
Expand All @@ -44,8 +44,8 @@ test('worker(): runs compiled files', withProvider, async (t, provider) => {
const {state} = await compile(provider);
const {stdout, stderr} = await execa.node(
path.join(__dirname, 'fixtures/install-and-load'),
[JSON.stringify(state), path.join(__dirname, 'fixtures/compiled', 'index.ts')],
{cwd: path.join(__dirname, 'fixtures')}
[JSON.stringify({state}), path.join(__dirname, 'fixtures/compiled', 'index.ts')],
{cwd: path.join(__dirname, 'fixtures')},
);
if (stderr.length > 0) {
t.log(stderr);
Expand Down
Loading