// Copyright 2014 Simon Lydell var expect = require("chai").expect var sourceMappingURL = require("../") var SourceMappingURL = sourceMappingURL.SourceMappingURL "use strict" var comments = { universal: [ "/*# sourceMappingURL=foo.js.map */" ], js: [ "//# sourceMappingURL=foo.js.map" ], block: [ "/*", "# sourceMappingURL=foo.js.map", "*/" ], mix: [ "/*", "//# sourceMappingURL=foo.js.map", "*/" ] } var newlines = {"\n": "\\n", "\r": "\\r", "\r\n": "\\r\\n"} function forEachNewLine(lines, fn) { forOf(newlines, function(newline) { fn(lines.join(newline), newline) }) } function forEachComment(fn) { forOf(comments, function(name, comment) { forEachNewLine(comment, function(comment, newline) { var description = "the '" + name + "' syntax with '" + newlines[newline] + "' newlines" fn(comment, description, newline) }) }) } function forOf(obj, fn) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { fn(key, obj[key]) } } } describe("sourceMappingURL", function() { it("is an instance of SourceMappingURL", function() { expect(sourceMappingURL) .to.be.an.instanceOf(SourceMappingURL) }) describe(".get", function() { forEachComment(function(comment, description, newline) { it("gets the url from " + description, function() { expect(sourceMappingURL.get("code" + newline + comment)) .to.equal("foo.js.map") }) it("gets the url from " + description + ", with no code", function() { expect(sourceMappingURL.get(comment)) .to.equal("foo.js.map") }) }) it("returns null if no comment", function() { expect(sourceMappingURL.get("code")) .to.equal(null) }) it("can return an empty string as url", function() { expect(sourceMappingURL.get("/*# sourceMappingURL= */")) .to.equal("") }) }) describe(".set", function() { forEachComment(function(comment, description, newline) { it("updates the comment for " + description, function() { expect(sourceMappingURL.set("code" + newline + comment, "/other/file.js.map")) .to.equal("code" + newline + "/*# sourceMappingURL=/other/file.js.map */") }) it("allows to change comment syntax for " + description, function() { expect(sourceMappingURL.set("code" + newline + comment, "bar", ["//", ""])) .to.equal("code" + newline + "//# sourceMappingURL=bar") expect(sourceMappingURL.set("code" + newline + comment, "bar", ["//"])) .to.equal("code" + newline + "//# sourceMappingURL=bar") expect(sourceMappingURL.set("code" + newline + comment, "bar", ["/*\n//", "\n*/\n"])) .to.equal("code" + newline + "/*\n//# sourceMappingURL=bar\n*/\n") }) }) it("tries to use the same newline as the rest of the code", function() { expect(sourceMappingURL.set("code\nmore code", "foo")) .to.eql("code\nmore code\n/*# sourceMappingURL=foo */") expect(sourceMappingURL.set("code\rmore code", "foo")) .to.eql("code\rmore code\r/*# sourceMappingURL=foo */") expect(sourceMappingURL.set("code\r\nmore code", "foo")) .to.eql("code\r\nmore code\r\n/*# sourceMappingURL=foo */") expect(sourceMappingURL.set("a\r\nb\rc\nd", "foo")) .to.eql("a\r\nb\rc\nd\r\n/*# sourceMappingURL=foo */") }) it("defaults to \\n if no newline", function() { expect(sourceMappingURL.set("code", "foo")) .to.equal("code\n/*# sourceMappingURL=foo */") }) it("always adds a newline", function() { expect(sourceMappingURL.set("", "foo")) .to.equal("\n/*# sourceMappingURL=foo */") expect(sourceMappingURL.set("code\n", "foo")) .to.equal("code\n\n/*# sourceMappingURL=foo */") }) it("adds a comment if no comment", function() { expect(sourceMappingURL.set("code\n", "/other/file.js.map")) .to.equal("code\n\n/*# sourceMappingURL=/other/file.js.map */") }) it("obeys a changed default comment syntax", function() { expect(new SourceMappingURL(["Open", "Close"]).set("code\n", "foo")) .to.eql("code\n\nOpen# sourceMappingURL=fooClose") }) }) describe(".remove", function() { forEachComment(function(comment, description, newline) { it("removes the comment for " + description, function() { expect(sourceMappingURL.remove("code" + newline + comment)) .to.equal("code") }) it("removes the comment for " + description + ", with no code", function() { expect(sourceMappingURL.remove(comment)) .to.equal("") }) }) it("does nothing if no comment", function() { expect(sourceMappingURL.remove("code\n")) .to.equal("code\n") }) }) describe(".insertBefore", function() { forEachComment(function(comment, description, newline) { it("inserts a string before the comment for " + description, function() { expect(sourceMappingURL.insertBefore("code" + newline + comment, newline + "more code")) .to.equal("code" + newline + "more code" + newline + comment) expect(sourceMappingURL.insertBefore(comment, "some code")) .to.equal("some code\n" + comment) }) }) it("appends if no comment", function() { expect(sourceMappingURL.insertBefore("code", "\nmore code")) .to.equal("code\nmore code") }) }) describe(".regex", function() { it("includes ._innerRegex", function() { expect(sourceMappingURL.regex.source) .to.contain(sourceMappingURL._innerRegex.source) }) it("includes ._newlineRegex", function() { expect(sourceMappingURL.regex.source) .to.contain(sourceMappingURL._newlineRegex.source) }) var match = function(code) { expect(code) .to.match(sourceMappingURL.regex) } var noMatch = function(code) { expect(code) .not.to.match(sourceMappingURL.regex) } forEachComment(function(comment, description, newline) { it("matches " + description + ", even with trailing whitespace", function() { match("code" + newline + comment) }) it("matches " + description + ", with no code", function() { match(comment) }) it("matches " + description + ", with trailing whitespace", function() { match(comment + " ") match(comment + newline) match(comment + newline + newline + "\t" + newline + " \t ") }) it("only matches " + description + " at the end of files", function() { noMatch("code" + newline + comment + " code") noMatch("code" + newline + comment + newline + "code") noMatch("code" + newline + comment + newline + "// Generated by foobar") noMatch("alert('\\" + newline + comment + "')") noMatch('alert("\\' + newline + comment + '")') }) }) it("does not match some cases that are easy to mess up", function() { noMatch( "/* # sourceMappingURL=foo */" ) noMatch( "/*\n" + " //# sourceMappingURL=foo\n" + "*/" ) noMatch( "/*//# sourceMappingURL=foo\n" + "*/" ) noMatch( "// # sourceMappingURL=foo" ) }) it("is liberal regarding inner whitespace", function() { match( "/*# sourceMappingURL=foo*/" ) match( "/*# sourceMappingURL=foo */" ) match( "/*# sourceMappingURL=foo \t\n" + "*/" ) match( "/* \n" + "# sourceMappingURL=foo\n" + "*/" ) match( "/*\n" + "# sourceMappingURL=foo\n" + " */" ) match( "/*\n" + "# sourceMappingURL=foo\n" + "\n" + "\t\n" + "*/" ) }) }) describe("._innerRegex", function() { it("matches the contents of sourceMappingURL comments", function() { expect("# sourceMappingURL=http://www.example.com/foo/bar.js.map") .to.match(sourceMappingURL._innerRegex) }) it("captures the url in the first capture group", function() { expect(sourceMappingURL._innerRegex.exec("# sourceMappingURL=foo")[1]) .to.equal("foo") }) it("supports the legacy syntax", function() { expect("@ sourceMappingURL=http://www.example.com/foo/bar.js.map") .to.match(sourceMappingURL._innerRegex) }) }) describe("._newlineRegex", function() { var match = function(string) { var newline = string.match(sourceMappingURL._newlineRegex) expect(newline).to.be.ok expect(newline[0]).to.equal(string) } it("matches \\n", function() { match("\n") }) it("matches \\r", function() { match("\r") }) it("matches \\r\\n", function() { match("\r\n") }) }) describe("._commentSyntax", function() { it("defaults to /**/ comments", function() { expect(sourceMappingURL._commentSyntax) .to.eql(["/*", " */"]) }) }) describe(".SourceMappingURL", function() { it("sets ._commentSyntax", function() { expect(new SourceMappingURL(["//", ""])._commentSyntax) .to.eql(["//", ""]) }) it("creates an equivalent sourceMappingURL object", function() { expect(new SourceMappingURL(sourceMappingURL._commentSyntax)) .to.eql(sourceMappingURL) }) }) })