source-map-resolve.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. // Copyright 2014 Simon Lydell
  2. // X11 (“MIT”) Licensed. (See LICENSE.)
  3. var test = require("tape")
  4. var asyncify = require("simple-asyncify")
  5. var common = require("./common")
  6. var u = common.u
  7. var read = common.read
  8. var Throws = common.Throws
  9. var identity = common.identity
  10. var sourceMapResolve = require("../")
  11. // Polyfills.
  12. require("setimmediate")
  13. if (typeof window !== "undefined" && !window.atob) {
  14. window.atob = require("Base64").atob
  15. }
  16. "use strict"
  17. var map = {
  18. simple: {
  19. mappings: "AAAA",
  20. sources: ["foo.js"],
  21. names: []
  22. },
  23. sourceRoot: {
  24. mappings: "AAAA",
  25. sourceRoot: "/static/js/app/",
  26. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  27. names: []
  28. },
  29. sourceRootNoSlash: {
  30. mappings: "AAAA",
  31. sourceRoot: "/static/js/app",
  32. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  33. names: []
  34. },
  35. sourcesContent: {
  36. mappings: "AAAA",
  37. sourceRoot: "/static/js/app/",
  38. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  39. sourcesContent: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  40. names: []
  41. },
  42. mixed: {
  43. mappings: "AAAA",
  44. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  45. sourcesContent: ["foo.js", null , null , "/version.js", "//foo.org/baz.js"],
  46. names: []
  47. }
  48. }
  49. map.simpleString = JSON.stringify(map.simple)
  50. map.XSSIsafe = ")]}'" + map.simpleString
  51. var code = {
  52. fileRelative: u("foo.js.map"),
  53. domainRelative: u("/foo.js.map"),
  54. schemeRelative: u("//foo.org/foo.js.map"),
  55. absolute: u("https://foo.org/foo.js.map"),
  56. dataUri: u("data:application/json," +
  57. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  58. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  59. base64: u("data:application/json;base64," +
  60. "eyJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W119"),
  61. dataUriText: u("data:text/json," +
  62. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  63. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  64. dataUriParameter: u("data:application/json;charset=UTF-8;foo=bar," +
  65. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  66. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  67. dataUriNoMime: u("data:,foo"),
  68. dataUriInvalidMime: u("data:text/html,foo"),
  69. dataUriInvalidJSON: u("data:application/json,foo"),
  70. dataUriXSSIsafe: u("data:application/json," + ")%5D%7D%27" +
  71. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  72. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  73. dataUriEmpty: u("data:"),
  74. noMap: ""
  75. }
  76. function testResolveSourceMap(method, sync) {
  77. return function(t) {
  78. var wrap = (sync ? identity : asyncify)
  79. var codeUrl = "http://example.com/a/b/c/foo.js"
  80. t.plan(1 + 18*3)
  81. t.equal(typeof method, "function", "is a function")
  82. if (sync) {
  83. method = asyncify(method)
  84. }
  85. var next = false
  86. function isAsync() { t.ok(next, "is async") }
  87. method(code.fileRelative, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  88. t.error(error)
  89. t.deepEqual(result, {
  90. sourceMappingURL: "foo.js.map",
  91. url: "http://example.com/a/b/c/foo.js.map",
  92. sourcesRelativeTo: "http://example.com/a/b/c/foo.js.map",
  93. map: map.simple
  94. }, "fileRelative")
  95. isAsync()
  96. })
  97. method(code.domainRelative, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  98. t.error(error)
  99. t.deepEqual(result, {
  100. sourceMappingURL: "/foo.js.map",
  101. url: "http://example.com/foo.js.map",
  102. sourcesRelativeTo: "http://example.com/foo.js.map",
  103. map: map.simple
  104. }, "domainRelative")
  105. isAsync()
  106. })
  107. method(code.schemeRelative, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  108. t.error(error)
  109. t.deepEqual(result, {
  110. sourceMappingURL: "//foo.org/foo.js.map",
  111. url: "http://foo.org/foo.js.map",
  112. sourcesRelativeTo: "http://foo.org/foo.js.map",
  113. map: map.simple
  114. }, "schemeRelative")
  115. isAsync()
  116. })
  117. method(code.absolute, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  118. t.error(error)
  119. t.deepEqual(result, {
  120. sourceMappingURL: "https://foo.org/foo.js.map",
  121. url: "https://foo.org/foo.js.map",
  122. sourcesRelativeTo: "https://foo.org/foo.js.map",
  123. map: map.simple
  124. }, "absolute")
  125. isAsync()
  126. })
  127. method(code.dataUri, codeUrl, wrap(Throws), function(error, result) {
  128. t.error(error)
  129. t.deepEqual(result, {
  130. sourceMappingURL: "data:application/json," +
  131. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  132. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  133. url: null,
  134. sourcesRelativeTo: codeUrl,
  135. map: map.simple
  136. }, "dataUri")
  137. isAsync()
  138. })
  139. method(code.base64, codeUrl, wrap(Throws), function(error, result) {
  140. t.error(error)
  141. t.deepEqual(result, {
  142. sourceMappingURL: "data:application/json;base64," +
  143. "eyJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W119",
  144. url: null,
  145. sourcesRelativeTo: codeUrl,
  146. map: map.simple
  147. }, "base64")
  148. isAsync()
  149. })
  150. method(code.dataUriText, codeUrl, wrap(Throws), function(error, result) {
  151. t.error(error)
  152. t.deepEqual(result, {
  153. sourceMappingURL: "data:text/json," +
  154. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  155. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  156. url: null,
  157. sourcesRelativeTo: codeUrl,
  158. map: map.simple
  159. }, "dataUriText")
  160. isAsync()
  161. })
  162. method(code.dataUriParameter, codeUrl, wrap(Throws), function(error, result) {
  163. t.error(error)
  164. t.deepEqual(result, {
  165. sourceMappingURL: "data:application/json;charset=UTF-8;foo=bar," +
  166. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  167. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  168. url: null,
  169. sourcesRelativeTo: codeUrl,
  170. map: map.simple
  171. }, "dataUriParameter")
  172. isAsync()
  173. })
  174. method(code.dataUriNoMime, codeUrl, wrap(Throws), function(error, result) {
  175. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriNoMime")
  176. t.notOk(result)
  177. isAsync()
  178. })
  179. method(code.dataUriInvalidMime, codeUrl, wrap(Throws), function(error, result) {
  180. t.ok(error.message.match(/mime type.+text\/html/), "dataUriInvalidMime")
  181. t.notOk(result)
  182. isAsync()
  183. })
  184. method(code.dataUriInvalidJSON, codeUrl, wrap(Throws), function(error, result) {
  185. t.ok(error instanceof SyntaxError && error.message !== "data:application/json,foo",
  186. "dataUriInvalidJSON")
  187. t.notOk(result)
  188. isAsync()
  189. })
  190. method(code.dataUriXSSIsafe, codeUrl, wrap(Throws), function(error, result) {
  191. t.error(error)
  192. t.deepEqual(result, {
  193. sourceMappingURL: "data:application/json," + ")%5D%7D%27" +
  194. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  195. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  196. url: null,
  197. sourcesRelativeTo: codeUrl,
  198. map: map.simple
  199. }, "dataUriXSSIsafe")
  200. isAsync()
  201. })
  202. method(code.dataUriEmpty, codeUrl, wrap(Throws), function(error, result) {
  203. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriEmpty")
  204. t.notOk(result)
  205. isAsync()
  206. })
  207. method(code.noMap, codeUrl, wrap(Throws), function(error, result) {
  208. t.error(error)
  209. t.equal(result, null, "noMap")
  210. isAsync()
  211. })
  212. method(code.absolute, codeUrl, wrap(read([map.simpleString])), function(error, result) {
  213. t.error(error)
  214. t.deepEqual(result, {
  215. sourceMappingURL: "https://foo.org/foo.js.map",
  216. url: "https://foo.org/foo.js.map",
  217. sourcesRelativeTo: "https://foo.org/foo.js.map",
  218. map: map.simple
  219. }, "read non-string")
  220. isAsync()
  221. })
  222. method(code.absolute, codeUrl, wrap(read("invalid JSON")), function(error, result) {
  223. t.ok(error instanceof SyntaxError, "read invalid JSON")
  224. t.notOk(result)
  225. isAsync()
  226. })
  227. method(code.absolute, codeUrl, wrap(read(map.XSSIsafe)), function(error, result) {
  228. t.error(error)
  229. t.deepEqual(result, {
  230. sourceMappingURL: "https://foo.org/foo.js.map",
  231. url: "https://foo.org/foo.js.map",
  232. sourcesRelativeTo: "https://foo.org/foo.js.map",
  233. map: map.simple
  234. }, "XSSIsafe map")
  235. isAsync()
  236. })
  237. method(code.absolute, codeUrl, wrap(Throws), function(error, result) {
  238. t.equal(error.message, "https://foo.org/foo.js.map", "read throws")
  239. t.notOk(result)
  240. isAsync()
  241. })
  242. next = true
  243. }
  244. }
  245. test(".resolveSourceMap", testResolveSourceMap(sourceMapResolve.resolveSourceMap, false))
  246. test(".resolveSourceMapSync", testResolveSourceMap(sourceMapResolve.resolveSourceMapSync, true))
  247. function testResolveSources(method, sync) {
  248. return function(t) {
  249. var wrap = (sync ? identity : asyncify)
  250. var mapUrl = "http://example.com/a/b/c/foo.js.map"
  251. t.plan(1 + 7*3 + 4)
  252. t.equal(typeof method, "function", "is a function")
  253. if (sync) {
  254. method = asyncify(method)
  255. }
  256. var next = false
  257. function isAsync() { t.ok(next, "is async") }
  258. var options
  259. method(map.simple, mapUrl, wrap(identity), function(error, result) {
  260. t.error(error)
  261. t.deepEqual(result, {
  262. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  263. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  264. }, "simple")
  265. isAsync()
  266. })
  267. method(map.sourceRoot, mapUrl, wrap(identity), function(error, result) {
  268. t.error(error)
  269. t.deepEqual(result, {
  270. sourcesResolved: [
  271. "http://example.com/static/js/app/foo.js",
  272. "http://example.com/static/js/app/lib/bar.js",
  273. "http://example.com/static/js/vendor/dom.js",
  274. "http://example.com/version.js",
  275. "http://foo.org/baz.js"
  276. ],
  277. sourcesContent: [
  278. "http://example.com/static/js/app/foo.js",
  279. "http://example.com/static/js/app/lib/bar.js",
  280. "http://example.com/static/js/vendor/dom.js",
  281. "http://example.com/version.js",
  282. "http://foo.org/baz.js"
  283. ]
  284. }, "sourceRoot")
  285. isAsync()
  286. })
  287. options = {ignoreSourceRoot: true}
  288. method(map.sourceRoot, mapUrl, wrap(identity), options, function(error, result) {
  289. t.error(error)
  290. t.deepEqual(result, {
  291. sourcesResolved: [
  292. "http://example.com/a/b/c/foo.js",
  293. "http://example.com/a/b/c/lib/bar.js",
  294. "http://example.com/a/b/vendor/dom.js",
  295. "http://example.com/version.js",
  296. "http://foo.org/baz.js"
  297. ],
  298. sourcesContent: [
  299. "http://example.com/a/b/c/foo.js",
  300. "http://example.com/a/b/c/lib/bar.js",
  301. "http://example.com/a/b/vendor/dom.js",
  302. "http://example.com/version.js",
  303. "http://foo.org/baz.js"
  304. ]
  305. }, "ignore sourceRoot")
  306. isAsync()
  307. })
  308. method(map.sourceRootNoSlash, mapUrl, wrap(identity), function(error, result) {
  309. t.error(error)
  310. t.deepEqual(result, {
  311. sourcesResolved: [
  312. "http://example.com/static/js/app/foo.js",
  313. "http://example.com/static/js/app/lib/bar.js",
  314. "http://example.com/static/js/vendor/dom.js",
  315. "http://example.com/version.js",
  316. "http://foo.org/baz.js"
  317. ],
  318. sourcesContent: [
  319. "http://example.com/static/js/app/foo.js",
  320. "http://example.com/static/js/app/lib/bar.js",
  321. "http://example.com/static/js/vendor/dom.js",
  322. "http://example.com/version.js",
  323. "http://foo.org/baz.js"
  324. ]
  325. }, "sourceRootNoSlash")
  326. isAsync()
  327. })
  328. method(map.sourcesContent, mapUrl, wrap(Throws), function(error, result) {
  329. t.error(error)
  330. t.deepEqual(result, {
  331. sourcesResolved: [
  332. "http://example.com/static/js/app/foo.js",
  333. "http://example.com/static/js/app/lib/bar.js",
  334. "http://example.com/static/js/vendor/dom.js",
  335. "http://example.com/version.js",
  336. "http://foo.org/baz.js"
  337. ],
  338. sourcesContent: [
  339. "foo.js",
  340. "lib/bar.js",
  341. "../vendor/dom.js",
  342. "/version.js",
  343. "//foo.org/baz.js"
  344. ]
  345. }, "sourcesContent")
  346. isAsync()
  347. })
  348. method(map.mixed, mapUrl, wrap(identity), function(error, result) {
  349. t.error(error)
  350. t.deepEqual(result, {
  351. sourcesResolved: [
  352. "http://example.com/a/b/c/foo.js",
  353. "http://example.com/a/b/c/lib/bar.js",
  354. "http://example.com/a/b/vendor/dom.js",
  355. "http://example.com/version.js",
  356. "http://foo.org/baz.js"
  357. ],
  358. sourcesContent: [
  359. "foo.js",
  360. "http://example.com/a/b/c/lib/bar.js",
  361. "http://example.com/a/b/vendor/dom.js",
  362. "/version.js",
  363. "//foo.org/baz.js"
  364. ]
  365. }, "mixed")
  366. isAsync()
  367. })
  368. method(map.simple, mapUrl, wrap(read(["non", "string"])), function(error, result) {
  369. t.error(error)
  370. t.deepEqual(result, {
  371. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  372. sourcesContent: ["non,string"]
  373. }, "read non-string")
  374. isAsync()
  375. })
  376. var calledBack = false
  377. method(map.mixed, mapUrl, wrap(Throws), function(error, result) {
  378. t.equal(calledBack, false)
  379. calledBack = true
  380. t.equal(error.message, "http://example.com/a/b/c/lib/bar.js", "read throws")
  381. t.notOk(result)
  382. isAsync()
  383. })
  384. next = true
  385. }
  386. }
  387. test(".resolveSources", testResolveSources(sourceMapResolve.resolveSources, false))
  388. test(".resolveSourcesSync", testResolveSources(sourceMapResolve.resolveSourcesSync, true))
  389. test(".resolveSourcesSync no read", function(t) {
  390. t.plan(1)
  391. var mapUrl = "http://example.com/a/b/c/foo.js.map"
  392. var result = sourceMapResolve.resolveSourcesSync(map.mixed, mapUrl, null)
  393. t.deepEqual(result, {
  394. sourcesResolved: [
  395. "http://example.com/a/b/c/foo.js",
  396. "http://example.com/a/b/c/lib/bar.js",
  397. "http://example.com/a/b/vendor/dom.js",
  398. "http://example.com/version.js",
  399. "http://foo.org/baz.js"
  400. ],
  401. sourcesContent: []
  402. })
  403. })
  404. function testResolve(method, sync) {
  405. return function(t) {
  406. var wrap = (sync ? identity : asyncify)
  407. var wrapMap = function(mapFn, fn) {
  408. return wrap(function(url) {
  409. if (/\.map$/.test(url)) {
  410. return mapFn(url)
  411. }
  412. return fn(url)
  413. })
  414. }
  415. var codeUrl = "http://example.com/a/b/c/foo.js"
  416. t.plan(1 + 18*3 + 7*4 + 4)
  417. t.equal(typeof method, "function", "is a function")
  418. if (sync) {
  419. method = asyncify(method)
  420. }
  421. var next = false
  422. function isAsync() { t.ok(next, "is async") }
  423. var readSimple = wrapMap(read(map.simpleString), identity)
  424. method(code.fileRelative, codeUrl, readSimple, function(error, result) {
  425. t.error(error)
  426. t.deepEqual(result, {
  427. sourceMappingURL: "foo.js.map",
  428. url: "http://example.com/a/b/c/foo.js.map",
  429. sourcesRelativeTo: "http://example.com/a/b/c/foo.js.map",
  430. map: map.simple,
  431. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  432. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  433. }, "fileRelative")
  434. isAsync()
  435. })
  436. method(code.domainRelative, codeUrl, readSimple, function(error, result) {
  437. t.error(error)
  438. t.deepEqual(result, {
  439. sourceMappingURL: "/foo.js.map",
  440. url: "http://example.com/foo.js.map",
  441. sourcesRelativeTo: "http://example.com/foo.js.map",
  442. map: map.simple,
  443. sourcesResolved: ["http://example.com/foo.js"],
  444. sourcesContent: ["http://example.com/foo.js"]
  445. }, "domainRelative")
  446. isAsync()
  447. })
  448. method(code.schemeRelative, codeUrl, readSimple, function(error, result) {
  449. t.error(error)
  450. t.deepEqual(result, {
  451. sourceMappingURL: "//foo.org/foo.js.map",
  452. url: "http://foo.org/foo.js.map",
  453. sourcesRelativeTo: "http://foo.org/foo.js.map",
  454. map: map.simple,
  455. sourcesResolved: ["http://foo.org/foo.js"],
  456. sourcesContent: ["http://foo.org/foo.js"]
  457. }, "schemeRelative")
  458. isAsync()
  459. })
  460. method(code.absolute, codeUrl, readSimple, function(error, result) {
  461. t.error(error)
  462. t.deepEqual(result, {
  463. sourceMappingURL: "https://foo.org/foo.js.map",
  464. url: "https://foo.org/foo.js.map",
  465. sourcesRelativeTo: "https://foo.org/foo.js.map",
  466. map: map.simple,
  467. sourcesResolved: ["https://foo.org/foo.js"],
  468. sourcesContent: ["https://foo.org/foo.js"]
  469. }, "absolute")
  470. isAsync()
  471. })
  472. method(code.dataUri, codeUrl, wrapMap(Throws, identity), function(error, result) {
  473. t.error(error)
  474. t.deepEqual(result, {
  475. sourceMappingURL: "data:application/json," +
  476. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  477. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  478. url: null,
  479. sourcesRelativeTo: codeUrl,
  480. map: map.simple,
  481. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  482. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  483. }, "dataUri")
  484. isAsync()
  485. })
  486. method(code.base64, codeUrl, wrapMap(Throws, identity), function(error, result) {
  487. t.error(error)
  488. t.deepEqual(result, {
  489. sourceMappingURL: "data:application/json;base64," +
  490. "eyJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W119",
  491. url: null,
  492. sourcesRelativeTo: codeUrl,
  493. map: map.simple,
  494. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  495. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  496. }, "base64")
  497. isAsync()
  498. })
  499. method(code.dataUriText, codeUrl, wrapMap(Throws, identity), function(error, result) {
  500. t.error(error)
  501. t.deepEqual(result, {
  502. sourceMappingURL: "data:text/json," +
  503. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  504. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  505. url: null,
  506. sourcesRelativeTo: codeUrl,
  507. map: map.simple,
  508. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  509. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  510. }, "dataUriText")
  511. isAsync()
  512. })
  513. method(code.dataUriParameter, codeUrl, wrapMap(Throws, identity), function(error, result) {
  514. t.error(error)
  515. t.deepEqual(result, {
  516. sourceMappingURL: "data:application/json;charset=UTF-8;foo=bar," +
  517. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  518. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  519. url: null,
  520. sourcesRelativeTo: codeUrl,
  521. map: map.simple,
  522. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  523. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  524. }, "dataUriParameter")
  525. isAsync()
  526. })
  527. method(code.dataUriNoMime, codeUrl, wrap(Throws), function(error, result) {
  528. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriNoMime")
  529. t.notOk(result)
  530. isAsync()
  531. })
  532. method(code.dataUriInvalidMime, codeUrl, wrap(Throws), function(error, result) {
  533. t.ok(error.message.match(/mime type.+text\/html/), "dataUriInvalidMime")
  534. t.notOk(result)
  535. isAsync()
  536. })
  537. method(code.dataUriInvalidJSON, codeUrl, wrap(Throws), function(error, result) {
  538. t.ok(error instanceof SyntaxError && error.message !== "data:application/json,foo",
  539. "dataUriInvalidJSON")
  540. t.notOk(result)
  541. isAsync()
  542. })
  543. method(code.dataUriXSSIsafe, codeUrl, wrapMap(Throws, identity), function(error, result) {
  544. t.error(error)
  545. t.deepEqual(result, {
  546. sourceMappingURL: "data:application/json," + ")%5D%7D%27" +
  547. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  548. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  549. url: null,
  550. sourcesRelativeTo: codeUrl,
  551. map: map.simple,
  552. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  553. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  554. }, "dataUriXSSIsafe")
  555. isAsync()
  556. })
  557. method(code.dataUriEmpty, codeUrl, wrap(Throws), function(error, result) {
  558. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriEmpty")
  559. t.notOk(result)
  560. isAsync()
  561. })
  562. method(code.noMap, codeUrl, wrap(Throws), function(error, result) {
  563. t.error(error)
  564. t.equal(result, null, "noMap")
  565. isAsync()
  566. })
  567. method(code.absolute, codeUrl, wrap(read([map.simpleString])), function(error, result) {
  568. t.error(error)
  569. t.deepEqual(result, {
  570. sourceMappingURL: "https://foo.org/foo.js.map",
  571. url: "https://foo.org/foo.js.map",
  572. sourcesRelativeTo: "https://foo.org/foo.js.map",
  573. map: map.simple,
  574. sourcesResolved: ["https://foo.org/foo.js"],
  575. sourcesContent: [map.simpleString]
  576. }, "read non-string")
  577. isAsync()
  578. })
  579. method(code.absolute, codeUrl, wrap(read("invalid JSON")), function(error, result) {
  580. t.ok(error instanceof SyntaxError, "read invalid JSON")
  581. t.notOk(result)
  582. isAsync()
  583. })
  584. method(code.absolute, codeUrl, wrapMap(read(map.XSSIsafe), identity), function(error, result) {
  585. t.error(error)
  586. t.deepEqual(result, {
  587. sourceMappingURL: "https://foo.org/foo.js.map",
  588. url: "https://foo.org/foo.js.map",
  589. sourcesRelativeTo: "https://foo.org/foo.js.map",
  590. map: map.simple,
  591. sourcesResolved: ["https://foo.org/foo.js"],
  592. sourcesContent: ["https://foo.org/foo.js"]
  593. }, "XSSIsafe map")
  594. isAsync()
  595. })
  596. method(code.absolute, codeUrl, wrap(Throws), function(error, result) {
  597. t.equal(error.message, "https://foo.org/foo.js.map", "read throws")
  598. t.notOk(result)
  599. isAsync()
  600. })
  601. function readMap(what) {
  602. return wrapMap(read(JSON.stringify(what)), identity)
  603. }
  604. var options
  605. method(code.fileRelative, codeUrl, readMap(map.simple), function(error, result) {
  606. t.error(error)
  607. t.deepEqual(result.sourcesResolved, ["http://example.com/a/b/c/foo.js"], "simple")
  608. t.deepEqual(result.sourcesContent, ["http://example.com/a/b/c/foo.js"], "simple")
  609. isAsync()
  610. })
  611. method(code.fileRelative, codeUrl, readMap(map.sourceRoot), function(error, result) {
  612. t.error(error)
  613. t.deepEqual(result.sourcesResolved, [
  614. "http://example.com/static/js/app/foo.js",
  615. "http://example.com/static/js/app/lib/bar.js",
  616. "http://example.com/static/js/vendor/dom.js",
  617. "http://example.com/version.js",
  618. "http://foo.org/baz.js"
  619. ], "sourceRoot")
  620. t.deepEqual(result.sourcesContent, [
  621. "http://example.com/static/js/app/foo.js",
  622. "http://example.com/static/js/app/lib/bar.js",
  623. "http://example.com/static/js/vendor/dom.js",
  624. "http://example.com/version.js",
  625. "http://foo.org/baz.js"
  626. ], "sourceRoot")
  627. isAsync()
  628. })
  629. options = {ignoreSourceRoot: true}
  630. method(code.fileRelative, codeUrl, readMap(map.sourceRoot), options, function(error, result) {
  631. t.error(error)
  632. t.deepEqual(result.sourcesResolved, [
  633. "http://example.com/a/b/c/foo.js",
  634. "http://example.com/a/b/c/lib/bar.js",
  635. "http://example.com/a/b/vendor/dom.js",
  636. "http://example.com/version.js",
  637. "http://foo.org/baz.js"
  638. ], "sourceRoot")
  639. t.deepEqual(result.sourcesContent, [
  640. "http://example.com/a/b/c/foo.js",
  641. "http://example.com/a/b/c/lib/bar.js",
  642. "http://example.com/a/b/vendor/dom.js",
  643. "http://example.com/version.js",
  644. "http://foo.org/baz.js"
  645. ], "ignore sourceRoot")
  646. isAsync()
  647. })
  648. method(code.fileRelative, codeUrl, readMap(map.sourceRootNoSlash), function(error, result) {
  649. t.error(error)
  650. t.deepEqual(result.sourcesResolved, [
  651. "http://example.com/static/js/app/foo.js",
  652. "http://example.com/static/js/app/lib/bar.js",
  653. "http://example.com/static/js/vendor/dom.js",
  654. "http://example.com/version.js",
  655. "http://foo.org/baz.js"
  656. ], "sourceRootNoSlash")
  657. t.deepEqual(result.sourcesContent, [
  658. "http://example.com/static/js/app/foo.js",
  659. "http://example.com/static/js/app/lib/bar.js",
  660. "http://example.com/static/js/vendor/dom.js",
  661. "http://example.com/version.js",
  662. "http://foo.org/baz.js"
  663. ], "sourceRootNoSlash")
  664. isAsync()
  665. })
  666. method(code.fileRelative, codeUrl, readMap(map.sourcesContent), function(error, result) {
  667. t.error(error)
  668. t.deepEqual(result.sourcesResolved, [
  669. "http://example.com/static/js/app/foo.js",
  670. "http://example.com/static/js/app/lib/bar.js",
  671. "http://example.com/static/js/vendor/dom.js",
  672. "http://example.com/version.js",
  673. "http://foo.org/baz.js"
  674. ], "sourcesContent")
  675. t.deepEqual(result.sourcesContent, [
  676. "foo.js",
  677. "lib/bar.js",
  678. "../vendor/dom.js",
  679. "/version.js",
  680. "//foo.org/baz.js"
  681. ], "sourcesContent")
  682. isAsync()
  683. })
  684. method(code.fileRelative, codeUrl, readMap(map.mixed), function(error, result) {
  685. t.error(error)
  686. t.deepEqual(result.sourcesResolved, [
  687. "http://example.com/a/b/c/foo.js",
  688. "http://example.com/a/b/c/lib/bar.js",
  689. "http://example.com/a/b/vendor/dom.js",
  690. "http://example.com/version.js",
  691. "http://foo.org/baz.js"
  692. ], "mixed")
  693. t.deepEqual(result.sourcesContent, [
  694. "foo.js",
  695. "http://example.com/a/b/c/lib/bar.js",
  696. "http://example.com/a/b/vendor/dom.js",
  697. "/version.js",
  698. "//foo.org/baz.js"
  699. ], "mixed")
  700. isAsync()
  701. })
  702. method(code.fileRelative, codeUrl, wrap(read([map.simpleString])), function(error, result) {
  703. t.error(error)
  704. t.deepEqual(result.sourcesResolved, ["http://example.com/a/b/c/foo.js"], "read non-string")
  705. t.deepEqual(result.sourcesContent, [map.simpleString], "read non-string")
  706. isAsync()
  707. })
  708. function ThrowsMap(what) {
  709. return wrapMap(read(JSON.stringify(what)), Throws)
  710. }
  711. var calledBack = false
  712. method(code.fileRelative, codeUrl, ThrowsMap(map.mixed), function(error, result) {
  713. t.equal(calledBack, false)
  714. calledBack = true
  715. t.equal(error.message, "http://example.com/a/b/c/lib/bar.js", "read throws")
  716. t.notOk(result)
  717. isAsync()
  718. })
  719. next = true
  720. }
  721. }
  722. test(".resolve", testResolve(sourceMapResolve.resolve, false))
  723. test(".resolveSync", testResolve(sourceMapResolve.resolveSync, true))