Completed
Push — master ( aef940...96bd55 )
by Vitaly
34s
created

get-source.js (3 issues)

1
"use strict";
2
3
/*  ------------------------------------------------------------------------ */
4
5
const O                 = Object,
0 ignored issues
show
Comprehensibility Best Practice introduced by
You seem to be aliasing the built-in name Object as O. This makes your code very difficult to follow, consider using the built-in name directly.
Loading history...
6
      isBrowser         = (typeof window !== 'undefined') && (window.window === window) && window.navigator,
7
      SourceMapConsumer = require ('source-map').SourceMapConsumer,
8
      path              = require ('./impl/path'),
9
      dataURIToBuffer   = require ('data-uri-to-buffer'),
10
      lastOf            = x => x[x.length - 1]
0 ignored issues
show
The constant lastOf seems to be never used. Consider removing it.
Loading history...
11
12
/*  ------------------------------------------------------------------------ */
13
14
const memoize = f => {
15
    
16
    const m = x => (x in m.cache) ? m.cache[x] : (m.cache[x] = f(x))
17
    m.forgetEverything = () => { m.cache = Object.create (null) }
18
    m.cache = Object.create (null)
19
20
    return m
21
}
22
23
/*  ------------------------------------------------------------------------ */
24
25
const newSourceFileMemoized = memoize (file => new SourceFile (file))
26
27
const getSource = module.exports = file => { return newSourceFileMemoized (path.resolve (file)) }
28
29
getSource.resetCache = () => newSourceFileMemoized.forgetEverything ()
30
getSource.getCache = () => newSourceFileMemoized.cache
31
32
/*  ------------------------------------------------------------------------ */
33
34
class SourceMap {
35
36
    constructor (originalFilePath, sourceMapPath) {
37
38
        this.file = sourceMapPath.startsWith ('data:')
39
                        ? new SourceFile (originalFilePath, dataURIToBuffer (sourceMapPath).toString ())
40
                        : getSource (path.relativeToFile (originalFilePath, sourceMapPath))
41
42
        this.parsed    = (this.file.text && SourceMapConsumer (JSON.parse (this.file.text))) || null
43
        this.sourceFor = memoize (this.sourceFor.bind (this))
44
    }
45
46
    sourceFor (file) {
47
        const content = this.parsed.sourceContentFor (file, true /* return null on missing */)
48
        const fullPath = path.relativeToFile (this.file.path, file)
49
        return content ? new SourceFile (fullPath, content) : getSource (fullPath)
50
    }
51
52
    resolve (loc) {
53
54
        const originalLoc = this.parsed.originalPositionFor (loc)
55
        return originalLoc.source ? this.sourceFor (originalLoc.source)
56
                                        .resolve (O.assign ({}, loc, {
57
                                            line: originalLoc.line,
58
                                            column: originalLoc.column,
59
                                            name: originalLoc.name })) : loc
60
    }
61
}
62
63
/*  ------------------------------------------------------------------------ */
64
65
class SourceFile {
66
67
    constructor (path, text /* optional */) {
68
        
69
        this.path = path
70
71
        if (text) {
72
            this.text = text }
73
74
        else {
75
            try {
76
                if (isBrowser) {
77
78
                    let xhr = new XMLHttpRequest ()
0 ignored issues
show
The variable XMLHttpRequest seems to be never declared. If this is a global, consider adding a /** global: XMLHttpRequest */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
79
80
                        xhr.open ('GET', path, false /* SYNCHRONOUS XHR FTW :) */)
81
                        xhr.send (null)
82
                        
83
                    this.text = xhr.responseText }
84
85
                else {
86
                    this.text = module.require ('fs').readFileSync (path, { encoding: 'utf8' }) } }
87
88
            catch (e) {
89
                this.error = e
90
                this.text = '' } }
91
    }
92
93
    get lines () {
94
        return (this.lines_ = this.lines_ || this.text.split ('\n'))
95
    }
96
97
    get sourceMap () {
98
99
        try {
100
101
            if (this.sourceMap_ === undefined) {
102
103
                // Node v4 does not support destructuring...
104
                // const [,url] = this.text.match (/\u0023 sourceMappingURL=(.+)\n?/) || [undefined, undefined] // escape #, otherwise it will match this exact line.. %)
105
                
106
                const match = this.text.match (/\u0023 sourceMappingURL=(.+)\n?/) || [undefined, undefined] // escape #, otherwise it will match this exact line.. %)
107
                    , url = match[1]
108
109
                if (url) {
110
                    
111
                    const sourceMap = new SourceMap (this.path, url)
112
113
                    if (sourceMap.parsed) {
114
                        this.sourceMap_ = sourceMap
115
                    }
116
117
                } else {
118
119
                    this.sourceMap_ = null
120
                }
121
            }
122
        }
123
124
        catch (e) {
125
            this.sourceMap_ = null
126
            this.sourceMapError = e
127
        }
128
129
        return this.sourceMap_
130
    }
131
132
    resolve (loc /* { line[, column] } */) /* → { line, column, sourceFile, sourceLine } */ {
133
134
        return this.sourceMap ? this.sourceMap.resolve (loc) : O.assign ({}, loc, {
135
136
            sourceFile:  this,
137
            sourceLine: (this.lines[loc.line - 1] || ''),
138
            error:       this.error
139
        })
140
    }
141
}
142
143
/*  ------------------------------------------------------------------------ */
144