Projekt

Obecné

Profil

Stáhnout (8.69 KB) Statistiky
| Větev: | Revize:
1
var sourceMappingURL   = require("source-map-url")
2

    
3
var resolveUrl         = require("./resolve-url")
4
var decodeUriComponent = require("./decode-uri-component")
5
var urix               = require("urix")
6
var atob               = require("atob")
7

    
8

    
9

    
10
function callbackAsync(callback, error, result) {
11
  setImmediate(function() { callback(error, result) })
12
}
13

    
14
function parseMapToJSON(string, data) {
15
  try {
16
    return JSON.parse(string.replace(/^\)\]\}'/, ""))
17
  } catch (error) {
18
    error.sourceMapData = data
19
    throw error
20
  }
21
}
22

    
23
function readSync(read, url, data) {
24
  var readUrl = decodeUriComponent(url)
25
  try {
26
    return String(read(readUrl))
27
  } catch (error) {
28
    error.sourceMapData = data
29
    throw error
30
  }
31
}
32

    
33

    
34

    
35
function resolveSourceMap(code, codeUrl, read, callback) {
36
  var mapData
37
  try {
38
    mapData = resolveSourceMapHelper(code, codeUrl)
39
  } catch (error) {
40
    return callbackAsync(callback, error)
41
  }
42
  if (!mapData || mapData.map) {
43
    return callbackAsync(callback, null, mapData)
44
  }
45
  var readUrl = decodeUriComponent(mapData.url)
46
  read(readUrl, function(error, result) {
47
    if (error) {
48
      error.sourceMapData = mapData
49
      return callback(error)
50
    }
51
    mapData.map = String(result)
52
    try {
53
      mapData.map = parseMapToJSON(mapData.map, mapData)
54
    } catch (error) {
55
      return callback(error)
56
    }
57
    callback(null, mapData)
58
  })
59
}
60

    
61
function resolveSourceMapSync(code, codeUrl, read) {
62
  var mapData = resolveSourceMapHelper(code, codeUrl)
63
  if (!mapData || mapData.map) {
64
    return mapData
65
  }
66
  mapData.map = readSync(read, mapData.url, mapData)
67
  mapData.map = parseMapToJSON(mapData.map, mapData)
68
  return mapData
69
}
70

    
71
var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/
72

    
73
/**
74
 * The media type for JSON text is application/json.
75
 *
76
 * {@link https://tools.ietf.org/html/rfc8259#section-11 | IANA Considerations }
77
 *
78
 * `text/json` is non-standard media type
79
 */
80
var jsonMimeTypeRegex = /^(?:application|text)\/json$/
81

    
82
/**
83
 * JSON text exchanged between systems that are not part of a closed ecosystem
84
 * MUST be encoded using UTF-8.
85
 *
86
 * {@link https://tools.ietf.org/html/rfc8259#section-8.1 | Character Encoding}
87
 */
88
var jsonCharacterEncoding = "utf-8"
89

    
90
function base64ToBuf(b64) {
91
  var binStr = atob(b64)
92
  var len = binStr.length
93
  var arr = new Uint8Array(len)
94
  for (var i = 0; i < len; i++) {
95
    arr[i] = binStr.charCodeAt(i)
96
  }
97
  return arr
98
}
99

    
100
function decodeBase64String(b64) {
101
  if (typeof TextDecoder === "undefined" || typeof Uint8Array === "undefined") {
102
    return atob(b64)
103
  }
104
  var buf = base64ToBuf(b64);
105
  // Note: `decoder.decode` method will throw a `DOMException` with the
106
  // `"EncodingError"` value when an coding error is found.
107
  var decoder = new TextDecoder(jsonCharacterEncoding, {fatal: true})
108
  return decoder.decode(buf);
109
}
110

    
111
function resolveSourceMapHelper(code, codeUrl) {
112
  codeUrl = urix(codeUrl)
113

    
114
  var url = sourceMappingURL.getFrom(code)
115
  if (!url) {
116
    return null
117
  }
118

    
119
  var dataUri = url.match(dataUriRegex)
120
  if (dataUri) {
121
    var mimeType = dataUri[1] || "text/plain"
122
    var lastParameter = dataUri[2] || ""
123
    var encoded = dataUri[3] || ""
124
    var data = {
125
      sourceMappingURL: url,
126
      url: null,
127
      sourcesRelativeTo: codeUrl,
128
      map: encoded
129
    }
130
    if (!jsonMimeTypeRegex.test(mimeType)) {
131
      var error = new Error("Unuseful data uri mime type: " + mimeType)
132
      error.sourceMapData = data
133
      throw error
134
    }
135
    try {
136
      data.map = parseMapToJSON(
137
        lastParameter === ";base64" ? decodeBase64String(encoded) : decodeURIComponent(encoded),
138
        data
139
      )
140
    } catch (error) {
141
      error.sourceMapData = data
142
      throw error
143
    }
144
    return data
145
  }
146

    
147
  var mapUrl = resolveUrl(codeUrl, url)
148
  return {
149
    sourceMappingURL: url,
150
    url: mapUrl,
151
    sourcesRelativeTo: mapUrl,
152
    map: null
153
  }
154
}
155

    
156

    
157

    
158
function resolveSources(map, mapUrl, read, options, callback) {
159
  if (typeof options === "function") {
160
    callback = options
161
    options = {}
162
  }
163
  var pending = map.sources ? map.sources.length : 0
164
  var result = {
165
    sourcesResolved: [],
166
    sourcesContent:  []
167
  }
168

    
169
  if (pending === 0) {
170
    callbackAsync(callback, null, result)
171
    return
172
  }
173

    
174
  var done = function() {
175
    pending--
176
    if (pending === 0) {
177
      callback(null, result)
178
    }
179
  }
180

    
181
  resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) {
182
    result.sourcesResolved[index] = fullUrl
183
    if (typeof sourceContent === "string") {
184
      result.sourcesContent[index] = sourceContent
185
      callbackAsync(done, null)
186
    } else {
187
      var readUrl = decodeUriComponent(fullUrl)
188
      read(readUrl, function(error, source) {
189
        result.sourcesContent[index] = error ? error : String(source)
190
        done()
191
      })
192
    }
193
  })
