package/package.json000644 000765 000024 0000002511 13140153607013014 0ustar00000000 000000 { "name": "vinyl-sourcemap", "version": "1.1.0", "description": "Add/write sourcemaps to/from Vinyl files.", "author": "Gulp Team (http://gulpjs.com/)", "contributors": [ "Robin Venneman", "Blaine Bublitz " ], "repository": "gulpjs/vinyl-sourcemap", "license": "MIT", "engines": { "node": ">= 0.10" }, "main": "index.js", "files": [ "LICENSE", "index.js", "lib/" ], "scripts": { "lint": "eslint index.js lib/ test/add.js test/write.js && jscs index.js lib/ test/add.js test/write.js", "pretest": "npm run lint", "test": "mocha --async-only", "cover": "istanbul cover _mocha --report lcovonly", "coveralls": "npm run cover && istanbul-coveralls" }, "dependencies": { "append-buffer": "^1.0.2", "convert-source-map": "^1.5.0", "graceful-fs": "^4.1.6", "normalize-path": "^2.1.1", "now-and-later": "^2.0.0", "remove-bom-buffer": "^3.0.0", "vinyl": "^2.0.0" }, "devDependencies": { "eslint": "^1.10.3", "eslint-config-gulp": "^2.0.0", "expect": "^1.20.2", "istanbul": "^0.4.3", "istanbul-coveralls": "^1.0.3", "jscs": "^2.4.0", "jscs-preset-gulp": "^1.0.0", "mississippi": "^1.3.0", "mocha": "^3.2.0" }, "keywords": [ "vinyl", "sourcemap", "gulp" ] } package/README.md000644 000765 000024 0000011024 13121557344012011 0ustar00000000 000000

