diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index dfb42f83f6f1b1..ea87a579636671 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -155,6 +155,9 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc } const data = dataFromUrl(filename, sourceMapURL); + // `data` could be null if the source map is invalid. + // In this case, create a cache entry with null data with source url for test coverage. + const entry = { __proto__: null, lineLengths: lineLengths(content), @@ -277,6 +280,8 @@ function sourceMapFromDataUrl(sourceURL, url) { const parsedData = JSONParse(decodedData); return sourcesToAbsolute(sourceURL, parsedData); } catch (err) { + // TODO(legendecas): warn about invalid source map JSON string. + // But it could be verbose. debug(err); return null; } @@ -331,24 +336,38 @@ function sourceMapCacheToObject() { /** * Find a source map for a given actual source URL or path. + * + * This function may be invoked from user code or test runner, this must not throw + * any exceptions. * @param {string} sourceURL - actual source URL or path * @returns {import('internal/source_map/source_map').SourceMap | undefined} a source map or undefined if not found */ function findSourceMap(sourceURL) { - if (RegExpPrototypeExec(kLeadingProtocol, sourceURL) === null) { - sourceURL = pathToFileURL(sourceURL).href; + if (typeof sourceURL !== 'string') { + return undefined; } + SourceMap ??= require('internal/source_map/source_map').SourceMap; - const entry = getModuleSourceMapCache().get(sourceURL) ?? generatedSourceMapCache.get(sourceURL); - if (entry === undefined) { + try { + if (RegExpPrototypeExec(kLeadingProtocol, sourceURL) === null) { + // If the sourceURL is an invalid path, this will throw an error. + sourceURL = pathToFileURL(sourceURL).href; + } + const entry = getModuleSourceMapCache().get(sourceURL) ?? generatedSourceMapCache.get(sourceURL); + if (entry?.data == null) { + return undefined; + } + + let sourceMap = entry.sourceMap; + if (sourceMap === undefined) { + sourceMap = new SourceMap(entry.data, { lineLengths: entry.lineLengths }); + entry.sourceMap = sourceMap; + } + return sourceMap; + } catch (err) { + debug(err); return undefined; } - let sourceMap = entry.sourceMap; - if (sourceMap === undefined) { - sourceMap = new SourceMap(entry.data, { lineLengths: entry.lineLengths }); - entry.sourceMap = sourceMap; - } - return sourceMap; } module.exports = { diff --git a/test/parallel/test-runner-source-maps-invalid-json.js b/test/parallel/test-runner-source-maps-invalid-json.js new file mode 100644 index 00000000000000..508e2d432117f7 --- /dev/null +++ b/test/parallel/test-runner-source-maps-invalid-json.js @@ -0,0 +1,12 @@ +// Flags: --enable-source-maps +'use strict'; + +require('../common'); +const test = require('node:test'); + +// Verify that test runner can handle invalid source maps. + +test('ok', () => {}); + +// eslint-disable-next-line @stylistic/js/spaced-comment +//# sourceMappingURL=data:application/json;base64,-1