194
}
195

    
196
function resolveSourcesSync(map, mapUrl, read, options) {
197
  var result = {
198
    sourcesResolved: [],
199
    sourcesContent:  []
200
  }
201

    
202
  if (!map.sources || map.sources.length === 0) {
203
    return result
204
  }
205

    
206
  resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) {
207
    result.sourcesResolved[index] = fullUrl
208
    if (read !== null) {
209
      if (typeof sourceContent === "string") {
210
        result.sourcesContent[index] = sourceContent
211
      } else {
212
        var readUrl = decodeUriComponent(fullUrl)
213
        try {
214
          result.sourcesContent[index] = String(read(readUrl))
215
        } catch (error) {
216
          result.sourcesContent[index] = error
217
        }
218
      }
219
    }
220
  })
221

    
222
  return result
223
}
224

    
225
var endingSlash = /\/?$/
226

    
227
function resolveSourcesHelper(map, mapUrl, options, fn) {
228
  options = options || {}
229
  mapUrl = urix(mapUrl)
230
  var fullUrl
231
  var sourceContent
232
  var sourceRoot
233
  for (var index = 0, len = map.sources.length; index < len; index++) {
234
    sourceRoot = null
235
    if (typeof options.sourceRoot === "string") {
236
      sourceRoot = options.sourceRoot
237
    } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) {
238
      sourceRoot = map.sourceRoot
239
    }
240
    // If the sourceRoot is the empty string, it is equivalent to not setting
241
    // the property at all.
242
    if (sourceRoot === null || sourceRoot === '') {
243
      fullUrl = resolveUrl(mapUrl, map.sources[index])
244
    } else {
245
      // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes
246
      // `/scripts/subdir/<source>`, not `/scripts/<source>`. Pointing to a file as source root
247
      // does not make sense.
248
      fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index])
249
    }
250
    sourceContent = (map.sourcesContent || [])[index]
251
    fn(fullUrl, sourceContent, index)
252
  }
253
}
254

    
255

    
256

    
257
function resolve(code, codeUrl, read, options, callback) {
258
  if (typeof options === "function") {
259
    callback = options
260
    options = {}
261
  }
262
  if (code === null) {
263
    var mapUrl = codeUrl
264
    var data = {
265
      sourceMappingURL: null,
266
      url: mapUrl,
267
      sourcesRelativeTo: mapUrl,
268
      map: null
269
    }
270
    var readUrl = decodeUriComponent(mapUrl)
271
    read(readUrl, function(error, result) {
272
      if (error) {
273
        error.sourceMapData = data
274
        return callback(error)
275
      }
276
      data.map = String(result)
277
      try {
278
        data.map = parseMapToJSON(data.map, data)
279
      } catch (error) {
280
        return callback(error)
281
      }
282
      _resolveSources(data)
283
    })
284
  } else {
285
    resolveSourceMap(code, codeUrl, read, function(error, mapData) {
286
      if (error) {
287
        return callback(error)
288
      }
289
      if (!mapData) {
290
        return callback(null, null)
291
      }
292
      _resolveSources(mapData)
293
    })
294
  }
295

    
296
  function _resolveSources(mapData) {
297
    resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) {
298
      if (error) {
299
        return callback(error)
300
      }
301
      mapData.sourcesResolved = result.sourcesResolved
302
      mapData.sourcesContent  = result.sourcesContent
303
      callback(null, mapData)
304
    })
305
  }
306
}
307

    
308
function resolveSync(code, codeUrl, read, options) {
309
  var mapData
310
  if (code === null) {
311
    var mapUrl = codeUrl
312
    mapData = {
313
      sourceMappingURL: null,
314
      url: mapUrl,
315
      sourcesRelativeTo: mapUrl,
316
      map: null
317
    }
318
    mapData.map = readSync(read, mapUrl, mapData)
319
    mapData.map = parseMapToJSON(mapData.map, mapData)
320
  } else {
321
    mapData = resolveSourceMapSync(code, codeUrl, read)
322
    if (!mapData) {
323
      return null
324
    }
325
  }
326
  var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options)
327
  mapData.sourcesResolved = result.sourcesResolved
328
  mapData.sourcesContent  = result.sourcesContent
329
  return mapData
330
}
331

    
332

    
333

    
334
module.exports = {
335
  resolveSourceMap:     resolveSourceMap,
336
  resolveSourceMapSync: resolveSourceMapSync,
337
  resolveSources:       resolveSources,
338
  resolveSourcesSync:   resolveSourcesSync,
339
  resolve:              resolve,
340
  resolveSync:          resolveSync,
341
  parseMapToJSON:       parseMapToJSON
342
}
(3-3/3)