-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
src,lib: retrieve parsed source map url from v8 #44798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,7 +97,21 @@ function extractSourceURLMagicComment(content) { | |
return sourceURL; | ||
} | ||
|
||
function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSource, sourceURL) { | ||
function extractSourceMapURLMagicComment(content) { | ||
let match; | ||
let lastMatch; | ||
// A while loop is used here to get the last occurrence of sourceMappingURL. | ||
// This is needed so that we don't match sourceMappingURL in string literals. | ||
while ((match = RegExpPrototypeExec(kSourceMappingURLMagicComment, content))) { | ||
lastMatch = match; | ||
} | ||
if (lastMatch == null) { | ||
return null; | ||
} | ||
return lastMatch.groups.sourceMappingURL; | ||
} | ||
|
||
function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSource, sourceURL, sourceMapURL) { | ||
const sourceMapsEnabled = getSourceMapsEnabled(); | ||
if (!(process.env.NODE_V8_COVERAGE || sourceMapsEnabled)) return; | ||
try { | ||
|
@@ -108,52 +122,52 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo | |
return; | ||
} | ||
|
||
let match; | ||
let lastMatch; | ||
// A while loop is used here to get the last occurrence of sourceMappingURL. | ||
// This is needed so that we don't match sourceMappingURL in string literals. | ||
while ((match = RegExpPrototypeExec(kSourceMappingURLMagicComment, content))) { | ||
lastMatch = match; | ||
if (sourceMapURL === undefined) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it by design that we still do the regex parse when V8 told us that there is no source map? If so, should we add a test case, e.g.:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this fallback is kept here to handle the ES modules? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jkrems @joyeecheung thanks for the suggestion. We don't need to apply the regex again when the parse result of the script indicates that no source mapping URL is available. I've updated the code to eliminate the duplicated scans. It is true that the fallback is left here to handle the ES modules. |
||
sourceMapURL = extractSourceMapURLMagicComment(content); | ||
} | ||
|
||
// Bail out when there is no source map url. | ||
if (typeof sourceMapURL !== 'string') { | ||
return; | ||
} | ||
|
||
if (sourceURL === undefined) { | ||
sourceURL = extractSourceURLMagicComment(content); | ||
} | ||
if (lastMatch) { | ||
const data = dataFromUrl(filename, lastMatch.groups.sourceMappingURL); | ||
const url = data ? null : lastMatch.groups.sourceMappingURL; | ||
if (cjsModuleInstance) { | ||
cjsSourceMapCache.set(cjsModuleInstance, { | ||
filename, | ||
lineLengths: lineLengths(content), | ||
data, | ||
url, | ||
sourceURL, | ||
}); | ||
} else if (isGeneratedSource) { | ||
const entry = { | ||
lineLengths: lineLengths(content), | ||
data, | ||
url, | ||
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. | ||
const entry = { | ||
lineLengths: lineLengths(content), | ||
data, | ||
url, | ||
sourceURL, | ||
}; | ||
esmSourceMapCache.set(filename, entry); | ||
if (sourceURL) { | ||
esmSourceMapCache.set(sourceURL, entry); | ||
} | ||
|
||
const data = dataFromUrl(filename, sourceMapURL); | ||
const url = data ? null : sourceMapURL; | ||
if (cjsModuleInstance) { | ||
cjsSourceMapCache.set(cjsModuleInstance, { | ||
filename, | ||
lineLengths: lineLengths(content), | ||
data, | ||
url, | ||
sourceURL, | ||
}); | ||
} else if (isGeneratedSource) { | ||
const entry = { | ||
lineLengths: lineLengths(content), | ||
data, | ||
url, | ||
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. | ||
const entry = { | ||
lineLengths: lineLengths(content), | ||
data, | ||
url, | ||
sourceURL, | ||
}; | ||
esmSourceMapCache.set(filename, entry); | ||
if (sourceURL) { | ||
esmSourceMapCache.set(sourceURL, entry); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
'use strict'; | ||
|
||
const { | ||
ArrayPrototypeForEach, | ||
} = primordials; | ||
|
||
const { | ||
compileFunction, | ||
isContext: _isContext, | ||
} = internalBinding('contextify'); | ||
const { | ||
validateArray, | ||
validateBoolean, | ||
validateBuffer, | ||
validateFunction, | ||
validateObject, | ||
validateString, | ||
validateUint32, | ||
} = require('internal/validators'); | ||
const { | ||
ERR_INVALID_ARG_TYPE, | ||
} = require('internal/errors').codes; | ||
|
||
function isContext(object) { | ||
validateObject(object, 'object', { __proto__: null, allowArray: true }); | ||
|
||
return _isContext(object); | ||
} | ||
|
||
function internalCompileFunction(code, params, options) { | ||
validateString(code, 'code'); | ||
if (params !== undefined) { | ||
validateArray(params, 'params'); | ||
ArrayPrototypeForEach(params, | ||
(param, i) => validateString(param, `params[${i}]`)); | ||
} | ||
|
||
const { | ||
filename = '', | ||
columnOffset = 0, | ||
lineOffset = 0, | ||
cachedData = undefined, | ||
produceCachedData = false, | ||
parsingContext = undefined, | ||
contextExtensions = [], | ||
importModuleDynamically, | ||
} = options; | ||
|
||
validateString(filename, 'options.filename'); | ||
validateUint32(columnOffset, 'options.columnOffset'); | ||
validateUint32(lineOffset, 'options.lineOffset'); | ||
if (cachedData !== undefined) | ||
validateBuffer(cachedData, 'options.cachedData'); | ||
validateBoolean(produceCachedData, 'options.produceCachedData'); | ||
if (parsingContext !== undefined) { | ||
if ( | ||
typeof parsingContext !== 'object' || | ||
parsingContext === null || | ||
!isContext(parsingContext) | ||
) { | ||
throw new ERR_INVALID_ARG_TYPE( | ||
'options.parsingContext', | ||
'Context', | ||
parsingContext | ||
); | ||
} | ||
} | ||
validateArray(contextExtensions, 'options.contextExtensions'); | ||
ArrayPrototypeForEach(contextExtensions, (extension, i) => { | ||
const name = `options.contextExtensions[${i}]`; | ||
validateObject(extension, name, { __proto__: null, nullable: true }); | ||
}); | ||
|
||
const result = compileFunction( | ||
code, | ||
filename, | ||
lineOffset, | ||
columnOffset, | ||
cachedData, | ||
produceCachedData, | ||
parsingContext, | ||
contextExtensions, | ||
params | ||
); | ||
|
||
if (produceCachedData) { | ||
result.function.cachedDataProduced = result.cachedDataProduced; | ||
} | ||
|
||
if (result.cachedData) { | ||
result.function.cachedData = result.cachedData; | ||
} | ||
|
||
if (importModuleDynamically !== undefined) { | ||
validateFunction(importModuleDynamically, | ||
'options.importModuleDynamically'); | ||
const { importModuleDynamicallyWrap } = | ||
require('internal/vm/module'); | ||
legendecas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const { callbackMap } = internalBinding('module_wrap'); | ||
const wrapped = importModuleDynamicallyWrap(importModuleDynamically); | ||
const func = result.function; | ||
callbackMap.set(result.cacheKey, { | ||
importModuleDynamically: (s, _k, i) => wrapped(s, func, i), | ||
}); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
module.exports = { | ||
internalCompileFunction, | ||
isContext, | ||
}; |
Uh oh!
There was an error while loading. Please reload this page.