| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b86f575 commit 34221a1
16 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1375,7 +1375,7 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache, format) { | |||
| 1375 | 1375 | // Cache the source map for the module if present. | |
| 1376 | 1376 | const { sourceMapURL } = script; | |
| 1377 | 1377 | if (sourceMapURL) { | |
| 1378 | - maybeCacheSourceMap(filename, content, this, false, undefined, sourceMapURL); | ||
| 1378 | + maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, sourceMapURL); | ||
| 1379 | 1379 | } | |
| 1380 | 1380 | ||
| 1381 | 1381 | return { | |
@@ -1398,7 +1398,7 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache, format) { | |||
| 1398 | 1398 | ||
| 1399 | 1399 | // Cache the source map for the module if present. | |
| 1400 | 1400 | if (result.sourceMapURL) { | |
| 1401 | - maybeCacheSourceMap(filename, content, this, false, undefined, result.sourceMapURL); | ||
| 1401 | + maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, result.sourceMapURL); | ||
| 1402 | 1402 | } | |
| 1403 | 1403 | ||
| 1404 | 1404 | return result; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -178,13 +178,12 @@ translators.set('module', function moduleStrategy(url, source, isMain) { | |||
| 178 | 178 | function loadCJSModule(module, source, url, filename, isMain) { | |
| 179 | 179 | const compileResult = compileFunctionForCJSLoader(source, filename, isMain, false); | |
| 180 | 180 | ||
| 181 | + const { function: compiledWrapper, sourceMapURL } = compileResult; | ||
| 181 | 182 | // Cache the source map for the cjs module if present. | |
| 182 | - if (compileResult.sourceMapURL) { | ||
| 183 | - maybeCacheSourceMap(url, source, null, false, undefined, compileResult.sourceMapURL); | ||
| 183 | + if (sourceMapURL) { | ||
| 184 | + maybeCacheSourceMap(url, source, module, false, undefined, sourceMapURL); | ||
| 184 | 185 | } | |
| 185 | 186 | ||
| 186 | - const compiledWrapper = compileResult.function; | ||
| 187 | - | ||
| 188 | 187 | const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader(); | |
| 189 | 188 | const __dirname = dirname(filename); | |
| 190 | 189 | // eslint-disable-next-line func-name-matching,func-style | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -343,7 +343,7 @@ function compileSourceTextModule(url, source, cascadedLoader) { | |||
| 343 | 343 | } | |
| 344 | 344 | // Cache the source map for the module if present. | |
| 345 | 345 | if (wrap.sourceMapURL) { | |
| 346 | - maybeCacheSourceMap(url, source, null, false, undefined, wrap.sourceMapURL); | ||
| 346 | + maybeCacheSourceMap(url, source, wrap, false, undefined, wrap.sourceMapURL); | ||
| 347 | 347 | } | |
| 348 | 348 | return wrap; | |
| 349 | 349 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -139,9 +139,15 @@ function getOriginalSymbolName(sourceMap, callSite, callerCallSite) { | |||
| 139 | 139 | } | |
| 140 | 140 | } | |
| 141 | 141 | ||
| 142 | - // Places a snippet of code from where the exception was originally thrown | ||
| 143 | - // above the stack trace. This logic is modeled after GetErrorSource in | ||
| 144 | - // node_errors.cc. | ||
| 142 | + /** | ||
| 143 | + * Return a snippet of code from where the exception was originally thrown | ||
| 144 | + * above the stack trace. This called from GetErrorSource in node_errors.cc. | ||
| 145 | + * @param {import('internal/source_map/source_map').SourceMap} sourceMap - the source map to be used | ||
| 146 | + * @param {string} originalSourcePath - path or url of the original source | ||
| 147 | + * @param {number} originalLine - line number in the original source | ||
| 148 | + * @param {number} originalColumn - column number in the original source | ||
| 149 | + * @returns {string | undefined} - the exact line in the source content or undefined if file not found | ||
| 150 | + */ | ||
| 145 | 151 | function getErrorSource( | |
| 146 | 152 | sourceMap, | |
| 147 | 153 | originalSourcePath, | |
@@ -179,6 +185,12 @@ function getErrorSource( | |||
| 179 | 185 | return exceptionLine; | |
| 180 | 186 | } | |
| 181 | 187 | ||
| 188 | + /** | ||
| 189 | + * Retrieve the original source code from the source map's `sources` list or disk. | ||
| 190 | + * @param {import('internal/source_map/source_map').SourceMap.payload} payload | ||
| 191 | + * @param {string} originalSourcePath - path or url of the original source | ||
| 192 | + * @returns {string | undefined} - the source content or undefined if file not found | ||
| 193 | + */ | ||
| 182 | 194 | function getOriginalSource(payload, originalSourcePath) { | |
| 183 | 195 | let source; | |
| 184 | 196 | // payload.sources has been normalized to be an array of absolute urls. | |
@@ -202,6 +214,13 @@ function getOriginalSource(payload, originalSourcePath) { | |||
| 202 | 214 | return source; | |
| 203 | 215 | } | |
| 204 | 216 | ||
| 217 | + /** | ||
| 218 | + * Retrieve exact line in the original source code from the source map's `sources` list or disk. | ||
| 219 | + * @param {string} fileName - actual file name | ||
| 220 | + * @param {number} lineNumber - actual line number | ||
| 221 | + * @param {number} columnNumber - actual column number | ||
| 222 | + * @returns {string | undefined} - the source content or undefined if file not found | ||
| 223 | + */ | ||
| 205 | 224 | function getSourceMapErrorSource(fileName, lineNumber, columnNumber) { | |
| 206 | 225 | const sm = findSourceMap(fileName); | |
| 207 | 226 | if (sm === undefined) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,6 @@ | |||
| 3 | 3 | const { | |
| 4 | 4 | ArrayPrototypePush, | |
| 5 | 5 | JSONParse, | |
| 6 | - ObjectKeys, | ||
| 7 | 6 | RegExpPrototypeExec, | |
| 8 | 7 | SafeMap, | |
| 9 | 8 | StringPrototypeCodePointAt, | |
@@ -25,17 +24,15 @@ const { | |||
| 25 | 24 | } = require('internal/errors'); | |
| 26 | 25 | const { getLazy } = require('internal/util'); | |
| 27 | 26 | ||
| 28 | - // Since the CJS module cache is mutable, which leads to memory leaks when | ||
| 29 | - // modules are deleted, we use a WeakMap so that the source map cache will | ||
| 30 | - // be purged automatically: | ||
| 31 | - const getCjsSourceMapCache = getLazy(() => { | ||
| 32 | - const { IterableWeakMap } = require('internal/util/iterable_weak_map'); | ||
| 33 | - return new IterableWeakMap(); | ||
| 27 | + const getModuleSourceMapCache = getLazy(() => { | ||
| 28 | + const { SourceMapCacheMap } = require('internal/source_map/source_map_cache_map'); | ||
| 29 | + return new SourceMapCacheMap(); | ||
| 34 | 30 | }); | |
| 35 | 31 | ||
| 36 | - // The esm cache is not mutable, so we can use a Map without memory concerns: | ||
| 37 | - const esmSourceMapCache = new SafeMap(); | ||
| 38 | - // The generated sources is not mutable, so we can use a Map without memory concerns: | ||
| 32 | + // The generated source module/script instance is not accessible, so we can use | ||
| 33 | + // a Map without memory concerns. Separate generated source entries with the module | ||
| 34 | + // source entries to avoid overriding the module source entries with arbitrary | ||
| 35 | + // source url magic comments. | ||
| 39 | 36 | const generatedSourceMapCache = new SafeMap(); | |
| 40 | 37 | const kLeadingProtocol = /^\w+:\/\//; | |
| 41 | 38 | const kSourceMappingURLMagicComment = /\/[*/]#\s+sourceMappingURL=(?<sourceMappingURL>[^\s]+)/g; | |
@@ -52,6 +49,10 @@ function getSourceMapsEnabled() { | |||
| 52 | 49 | return sourceMapsEnabled; | |
| 53 | 50 | } | |
| 54 | 51 | ||
| 52 | + /** | ||
| 53 | + * Enables or disables source maps programmatically. | ||
| 54 | + * @param {boolean} val | ||
| 55 | + */ | ||
| 55 | 56 | function setSourceMapsEnabled(val) { | |
| 56 | 57 | validateBoolean(val, 'val'); | |
| 57 | 58 | ||
@@ -72,6 +73,14 @@ function setSourceMapsEnabled(val) { | |||
| 72 | 73 | sourceMapsEnabled = val; | |
| 73 | 74 | } | |
| 74 | 75 | ||
| 76 | + /** | ||
| 77 | + * Extracts the source url from the content if present. For example | ||
| 78 | + * //# sourceURL=file:///path/to/file | ||
| 79 | + * | ||
| 80 | + * Read more at: https://tc39.es/source-map-spec/#linking-evald-code-to-named-generated-code | ||
| 81 | + * @param {string} content - source content | ||
| 82 | + * @returns {string | null} source url or null if not present | ||
| 83 | + */ | ||
| 75 | 84 | function extractSourceURLMagicComment(content) { | |
| 76 | 85 | let match; | |
| 77 | 86 | let matchSourceURL; | |
@@ -90,6 +99,14 @@ function extractSourceURLMagicComment(content) { | |||
| 90 | 99 | return sourceURL; | |
| 91 | 100 | } | |
| 92 | 101 | ||
| 102 | + /** | ||
| 103 | + * Extracts the source map url from the content if present. For example | ||
| 104 | + * //# sourceMappingURL=file:///path/to/file | ||
| 105 | + * | ||
| 106 | + * Read more at: https://tc39.es/source-map-spec/#linking-generated-code | ||
| 107 | + * @param {string} content - source content | ||
| 108 | + * @returns {string | null} source map url or null if not present | ||
| 109 | + */ | ||
| 93 | 110 | function extractSourceMapURLMagicComment(content) { | |
| 94 | 111 | let match; | |
| 95 | 112 | let lastMatch; | |
@@ -104,7 +121,17 @@ function extractSourceMapURLMagicComment(content) { | |||
| 104 | 121 | return lastMatch.groups.sourceMappingURL; | |
| 105 | 122 | } | |
| 106 | 123 | ||
| 107 | - function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSource, sourceURL, sourceMapURL) { | ||
| 124 | + /** | ||
| 125 | + * Caches the source map if it is present in the content, with the given filename, moduleInstance, and sourceURL. | ||
| 126 | + * @param {string} filename - the actual filename | ||
| 127 | + * @param {string} content - the actual source content | ||
| 128 | + * @param {import('internal/modules/cjs/loader').Module | ModuleWrap} moduleInstance - a module instance that | ||
| 129 | + * associated with the source, once this is reclaimed, the source map entry will be removed from the cache | ||
| 130 | + * @param {boolean} isGeneratedSource - if the source was generated and evaluated with the global eval | ||
| 131 | + * @param {string | undefined} sourceURL - the source url | ||
| 132 | + * @param {string | undefined} sourceMapURL - the source map url | ||
| 133 | + */ | ||
| 134 | + function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSource, sourceURL, sourceMapURL) { | ||
| 108 | 135 | const sourceMapsEnabled = getSourceMapsEnabled(); | |
| 109 | 136 | if (!(process.env.NODE_V8_COVERAGE || sourceMapsEnabled)) return; | |
| 110 | 137 | const { normalizeReferrerURL } = require('internal/modules/helpers'); | |
@@ -130,45 +157,32 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo | |||
| 130 | 157 | } | |
| 131 | 158 | ||
| 132 | 159 | const data = dataFromUrl(filename, sourceMapURL); | |
| 133 | - const url = data ? null : sourceMapURL; | ||
| 134 | - if (cjsModuleInstance) { | ||
| 135 | - getCjsSourceMapCache().set(cjsModuleInstance, { | ||
| 136 | - __proto__: null, | ||
| 137 | - filename, | ||
| 138 | - lineLengths: lineLengths(content), | ||
| 139 | - data, | ||
| 140 | - url, | ||
| 141 | - sourceURL, | ||
| 142 | - }); | ||
| 143 | - } else if (isGeneratedSource) { | ||
| 144 | - const entry = { | ||
| 145 | - __proto__: null, | ||
| 146 | - lineLengths: lineLengths(content), | ||
| 147 | - data, | ||
| 148 | - url, | ||
| 149 | - sourceURL, | ||
| 150 | - }; | ||
| 160 | + const entry = { | ||
| 161 | + __proto__: null, | ||
| 162 | + lineLengths: lineLengths(content), | ||
| 163 | + data, | ||
| 164 | + // Save the source map url if it is not a data url. | ||
| 165 | + sourceMapURL: data ? null : sourceMapURL, | ||
| 166 | + sourceURL, | ||
| 167 | + }; | ||
| 168 | + | ||
| 169 | + if (isGeneratedSource) { | ||
| 151 | 170 | generatedSourceMapCache.set(filename, entry); | |
| 152 | 171 | if (sourceURL) { | |
| 153 | 172 | generatedSourceMapCache.set(sourceURL, entry); | |
| 154 | 173 | } | |
| 155 | - } else { | ||
| 156 | - // If there is no cjsModuleInstance and is not generated source assume we are in a | ||
| 157 | - // "modules/esm" context. | ||
| 158 | - const entry = { | ||
| 159 | - __proto__: null, | ||
| 160 | - lineLengths: lineLengths(content), | ||
| 161 | - data, | ||
| 162 | - url, | ||
| 163 | - sourceURL, | ||
| 164 | - }; | ||
| 165 | - esmSourceMapCache.set(filename, entry); | ||
| 166 | - if (sourceURL) { | ||
| 167 | - esmSourceMapCache.set(sourceURL, entry); | ||
| 168 | - } | ||
| 174 | + return; | ||
| 169 | 175 | } | |
| 176 | + // If it is not a generated source, we assume we are in a "cjs/esm" | ||
| 177 | + // context. | ||
| 178 | + const keys = sourceURL ? [filename, sourceURL] : [filename]; | ||
| 179 | + getModuleSourceMapCache().set(keys, entry, moduleInstance); | ||
| 170 | 180 | } | |
| 171 | 181 | ||
| 182 | + /** | ||
| 183 | + * Caches the source map if it is present in the eval'd source. | ||
| 184 | + * @param {string} content - the eval'd source code | ||
| 185 | + */ | ||
| 172 | 186 | function maybeCacheGeneratedSourceMap(content) { | |
| 173 | 187 | const sourceMapsEnabled = getSourceMapsEnabled(); | |
| 174 | 188 | if (!(process.env.NODE_V8_COVERAGE || sourceMapsEnabled)) return; | |
@@ -186,6 +200,14 @@ function maybeCacheGeneratedSourceMap(content) { | |||
| 186 | 200 | } | |
| 187 | 201 | } | |
| 188 | 202 | ||
| 203 | + /** | ||
| 204 | + * Resolves source map payload data from the source url and source map url. | ||
| 205 | + * If the source map url is a data url, the data is returned. | ||
| 206 | + * Otherwise the source map url is resolved to a file path and the file is read. | ||
| 207 | + * @param {string} sourceURL - url of the source file | ||
| 208 | + * @param {string} sourceMappingURL - url of the source map | ||
| 209 | + * @returns {object} deserialized source map JSON object | ||
| 210 | + */ | ||
| 189 | 211 | function dataFromUrl(sourceURL, sourceMappingURL) { | |
| 190 | 212 | try { | |
| 191 | 213 | const url = new URL(sourceMappingURL); | |
@@ -227,7 +249,11 @@ function lineLengths(content) { | |||
| 227 | 249 | return output; | |
| 228 | 250 | } | |
| 229 | 251 | ||
| 230 | - | ||
| 252 | + /** | ||
| 253 | + * Read source map from file. | ||
| 254 | + * @param {string} mapURL - file url of the source map | ||
| 255 | + * @returns {object} deserialized source map JSON object | ||
| 256 | + */ | ||
| 231 | 257 | function sourceMapFromFile(mapURL) { | |
| 232 | 258 | try { | |
| 233 | 259 | const fs = require('fs'); | |
@@ -281,56 +307,44 @@ function sourcesToAbsolute(baseURL, data) { | |||
| 281 | 307 | return data; | |
| 282 | 308 | } | |
| 283 | 309 | ||
| 284 | - // WARNING: The `sourceMapCacheToObject` and `appendCJSCache` run during | ||
| 285 | - // shutdown. In particular, they also run when Workers are terminated, making | ||
| 286 | - // it important that they do not call out to any user-provided code, including | ||
| 287 | - // built-in prototypes that might have been tampered with. | ||
| 310 | + // WARNING: The `sourceMapCacheToObject` runs during shutdown. In particular, | ||
| 311 | + // it also runs when Workers are terminated, making it important that it does | ||
| 312 | + // not call out to any user-provided code, including built-in prototypes that | ||
| 313 | + // might have been tampered with. | ||
| 288 | 314 | ||
| 289 | 315 | // Get serialized representation of source-map cache, this is used | |
| 290 | 316 | // to persist a cache of source-maps to disk when NODE_V8_COVERAGE is enabled. | |
| 291 | 317 | function sourceMapCacheToObject() { | |
| 292 | - const obj = { __proto__: null }; | ||
| 293 | - | ||
| 294 | - for (const { 0: k, 1: v } of esmSourceMapCache) { | ||
| 295 | - obj[k] = v; | ||
| 296 | - } | ||
| 297 | - | ||
| 298 | - appendCJSCache(obj); | ||
| 299 | - | ||
| 300 | - if (ObjectKeys(obj).length === 0) { | ||
| 318 | + const moduleSourceMapCache = getModuleSourceMapCache(); | ||
| 319 | + if (moduleSourceMapCache.size === 0) { | ||
| 301 | 320 | return undefined; | |
| 302 | 321 | } | |
| 303 | - return obj; | ||
| 304 | - } | ||
| 305 | 322 | ||
| 306 | - function appendCJSCache(obj) { | ||
| 307 | - for (const value of getCjsSourceMapCache()) { | ||
| 308 | - obj[value.filename] = { | ||
| 323 | + const obj = { __proto__: null }; | ||
| 324 | + for (const { 0: k, 1: v } of moduleSourceMapCache) { | ||
| 325 | + obj[k] = { | ||
| 309 | 326 | __proto__: null, | |
| 310 | - lineLengths: value.lineLengths, | ||
| 311 | - data: value.data, | ||
| 312 | - url: value.url, | ||
| 327 | + lineLengths: v.lineLengths, | ||
| 328 | + data: v.data, | ||
| 329 | + url: v.sourceMapURL, | ||
| 313 | 330 | }; | |
| 314 | 331 | } | |
| 332 | + return obj; | ||
| 315 | 333 | } | |
| 316 | 334 | ||
| 335 | + /** | ||
| 336 | + * Find a source map for a given actual source URL or path. | ||
| 337 | + * @param {string} sourceURL - actual source URL or path | ||
| 338 | + * @returns {import('internal/source_map/source_map').SourceMap | undefined} a source map or undefined if not found | ||
| 339 | + */ | ||
| 317 | 340 | function findSourceMap(sourceURL) { | |
| 318 | 341 | if (RegExpPrototypeExec(kLeadingProtocol, sourceURL) === null) { | |
| 319 | 342 | sourceURL = pathToFileURL(sourceURL).href; | |
| 320 | 343 | } | |
| 321 | 344 | if (!SourceMap) { | |
| 322 | 345 | SourceMap = require('internal/source_map/source_map').SourceMap; | |
| 323 | 346 | } | |
| 324 | - let entry = esmSourceMapCache.get(sourceURL) ?? generatedSourceMapCache.get(sourceURL); | ||
| 325 | - if (entry === undefined) { | ||
| 326 | - for (const value of getCjsSourceMapCache()) { | ||
| 327 | - const filename = value.filename; | ||
| 328 | - const cachedSourceURL = value.sourceURL; | ||
| 329 | - if (sourceURL === filename || sourceURL === cachedSourceURL) { | ||
| 330 | - entry = value; | ||
| 331 | - } | ||
| 332 | - } | ||
| 333 | - } | ||
| 347 | + const entry = getModuleSourceMapCache().get(sourceURL) ?? generatedSourceMapCache.get(sourceURL); | ||
| 334 | 348 | if (entry === undefined) { | |
| 335 | 349 | return undefined; | |
| 336 | 350 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments