combine-source-map.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. 'use strict';
  2. /*jshint asi: true */
  3. var test = require('tap').test;
  4. var convert = require('convert-source-map');
  5. var commentRegex = require('convert-source-map').commentRegex;
  6. var combine = require('..');
  7. var mappingsFromMap = require('../lib/mappings-from-map');
  8. function checkMappings(foo, sm, lineOffset) {
  9. function inspect(obj, depth) {
  10. return require('util').inspect(obj, false, depth || 5, true);
  11. }
  12. var fooMappings = mappingsFromMap(foo);
  13. var mappings = mappingsFromMap(sm);
  14. var genLinesOffset = true;
  15. var origLinesSame = true;
  16. for (var i = 0; i < mappings.length; i++) {
  17. var fooGen = fooMappings[i].generated;
  18. var fooOrig = fooMappings[i].original;
  19. var gen = mappings[i].generated
  20. var orig = mappings[i].original;
  21. if (gen.column !== fooGen.column || gen.line !== (fooGen.line + lineOffset)) {
  22. console.error(
  23. 'generated mapping at %s not offset properly:\ninput: [%s]\noutput:[%s]\n\n',
  24. i ,
  25. inspect(fooGen),
  26. inspect(gen)
  27. );
  28. genLinesOffset = false;
  29. }
  30. if (orig.column !== fooOrig.column || orig.line !== fooOrig.line) {
  31. console.error(
  32. 'original mapping at %s is not the same as the genrated mapping:\ninput: [%s]\noutput:[%s]\n\n',
  33. i ,
  34. inspect(fooOrig),
  35. inspect(orig)
  36. );
  37. origLinesSame = false;
  38. }
  39. }
  40. return { genLinesOffset: genLinesOffset, origLinesSame: origLinesSame };
  41. }
  42. var foo = {
  43. version : 3,
  44. file : 'foo.js',
  45. sourceRoot : '',
  46. sources : [ 'foo.coffee' ],
  47. names : [],
  48. mappings : ';AAAA;CAAA;CAAA,CAAA,CAAA,IAAO,GAAK;CAAZ',
  49. sourcesContent : [ 'console.log(require \'./bar.js\')\n' ] };
  50. test('add one file with inlined source', function (t) {
  51. var mapComment = convert.fromObject(foo).toComment();
  52. var file = {
  53. id: 'xyz'
  54. , source: '(function() {\n\n console.log(require(\'./bar.js\'));\n\n}).call(this);\n' + '\n' + mapComment
  55. , sourceFile: 'foo.js'
  56. };
  57. var lineOffset = 3
  58. var base64 = combine.create()
  59. .addFile(file, { line: lineOffset })
  60. .base64()
  61. var sm = convert.fromBase64(base64).toObject();
  62. var res = checkMappings(foo, sm, lineOffset);
  63. t.ok(res.genLinesOffset, 'all generated lines are offset properly and columns unchanged')
  64. t.ok(res.origLinesSame, 'all original lines and columns are unchanged')
  65. t.deepEqual(sm.sourcesContent, foo.sourcesContent, 'includes the original source')
  66. t.deepEqual(sm.sources, ['foo.coffee'], 'includes original filename')
  67. t.end()
  68. });
  69. test('add one file without inlined source', function (t) {
  70. var mapComment = convert
  71. .fromObject(foo)
  72. .setProperty('sourcesContent', [])
  73. .toComment();
  74. var file = {
  75. id: 'xyz'
  76. , source: '(function() {\n\n console.log(require(\'./bar.js\'));\n\n}).call(this);\n' + '\n' + mapComment
  77. , sourceFile: 'foo.js'
  78. };
  79. var lineOffset = 3
  80. var base64 = combine.create()
  81. .addFile(file, { line: lineOffset })
  82. .base64()
  83. var sm = convert.fromBase64(base64).toObject();
  84. var mappings = mappingsFromMap(sm);
  85. t.deepEqual(sm.sourcesContent, [file.source], 'includes the generated source')
  86. t.deepEqual(sm.sources, ['foo.js'], 'includes generated filename')
  87. t.deepEqual(
  88. mappings
  89. , [ { generated: { line: 4, column: 0 },
  90. original: { line: 1, column: 0 },
  91. source: 'foo.js', name: null },
  92. { generated: { line: 5, column: 0 },
  93. original: { line: 2, column: 0 },
  94. source: 'foo.js', name: null },
  95. { generated: { line: 6, column: 0 },
  96. original: { line: 3, column: 0 },
  97. source: 'foo.js', name: null },
  98. { generated: { line: 7, column: 0 },
  99. original: { line: 4, column: 0 },
  100. source: 'foo.js', name: null },
  101. { generated: { line: 8, column: 0 },
  102. original: { line: 5, column: 0 },
  103. source: 'foo.js', name: null },
  104. { generated: { line: 9, column: 0 },
  105. original: { line: 6, column: 0 },
  106. source: 'foo.js', name: null },
  107. { generated: { line: 10, column: 0 },
  108. original: { line: 7, column: 0 },
  109. source: 'foo.js', name: null } ]
  110. , 'generates mappings offset by the given line'
  111. )
  112. t.end()
  113. })
  114. test('add one file with inlined sources from multiple files', function(t) {
  115. var gen1Map = {
  116. version: 3,
  117. sources: [ 'one.js', 'two.js' ],
  118. names: [],
  119. mappings: 'AAAA;ACAA',
  120. sourcesContent: [ 'console.log(1);', 'console.log(2);' ]
  121. };
  122. var gen2Map = {
  123. version: 3,
  124. sources: [ 'three.js', 'four.js' ],
  125. names: [],
  126. mappings: 'AAAA;ACAA',
  127. sourcesContent: [ 'console.log(3);', 'console.log(4);' ]
  128. };
  129. var base64 = combine.create()
  130. .addFile({
  131. source: 'console.log(1);\nconsole.log(2);\n' + convert.fromObject(gen1Map).toComment(),
  132. sourceFile: 'gen1.js'
  133. })
  134. .addFile({
  135. source: 'console.log(3);\nconsole.log(4);\n' + convert.fromObject(gen2Map).toComment(),
  136. sourceFile: 'gen2.js'
  137. }, {line: 2})
  138. .base64()
  139. var sm = convert.fromBase64(base64).toObject();
  140. t.deepEqual(sm.sources, ['one.js', 'two.js', 'three.js', 'four.js'], 'include the correct source');
  141. t.deepEqual(sm.sourcesContent, [
  142. 'console.log(1);',
  143. 'console.log(2);',
  144. 'console.log(3);',
  145. 'console.log(4);'
  146. ], 'include the correct source file content');
  147. t.deepEqual(
  148. mappingsFromMap(sm)
  149. , [ { original: { column: 0, line: 1 },
  150. generated: { column: 0, line: 1 },
  151. source: 'one.js',
  152. name: null },
  153. { original: { column: 0, line: 1 },
  154. generated: { column: 0, line: 2 },
  155. source: 'two.js',
  156. name: null },
  157. { original: { column: 0, line: 1 },
  158. generated: { column: 0, line: 3 },
  159. source: 'three.js',
  160. name: null },
  161. { original: { column: 0, line: 1 },
  162. generated: { column: 0, line: 4 },
  163. source: 'four.js',
  164. name: null } ], 'should properly map multiple files');
  165. t.end()
  166. });
  167. test('relative path from multiple files', function(t) {
  168. // Folder structure as follows:
  169. //
  170. // project
  171. // +- src
  172. // +- package1
  173. // +- sub
  174. // -- one.js
  175. // -- two.js
  176. // +- package2
  177. // +- sub
  178. // -- three.js
  179. // -- four.js
  180. // +- gen
  181. // +- gen1.js
  182. // +- gen2.js
  183. // -- combined.js
  184. //
  185. // Where 'one.js', 'two.js' were combined to 'gen1.js'
  186. // and 'three.js', 'four.js' were combined to 'gen2.js'.
  187. // Now 'gen1.js' and 'gen2.js' are being combined from
  188. // the project root folder.
  189. var gen1Map = {
  190. version: 3,
  191. sources: [ 'sub/one.js', 'sub/two.js' ],
  192. names: [],
  193. mappings: 'AAAA;ACAA',
  194. sourcesContent: [ 'console.log(1);', 'console.log(2);' ],
  195. sourceRoot: '../src/package1'
  196. };
  197. var gen2Map = {
  198. version: 3,
  199. sources: [ 'sub/three.js', 'sub/four.js' ],
  200. names: [],
  201. mappings: 'AAAA;ACAA',
  202. sourcesContent: [ 'console.log(3);', 'console.log(4);' ],
  203. sourceRoot: '../src/package2'
  204. };
  205. var base64 = combine.create()
  206. .addFile({
  207. source: 'console.log(1);\nconsole.log(2);\n' + convert.fromObject(gen1Map).toComment(),
  208. sourceFile: 'gen/gen1.js'
  209. })
  210. .addFile({
  211. source: 'console.log(3);\nconsole.log(4);\n' + convert.fromObject(gen2Map).toComment(),
  212. sourceFile: 'gen/gen2.js'
  213. }, {line: 2})
  214. .base64()
  215. var sm = convert.fromBase64(base64).toObject();
  216. t.deepEqual(sm.sources, ['src/package1/sub/one.js', 'src/package1/sub/two.js',
  217. 'src/package2/sub/three.js', 'src/package2/sub/four.js'],
  218. 'include the correct source');
  219. t.deepEqual(sm.sourcesContent, [
  220. 'console.log(1);',
  221. 'console.log(2);',
  222. 'console.log(3);',
  223. 'console.log(4);'
  224. ], 'include the correct source file content');
  225. t.deepEqual(
  226. mappingsFromMap(sm)
  227. , [ { original: { column: 0, line: 1 },
  228. generated: { column: 0, line: 1 },
  229. source: 'src/package1/sub/one.js',
  230. name: null },
  231. { original: { column: 0, line: 1 },
  232. generated: { column: 0, line: 2 },
  233. source: 'src/package1/sub/two.js',
  234. name: null },
  235. { original: { column: 0, line: 1 },
  236. generated: { column: 0, line: 3 },
  237. source: 'src/package2/sub/three.js',
  238. name: null },
  239. { original: { column: 0, line: 1 },
  240. generated: { column: 0, line: 4 },
  241. source: 'src/package2/sub/four.js',
  242. name: null } ], 'should properly map multiple files');
  243. t.end()
  244. });
  245. test('relative path when source and file name are the same', function(t) {
  246. var gen1Map = {
  247. version: 3,
  248. sources: [ 'a/b/one.js' ],
  249. names: [],
  250. mappings: 'AAAA',
  251. file: 'a/b/one.js',
  252. sourcesContent: [ 'console.log(1);\n' ]
  253. };
  254. var gen2Map = {
  255. version: 3,
  256. sources: [ 'a/b/two.js' ],
  257. names: [],
  258. mappings: 'AAAA',
  259. file: 'a/b/two.js',
  260. sourcesContent: [ 'console.log(2);\n' ]
  261. };
  262. var base64 = combine.create()
  263. .addFile({
  264. source: 'console.log(1);\n' + convert.fromObject(gen1Map).toComment(),
  265. sourceFile: 'a/b/one.js'
  266. })
  267. .addFile({
  268. source: 'console.log(2);\n' + convert.fromObject(gen2Map).toComment(),
  269. sourceFile: 'a/b/two.js'
  270. }, {line: 1})
  271. .base64()
  272. var sm = convert.fromBase64(base64).toObject();
  273. t.deepEqual(sm.sources, ['a/b/one.js', 'a/b/two.js'],
  274. 'include the correct source');
  275. t.deepEqual(
  276. mappingsFromMap(sm)
  277. , [ { original: { column: 0, line: 1 },
  278. generated: { column: 0, line: 1 },
  279. source: 'a/b/one.js',
  280. name: null },
  281. { original: { column: 0, line: 1 },
  282. generated: { column: 0, line: 2 },
  283. source: 'a/b/two.js',
  284. name: null } ], 'should properly map multiple files');
  285. t.end()
  286. });
  287. test('remove comments', function (t) {
  288. var mapComment = convert.fromObject(foo).toComment();
  289. function sourcemapComments(src) {
  290. var matches = src.match(commentRegex);
  291. return matches ? matches.length : 0;
  292. }
  293. t.equal(sourcemapComments('var a = 1;\n' + mapComment), 1);
  294. [ ''
  295. , 'var a = 1;\n' + mapComment
  296. , 'var a = 1;\n' + mapComment + '\nvar b = 5;\n' + mapComment
  297. ] .forEach(function (x) {
  298. var removed = combine.removeComments(x)
  299. t.equal(sourcemapComments(removed), 0)
  300. })
  301. t.end()
  302. })