diff --git a/lib/source-map-url.js b/lib/source-map-url.js new file mode 100644 index 0000000..b1aa641 --- /dev/null +++ b/lib/source-map-url.js @@ -0,0 +1,47 @@ +// Copyright 2014 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) +// copied from https://github.com/lydell/source-map-url/blob/4106e5f0b001918790e3b830d2541252ba025a3d/source-map-url.js +// adapted to remove umd +/* eslint-disable no-var */ + +var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ + +var regex = RegExp( + "(?:" + + "/\\*" + + "(?:\\s*\r?\n(?://)?)?" + + "(?:" + innerRegex.source + ")" + + "\\s*" + + "\\*/" + + "|" + + "//(?:" + innerRegex.source + ")" + + ")" + + "\\s*" +) + +module.exports = { + regex: regex, + _innerRegex: innerRegex, + + getFrom: function(code) { + var match = code.match(regex) + return (match ? match[1] || match[2] || "" : null) + }, + + existsIn: function(code) { + return regex.test(code) + }, + + removeFrom: function(code) { + return code.replace(regex, "") + }, + + insertBefore: function(code, string) { + var match = code.match(regex) + if (match) { + return code.slice(0, match.index) + string + code.slice(match.index) + } else { + return code + string + } + } +} \ No newline at end of file diff --git a/lib/source-map.js b/lib/source-map.js index effd931..d5bc0fd 100644 --- a/lib/source-map.js +++ b/lib/source-map.js @@ -1,7 +1,7 @@ 'use strict'; const fs = require('fs-extra'); -const srcURL = require('source-map-url'); +const srcURL = require('./source-map-url'); const path = require('path'); const MemoryStreams = require('memory-streams'); const Coder = require('./coder'); diff --git a/package.json b/package.json index d56e9c2..d4a0434 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,7 @@ "heimdalljs-logger": "^0.1.9", "memory-streams": "^0.1.3", "mkdirp": "^0.5.0", - "@jacobq/source-map": "^1.1.0", - "source-map-url": "^0.3.0" + "@jacobq/source-map": "^1.1.0" }, "devDependencies": { "chai": "^4.1.2", diff --git a/test/source-map-url.js b/test/source-map-url.js new file mode 100644 index 0000000..f5b1ce0 --- /dev/null +++ b/test/source-map-url.js @@ -0,0 +1,405 @@ +// Copyright 2014 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) +// copied from https://github.com/lydell/source-map-url/blob/4106e5f0b001918790e3b830d2541252ba025a3d/test/source-map-url.js + +/* eslint-disable */ + +var { expect } = require('chai'); + +var sourceMappingURL = require("../lib/source-map-url") + +var comments = { + + universal: [ + "/*# sourceMappingURL=foo.js.map */" + ], + + js: [ + "//# sourceMappingURL=foo.js.map" + ], + + block: [ + "/*", + "# sourceMappingURL=foo.js.map", + "*/" + ], + + mix: [ + "/*", + "//# sourceMappingURL=foo.js.map", + "*/" + ] + +} + +var nonTrailingComments = { + + jsLeading: { + contents: [ + "//# sourceMappingURL=foo.js.map", + "(function(){})" + ], + solution: [ + "(function(){})" + ] + }, + + mixEmbedded: { + contents: [ + "/*! Library Name v1.0.0", + "//# sourceMappingURL=foo.js.map", + "*/", + "(function(){})" + ], + solution: [ + "/*! Library Name v1.0.0", + "*/", + "(function(){})" + ] + } + +} + +function forEachComment(fn) { + forOf(comments, function(name, comment) { + var description = "the '" + name + "' syntax with " + fn(comment.join("\n"), description + "regular newlines") + fn(comment.join("\r\n"), description + "Windows newlines") + }) +} + +function forEachNonTrailingComment(fn) { + forOf(nonTrailingComments, function(name, comment) { + + var description = "the '" + name + "' syntax with " + + fn({ + contents: comment.contents.join("\n"), + solution: comment.solution.join("\n") + }, description + "regular newlines") + + fn({ + contents: comment.contents.join("\r\n"), + solution: comment.solution.join("\r\n") + }, description + "Windows newlines") + }) +} + +function forOf(obj, fn) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + fn(key, obj[key]) + } + } +} + + +describe("sourceMappingURL", function() { + + describe(".getFrom", function() { + + forEachComment(function(comment, description) { + + it("gets the url from " + description, function() { + expect(sourceMappingURL.getFrom("code\n" + comment)) + .to.equal("foo.js.map") + + expect(sourceMappingURL.getFrom("code" + comment)) + .to.equal("foo.js.map") + + expect(sourceMappingURL.getFrom(comment)) + .to.equal("foo.js.map") + }) + + }) + + forEachNonTrailingComment(function(comment, description) { + + it("gets the url from " + description, function() { + expect(sourceMappingURL.getFrom("code\n" + comment.contents)) + .to.equal("foo.js.map") + + expect(sourceMappingURL.getFrom("code" + comment.contents)) + .to.equal("foo.js.map") + + expect(sourceMappingURL.getFrom(comment.contents)) + .to.equal("foo.js.map") + }) + + }) + + + it("returns null if no comment", function() { + expect(sourceMappingURL.getFrom("code")) + .to.equal(null) + }) + + + it("can return an empty string as url", function() { + expect(sourceMappingURL.getFrom("/*# sourceMappingURL= */")) + .to.equal("") + }) + + + it("is detachable", function() { + var get = sourceMappingURL.getFrom + expect(get("/*# sourceMappingURL=foo */")) + .to.equal("foo") + }) + + }) + + + describe(".existsIn", function() { + + forEachComment(function(comment, description) { + + it("returns true for " + description, function() { + expect(sourceMappingURL.existsIn("code\n" + comment)) + .to.equal(true) + + expect(sourceMappingURL.existsIn("code" + comment)) + .to.equal(true) + + expect(sourceMappingURL.existsIn(comment)) + .to.equal(true) + }) + + }) + + forEachNonTrailingComment(function(comment, description) { + + it("returns true for " + description, function() { + expect(sourceMappingURL.existsIn("code\n" + comment.contents)) + .to.equal(true) + + expect(sourceMappingURL.existsIn("code" + comment.contents)) + .to.equal(true) + + expect(sourceMappingURL.existsIn(comment.contents)) + .to.equal(true) + }) + + }) + + + it("returns false if no comment", function() { + expect(sourceMappingURL.existsIn("code")) + .to.equal(false) + }) + + + it("is detachable", function() { + var has = sourceMappingURL.existsIn + expect(has("/*# sourceMappingURL=foo */")) + .to.equal(true) + }) + + }) + + + describe(".removeFrom", function() { + + forEachComment(function(comment, description) { + + it("removes the comment for " + description, function() { + expect(sourceMappingURL.removeFrom("code\n" + comment)) + .to.equal("code\n") + + expect(sourceMappingURL.removeFrom("code" + comment)) + .to.equal("code") + + expect(sourceMappingURL.removeFrom(comment)) + .to.equal("") + }) + + }) + + forEachNonTrailingComment(function(comment, description) { + + it("removes the comment for " + description, function() { + expect(sourceMappingURL.removeFrom("code\n" + comment.contents)) + .to.equal("code\n" + comment.solution) + + expect(sourceMappingURL.removeFrom("code" + comment.contents)) + .to.equal("code" + comment.solution) + + expect(sourceMappingURL.removeFrom(comment.contents)) + .to.equal(comment.solution) + }) + + }) + + + it("does nothing if no comment", function() { + expect(sourceMappingURL.removeFrom("code\n")) + .to.equal("code\n") + }) + + + it("is detachable", function() { + var remove = sourceMappingURL.removeFrom + expect(remove("/*# sourceMappingURL=foo */")) + .to.equal("") + }) + + }) + + + describe(".insertBefore", function() { + + forEachComment(function(comment, description) { + + it("inserts a string before the comment for " + description, function() { + expect(sourceMappingURL.insertBefore("code\n" + comment, "more code\n")) + .to.equal("code\nmore code\n" + comment) + + expect(sourceMappingURL.insertBefore("code" + comment, "\nmore code")) + .to.equal("code\nmore code" + comment) + + expect(sourceMappingURL.insertBefore(comment, "some code")) + .to.equal("some code" + comment) + }) + + }) + + + it("inserts a string before an embedded comment", function() { + expect(sourceMappingURL.insertBefore("/*! Library Name v1.0.0\n" + + "//# sourceMappingURL=foo.js.map\n*/\n(function(){})", "code\n")) + .to.equal("/*! Library Name v1.0.0\ncode\n" + + "//# sourceMappingURL=foo.js.map\n*/\n(function(){})") + }) + + + it("inserts a string before a leading comment", function() { + expect(sourceMappingURL.insertBefore("//# sourceMappingURL=foo.js.map\n" + + "(function(){})", "code\n")) + .to.equal("code\n//# sourceMappingURL=foo.js.map\n" + + "(function(){})") + }) + + + it("appends if no comment", function() { + expect(sourceMappingURL.insertBefore("code", "\nmore code")) + .to.equal("code\nmore code") + }) + + + it("is detachable", function() { + var insertBefore = sourceMappingURL.insertBefore + expect(insertBefore("/*# sourceMappingURL=foo */", "bar")) + .to.equal("bar/*# sourceMappingURL=foo */") + }) + + }) + + + describe(".regex", function() { + + it("includes ._innerRegex", function() { + expect(sourceMappingURL.regex.source) + .to.contain(sourceMappingURL._innerRegex.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) { + + it("matches " + description, function() { + match("code\n" + comment) + match("code" + comment) + match(comment) + }) + + + it("matches " + description + ", with trailing whitespace", function() { + match(comment + " ") + match(comment + "\n") + match(comment + "\n\n\t\n \t ") + }) + + }) + + + it("does not match some cases that are easy to mess up", function() { + noMatch( + "/* # sourceMappingURL=foo */" + ) + + 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) + }) + + }) + +}) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1e123e9..6f83657 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1103,11 +1103,6 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" -source-map-url@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz" - integrity sha1-fsrxO1e80J2opAxdJp2zN5nUqvk= - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"