diff --git a/doc/api/esm.md b/doc/api/esm.md index 64e9c68289d01d..81167eeb4e492b 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -502,6 +502,37 @@ a second argument: * `parent` {string|URL} An optional absolute parent module URL to resolve from. **Default:** `import.meta.url` +### `import.meta.sync(specifier)` + + + +> Stability: 1.0 - Early development + +* `specifier` {string} The module specifier to synchronously import. +* Returns: {Object} The module namespace object. + +`import.meta.sync()` provides a way to synchronously import ES modules, +offering feature parity with `require()` for conditional synchronous imports +in ES modules. This is particularly useful when migrating from CommonJS to ES modules +while maintaining the ability to conditionally load dependencies in synchronous code paths. + +The primary use case is conditional synchronous importing: + +```js +let mod; +try { + mod = import.meta.sync('./module-a.js'); +} catch { + mod = import.meta.sync('./module-b.js'); +} +``` + +If the imported module or any of its +dependencies use top-level `await`, `import.meta.sync()` will throw an +[`ERR_REQUIRE_ASYNC_MODULE`][] error. + ## Interoperability with CommonJS ### `import` statements @@ -1304,6 +1335,7 @@ resolution for ESM specifiers is [commonjs-extension-resolution-loader][]. [`"exports"`]: packages.md#exports [`"type"`]: packages.md#type [`--input-type`]: cli.md#--input-typetype +[`ERR_REQUIRE_ASYNC_MODULE`]: #err_require_async_module [`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs [`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export [`import()`]: #import-expressions diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index d30c824ce387a7..b5344a4eccbd79 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -31,7 +31,7 @@ const { } = require('internal/errors').codes; const { getOptionValue } = require('internal/options'); const { isURL, pathToFileURL } = require('internal/url'); -const { kEmptyObject } = require('internal/util'); +const { kEmptyObject, emitExperimentalWarning } = require('internal/util'); const { compileSourceTextModule, getDefaultConditions, @@ -52,6 +52,7 @@ const { kSourcePhase, throwIfPromiseRejected, setImportMetaResolveInitializer, + setImportMetaSyncInitializer, } = internalBinding('module_wrap'); const { urlToFilename, @@ -908,6 +909,36 @@ function createImportMetaResolve(loader, moduleURL) { }; } +/** + * @param {ModuleLoader} loader The cascaded loader. + * @param {string} moduleURL URL of the module accessing import.meta + * @returns {function(string, ImportAttributes|undefined): ModuleNamespace} The import.meta.sync function + */ +function createImportMetaSync(loader, moduleURL) { + /** + * @param {string} specifier The module specifier to synchronously import. + * @param {Record} [importAttributes] Optional import attributes object. Accepts + * the same shape as dynamic import(): { with: { type: 'json' } } etc. + * @returns {ModuleNamespace} The module namespace object + */ + return function sync(specifier, importAttributes = kEmptyObject) { + emitExperimentalWarning('import.meta.sync'); + let normalizedAttributes = importAttributes; + if (importAttributes && typeof importAttributes === 'object' && importAttributes.with) { + const withBag = importAttributes.with; + if (withBag && typeof withBag === 'object') { + normalizedAttributes = { ...withBag, __proto__: null }; + } + } + const request = { specifier, phase: kEvaluationPhase, attributes: normalizedAttributes, __proto__: null }; + const job = loader.getOrCreateModuleJob(moduleURL, request, kImportInImportedESM); + + // This will throw if the module has TLA or is async + const result = job.runSync(); + return result.namespace; + }; +} + let cascadedLoader; /** * This is a singleton ESM loader that integrates the loader hooks, if any. @@ -924,12 +955,13 @@ let cascadedLoader; function getOrInitializeCascadedLoader(asyncLoaderHooks) { if (!cascadedLoader) { cascadedLoader = createModuleLoader(asyncLoaderHooks); - // import.meta.resolve is not allowed in the async loader hook worker thread. - // So only set up the import.meta.resolve initializer when we are initializing + // import.meta.resolve and import.meta.sync are not allowed in the async loader hook worker thread. + // So only set up the initializers when we are initializing // the non-loader-hook-thread cascaded loader. When the native land doesn't see it, // it knows the loader is running on the loader hook thread. if (!(asyncLoaderHooks?.isForAsyncLoaderHookWorker)) { setImportMetaResolveInitializer(createImportMetaResolve.bind(null, cascadedLoader)); + setImportMetaSyncInitializer(createImportMetaSync.bind(null, cascadedLoader)); } } return cascadedLoader; diff --git a/src/env_properties.h b/src/env_properties.h index 5a83392120d096..7dea76ceb9405f 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -471,6 +471,7 @@ V(get_source_map_error_source, v8::Function) \ V(host_import_module_dynamically_callback, v8::Function) \ V(host_import_meta_resolve_initializer, v8::Function) \ + V(host_import_meta_sync_initializer, v8::Function) \ V(host_initialize_import_meta_object_callback, v8::Function) \ V(http2session_on_altsvc_function, v8::Function) \ V(http2session_on_error_function, v8::Function) \ diff --git a/src/module_wrap.cc b/src/module_wrap.cc index d9711500f178c7..154eb756d1b47f 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -1220,6 +1220,18 @@ void ModuleWrap::SetImportMetaResolveInitializer( realm->set_host_import_meta_resolve_initializer(initializer); } +void ModuleWrap::SetImportMetaSyncInitializer( + const v8::FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + Realm* realm = Realm::GetCurrent(args); + HandleScope handle_scope(isolate); + + CHECK_EQ(args.Length(), 1); + CHECK(args[0]->IsFunction()); + Local initializer = args[0].As(); + realm->set_host_import_meta_sync_initializer(initializer); +} + static void ImportMetaResolveLazyGetter( Local name, const PropertyCallbackInfo& info) { Isolate* isolate = info.GetIsolate(); @@ -1256,6 +1268,42 @@ static void ImportMetaResolveLazyGetter( info.GetReturnValue().Set(ret); } +static void ImportMetaSyncLazyGetter(Local name, + const PropertyCallbackInfo& info) { + Isolate* isolate = info.GetIsolate(); + Local receiver_val = info.This(); + if (!receiver_val->IsObject()) { + THROW_ERR_INVALID_INVOCATION(isolate); + return; + } + Local receiver = receiver_val.As(); + Local context; + if (!receiver->GetCreationContext().ToLocal(&context)) { + THROW_ERR_INVALID_INVOCATION(isolate); + return; + } + Realm* realm = Realm::GetCurrent(context); + if (realm == nullptr) { + THROW_ERR_INVALID_INVOCATION(isolate); + } + Local initializer = realm->host_import_meta_sync_initializer(); + if (initializer.IsEmpty()) { + THROW_ERR_INVALID_INVOCATION(isolate); + return; + } + + // This should be createImportMetaSync(). The loader argument is already + // bound at initialization time. + Local args[] = {info.Data()}; + Local ret; + if (!initializer + ->Call(context, Undefined(realm->isolate()), arraysize(args), args) + .ToLocal(&ret)) { + return; + } + info.GetReturnValue().Set(ret); +} + static void PathHelpersLazyGetter(Local name, const PropertyCallbackInfo& info) { Isolate* isolate = info.GetIsolate(); @@ -1361,6 +1409,18 @@ static Maybe DefaultImportMetaObjectInitializer(Realm* realm, return Nothing(); } + // Set a lazy getter of import.meta.sync + Local import_meta_sync_initializer = + realm->host_import_meta_sync_initializer(); + if (!import_meta_sync_initializer.IsEmpty() && + meta->SetLazyDataProperty(context, + FIXED_ONE_BYTE_STRING(isolate, "sync"), + ImportMetaSyncLazyGetter, + url) + .IsNothing()) { + return Nothing(); + } + // Set import.meta.url = moduleWrap.url if (meta->Set(context, env->url_string(), url).IsEmpty()) { return Nothing(); @@ -1629,6 +1689,10 @@ void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data, target, "setImportMetaResolveInitializer", SetImportMetaResolveInitializer); + SetMethod(isolate, + target, + "setImportMetaSyncInitializer", + SetImportMetaSyncInitializer); SetMethod(isolate, target, "createRequiredModuleFacade", @@ -1683,6 +1747,7 @@ void ModuleWrap::RegisterExternalReferences( registry->Register(SetImportModuleDynamicallyCallback); registry->Register(SetInitializeImportMetaObjectCallback); registry->Register(SetImportMetaResolveInitializer); + registry->Register(SetImportMetaSyncInitializer); registry->Register(ThrowIfPromiseRejected); } } // namespace loader diff --git a/src/module_wrap.h b/src/module_wrap.h index 4c18eef502b070..83dd0a42e3b021 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -184,6 +184,8 @@ class ModuleWrap : public BaseObject { const v8::FunctionCallbackInfo& args); static void SetImportMetaResolveInitializer( const v8::FunctionCallbackInfo& args); + static void SetImportMetaSyncInitializer( + const v8::FunctionCallbackInfo& args); static void SetInitializeImportMetaObjectCallback( const v8::FunctionCallbackInfo& args); static v8::MaybeLocal SyntheticModuleEvaluationStepsCallback( diff --git a/test/es-module/test-esm-import-meta-sync.mjs b/test/es-module/test-esm-import-meta-sync.mjs new file mode 100644 index 00000000000000..de1ccb05c66721 --- /dev/null +++ b/test/es-module/test-esm-import-meta-sync.mjs @@ -0,0 +1,253 @@ +import { spawnPromisified } from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert'; +import { describe, it } from 'node:test'; + +describe('import.meta.sync', () => { + it('should synchronously import a simple ESM module', () => { + const simpleModule = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-simple.mjs').href); + assert.strictEqual(simpleModule.value, 42); + assert.strictEqual(typeof simpleModule.greet, 'function'); + assert.strictEqual(simpleModule.greet('World'), 'Hello, World!'); + }); + + it('should synchronously import a builtin module', () => { + const fsModule = import.meta.sync('node:fs'); + assert.strictEqual(typeof fsModule.readFileSync, 'function'); + assert.strictEqual(typeof fsModule.readFile, 'function'); + }); + + it('should throw ERR_MODULE_NOT_FOUND for non-existent modules', () => { + assert.throws(() => { + import.meta.sync(fixtures.fileURL('es-modules', 'does-not-exist.mjs').href); + }, { + code: 'ERR_MODULE_NOT_FOUND', + }); + }); + + it('should throw ERR_REQUIRE_ASYNC_MODULE for modules with TLA', () => { + assert.throws(() => { + import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-tla.mjs').href); + }, { + code: 'ERR_REQUIRE_ASYNC_MODULE', + }); + }); + + it('should return the same namespace for already loaded modules', () => { + const simpleModule1 = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-simple.mjs').href); + const simpleModule2 = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-simple.mjs').href); + // Both should reference the same module namespace + assert.strictEqual(simpleModule1.value, simpleModule2.value); + }); + + it('should synchronously import a CommonJS module', () => { + const cjsModule = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-cjs.cjs').href); + assert.strictEqual(cjsModule.default.cjsValue, 'CJS works'); + }); + + it('should handle relative path resolution', () => { + const simpleModule = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-simple.mjs').href); + assert.ok(simpleModule); + assert.strictEqual(simpleModule.value, 42); + }); + + it('should throw for modules that import modules with TLA', () => { + // This tests that TLA detection works transitively through the module graph + assert.throws(() => { + import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-imports-tla.mjs').href); + }, { + code: 'ERR_REQUIRE_ASYNC_MODULE', + }); + }); + + it('should throw ERR_UNSUPPORTED_DIR_IMPORT for directory imports', () => { + assert.throws(() => { + import.meta.sync(fixtures.fileURL('es-modules').href); + }, { + code: 'ERR_UNSUPPORTED_DIR_IMPORT', + }); + }); + + it('should work with file path', () => { + const filePath = fixtures.path('es-modules', 'test-esm-import-meta-sync-simple.mjs'); + const simpleModule = import.meta.sync(filePath); + assert.strictEqual(simpleModule.value, 42); + assert.strictEqual(typeof simpleModule.greet, 'function'); + }); + + it('should work with relative paths', () => { + const simpleModule = import.meta.sync('../fixtures/es-modules/test-esm-import-meta-sync-simple.mjs'); + assert.strictEqual(simpleModule.value, 42); + assert.strictEqual(simpleModule.greet('Test'), 'Hello, Test!'); + }); + + it('should not import extensionless modules', () => { + const noext = import.meta.sync(fixtures.fileURL('es-modules', 'noext-esm').href); + assert.ok(noext); + }); + + it('should synchronously import TypeScript modules', () => { + const tsModule = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-typescript.ts').href); + assert.strictEqual(tsModule.tsValue, 100); + assert.strictEqual(typeof tsModule.tsGreet, 'function'); + assert.strictEqual(tsModule.tsGreet('Node'), 'Hello from TypeScript, Node!'); + }); + + it('should synchronously import a module that was already imported asynchronously', async () => { + const url = fixtures.fileURL('es-modules', 'stateful.mjs').href; + const asyncNs = await import(url); + const syncNs = import.meta.sync(url); + assert.strictEqual(syncNs, asyncNs); + }); + + it('should return the same namespace when imported sync first then async', async () => { + const url = fixtures.fileURL('es-modules', 'test-esm-ok.mjs').href; + const syncNs = import.meta.sync(url); + const asyncNs = await import(url); + assert.strictEqual(syncNs, asyncNs); + }); + + it('should return a Module Namespace Exotic Object', () => { + const ns = import.meta.sync(fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-simple.mjs').href); + + // Module namespace objects have Symbol.toStringTag === 'Module' + assert.strictEqual(ns[Symbol.toStringTag], 'Module'); + assert.strictEqual(Object.isSealed(ns), true); + }); + + it('should have typeof "function"', () => { + assert.strictEqual(typeof import.meta.sync, 'function'); + }); + + it('should work with bare specifiers for builtins', () => { + const fs1 = import.meta.sync('fs'); + const fs2 = import.meta.sync('node:fs'); + assert.strictEqual(fs1, fs2); + }); + + it('should coerce specifiers to string like import()', () => { + assert.throws(() => { + import.meta.sync(123); + }, { + code: 'ERR_MODULE_NOT_FOUND', + }); + + assert.throws(() => { + import.meta.sync(null); + }, { + code: 'ERR_MODULE_NOT_FOUND', + }); + + assert.throws(() => { + import.meta.sync(undefined); + }, { + code: 'ERR_MODULE_NOT_FOUND', + }); + + assert.throws(() => { + import.meta.sync({}); + }, { + code: 'ERR_MODULE_NOT_FOUND', + }); + }); + + it('should import JSON with import attributes', () => { + const jsonPath = fixtures.path('es-modules', 'import-attrs', 'data.json'); + const jsonNs = import.meta.sync(jsonPath, { with: { type: 'json' } }); + assert.deepStrictEqual(jsonNs.default, { value: 42 }); + }); + + it('should throw ERR_IMPORT_ATTRIBUTE_MISSING when importing JSON without type attribute', () => { + const jsonPath = fixtures.path('es-modules', 'import-attrs', 'data.json'); + assert.throws(() => { + import.meta.sync(jsonPath); + }, { code: 'ERR_IMPORT_ATTRIBUTE_MISSING' }); + }); + + it('should throw ERR_IMPORT_ATTRIBUTE_UNSUPPORTED for unknown attribute keys', () => { + const jsonPath = fixtures.path('es-modules', 'import-attrs', 'data.json'); + assert.throws(() => { + import.meta.sync(jsonPath, { with: { bogus: 'value' } }); + }, { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' }); + }); + + it('should ignore explicit type: "javascript" for ESM (no throw)', () => { + const esmUrl = fixtures.fileURL('es-modules', 'test-esm-import-meta-sync-simple.mjs').href; + const ns = import.meta.sync(esmUrl, { with: { type: 'javascript' } }); + assert.strictEqual(ns.value, 42); + }); + + it('should select the correct default export in package exports', async () => { + const fixtureCwd = fixtures.path('es-modules', 'cond-exports'); + const code = [ + "import assert from 'node:assert';", + "import { createRequire } from 'node:module';", + 'const requireFn = createRequire(import.meta.url);', + "const syncNs = import.meta.sync('cond-pkg');", + "assert.strictEqual(syncNs.which, 'default');", + "const ns = await import('cond-pkg');", + "assert.strictEqual(ns.which, 'default');", + "const req = requireFn('cond-pkg');", + "assert.strictEqual(req.which, 'require');", + ].join(''); + const result = await spawnPromisified(process.execPath, [ + '--no-warnings', + '--input-type=module', + '--eval', + code, + ], { cwd: fixtureCwd }); + + assert.strictEqual(result.stderr, ''); + assert.strictEqual(result.code, 0, result.stdout + result.stderr); + }); + + describe('Module graph combinations (A->B->C)', () => { + it('should import A->B->C when all are sync ESM', () => { + const url = fixtures.fileURL('es-modules', + 'test-esm-import-meta-sync-a-esm-b-esm-c-sync.mjs'); + const a = import.meta.sync(url.href); + assert.strictEqual(a.aValue, 'a-b-esm-sync-c'); + }); + + it('should throw when A->B->C where C has TLA', () => { + const url = fixtures.fileURL('es-modules', + 'test-esm-import-meta-sync-a-esm-b-esm-c-async.mjs'); + assert.throws(() => { + import.meta.sync(url.href); + }, { + code: 'ERR_REQUIRE_ASYNC_MODULE', + }); + }); + + it('should import A(ESM)->B(CJS)', () => { + const url = fixtures.fileURL('es-modules', + 'test-esm-import-meta-sync-a-esm-b-cjs.mjs'); + const a = import.meta.sync(url.href); + assert.strictEqual(a.aValue, 'a-b-cjs-sync'); + }); + + it('should throw when B(ESM)->C(async)', () => { + const url = fixtures.fileURL('es-modules', + 'test-esm-import-meta-sync-b-esm-async.mjs'); + assert.throws(() => { + import.meta.sync(url.href); + }, { + code: 'ERR_REQUIRE_ASYNC_MODULE', + }); + }); + + it('should import B(ESM)->C(sync)', () => { + const url = fixtures.fileURL('es-modules', + 'test-esm-import-meta-sync-b-esm-sync.mjs'); + const b = import.meta.sync(url.href); + assert.strictEqual(b.bValue, 'b-esm-sync-c'); + }); + + it('should import standalone CJS module', () => { + const url = fixtures.fileURL('es-modules', + 'test-esm-import-meta-sync-b-cjs.cjs'); + const b = import.meta.sync(url.href); + assert.strictEqual(b.default.bValue, 'b-cjs-sync'); + }); + }); +}); diff --git a/test/es-module/test-esm-import-meta.mjs b/test/es-module/test-esm-import-meta.mjs index a2575c4d108cc1..769a300252e7d6 100644 --- a/test/es-module/test-esm-import-meta.mjs +++ b/test/es-module/test-esm-import-meta.mjs @@ -3,7 +3,7 @@ import assert from 'assert'; assert.strictEqual(Object.getPrototypeOf(import.meta), null); -const keys = ['dirname', 'filename', 'main', 'resolve', 'url']; +const keys = ['dirname', 'filename', 'main', 'resolve', 'sync', 'url']; assert.deepStrictEqual(Reflect.ownKeys(import.meta), keys); const descriptors = Object.getOwnPropertyDescriptors(import.meta); diff --git a/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/bar.cjs b/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/bar.cjs new file mode 100644 index 00000000000000..f4ff08428074ac --- /dev/null +++ b/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/bar.cjs @@ -0,0 +1 @@ +module.exports = { which: 'require' }; diff --git a/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/foo.js b/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/foo.js new file mode 100644 index 00000000000000..b36d32ce978a65 --- /dev/null +++ b/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/foo.js @@ -0,0 +1 @@ +export const which = 'default'; diff --git a/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/package.json b/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/package.json new file mode 100644 index 00000000000000..8502052f34c2cd --- /dev/null +++ b/test/fixtures/es-modules/cond-exports/node_modules/cond-pkg/package.json @@ -0,0 +1,9 @@ +{ + "name": "cond-pkg", + "version": "1.0.0", + "type": "module", + "exports": { + "require": "./bar.cjs", + "default": "./foo.js" + } +} \ No newline at end of file diff --git a/test/fixtures/es-modules/import-attrs/data.json b/test/fixtures/es-modules/import-attrs/data.json new file mode 100644 index 00000000000000..eba21e696d05cb --- /dev/null +++ b/test/fixtures/es-modules/import-attrs/data.json @@ -0,0 +1,3 @@ +{ + "value": 42 +} \ No newline at end of file diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-cjs.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-cjs.mjs new file mode 100644 index 00000000000000..77c31e5a918909 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-cjs.mjs @@ -0,0 +1,3 @@ +// Module A (ESM) - imports B (CJS) +import { default as b } from './test-esm-import-meta-sync-b-cjs.cjs'; +export const aValue = 'a-' + b.bValue; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-esm-c-async.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-esm-c-async.mjs new file mode 100644 index 00000000000000..b47d264d3e34d3 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-esm-c-async.mjs @@ -0,0 +1,2 @@ +import { bValue } from './test-esm-import-meta-sync-b-esm-async.mjs'; +export const aValue = 'a-' + bValue; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-esm-c-sync.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-esm-c-sync.mjs new file mode 100644 index 00000000000000..a4784e8ed3f4e1 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-a-esm-b-esm-c-sync.mjs @@ -0,0 +1,2 @@ +import { bValue } from './test-esm-import-meta-sync-b-esm-sync.mjs'; +export const aValue = 'a-' + bValue; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-b-cjs.cjs b/test/fixtures/es-modules/test-esm-import-meta-sync-b-cjs.cjs new file mode 100644 index 00000000000000..aa719ae01ed5f5 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-b-cjs.cjs @@ -0,0 +1 @@ +exports.bValue = 'b-cjs-sync'; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-b-esm-async.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-b-esm-async.mjs new file mode 100644 index 00000000000000..a8682a8e4125db --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-b-esm-async.mjs @@ -0,0 +1,2 @@ +import { value } from './test-esm-import-meta-sync-c-async.mjs'; +export const bValue = 'b-esm-' + value; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-b-esm-sync.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-b-esm-sync.mjs new file mode 100644 index 00000000000000..09f7ebc4462947 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-b-esm-sync.mjs @@ -0,0 +1,2 @@ +import { value } from './test-esm-import-meta-sync-c-sync.mjs'; +export const bValue = 'b-esm-' + value; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-c-async.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-c-async.mjs new file mode 100644 index 00000000000000..d84ad2e95d0eea --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-c-async.mjs @@ -0,0 +1,2 @@ +await Promise.resolve(); +export const value = 'async-c'; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-c-sync.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-c-sync.mjs new file mode 100644 index 00000000000000..ad65bd8ee389bf --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-c-sync.mjs @@ -0,0 +1 @@ +export const value = 'sync-c'; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-cjs.cjs b/test/fixtures/es-modules/test-esm-import-meta-sync-cjs.cjs new file mode 100644 index 00000000000000..90dfc56fdecc5b --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-cjs.cjs @@ -0,0 +1 @@ +exports.cjsValue = 'CJS works'; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-imports-tla.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-imports-tla.mjs new file mode 100644 index 00000000000000..283089793aa527 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-imports-tla.mjs @@ -0,0 +1,3 @@ +import './test-esm-import-meta-sync-tla.mjs'; + +export const value = 'imports tla'; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-simple.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-simple.mjs new file mode 100644 index 00000000000000..72439c146c1f24 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-simple.mjs @@ -0,0 +1,4 @@ +export const value = 42; +export function greet(name) { + return `Hello, ${name}!`; +} diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-tla.mjs b/test/fixtures/es-modules/test-esm-import-meta-sync-tla.mjs new file mode 100644 index 00000000000000..fab2eac1224bb5 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-tla.mjs @@ -0,0 +1,2 @@ +await Promise.resolve(); +export const value = 'async'; diff --git a/test/fixtures/es-modules/test-esm-import-meta-sync-typescript.ts b/test/fixtures/es-modules/test-esm-import-meta-sync-typescript.ts new file mode 100644 index 00000000000000..7dd9e660d584e3 --- /dev/null +++ b/test/fixtures/es-modules/test-esm-import-meta-sync-typescript.ts @@ -0,0 +1,5 @@ +export const tsValue: number = 100; + +export function tsGreet(name: string): string { + return `Hello from TypeScript, ${name}!`; +}