1 /* -*- Mode: js; js-indent-level: 2; -*- */
3 * Copyright 2011 Mozilla Foundation and contributors
4 * Licensed under the New BSD license. See LICENSE or:
5 * http://opensource.org/licenses/BSD-3-Clause
7 if (typeof define !== 'function') {
8 var define = require('amdefine')(module, require);
10 define(function (require, exports, module) {
12 var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator;
13 var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer;
14 var SourceNode = require('../../lib/source-map/source-node').SourceNode;
15 var util = require('./util');
17 exports['test some simple stuff'] = function (assert, util) {
18 var map = new SourceMapGenerator({
24 var map = new SourceMapGenerator().toJSON();
25 assert.ok(!('file' in map));
26 assert.ok(!('sourceRoot' in map));
29 exports['test JSON serialization'] = function (assert, util) {
30 var map = new SourceMapGenerator({
34 assert.equal(map.toString(), JSON.stringify(map));
37 exports['test adding mappings (case 1)'] = function (assert, util) {
38 var map = new SourceMapGenerator({
39 file: 'generated-foo.js',
43 assert.doesNotThrow(function () {
45 generated: { line: 1, column: 1 }
50 exports['test adding mappings (case 2)'] = function (assert, util) {
51 var map = new SourceMapGenerator({
52 file: 'generated-foo.js',
56 assert.doesNotThrow(function () {
58 generated: { line: 1, column: 1 },
60 original: { line: 1, column: 1 }
65 exports['test adding mappings (case 3)'] = function (assert, util) {
66 var map = new SourceMapGenerator({
67 file: 'generated-foo.js',
71 assert.doesNotThrow(function () {
73 generated: { line: 1, column: 1 },
75 original: { line: 1, column: 1 },
81 exports['test adding mappings (invalid)'] = function (assert, util) {
82 var map = new SourceMapGenerator({
83 file: 'generated-foo.js',
88 assert.throws(function () {
92 // Original file position, but no source.
93 assert.throws(function () {
95 generated: { line: 1, column: 1 },
96 original: { line: 1, column: 1 }
101 exports['test adding mappings with skipValidation'] = function (assert, util) {
102 var map = new SourceMapGenerator({
103 file: 'generated-foo.js',
108 // Not enough info, caught by `util.getArgs`
109 assert.throws(function () {
113 // Original file position, but no source. Not checked.
114 assert.doesNotThrow(function () {
116 generated: { line: 1, column: 1 },
117 original: { line: 1, column: 1 }
122 exports['test that the correct mappings are being generated'] = function (assert, util) {
123 var map = new SourceMapGenerator({
125 sourceRoot: '/the/root'
129 generated: { line: 1, column: 1 },
130 original: { line: 1, column: 1 },
134 generated: { line: 1, column: 5 },
135 original: { line: 1, column: 5 },
139 generated: { line: 1, column: 9 },
140 original: { line: 1, column: 11 },
144 generated: { line: 1, column: 18 },
145 original: { line: 1, column: 21 },
150 generated: { line: 1, column: 21 },
151 original: { line: 2, column: 3 },
155 generated: { line: 1, column: 28 },
156 original: { line: 2, column: 10 },
161 generated: { line: 1, column: 32 },
162 original: { line: 2, column: 14 },
168 generated: { line: 2, column: 1 },
169 original: { line: 1, column: 1 },
173 generated: { line: 2, column: 5 },
174 original: { line: 1, column: 5 },
178 generated: { line: 2, column: 9 },
179 original: { line: 1, column: 11 },
183 generated: { line: 2, column: 18 },
184 original: { line: 1, column: 21 },
189 generated: { line: 2, column: 21 },
190 original: { line: 2, column: 3 },
194 generated: { line: 2, column: 28 },
195 original: { line: 2, column: 10 },
200 map = JSON.parse(map.toString());
202 util.assertEqualMaps(assert, map, util.testMap);
205 exports['test that adding a mapping with an empty string name does not break generation'] = function (assert, util) {
206 var map = new SourceMapGenerator({
207 file: 'generated-foo.js',
212 generated: { line: 1, column: 1 },
214 original: { line: 1, column: 1 },
218 assert.doesNotThrow(function () {
219 JSON.parse(map.toString());
223 exports['test that source content can be set'] = function (assert, util) {
224 var map = new SourceMapGenerator({
226 sourceRoot: '/the/root'
229 generated: { line: 1, column: 1 },
230 original: { line: 1, column: 1 },
234 generated: { line: 2, column: 1 },
235 original: { line: 1, column: 1 },
238 map.setSourceContent('one.js', 'one file content');
240 map = JSON.parse(map.toString());
241 assert.equal(map.sources[0], 'one.js');
242 assert.equal(map.sources[1], 'two.js');
243 assert.equal(map.sourcesContent[0], 'one file content');
244 assert.equal(map.sourcesContent[1], null);
247 exports['test .fromSourceMap'] = function (assert, util) {
248 var map = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(util.testMap));
249 util.assertEqualMaps(assert, map.toJSON(), util.testMap);
252 exports['test .fromSourceMap with sourcesContent'] = function (assert, util) {
253 var map = SourceMapGenerator.fromSourceMap(
254 new SourceMapConsumer(util.testMapWithSourcesContent));
255 util.assertEqualMaps(assert, map.toJSON(), util.testMapWithSourcesContent);
258 exports['test applySourceMap'] = function (assert, util) {
259 var node = new SourceNode(null, null, null, [
260 new SourceNode(2, 0, 'fileX', 'lineX2\n'),
262 new SourceNode(2, 0, 'fileY', 'lineY2\n'),
264 new SourceNode(1, 0, 'fileX', 'lineX1\n'),
266 new SourceNode(1, 0, 'fileY', 'lineY1\n')
268 var mapStep1 = node.toStringWithSourceMap({
271 mapStep1.setSourceContent('fileX', 'lineX1\nlineX2\n');
272 mapStep1 = mapStep1.toJSON();
274 node = new SourceNode(null, null, null, [
276 new SourceNode(1, 0, 'fileA', 'lineA1\n'),
277 new SourceNode(2, 0, 'fileA', 'lineA2\n'),
278 new SourceNode(3, 0, 'fileA', 'lineA3\n'),
279 new SourceNode(4, 0, 'fileA', 'lineA4\n'),
280 new SourceNode(1, 0, 'fileB', 'lineB1\n'),
281 new SourceNode(2, 0, 'fileB', 'lineB2\n'),
284 var mapStep2 = node.toStringWithSourceMap({
287 mapStep2.setSourceContent('fileB', 'lineB1\nlineB2\n');
288 mapStep2 = mapStep2.toJSON();
290 node = new SourceNode(null, null, null, [
292 new SourceNode(2, 0, 'fileX', 'lineA1\n'),
293 new SourceNode(2, 0, 'fileA', 'lineA2\n'),
294 new SourceNode(2, 0, 'fileY', 'lineA3\n'),
295 new SourceNode(4, 0, 'fileA', 'lineA4\n'),
296 new SourceNode(1, 0, 'fileB', 'lineB1\n'),
297 new SourceNode(2, 0, 'fileB', 'lineB2\n'),
300 var expectedMap = node.toStringWithSourceMap({
303 expectedMap.setSourceContent('fileX', 'lineX1\nlineX2\n');
304 expectedMap.setSourceContent('fileB', 'lineB1\nlineB2\n');
305 expectedMap = expectedMap.toJSON();
307 // apply source map "mapStep1" to "mapStep2"
308 var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(mapStep2));
309 generator.applySourceMap(new SourceMapConsumer(mapStep1));
310 var actualMap = generator.toJSON();
312 util.assertEqualMaps(assert, actualMap, expectedMap);
315 exports['test applySourceMap throws when file is missing'] = function (assert, util) {
316 var map = new SourceMapGenerator({
319 var map2 = new SourceMapGenerator();
320 assert.throws(function() {
321 map.applySourceMap(new SourceMapConsumer(map2.toJSON()));
325 exports['test the two additional parameters of applySourceMap'] = function (assert, util) {
326 // Assume the following directory structure:
341 // http://www.example.com/
344 var bundleMap = new SourceMapGenerator({
347 bundleMap.addMapping({
348 generated: { line: 3, column: 3 },
349 original: { line: 2, column: 2 },
350 source: '../../coffee/foo.coffee'
352 bundleMap.setSourceContent('../../coffee/foo.coffee', 'foo coffee');
353 bundleMap.addMapping({
354 generated: { line: 13, column: 13 },
355 original: { line: 12, column: 12 },
356 source: '/bar.coffee'
358 bundleMap.setSourceContent('/bar.coffee', 'bar coffee');
359 bundleMap.addMapping({
360 generated: { line: 23, column: 23 },
361 original: { line: 22, column: 22 },
362 source: 'http://www.example.com/baz.coffee'
364 bundleMap.setSourceContent(
365 'http://www.example.com/baz.coffee',
368 bundleMap = new SourceMapConsumer(bundleMap.toJSON());
370 var minifiedMap = new SourceMapGenerator({
371 file: 'bundle.min.js',
374 minifiedMap.addMapping({
375 generated: { line: 1, column: 1 },
376 original: { line: 3, column: 3 },
377 source: 'temp/bundle.js'
379 minifiedMap.addMapping({
380 generated: { line: 11, column: 11 },
381 original: { line: 13, column: 13 },
382 source: 'temp/bundle.js'
384 minifiedMap.addMapping({
385 generated: { line: 21, column: 21 },
386 original: { line: 23, column: 23 },
387 source: 'temp/bundle.js'
389 minifiedMap = new SourceMapConsumer(minifiedMap.toJSON());
391 var expectedMap = function (sources) {
392 var map = new SourceMapGenerator({
393 file: 'bundle.min.js',
397 generated: { line: 1, column: 1 },
398 original: { line: 2, column: 2 },
401 map.setSourceContent(sources[0], 'foo coffee');
403 generated: { line: 11, column: 11 },
404 original: { line: 12, column: 12 },
407 map.setSourceContent(sources[1], 'bar coffee');
409 generated: { line: 21, column: 21 },
410 original: { line: 22, column: 22 },
413 map.setSourceContent(sources[2], 'baz coffee');
417 var actualMap = function (aSourceMapPath) {
418 var map = SourceMapGenerator.fromSourceMap(minifiedMap);
419 // Note that relying on `bundleMap.file` (which is simply 'bundle.js')
420 // instead of supplying the second parameter wouldn't work here.
421 map.applySourceMap(bundleMap, '../temp/bundle.js', aSourceMapPath);
425 util.assertEqualMaps(assert, actualMap('../temp/temp_maps'), expectedMap([
428 'http://www.example.com/baz.coffee'
431 util.assertEqualMaps(assert, actualMap('/app/temp/temp_maps'), expectedMap([
432 '/app/coffee/foo.coffee',
434 'http://www.example.com/baz.coffee'
437 util.assertEqualMaps(assert, actualMap('http://foo.org/app/temp/temp_maps'), expectedMap([
438 'http://foo.org/app/coffee/foo.coffee',
439 'http://foo.org/bar.coffee',
440 'http://www.example.com/baz.coffee'
443 // If the third parameter is omitted or set to the current working
444 // directory we get incorrect source paths:
446 util.assertEqualMaps(assert, actualMap(), expectedMap([
447 '../coffee/foo.coffee',
449 'http://www.example.com/baz.coffee'
452 util.assertEqualMaps(assert, actualMap(''), expectedMap([
453 '../coffee/foo.coffee',
455 'http://www.example.com/baz.coffee'
458 util.assertEqualMaps(assert, actualMap('.'), expectedMap([
459 '../coffee/foo.coffee',
461 'http://www.example.com/baz.coffee'
464 util.assertEqualMaps(assert, actualMap('./'), expectedMap([
465 '../coffee/foo.coffee',
467 'http://www.example.com/baz.coffee'
471 exports['test applySourceMap name handling'] = function (assert, util) {
472 // Imagine some CoffeeScript code being compiled into JavaScript and then
475 var assertName = function(coffeeName, jsName, expectedName) {
476 var minifiedMap = new SourceMapGenerator({
479 minifiedMap.addMapping({
480 generated: { line: 1, column: 4 },
481 original: { line: 1, column: 4 },
486 var coffeeMap = new SourceMapGenerator({
489 coffeeMap.addMapping({
490 generated: { line: 1, column: 4 },
491 original: { line: 1, column: 0 },
492 source: 'test.coffee',
496 minifiedMap.applySourceMap(new SourceMapConsumer(coffeeMap.toJSON()));
498 new SourceMapConsumer(minifiedMap.toJSON()).eachMapping(function(mapping) {
499 assert.equal(mapping.name, expectedName);
503 // `foo = 1` -> `var foo = 1;` -> `var a=1`
504 // CoffeeScript doesn’t rename variables, so there’s no need for it to
505 // provide names in its source maps. Minifiers do rename variables and
506 // therefore do provide names in their source maps. So that name should be
507 // retained if the original map lacks names.
508 assertName(null, 'foo', 'foo');
510 // `foo = 1` -> `var coffee$foo = 1;` -> `var a=1`
511 // Imagine that CoffeeScript prefixed all variables with `coffee$`. Even
512 // though the minifier then also provides a name, the original name is
513 // what corresponds to the source.
514 assertName('foo', 'coffee$foo', 'foo');
516 // `foo = 1` -> `var coffee$foo = 1;` -> `var coffee$foo=1`
517 // Minifiers can turn off variable mangling. Then there’s no need to
518 // provide names in the source map, but the names from the original map are
520 assertName('foo', null, 'foo');
522 // `foo = 1` -> `var foo = 1;` -> `var foo=1`
523 // No renaming at all.
524 assertName(null, null, null);
527 exports['test sorting with duplicate generated mappings'] = function (assert, util) {
528 var map = new SourceMapGenerator({
532 generated: { line: 3, column: 0 },
533 original: { line: 2, column: 0 },
537 generated: { line: 2, column: 0 }
540 generated: { line: 2, column: 0 }
543 generated: { line: 1, column: 0 },
544 original: { line: 1, column: 0 },
548 util.assertEqualMaps(assert, map.toJSON(), {
553 mappings: 'AAAA;A;AACA'
557 exports['test ignore duplicate mappings.'] = function (assert, util) {
558 var init = { file: 'min.js', sourceRoot: '/the/root' };
561 // null original source location
563 generated: { line: 1, column: 0 }
566 generated: { line: 2, column: 2 }
569 map1 = new SourceMapGenerator(init);
570 map2 = new SourceMapGenerator(init);
572 map1.addMapping(nullMapping1);
573 map1.addMapping(nullMapping1);
575 map2.addMapping(nullMapping1);
577 util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON());
579 map1.addMapping(nullMapping2);
580 map1.addMapping(nullMapping1);
582 map2.addMapping(nullMapping2);
584 util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON());
586 // original source location
588 generated: { line: 1, column: 0 },
589 original: { line: 11, column: 0 },
590 source: 'srcMapping1.js'
593 generated: { line: 2, column: 2 },
594 original: { line: 11, column: 0 },
595 source: 'srcMapping2.js'
598 map1 = new SourceMapGenerator(init);
599 map2 = new SourceMapGenerator(init);
601 map1.addMapping(srcMapping1);
602 map1.addMapping(srcMapping1);
604 map2.addMapping(srcMapping1);
606 util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON());
608 map1.addMapping(srcMapping2);
609 map1.addMapping(srcMapping1);
611 map2.addMapping(srcMapping2);
613 util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON());
615 // full original source and name information
617 generated: { line: 1, column: 0 },
618 original: { line: 11, column: 0 },
619 source: 'fullMapping1.js',
623 generated: { line: 2, column: 2 },
624 original: { line: 11, column: 0 },
625 source: 'fullMapping2.js',
629 map1 = new SourceMapGenerator(init);
630 map2 = new SourceMapGenerator(init);
632 map1.addMapping(fullMapping1);
633 map1.addMapping(fullMapping1);
635 map2.addMapping(fullMapping1);
637 util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON());
639 map1.addMapping(fullMapping2);
640 map1.addMapping(fullMapping1);
642 map2.addMapping(fullMapping2);
644 util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON());
647 exports['test github issue #72, check for duplicate names or sources'] = function (assert, util) {
648 var map = new SourceMapGenerator({
652 generated: { line: 1, column: 1 },
653 original: { line: 2, column: 2 },
658 generated: { line: 3, column: 3 },
659 original: { line: 4, column: 4 },
663 util.assertEqualMaps(assert, map.toJSON(), {
668 mappings: 'CACEA;;GAEEA'
672 exports['test setting sourcesContent to null when already null'] = function (assert, util) {
673 var smg = new SourceMapGenerator({ file: "foo.js" });
674 assert.doesNotThrow(function() {
675 smg.setSourceContent("bar.js", null);