Skip to content

Commit cdf7251

Browse files
legendecasBethGriggs
authored andcommitted
process: add api to enable source-maps programmatically
Add `process.setSourceMapsEnabled` to enable source-maps programmatically. PR-URL: #39085 Reviewed-By: Ben Coe <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e44ccd9 commit cdf7251

10 files changed

+170
-16
lines changed

doc/api/process.md

+19
Original file line numberDiff line numberDiff line change
@@ -3248,6 +3248,24 @@ This function is only available on POSIX platforms (i.e. not Windows or
32483248
Android).
32493249
This feature is not available in [`Worker`][] threads.
32503250
3251+
## `process.setSourceMapsEnabled(val)`
3252+
<!-- YAML
3253+
added: REPLACEME
3254+
-->
3255+
3256+
> Stability: 1 - Experimental
3257+
3258+
* `val` {boolean}
3259+
3260+
This function enables or disables the [Source Map v3][Source Map] support for
3261+
stack traces.
3262+
3263+
It provides same features as launching Node.js process with commandline options
3264+
`--enable-source-maps`.
3265+
3266+
Only source maps in JavaScript files that are loaded after source maps has been
3267+
enabled will be parsed and loaded.
3268+
32513269
## `process.setUncaughtExceptionCaptureCallback(fn)`
32523270
<!-- YAML
32533271
added: v9.3.0
@@ -3669,6 +3687,7 @@ cases:
36693687
[LTS]: https://github.com/nodejs/Release
36703688
[Readable]: stream.md#stream_readable_streams
36713689
[Signal Events]: #process_signal_events
3690+
[Source Map]: https://sourcemaps.info/spec.html
36723691
[Stream compatibility]: stream.md#stream_compatibility_with_older_node_js_versions
36733692
[TTY]: tty.md#tty_tty
36743693
[Writable]: stream.md#stream_writable_streams

lib/internal/bootstrap/pre_execution.js

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
6666
// (including preload modules).
6767
initializeClusterIPC();
6868

69+
initializeSourceMapsHandlers();
6970
initializeDeprecations();
7071
initializeWASI();
7172
initializeCJSLoader();
@@ -454,6 +455,12 @@ function initializeESMLoader() {
454455
}
455456
}
456457

