UNPKG

3.01 kBJavaScriptView Raw
1
2/**
3 * Module dependencies.
4 */
5
6var SourceMap = require('source-map').SourceMapGenerator;
7var SourceMapConsumer = require('source-map').SourceMapConsumer;
8var sourceMapResolve = require('source-map-resolve');
9var fs = require('fs');
10var path = require('path');
11
12/**
13 * Expose `mixin()`.
14 */
15
16module.exports = mixin;
17
18/**
19 * Ensure Windows-style paths are formatted properly
20 */
21
22const makeFriendlyPath = function(aPath) {
23 return path.sep === "\\" ? aPath.replace(/\\/g, "/").replace(/^[a-z]:\/?/i, "/") : aPath;
24}
25
26/**
27 * Mixin source map support into `compiler`.
28 *
29 * @param {Compiler} compiler
30 * @api public
31 */
32
33function mixin(compiler) {
34 compiler._comment = compiler.comment;
35 compiler.map = new SourceMap();
36 compiler.position = { line: 1, column: 1 };
37 compiler.files = {};
38 for (var k in exports) compiler[k] = exports[k];
39}
40
41/**
42 * Update position.
43 *
44 * @param {String} str
45 * @api private
46 */
47
48exports.updatePosition = function(str) {
49 var lines = str.match(/\n/g);
50 if (lines) this.position.line += lines.length;
51 var i = str.lastIndexOf('\n');
52 this.position.column = ~i ? str.length - i : this.position.column + str.length;
53};
54
55/**
56 * Emit `str`.
57 *
58 * @param {String} str
59 * @param {Object} [pos]
60 * @return {String}
61 * @api private
62 */
63
64exports.emit = function(str, pos) {
65 if (pos) {
66 var sourceFile = makeFriendlyPath(pos.source || 'source.css');
67
68 this.map.addMapping({
69 source: sourceFile,
70 generated: {
71 line: this.position.line,
72 column: Math.max(this.position.column - 1, 0)
73 },
74 original: {
75 line: pos.start.line,
76 column: pos.start.column - 1
77 }
78 });
79
80 this.addFile(sourceFile, pos);
81 }
82
83 this.updatePosition(str);
84
85 return str;
86};
87
88/**
89 * Adds a file to the source map output if it has not already been added
90 * @param {String} file
91 * @param {Object} pos
92 */
93
94exports.addFile = function(file, pos) {
95 if (typeof pos.content !== 'string') return;
96 if (Object.prototype.hasOwnProperty.call(this.files, file)) return;
97
98 this.files[file] = pos.content;
99};
100
101/**
102 * Applies any original source maps to the output and embeds the source file
103 * contents in the source map.
104 */
105
106exports.applySourceMaps = function() {
107 Object.keys(this.files).forEach(function(file) {
108 var content = this.files[file];
109 this.map.setSourceContent(file, content);
110
111 if (this.options.inputSourcemaps !== false) {
112 var originalMap = sourceMapResolve.resolveSync(
113 content, file, fs.readFileSync);
114 if (originalMap) {
115 var map = new SourceMapConsumer(originalMap.map);
116 var relativeTo = originalMap.sourcesRelativeTo;
117 this.map.applySourceMap(map, file, makeFriendlyPath(path.dirname(relativeTo)));
118 }
119 }
120 }, this);
121};
122
123/**
124 * Process comments, drops sourceMap comments.
125 * @param {Object} node
126 */
127
128exports.comment = function(node) {
129 if (/^# sourceMappingURL=/.test(node.comment))
130 return this.emit('', node.position);
131 else
132 return this._comment(node);
133};