GeezerVison is showing github.com — module: add dynamic file-specific ESM warnings · nodejs/node@718305d
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: src/node_contextify.cc +14-8Lines changed: 14 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1702,13 +1702,19 @@ static MaybeLocal<Function> CompileFunctionForCJSLoader( | 1702 | 1702 | return scope.Escape(fn); | 1703 | 1703 | } | 1704 | 1704 |
| | 1705 | +static std::string GetRequireEsmWarning(Local<String> filename) { | | 1706 | + Isolate* isolate = Isolate::GetCurrent(); | | 1707 | + Utf8Value filename_utf8(isolate, filename); | | 1708 | + | | 1709 | + std::string warning_message = | | 1710 | + "Failed to load the ES module: " + filename_utf8.ToString() + | | 1711 | + ". Make sure to set \"type\": \"module\" in the nearest package.json " | | 1712 | + "file " | | 1713 | + "or use the .mjs extension."; | | 1714 | + return warning_message; | | 1715 | +} | | 1716 | + | 1705 | 1717 | static bool warned_about_require_esm = false; | 1706 | | -// TODO(joyeecheung): this was copied from the warning previously emitted in the | 1707 | | -// JS land, but it's not very helpful. There should be specific information | 1708 | | -// about which file or which package.json to update. | 1709 | | -const char* require_esm_warning = | 1710 | | - "To load an ES module, set \"type\": \"module\" in the package.json or use " | 1711 | | - "the .mjs extension."; | 1712 | 1718 |
| 1713 | 1719 | static bool ShouldRetryAsESM(Realm* realm, | 1714 | 1720 | Local<String> message, | @@ -1794,8 +1800,8 @@ static void CompileFunctionForCJSLoader( | 1794 | 1800 | // This needs to call process.emit('warning') in JS which can throw if | 1795 | 1801 | // the user listener throws. In that case, don't try to throw the syntax | 1796 | 1802 | // error. | 1797 | | - should_throw = | 1798 | | - ProcessEmitWarningSync(env, require_esm_warning).IsJust(); | | 1803 | + std::string warning_message = GetRequireEsmWarning(filename); | | 1804 | + should_throw = ProcessEmitWarningSync(env, warning_message).IsJust(); | 1799 | 1805 | } | 1800 | 1806 | if (should_throw) { | 1801 | 1807 | isolate->ThrowException(cjs_exception); | |
Collapse file Copy file name to clipboardExpand all lines: src/node_process_events.cc +9-1Lines changed: 9 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -13,6 +13,7 @@ using v8::Just; | 13 | 13 | using v8::Local; | 14 | 14 | using v8::Maybe; | 15 | 15 | using v8::MaybeLocal; | | 16 | +using v8::NewStringType; | 16 | 17 | using v8::Nothing; | 17 | 18 | using v8::Object; | 18 | 19 | using v8::String; | @@ -21,7 +22,14 @@ using v8::Value; | 21 | 22 | Maybe<bool> ProcessEmitWarningSync(Environment* env, std::string_view message) { | 22 | 23 | Isolate* isolate = env->isolate(); | 23 | 24 | Local<Context> context = env->context(); | 24 | | - Local<String> message_string = OneByteString(isolate, message); | | 25 | + Local<String> message_string; | | 26 | + if (!String::NewFromUtf8(isolate, | | 27 | + message.data(), | | 28 | + NewStringType::kNormal, | | 29 | + static_cast<int>(message.size())) | | 30 | + .ToLocal(&message_string)) { | | 31 | + return Nothing<bool>(); | | 32 | + } | 25 | 33 |
| 26 | 34 | Local<Value> argv[] = {message_string}; | 27 | 35 | Local<Function> emit_function = env->process_emit_warning_sync(); | |
Collapse file Copy file name to clipboardExpand all lines: test/es-module/test-esm-cjs-load-error-note.mjs +1-2Lines changed: 1 addition & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -4,11 +4,10 @@ import assert from 'node:assert'; | 4 | 4 | import { execPath } from 'node:process'; | 5 | 5 | import { describe, it } from 'node:test'; | 6 | 6 |
| 7 | | - | 8 | 7 | // Expect note to be included in the error output | 9 | 8 | // Don't match the following sentence because it can change as features are | 10 | 9 | // added. | 11 | | -const expectedNote = 'Warning: To load an ES module'; | | 10 | +const expectedNote = 'Failed to load the ES module'; | 12 | 11 |
| 13 | 12 | const mustIncludeMessage = { | 14 | 13 | getMessage: (stderr) => `${expectedNote} not found in ${stderr}`, | |
Collapse file Copy file name to clipboardExpand all lines: test/es-module/test-esm-long-path-win.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -182,7 +182,7 @@ describe('long path on Windows', () => { | 182 | 182 | fs.writeFileSync(cjsIndexJSPath, 'import fs from "node:fs/promises";'); | 183 | 183 | const { code, signal, stderr } = await spawnPromisified(execPath, [cjsIndexJSPath]); | 184 | 184 |
| 185 | | - assert.ok(stderr.includes('Warning: To load an ES module')); | | 185 | + assert.ok(stderr.includes('Failed to load the ES module')); | 186 | 186 | assert.strictEqual(code, 1); | 187 | 187 | assert.strictEqual(signal, null); | 188 | 188 | }); | |
Collapse file Copy file name to clipboardExpand all lines: test/es-module/test-typescript-commonjs.mjs +30-8Lines changed: 30 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | import { skip, spawnPromisified } from '../common/index.mjs'; | 2 | 2 | import * as fixtures from '../common/fixtures.mjs'; | 3 | | -import { match, strictEqual } from 'node:assert'; | | 3 | +import assert, { match, strictEqual } from 'node:assert'; | 4 | 4 | import { test } from 'node:test'; | 5 | 5 |
| 6 | 6 | if (!process.config.variables.node_use_amaro) skip('Requires Amaro'); | @@ -59,13 +59,35 @@ test('require a .ts file with implicit extension fails', async () => { | 59 | 59 | }); | 60 | 60 |
| 61 | 61 | test('expect failure of an .mts file with CommonJS syntax', async () => { | 62 | | - const result = await spawnPromisified(process.execPath, [ | 63 | | - fixtures.path('typescript/cts/test-cts-but-module-syntax.cts'), | 64 | | - ]); | 65 | | - | 66 | | - strictEqual(result.stdout, ''); | 67 | | - match(result.stderr, /To load an ES module, set "type": "module" in the package\.json or use the \.mjs extension\./); | 68 | | - strictEqual(result.code, 1); | | 62 | + const testFilePath = fixtures.path( | | 63 | + 'typescript/cts/test-cts-but-module-syntax.cts' | | 64 | + ); | | 65 | + const result = await spawnPromisified(process.execPath, [testFilePath]); | | 66 | + | | 67 | + assert.strictEqual(result.stdout, ''); | | 68 | + | | 69 | + const expectedWarning = `Failed to load the ES module: ${testFilePath}. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.`; | | 70 | + | | 71 | + try { | | 72 | + assert.ok( | | 73 | + result.stderr.includes(expectedWarning), | | 74 | + `Expected stderr to include: ${expectedWarning}` | | 75 | + ); | | 76 | + } catch (e) { | | 77 | + if (e?.code === 'ERR_ASSERTION') { | | 78 | + assert.match( | | 79 | + result.stderr, | | 80 | + /Failed to load the ES module:.*test-cts-but-module-syntax\.cts/ | | 81 | + ); | | 82 | + e.expected = expectedWarning; | | 83 | + e.actual = result.stderr; | | 84 | + e.operator = 'includes'; | | 85 | + } | | 86 | + throw e; | | 87 | + } | | 88 | + | | 89 | + | | 90 | + assert.strictEqual(result.code, 1); | 69 | 91 | }); | 70 | 92 |
| 71 | 93 | test('execute a .cts file importing a .cts file', async () => { | |
|