| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 76e3c8a commit aa657f0
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,15 +35,15 @@ function expectFsNamespace(result) { | |||
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | 37 | // For direct use of import expressions inside of CJS or ES modules, including | |
| 38 | - // via eval, all kinds of specifiers should work without issue. | ||
| 38 | + // via direct/indirect eval, all kinds of specifiers should work without issue. | ||
| 39 | 39 | (function testScriptOrModuleImport() { | |
| 40 | - // Importing another file, both direct & via eval | ||
| 40 | + // Importing another file, both direct & via direct eval | ||
| 41 | 41 | // expectOkNamespace(import(relativePath)); | |
| 42 | 42 | expectOkNamespace(eval(`import("${relativePath}")`)); | |
| 43 | 43 | expectOkNamespace(eval(`import("${relativePath}")`)); | |
| 44 | 44 | expectOkNamespace(eval(`import(${JSON.stringify(targetURL)})`)); | |
| 45 | 45 | ||
| 46 | - // Importing a built-in, both direct & via eval | ||
| 46 | + // Importing a built-in, both direct & via direct eval | ||
| 47 | 47 | expectFsNamespace(import('fs')); | |
| 48 | 48 | expectFsNamespace(eval('import("fs")')); | |
| 49 | 49 | expectFsNamespace(eval('import("fs")')); | |
@@ -70,6 +70,8 @@ function expectFsNamespace(result) { | |||
| 70 | 70 | // be treated as a file: URL. | |
| 71 | 71 | expectOkNamespace(import(targetURL.pathname)); | |
| 72 | 72 | ||
| 73 | + // Import with an indirect eval. In this case, the referrer is null and | ||
| 74 | + // defaults to the realm record. | ||
| 73 | 75 | // If the referrer is a realm record, there is no way to resolve the | |
| 74 | 76 | // specifier. | |
| 75 | 77 | // TODO(legendecas): https://github.com/tc39/ecma262/pull/3195 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,73 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + /** | ||
| 3 | + * This test verifies that dynamic import in an indirect eval without JS stacks. | ||
| 4 | + * In this case, the referrer for the dynamic import will be null and the main | ||
| 5 | + * context default loader in createContext() resolves to cwd. | ||
| 6 | + * | ||
| 7 | + * Caveat: this test can be unstable if the loader internals are changed and performs | ||
| 8 | + * microtasks with a JS stack (e.g. with CallbackScope). In this case, the | ||
| 9 | + * referrer will be resolved to the top JS stack frame `node:internal/process/task_queues.js`. | ||
| 10 | + * This is due to the implementation detail of how V8 finds the referrer for a dynamic import | ||
| 11 | + * call. | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | + const common = require('../common'); | ||
| 15 | + | ||
| 16 | + // Can't process.chdir() in worker. | ||
| 17 | + const { isMainThread } = require('worker_threads'); | ||
| 18 | + | ||
| 19 | + if (!isMainThread) { | ||
| 20 | + common.skip('This test only works on a main thread'); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + const tmpdir = require('../common/tmpdir'); | ||
| 24 | + const fixtures = require('../common/fixtures'); | ||
| 25 | + const fs = require('node:fs'); | ||
| 26 | + const { | ||
| 27 | + Script, | ||
| 28 | + createContext, | ||
| 29 | + constants: { USE_MAIN_CONTEXT_DEFAULT_LOADER }, | ||
| 30 | + } = require('node:vm'); | ||
| 31 | + const assert = require('node:assert'); | ||
| 32 | + | ||
| 33 | + common.expectWarning('ExperimentalWarning', | ||
| 34 | + 'vm.USE_MAIN_CONTEXT_DEFAULT_LOADER is an experimental feature and might change at any time'); | ||
| 35 | + assert( | ||
| 36 | + !process.execArgv.includes('--experimental-vm-modules'), | ||
| 37 | + 'This test must be run without --experimental-vm-modules'); | ||
| 38 | + assert.strictEqual(typeof USE_MAIN_CONTEXT_DEFAULT_LOADER, 'symbol'); | ||
| 39 | + | ||
| 40 | + async function main() { | ||
| 41 | + tmpdir.refresh(); | ||
| 42 | + process.chdir(tmpdir.path); | ||
| 43 | + | ||
| 44 | + // | ||
| 45 | + { | ||
| 46 | + const options = { | ||
| 47 | + importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER, | ||
| 48 | + }; | ||
| 49 | + const ctx = createContext({}, options); | ||
| 50 | + const s = new Script('Promise.resolve("import(\'./message.mjs\')").then(eval)', { | ||
| 51 | + importModuleDynamically: common.mustNotCall(), | ||
| 52 | + }); | ||
| 53 | + await assert.rejects(s.runInContext(ctx), { code: 'ERR_MODULE_NOT_FOUND' }); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + const moduleUrl = fixtures.fileURL('es-modules', 'message.mjs'); | ||
| 57 | + fs.copyFileSync(moduleUrl, tmpdir.resolve('message.mjs')); | ||
| 58 | + { | ||
| 59 | + const options = { | ||
| 60 | + importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER, | ||
| 61 | + }; | ||
| 62 | + const ctx = createContext({}, options); | ||
| 63 | + const moduleUrl = fixtures.fileURL('es-modules', 'message.mjs'); | ||
| 64 | + const namespace = await import(moduleUrl.href); | ||
| 65 | + const script = new Script('Promise.resolve("import(\'./message.mjs\')").then(eval)', { | ||
| 66 | + importModuleDynamically: common.mustNotCall(), | ||
| 67 | + }); | ||
| 68 | + const result = await script.runInContext(ctx); | ||
| 69 | + assert.deepStrictEqual(result, namespace); | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + main().catch(common.mustNotCall()); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,7 +16,6 @@ const fs = require('fs'); | |||
| 16 | 16 | const { | |
| 17 | 17 | compileFunction, | |
| 18 | 18 | Script, | |
| 19 | - createContext, | ||
| 20 | 19 | constants: { USE_MAIN_CONTEXT_DEFAULT_LOADER }, | |
| 21 | 20 | } = require('vm'); | |
| 22 | 21 | const assert = require('assert'); | |
@@ -112,34 +111,8 @@ async function main() { | |||
| 112 | 111 | await testNotFoundErrors(undefinedOptions); | |
| 113 | 112 | await testNotFoundErrors(nonPathOptions); | |
| 114 | 113 | ||
| 115 | - // createContext() with null referrer also resolves to cwd. | ||
| 116 | - { | ||
| 117 | - const options = { | ||
| 118 | - importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER, | ||
| 119 | - }; | ||
| 120 | - const ctx = createContext({}, options); | ||
| 121 | - const s = new Script('Promise.resolve("import(\'./message.mjs\')").then(eval)', { | ||
| 122 | - importModuleDynamically: common.mustNotCall(), | ||
| 123 | - }); | ||
| 124 | - await assert.rejects(s.runInContext(ctx), { code: 'ERR_MODULE_NOT_FOUND' }); | ||
| 125 | - } | ||
| 126 | - | ||
| 127 | 114 | await testLoader(undefinedOptions); | |
| 128 | 115 | await testLoader(nonPathOptions); | |
| 129 | - | ||
| 130 | - { | ||
| 131 | - const options = { | ||
| 132 | - importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER, | ||
| 133 | - }; | ||
| 134 | - const ctx = createContext({}, options); | ||
| 135 | - const moduleUrl = fixtures.fileURL('es-modules', 'message.mjs'); | ||
| 136 | - const namespace = await import(moduleUrl.href); | ||
| 137 | - const script = new Script('Promise.resolve("import(\'./message.mjs\')").then(eval)', { | ||
| 138 | - importModuleDynamically: common.mustNotCall(), | ||
| 139 | - }); | ||
| 140 | - const result = await script.runInContext(ctx); | ||
| 141 | - assert.deepStrictEqual(result, namespace); | ||
| 142 | - } | ||
| 143 | 116 | } | |
| 144 | 117 | } | |
| 145 | 118 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,6 +3,18 @@ import * as common from '../common/index.mjs'; | |||
| 3 | 3 | import assert from 'node:assert'; | |
| 4 | 4 | import { Script, SourceTextModule, createContext } from 'node:vm'; | |
| 5 | 5 | ||
| 6 | + /** | ||
| 7 | + * This test verifies that dynamic import in an indirect eval without JS stacks. | ||
| 8 | + * In this case, the referrer for the dynamic import will be null and the | ||
| 9 | + * per-context importModuleDynamically callback will be invoked. | ||
| 10 | + * | ||
| 11 | + * Caveat: this test can be unstable if the loader internals are changed and performs | ||
| 12 | + * microtasks with a JS stack (e.g. with CallbackScope). In this case, the | ||
| 13 | + * referrer will be resolved to the top JS stack frame `node:internal/process/task_queues.js`. | ||
| 14 | + * This is due to the implementation detail of how V8 finds the referrer for a dynamic import | ||
| 15 | + * call. | ||
| 16 | + */ | ||
| 17 | + | ||
| 6 | 18 | async function test() { | |
| 7 | 19 | const foo = new SourceTextModule('export const a = 1;'); | |
| 8 | 20 | await foo.link(common.mustNotCall()); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments