GeezerVison is showing github.com — src,lib: retrieve parsed source map url from v8 · nodejs/node@12779b3
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: doc/api/vm.md +35Lines changed: 35 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -344,6 +344,41 @@ console.log(globalVar); | 344 | 344 | // 1000 | 345 | 345 | ``` | 346 | 346 |
| | 347 | +### `script.sourceMapURL` | | 348 | + | | 349 | +<!-- YAML | | 350 | +added: REPLACEME | | 351 | +--> | | 352 | + | | 353 | +* {string|undefined} | | 354 | + | | 355 | +When the script is compiled from a source that contains a source map magic | | 356 | +comment, this property will be set to the URL of the source map. | | 357 | + | | 358 | +```mjs | | 359 | +import vm from 'node:vm'; | | 360 | + | | 361 | +const script = new vm.Script(` | | 362 | +function myFunc() {} | | 363 | +//# sourceMappingURL=sourcemap.json | | 364 | +`); | | 365 | + | | 366 | +console.log(script.sourceMapURL); | | 367 | +// Prints: sourcemap.json | | 368 | +``` | | 369 | + | | 370 | +```cjs | | 371 | +const vm = require('node:vm'); | | 372 | + | | 373 | +const script = new vm.Script(` | | 374 | +function myFunc() {} | | 375 | +//# sourceMappingURL=sourcemap.json | | 376 | +`); | | 377 | + | | 378 | +console.log(script.sourceMapURL); | | 379 | +// Prints: sourcemap.json | | 380 | +``` | | 381 | + | 347 | 382 | ## Class: `vm.Module` | 348 | 383 |
| 349 | 384 | <!-- YAML | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/cjs/loader.js +21-5Lines changed: 21 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -86,7 +86,8 @@ const { | 86 | 86 | filterOwnProperties, | 87 | 87 | setOwnProperty, | 88 | 88 | } = require('internal/util'); | 89 | | -const vm = require('vm'); | | 89 | +const { Script } = require('vm'); | | 90 | +const { internalCompileFunction } = require('internal/vm'); | 90 | 91 | const assert = require('internal/assert'); | 91 | 92 | const fs = require('fs'); | 92 | 93 | const internalFS = require('internal/fs/utils'); | @@ -1073,19 +1074,28 @@ let hasPausedEntry = false; | 1073 | 1074 | function wrapSafe(filename, content, cjsModuleInstance) { | 1074 | 1075 | if (patched) { | 1075 | 1076 | const wrapper = Module.wrap(content); | 1076 | | - return vm.runInThisContext(wrapper, { | | 1077 | + const script = new Script(wrapper, { | 1077 | 1078 | filename, | 1078 | 1079 | lineOffset: 0, | 1079 | | - displayErrors: true, | 1080 | 1080 | importModuleDynamically: async (specifier, _, importAssertions) => { | 1081 | 1081 | const loader = asyncESM.esmLoader; | 1082 | 1082 | return loader.import(specifier, normalizeReferrerURL(filename), | 1083 | 1083 | importAssertions); | 1084 | 1084 | }, | 1085 | 1085 | }); | | 1086 | + | | 1087 | + // Cache the source map for the module if present. | | 1088 | + if (script.sourceMapURL) { | | 1089 | + maybeCacheSourceMap(filename, content, this, false, undefined, script.sourceMapURL); | | 1090 | + } | | 1091 | + | | 1092 | + return script.runInThisContext({ | | 1093 | + displayErrors: true, | | 1094 | + }); | 1086 | 1095 | } | | 1096 | + | 1087 | 1097 | try { | 1088 | | - return vm.compileFunction(content, [ | | 1098 | + const result = internalCompileFunction(content, [ | 1089 | 1099 | 'exports', | 1090 | 1100 | 'require', | 1091 | 1101 | 'module', | @@ -1099,6 +1109,13 @@ function wrapSafe(filename, content, cjsModuleInstance) { | 1099 | 1109 | importAssertions); | 1100 | 1110 | }, | 1101 | 1111 | }); | | 1112 | + | | 1113 | + // Cache the source map for the module if present. | | 1114 | + if (result.sourceMapURL) { | | 1115 | + maybeCacheSourceMap(filename, content, this, false, undefined, result.sourceMapURL); | | 1116 | + } | | 1117 | + | | 1118 | + return result.function; | 1102 | 1119 | } catch (err) { | 1103 | 1120 | if (process.mainModule === cjsModuleInstance) | 1104 | 1121 | enrichCJSError(err, content); | @@ -1119,7 +1136,6 @@ Module.prototype._compile = function(content, filename) { | 1119 | 1136 | policy.manifest.assertIntegrity(moduleURL, content); | 1120 | 1137 | } | 1121 | 1138 |
| 1122 | | - maybeCacheSourceMap(filename, content, this); | 1123 | 1139 | const compiledWrapper = wrapSafe(filename, content, this); | 1124 | 1140 |
| 1125 | 1141 | let inspectorWrapper = null; | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/process/pre_execution.js +3-1Lines changed: 3 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -596,9 +596,11 @@ function initializeESMLoader() { | 596 | 596 | } | 597 | 597 |
| 598 | 598 | function initializeSourceMapsHandlers() { | 599 | | - const { setSourceMapsEnabled } = | | 599 | + const { setSourceMapsEnabled, getSourceMapsEnabled } = | 600 | 600 | require('internal/source_map/source_map_cache'); | 601 | 601 | process.setSourceMapsEnabled = setSourceMapsEnabled; | | 602 | + // Initialize the environment flag of source maps. | | 603 | + getSourceMapsEnabled(); | 602 | 604 | } | 603 | 605 |
| 604 | 606 | function initializeFrozenIntrinsics() { | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/source_map/source_map_cache.js +56-42Lines changed: 56 additions & 42 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -97,7 +97,21 @@ function extractSourceURLMagicComment(content) { | 97 | 97 | return sourceURL; | 98 | 98 | } | 99 | 99 |
| 100 | | -function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSource, sourceURL) { | | 100 | +function extractSourceMapURLMagicComment(content) { | | 101 | + let match; | | 102 | + let lastMatch; | | 103 | + // A while loop is used here to get the last occurrence of sourceMappingURL. | | 104 | + // This is needed so that we don't match sourceMappingURL in string literals. | | 105 | + while ((match = RegExpPrototypeExec(kSourceMappingURLMagicComment, content))) { | | 106 | + lastMatch = match; | | 107 | + } | | 108 | + if (lastMatch == null) { | | 109 | + return null; | | 110 | + } | | 111 | + return lastMatch.groups.sourceMappingURL; | | 112 | +} | | 113 | + | | 114 | +function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSource, sourceURL, sourceMapURL) { | 101 | 115 | const sourceMapsEnabled = getSourceMapsEnabled(); | 102 | 116 | if (!(process.env.NODE_V8_COVERAGE || sourceMapsEnabled)) return; | 103 | 117 | try { | @@ -108,52 +122,52 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo | 108 | 122 | return; | 109 | 123 | } | 110 | 124 |
| 111 | | - let match; | 112 | | - let lastMatch; | 113 | | - // A while loop is used here to get the last occurrence of sourceMappingURL. | 114 | | - // This is needed so that we don't match sourceMappingURL in string literals. | 115 | | - while ((match = RegExpPrototypeExec(kSourceMappingURLMagicComment, content))) { | 116 | | - lastMatch = match; | | 125 | + if (sourceMapURL === undefined) { | | 126 | + sourceMapURL = extractSourceMapURLMagicComment(content); | | 127 | + } | | 128 | + | | 129 | + // Bail out when there is no source map url. | | 130 | + if (typeof sourceMapURL !== 'string') { | | 131 | + return; | 117 | 132 | } | 118 | 133 |
| 119 | 134 | if (sourceURL === undefined) { | 120 | 135 | sourceURL = extractSourceURLMagicComment(content); | 121 | 136 | } | 122 | | - if (lastMatch) { | 123 | | - const data = dataFromUrl(filename, lastMatch.groups.sourceMappingURL); | 124 | | - const url = data ? null : lastMatch.groups.sourceMappingURL; | 125 | | - if (cjsModuleInstance) { | 126 | | - cjsSourceMapCache.set(cjsModuleInstance, { | 127 | | - filename, | 128 | | - lineLengths: lineLengths(content), | 129 | | - data, | 130 | | - url, | 131 | | - sourceURL, | 132 | | - }); | 133 | | - } else if (isGeneratedSource) { | 134 | | - const entry = { | 135 | | - lineLengths: lineLengths(content), | 136 | | - data, | 137 | | - url, | 138 | | - sourceURL | 139 | | - }; | 140 | | - generatedSourceMapCache.set(filename, entry); | 141 | | - if (sourceURL) { | 142 | | - generatedSourceMapCache.set(sourceURL, entry); | 143 | | - } | 144 | | - } else { | 145 | | - // If there is no cjsModuleInstance and is not generated source assume we are in a | 146 | | - // "modules/esm" context. | 147 | | - const entry = { | 148 | | - lineLengths: lineLengths(content), | 149 | | - data, | 150 | | - url, | 151 | | - sourceURL, | 152 | | - }; | 153 | | - esmSourceMapCache.set(filename, entry); | 154 | | - if (sourceURL) { | 155 | | - esmSourceMapCache.set(sourceURL, entry); | 156 | | - } | | 137 | + | | 138 | + const data = dataFromUrl(filename, sourceMapURL); | | 139 | + const url = data ? null : sourceMapURL; | | 140 | + if (cjsModuleInstance) { | | 141 | + cjsSourceMapCache.set(cjsModuleInstance, { | | 142 | + filename, | | 143 | + lineLengths: lineLengths(content), | | 144 | + data, | | 145 | + url, | | 146 | + sourceURL, | | 147 | + }); | | 148 | + } else if (isGeneratedSource) { | | 149 | + const entry = { | | 150 | + lineLengths: lineLengths(content), | | 151 | + data, | | 152 | + url, | | 153 | + sourceURL | | 154 | + }; | | 155 | + generatedSourceMapCache.set(filename, entry); | | 156 | + if (sourceURL) { | | 157 | + generatedSourceMapCache.set(sourceURL, entry); | | 158 | + } | | 159 | + } else { | | 160 | + // If there is no cjsModuleInstance and is not generated source assume we are in a | | 161 | + // "modules/esm" context. | | 162 | + const entry = { | | 163 | + lineLengths: lineLengths(content), | | 164 | + data, | | 165 | + url, | | 166 | + sourceURL, | | 167 | + }; | | 168 | + esmSourceMapCache.set(filename, entry); | | 169 | + if (sourceURL) { | | 170 | + esmSourceMapCache.set(sourceURL, entry); | 157 | 171 | } | 158 | 172 | } | 159 | 173 | } | |
Collapse file Copy file name to clipboard +113Lines changed: 113 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +const { | | 4 | + ArrayPrototypeForEach, | | 5 | +} = primordials; | | 6 | + | | 7 | +const { | | 8 | + compileFunction, | | 9 | + isContext: _isContext, | | 10 | +} = internalBinding('contextify'); | | 11 | +const { | | 12 | + validateArray, | | 13 | + validateBoolean, | | 14 | + validateBuffer, | | 15 | + validateFunction, | | 16 | + validateObject, | | 17 | + validateString, | | 18 | + validateUint32, | | 19 | +} = require('internal/validators'); | | 20 | +const { | | 21 | + ERR_INVALID_ARG_TYPE, | | 22 | +} = require('internal/errors').codes; | | 23 | + | | 24 | +function isContext(object) { | | 25 | + validateObject(object, 'object', { __proto__: null, allowArray: true }); | | 26 | + | | 27 | + return _isContext(object); | | 28 | +} | | 29 | + | | 30 | +function internalCompileFunction(code, params, options) { | | 31 | + validateString(code, 'code'); | | 32 | + if (params !== undefined) { | | 33 | + validateArray(params, 'params'); | | 34 | + ArrayPrototypeForEach(params, | | 35 | + (param, i) => validateString(param, `params[${i}]`)); | | 36 | + } | | 37 | + | | 38 | + const { | | 39 | + filename = '', | | 40 | + columnOffset = 0, | | 41 | + lineOffset = 0, | | 42 | + cachedData = undefined, | | 43 | + produceCachedData = false, | | 44 | + parsingContext = undefined, | | 45 | + contextExtensions = [], | | 46 | + importModuleDynamically, | | 47 | + } = options; | | 48 | + | | 49 | + validateString(filename, 'options.filename'); | | 50 | + validateUint32(columnOffset, 'options.columnOffset'); | | 51 | + validateUint32(lineOffset, 'options.lineOffset'); | | 52 | + if (cachedData !== undefined) | | 53 | + validateBuffer(cachedData, 'options.cachedData'); | | 54 | + validateBoolean(produceCachedData, 'options.produceCachedData'); | | 55 | + if (parsingContext !== undefined) { | | 56 | + if ( | | 57 | + typeof parsingContext !== 'object' || | | 58 | + parsingContext === null || | | 59 | + !isContext(parsingContext) | | 60 | + ) { | | 61 | + throw new ERR_INVALID_ARG_TYPE( | | 62 | + 'options.parsingContext', | | 63 | + 'Context', | | 64 | + parsingContext | | 65 | + ); | | 66 | + } | | 67 | + } | | 68 | + validateArray(contextExtensions, 'options.contextExtensions'); | | 69 | + ArrayPrototypeForEach(contextExtensions, (extension, i) => { | | 70 | + const name = `options.contextExtensions[${i}]`; | | 71 | + validateObject(extension, name, { __proto__: null, nullable: true }); | | 72 | + }); | | 73 | + | | 74 | + const result = compileFunction( | | 75 | + code, | | 76 | + filename, | | 77 | + lineOffset, | | 78 | + columnOffset, | | 79 | + cachedData, | | 80 | + produceCachedData, | | 81 | + parsingContext, | | 82 | + contextExtensions, | | 83 | + params | | 84 | + ); | | 85 | + | | 86 | + if (produceCachedData) { | | 87 | + result.function.cachedDataProduced = result.cachedDataProduced; | | 88 | + } | | 89 | + | | 90 | + if (result.cachedData) { | | 91 | + result.function.cachedData = result.cachedData; | | 92 | + } | | 93 | + | | 94 | + if (importModuleDynamically !== undefined) { | | 95 | + validateFunction(importModuleDynamically, | | 96 | + 'options.importModuleDynamically'); | | 97 | + const { importModuleDynamicallyWrap } = | | 98 | + require('internal/vm/module'); | | 99 | + const { callbackMap } = internalBinding('module_wrap'); | | 100 | + const wrapped = importModuleDynamicallyWrap(importModuleDynamically); | | 101 | + const func = result.function; | | 102 | + callbackMap.set(result.cacheKey, { | | 103 | + importModuleDynamically: (s, _k, i) => wrapped(s, func, i), | | 104 | + }); | | 105 | + } | | 106 | + | | 107 | + return result; | | 108 | +} | | 109 | + | | 110 | +module.exports = { | | 111 | + internalCompileFunction, | | 112 | + isContext, | | 113 | +}; |
|