-
Notifications
You must be signed in to change notification settings - Fork 1
/
sourceMap.js
98 lines (85 loc) · 3.03 KB
/
sourceMap.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import esprima from 'esprima'
import { SourceMapGenerator, SourceMapConsumer } from 'source-map'
import path from 'path'
/**
* @param {Object} sourceMap Source map to apply onto.
* @param {Object} applicator Source map to apply.
* @return {Object} transformed source map
*/
export function apply(sourceMap, applicator) {
var cons = new SourceMapConsumer(sourceMap)
var applCons = new SourceMapConsumer(applicator)
var generator = SourceMapGenerator.fromSourceMap(applCons)
// TODO: use the default (applicator.file) instead of applicator.sources[0]
generator.applySourceMap(cons, applicator.sources[0])
return generator.toJSON()
}
/**
* @param {Array} sourceMaps Array of source maps to concatenate.
* @param {Array} offsets Contains the offset within the concatenated map for each source map (the array must be the same length as the sourceMaps parameter).
* @return {Object} Concatenated source maps (you may wish to set the "file" property)
*/
export function concatenate(sourceMaps, offsets) {
var generator = new SourceMapGenerator()
var consumers = sourceMaps.map(sourceMap => new SourceMapConsumer(sourceMap))
// TODO: look for content collisions in consumers?
consumers.forEach((consumer, sourceMapIdx) => {
consumer.sourcesContent.forEach((content, i) => {
generator.setSourceContent(consumer.sources[i], content)
})
var offset = offsets[sourceMapIdx]
consumer.eachMapping(mapping => {
generator.addMapping({
generated: {
line: mapping.generatedLine + offset,
column: mapping.generatedColumn
},
original: {
line: mapping.originalLine,
column: mapping.originalColumn
},
source: mapping.source,
name: mapping.name
})
})
})
return generator.toJSON()
}
/**
* @param {String} sourceType js/css
* @param {String} sourcePath path to source file.
* @return {Object} identity source map.
*/
export function generateIdentitySourceMap(sourceType, sourcePath, data) {
let tokens
if (sourceType === 'js') {
tokens = esprima.tokenize(data, { loc: true })
}
else if (sourceType === 'css') {
// TODO: set tokens
}
if (! tokens)
return {}
const generator = new SourceMapGenerator({ file: path.basename(sourcePath) })
tokens.forEach(function(token) {
var loc = token.loc.start
generator.addMapping({ generated: loc, original: loc, source: sourcePath })
})
return generator.toJSON()
}
/**
* Like indexOf but return source map style line/column data.
* @return {Object} { line, column } of matching element or null if not found.
*/
export function positionOf(haystack, needle) {
var index = haystack.indexOf(needle)
if (index === -1)
return null
var line = 1, lineOffset = -1, nextLineOffset = haystack.indexOf('\n')
while (nextLineOffset <= index && nextLineOffset !== -1) {
lineOffset = nextLineOffset
++line
nextLineOffset = haystack.indexOf('\n', lineOffset + 1)
}
return { line, column: index - lineOffset - 1 } // first column is 0
}