| /* | 
|     MIT License http://www.opensource.org/licenses/mit-license.php | 
|     Author Tobias Koppers @sokra | 
| */ | 
|   | 
| "use strict"; | 
|   | 
| var SourceNode = require("source-map").SourceNode; | 
| var SourceMapConsumer = require("source-map").SourceMapConsumer; | 
|   | 
| var applySourceMap = function( | 
|     sourceNode, | 
|     sourceMapConsumer, | 
|     sourceFile, | 
|     removeGeneratedCodeForSourceFile | 
| ) { | 
|     // The following notations are used to name stuff: | 
|     // Left <------------> Middle <-------------------> Right | 
|     // Input arguments: | 
|     //        sourceNode                                       - Code mapping from Left to Middle | 
|     //                   sourceFile                            - Name of a Middle file | 
|     //                              sourceMapConsumer          - Code mapping from Middle to Right | 
|     // Variables: | 
|     //           l2m                      m2r | 
|     // Left <-----------------------------------------> Right | 
|     // Variables: | 
|     //                       l2r | 
|   | 
|     var l2rResult = new SourceNode(); | 
|     var l2rOutput = []; | 
|   | 
|     var middleSourceContents = {}; | 
|   | 
|     var m2rMappingsByLine = {}; | 
|   | 
|     var rightSourceContentsSet = {}; | 
|     var rightSourceContentsLines = {}; | 
|   | 
|     // Store all mappings by generated line | 
|     sourceMapConsumer.eachMapping( | 
|         function(mapping) { | 
|             (m2rMappingsByLine[mapping.generatedLine] = | 
|                 m2rMappingsByLine[mapping.generatedLine] || []).push(mapping); | 
|         }, | 
|         null, | 
|         SourceMapConsumer.GENERATED_ORDER | 
|     ); | 
|   | 
|     // Store all source contents | 
|     sourceNode.walkSourceContents(function(source, content) { | 
|         middleSourceContents["$" + source] = content; | 
|     }); | 
|   | 
|     var middleSource = middleSourceContents["$" + sourceFile]; | 
|     var middleSourceLines = middleSource ? middleSource.split("\n") : undefined; | 
|   | 
|     // Walk all left to middle mappings | 
|     sourceNode.walk(function(chunk, middleMapping) { | 
|         var source; | 
|   | 
|         // Find a mapping from middle to right | 
|         if( | 
|             middleMapping.source === sourceFile && | 
|             middleMapping.line && | 
|             m2rMappingsByLine[middleMapping.line] | 
|         ) { | 
|             var m2rBestFit; | 
|             var m2rMappings = m2rMappingsByLine[middleMapping.line]; | 
|             // Note: if this becomes a performance problem, use binary search | 
|             for(var i = 0; i < m2rMappings.length; i++) { | 
|                 if(m2rMappings[i].generatedColumn <= middleMapping.column) { | 
|                     m2rBestFit = m2rMappings[i]; | 
|                 } | 
|             } | 
|             if(m2rBestFit) { | 
|                 var allowMiddleName = false; | 
|                 var middleLine; | 
|                 var rightSourceContent; | 
|                 var rightSourceContentLines; | 
|                 var rightSource = m2rBestFit.source; | 
|                 // Check if we have middle and right source for this mapping | 
|                 // Then we could have an "identify" mapping | 
|                 if( | 
|                     middleSourceLines && | 
|                     rightSource && | 
|                     (middleLine = middleSourceLines[m2rBestFit.generatedLine - 1]) && | 
|                     ((rightSourceContentLines = rightSourceContentsLines[rightSource]) || | 
|                         (rightSourceContent = sourceMapConsumer.sourceContentFor( | 
|                             rightSource, | 
|                             true | 
|                         ))) | 
|                 ) { | 
|                     if(!rightSourceContentLines) { | 
|                         rightSourceContentLines = rightSourceContentsLines[ | 
|                             rightSource | 
|                         ] = rightSourceContent.split("\n"); | 
|                     } | 
|                     var rightLine = rightSourceContentLines[m2rBestFit.originalLine - 1]; | 
|                     if(rightLine) { | 
|                         var offset = middleMapping.column - m2rBestFit.generatedColumn; | 
|                         if(offset > 0) { | 
|                             var middlePart = middleLine.slice( | 
|                                 m2rBestFit.generatedColumn, | 
|                                 middleMapping.column | 
|                             ); | 
|                             var rightPart = rightLine.slice( | 
|                                 m2rBestFit.originalColumn, | 
|                                 m2rBestFit.originalColumn + offset | 
|                             ); | 
|                             if(middlePart === rightPart) { | 
|                                 // When original and generated code is equal we assume we have an "identity" mapping | 
|                                 // In this case we can offset the original position | 
|                                 m2rBestFit = Object.assign({}, m2rBestFit, { | 
|                                     originalColumn: m2rBestFit.originalColumn + offset, | 
|                                     generatedColumn: middleMapping.column | 
|                                 }); | 
|                             } | 
|                         } | 
|                         if(!m2rBestFit.name && middleMapping.name) { | 
|                             allowMiddleName = | 
|                                 rightLine.slice( | 
|                                     m2rBestFit.originalColumn, | 
|                                     m2rBestFit.originalColumn + middleMapping.name.length | 
|                                 ) === middleMapping.name; | 
|                         } | 
|                     } | 
|                 } | 
|   | 
|                 // Construct a left to right node from the found middle to right mapping | 
|                 source = m2rBestFit.source; | 
|                 l2rOutput.push( | 
|                     new SourceNode( | 
|                         m2rBestFit.originalLine, | 
|                         m2rBestFit.originalColumn, | 
|                         source, | 
|                         chunk, | 
|                         allowMiddleName ? middleMapping.name : m2rBestFit.name | 
|                     ) | 
|                 ); | 
|   | 
|                 // Set the source contents once | 
|                 if(!("$" + source in rightSourceContentsSet)) { | 
|                     rightSourceContentsSet["$" + source] = true; | 
|                     var sourceContent = sourceMapConsumer.sourceContentFor(source, true); | 
|                     if(sourceContent) { | 
|                         l2rResult.setSourceContent(source, sourceContent); | 
|                     } | 
|                 } | 
|                 return; | 
|             } | 
|         } | 
|   | 
|         if((removeGeneratedCodeForSourceFile && middleMapping.source === sourceFile) || !middleMapping.source) { | 
|             // Construct a left to middle node with only generated code | 
|             // Because user do not want mappings to middle sources | 
|             // Or this chunk has no mapping | 
|             l2rOutput.push(chunk); | 
|             return; | 
|         } | 
|   | 
|         // Construct a left to middle node | 
|         source = middleMapping.source; | 
|         l2rOutput.push( | 
|             new SourceNode( | 
|                 middleMapping.line, | 
|                 middleMapping.column, | 
|                 source, | 
|                 chunk, | 
|                 middleMapping.name | 
|             ) | 
|         ); | 
|         if("$" + source in middleSourceContents) { | 
|             if(!("$" + source in rightSourceContentsSet)) { | 
|                 l2rResult.setSourceContent(source, middleSourceContents["$" + source]); | 
|                 delete middleSourceContents["$" + source]; | 
|             } | 
|         } | 
|     }); | 
|   | 
|     // Put output into the resulting SourceNode | 
|     l2rResult.add(l2rOutput); | 
|     return l2rResult; | 
| }; | 
|   | 
| module.exports = applySourceMap; |