From 44aa27292dece1911a8c9691cf1b0e9b2c3ad306 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Tue, 19 Mar 2024 16:19:48 +0800 Subject: [PATCH] lib: cache source maps in vm sources Cache source maps found in sources parsed with `vm.Script`, `vm.compileFunction`, and `vm.SourceTextModule`. Also, retrieve source url from V8 parsing results. Not like filenames returned by `CallSite.getFileName()` in translating stack traces, when generating source lines prepended to exceptions, only resource names can be used as an index to find source maps, which can be source url magic comments instead. Source url magic comments can be either a file path or a URL. To verify that source urls with absolute file paths in the source lines are correctly translated, snapshots should include the full snapshot urls rather than neutralizing all the path strings in the stack traces. --- lib/internal/modules/cjs/loader.js | 6 ++-- lib/internal/modules/esm/loader.js | 2 +- lib/internal/modules/esm/translators.js | 4 +-- lib/internal/source_map/source_map_cache.js | 13 +++---- lib/internal/vm.js | 2 ++ lib/internal/vm/module.js | 2 ++ lib/vm.js | 2 ++ src/env_properties.h | 1 + src/module_wrap.cc | 7 ++++ src/node_contextify.cc | 20 +++++++++++ src/node_errors.cc | 19 +++++++++-- test/common/assertSnapshot.js | 30 ++++++++++++++-- .../source_map_disabled_by_api.snapshot | 20 +++++------ .../output/source_map_enabled_by_api.snapshot | 20 +++++------ .../source_map_enclosing_function.snapshot | 12 +++---- .../source-map/output/source_map_eval.js | 1 + .../output/source_map_eval.snapshot | 8 ++--- .../output/source_map_no_source_file.snapshot | 6 ++-- .../source_map_prepare_stack_trace.snapshot | 16 ++++----- .../source_map_reference_error_tabs.snapshot | 6 ++-- ...urce_map_sourcemapping_url_string.snapshot | 2 +- .../output/source_map_throw_catch.snapshot | 4 +-- .../source_map_throw_first_tick.snapshot | 6 ++-- .../output/source_map_throw_icu.snapshot | 6 ++-- .../source_map_throw_set_immediate.snapshot | 8 ++--- .../output/source_map_vm_function.js | 18 ++++++++++ .../output/source_map_vm_function.snapshot | 11 ++++++ .../source-map/output/source_map_vm_module.js | 22 ++++++++++++ .../output/source_map_vm_module.snapshot | 11 ++++++ .../source-map/output/source_map_vm_script.js | 28 +++++++++++++++ .../output/source_map_vm_script.snapshot | 20 +++++++++++ test/fixtures/source-map/tabs.coffee | 5 +++ test/fixtures/source-map/tabs.js | 9 +++-- test/parallel/test-node-output-sourcemaps.mjs | 34 ++++++++----------- test/parallel/test-runner-output.mjs | 4 +-- 35 files changed, 284 insertions(+), 101 deletions(-) create mode 100644 test/fixtures/source-map/output/source_map_vm_function.js create mode 100644 test/fixtures/source-map/output/source_map_vm_function.snapshot create mode 100644 test/fixtures/source-map/output/source_map_vm_module.js create mode 100644 test/fixtures/source-map/output/source_map_vm_module.snapshot create mode 100644 test/fixtures/source-map/output/source_map_vm_script.js create mode 100644 test/fixtures/source-map/output/source_map_vm_script.snapshot diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 22e77d8bff70c0..418f672e34c24e 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1308,9 +1308,9 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache) { ); // Cache the source map for the module if present. - const { sourceMapURL } = script; + const { sourceMapURL, sourceURL } = script; if (sourceMapURL) { - maybeCacheSourceMap(filename, content, this, false, undefined, sourceMapURL); + maybeCacheSourceMap(filename, content, this, false, sourceURL, sourceMapURL); } return { @@ -1332,7 +1332,7 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache) { // Cache the source map for the module if present. if (result.sourceMapURL) { - maybeCacheSourceMap(filename, content, this, false, undefined, result.sourceMapURL); + maybeCacheSourceMap(filename, content, this, false, result.sourceURL, result.sourceMapURL); } return result; diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 85c4960c8e3b11..a5fa374936353c 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -280,7 +280,7 @@ class ModuleLoader { const wrap = new ModuleWrap(url, undefined, source, 0, 0); // Cache the source map for the module if present. if (wrap.sourceMapURL) { - maybeCacheSourceMap(url, source, null, false, undefined, wrap.sourceMapURL); + maybeCacheSourceMap(url, source, null, false, wrap.sourceURL, wrap.sourceMapURL); } const { registerModule } = require('internal/modules/esm/utils'); // TODO(joyeecheung): refactor so that the default options are shared across diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 7312bd0b09f41a..1552d1ef6f841d 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -177,7 +177,7 @@ translators.set('module', function moduleStrategy(url, source, isMain) { const module = new ModuleWrap(url, undefined, source, 0, 0); // Cache the source map for the module if present. if (module.sourceMapURL) { - maybeCacheSourceMap(url, source, null, false, undefined, module.sourceMapURL); + maybeCacheSourceMap(url, source, null, false, module.sourceURL, module.sourceMapURL); } const { registerModule } = require('internal/modules/esm/utils'); registerModule(module, { @@ -227,7 +227,7 @@ function loadCJSModule(module, source, url, filename) { } // Cache the source map for the cjs module if present. if (compileResult.sourceMapURL) { - maybeCacheSourceMap(url, source, null, false, undefined, compileResult.sourceMapURL); + maybeCacheSourceMap(url, source, null, false, compileResult.sourceURL, compileResult.sourceMapURL); } const compiledWrapper = compileResult.function; diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 53c3374fc09176..25fe56e6c38926 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -123,10 +123,10 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo return; } - // FIXME: callers should obtain sourceURL from v8 and pass it - // rather than leaving it undefined and extract by regex. - if (sourceURL === undefined) { - sourceURL = extractSourceURLMagicComment(content); + if (sourceURL !== undefined) { + // SourceURL magic comment content might be a file path or URL. + // Normalize the sourceURL to be a file URL if it is a file path. + sourceURL = normalizeReferrerURL(sourceURL); } const data = dataFromUrl(filename, sourceMapURL); @@ -149,9 +149,6 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo sourceURL, }; generatedSourceMapCache.set(filename, entry); - if (sourceURL) { - generatedSourceMapCache.set(sourceURL, entry); - } } else { // If there is no cjsModuleInstance and is not generated source assume we are in a // "modules/esm" context. @@ -178,7 +175,7 @@ function maybeCacheGeneratedSourceMap(content) { return; } try { - maybeCacheSourceMap(sourceURL, content, null, true, sourceURL); + maybeCacheSourceMap(sourceURL, content, null, true); } catch (err) { // This can happen if the filename is not a valid URL. // If we fail to cache the source map, we should not fail the whole process. diff --git a/lib/internal/vm.js b/lib/internal/vm.js index 0b9865ea9a0cf6..cc0cdd54ed7414 100644 --- a/lib/internal/vm.js +++ b/lib/internal/vm.js @@ -25,6 +25,7 @@ const { const { getOptionValue, } = require('internal/options'); +const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache'); const { privateSymbols: { contextify_context_private_symbol, @@ -151,6 +152,7 @@ function internalCompileFunction( } registerImportModuleDynamically(result.function, importModuleDynamically); + maybeCacheSourceMap(filename, code, result.function, false, result.sourceURL, result.sourceMapURL); return result; } diff --git a/lib/internal/vm/module.js b/lib/internal/vm/module.js index cd4f3a65f8466c..b8ae4e10bda33a 100644 --- a/lib/internal/vm/module.js +++ b/lib/internal/vm/module.js @@ -77,6 +77,7 @@ const kPerContextModuleId = Symbol('kPerContextModuleId'); const kLink = Symbol('kLink'); const { isContext } = require('internal/vm'); +const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache'); function isModule(object) { if (typeof object !== 'object' || object === null || !ObjectPrototypeHasOwnProperty(object, kWrap)) { @@ -141,6 +142,7 @@ class Module { importModuleDynamicallyWrap(options.importModuleDynamically) : undefined, }; + maybeCacheSourceMap(identifier, sourceText, this, false, this[kWrap].sourceURL, this[kWrap].sourceMapURL); } else { assert(syntheticEvaluationSteps); this[kWrap] = new ModuleWrap(identifier, context, diff --git a/lib/vm.js b/lib/vm.js index 34814c430d3253..138b2118eaa359 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -63,6 +63,7 @@ const { isContext: _isContext, registerImportModuleDynamically, } = require('internal/vm'); +const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache'); const { vm_dynamic_import_main_context_default, } = internalBinding('symbols'); @@ -126,6 +127,7 @@ class Script extends ContextifyScript { } registerImportModuleDynamically(this, importModuleDynamically); + maybeCacheSourceMap(filename, code, this, false, this.sourceURL, this.sourceMapURL); } runInThisContext(options) { diff --git a/src/env_properties.h b/src/env_properties.h index 05d8fcf576c51a..287e669012e2d8 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -300,6 +300,7 @@ V(sni_context_string, "sni_context") \ V(source_string, "source") \ V(source_map_url_string, "sourceMapURL") \ + V(source_url_string, "sourceURL") \ V(stack_string, "stack") \ V(standard_name_string, "standardName") \ V(start_time_string, "startTime") \ diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 92b34f5a8b99c2..b5f05a6b62dfc4 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -265,6 +265,13 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { return; } + if (that->Set(context, + realm->env()->source_url_string(), + module->GetUnboundModuleScript()->GetSourceURL()) + .IsNothing()) { + return; + } + if (that->Set(context, realm->env()->source_map_url_string(), module->GetUnboundModuleScript()->GetSourceMappingURL()) diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 0f94ea501cea64..f317b1301dd2fb 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -905,6 +905,13 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { return; } + if (args.This() + ->Set(env->context(), + env->source_url_string(), + v8_script->GetSourceURL()) + .IsNothing()) + return; + if (args.This() ->Set(env->context(), env->source_map_url_string(), @@ -1373,6 +1380,15 @@ Local ContextifyContext::CompileFunctionAndCacheResult( Local result = Object::New(isolate); if (result->Set(parsing_context, env->function_string(), fn).IsNothing()) return Object::New(env->isolate()); + + // ScriptOrigin::ResourceName() returns SourceURL magic comment content if + // present. + if (result + ->Set(parsing_context, + env->source_url_string(), + fn->GetScriptOrigin().ResourceName()) + .IsNothing()) + return Object::New(env->isolate()); if (result ->Set(parsing_context, env->source_map_url_string(), @@ -1650,11 +1666,15 @@ static void CompileFunctionForCJSLoader( std::vector> names = { env->cached_data_rejected_string(), env->source_map_url_string(), + env->source_url_string(), env->function_string(), }; std::vector> values = { Boolean::New(isolate, cache_rejected), fn->GetScriptOrigin().SourceMapUrl(), + // ScriptOrigin::ResourceName() returns SourceURL magic comment content if + // present. + fn->GetScriptOrigin().ResourceName(), fn, }; Local result = Object::New( diff --git a/src/node_errors.cc b/src/node_errors.cc index ff091fd20d915b..4b560b8b4feffc 100644 --- a/src/node_errors.cc +++ b/src/node_errors.cc @@ -57,7 +57,20 @@ static std::string GetSourceMapErrorSource(Isolate* isolate, bool* added_exception_line) { v8::TryCatch try_catch(isolate); HandleScope handle_scope(isolate); - Environment* env = Environment::GetCurrent(context); + Realm* realm = Realm::GetCurrent(context); + + Local get_source; + if (realm != nullptr) { + // If we are in a Realm, call the realm specific getSourceMapErrorSource + // callback to avoid passing the JS objects (the exception and trace) across + // the realm boundary. + get_source = realm->get_source_map_error_source(); + } else { + Environment* env = Environment::GetCurrent(context); + // The context is created with ContextifyContext, call the principal + // realm's getSourceMapErrorSource callback. + get_source = env->principal_realm()->get_source_map_error_source(); + } // The ScriptResourceName of the message may be different from the one we use // to compile the script. V8 replaces it when it detects magic comments in @@ -69,8 +82,8 @@ static std::string GetSourceMapErrorSource(Isolate* isolate, Local argv[] = {script_resource_name, v8::Int32::New(isolate, linenum), v8::Int32::New(isolate, columnum)}; - MaybeLocal maybe_ret = env->get_source_map_error_source()->Call( - context, Undefined(isolate), arraysize(argv), argv); + MaybeLocal maybe_ret = + get_source->Call(context, Undefined(isolate), arraysize(argv), argv); Local ret; if (!maybe_ret.ToLocal(&ret)) { // Ignore the caught exceptions. diff --git a/test/common/assertSnapshot.js b/test/common/assertSnapshot.js index 88f40281e069b7..cb3b9fd332b24b 100644 --- a/test/common/assertSnapshot.js +++ b/test/common/assertSnapshot.js @@ -8,6 +8,11 @@ const assert = require('node:assert/strict'); const stackFramesRegexp = /(?<=\n)(\s+)((.+?)\s+\()?(?:\(?(.+?):(\d+)(?::(\d+))?)\)?(\s+\{)?(\[\d+m)?(\n|$)/g; const windowNewlineRegexp = /\r/g; +function replaceExperimentalWarning(str) { + return str.replace(/\(node:\d+\) ExperimentalWarning: (.*)\n/g, '') + .replace('(Use `node --trace-warnings ...` to show where the warning was created)\n', ''); +} + function replaceNodeVersion(str) { return str.replaceAll(process.version, '*'); } @@ -16,6 +21,10 @@ function replaceStackTrace(str, replacement = '$1*$7$8\n') { return str.replace(stackFramesRegexp, replacement); } +function replaceInternalStackTrace(str) { + return str.replaceAll(/(\W+).*node:internal.*/g, '$1*'); +} + function replaceWindowsLineEndings(str) { return str.replace(windowNewlineRegexp, ''); } @@ -24,8 +33,20 @@ function replaceWindowsPaths(str) { return common.isWindows ? str.replaceAll(path.win32.sep, path.posix.sep) : str; } -function replaceFullPaths(str) { - return str.replaceAll(process.cwd(), ''); +function replaceWindowsDriveLetter(str) { + if (!common.isWindows) { + return str; + } + const currentDriveLetter = path.parse(process.cwd()).root.substring(0, 1).toLowerCase(); + const regex = new RegExp(`${currentDriveLetter}:`, 'gi'); + return str.replaceAll(regex, ''); +} + +function transformCwd(replacement = '') { + const cwd = process.cwd(); + return (str) => { + return str.replaceAll(cwd, replacement); + }; } function transform(...args) { @@ -87,11 +108,14 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ... module.exports = { assertSnapshot, getSnapshotPath, - replaceFullPaths, + replaceExperimentalWarning, replaceNodeVersion, replaceStackTrace, + replaceInternalStackTrace, replaceWindowsLineEndings, replaceWindowsPaths, + replaceWindowsDriveLetter, spawnAndAssert, transform, + transformCwd, }; diff --git a/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot b/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot index 655cd6695e1116..f538904873393e 100644 --- a/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot +++ b/test/fixtures/source-map/output/source_map_disabled_by_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) diff --git a/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot b/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot index 082b3f310ed4f9..9fe43a29865b35 100644 --- a/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot +++ b/test/fixtures/source-map/output/source_map_enabled_by_api.snapshot @@ -1,12 +1,12 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionC (*enclosing-call-site-min.js:1:97) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionC (*/test/fixtures/source-map/enclosing-call-site-min.js:1:97) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_enclosing_function.snapshot b/test/fixtures/source-map/output/source_map_enclosing_function.snapshot index 976cd4fdbbc6e9..b60f988be3214e 100644 --- a/test/fixtures/source-map/output/source_map_enclosing_function.snapshot +++ b/test/fixtures/source-map/output/source_map_enclosing_function.snapshot @@ -1,13 +1,13 @@ -*enclosing-call-site.js:26 +*/test/fixtures/source-map/enclosing-call-site.js:26 throw err ^ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionC (*enclosing-call-site.js:10:3) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionC (*/test/fixtures/source-map/enclosing-call-site.js:10:3) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Node.js * diff --git a/test/fixtures/source-map/output/source_map_eval.js b/test/fixtures/source-map/output/source_map_eval.js index 5492c179248180..5270de68826103 100644 --- a/test/fixtures/source-map/output/source_map_eval.js +++ b/test/fixtures/source-map/output/source_map_eval.js @@ -7,4 +7,5 @@ Error.stackTraceLimit = 3; const fs = require('fs'); const content = fs.readFileSync(require.resolve('../tabs.js'), 'utf8'); +// SourceURL magic comment is hardcoded in the source content. eval(content); diff --git a/test/fixtures/source-map/output/source_map_eval.snapshot b/test/fixtures/source-map/output/source_map_eval.snapshot index a4fcdb25282dfa..87afb545b56636 100644 --- a/test/fixtures/source-map/output/source_map_eval.snapshot +++ b/test/fixtures/source-map/output/source_map_eval.snapshot @@ -1,11 +1,11 @@ -*tabs.coffee:26 +/synthethized/workspace/tabs.coffee:26 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object.eval (*tabs.coffee:26:2) - at eval (*tabs.coffee:1:14) - at Object. (*output*source_map_eval.js:10:1) + at Object.eval (/synthethized/workspace/tabs.coffee:26:2) + at eval (/synthethized/workspace/tabs.coffee:1:14) + at Object. (*/test/fixtures/source-map/output/source_map_eval.js:11:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_no_source_file.snapshot b/test/fixtures/source-map/output/source_map_no_source_file.snapshot index cf9329747ba692..6d0e0cf6db727e 100644 --- a/test/fixtures/source-map/output/source_map_no_source_file.snapshot +++ b/test/fixtures/source-map/output/source_map_no_source_file.snapshot @@ -1,9 +1,9 @@ -*no-source.js:2 +*/test/fixtures/source-map/no-source.js:2 throw new Error('foo'); ^ Error: foo - at Throw (*file-not-exists.ts:2:9) - at Object. (*file-not-exists.ts:5:1) + at Throw (*/test/fixtures/source-map/file-not-exists.ts:2:9) + at Object. (*/test/fixtures/source-map/file-not-exists.ts:5:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot b/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot index 9e9740a26fc34e..57bac36a2e5214 100644 --- a/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot +++ b/test/fixtures/source-map/output/source_map_prepare_stack_trace.snapshot @@ -1,10 +1,10 @@ Error: an error! - at functionD (*enclosing-call-site.js:16:17) - at functionB (*enclosing-call-site.js:6:3) - at functionA (*enclosing-call-site.js:2:3) - at Object. (*enclosing-call-site.js:24:3) + at functionD (*/test/fixtures/source-map/enclosing-call-site.js:16:17) + at functionB (*/test/fixtures/source-map/enclosing-call-site.js:6:3) + at functionA (*/test/fixtures/source-map/enclosing-call-site.js:2:3) + at Object. (*/test/fixtures/source-map/enclosing-call-site.js:24:3) Error: an error! - at functionD (*enclosing-call-site-min.js:1:156) - at functionB (*enclosing-call-site-min.js:1:60) - at functionA (*enclosing-call-site-min.js:1:26) - at Object. (*enclosing-call-site-min.js:1:199) + at functionD (*/test/fixtures/source-map/enclosing-call-site-min.js:1:156) + at functionB (*/test/fixtures/source-map/enclosing-call-site-min.js:1:60) + at functionA (*/test/fixtures/source-map/enclosing-call-site-min.js:1:26) + at Object. (*/test/fixtures/source-map/enclosing-call-site-min.js:1:199) diff --git a/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot b/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot index 97d02f176c0cb7..2043bd0a88e897 100644 --- a/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot +++ b/test/fixtures/source-map/output/source_map_reference_error_tabs.snapshot @@ -1,10 +1,10 @@ -*tabs.coffee:26 +*/test/fixtures/source-map/tabs.coffee:26 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object. (*tabs.coffee:26:2) - at Object. (*tabs.coffee:1:14) + at Object. (*/test/fixtures/source-map/tabs.coffee:26:2) + at Object. (*/test/fixtures/source-map/tabs.coffee:1:14) Node.js * diff --git a/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot b/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot index 6a109c904e1155..52d4e6a28ee5ce 100644 --- a/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot +++ b/test/fixtures/source-map/output/source_map_sourcemapping_url_string.snapshot @@ -1,3 +1,3 @@ Error: an exception. - at Object. (*typescript-sourcemapping_url_string.ts:3:7) + at Object. (*/test/fixtures/source-map/typescript-sourcemapping_url_string.ts:3:7) * diff --git a/test/fixtures/source-map/output/source_map_throw_catch.snapshot b/test/fixtures/source-map/output/source_map_throw_catch.snapshot index 5eaffbfbf7874f..6e80e500c8cf17 100644 --- a/test/fixtures/source-map/output/source_map_throw_catch.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_catch.snapshot @@ -1,4 +1,4 @@ reachable Error: an exception - at branch (*typescript-throw.ts:18:11) - at Object. (*typescript-throw.ts:24:1) + at branch (*/test/fixtures/source-map/typescript-throw.ts:18:11) + at Object. (*/test/fixtures/source-map/typescript-throw.ts:24:1) diff --git a/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot b/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot index fba8c95cc1103f..e129d73ef1581c 100644 --- a/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_first_tick.snapshot @@ -1,11 +1,11 @@ reachable -*typescript-throw.ts:18 +*/test/fixtures/source-map/typescript-throw.ts:18 throw Error('an exception'); ^ Error: an exception - at branch (*typescript-throw.ts:18:11) - at Object. (*typescript-throw.ts:24:1) + at branch (*/test/fixtures/source-map/typescript-throw.ts:18:11) + at Object. (*/test/fixtures/source-map/typescript-throw.ts:24:1) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_icu.snapshot b/test/fixtures/source-map/output/source_map_throw_icu.snapshot index 425495062e6423..4b2853479b9576 100644 --- a/test/fixtures/source-map/output/source_map_throw_icu.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_icu.snapshot @@ -1,10 +1,10 @@ -*icu.jsx:3 +*/test/fixtures/source-map/icu.jsx:3 ("あ 🐕 🐕", throw Error("an error")); ^ Error: an error - at Object.createElement (*icu.jsx:3:23) - at Object. (*icu.jsx:9:5) + at Object.createElement (*/test/fixtures/source-map/icu.jsx:3:23) + at Object. (*/test/fixtures/source-map/icu.jsx:9:5) Node.js * diff --git a/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot b/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot index e5054d01b8f91b..4cf4d52a16ea93 100644 --- a/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot +++ b/test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot @@ -1,11 +1,11 @@ -*uglify-throw-original.js:5 +*/test/fixtures/source-map/uglify-throw-original.js:5 throw Error('goodbye'); ^ Error: goodbye - at Hello (*uglify-throw-original.js:5:9) - at Immediate. (*uglify-throw-original.js:9:3) - at process.processImmediate (node:internal*timers:478:21) + at Hello (*/test/fixtures/source-map/uglify-throw-original.js:5:9) + at Immediate. (*/test/fixtures/source-map/uglify-throw-original.js:9:3) + * Node.js * diff --git a/test/fixtures/source-map/output/source_map_vm_function.js b/test/fixtures/source-map/output/source_map_vm_function.js new file mode 100644 index 00000000000000..01fe273f0b34dd --- /dev/null +++ b/test/fixtures/source-map/output/source_map_vm_function.js @@ -0,0 +1,18 @@ +// Flags: --enable-source-maps + +'use strict'; +require('../../../common'); +const vm = require('vm'); + +const fs = require('fs'); +const filename = require.resolve('../tabs.js'); +const content = fs.readFileSync(filename, 'utf8'); + +const context = vm.createContext({}); +vm.runInContext('Error.stackTraceLimit = 3', context); + +const fn = vm.compileFunction(content, [], { + filename, + parsingContext: context, +}) +fn(); diff --git a/test/fixtures/source-map/output/source_map_vm_function.snapshot b/test/fixtures/source-map/output/source_map_vm_function.snapshot new file mode 100644 index 00000000000000..6a5d3bb7d64b2a --- /dev/null +++ b/test/fixtures/source-map/output/source_map_vm_function.snapshot @@ -0,0 +1,11 @@ +*/test/fixtures/source-map/tabs.coffee:26 + alert "I knew it!" + ^ + + +ReferenceError: alert is not defined + at (*/test/fixtures/source-map/tabs.coffee:26:2) + at (*/test/fixtures/source-map/tabs.coffee:1:14) + at Object. (*/test/fixtures/source-map/output/source_map_vm_function.js:18:1) + +Node.js * diff --git a/test/fixtures/source-map/output/source_map_vm_module.js b/test/fixtures/source-map/output/source_map_vm_module.js new file mode 100644 index 00000000000000..117e31bd03b856 --- /dev/null +++ b/test/fixtures/source-map/output/source_map_vm_module.js @@ -0,0 +1,22 @@ +// Flags: --enable-source-maps --experimental-vm-modules + +'use strict'; +const common = require('../../../common'); +const vm = require('vm'); +Error.stackTraceLimit = 3; + +const fs = require('fs'); +const filename = require.resolve('../tabs.js'); +const content = fs.readFileSync(filename, 'utf8'); + +const context = vm.createContext({}); +vm.runInContext('Error.stackTraceLimit = 3', context); + +(async () => { + const mod = new vm.SourceTextModule(content, { + context, + identifier: filename, + }); + await mod.link(common.mustNotCall()); + await mod.evaluate(); +})(); diff --git a/test/fixtures/source-map/output/source_map_vm_module.snapshot b/test/fixtures/source-map/output/source_map_vm_module.snapshot new file mode 100644 index 00000000000000..76c8a437116fba --- /dev/null +++ b/test/fixtures/source-map/output/source_map_vm_module.snapshot @@ -0,0 +1,11 @@ +*/test/fixtures/source-map/tabs.coffee:26 + alert "I knew it!" + ^ + + +ReferenceError: alert is not defined + at (*/test/fixtures/source-map/tabs.coffee:26:2) + at (*/test/fixtures/source-map/tabs.coffee:1:14) + * + +Node.js * diff --git a/test/fixtures/source-map/output/source_map_vm_script.js b/test/fixtures/source-map/output/source_map_vm_script.js new file mode 100644 index 00000000000000..f6eff3282c0294 --- /dev/null +++ b/test/fixtures/source-map/output/source_map_vm_script.js @@ -0,0 +1,28 @@ +// Flags: --enable-source-maps + +'use strict'; +require('../../../common'); +const vm = require('vm'); +Error.stackTraceLimit = 3; + +const fs = require('fs'); +const filename = require.resolve('../tabs.js'); +const content = fs.readFileSync(filename, 'utf8'); + +const context = vm.createContext({}); +vm.runInContext('Error.stackTraceLimit = 3', context); + +// Scripts created implicitly with `vm.runInContext`. +try { + vm.runInContext(content, context, { + filename, + }); +} catch (e) { + console.error(e); +} + +// Scripts created explicitly with `vm.Script`. +const script = new vm.Script(content, { + filename, +}); +script.runInContext(context); diff --git a/test/fixtures/source-map/output/source_map_vm_script.snapshot b/test/fixtures/source-map/output/source_map_vm_script.snapshot new file mode 100644 index 00000000000000..dfce0837dfb7ea --- /dev/null +++ b/test/fixtures/source-map/output/source_map_vm_script.snapshot @@ -0,0 +1,20 @@ +*/test/fixtures/source-map/tabs.coffee:26 + alert "I knew it!" + ^ + + +ReferenceError: alert is not defined + at (*/test/fixtures/source-map/tabs.coffee:26:2) + at (*/test/fixtures/source-map/tabs.coffee:1:14) + at Script.runInContext (node:vm:150:12) +*/test/fixtures/source-map/tabs.coffee:26 + alert "I knew it!" + ^ + + +ReferenceError: alert is not defined + at (*/test/fixtures/source-map/tabs.coffee:26:2) + at (*/test/fixtures/source-map/tabs.coffee:1:14) + at Script.runInContext (node:vm:150:12) + +Node.js * diff --git a/test/fixtures/source-map/tabs.coffee b/test/fixtures/source-map/tabs.coffee index abc5baab636e8a..dd03beeedf4ee8 100644 --- a/test/fixtures/source-map/tabs.coffee +++ b/test/fixtures/source-map/tabs.coffee @@ -27,3 +27,8 @@ if true # Array comprehensions: cubes = (math.cube num for num in list) + +# To reproduce: +# cd test/fixtures/source-map +# npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs.coffee +# sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/\\/synthethized\\/workspace/g" tabs.js diff --git a/test/fixtures/source-map/tabs.js b/test/fixtures/source-map/tabs.js index 4e8ebf149dfd16..c13ea80a74922f 100644 --- a/test/fixtures/source-map/tabs.js +++ b/test/fixtures/source-map/tabs.js @@ -50,7 +50,12 @@ return results; })(); + // To reproduce: +// cd test/fixtures/source-map +// npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs.coffee +// sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/\\/synthethized\\/workspace/g" tabs.js + }).call(this); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRhYnMuY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBYTtFQUFBO0FBQUEsTUFBQSxLQUFBLEVBQUEsSUFBQSxFQUFBLElBQUEsRUFBQSxHQUFBLEVBQUEsTUFBQSxFQUFBLFFBQUEsRUFBQSxJQUFBLEVBQUE7O0VBQ2IsTUFBQSxHQUFXOztFQUNYLFFBQUEsR0FBVzs7RUFHWCxJQUFnQixRQUFoQjs7SUFBQSxNQUFBLEdBQVMsQ0FBQyxHQUFWO0dBTGE7OztFQVFiLE1BQUEsR0FBUyxRQUFBLENBQUMsQ0FBRCxDQUFBO1dBQU8sQ0FBQSxHQUFJO0VBQVgsRUFSSTs7O0VBV2IsSUFBQSxHQUFPLENBQUMsQ0FBRCxFQUFJLENBQUosRUFBTyxDQUFQLEVBQVUsQ0FBVixFQUFhLENBQWIsRUFYTTs7O0VBY2IsSUFBQSxHQUNDO0lBQUEsSUFBQSxFQUFRLElBQUksQ0FBQyxJQUFiO0lBQ0EsTUFBQSxFQUFRLE1BRFI7SUFFQSxJQUFBLEVBQVEsUUFBQSxDQUFDLENBQUQsQ0FBQTthQUFPLENBQUEsR0FBSSxNQUFBLENBQU8sQ0FBUDtJQUFYO0VBRlIsRUFmWTs7O0VBb0JiLElBQUEsR0FBTyxRQUFBLENBQUMsTUFBRCxFQUFBLEdBQVMsT0FBVCxDQUFBO1dBQ04sS0FBQSxDQUFNLE1BQU4sRUFBYyxPQUFkO0VBRE0sRUFwQk07OztFQXdCYixJQUFHLElBQUg7SUFDQyxLQUFBLENBQU0sWUFBTixFQUREO0dBeEJhOzs7RUE0QmIsS0FBQTs7QUFBUztJQUFBLEtBQUEsc0NBQUE7O21CQUFBLElBQUksQ0FBQyxJQUFMLENBQVUsR0FBVjtJQUFBLENBQUE7OztBQTVCSSIsInNvdXJjZXNDb250ZW50IjpbIiMgQXNzaWdubWVudDpcbm51bWJlciAgID0gNDJcbm9wcG9zaXRlID0gdHJ1ZVxuXG4jIENvbmRpdGlvbnM6XG5udW1iZXIgPSAtNDIgaWYgb3Bwb3NpdGVcblxuIyBGdW5jdGlvbnM6XG5zcXVhcmUgPSAoeCkgLT4geCAqIHhcblxuIyBBcnJheXM6XG5saXN0ID0gWzEsIDIsIDMsIDQsIDVdXG5cbiMgT2JqZWN0czpcbm1hdGggPVxuXHRyb290OiAgIE1hdGguc3FydFxuXHRzcXVhcmU6IHNxdWFyZVxuXHRjdWJlOiAgICh4KSAtPiB4ICogc3F1YXJlIHhcblxuIyBTcGxhdHM6XG5yYWNlID0gKHdpbm5lciwgcnVubmVycy4uLikgLT5cblx0cHJpbnQgd2lubmVyLCBydW5uZXJzXG5cbiMgRXhpc3RlbmNlOlxuaWYgdHJ1ZVxuXHRhbGVydCBcIkkga25ldyBpdCFcIlxuXG4jIEFycmF5IGNvbXByZWhlbnNpb25zOlxuY3ViZXMgPSAobWF0aC5jdWJlIG51bSBmb3IgbnVtIGluIGxpc3QpXG4iXX0= -//# sourceURL=/Users/bencoe/oss/coffee-script-test/tabs.coffee +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRhYnMuY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBYTtFQUFBO0FBQUEsTUFBQSxLQUFBLEVBQUEsSUFBQSxFQUFBLElBQUEsRUFBQSxHQUFBLEVBQUEsTUFBQSxFQUFBLFFBQUEsRUFBQSxJQUFBLEVBQUE7O0VBQ2IsTUFBQSxHQUFXOztFQUNYLFFBQUEsR0FBVzs7RUFHWCxJQUFnQixRQUFoQjs7SUFBQSxNQUFBLEdBQVMsQ0FBQyxHQUFWO0dBTGE7OztFQVFiLE1BQUEsR0FBUyxRQUFBLENBQUMsQ0FBRCxDQUFBO1dBQU8sQ0FBQSxHQUFJO0VBQVgsRUFSSTs7O0VBV2IsSUFBQSxHQUFPLENBQUMsQ0FBRCxFQUFJLENBQUosRUFBTyxDQUFQLEVBQVUsQ0FBVixFQUFhLENBQWIsRUFYTTs7O0VBY2IsSUFBQSxHQUNDO0lBQUEsSUFBQSxFQUFRLElBQUksQ0FBQyxJQUFiO0lBQ0EsTUFBQSxFQUFRLE1BRFI7SUFFQSxJQUFBLEVBQVEsUUFBQSxDQUFDLENBQUQsQ0FBQTthQUFPLENBQUEsR0FBSSxNQUFBLENBQU8sQ0FBUDtJQUFYO0VBRlIsRUFmWTs7O0VBb0JiLElBQUEsR0FBTyxRQUFBLENBQUMsTUFBRCxFQUFBLEdBQVMsT0FBVCxDQUFBO1dBQ04sS0FBQSxDQUFNLE1BQU4sRUFBYyxPQUFkO0VBRE0sRUFwQk07OztFQXdCYixJQUFHLElBQUg7SUFDQyxLQUFBLENBQU0sWUFBTixFQUREO0dBeEJhOzs7RUE0QmIsS0FBQTs7QUFBUztJQUFBLEtBQUEsc0NBQUE7O21CQUFBLElBQUksQ0FBQyxJQUFMLENBQVUsR0FBVjtJQUFBLENBQUE7Ozs7RUE1Qkk7Ozs7QUFBQSIsInNvdXJjZXNDb250ZW50IjpbIiMgQXNzaWdubWVudDpcbm51bWJlciAgID0gNDJcbm9wcG9zaXRlID0gdHJ1ZVxuXG4jIENvbmRpdGlvbnM6XG5udW1iZXIgPSAtNDIgaWYgb3Bwb3NpdGVcblxuIyBGdW5jdGlvbnM6XG5zcXVhcmUgPSAoeCkgLT4geCAqIHhcblxuIyBBcnJheXM6XG5saXN0ID0gWzEsIDIsIDMsIDQsIDVdXG5cbiMgT2JqZWN0czpcbm1hdGggPVxuXHRyb290OiAgIE1hdGguc3FydFxuXHRzcXVhcmU6IHNxdWFyZVxuXHRjdWJlOiAgICh4KSAtPiB4ICogc3F1YXJlIHhcblxuIyBTcGxhdHM6XG5yYWNlID0gKHdpbm5lciwgcnVubmVycy4uLikgLT5cblx0cHJpbnQgd2lubmVyLCBydW5uZXJzXG5cbiMgRXhpc3RlbmNlOlxuaWYgdHJ1ZVxuXHRhbGVydCBcIkkga25ldyBpdCFcIlxuXG4jIEFycmF5IGNvbXByZWhlbnNpb25zOlxuY3ViZXMgPSAobWF0aC5jdWJlIG51bSBmb3IgbnVtIGluIGxpc3QpXG5cbiMgVG8gcmVwcm9kdWNlOlxuIyBjZCB0ZXN0L2ZpeHR1cmVzL3NvdXJjZS1tYXBcbiMgbnB4IC0tcGFja2FnZT1jb2ZmZWVzY3JpcHRAMi41LjEgLS0gY29mZmVlIC1NIC0tY29tcGlsZSB0YWJzLmNvZmZlZVxuIyBzZWQgLWkgLWUgXCJzLyQocHdkIHwgc2VkIC1lIFwicy9cXC8vXFxcXFxcXFxcXC8vZ1wiKS9cXFxcL3N5bnRoZXRoaXplZFxcXFwvd29ya3NwYWNlL2dcIiB0YWJzLmpzXG4iXX0= +//# sourceURL=/synthethized/workspace/tabs.coffee \ No newline at end of file diff --git a/test/parallel/test-node-output-sourcemaps.mjs b/test/parallel/test-node-output-sourcemaps.mjs index d82f4a249cd1d9..64a33f71795232 100644 --- a/test/parallel/test-node-output-sourcemaps.mjs +++ b/test/parallel/test-node-output-sourcemaps.mjs @@ -1,29 +1,20 @@ -import * as common from '../common/index.mjs'; +import '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import * as snapshot from '../common/assertSnapshot.js'; -import * as path from 'node:path'; import { describe, it } from 'node:test'; describe('sourcemaps output', { concurrency: !process.env.TEST_PARALLEL }, () => { - function normalize(str) { - const result = str - .replaceAll(snapshot.replaceWindowsPaths(process.cwd()), '') - .replaceAll('//', '*') - .replaceAll('/Users/bencoe/oss/coffee-script-test', '') - .replaceAll(/\/(\w)/g, '*$1') - .replaceAll('*test*', '*') - .replaceAll('*fixtures*source-map*', '*') - .replaceAll(/(\W+).*node:internal\*modules.*/g, '$1*'); - if (common.isWindows) { - const currentDeviceLetter = path.parse(process.cwd()).root.substring(0, 1).toLowerCase(); - const regex = new RegExp(`${currentDeviceLetter}:/?`, 'gi'); - return result.replaceAll(regex, ''); - } - return result; - } const defaultTransform = snapshot - .transform(snapshot.replaceWindowsLineEndings, snapshot.replaceWindowsPaths, - normalize, snapshot.replaceNodeVersion); + .transform( + snapshot.replaceWindowsLineEndings, + snapshot.transformCwd('*'), + snapshot.replaceWindowsPaths, + // Remove drive letters from synthethized paths (i.e. not cwd). + snapshot.replaceWindowsDriveLetter, + snapshot.replaceInternalStackTrace, + snapshot.replaceExperimentalWarning, + snapshot.replaceNodeVersion + ); const tests = [ { name: 'source-map/output/source_map_disabled_by_api.js' }, @@ -38,6 +29,9 @@ describe('sourcemaps output', { concurrency: !process.env.TEST_PARALLEL }, () => { name: 'source-map/output/source_map_throw_first_tick.js' }, { name: 'source-map/output/source_map_throw_icu.js' }, { name: 'source-map/output/source_map_throw_set_immediate.js' }, + { name: 'source-map/output/source_map_vm_function.js' }, + { name: 'source-map/output/source_map_vm_module.js' }, + { name: 'source-map/output/source_map_vm_script.js' }, ]; for (const { name, transform } of tests) { it(name, async () => { diff --git a/test/parallel/test-runner-output.mjs b/test/parallel/test-runner-output.mjs index abc3d7c97b4879..1d371264e64deb 100644 --- a/test/parallel/test-runner-output.mjs +++ b/test/parallel/test-runner-output.mjs @@ -61,7 +61,7 @@ const defaultTransform = snapshot.transform( snapshot.replaceWindowsLineEndings, snapshot.replaceStackTrace, removeWindowsPathEscaping, - snapshot.replaceFullPaths, + snapshot.transformCwd(), snapshot.replaceWindowsPaths, replaceTestDuration, replaceTestLocationLine, @@ -79,7 +79,7 @@ const junitTransform = snapshot.transform( const lcovTransform = snapshot.transform( snapshot.replaceWindowsLineEndings, snapshot.replaceStackTrace, - snapshot.replaceFullPaths, + snapshot.transformCwd(), snapshot.replaceWindowsPaths, pickTestFileFromLcov );