# vinyl-sourcemap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![AppVeyor Build Status][appveyor-image]][appveyor-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url] Add/write sourcemaps to/from Vinyl files. ## Usage ```js sourcemap.add(file, function(err, updatedFile) { // updatedFile will have a .sourceMap property }); // The 2nd argument can be given as a path string sourcemap.write(file, './maps', function(err, updatedFile, sourcemapFile) { // sourcemapFile will be a Vinyl file to be written to some location // updatedFile will have the .contents property updated with a sourceMappingURL that resolves to sourcemapFile }); // If not defined, the sourcemap is inlined sourcemap.write(file, function(err, updatedFile, sourcemapFile) { // sourcemapFile is undefined // updatedFile will have the .contents property updated with a sourceMappingURL that is an inlined sourcemap }); ``` ## API ### `sourcemap.add(file, callback)` Takes a [Vinyl][vinyl] `file` object and a `callback` function. It attempts to parse an inline sourcemap or load an external sourcemap for the file. If a valid sourcemap is found, the `sources` & `sourcesContent` properties are resolved to actual files (if possible) and a fully resolved sourcemap is attached as `file.sourceMap`. If a sourcemap is not found, a stub sourcemap is generated for the file and attached as `file.sourceMap`. Once all resolution is complete, the `callback(err, updatedFile)` is called with the `updatedFile`. If an error occurs, it will be passed as `err` and `updatedFile` will be undefined. __Note:__ The original file is mutated but `updatedFile` is passed to the callback as a convenience. If the `file` is not a Vinyl object or the contents are streaming, an Error will be passed to the `callback`. If the `file` has a `.sourceMap` property or the contents are null, the `callback` will be called immediately without mutation to the file. All filesystem operations are optional & non-fatal so any errors will not be bubbled to the `callback`. ### `sourcemap.write(file, [outputPath,] callback)` Takes a [Vinyl][vinyl] `file` object, (optionally) an `outputPath` string and a `callback` function. If `outputPath` is not passed, an inline sourcemap will be generated from the `file.sourceMap` property and appended to the `file.contents`. Once the inline sourcemap is appended, the `callback(err, updatedFile)` is called with the `updatedFile`. If an error occurs, it will be passed as `err` and `updatedFile` will be undefined. __Note:__ The original file is mutated but `updatedFile` is passed to the callback as a convenience. If `outputPath` is passed, a new Vinyl file will be generated using `file.cwd` and `file.base` from the original file, the path to the external sourcemap, and the `file.sourceMap` (as contents). The external location will be appended to the `file.contents` of the original file. Once the new file is created and location appended, the `callback(err, updatedFile, sourcemapFile)` is called with the `updatedFile` and the `sourcemapFile`. If an error occurs, it will be passed as `err` and `updatedFile`/`sourcemapFile` will be undefined. __Note:__ The original file is mutated but `updatedFile` is passed to the callback as a convenience. If the `file` is not a Vinyl object or the contents are streaming, an Error will be passed to the `callback`. If the `file` doesn't have a `.sourceMap` property or the contents are null, the `callback` will be called immediately without mutation to the file. ## License MIT [vinyl]: https://github.com/gulpjs/vinyl [downloads-image]: http://img.shields.io/npm/dm/vinyl-sourcemap.svg [npm-url]: https://npmjs.com/package/vinyl-sourcemap [npm-image]: http://img.shields.io/npm/v/vinyl-sourcemap.svg [travis-url]: https://travis-ci.org/gulpjs/vinyl-sourcemap [travis-image]: http://img.shields.io/travis/gulpjs/vinyl-sourcemap.svg?label=travis-ci [appveyor-url]: https://ci.appveyor.com/project/gulpjs/vinyl-sourcemap [appveyor-image]: https://img.shields.io/appveyor/ci/gulpjs/vinyl-sourcemap.svg?label=appveyor [coveralls-url]: https://coveralls.io/r/gulpjs/vinyl-sourcemap [coveralls-image]: http://img.shields.io/coveralls/gulpjs/vinyl-sourcemap/master.svg [gitter-url]: https://gitter.im/gulpjs/gulp [gitter-image]: https://badges.gitter.im/gulpjs/gulp.png package/LICENSE000644 000765 000024 0000002346 13121337355011544 0ustar00000000 000000 The MIT License (MIT) Copyright (c) 2017 Blaine Bublitz , Eric Schoffstall and other contributors (Based on code from gulp-sourcemaps - ISC License - Copyright (c) 2014, Florian Reiterer) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package/index.js000644 000765 000024 0000003244 13121337355012202 0ustar00000000 000000 'use strict'; var File = require('vinyl'); var helpers = require('./lib/helpers'); var PLUGIN_NAME = 'vinyl-sourcemap'; function add(file, callback) { // Bail early an error if the file argument is not a Vinyl file if (!File.isVinyl(file)) { return callback(new Error(PLUGIN_NAME + '-add: Not a vinyl file')); } // Bail early with an error if file has streaming contents if (file.isStream()) { return callback(new Error(PLUGIN_NAME + '-add: Streaming not supported')); } // Bail early successfully if file is null or already has a sourcemap if (file.isNull() || file.sourceMap) { return callback(null, file); } var state = { path: '', // Root path for the sources in the map map: null, content: file.contents.toString(), // TODO: handle this? preExistingComment: null, }; helpers.addSourceMaps(file, state, callback); } function write(file, destPath, callback) { // Check if options or a callback are passed as second argument if (typeof destPath === 'function') { callback = destPath; destPath = undefined; } // Bail early with an error if the file argument is not a Vinyl file if (!File.isVinyl(file)) { return callback(new Error(PLUGIN_NAME + '-write: Not a vinyl file')); } // Bail early with an error if file has streaming contents if (file.isStream()) { return callback(new Error(PLUGIN_NAME + '-write: Streaming not supported')); } // Bail early successfully if file is null or doesn't have sourcemap if (file.isNull() || !file.sourceMap) { return callback(null, file); } helpers.writeSourceMaps(file, destPath, callback); } module.exports = { add: add, write: write, }; package/lib/helpers.js000644 000765 000024 0000013357 13140153152013301 0ustar00000000 000000 'use strict'; var path = require('path'); var fs = require('graceful-fs'); var nal = require('now-and-later'); var File = require('vinyl'); var convert = require('convert-source-map'); var removeBOM = require('remove-bom-buffer'); var appendBuffer = require('append-buffer'); var normalizePath = require('normalize-path'); var urlRegex = /^(https?|webpack(-[^:]+)?):\/\//; function isRemoteSource(source) { return source.match(urlRegex); } function parse(data) { try { return JSON.parse(removeBOM(data)); } catch (err) { // TODO: should this log a debug? } } function loadSourceMap(file, state, callback) { // Try to read inline source map state.map = convert.fromSource(state.content); if (state.map) { state.map = state.map.toObject(); // Sources in map are relative to the source file state.path = file.dirname; state.content = convert.removeComments(state.content); // Remove source map comment from source file.contents = new Buffer(state.content, 'utf8'); return callback(); } // Look for source map comment referencing a source map file var mapComment = convert.mapFileCommentRegex.exec(state.content); var mapFile; if (mapComment) { mapFile = path.resolve(file.dirname, mapComment[1] || mapComment[2]); state.content = convert.removeMapFileComments(state.content); // Remove source map comment from source file.contents = new Buffer(state.content, 'utf8'); } else { // If no comment try map file with same name as source file mapFile = file.path + '.map'; } // Sources in external map are relative to map file state.path = path.dirname(mapFile); fs.readFile(mapFile, onRead); function onRead(err, data) { if (err) { return callback(); } state.map = parse(data); callback(); } } // Fix source paths and sourceContent for imported source map function fixImportedSourceMap(file, state, callback) { if (!state.map) { return callback(); } state.map.sourcesContent = state.map.sourcesContent || []; nal.map(state.map.sources, normalizeSourcesAndContent, callback); function assignSourcesContent(sourceContent, idx) { state.map.sourcesContent[idx] = sourceContent; } function normalizeSourcesAndContent(sourcePath, idx, cb) { var sourceRoot = state.map.sourceRoot || ''; var sourceContent = state.map.sourcesContent[idx] || null; if (isRemoteSource(sourcePath)) { assignSourcesContent(sourceContent, idx); return cb(); } if (state.map.sourcesContent[idx]) { return cb(); } if (sourceRoot && isRemoteSource(sourceRoot)) { assignSourcesContent(sourceContent, idx); return cb(); } var basePath = path.resolve(file.base, sourceRoot); var absPath = path.resolve(state.path, sourceRoot, sourcePath); var relPath = path.relative(basePath, absPath); var unixRelPath = normalizePath(relPath); state.map.sources[idx] = unixRelPath; if (absPath !== file.path) { // Load content from file async return fs.readFile(absPath, onRead); } // If current file: use content assignSourcesContent(state.content, idx); cb(); function onRead(err, data) { if (err) { assignSourcesContent(null, idx); return cb(); } assignSourcesContent(removeBOM(data).toString('utf8'), idx); cb(); } } } function mapsLoaded(file, state, callback) { if (!state.map) { state.map = { version: 3, names: [], mappings: '', sources: [normalizePath(file.relative)], sourcesContent: [state.content], }; } state.map.file = normalizePath(file.relative); file.sourceMap = state.map; callback(); } function addSourceMaps(file, state, callback) { var tasks = [ loadSourceMap, fixImportedSourceMap, mapsLoaded, ]; function apply(fn, key, cb) { fn(file, state, cb); } nal.mapSeries(tasks, apply, done); function done() { callback(null, file); } } /* Write Helpers */ function createSourceMapFile(opts) { return new File({ cwd: opts.cwd, base: opts.base, path: opts.path, contents: new Buffer(JSON.stringify(opts.content)), 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; }, }, }); } var needsMultiline = ['.css']; function getCommentOptions(extname) { var opts = { multiline: (needsMultiline.indexOf(extname) !== -1), }; return opts; } function writeSourceMaps(file, destPath, callback) { var sourceMapFile; var commentOpts = getCommentOptions(file.extname); var comment; if (destPath == null) { // Encode source map into comment comment = convert.fromObject(file.sourceMap).toComment(commentOpts); } else { var mapFile = path.join(destPath, file.relative) + '.map'; var sourceMapPath = path.join(file.base, mapFile); // Create new sourcemap File sourceMapFile = createSourceMapFile({ cwd: file.cwd, base: file.base, path: sourceMapPath, content: file.sourceMap, }); var sourcemapLocation = path.relative(file.dirname, sourceMapPath); sourcemapLocation = normalizePath(sourcemapLocation); comment = convert.generateMapFileComment(sourcemapLocation, commentOpts); } // Append source map comment file.contents = appendBuffer(file.contents, comment); callback(null, file, sourceMapFile); } module.exports = { addSourceMaps: addSourceMaps, writeSourceMaps: writeSourceMaps, };