Skip to content

Commit

Permalink
Addressing review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
cspotcode committed Dec 26, 2021
1 parent 60c7d59 commit 4f64fa4
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 5 deletions.
11 changes: 6 additions & 5 deletions src/esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export interface NodeLoaderHooksAPI2 {
export namespace NodeLoaderHooksAPI2 {
export type ResolveHook = (
specifier: string,
context: { parentURL: string },
context: { conditions?: NodeImportConditions, importAssertions?: NodeImportAssertions, parentURL: string },
defaultResolve: ResolveHook
) => Promise<{ url: string }>;
export type LoadHook = (
Expand All @@ -86,9 +86,10 @@ export type NodeLoaderHooksFormat =
| 'module'
| 'wasm';

export type NodeImportAssertions = {
type: 'json' | 'wasm';
};
export type NodeImportConditions = unknown;
export interface NodeImportAssertions {
type?: 'json';
}

/** @internal */
export function registerAndCreateEsmHooks(opts?: RegisterOptions) {
Expand Down Expand Up @@ -187,8 +188,8 @@ export function createEsmHooks(tsNodeService: Service) {
const { source: rawSource } = await defaultLoad(
url,
{
...context,
format,
importAssertions: context.importAssertions,
},
defaultLoad
);
Expand Down
38 changes: 38 additions & 0 deletions src/test/esm-loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as expect from 'expect';
import type { NodeLoaderHooksAPI2 } from '../';

const nodeUsesNewHooksApi = semver.gte(process.version, '16.12.0');
const nodeSupportsImportAssertions = semver.gte(process.version, '17.1.0');

const test = context(contextTsNodeUnderTest);

Expand Down Expand Up @@ -71,3 +72,40 @@ test.suite('hooks', (_test) => {
});
}
});

if (nodeSupportsImportAssertions) {
test.suite("Catch unexpected changes to node's loader context", (test) => {
/*
* This does not test ts-node.
* Rather, it is meant to alert us to potentially breaking changes in node's
* loader API. If node starts returning more or less properties on `context`
* objects, we want to know, because it may indicate that our loader code
* should be updated to accomodate the new properties, either by proxying them,
* modifying them, or suppressing them.
*/
test('Ensure context passed to loader by node has only expected properties', async (t) => {
const { stdout, stderr } = await exec(
`node --loader ./esm-loader-context/loader.mjs --experimental-json-modules ./esm-loader-context/index.mjs`
);
const rows = stdout.split('\n').filter((v) => v[0] === '{');
expect(rows.length).toBe(14);
rows.forEach((row) => {
const json = JSON.parse(row) as {
resolveContextKeys?: string[];
loadContextKeys?: string;
};
if (json.resolveContextKeys) {
expect(json.resolveContextKeys).toEqual([
'conditions',
'importAssertions',
'parentURL',
]);
} else if (json.loadContextKeys) {
expect(json.loadContextKeys).toEqual(['format', 'importAssertions']);
} else {
throw new Error('Unexpected stdout in test.');
}
});
});
});
}
7 changes: 7 additions & 0 deletions tests/esm-loader-context/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as moduleA from './moduleA.mjs';
import * as moduleB from './moduleB.mjs' assert { foo: 'bar' };
import * as jsonModule from './jsonModuleA.json' assert { type: 'json' };

await import('./moduleC.mjs');
await import('./moduleD.mjs', { foo: 'bar' });
await import('./jsonModuleB.json', { assert: { type: 'json' } });
1 change: 1 addition & 0 deletions tests/esm-loader-context/jsonModuleA.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions tests/esm-loader-context/jsonModuleB.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
8 changes: 8 additions & 0 deletions tests/esm-loader-context/loader.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function resolve(specifier, context, defaultResolve) {
console.log(JSON.stringify({ resolveContextKeys: Object.keys(context) }));
return defaultResolve(specifier, context);
}
export function load(url, context, defaultLoad) {
console.log(JSON.stringify({ loadContextKeys: Object.keys(context) }));
return defaultLoad(url, context);
}
Empty file.
Empty file.
Empty file.
Empty file.

0 comments on commit 4f64fa4

Please sign in to comment.