├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── fixtures ├── coffee-script │ ├── actual.js │ ├── expected.coffee │ ├── expected.js │ └── expected.js.map └── es2015 │ ├── actual.js │ └── expected.js ├── test.js └── transforms ├── tr-double-line.js └── tr-insert-empty-statement.js /.eslintignore: -------------------------------------------------------------------------------- 1 | test/fixtures 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "parserOptions": { 3 | "sourceType": "module", 4 | "ecmaVersion": 6 5 | }, 6 | "env": { 7 | "es6": true, 8 | "node": true 9 | }, 10 | "rules": { 11 | "semi": [2, "never"], 12 | "no-unused-vars": [2] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .nyc_output 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | semi: false 2 | singleQuote: true 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.12' 4 | - '4' 5 | - '5' 6 | - '6' 7 | sudo: false 8 | cache: 9 | directories: 10 | - node_modules 11 | after_success: npm i coveralls && $(npm bin)/nyc report --reporter=text-lcov | $(npm bin)/coveralls 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) keik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # merge-source-map 2 | 3 | [![npm-version](https://img.shields.io/npm/v/merge-source-map.svg?style=flat-square)](https://npmjs.org/package/merge-source-map) 4 | [![downloads](http://img.shields.io/npm/dm/merge-source-map.svg?style=flat-square)](https://npmjs.org/package/merge-source-map) 5 | [![travis-ci](https://img.shields.io/travis/keik/merge-source-map.svg?style=flat-square)](https://travis-ci.org/keik/merge-source-map) 6 | [![Coverage Status](https://img.shields.io/coveralls/keik/merge-source-map.svg?style=flat-square)](https://coveralls.io/github/keik/merge-source-map) 7 | 8 | Merge old source map and new source map in multi-transform flow 9 | 10 | 11 | # API 12 | 13 | ```javascript 14 | var merge = require('merge-source-map') 15 | ``` 16 | 17 | 18 | ## `merge(oldMap, newMap)` 19 | 20 | Merge old source map and new source map and return merged. 21 | If old or new source map value is falsy, return another one as it is. 22 | 23 |
24 |
25 | oldMap : object|undefined 26 |
27 |
28 | old source map object 29 |
30 | 31 |
32 | newmap : object|undefined 33 |
34 |
35 | new source map object 36 |
37 |
38 | 39 | 40 | # Example 41 | 42 | ```javascript 43 | var esprima = require('esprima'), 44 | estraverse = require('estraverse'), 45 | escodegen = require('escodegen'), 46 | convert = require('convert-source-map'), 47 | merge = require('merge-source-map') 48 | 49 | const CODE = 'a = 1', 50 | FILEPATH = 'a.js' 51 | 52 | // create AST of original code 53 | var ast = esprima.parse(CODE, {sourceType: 'module', loc: true}) 54 | 55 | // transform AST of original code 56 | estraverse.replace(ast, { 57 | enter: function(node, parent) { /* change AST */ }, 58 | leave: function(node, parent) { /* change AST */ } 59 | }) 60 | 61 | // generate code and source map from transformed AST 62 | var gen = escodegen.generate(ast, { 63 | sourceMap: FILEPATH, 64 | sourceMapWithCode: true, 65 | sourceContent: CODE 66 | }) 67 | 68 | // merge old source map and new source map 69 | var oldMap = convert.fromSource(CODE) && convert.fromSource(CODE).toObject(), 70 | newMap = JSON.parse(gen.map.toString()), 71 | mergedMap = merge(oldMap, newMap), 72 | mapComment = convert.fromObject(mergedMap).toComment() 73 | 74 | // attach merge source map to transformed code 75 | var transformed = gen.code + '\n' + mapComment 76 | 77 | console.log(transformed); 78 | ``` 79 | 80 | 81 | # Test 82 | 83 | ``` 84 | % npm install 85 | % npm test 86 | ``` 87 | 88 | 89 | # License 90 | 91 | MIT (c) keik 92 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var sourceMap = require('source-map') 2 | var SourceMapConsumer = sourceMap.SourceMapConsumer 3 | var SourceMapGenerator = sourceMap.SourceMapGenerator 4 | 5 | module.exports = merge 6 | 7 | /** 8 | * Merge old source map and new source map and return merged. 9 | * If old or new source map value is falsy, return another one as it is. 10 | * 11 | * @param {object|string} [oldMap] old source map object 12 | * @param {object|string} [newmap] new source map object 13 | * @return {object|undefined} merged source map object, or undefined when both old and new source map are undefined 14 | */ 15 | function merge(oldMap, newMap) { 16 | if (!oldMap) return newMap 17 | if (!newMap) return oldMap 18 | 19 | var oldMapConsumer = new SourceMapConsumer(oldMap) 20 | var newMapConsumer = new SourceMapConsumer(newMap) 21 | var mergedMapGenerator = new SourceMapGenerator() 22 | 23 | // iterate on new map and overwrite original position of new map with one of old map 24 | newMapConsumer.eachMapping(function(m) { 25 | // pass when `originalLine` is null. 26 | // It occurs in case that the node does not have origin in original code. 27 | if (m.originalLine == null) return 28 | 29 | var origPosInOldMap = oldMapConsumer.originalPositionFor({ 30 | line: m.originalLine, 31 | column: m.originalColumn 32 | }) 33 | 34 | if (origPosInOldMap.source == null) return 35 | 36 | mergedMapGenerator.addMapping({ 37 | original: { 38 | line: origPosInOldMap.line, 39 | column: origPosInOldMap.column 40 | }, 41 | generated: { 42 | line: m.generatedLine, 43 | column: m.generatedColumn 44 | }, 45 | source: origPosInOldMap.source, 46 | name: origPosInOldMap.name 47 | }) 48 | }) 49 | 50 | var consumers = [oldMapConsumer, newMapConsumer] 51 | consumers.forEach(function(consumer) { 52 | consumer.sources.forEach(function(sourceFile) { 53 | mergedMapGenerator._sources.add(sourceFile) 54 | var sourceContent = consumer.sourceContentFor(sourceFile) 55 | if (sourceContent != null) { 56 | mergedMapGenerator.setSourceContent(sourceFile, sourceContent) 57 | } 58 | }) 59 | }) 60 | 61 | mergedMapGenerator._sourceRoot = oldMap.sourceRoot 62 | mergedMapGenerator._file = oldMap.file 63 | 64 | return JSON.parse(mergedMapGenerator.toString()) 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "merge-source-map", 3 | "version": "1.1.0", 4 | "description": "Merge old source map and new source map in multi-transform flow", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "nyc tape test/*.js", 8 | "lint": "eslint index.js 'test/**/*.js'", 9 | "version": "npm run lint && npm run test" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/keik/merge-source-map.git" 14 | }, 15 | "author": "keik ", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/keik/merge-source-map/issues" 19 | }, 20 | "keywords": [ 21 | "sourcemap", 22 | "source-map" 23 | ], 24 | "dependencies": { 25 | "source-map": "^0.6.1" 26 | }, 27 | "devDependencies": { 28 | "babel-core": "^6.25.0", 29 | "babel-plugin-syntax-object-rest-spread": "^6.13.0", 30 | "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", 31 | "babel-plugin-transform-es2015-spread": "^6.22.0", 32 | "coffee-script": "^1.12.6", 33 | "convert-source-map": "^1.5.0", 34 | "escodegen": "^1.8.1", 35 | "eslint": "^3.19.0", 36 | "esprima": "^3.1.3", 37 | "estraverse": "^4.2.0", 38 | "nyc": "^8.4.0", 39 | "tape": "^4.6.3" 40 | }, 41 | "files": [] 42 | } 43 | -------------------------------------------------------------------------------- /test/fixtures/coffee-script/actual.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var a, b; 3 | a = 1; 4 | a = 1; 5 | b = function (arg1, arg2) { 6 | console.log(arg1); 7 | console.log(arg1); 8 | console.log(arg2); 9 | console.log(arg2); 10 | }; 11 | b = function (arg1, arg2) { 12 | console.log(arg1); 13 | console.log(arg1); 14 | console.log(arg2); 15 | console.log(arg2); 16 | }; 17 | }.call(this)); 18 | (function () { 19 | var a, b; 20 | a = 1; 21 | a = 1; 22 | b = function (arg1, arg2) { 23 | console.log(arg1); 24 | console.log(arg1); 25 | console.log(arg2); 26 | console.log(arg2); 27 | }; 28 | b = function (arg1, arg2) { 29 | console.log(arg1); 30 | console.log(arg1); 31 | console.log(arg2); 32 | console.log(arg2); 33 | }; 34 | }.call(this)); -------------------------------------------------------------------------------- /test/fixtures/coffee-script/expected.coffee: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = (arg1, arg2) -> 3 | console.log arg1 4 | # comment 5 | console.log arg2 6 | return 7 | -------------------------------------------------------------------------------- /test/fixtures/coffee-script/expected.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.12.6 2 | (function() { 3 | var a, b; 4 | 5 | a = 1; 6 | 7 | b = function(arg1, arg2) { 8 | console.log(arg1); 9 | console.log(arg2); 10 | }; 11 | 12 | }).call(this); 13 | 14 | //# sourceMappingURL=expected.js.map 15 | -------------------------------------------------------------------------------- /test/fixtures/coffee-script/expected.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "file": "expected.js", 4 | "sourceRoot": "../../..", 5 | "sources": [ 6 | "test/fixtures/coffee-script/expected.coffee" 7 | ], 8 | "names": [], 9 | "mappings": ";AAAA;AAAA,MAAA;;EAAA,CAAA,GAAI;;EACJ,CAAA,GAAI,SAAC,IAAD,EAAO,IAAP;IACF,OAAO,CAAC,GAAR,CAAY,IAAZ;IAEA,OAAO,CAAC,GAAR,CAAY,IAAZ;EAHE;AADJ" 10 | } -------------------------------------------------------------------------------- /test/fixtures/es2015/actual.js: -------------------------------------------------------------------------------- 1 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 2 | 3 | var concatFooBar = function (args) { 4 | const f = 'foo'; 5 | const b = 'bar'; 6 | return [f, b].concat(_toConsumableArray(args)); 7 | }; -------------------------------------------------------------------------------- /test/fixtures/es2015/expected.js: -------------------------------------------------------------------------------- 1 | var concatFooBar = (args) => { 2 | const f = 'foo' 3 | const b = 'bar' 4 | return [f, b, ...args] 5 | } 6 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | 3 | const merge = require('../') 4 | 5 | const fs = require('fs') 6 | const resolve = require('path').resolve 7 | 8 | const babel = require('babel-core') 9 | const SourceMapConsumer = require('source-map').SourceMapConsumer 10 | 11 | const doubleLineTransform = require('./transforms/tr-double-line') 12 | const insertEmptyStatementTransform = require('./transforms/tr-insert-empty-statement') 13 | 14 | test('undefined args should not effect results', function(t) { 15 | const code = 'y = x => x * 2' 16 | const transformed = babel.transform(code, { 17 | filename: 'source.js', 18 | plugins: ['transform-es2015-spread'], 19 | sourceMaps: true 20 | }) 21 | 22 | const map = transformed.map 23 | t.equal(map, merge(undefined, map)) 24 | t.equal(map, merge(map, undefined)) 25 | t.end() 26 | }) 27 | 28 | test('multi transform with CoffeeScript and doubleLineTransform', function(t) { 29 | // first transform from CofeeeScript to JavaScript (assumed pre-processed) 30 | const coffeeCompiledCode = fs.readFileSync(resolve(__dirname, './fixtures/coffee-script/expected.js'), 'utf-8') 31 | const coffeeCompiledMap = fs.readFileSync(resolve(__dirname, './fixtures/coffee-script/expected.js.map'), 'utf-8') 32 | 33 | // second transform with `doubleLineTransform` 34 | const doubleLineTransformed = doubleLineTransform(coffeeCompiledCode, 'coffeeCompiled.js') 35 | 36 | // exercise: merge maps of `coffeeCompiled` and `doubleLineTransformed` 37 | const mergedMap = merge(coffeeCompiledMap, doubleLineTransformed.map.toJSON()) 38 | 39 | // logging... 40 | // console.log('# 1') 41 | // new SourceMapConsumer(coffeeCompiledMap).eachMapping(m => console.log(JSON.stringify(m))) 42 | // console.log('# 2') 43 | // new SourceMapConsumer(doubleLineTransformed.map.toJSON()).eachMapping(m => console.log(JSON.stringify(m))) 44 | // console.log('# 3') 45 | // new SourceMapConsumer(mergedMap).eachMapping(m => console.log(JSON.stringify(m))) 46 | 47 | // verify 48 | t.equal(doubleLineTransformed.code, fs.readFileSync(resolve(__dirname, './fixtures/coffee-script/actual.js'), 'utf-8')) 49 | 50 | const con = new SourceMapConsumer(mergedMap) 51 | for (var i = 0; i < 2; i++) { 52 | const offset = i * 17 53 | t.deepEqual( 54 | con.originalPositionFor({ line: 2 + offset, column: 8 }), 55 | { column: 0, line: 1, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 56 | 'pos of `var *a* = b`' 57 | ) 58 | t.deepEqual( 59 | con.originalPositionFor({ line: 2 + offset, column: 11 }), 60 | { column: 0, line: 1, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 61 | 'pos of `var *a* = b`' 62 | ) 63 | t.deepEqual( 64 | con.originalPositionFor({ line: 3 + offset, column: 4 }), 65 | { column: 0, line: 1, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 66 | 'pos of `var *a* = b`' 67 | ) 68 | t.deepEqual( 69 | con.originalPositionFor({ line: 4 + offset, column: 4 }), 70 | { column: 0, line: 1, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 71 | 'pos of `var *a* = b`' 72 | ) 73 | t.deepEqual( 74 | con.originalPositionFor({ line: 5 + offset, column: 4 }), 75 | { column: 0, line: 2, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 76 | 'pos of `*b* = function (arg1, arg2)`' 77 | ) 78 | t.deepEqual( 79 | con.originalPositionFor({ line: 5 + offset, column: 18 }), 80 | { column: 5, line: 2, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 81 | 'pos of `b = function (*arg1*, arg2)`' 82 | ) 83 | t.deepEqual( 84 | con.originalPositionFor({ line: 6 + offset, column: 8 }), 85 | { column: 2, line: 3, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 86 | 'pos of `*console*.log(arg1)`' 87 | ) 88 | t.deepEqual( 89 | con.originalPositionFor({ line: 6 + offset, column: 20 }), 90 | { column: 14, line: 3, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 91 | 'pos of `*console*.log(arg1)`' 92 | ) 93 | t.deepEqual( 94 | con.originalPositionFor({ line: 7 + offset, column: 8 }), 95 | { column: 2, line: 3, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 96 | 'pos of `*console*.log(arg1)`' 97 | ) 98 | t.deepEqual( 99 | con.originalPositionFor({ line: 7 + offset, column: 20 }), 100 | { column: 14, line: 3, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 101 | 'pos of `*console*.log(arg1)`' 102 | ) 103 | t.deepEqual( 104 | con.originalPositionFor({ line: 8 + offset, column: 8 }), 105 | { column: 2, line: 5, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 106 | 'pos of `*console*.log(arg1)`' 107 | ) 108 | t.deepEqual( 109 | con.originalPositionFor({ line: 8 + offset, column: 20 }), 110 | { column: 14, line: 5, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 111 | 'pos of `*console*.log(arg1)`' 112 | ) 113 | t.deepEqual( 114 | con.originalPositionFor({ line: 9 + offset, column: 8 }), 115 | { column: 2, line: 5, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 116 | 'pos of `*console*.log(arg1)`' 117 | ) 118 | t.deepEqual( 119 | con.originalPositionFor({ line: 9 + offset, column: 20 }), 120 | { column: 14, line: 5, name: null, source: '../../../test/fixtures/coffee-script/expected.coffee' }, 121 | 'pos of `*console*.log(arg1)`' 122 | ) 123 | } 124 | t.end() 125 | }) 126 | 127 | test('multi transform with es2015-arrow and es2015-spread on babel', function(t) { 128 | 129 | // source.js -> resultOfArrow.js 130 | const resultOfArrow = babel.transform(fs.readFileSync(resolve(__dirname, './fixtures/es2015/expected.js')), { 131 | filename: 'source.js', 132 | plugins: ['transform-es2015-arrow-functions'], 133 | sourceMaps: true, 134 | }) 135 | // logging... 136 | // console.log('# arrow') 137 | // const arrowMapConsumer = new SourceMapConsumer(resultOfArrow.map) 138 | // arrowMapConsumer.eachMapping(m => console.log(JSON.stringify(m))) 139 | // console.log(resultOfArrow.code) 140 | 141 | // resultOfArrow.js -> resultOfAdditionalSpread.js 142 | const resultOfAdditionalSpread = babel.transform(resultOfArrow.code, { 143 | filename: 'resultOfArrow.js', 144 | plugins: ['transform-es2015-spread'], 145 | sourceMaps: true 146 | }) 147 | // logging... 148 | // console.log('# additionalSpread') 149 | // const additionalSpreadMapConsumer = new SourceMapConsumer(resultOfAdditionalSpread.map) 150 | // additionalSpreadMapConsumer.eachMapping(m => console.log(JSON.stringify(m))) 151 | // console.log(resultOfAdditionalSpread.code) 152 | 153 | // exercise: merge maps of `resultOfArrow` and `resultOfAdditionalSpread 154 | const mergedMap = merge(resultOfArrow.map, resultOfAdditionalSpread.map) 155 | const mergedMapConsumer = new SourceMapConsumer(mergedMap) 156 | 157 | // logging... 158 | // console.log('# merged') 159 | // mergedMapConsumer.eachMapping(m => console.log(JSON.stringify(m))) 160 | 161 | // actual map with babel in same time transform 162 | const resultOfArrowAndSpreadAtSameTime = babel.transform(fs.readFileSync(resolve(__dirname, './fixtures/es2015/expected.js')), { 163 | filename: 'source.js', 164 | plugins: ['transform-es2015-arrow-functions', 'transform-es2015-spread'], 165 | sourceMaps: true 166 | }) 167 | const sameTimeMapConsumer = new SourceMapConsumer(resultOfArrowAndSpreadAtSameTime.map) 168 | // logging... 169 | // console.log('# actual with babel') 170 | // sameTimeMapConsumer.eachMapping(m => console.log(JSON.stringify(m))) 171 | // console.log(resultOfArrowAndSpreadAtSameTime.code) 172 | 173 | // verify 174 | const actualCode = fs.readFileSync(resolve(__dirname, './fixtures/es2015/actual.js'), 'utf-8') 175 | t.equal(resultOfAdditionalSpread.code, actualCode) 176 | t.equal(resultOfArrowAndSpreadAtSameTime.code, actualCode) 177 | 178 | // mappings by merge-soource-source-map, filtered by having `name` property 179 | const mergedMappings = [] 180 | mergedMapConsumer.eachMapping(function(m) { m.name && mergedMappings.push(m) }) 181 | 182 | // mappings by babel, filtered by having `name` property 183 | const sameTimeMappings = [] 184 | sameTimeMapConsumer.eachMapping(function(m) { m.name && sameTimeMappings.push(m) }) 185 | 186 | t.deepEqual(mergedMappings, sameTimeMappings) 187 | t.end() 188 | }) 189 | 190 | test('handle original position of code that does not have an origin', function(t) { 191 | const origCode = 'a = b' 192 | 193 | // transform to insert empty statement 194 | const transformed1 = insertEmptyStatementTransform(origCode, 'source.js') 195 | t.equal(transformed1.code, 'a = b;\n;') 196 | 197 | // transform to insert empty statement (x2) 198 | const transformed2 = insertEmptyStatementTransform(transformed1.code, 'transformed1.js') 199 | t.equal(transformed2.code, 'a = b;\n;\n;') 200 | 201 | // verify 202 | const mergedMap = merge(transformed1.map.toJSON(), transformed2.map.toJSON()) 203 | const con = new SourceMapConsumer(mergedMap) 204 | var origPos 205 | 206 | // pos for variable `a` 207 | origPos = con.originalPositionFor({line: 1, column: 0}) 208 | t.deepEqual(origPos, {line: 1, column: 0, name: 'a', source: 'source.js'}) 209 | 210 | // pos for variable `b` 211 | origPos = con.originalPositionFor({line: 1, column: 4}) 212 | t.deepEqual(origPos, {line: 1, column: 4, name: 'b', source: 'source.js'}) 213 | 214 | t.end() 215 | }) 216 | 217 | test('handle original position of code that does not have an origin (with compact format)', function(t) { 218 | const origCode = 'a = b' 219 | 220 | // transform to insert empty statement 221 | const transformed1 = insertEmptyStatementTransform(origCode, 'source.js', true) 222 | t.equal(transformed1.code, 'a=b;;') 223 | 224 | // transform to insert empty statement (x2) 225 | const transformed2 = insertEmptyStatementTransform(transformed1.code, 'transformed1.js', true) 226 | t.equal(transformed2.code, 'a=b;;;') 227 | 228 | const mergedMap = merge(transformed1.map.toJSON(), transformed2.map.toJSON()) 229 | const con = new SourceMapConsumer(mergedMap) 230 | var origPos 231 | 232 | // pos for variable `a` 233 | origPos = con.originalPositionFor({line: 1, column: 0}) 234 | t.deepEqual(origPos, {line: 1, column: 0, name: 'a', source: 'source.js'}) 235 | 236 | // pos for variable `b` 237 | origPos = con.originalPositionFor({line: 1, column: 2}) 238 | t.deepEqual(origPos, {line: 1, column: 4, name: 'b', source: 'source.js'}) 239 | 240 | t.end() 241 | }) 242 | -------------------------------------------------------------------------------- /test/transforms/tr-double-line.js: -------------------------------------------------------------------------------- 1 | const esprima = require('esprima') 2 | const estraverse = require('estraverse') 3 | const escodegen = require('escodegen') 4 | 5 | module.exports = function(code, filepath) { 6 | const ast = esprima.parse(code, {sourceType: 'module', loc: true}) 7 | estraverse.replace(ast, { 8 | enter: function(node, parent) { 9 | if (node.type === 'ExpressionStatement') { 10 | parent.body.splice(parent.body.indexOf(node), 0, node) 11 | } 12 | }, 13 | leave: function() {} 14 | }) 15 | 16 | return escodegen.generate(ast, { 17 | sourceMap: filepath, 18 | sourceMapWithCode: true, 19 | sourceContent: code 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /test/transforms/tr-insert-empty-statement.js: -------------------------------------------------------------------------------- 1 | const esprima = require('esprima') 2 | const estraverse = require('estraverse') 3 | const escodegen = require('escodegen') 4 | 5 | module.exports = function insertEmptyStatementTransform(code, filepath, compact) { 6 | const emptyStatement = esprima.parse(';').body[0] 7 | const ast = esprima.parse(code, {sourceType: 'module', loc: true}) 8 | estraverse.replace(ast, { 9 | enter: function(node, parent) { 10 | if (node.type === 'ExpressionStatement') { 11 | parent.body.push(emptyStatement) 12 | } 13 | }, 14 | leave: function() {} 15 | }) 16 | 17 | return escodegen.generate(ast, { 18 | sourceMap: filepath, 19 | sourceMapWithCode: true, 20 | sourceContent: code, 21 | format: {compact: compact} 22 | }) 23 | } 24 | --------------------------------------------------------------------------------