refactor(ngcc): guard against a crash if source-map flattening fails (#35718)

Source-maps in the wild could be badly formatted,
causing the source-map flattening processing to fail
unexpectedly. Rather than causing the whole of ngcc
to crash, we gracefully fallback to just returning the
generated source-map instead.

PR Close #35718
This commit is contained in:
Pete Bacon Darwin 2020-02-27 19:50:14 +00:00 committed by Matias Niemelä
parent 73cf7d5cb4
commit 5d8f7da3aa
3 changed files with 28 additions and 16 deletions

View File

@ -111,7 +111,7 @@ export class DtsRenderer {
this.dtsFormatter.addImports( this.dtsFormatter.addImports(
outputText, importManager.getAllImports(dtsFile.fileName), dtsFile); outputText, importManager.getAllImports(dtsFile.fileName), dtsFile);
return renderSourceAndMap(this.fs, dtsFile, outputText); return renderSourceAndMap(this.logger, this.fs, dtsFile, outputText);
} }
private getTypingsFilesToRender( private getTypingsFilesToRender(

View File

@ -114,7 +114,7 @@ export class Renderer {
} }
if (compiledFile || switchMarkerAnalysis || isEntryPoint) { if (compiledFile || switchMarkerAnalysis || isEntryPoint) {
return renderSourceAndMap(this.fs, sourceFile, outputText); return renderSourceAndMap(this.logger, this.fs, sourceFile, outputText);
} else { } else {
return []; return [];
} }

View File

@ -12,6 +12,7 @@ import {FileSystem, absoluteFromSourceFile, basename, absoluteFrom} from '../../
import {FileToWrite} from './utils'; import {FileToWrite} from './utils';
import {SourceFileLoader} from '../sourcemaps/source_file_loader'; import {SourceFileLoader} from '../sourcemaps/source_file_loader';
import {RawSourceMap} from '../sourcemaps/raw_source_map'; import {RawSourceMap} from '../sourcemaps/raw_source_map';
import {Logger} from '../logging/logger';
export interface SourceMapInfo { export interface SourceMapInfo {
source: string; source: string;
@ -24,28 +25,39 @@ export interface SourceMapInfo {
* with an appropriate source-map comment pointing to the merged source-map. * with an appropriate source-map comment pointing to the merged source-map.
*/ */
export function renderSourceAndMap( export function renderSourceAndMap(
fs: FileSystem, sourceFile: ts.SourceFile, generatedMagicString: MagicString): FileToWrite[] { logger: Logger, fs: FileSystem, sourceFile: ts.SourceFile,
generatedMagicString: MagicString): FileToWrite[] {
const generatedPath = absoluteFromSourceFile(sourceFile); const generatedPath = absoluteFromSourceFile(sourceFile);
const generatedMapPath = absoluteFrom(`${generatedPath}.map`); const generatedMapPath = absoluteFrom(`${generatedPath}.map`);
const generatedContent = generatedMagicString.toString(); const generatedContent = generatedMagicString.toString();
const generatedMap: RawSourceMap = generatedMagicString.generateMap( const generatedMap: RawSourceMap = generatedMagicString.generateMap(
{file: generatedPath, source: generatedPath, includeContent: true}); {file: generatedPath, source: generatedPath, includeContent: true});
const loader = new SourceFileLoader(fs); try {
const generatedFile = loader.loadSourceFile( const loader = new SourceFileLoader(fs);
generatedPath, generatedContent, {map: generatedMap, mapPath: generatedMapPath}); const generatedFile = loader.loadSourceFile(
generatedPath, generatedContent, {map: generatedMap, mapPath: generatedMapPath});
const rawMergedMap: RawSourceMap = generatedFile.renderFlattenedSourceMap(); const rawMergedMap: RawSourceMap = generatedFile.renderFlattenedSourceMap();
const mergedMap = fromObject(rawMergedMap); const mergedMap = fromObject(rawMergedMap);
if (generatedFile.sources[0]?.inline) {
if (generatedFile.sources[0]?.inline) { // The input source-map was inline so make the output one inline too.
// The input source-map was inline so make the output one inline too. return [
return [{path: generatedPath, contents: `${generatedFile.contents}\n${mergedMap.toComment()}`}]; {path: generatedPath, contents: `${generatedFile.contents}\n${mergedMap.toComment()}`}
} else { ];
const sourceMapComment = generateMapFileComment(`${basename(generatedPath)}.map`); } else {
const sourceMapComment = generateMapFileComment(`${basename(generatedPath)}.map`);
return [
{path: generatedPath, contents: `${generatedFile.contents}\n${sourceMapComment}`},
{path: generatedMapPath, contents: mergedMap.toJSON()}
];
}
} catch (e) {
logger.error(
`Error when flattening the source-map "${generatedMapPath}" for "${generatedPath}": ${e.toString()}`);
return [ return [
{path: generatedPath, contents: `${generatedFile.contents}\n${sourceMapComment}`}, {path: generatedPath, contents: generatedContent},
{path: generatedMapPath, contents: mergedMap.toJSON()} {path: generatedMapPath, contents: fromObject(generatedMap).toJSON()},
]; ];
} }
} }