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;
16 function forEachNewline(fn) {
17 return function (assert, util) {
18 ['\n', '\r\n'].forEach(fn.bind(null, assert, util));
22 exports['test .add()'] = function (assert, util) {
23 var node = new SourceNode(null, null, null);
25 // Adding a string works.
26 node.add('function noop() {}');
28 // Adding another source node works.
29 node.add(new SourceNode(null, null, null));
31 // Adding an array works.
32 node.add(['function foo() {',
33 new SourceNode(null, null, null,
37 // Adding other stuff doesn't.
38 assert.throws(function () {
41 assert.throws(function () {
42 node.add(function () {});
46 exports['test .prepend()'] = function (assert, util) {
47 var node = new SourceNode(null, null, null);
49 // Prepending a string works.
50 node.prepend('function noop() {}');
51 assert.equal(node.children[0], 'function noop() {}');
52 assert.equal(node.children.length, 1);
54 // Prepending another source node works.
55 node.prepend(new SourceNode(null, null, null));
56 assert.equal(node.children[0], '');
57 assert.equal(node.children[1], 'function noop() {}');
58 assert.equal(node.children.length, 2);
60 // Prepending an array works.
61 node.prepend(['function foo() {',
62 new SourceNode(null, null, null,
65 assert.equal(node.children[0], 'function foo() {');
66 assert.equal(node.children[1], 'return 10;');
67 assert.equal(node.children[2], '}');
68 assert.equal(node.children[3], '');
69 assert.equal(node.children[4], 'function noop() {}');
70 assert.equal(node.children.length, 5);
72 // Prepending other stuff doesn't.
73 assert.throws(function () {
76 assert.throws(function () {
77 node.prepend(function () {});
81 exports['test .toString()'] = function (assert, util) {
82 assert.equal((new SourceNode(null, null, null,
84 new SourceNode(null, null, null, 'return 10;'),
86 'function foo() {return 10;}');
89 exports['test .join()'] = function (assert, util) {
90 assert.equal((new SourceNode(null, null, null,
91 ['a', 'b', 'c', 'd'])).join(', ').toString(),
95 exports['test .walk()'] = function (assert, util) {
96 var node = new SourceNode(null, null, null,
98 ' ', new SourceNode(1, 0, 'a.js', ['someCall()']), ';\n',
99 ' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n',
102 { str: '(function () {\n', source: null, line: null, column: null },
103 { str: ' ', source: null, line: null, column: null },
104 { str: 'someCall()', source: 'a.js', line: 1, column: 0 },
105 { str: ';\n', source: null, line: null, column: null },
106 { str: ' ', source: null, line: null, column: null },
107 { str: 'if (foo) bar()', source: 'b.js', line: 2, column: 0 },
108 { str: ';\n', source: null, line: null, column: null },
109 { str: '}());', source: null, line: null, column: null },
112 node.walk(function (chunk, loc) {
113 assert.equal(expected[i].str, chunk);
114 assert.equal(expected[i].source, loc.source);
115 assert.equal(expected[i].line, loc.line);
116 assert.equal(expected[i].column, loc.column);
121 exports['test .replaceRight'] = function (assert, util) {
125 node = new SourceNode(null, null, null, 'hello world');
126 node.replaceRight(/world/, 'universe');
127 assert.equal(node.toString(), 'hello universe');
130 node = new SourceNode(null, null, null,
131 [new SourceNode(null, null, null, 'hey sexy mama, '),
132 new SourceNode(null, null, null, 'want to kill all humans?')]);
133 node.replaceRight(/kill all humans/, 'watch Futurama');
134 assert.equal(node.toString(), 'hey sexy mama, want to watch Futurama?');
137 exports['test .toStringWithSourceMap()'] = forEachNewline(function (assert, util, nl) {
138 var node = new SourceNode(null, null, null,
139 ['(function () {' + nl,
141 new SourceNode(1, 0, 'a.js', 'someCall', 'originalCall'),
142 new SourceNode(1, 8, 'a.js', '()'),
144 ' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';' + nl,
146 var result = node.toStringWithSourceMap({
150 assert.equal(result.code, [
157 var map = result.map;
158 var mapWithoutOptions = node.toStringWithSourceMap().map;
160 assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
161 assert.ok(mapWithoutOptions instanceof SourceMapGenerator, 'mapWithoutOptions instanceof SourceMapGenerator');
162 assert.ok(!('file' in mapWithoutOptions));
163 mapWithoutOptions._file = 'foo.js';
164 util.assertEqualMaps(assert, map.toJSON(), mapWithoutOptions.toJSON());
166 map = new SourceMapConsumer(map.toString());
170 actual = map.originalPositionFor({
174 assert.equal(actual.source, null);
175 assert.equal(actual.line, null);
176 assert.equal(actual.column, null);
178 actual = map.originalPositionFor({
182 assert.equal(actual.source, 'a.js');
183 assert.equal(actual.line, 1);
184 assert.equal(actual.column, 0);
185 assert.equal(actual.name, 'originalCall');
187 actual = map.originalPositionFor({
191 assert.equal(actual.source, 'b.js');
192 assert.equal(actual.line, 2);
193 assert.equal(actual.column, 0);
195 actual = map.originalPositionFor({
199 assert.equal(actual.source, null);
200 assert.equal(actual.line, null);
201 assert.equal(actual.column, null);
203 actual = map.originalPositionFor({
207 assert.equal(actual.source, null);
208 assert.equal(actual.line, null);
209 assert.equal(actual.column, null);
212 exports['test .fromStringWithSourceMap()'] = forEachNewline(function (assert, util, nl) {
213 var testCode = util.testGeneratedCode.replace(/\n/g, nl);
214 var node = SourceNode.fromStringWithSourceMap(
216 new SourceMapConsumer(util.testMap));
218 var result = node.toStringWithSourceMap({
221 var map = result.map;
222 var code = result.code;
224 assert.equal(code, testCode);
225 assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
227 assert.equal(map.version, util.testMap.version);
228 assert.equal(map.file, util.testMap.file);
229 assert.equal(map.mappings, util.testMap.mappings);
232 exports['test .fromStringWithSourceMap() empty map'] = forEachNewline(function (assert, util, nl) {
233 var node = SourceNode.fromStringWithSourceMap(
234 util.testGeneratedCode.replace(/\n/g, nl),
235 new SourceMapConsumer(util.emptyMap));
236 var result = node.toStringWithSourceMap({
239 var map = result.map;
240 var code = result.code;
242 assert.equal(code, util.testGeneratedCode.replace(/\n/g, nl));
243 assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
245 assert.equal(map.version, util.emptyMap.version);
246 assert.equal(map.file, util.emptyMap.file);
247 assert.equal(map.mappings.length, util.emptyMap.mappings.length);
248 assert.equal(map.mappings, util.emptyMap.mappings);
251 exports['test .fromStringWithSourceMap() complex version'] = forEachNewline(function (assert, util, nl) {
252 var input = new SourceNode(null, null, null, [
253 "(function() {" + nl,
254 " var Test = {};" + nl,
255 " ", new SourceNode(1, 0, "a.js", "Test.A = { value: 1234 };" + nl),
256 " ", new SourceNode(2, 0, "a.js", "Test.A.x = 'xyz';"), nl,
258 "/* Generated Source */"]);
259 input = input.toStringWithSourceMap({
263 var node = SourceNode.fromStringWithSourceMap(
265 new SourceMapConsumer(input.map.toString()));
267 var result = node.toStringWithSourceMap({
270 var map = result.map;
271 var code = result.code;
273 assert.equal(code, input.code);
274 assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
276 var inputMap = input.map.toJSON();
277 util.assertEqualMaps(assert, map, inputMap);
280 exports['test .fromStringWithSourceMap() third argument'] = function (assert, util) {
281 // Assume the following directory structure:
288 // coffeeBundle.js # Made from {foo,bar,baz}.coffee
290 // coffeeBundle.js.map
294 // app.js # Made from {foo,coffeeBundle}.js
297 // http://www.example.com/
300 var coffeeBundle = new SourceNode(1, 0, 'foo.coffee', 'foo(coffee);\n');
301 coffeeBundle.setSourceContent('foo.coffee', 'foo coffee');
302 coffeeBundle.add(new SourceNode(2, 0, '/bar.coffee', 'bar(coffee);\n'));
303 coffeeBundle.add(new SourceNode(3, 0, 'http://www.example.com/baz.coffee', 'baz(coffee);'));
304 coffeeBundle = coffeeBundle.toStringWithSourceMap({
309 var foo = new SourceNode(1, 0, 'foo.js', 'foo(js);');
311 var test = function(relativePath, expectedSources) {
312 var app = new SourceNode();
313 app.add(SourceNode.fromStringWithSourceMap(
315 new SourceMapConsumer(coffeeBundle.map.toString()),
319 app.walk(function (chunk, loc) {
320 assert.equal(loc.source, expectedSources[i]);
323 app.walkSourceContents(function (sourceFile, sourceContent) {
324 assert.equal(sourceFile, expectedSources[0]);
325 assert.equal(sourceContent, 'foo coffee');
329 test('../coffee/maps', [
330 '../coffee/foo.coffee',
332 'http://www.example.com/baz.coffee',
336 // If the third parameter is omitted or set to the current working
337 // directory we get incorrect source paths:
342 'http://www.example.com/baz.coffee',
349 'http://www.example.com/baz.coffee',
356 'http://www.example.com/baz.coffee',
363 'http://www.example.com/baz.coffee',
368 exports['test .toStringWithSourceMap() merging duplicate mappings'] = forEachNewline(function (assert, util, nl) {
369 var input = new SourceNode(null, null, null, [
370 new SourceNode(1, 0, "a.js", "(function"),
371 new SourceNode(1, 0, "a.js", "() {" + nl),
373 new SourceNode(1, 0, "a.js", "var Test = "),
374 new SourceNode(1, 0, "b.js", "{};" + nl),
375 new SourceNode(2, 0, "b.js", "Test"),
376 new SourceNode(2, 0, "b.js", ".A", "A"),
377 new SourceNode(2, 20, "b.js", " = { value: ", "A"),
379 new SourceNode(2, 40, "b.js", " };" + nl, "A"),
381 "/* Generated Source */"
383 input = input.toStringWithSourceMap({
387 assert.equal(input.code, [
390 "Test.A = { value: 1234 };",
392 "/* Generated Source */"
395 var correctMap = new SourceMapGenerator({
398 correctMap.addMapping({
399 generated: { line: 1, column: 0 },
401 original: { line: 1, column: 0 }
403 // Here is no need for a empty mapping,
404 // because mappings ends at eol
405 correctMap.addMapping({
406 generated: { line: 2, column: 2 },
408 original: { line: 1, column: 0 }
410 correctMap.addMapping({
411 generated: { line: 2, column: 13 },
413 original: { line: 1, column: 0 }
415 correctMap.addMapping({
416 generated: { line: 3, column: 0 },
418 original: { line: 2, column: 0 }
420 correctMap.addMapping({
421 generated: { line: 3, column: 4 },
424 original: { line: 2, column: 0 }
426 correctMap.addMapping({
427 generated: { line: 3, column: 6 },
430 original: { line: 2, column: 20 }
432 // This empty mapping is required,
433 // because there is a hole in the middle of the line
434 correctMap.addMapping({
435 generated: { line: 3, column: 18 }
437 correctMap.addMapping({
438 generated: { line: 3, column: 22 },
441 original: { line: 2, column: 40 }
443 // Here is no need for a empty mapping,
444 // because mappings ends at eol
446 var inputMap = input.map.toJSON();
447 correctMap = correctMap.toJSON();
448 util.assertEqualMaps(assert, inputMap, correctMap);
451 exports['test .toStringWithSourceMap() multi-line SourceNodes'] = forEachNewline(function (assert, util, nl) {
452 var input = new SourceNode(null, null, null, [
453 new SourceNode(1, 0, "a.js", "(function() {" + nl + "var nextLine = 1;" + nl + "anotherLine();" + nl),
454 new SourceNode(2, 2, "b.js", "Test.call(this, 123);" + nl),
455 new SourceNode(2, 2, "b.js", "this['stuff'] = 'v';" + nl),
456 new SourceNode(2, 2, "b.js", "anotherLine();" + nl),
457 "/*" + nl + "Generated" + nl + "Source" + nl + "*/" + nl,
458 new SourceNode(3, 4, "c.js", "anotherLine();" + nl),
459 "/*" + nl + "Generated" + nl + "Source" + nl + "*/"
461 input = input.toStringWithSourceMap({
465 assert.equal(input.code, [
469 "Test.call(this, 123);",
470 "this['stuff'] = 'v';",
483 var correctMap = new SourceMapGenerator({
486 correctMap.addMapping({
487 generated: { line: 1, column: 0 },
489 original: { line: 1, column: 0 }
491 correctMap.addMapping({
492 generated: { line: 2, column: 0 },
494 original: { line: 1, column: 0 }
496 correctMap.addMapping({
497 generated: { line: 3, column: 0 },
499 original: { line: 1, column: 0 }
501 correctMap.addMapping({
502 generated: { line: 4, column: 0 },
504 original: { line: 2, column: 2 }
506 correctMap.addMapping({
507 generated: { line: 5, column: 0 },
509 original: { line: 2, column: 2 }
511 correctMap.addMapping({
512 generated: { line: 6, column: 0 },
514 original: { line: 2, column: 2 }
516 correctMap.addMapping({
517 generated: { line: 11, column: 0 },
519 original: { line: 3, column: 4 }
522 var inputMap = input.map.toJSON();
523 correctMap = correctMap.toJSON();
524 util.assertEqualMaps(assert, inputMap, correctMap);
527 exports['test .toStringWithSourceMap() with empty string'] = function (assert, util) {
528 var node = new SourceNode(1, 0, 'empty.js', '');
529 var result = node.toStringWithSourceMap();
530 assert.equal(result.code, '');
533 exports['test .toStringWithSourceMap() with consecutive newlines'] = forEachNewline(function (assert, util, nl) {
534 var input = new SourceNode(null, null, null, [
536 new SourceNode(1, 0, "a.js", "'use strict';" + nl),
537 new SourceNode(2, 0, "a.js", "a();"),
539 input = input.toStringWithSourceMap({
543 assert.equal(input.code, [
550 var correctMap = new SourceMapGenerator({
553 correctMap.addMapping({
554 generated: { line: 3, column: 0 },
556 original: { line: 1, column: 0 }
558 correctMap.addMapping({
559 generated: { line: 4, column: 0 },
561 original: { line: 2, column: 0 }
564 var inputMap = input.map.toJSON();
565 correctMap = correctMap.toJSON();
566 util.assertEqualMaps(assert, inputMap, correctMap);
569 exports['test setSourceContent with toStringWithSourceMap'] = function (assert, util) {
570 var aNode = new SourceNode(1, 1, 'a.js', 'a');
571 aNode.setSourceContent('a.js', 'someContent');
572 var node = new SourceNode(null, null, null,
575 ' ', new SourceNode(1, 1, 'b.js', 'b'),
577 node.setSourceContent('b.js', 'otherContent');
578 var map = node.toStringWithSourceMap({
582 assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
583 map = new SourceMapConsumer(map.toString());
585 assert.equal(map.sources.length, 2);
586 assert.equal(map.sources[0], 'a.js');
587 assert.equal(map.sources[1], 'b.js');
588 assert.equal(map.sourcesContent.length, 2);
589 assert.equal(map.sourcesContent[0], 'someContent');
590 assert.equal(map.sourcesContent[1], 'otherContent');
593 exports['test walkSourceContents'] = function (assert, util) {
594 var aNode = new SourceNode(1, 1, 'a.js', 'a');
595 aNode.setSourceContent('a.js', 'someContent');
596 var node = new SourceNode(null, null, null,
599 ' ', new SourceNode(1, 1, 'b.js', 'b'),
601 node.setSourceContent('b.js', 'otherContent');
603 node.walkSourceContents(function (sourceFile, sourceContent) {
604 results.push([sourceFile, sourceContent]);
606 assert.equal(results.length, 2);
607 assert.equal(results[0][0], 'a.js');
608 assert.equal(results[0][1], 'someContent');
609 assert.equal(results[1][0], 'b.js');
610 assert.equal(results[1][1], 'otherContent');