gulp-sourcemaps
Advanced tools
Comparing version 2.0.1 to 2.1.1
386
index.js
'use strict'; | ||
var through = require('through2'); | ||
var fs = require('graceful-fs'); | ||
var path = require('path'); | ||
var File = require('vinyl'); | ||
var convert = require('convert-source-map'); | ||
var stripBom = require('strip-bom'); | ||
var detectNewline = require('detect-newline'); | ||
var acorn = require('acorn'); | ||
var SourceMapGenerator = require('source-map').SourceMapGenerator; | ||
var css = require('css'); | ||
var PLUGIN_NAME = 'gulp-sourcemap'; | ||
var urlRegex = /^(https?|webpack(-[^:]+)?):\/\//; | ||
/** | ||
* Initialize source mapping chain | ||
*/ | ||
module.exports.init = function init(options) { | ||
var debug = require('debug-fabulous')()(PLUGIN_NAME + ':init'); | ||
function sourceMapInit(file, encoding, callback) { | ||
/*jshint validthis:true */ | ||
// pass through if file is null or already has a source map | ||
if (file.isNull() || file.sourceMap) { | ||
this.push(file); | ||
return callback(); | ||
} | ||
if (file.isStream()) { | ||
return callback(new Error(PLUGIN_NAME + '-init: Streaming not supported')); | ||
} | ||
if (options === undefined) { | ||
options = {}; | ||
} | ||
debug(() => {return options;}); | ||
var fileContent = file.contents.toString(); | ||
var sourceMap; | ||
if (options.loadMaps) { | ||
debug('loadMaps'); | ||
var sourcePath = ''; //root path for the sources in the map | ||
// Try to read inline source map | ||
sourceMap = convert.fromSource(fileContent, options.largeFile); | ||
if (sourceMap) { | ||
sourceMap = sourceMap.toObject(); | ||
// sources in map are relative to the source file | ||
sourcePath = path.dirname(file.path); | ||
if (!options.largeFile) { | ||
fileContent = convert.removeComments(fileContent); | ||
} | ||
} else { | ||
// look for source map comment referencing a source map file | ||
var mapComment = convert.mapFileCommentRegex.exec(fileContent); | ||
var mapFile; | ||
if (mapComment) { | ||
mapFile = path.resolve(path.dirname(file.path), mapComment[1] || mapComment[2]); | ||
fileContent = convert.removeMapFileComments(fileContent); | ||
// if no comment try map file with same name as source file | ||
} else { | ||
mapFile = file.path + '.map'; | ||
} | ||
// sources in external map are relative to map file | ||
sourcePath = path.dirname(mapFile); | ||
try { | ||
sourceMap = JSON.parse(stripBom(fs.readFileSync(mapFile, 'utf8'))); | ||
} catch(e) {} | ||
} | ||
// fix source paths and sourceContent for imported source map | ||
if (sourceMap) { | ||
sourceMap.sourcesContent = sourceMap.sourcesContent || []; | ||
sourceMap.sources.forEach(function(source, i) { | ||
if (source.match(urlRegex)) { | ||
sourceMap.sourcesContent[i] = sourceMap.sourcesContent[i] || null; | ||
return; | ||
} | ||
var absPath = path.resolve(sourcePath, source); | ||
sourceMap.sources[i] = unixStylePath(path.relative(file.base, absPath)); | ||
if (!sourceMap.sourcesContent[i]) { | ||
var sourceContent = null; | ||
if (sourceMap.sourceRoot) { | ||
if (sourceMap.sourceRoot.match(urlRegex)) { | ||
sourceMap.sourcesContent[i] = null; | ||
return; | ||
} | ||
absPath = path.resolve(sourcePath, sourceMap.sourceRoot, source); | ||
} | ||
// if current file: use content | ||
if (absPath === file.path) { | ||
sourceContent = fileContent; | ||
// else load content from file | ||
} else { | ||
try { | ||
if (options.debug) | ||
debug('No source content for "' + source + '". Loading from file.'); | ||
sourceContent = stripBom(fs.readFileSync(absPath, 'utf8')); | ||
} catch (e) { | ||
if (options.debug) | ||
debug('warn: source file not found: ' + absPath); | ||
} | ||
} | ||
sourceMap.sourcesContent[i] = sourceContent; | ||
} | ||
}); | ||
// remove source map comment from source | ||
file.contents = new Buffer(fileContent, 'utf8'); | ||
} | ||
} | ||
if (!sourceMap && options.identityMap) { | ||
debug(() => { return 'identityMap'; }); | ||
var fileType = path.extname(file.path); | ||
var source = unixStylePath(file.relative); | ||
var generator = new SourceMapGenerator({file: source}); | ||
if (fileType === '.js') { | ||
var tokenizer = acorn.tokenizer(fileContent, {locations: true}); | ||
while (true) { | ||
var token = tokenizer.getToken(); | ||
if (token.type.label === "eof") | ||
break; | ||
var mapping = { | ||
original: token.loc.start, | ||
generated: token.loc.start, | ||
source: source, | ||
}; | ||
if (token.type.label === 'name') { | ||
mapping.name = token.value; | ||
} | ||
generator.addMapping(mapping); | ||
} | ||
generator.setSourceContent(source, fileContent); | ||
sourceMap = generator.toJSON(); | ||
} else if (fileType === '.css') { | ||
debug('css'); | ||
var ast = css.parse(fileContent, {silent: true}); | ||
debug(() => { return ast;}); | ||
var registerTokens = function(ast) { | ||
if (ast.position) { | ||
generator.addMapping({ | ||
original: ast.position.start, | ||
generated: ast.position.start, | ||
source: source, | ||
}); | ||
} | ||
function logAst(key, ast) { | ||
debug(() => { return 'key: ' + key;}); | ||
debug(() => { return ast[key];}); | ||
} | ||
for (var key in ast) { | ||
logAst(key, ast); | ||
if (key !== "position") { | ||
if (Object.prototype.toString.call(ast[key]) === '[object Object]') { | ||
registerTokens(ast[key]); | ||
} else if (Array.isArray(ast[key])) { | ||
debug(() => { return "@@@@ ast[key] isArray @@@@";}); | ||
for (var i = 0; i < ast[key].length; i++) { | ||
registerTokens(ast[key][i]); | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
registerTokens(ast); | ||
generator.setSourceContent(source, fileContent); | ||
sourceMap = generator.toJSON(); | ||
} | ||
} | ||
if (!sourceMap) { | ||
// Make an empty source map | ||
sourceMap = { | ||
version : 3, | ||
names: [], | ||
mappings: '', | ||
sources: [unixStylePath(file.relative)], | ||
sourcesContent: [fileContent] | ||
}; | ||
} | ||
sourceMap.file = unixStylePath(file.relative); | ||
file.sourceMap = sourceMap; | ||
this.push(file); | ||
callback(); | ||
} | ||
return through.obj(sourceMapInit); | ||
module.exports = { | ||
init: require('./src/init'), | ||
write: require('./src/write') | ||
}; | ||
/** | ||
* Write the source map | ||
* | ||
* @param options options to change the way the source map is written | ||
* | ||
*/ | ||
module.exports.write = function write(destPath, options) { | ||
var debug = require('debug-fabulous')()(PLUGIN_NAME + ':write'); | ||
if (options === undefined && Object.prototype.toString.call(destPath) === '[object Object]') { | ||
options = destPath; | ||
destPath = undefined; | ||
} | ||
options = options || {}; | ||
// set defaults for options if unset | ||
if (options.includeContent === undefined) | ||
options.includeContent = true; | ||
if (options.addComment === undefined) | ||
options.addComment = true; | ||
if (options.charset === undefined) | ||
options.charset = "utf8"; | ||
debug(()=> {return options;}); | ||
function sourceMapWrite(file, encoding, callback) { | ||
/*jshint validthis:true */ | ||
if (file.isNull() || !file.sourceMap) { | ||
this.push(file); | ||
return callback(); | ||
} | ||
if (file.isStream()) { | ||
return callback(new Error(PLUGIN_NAME + '-write: Streaming not supported')); | ||
} | ||
var sourceMap = file.sourceMap; | ||
// fix paths if Windows style paths | ||
sourceMap.file = unixStylePath(file.relative); | ||
if (options.mapSources && typeof options.mapSources === 'function') { | ||
sourceMap.sources = sourceMap.sources.map(function(filePath) { | ||
return options.mapSources(filePath); | ||
}); | ||
} | ||
sourceMap.sources = sourceMap.sources.map(function(filePath) { | ||
return unixStylePath(filePath); | ||
}); | ||
if (typeof options.sourceRoot === 'function') { | ||
sourceMap.sourceRoot = options.sourceRoot(file); | ||
} else { | ||
sourceMap.sourceRoot = options.sourceRoot; | ||
} | ||
if (sourceMap.sourceRoot === null) { | ||
sourceMap.sourceRoot = undefined; | ||
} | ||
if (options.includeContent) { | ||
sourceMap.sourcesContent = sourceMap.sourcesContent || []; | ||
// load missing source content | ||
for (var i = 0; i < file.sourceMap.sources.length; i++) { | ||
if (!sourceMap.sourcesContent[i]) { | ||
var sourcePath = path.resolve(sourceMap.sourceRoot || file.base, sourceMap.sources[i]); | ||
try { | ||
if (options.debug) | ||
debug('No source content for "' + sourceMap.sources[i] + '". Loading from file.'); | ||
sourceMap.sourcesContent[i] = stripBom(fs.readFileSync(sourcePath, 'utf8')); | ||
} catch (e) { | ||
if (options.debug) | ||
debug('source file not found: ' + sourcePath); | ||
} | ||
} | ||
} | ||
} else { | ||
delete sourceMap.sourcesContent; | ||
} | ||
var extension = file.relative.split('.').pop(); | ||
var newline = detectNewline.graceful(file.contents.toString()); | ||
var commentFormatter; | ||
switch (extension) { | ||
case 'css': | ||
commentFormatter = function(url) { | ||
return newline + "/*# sourceMappingURL=" + url + " */" + newline; | ||
}; | ||
break; | ||
case 'js': | ||
commentFormatter = function(url) { | ||
return newline + "//# sourceMappingURL=" + url + newline; | ||
}; | ||
break; | ||
default: | ||
commentFormatter = function(url) { return ""; }; | ||
} | ||
var comment, sourceMappingURLPrefix; | ||
if (destPath === undefined || destPath === null) { | ||
// encode source map into comment | ||
var base64Map = new Buffer(JSON.stringify(sourceMap)).toString('base64'); | ||
comment = commentFormatter('data:application/json;charset=' + options.charset + ';base64,' + base64Map); | ||
} else { | ||
var mapFile = path.join(destPath, file.relative) + '.map'; | ||
// custom map file name | ||
if (options.mapFile && typeof options.mapFile === 'function') { | ||
mapFile = options.mapFile(mapFile); | ||
} | ||
var sourceMapPath = path.join(file.base, mapFile); | ||
// if explicit destination path is set | ||
if (options.destPath) { | ||
var destSourceMapPath = path.join(file.cwd, options.destPath, mapFile); | ||
var destFilePath = path.join(file.cwd, options.destPath, file.relative); | ||
sourceMap.file = unixStylePath(path.relative(path.dirname(destSourceMapPath), destFilePath)); | ||
if (sourceMap.sourceRoot === undefined) { | ||
sourceMap.sourceRoot = unixStylePath(path.relative(path.dirname(destSourceMapPath), file.base)); | ||
} else if (sourceMap.sourceRoot === '' || (sourceMap.sourceRoot && sourceMap.sourceRoot[0] === '.')) { | ||
sourceMap.sourceRoot = unixStylePath(path.join(path.relative(path.dirname(destSourceMapPath), file.base), sourceMap.sourceRoot)); | ||
} | ||
} else { | ||
// best effort, can be incorrect if options.destPath not set | ||
sourceMap.file = unixStylePath(path.relative(path.dirname(sourceMapPath), file.path)); | ||
if (sourceMap.sourceRoot === '' || (sourceMap.sourceRoot && sourceMap.sourceRoot[0] === '.')) { | ||
sourceMap.sourceRoot = unixStylePath(path.join(path.relative(path.dirname(sourceMapPath), file.base), sourceMap.sourceRoot)); | ||
} | ||
} | ||
// add new source map file to stream | ||
var sourceMapFile = new File({ | ||
cwd: file.cwd, | ||
base: file.base, | ||
path: sourceMapPath, | ||
contents: new Buffer(JSON.stringify(sourceMap)), | ||
stat: { | ||
isFile: function () { return true; }, | ||
isDirectory: function () { return false; }, | ||
isBlockDevice: function () { return false; }, | ||
isCharacterDevice: function () { return false; }, | ||
isSymbolicLink: function () { return false; }, | ||
isFIFO: function () { return false; }, | ||
isSocket: function () { return false; } | ||
} | ||
}); | ||
this.push(sourceMapFile); | ||
var sourceMapPathRelative = path.relative(path.dirname(file.path), sourceMapPath); | ||
if (options.sourceMappingURLPrefix) { | ||
var prefix = ''; | ||
if (typeof options.sourceMappingURLPrefix === 'function') { | ||
prefix = options.sourceMappingURLPrefix(file); | ||
} else { | ||
prefix = options.sourceMappingURLPrefix; | ||
} | ||
sourceMapPathRelative = prefix+path.join('/', sourceMapPathRelative); | ||
} | ||
comment = commentFormatter(unixStylePath(sourceMapPathRelative)); | ||
if (options.sourceMappingURL && typeof options.sourceMappingURL === 'function') { | ||
comment = commentFormatter(options.sourceMappingURL(file)); | ||
} | ||
} | ||
// append source map comment | ||
if (options.addComment) | ||
file.contents = Buffer.concat([file.contents, new Buffer(comment)]); | ||
this.push(file); | ||
callback(); | ||
} | ||
return through.obj(sourceMapWrite); | ||
}; | ||
function unixStylePath(filePath) { | ||
return filePath.split(path.sep).join('/'); | ||
} |
{ | ||
"name": "gulp-sourcemaps", | ||
"version": "2.0.1", | ||
"version": "2.1.1", | ||
"description": "Source map support for Gulp.js", | ||
@@ -43,4 +43,5 @@ "homepage": "http://github.com/floridoo/gulp-sourcemaps", | ||
"files": [ | ||
"index.js" | ||
"index.js", | ||
"src" | ||
] | ||
} |
## gulp-sourcemaps [![NPM version][npm-image]][npm-url] [![build status][travis-image]][travis-url] [![Test coverage][coveralls-image]][coveralls-url] | ||
### Branching | ||
- master: is latest currently (2.X) - node > 4.X | ||
- 1.X: is node 0.X - only issues appear to be es6 | ||
Preferably, we would like move on from node 0.X as much as possible as some of the dependencies are doing so as well. Meaning for features please target master for PRs. If bugs are found to be relvant to both 1.X and master then please target PRs for the 1.X branch to make git merging easier. | ||
### Usage | ||
@@ -4,0 +11,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28076
7
389
379
1