458+
function initializeSourceMapsHandlers() {
459+
const { setSourceMapsEnabled } =
460+
require('internal/source_map/source_map_cache');
461+
process.setSourceMapsEnabled = setSourceMapsEnabled;
462+
}
463+
457464
function initializeFrozenIntrinsics() {
458465
if (getOptionValue('--frozen-intrinsics')) {
459466
process.emitWarning('The --frozen-intrinsics flag is experimental',
@@ -485,6 +492,7 @@ module.exports = {
485492
initializeDeprecations,
486493
initializeESMLoader,
487494
initializeFrozenIntrinsics,
495+
initializeSourceMapsHandlers,
488496
loadPreloadModules,
489497
setupTraceCategoryState,
490498
setupInspectorHooks,

lib/internal/main/worker_thread.js

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const {
2525
initializeESMLoader,
2626
initializeFrozenIntrinsics,
2727
initializeReport,
28+
initializeSourceMapsHandlers,
2829
loadPreloadModules,
2930
setupTraceCategoryState
3031
} = require('internal/bootstrap/pre_execution');
@@ -66,6 +67,7 @@ setupInspectorHooks();
6667
setupDebugEnv();
6768

6869
setupWarningHandler();
70+
initializeSourceMapsHandlers();
6971

7072
// Since worker threads cannot switch cwd, we do not need to
7173
// overwrite the process.env.NODE_V8_COVERAGE variable.

lib/internal/source_map/source_map_cache.js

+27-12
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const { IterableWeakMap } = require('internal/util/iterable_weak_map');
2929
const {
3030
normalizeReferrerURL,
3131
} = require('internal/modules/cjs/helpers');
32+
const { validateBoolean } = require('internal/validators');
3233
// Since the CJS module cache is mutable, which leads to memory leaks when
3334
// modules are deleted, we use a WeakMap so that the source map cache will
3435
// be purged automatically:
@@ -41,22 +42,35 @@ let SourceMap;
4142
let sourceMapsEnabled;
4243
function getSourceMapsEnabled() {
4344
if (sourceMapsEnabled === undefined) {
44-
sourceMapsEnabled = getOptionValue('--enable-source-maps');
45-
if (sourceMapsEnabled) {
46-
const {
47-
enableSourceMaps,
48-
setPrepareStackTraceCallback
49-
} = internalBinding('errors');
50-
const {
51-
prepareStackTrace
52-
} = require('internal/source_map/prepare_stack_trace');
53-
setPrepareStackTraceCallback(prepareStackTrace);
54-
enableSourceMaps();
55-
}
45+
setSourceMapsEnabled(getOptionValue('--enable-source-maps'));
5646
}
5747
return sourceMapsEnabled;
5848
}
5949

50+
function setSourceMapsEnabled(val) {
51+
validateBoolean(val, 'val');
52+
53+
const {
54+
setSourceMapsEnabled,
55+
setPrepareStackTraceCallback
56+
} = internalBinding('errors');
57+
setSourceMapsEnabled(val);
58+
if (val) {
59+
const {
60+
prepareStackTrace
61+
} = require('internal/source_map/prepare_stack_trace');
62+
setPrepareStackTraceCallback(prepareStackTrace);
63+
} else if (sourceMapsEnabled !== undefined) {
64+
// Reset prepare stack trace callback only when disabling source maps.
65+
const {
66+
prepareStackTrace,
67+
} = require('internal/errors');
68+
setPrepareStackTraceCallback(prepareStackTrace);
69+
}
70+
71+
sourceMapsEnabled = val;
72+
}
73+
6074
function maybeCacheSourceMap(filename, content, cjsModuleInstance) {
6175
const sourceMapsEnabled = getSourceMapsEnabled();
6276
if (!(process.env.NODE_V8_COVERAGE || sourceMapsEnabled)) return;
@@ -231,6 +245,7 @@ function findSourceMap(sourceURL) {
231245
module.exports = {
232246
findSourceMap,
233247
getSourceMapsEnabled,
248+
setSourceMapsEnabled,
234249
maybeCacheSourceMap,
235250
sourceMapCacheToObject,
236251
};

src/node_errors.cc

+5-4
Original file line numberDiff line numberDiff line change
@@ -820,9 +820,10 @@ void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
820820
env->set_prepare_stack_trace_callback(args[0].As<Function>());
821821
}
822822

823-
static void EnableSourceMaps(const FunctionCallbackInfo<Value>& args) {
823+
static void SetSourceMapsEnabled(const FunctionCallbackInfo<Value>& args) {
824824
Environment* env = Environment::GetCurrent(args);
825-
env->set_source_maps_enabled(true);
825+
CHECK(args[0]->IsBoolean());
826+
env->set_source_maps_enabled(args[0].As<Boolean>()->Value());
826827
}
827828

828829
static void SetEnhanceStackForFatalException(
@@ -858,7 +859,7 @@ static void TriggerUncaughtException(const FunctionCallbackInfo<Value>& args) {
858859

859860
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
860861
registry->Register(SetPrepareStackTraceCallback);
861-
registry->Register(EnableSourceMaps);
862+
registry->Register(SetSourceMapsEnabled);
862863
registry->Register(SetEnhanceStackForFatalException);
863864
registry->Register(NoSideEffectsToString);
864865
registry->Register(TriggerUncaughtException);
@@ -871,7 +872,7 @@ void Initialize(Local<Object> target,
871872
Environment* env = Environment::GetCurrent(context);
872873
env->SetMethod(
873874
target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
874-
env->SetMethod(target, "enableSourceMaps", EnableSourceMaps);
875+
env->SetMethod(target, "setSourceMapsEnabled", SetSourceMapsEnabled);
875876
env->SetMethod(target,
876877
"setEnhanceStackForFatalException",
877878
SetEnhanceStackForFatalException);
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Flags: --enable-source-maps
2+
3+
'use strict';
4+
require('../common');
5+
6+
process.setSourceMapsEnabled(false);
7+
8+
try {
9+
require('../fixtures/source-map/enclosing-call-site-min.js');
10+
} catch (e) {
11+
console.log(e);
12+
}
13+
14+
delete require.cache[require
15+
.resolve('../fixtures/source-map/enclosing-call-site-min.js')];
16+
17+
// Re-enable.
18+
process.setSourceMapsEnabled(true);
19+
20+
require('../fixtures/source-map/enclosing-call-site-min.js');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Error: an error!
2+
at functionD (*enclosing-call-site-min.js:1:156)
3+
at functionC (*enclosing-call-site-min.js:1:97)
4+
at functionB (*enclosing-call-site-min.js:1:60)
5+
at functionA (*enclosing-call-site-min.js:1:26)
6+
at Object.<anonymous> (*enclosing-call-site-min.js:1:199)
7+
at Module._compile (node:internal/modules/cjs/loader:*)
8+
at Object.Module._extensions..js (node:internal/modules/cjs/loader:*)
9+
at Module.load (node:internal/modules/cjs/loader:*)
10+
at Function.Module._load (node:internal/modules/cjs/loader:*)
11+
at Module.require (node:internal/modules/cjs/loader:*)
12+
*enclosing-call-site.js:16
13+
throw new Error('an error!')
14+
^
15+
16+
Error: an error!
17+
at functionD (*enclosing-call-site.js:16:17)
18+
at functionC (*enclosing-call-site.js:10:3)
19+
at functionB (*enclosing-call-site.js:6:3)
20+
at functionA (*enclosing-call-site.js:2:3)
21+
at Object.<anonymous> (*enclosing-call-site.js:24:3)
22+
at Module._compile (node:internal/modules/cjs/loader:*)
23+
at Object.Module._extensions..js (node:internal/modules/cjs/loader:*)
24+
at Module.load (node:internal/modules/cjs/loader:*)
25+
at Function.Module._load (node:internal/modules/cjs/loader:*)
26+
at Module.require (node:internal/modules/cjs/loader:*)
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
require('../common');
3+
4+
process.setSourceMapsEnabled(true);
5+
6+
try {
7+
require('../fixtures/source-map/enclosing-call-site-min.js');
8+
} catch (e) {
9+
console.log(e);
10+
}
11+
12+
delete require.cache[require
13+
.resolve('../fixtures/source-map/enclosing-call-site-min.js')];
14+
15+
process.setSourceMapsEnabled(false);
16+
17+
require('../fixtures/source-map/enclosing-call-site-min.js');
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
*enclosing-call-site.js:16
2+
throw new Error('an error!')
3+
^
4+
5+
Error: an error!
6+
at functionD (*enclosing-call-site.js:16:17)
7+
at functionC (*enclosing-call-site.js:10:3)
8+
at functionB (*enclosing-call-site.js:6:3)
9+
at functionA (*enclosing-call-site.js:2:3)
10+
at Object.<anonymous> (*enclosing-call-site.js:24:3)
11+
at Module._compile (node:internal/modules/cjs/loader:*)
12+
at Object.Module._extensions..js (node:internal/modules/cjs/loader:*)
13+
at Module.load (node:internal/modules/cjs/loader:*)
14+
at Function.Module._load (node:internal/modules/cjs/loader:*)
15+
at Module.require (node:internal/modules/cjs/loader:*)
16+
*enclosing-call-site-min.js:1
17+
var functionA=function(){functionB()};function functionB(){functionC()}var functionC=function(){functionD()},functionD=function(){if(0<Math.random())throw Error("an error!");},thrower=functionA;try{functionA()}catch(a){throw a;};
18+
^
19+
20+
Error: an error!
21+
at functionD (*enclosing-call-site-min.js:1:156)
22+
at functionC (*enclosing-call-site-min.js:1:97)
23+
at functionB (*enclosing-call-site-min.js:1:60)
24+
at functionA (*enclosing-call-site-min.js:1:26)
25+
at Object.<anonymous> (*enclosing-call-site-min.js:1:199)
26+
at Module._compile (node:internal/modules/cjs/loader:*)
27+
at Object.Module._extensions..js (node:internal/modules/cjs/loader:*)
28+
at Module.load (node:internal/modules/cjs/loader:*)
29+
at Function.Module._load (node:internal/modules/cjs/loader:*)
30+
at Module.require (node:internal/modules/cjs/loader:*)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('assert');
4+
5+
const unexpectedValues = [
6+
undefined,
7+
null,
8+
1,
9+
{},
10+
() => {},
11+
];
12+
for (const it of unexpectedValues) {
13+
assert.throws(() => {
14+
process.setSourceMapsEnabled(it);
15+
}, /ERR_INVALID_ARG_TYPE/);
16+
}

0 commit comments

Comments
 (0)