Projekt

Obecné

Profil

Stáhnout (5.46 KB) Statistiky
| Větev: | Revize:
1
/*
2
	MIT License http://www.opensource.org/licenses/mit-license.php
3
	Author Tobias Koppers @sokra
4
*/
5

    
6
"use strict";
7

    
8
var SourceNode = require("source-map").SourceNode;
9
var SourceMapConsumer = require("source-map").SourceMapConsumer;
10

    
11
var applySourceMap = function(
12
	sourceNode,
13
	sourceMapConsumer,
14
	sourceFile,
15
	removeGeneratedCodeForSourceFile
16
) {
17
	// The following notations are used to name stuff:
18
	// Left <------------> Middle <-------------------> Right
19
	// Input arguments:
20
	//        sourceNode                                       - Code mapping from Left to Middle
21
	//                   sourceFile                            - Name of a Middle file
22
	//                              sourceMapConsumer          - Code mapping from Middle to Right
23
	// Variables:
24
	//           l2m                      m2r
25
	// Left <-----------------------------------------> Right
26
	// Variables:
27
	//                       l2r
28

    
29
	var l2rResult = new SourceNode();
30
	var l2rOutput = [];
31

    
32
	var middleSourceContents = {};
33

    
34
	var m2rMappingsByLine = {};
35

    
36
	var rightSourceContentsSet = {};
37
	var rightSourceContentsLines = {};
38

    
39
	// Store all mappings by generated line
40
	sourceMapConsumer.eachMapping(
41
		function(mapping) {
42
			(m2rMappingsByLine[mapping.generatedLine] =
43
				m2rMappingsByLine[mapping.generatedLine] || []).push(mapping);
44
		},
45
		null,
46
		SourceMapConsumer.GENERATED_ORDER
47
	);
48

    
49
	// Store all source contents
50
	sourceNode.walkSourceContents(function(source, content) {
51
		middleSourceContents["$" + source] = content;
52
	});
53

    
54
	var middleSource = middleSourceContents["$" + sourceFile];
55
	var middleSourceLines = middleSource ? middleSource.split("\n") : undefined;
56

    
57
	// Walk all left to middle mappings
58
	sourceNode.walk(function(chunk, middleMapping) {
59
		var source;
60

    
61
		// Find a mapping from middle to right
62
		if(
63
			middleMapping.source === sourceFile &&
64
			middleMapping.line &&
65
			m2rMappingsByLine[middleMapping.line]
66
		) {
67
			var m2rBestFit;
68
			var m2rMappings = m2rMappingsByLine[middleMapping.line];
69
			// Note: if this becomes a performance problem, use binary search
70
			for(var i = 0; i < m2rMappings.length; i++) {
71
				if(m2rMappings[i].generatedColumn <= middleMapping.column) {
72
					m2rBestFit = m2rMappings[i];
73
				}
74
			}
75
			if(m2rBestFit) {
76
				var allowMiddleName = false;
77
				var middleLine;
78
				var rightSourceContent;
79
				var rightSourceContentLines;
80
				var rightSource = m2rBestFit.source;
81
				// Check if we have middle and right source for this mapping
82
				// Then we could have an "identify" mapping
83
				if(
84
					middleSourceLines &&
85
					rightSource &&
86
					(middleLine = middleSourceLines[m2rBestFit.generatedLine - 1]) &&
87
					((rightSourceContentLines = rightSourceContentsLines[rightSource]) ||
88
						(rightSourceContent = sourceMapConsumer.sourceContentFor(
89
							rightSource,
90
							true
91
						)))
92
				) {
93
					if(!rightSourceContentLines) {
94
						rightSourceContentLines = rightSourceContentsLines[
95
							rightSource
96
						] = rightSourceContent.split("\n");
97
					}
98
					var rightLine = rightSourceContentLines[m2rBestFit.originalLine - 1];
99
					if(rightLine) {
100
						var offset = middleMapping.column - m2rBestFit.generatedColumn;
101
						if(offset > 0) {
102
							var middlePart = middleLine.slice(
103
								m2rBestFit.generatedColumn,
104
								middleMapping.column
105
							);
106
							var rightPart = rightLine.slice(
107
								m2rBestFit.originalColumn,
108
								m2rBestFit.originalColumn + offset
109
							);
110
							if(middlePart === rightPart) {
111
								// When original and generated code is equal we assume we have an "identity" mapping
112
								// In this case we can offset the original position
113
								m2rBestFit = Object.assign({}, m2rBestFit, {
114
									originalColumn: m2rBestFit.originalColumn + offset,
115
									generatedColumn: middleMapping.column
116
								});
117
							}
118
						}
119
						if(!m2rBestFit.name && middleMapping.name) {
120
							allowMiddleName =
121
								rightLine.slice(
122
									m2rBestFit.originalColumn,
123
									m2rBestFit.originalColumn + middleMapping.name.length
124
								) === middleMapping.name;
125
						}
126
					}
127
				}
128

    
129
				// Construct a left to right node from the found middle to right mapping
130
				source = m2rBestFit.source;
131
				l2rOutput.push(
132
					new SourceNode(
133
						m2rBestFit.originalLine,
134
						m2rBestFit.originalColumn,
135
						source,
136
						chunk,
137
						allowMiddleName ? middleMapping.name : m2rBestFit.name
138
					)
139
				);
140

    
141
				// Set the source contents once
142
				if(!("$" + source in rightSourceContentsSet)) {
143
					rightSourceContentsSet["$" + source] = true;
144
					var sourceContent = sourceMapConsumer.sourceContentFor(source, true);
145
					if(sourceContent) {
146
						l2rResult.setSourceContent(source, sourceContent);
147
					}
148
				}
149
				return;
150
			}
151
		}
152

    
153
		if((removeGeneratedCodeForSourceFile && middleMapping.source === sourceFile) || !middleMapping.source) {
154
			// Construct a left to middle node with only generated code
155
			// Because user do not want mappings to middle sources
156
			// Or this chunk has no mapping
157
			l2rOutput.push(chunk);
158
			return;
159
		}
160

    
161
		// Construct a left to middle node
162
		source = middleMapping.source;
163
		l2rOutput.push(
164
			new SourceNode(
165
				middleMapping.line,
166
				middleMapping.column,
167
				source,
168
				chunk,
169
				middleMapping.name
170
			)
171
		);
172
		if("$" + source in middleSourceContents) {
173
			if(!("$" + source in rightSourceContentsSet)) {
174
				l2rResult.setSourceContent(source, middleSourceContents["$" + source]);
175
				delete middleSourceContents["$" + source];
176
			}
177
		}
178
	});
179

    
180
	// Put output into the resulting SourceNode
181
	l2rResult.add(l2rOutput);
182
	return l2rResult;
183
};
184

    
185
module.exports = applySourceMap;
(11-11/12)