UNPKG

3.51 kBJavaScriptView Raw
1/*
2* Copyright Node.js contributors. All rights reserved.
3*
4* Permission is hereby granted, free of charge, to any person obtaining a copy
5* of this software and associated documentation files (the "Software"), to
6* deal in the Software without restriction, including without limitation the
7* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8* sell copies of the Software, and to permit persons to whom the Software is
9* furnished to do so, subject to the following conditions:
10*
11* The above copyright notice and this permission notice shall be included in
12* all copies or substantial portions of the Software.
13*
14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20* IN THE SOFTWARE.
21*/
22// TODO(bcoe): this logic is ported from Node.js' internal source map
23// helpers:
24// https://github.com/nodejs/node/blob/master/lib/internal/source_map/source_map_cache.js
25// we should to upstream and downstream fixes.
26
27const { readFileSync } = require('fs')
28const { fileURLToPath, pathToFileURL } = require('url')
29const util = require('util')
30const debuglog = util.debuglog('c8')
31
32/**
33 * Extract the sourcemap url from a source file
34 * reference: https://sourcemaps.info/spec.html
35 * @param {String} file - compilation target file
36 * @returns {String} full path to source map file
37 * @private
38 */
39function getSourceMapFromFile (filename) {
40 const fileBody = readFileSync(filename).toString()
41 const sourceMapLineRE = /\/[*/]#\s+sourceMappingURL=(?<sourceMappingURL>[^\s]+)/
42 const results = fileBody.match(sourceMapLineRE)
43 if (results !== null) {
44 const sourceMappingURL = results.groups.sourceMappingURL
45 const sourceMap = dataFromUrl(pathToFileURL(filename), sourceMappingURL)
46 return sourceMap
47 } else {
48 return null
49 }
50}
51
52function dataFromUrl (sourceURL, sourceMappingURL) {
53 try {
54 const url = new URL(sourceMappingURL)
55 switch (url.protocol) {
56 case 'data:':
57 return sourceMapFromDataUrl(url.pathname)
58 default:
59 return null
60 }
61 } catch (err) {
62 debuglog(err)
63 // If no scheme is present, we assume we are dealing with a file path.
64 const mapURL = new URL(sourceMappingURL, sourceURL).href
65 return sourceMapFromFile(mapURL)
66 }
67}
68
69function sourceMapFromFile (mapURL) {
70 try {
71 const content = readFileSync(fileURLToPath(mapURL), 'utf8')
72 return JSON.parse(content)
73 } catch (err) {
74 debuglog(err)
75 return null
76 }
77}
78
79// data:[<mediatype>][;base64],<data> see:
80// https://tools.ietf.org/html/rfc2397#section-2
81function sourceMapFromDataUrl (url) {
82 const { 0: format, 1: data } = url.split(',')
83 const splitFormat = format.split(';')
84 const contentType = splitFormat[0]
85 const base64 = splitFormat[splitFormat.length - 1] === 'base64'
86 if (contentType === 'application/json') {
87 const decodedData = base64 ? Buffer.from(data, 'base64').toString('utf8') : data
88 try {
89 return JSON.parse(decodedData)
90 } catch (err) {
91 debuglog(err)
92 return null
93 }
94 } else {
95 debuglog(`unexpected content-type ${contentType}`)
96 return null
97 }
98}
99
100module.exports = getSourceMapFromFile