123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- // Copyright 2014, 2015, 2016, 2017 Simon Lydell
- // X11 (“MIT”) Licensed. (See LICENSE.)
-
- var sourceMappingURL = require("source-map-url")
- var resolveUrl = require("./resolve-url")
- var decodeUriComponent = require("./decode-uri-component")
- var urix = require("urix")
- var atob = require("atob")
-
-
-
- function callbackAsync(callback, error, result) {
- setImmediate(function() { callback(error, result) })
- }
-
- function parseMapToJSON(string, data) {
- try {
- return JSON.parse(string.replace(/^\)\]\}'/, ""))
- } catch (error) {
- error.sourceMapData = data
- throw error
- }
- }
-
- function readSync(read, url, data) {
- var readUrl = decodeUriComponent(url)
- try {
- return String(read(readUrl))
- } catch (error) {
- error.sourceMapData = data
- throw error
- }
- }
-
-
-
- function resolveSourceMap(code, codeUrl, read, callback) {
- var mapData
- try {
- mapData = resolveSourceMapHelper(code, codeUrl)
- } catch (error) {
- return callbackAsync(callback, error)
- }
- if (!mapData || mapData.map) {
- return callbackAsync(callback, null, mapData)
- }
- var readUrl = decodeUriComponent(mapData.url)
- read(readUrl, function(error, result) {
- if (error) {
- error.sourceMapData = mapData
- return callback(error)
- }
- mapData.map = String(result)
- try {
- mapData.map = parseMapToJSON(mapData.map, mapData)
- } catch (error) {
- return callback(error)
- }
- callback(null, mapData)
- })
- }
-
- function resolveSourceMapSync(code, codeUrl, read) {
- var mapData = resolveSourceMapHelper(code, codeUrl)
- if (!mapData || mapData.map) {
- return mapData
- }
- mapData.map = readSync(read, mapData.url, mapData)
- mapData.map = parseMapToJSON(mapData.map, mapData)
- return mapData
- }
-
- var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/
- var jsonMimeTypeRegex = /^(?:application|text)\/json$/
-
- function resolveSourceMapHelper(code, codeUrl) {
- codeUrl = urix(codeUrl)
-
- var url = sourceMappingURL.getFrom(code)
- if (!url) {
- return null
- }
-
- var dataUri = url.match(dataUriRegex)
- if (dataUri) {
- var mimeType = dataUri[1]
- var lastParameter = dataUri[2] || ""
- var encoded = dataUri[3] || ""
- var data = {
- sourceMappingURL: url,
- url: null,
- sourcesRelativeTo: codeUrl,
- map: encoded
- }
- if (!jsonMimeTypeRegex.test(mimeType)) {
- var error = new Error("Unuseful data uri mime type: " + (mimeType || "text/plain"))
- error.sourceMapData = data
- throw error
- }
- data.map = parseMapToJSON(
- lastParameter === ";base64" ? atob(encoded) : decodeURIComponent(encoded),
- data
- )
- return data
- }
-
- var mapUrl = resolveUrl(codeUrl, url)
- return {
- sourceMappingURL: url,
- url: mapUrl,
- sourcesRelativeTo: mapUrl,
- map: null
- }
- }
-
-
-
- function resolveSources(map, mapUrl, read, options, callback) {
- if (typeof options === "function") {
- callback = options
- options = {}
- }
- var pending = map.sources ? map.sources.length : 0
- var result = {
- sourcesResolved: [],
- sourcesContent: []
- }
-
- if (pending === 0) {
- callbackAsync(callback, null, result)
- return
- }
-
- var done = function() {
- pending--
- if (pending === 0) {
- callback(null, result)
- }
- }
-
- resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) {
- result.sourcesResolved[index] = fullUrl
- if (typeof sourceContent === "string") {
- result.sourcesContent[index] = sourceContent
- callbackAsync(done, null)
- } else {
- var readUrl = decodeUriComponent(fullUrl)
- read(readUrl, function(error, source) {
- result.sourcesContent[index] = error ? error : String(source)
- done()
- })
- }
- })
- }
-
- function resolveSourcesSync(map, mapUrl, read, options) {
- var result = {
- sourcesResolved: [],
- sourcesContent: []
- }
-
- if (!map.sources || map.sources.length === 0) {
- return result
- }
-
- resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) {
- result.sourcesResolved[index] = fullUrl
- if (read !== null) {
- if (typeof sourceContent === "string") {
- result.sourcesContent[index] = sourceContent
- } else {
- var readUrl = decodeUriComponent(fullUrl)
- try {
- result.sourcesContent[index] = String(read(readUrl))
- } catch (error) {
- result.sourcesContent[index] = error
- }
- }
- }
- })
-
- return result
- }
-
- var endingSlash = /\/?$/
-
- function resolveSourcesHelper(map, mapUrl, options, fn) {
- options = options || {}
- mapUrl = urix(mapUrl)
- var fullUrl
- var sourceContent
- var sourceRoot
- for (var index = 0, len = map.sources.length; index < len; index++) {
- sourceRoot = null
- if (typeof options.sourceRoot === "string") {
- sourceRoot = options.sourceRoot
- } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) {
- sourceRoot = map.sourceRoot
- }
- // If the sourceRoot is the empty string, it is equivalent to not setting
- // the property at all.
- if (sourceRoot === null || sourceRoot === '') {
- fullUrl = resolveUrl(mapUrl, map.sources[index])
- } else {
- // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes
- // `/scripts/subdir/<source>`, not `/scripts/<source>`. Pointing to a file as source root
- // does not make sense.
- fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index])
- }
- sourceContent = (map.sourcesContent || [])[index]
- fn(fullUrl, sourceContent, index)
- }
- }
-
-
-
- function resolve(code, codeUrl, read, options, callback) {
- if (typeof options === "function") {
- callback = options
- options = {}
- }
- if (code === null) {
- var mapUrl = codeUrl
- var data = {
- sourceMappingURL: null,
- url: mapUrl,
- sourcesRelativeTo: mapUrl,
- map: null
- }
- var readUrl = decodeUriComponent(mapUrl)
- read(readUrl, function(error, result) {
- if (error) {
- error.sourceMapData = data
- return callback(error)
- }
- data.map = String(result)
- try {
- data.map = parseMapToJSON(data.map, data)
- } catch (error) {
- return callback(error)
- }
- _resolveSources(data)
- })
- } else {
- resolveSourceMap(code, codeUrl, read, function(error, mapData) {
- if (error) {
- return callback(error)
- }
- if (!mapData) {
- return callback(null, null)
- }
- _resolveSources(mapData)
- })
- }
-
- function _resolveSources(mapData) {
- resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) {
- if (error) {
- return callback(error)
- }
- mapData.sourcesResolved = result.sourcesResolved
- mapData.sourcesContent = result.sourcesContent
- callback(null, mapData)
- })
- }
- }
-
- function resolveSync(code, codeUrl, read, options) {
- var mapData
- if (code === null) {
- var mapUrl = codeUrl
- mapData = {
- sourceMappingURL: null,
- url: mapUrl,
- sourcesRelativeTo: mapUrl,
- map: null
- }
- mapData.map = readSync(read, mapUrl, mapData)
- mapData.map = parseMapToJSON(mapData.map, mapData)
- } else {
- mapData = resolveSourceMapSync(code, codeUrl, read)
- if (!mapData) {
- return null
- }
- }
- var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options)
- mapData.sourcesResolved = result.sourcesResolved
- mapData.sourcesContent = result.sourcesContent
- return mapData
- }
-
-
-
- module.exports = {
- resolveSourceMap: resolveSourceMap,
- resolveSourceMapSync: resolveSourceMapSync,
- resolveSources: resolveSources,
- resolveSourcesSync: resolveSourcesSync,
- resolve: resolve,
- resolveSync: resolveSync,
- parseMapToJSON: parseMapToJSON
- }
|