From 4f64fa4ad695bd748fd487e1ae502f82683747b5 Mon Sep 17 00:00:00 2001 From: Andrew Bradley <abradley@brightcove.com> Date: Sun, 26 Dec 2021 21:25:56 +0000 Subject: [PATCH] Addressing review feedback --- src/esm.ts | 11 ++++--- src/test/esm-loader.spec.ts | 38 +++++++++++++++++++++++ tests/esm-loader-context/index.mjs | 7 +++++ tests/esm-loader-context/jsonModuleA.json | 1 + tests/esm-loader-context/jsonModuleB.json | 1 + tests/esm-loader-context/loader.mjs | 8 +++++ tests/esm-loader-context/moduleA.mjs | 0 tests/esm-loader-context/moduleB.mjs | 0 tests/esm-loader-context/moduleC.mjs | 0 tests/esm-loader-context/moduleD.mjs | 0 10 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 tests/esm-loader-context/index.mjs create mode 100644 tests/esm-loader-context/jsonModuleA.json create mode 100644 tests/esm-loader-context/jsonModuleB.json create mode 100644 tests/esm-loader-context/loader.mjs create mode 100644 tests/esm-loader-context/moduleA.mjs create mode 100644 tests/esm-loader-context/moduleB.mjs create mode 100644 tests/esm-loader-context/moduleC.mjs create mode 100644 tests/esm-loader-context/moduleD.mjs diff --git a/src/esm.ts b/src/esm.ts index 37bab3856..4d88541ea 100644 --- a/src/esm.ts +++ b/src/esm.ts @@ -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 = ( @@ -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) { @@ -187,8 +188,8 @@ export function createEsmHooks(tsNodeService: Service) { const { source: rawSource } = await defaultLoad( url, { + ...context, format, - importAssertions: context.importAssertions, }, defaultLoad ); diff --git a/src/test/esm-loader.spec.ts b/src/test/esm-loader.spec.ts index 6c3c1c51a..fe4110c58 100644 --- a/src/test/esm-loader.spec.ts +++ b/src/test/esm-loader.spec.ts @@ -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); @@ -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.'); + } + }); + }); + }); +} diff --git a/tests/esm-loader-context/index.mjs b/tests/esm-loader-context/index.mjs new file mode 100644 index 000000000..3def33246 --- /dev/null +++ b/tests/esm-loader-context/index.mjs @@ -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' } }); diff --git a/tests/esm-loader-context/jsonModuleA.json b/tests/esm-loader-context/jsonModuleA.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/tests/esm-loader-context/jsonModuleA.json @@ -0,0 +1 @@ +{} diff --git a/tests/esm-loader-context/jsonModuleB.json b/tests/esm-loader-context/jsonModuleB.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/tests/esm-loader-context/jsonModuleB.json @@ -0,0 +1 @@ +{} diff --git a/tests/esm-loader-context/loader.mjs b/tests/esm-loader-context/loader.mjs new file mode 100644 index 000000000..d500b5a79 --- /dev/null +++ b/tests/esm-loader-context/loader.mjs @@ -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); +} diff --git a/tests/esm-loader-context/moduleA.mjs b/tests/esm-loader-context/moduleA.mjs new file mode 100644 index 000000000..e69de29bb diff --git a/tests/esm-loader-context/moduleB.mjs b/tests/esm-loader-context/moduleB.mjs new file mode 100644 index 000000000..e69de29bb diff --git a/tests/esm-loader-context/moduleC.mjs b/tests/esm-loader-context/moduleC.mjs new file mode 100644 index 000000000..e69de29bb diff --git a/tests/esm-loader-context/moduleD.mjs b/tests/esm-loader-context/moduleD.mjs new file mode 100644 index 000000000..e69de29bb