'use strict'; var utils = require('../utils'); var unixStylePath = utils.unixStylePath; var through = require('through2'); var path = require('path'); var acorn = require('acorn'); var SourceMapGenerator = require('source-map').SourceMapGenerator; var css = require('css'); var initInternals = require('./index.internals'); /** * Initialize source mapping chain */ function init(options) { var debug = require('../debug').spawn('init'); function sourceMapInit(file, encoding, callback) { // 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(utils.PLUGIN_NAME + '-init: Streaming not supported')); } if (options === undefined) { options = {}; } debug(function() { return options; }); var fileContent = file.contents.toString(); var sourceMap, preExistingComment; var internals = initInternals(options, file, fileContent); if (options.loadMaps) { var result = internals.loadMaps(); sourceMap = result.map; fileContent = result.content; preExistingComment = result.preExistingComment; } if (!sourceMap && options.identityMap) { debug(function() { return '**identityMap option is deprecated, update to use sourcemap.identityMap stream**'; }); debug(function() { 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(function() { 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(function() { return 'key: ' + key; }); debug(function() { 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(function() { 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], }; } else if (preExistingComment !== null && typeof preExistingComment !== 'undefined') { sourceMap.preExistingComment = preExistingComment; } sourceMap.file = unixStylePath(file.relative); file.sourceMap = sourceMap; this.push(file); callback(); } return through.obj(sourceMapInit); } module.exports = init;