Skip to content

Commit 1a6bf1c

Browse files
legendecastargos
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 baaa397 commit 1a6bf1c

File tree

10 files changed

+169
-15
lines changed

10 files changed

+169
-15
lines changed

doc/api/process.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,24 @@ This function is only available on POSIX platforms (i.e. not Windows or
23482348
Android).
23492349
This feature is not available in [`Worker`][] threads.
23502350

2351+
## `process.setSourceMapsEnabled(val)`
2352+
<!-- YAML
2353+
added: REPLACEME
2354+
-->
2355+
2356+
> Stability: 1 - Experimental
2357+
2358+
* `val` {boolean}
2359+
2360+
This function enables or disables the [Source Map v3][Source Map] support for
2361+
stack traces.
2362+
2363+
It provides same features as launching Node.js process with commandline options
2364+
`--enable-source-maps`.
2365+
2366+
Only source maps in JavaScript files that are loaded after source maps has been
2367+
enabled will be parsed and loaded.
2368+
23512369
## `process.setUncaughtExceptionCaptureCallback(fn)`
23522370
<!-- YAML
23532371
added: v9.3.0
@@ -2732,6 +2750,7 @@ cases:
27322750
[LTS]: https://github.com/nodejs/Release
27332751
[Readable]: stream.md#stream_readable_streams
27342752
[Signal Events]: #process_signal_events
2753+
[Source Map]: https://sourcemaps.info/spec.html
27352754
[Stream compatibility]: stream.md#stream_compatibility_with_older_node_js_versions
27362755
[TTY]: tty.md#tty_tty
27372756
[Writable]: stream.md#stream_writable_streams

lib/internal/bootstrap/pre_execution.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
6161
initializeClusterIPC();
6262

6363
initializeAbortController();
64+
initializeSourceMapsHandlers();
6465
initializeDeprecations();
6566
initializeWASI();
6667
initializeCJSLoader();
@@ -448,6 +449,12 @@ function initializeESMLoader() {
448449
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
449450
}
450451

452+
function initializeSourceMapsHandlers() {
453+
const { setSourceMapsEnabled } =
454+
require('internal/source_map/source_map_cache');
455+
process.setSourceMapsEnabled = setSourceMapsEnabled;
456+
}
457+
451458
function initializeFrozenIntrinsics() {
452459
if (getOptionValue('--frozen-intrinsics')) {
453460
process.emitWarning('The --frozen-intrinsics flag is experimental',
@@ -479,6 +486,7 @@ module.exports = {
479486
initializeDeprecations,
480487
initializeESMLoader,
481488
initializeFrozenIntrinsics,
489+
initializeSourceMapsHandlers,
482490
loadPreloadModules,
483491
setupTraceCategoryState,
484492
setupInspectorHooks,

lib/internal/main/worker_thread.js

Lines changed: 2 additions & 0 deletions
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

Lines changed: 27 additions & 12 deletions
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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -819,9 +819,10 @@ void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
819819
env->set_prepare_stack_trace_callback(args[0].As<Function>());
820820
}
821821

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

827828
static void SetEnhanceStackForFatalException(
@@ -862,7 +863,7 @@ void Initialize(Local<Object> target,
862863
Environment* env = Environment::GetCurrent(context);
863864
env->SetMethod(
864865
target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
865-
env->SetMethod(target, "enableSourceMaps", EnableSourceMaps);
866+
env->SetMethod(target, "setSourceMapsEnabled", SetSourceMapsEnabled);
866867
env->SetMethod(target,
867868
"setEnhanceStackForFatalException",
868869
SetEnhanceStackForFatalException);
Lines changed: 20 additions & 0 deletions
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');
Lines changed: 26 additions & 0 deletions
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 (internal/modules/cjs/loader.js:*)
8+
at Object.Module._extensions..js (internal/modules/cjs/loader.js:*)
9+
at Module.load (internal/modules/cjs/loader.js:*)
10+
at Function.Module._load (internal/modules/cjs/loader.js:*)
11+
at Module.require (internal/modules/cjs/loader.js:*)
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 (internal/modules/cjs/loader.js:*)
23+
at Object.Module._extensions..js (internal/modules/cjs/loader.js:*)
24+
at Module.load (internal/modules/cjs/loader.js:*)
25+
at Function.Module._load (internal/modules/cjs/loader.js:*)
26+
at Module.require (internal/modules/cjs/loader.js:*)
Lines changed: 17 additions & 0 deletions
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');
Lines changed: 30 additions & 0 deletions
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 (internal/modules/cjs/loader.js:*)
12+
at Object.Module._extensions..js (internal/modules/cjs/loader.js:*)
13+
at Module.load (internal/modules/cjs/loader.js:*)
14+
at Function.Module._load (internal/modules/cjs/loader.js:*)
15+
at Module.require (internal/modules/cjs/loader.js:*)
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 (internal/modules/cjs/loader.js:*)
27+
at Object.Module._extensions..js (internal/modules/cjs/loader.js:*)
28+
at Module.load (internal/modules/cjs/loader.js:*)
29+
at Function.Module._load (internal/modules/cjs/loader.js:*)
30+
at Module.require (internal/modules/cjs/loader.js:*)
Lines changed: 16 additions & 0 deletions
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)