forked from kevinsawicki/coffeestack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.coffee
105 lines (85 loc) · 3.37 KB
/
index.coffee
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
99
100
101
102
103
104
105
crypto = require 'crypto'
fs = require 'fs-plus'
path = require 'path'
CoffeeScriptVersion = null # defer until used
CoffeeScript = null # defer until used
SourceMapConsumer = null # defer until used
cachePath = null
getCachePath = (code) ->
return unless cachePath
digest = crypto.createHash('sha1').update(code, 'utf8').digest('hex')
CoffeeScriptVersion ?= require('coffee-script/package.json').version
path.join(cachePath, CoffeeScriptVersion, "#{digest}.json")
getCachedSourceMap = (codeCachePath) ->
if fs.isFileSync(codeCachePath)
try
return fs.readFileSync(codeCachePath, 'utf8')
return
writeSourceMapToCache = (codeCachePath, sourceMap) ->
if codeCachePath
try
fs.writeFileSync(codeCachePath, sourceMap)
return
loadCoffeeScript = ->
coffee = require 'coffee-script'
# Work around for https://github.com/jashkenas/coffeescript/issues/3890
coffeePrepareStackTrace = Error.prepareStackTrace
if coffeePrepareStackTrace?
Error.prepareStackTrace = (error, stack) ->
try
return coffeePrepareStackTrace(error, stack)
catch coffeeError
return stack
coffee
compileSourceMap = (code, filePath, codeCachePath) ->
CoffeeScript ?= loadCoffeeScript()
{v3SourceMap} = CoffeeScript.compile(code, {sourceMap: true, filename: filePath})
writeSourceMapToCache(codeCachePath, v3SourceMap)
v3SourceMap
getSourceMapPosition = (sourceMapContents, line, column)->
SourceMapConsumer ?= require('source-map').SourceMapConsumer
sourceMap = new SourceMapConsumer(sourceMapContents)
sourceMap.originalPositionFor({line, column})
convertLine = (filePath, line, column, sourceMaps={}) ->
try
unless sourceMapContents = sourceMaps[filePath]
if path.extname(filePath) is '.js'
sourceMapPath = "#{filePath}.map"
sourceMapContents = fs.readFileSync(sourceMapPath, 'utf8')
else
code = fs.readFileSync(filePath, 'utf8')
codeCachePath = getCachePath(code)
sourceMapContents = getCachedSourceMap(codeCachePath)
sourceMapContents ?= compileSourceMap(code, filePath, codeCachePath)
if sourceMapContents
sourceMaps[filePath] = sourceMapContents
position = getSourceMapPosition(sourceMapContents, line, column)
if position.line? and position.column?
if position.source and position.source isnt '.'
source = path.resolve(filePath, '..', position.source)
else
source = filePath
return {line: position.line, column: position.column, source}
null
convertStackTrace = (stackTrace, sourceMaps={}) ->
return stackTrace unless stackTrace
convertedLines = []
atLinePattern = /^(\s+at .* )\((.*):(\d+):(\d+)\)/
for stackTraceLine in stackTrace.split('\n')
if match = atLinePattern.exec(stackTraceLine)
filePath = match[2]
line = match[3]
column = match[4]
if path.extname(filePath) is '.js'
mappedLine = convertLine(filePath, line, column, sourceMaps)
if mappedLine?
convertedLines.push("#{match[1]}(#{mappedLine.source}:#{mappedLine.line}:#{mappedLine.column})")
else
convertedLines.push(stackTraceLine)
else
convertedLines.push(stackTraceLine)
convertedLines.join('\n')
exports.convertLine = convertLine
exports.convertStackTrace = convertStackTrace
exports.setCacheDirectory = (newCachePath) -> cachePath = newCachePath
exports.getCacheDirectory = -> cachePath