You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1162 lines
40 KiB

4 years ago
  1. // Copyright 2014, 2015, 2016, 2017 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. sourceRootEmpty: {
  36. mappings: "AAAA",
  37. sourceRoot: "",
  38. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  39. names: []
  40. },
  41. sourcesContent: {
  42. mappings: "AAAA",
  43. sourceRoot: "/static/js/app/",
  44. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  45. sourcesContent: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  46. names: []
  47. },
  48. mixed: {
  49. mappings: "AAAA",
  50. sources: ["foo.js", "lib/bar.js", "../vendor/dom.js", "/version.js", "//foo.org/baz.js"],
  51. sourcesContent: ["foo.js", null , null , "/version.js", "//foo.org/baz.js"],
  52. names: []
  53. },
  54. noSources: {
  55. mappings: "",
  56. sources: [],
  57. names: []
  58. },
  59. empty: {}
  60. }
  61. map.simpleString = JSON.stringify(map.simple)
  62. map.XSSIsafe = ")]}'" + map.simpleString
  63. var code = {
  64. fileRelative: u("foo.js.map"),
  65. domainRelative: u("/foo.js.map"),
  66. schemeRelative: u("//foo.org/foo.js.map"),
  67. absolute: u("https://foo.org/foo.js.map"),
  68. dataUri: u("data:application/json," +
  69. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  70. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  71. base64: u("data:application/json;base64," +
  72. "eyJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W119"),
  73. dataUriText: u("data:text/json," +
  74. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  75. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  76. dataUriParameter: u("data:application/json;charset=UTF-8;foo=bar," +
  77. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  78. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  79. dataUriNoMime: u("data:,foo"),
  80. dataUriInvalidMime: u("data:text/html,foo"),
  81. dataUriInvalidJSON: u("data:application/json,foo"),
  82. dataUriXSSIsafe: u("data:application/json," + ")%5D%7D%27" +
  83. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  84. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D"),
  85. dataUriEmpty: u("data:"),
  86. noMap: ""
  87. }
  88. function testResolveSourceMap(method, sync) {
  89. return function(t) {
  90. var wrap = (sync ? identity : asyncify)
  91. var codeUrl = "http://example.com/a/b/c/foo.js"
  92. t.plan(1 + 12*3 + 6*4)
  93. t.equal(typeof method, "function", "is a function")
  94. if (sync) {
  95. method = asyncify(method)
  96. }
  97. var next = false
  98. function isAsync() { t.ok(next, "is async") }
  99. method(code.fileRelative, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  100. t.error(error)
  101. t.deepEqual(result, {
  102. sourceMappingURL: "foo.js.map",
  103. url: "http://example.com/a/b/c/foo.js.map",
  104. sourcesRelativeTo: "http://example.com/a/b/c/foo.js.map",
  105. map: map.simple
  106. }, "fileRelative")
  107. isAsync()
  108. })
  109. method(code.domainRelative, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  110. t.error(error)
  111. t.deepEqual(result, {
  112. sourceMappingURL: "/foo.js.map",
  113. url: "http://example.com/foo.js.map",
  114. sourcesRelativeTo: "http://example.com/foo.js.map",
  115. map: map.simple
  116. }, "domainRelative")
  117. isAsync()
  118. })
  119. method(code.schemeRelative, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  120. t.error(error)
  121. t.deepEqual(result, {
  122. sourceMappingURL: "//foo.org/foo.js.map",
  123. url: "http://foo.org/foo.js.map",
  124. sourcesRelativeTo: "http://foo.org/foo.js.map",
  125. map: map.simple
  126. }, "schemeRelative")
  127. isAsync()
  128. })
  129. method(code.absolute, codeUrl, wrap(read(map.simpleString)), function(error, result) {
  130. t.error(error)
  131. t.deepEqual(result, {
  132. sourceMappingURL: "https://foo.org/foo.js.map",
  133. url: "https://foo.org/foo.js.map",
  134. sourcesRelativeTo: "https://foo.org/foo.js.map",
  135. map: map.simple
  136. }, "absolute")
  137. isAsync()
  138. })
  139. method(code.dataUri, codeUrl, wrap(Throws), function(error, result) {
  140. t.error(error)
  141. t.deepEqual(result, {
  142. sourceMappingURL: "data:application/json," +
  143. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  144. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  145. url: null,
  146. sourcesRelativeTo: codeUrl,
  147. map: map.simple
  148. }, "dataUri")
  149. isAsync()
  150. })
  151. method(code.base64, codeUrl, wrap(Throws), function(error, result) {
  152. t.error(error)
  153. t.deepEqual(result, {
  154. sourceMappingURL: "data:application/json;base64," +
  155. "eyJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W119",
  156. url: null,
  157. sourcesRelativeTo: codeUrl,
  158. map: map.simple
  159. }, "base64")
  160. isAsync()
  161. })
  162. method(code.dataUriText, codeUrl, wrap(Throws), function(error, result) {
  163. t.error(error)
  164. t.deepEqual(result, {
  165. sourceMappingURL: "data:text/json," +
  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. }, "dataUriText")
  172. isAsync()
  173. })
  174. method(code.dataUriParameter, codeUrl, wrap(Throws), function(error, result) {
  175. t.error(error)
  176. t.deepEqual(result, {
  177. sourceMappingURL: "data:application/json;charset=UTF-8;foo=bar," +
  178. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  179. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  180. url: null,
  181. sourcesRelativeTo: codeUrl,
  182. map: map.simple
  183. }, "dataUriParameter")
  184. isAsync()
  185. })
  186. method(code.dataUriNoMime, codeUrl, wrap(Throws), function(error, result) {
  187. t.deepEqual(error.sourceMapData, {
  188. sourceMappingURL: "data:,foo",
  189. url: null,
  190. sourcesRelativeTo: codeUrl,
  191. map: "foo"
  192. }, "dataUriNoMime .sourceMapData")
  193. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriNoMime")
  194. t.notOk(result)
  195. isAsync()
  196. })
  197. method(code.dataUriInvalidMime, codeUrl, wrap(Throws), function(error, result) {
  198. t.deepEqual(error.sourceMapData, {
  199. sourceMappingURL: "data:text/html,foo",
  200. url: null,
  201. sourcesRelativeTo: codeUrl,
  202. map: "foo"
  203. }, "dataUriInvalidMime .sourceMapData")
  204. t.ok(error.message.match(/mime type.+text\/html/), "dataUriInvalidMime")
  205. t.notOk(result)
  206. isAsync()
  207. })
  208. method(code.dataUriInvalidJSON, codeUrl, wrap(Throws), function(error, result) {
  209. t.deepEqual(error.sourceMapData, {
  210. sourceMappingURL: "data:application/json,foo",
  211. url: null,
  212. sourcesRelativeTo: codeUrl,
  213. map: "foo"
  214. }, "dataUriInvalidJSON .sourceMapData")
  215. t.ok(error instanceof SyntaxError && error.message !== "data:application/json,foo",
  216. "dataUriInvalidJSON")
  217. t.notOk(result)
  218. isAsync()
  219. })
  220. method(code.dataUriXSSIsafe, codeUrl, wrap(Throws), function(error, result) {
  221. t.error(error)
  222. t.deepEqual(result, {
  223. sourceMappingURL: "data:application/json," + ")%5D%7D%27" +
  224. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  225. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  226. url: null,
  227. sourcesRelativeTo: codeUrl,
  228. map: map.simple
  229. }, "dataUriXSSIsafe")
  230. isAsync()
  231. })
  232. method(code.dataUriEmpty, codeUrl, wrap(Throws), function(error, result) {
  233. t.deepEqual(error.sourceMapData, {
  234. sourceMappingURL: "data:",
  235. url: null,
  236. sourcesRelativeTo: codeUrl,
  237. map: ""
  238. }, "dataUriEmpty .sourceMapData")
  239. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriEmpty")
  240. t.notOk(result)
  241. isAsync()
  242. })
  243. method(code.noMap, codeUrl, wrap(Throws), function(error, result) {
  244. t.error(error)
  245. t.equal(result, null, "noMap")
  246. isAsync()
  247. })
  248. method(code.absolute, codeUrl, wrap(read([map.simpleString])), function(error, result) {
  249. t.error(error)
  250. t.deepEqual(result, {
  251. sourceMappingURL: "https://foo.org/foo.js.map",
  252. url: "https://foo.org/foo.js.map",
  253. sourcesRelativeTo: "https://foo.org/foo.js.map",
  254. map: map.simple
  255. }, "read non-string")
  256. isAsync()
  257. })
  258. method(code.absolute, codeUrl, wrap(read("invalid JSON")), function(error, result) {
  259. t.deepEqual(error.sourceMapData, {
  260. sourceMappingURL: "https://foo.org/foo.js.map",
  261. url: "https://foo.org/foo.js.map",
  262. sourcesRelativeTo: "https://foo.org/foo.js.map",
  263. map: "invalid JSON"
  264. }, "read invalid JSON .sourceMapData")
  265. t.ok(error instanceof SyntaxError, "read invalid JSON")
  266. t.notOk(result)
  267. isAsync()
  268. })
  269. method(code.absolute, codeUrl, wrap(read(map.XSSIsafe)), function(error, result) {
  270. t.error(error)
  271. t.deepEqual(result, {
  272. sourceMappingURL: "https://foo.org/foo.js.map",
  273. url: "https://foo.org/foo.js.map",
  274. sourcesRelativeTo: "https://foo.org/foo.js.map",
  275. map: map.simple
  276. }, "XSSIsafe map")
  277. isAsync()
  278. })
  279. method(code.absolute, codeUrl, wrap(Throws), function(error, result) {
  280. t.deepEqual(error.sourceMapData, {
  281. sourceMappingURL: "https://foo.org/foo.js.map",
  282. url: "https://foo.org/foo.js.map",
  283. sourcesRelativeTo: "https://foo.org/foo.js.map",
  284. map: null
  285. }, "read throws .sourceMapData")
  286. t.equal(error.message, "https://foo.org/foo.js.map", "read throws")
  287. t.notOk(result)
  288. isAsync()
  289. })
  290. next = true
  291. }
  292. }
  293. test(".resolveSourceMap", testResolveSourceMap(sourceMapResolve.resolveSourceMap, false))
  294. test(".resolveSourceMapSync", testResolveSourceMap(sourceMapResolve.resolveSourceMapSync, true))
  295. function testResolveSources(method, sync) {
  296. return function(t) {
  297. var wrap = (sync ? identity : asyncify)
  298. var mapUrl = "http://example.com/a/b/c/foo.js.map"
  299. t.plan(1 + 11*3 + 4)
  300. t.equal(typeof method, "function", "is a function")
  301. if (sync) {
  302. method = asyncify(method)
  303. }
  304. var next = false
  305. function isAsync() { t.ok(next, "is async") }
  306. var options
  307. method(map.simple, mapUrl, wrap(identity), function(error, result) {
  308. t.error(error)
  309. t.deepEqual(result, {
  310. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  311. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  312. }, "simple")
  313. isAsync()
  314. })
  315. method(map.sourceRoot, mapUrl, wrap(identity), function(error, result) {
  316. t.error(error)
  317. t.deepEqual(result, {
  318. sourcesResolved: [
  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. sourcesContent: [
  326. "http://example.com/static/js/app/foo.js",
  327. "http://example.com/static/js/app/lib/bar.js",
  328. "http://example.com/static/js/vendor/dom.js",
  329. "http://example.com/version.js",
  330. "http://foo.org/baz.js"
  331. ]
  332. }, "sourceRoot")
  333. isAsync()
  334. })
  335. options = {sourceRoot: false}
  336. method(map.sourceRoot, mapUrl, wrap(identity), options, function(error, result) {
  337. t.error(error)
  338. t.deepEqual(result, {
  339. sourcesResolved: [
  340. "http://example.com/a/b/c/foo.js",
  341. "http://example.com/a/b/c/lib/bar.js",
  342. "http://example.com/a/b/vendor/dom.js",
  343. "http://example.com/version.js",
  344. "http://foo.org/baz.js"
  345. ],
  346. sourcesContent: [
  347. "http://example.com/a/b/c/foo.js",
  348. "http://example.com/a/b/c/lib/bar.js",
  349. "http://example.com/a/b/vendor/dom.js",
  350. "http://example.com/version.js",
  351. "http://foo.org/baz.js"
  352. ]
  353. }, "ignore sourceRoot")
  354. isAsync()
  355. })
  356. options = {sourceRoot: "/static/js/"}
  357. method(map.sourceRoot, mapUrl, wrap(identity), options, function(error, result) {
  358. t.error(error)
  359. t.deepEqual(result, {
  360. sourcesResolved: [
  361. "http://example.com/static/js/foo.js",
  362. "http://example.com/static/js/lib/bar.js",
  363. "http://example.com/static/vendor/dom.js",
  364. "http://example.com/version.js",
  365. "http://foo.org/baz.js"
  366. ],
  367. sourcesContent: [
  368. "http://example.com/static/js/foo.js",
  369. "http://example.com/static/js/lib/bar.js",
  370. "http://example.com/static/vendor/dom.js",
  371. "http://example.com/version.js",
  372. "http://foo.org/baz.js"
  373. ]
  374. }, "custom sourceRoot")
  375. isAsync()
  376. })
  377. method(map.sourceRootNoSlash, mapUrl, wrap(identity), function(error, result) {
  378. t.error(error)
  379. t.deepEqual(result, {
  380. sourcesResolved: [
  381. "http://example.com/static/js/app/foo.js",
  382. "http://example.com/static/js/app/lib/bar.js",
  383. "http://example.com/static/js/vendor/dom.js",
  384. "http://example.com/version.js",
  385. "http://foo.org/baz.js"
  386. ],
  387. sourcesContent: [
  388. "http://example.com/static/js/app/foo.js",
  389. "http://example.com/static/js/app/lib/bar.js",
  390. "http://example.com/static/js/vendor/dom.js",
  391. "http://example.com/version.js",
  392. "http://foo.org/baz.js"
  393. ]
  394. }, "sourceRootNoSlash")
  395. isAsync()
  396. })
  397. method(map.sourceRootEmpty, mapUrl, wrap(identity), function(error, result) {
  398. t.error(error)
  399. t.deepEqual(result, {
  400. sourcesResolved: [
  401. "http://example.com/a/b/c/foo.js",
  402. "http://example.com/a/b/c/lib/bar.js",
  403. "http://example.com/a/b/vendor/dom.js",
  404. "http://example.com/version.js",
  405. "http://foo.org/baz.js"
  406. ],
  407. sourcesContent: [
  408. "http://example.com/a/b/c/foo.js",
  409. "http://example.com/a/b/c/lib/bar.js",
  410. "http://example.com/a/b/vendor/dom.js",
  411. "http://example.com/version.js",
  412. "http://foo.org/baz.js"
  413. ]
  414. }, "sourceRootEmpty")
  415. isAsync()
  416. })
  417. method(map.sourcesContent, mapUrl, wrap(Throws), function(error, result) {
  418. t.error(error)
  419. t.deepEqual(result, {
  420. sourcesResolved: [
  421. "http://example.com/static/js/app/foo.js",
  422. "http://example.com/static/js/app/lib/bar.js",
  423. "http://example.com/static/js/vendor/dom.js",
  424. "http://example.com/version.js",
  425. "http://foo.org/baz.js"
  426. ],
  427. sourcesContent: [
  428. "foo.js",
  429. "lib/bar.js",
  430. "../vendor/dom.js",
  431. "/version.js",
  432. "//foo.org/baz.js"
  433. ]
  434. }, "sourcesContent")
  435. isAsync()
  436. })
  437. method(map.mixed, mapUrl, wrap(identity), function(error, result) {
  438. t.error(error)
  439. t.deepEqual(result, {
  440. sourcesResolved: [
  441. "http://example.com/a/b/c/foo.js",
  442. "http://example.com/a/b/c/lib/bar.js",
  443. "http://example.com/a/b/vendor/dom.js",
  444. "http://example.com/version.js",
  445. "http://foo.org/baz.js"
  446. ],
  447. sourcesContent: [
  448. "foo.js",
  449. "http://example.com/a/b/c/lib/bar.js",
  450. "http://example.com/a/b/vendor/dom.js",
  451. "/version.js",
  452. "//foo.org/baz.js"
  453. ]
  454. }, "mixed")
  455. isAsync()
  456. })
  457. method(map.noSources, mapUrl, wrap(identity), function(error, result) {
  458. t.error(error)
  459. t.deepEqual(result, {
  460. sourcesResolved: [],
  461. sourcesContent: []
  462. }, "noSources")
  463. isAsync()
  464. })
  465. method(map.empty, mapUrl, wrap(identity), function(error, result) {
  466. t.error(error)
  467. t.deepEqual(result, {
  468. sourcesResolved: [],
  469. sourcesContent: []
  470. }, "empty")
  471. isAsync()
  472. })
  473. method(map.simple, mapUrl, wrap(read(["non", "string"])), function(error, result) {
  474. t.error(error)
  475. t.deepEqual(result, {
  476. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  477. sourcesContent: ["non,string"]
  478. }, "read non-string")
  479. isAsync()
  480. })
  481. method(map.mixed, mapUrl, wrap(Throws), function(error, result) {
  482. t.error(error)
  483. t.deepEqual(result.sourcesResolved, [
  484. "http://example.com/a/b/c/foo.js",
  485. "http://example.com/a/b/c/lib/bar.js",
  486. "http://example.com/a/b/vendor/dom.js",
  487. "http://example.com/version.js",
  488. "http://foo.org/baz.js"
  489. ], "read throws .sourcesResolved")
  490. var sourcesContent = result.sourcesContent
  491. for (var index = 0, len = sourcesContent.length; index < len; index++) {
  492. var item = sourcesContent[index]
  493. if (item instanceof Error) {
  494. sourcesContent[index] = null
  495. }
  496. }
  497. t.deepEqual(sourcesContent, [
  498. "foo.js",
  499. null,
  500. null,
  501. "/version.js",
  502. "//foo.org/baz.js"
  503. ], "read throws .sourcesContent")
  504. isAsync()
  505. })
  506. next = true
  507. }
  508. }
  509. test(".resolveSources", testResolveSources(sourceMapResolve.resolveSources, false))
  510. test(".resolveSourcesSync", testResolveSources(sourceMapResolve.resolveSourcesSync, true))
  511. test(".resolveSourcesSync no read", function(t) {
  512. t.plan(1)
  513. var mapUrl = "http://example.com/a/b/c/foo.js.map"
  514. var result = sourceMapResolve.resolveSourcesSync(map.mixed, mapUrl, null)
  515. t.deepEqual(result, {
  516. sourcesResolved: [
  517. "http://example.com/a/b/c/foo.js",
  518. "http://example.com/a/b/c/lib/bar.js",
  519. "http://example.com/a/b/vendor/dom.js",
  520. "http://example.com/version.js",
  521. "http://foo.org/baz.js"
  522. ],
  523. sourcesContent: []
  524. })
  525. })
  526. function testResolve(method, sync) {
  527. return function(t) {
  528. var wrap = (sync ? identity : asyncify)
  529. var wrapMap = function(mapFn, fn) {
  530. return wrap(function(url) {
  531. if (/\.map$/.test(url)) {
  532. return mapFn(url)
  533. }
  534. return fn(url)
  535. })
  536. }
  537. var codeUrl = "http://example.com/a/b/c/foo.js"
  538. t.plan(1 + 15*3 + 21*4 + 4)
  539. t.equal(typeof method, "function", "is a function")
  540. if (sync) {
  541. method = asyncify(method)
  542. }
  543. var next = false
  544. function isAsync() { t.ok(next, "is async") }
  545. var readSimple = wrapMap(read(map.simpleString), identity)
  546. method(code.fileRelative, codeUrl, readSimple, function(error, result) {
  547. t.error(error)
  548. t.deepEqual(result, {
  549. sourceMappingURL: "foo.js.map",
  550. url: "http://example.com/a/b/c/foo.js.map",
  551. sourcesRelativeTo: "http://example.com/a/b/c/foo.js.map",
  552. map: map.simple,
  553. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  554. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  555. }, "fileRelative")
  556. isAsync()
  557. })
  558. method(code.domainRelative, codeUrl, readSimple, function(error, result) {
  559. t.error(error)
  560. t.deepEqual(result, {
  561. sourceMappingURL: "/foo.js.map",
  562. url: "http://example.com/foo.js.map",
  563. sourcesRelativeTo: "http://example.com/foo.js.map",
  564. map: map.simple,
  565. sourcesResolved: ["http://example.com/foo.js"],
  566. sourcesContent: ["http://example.com/foo.js"]
  567. }, "domainRelative")
  568. isAsync()
  569. })
  570. method(code.schemeRelative, codeUrl, readSimple, function(error, result) {
  571. t.error(error)
  572. t.deepEqual(result, {
  573. sourceMappingURL: "//foo.org/foo.js.map",
  574. url: "http://foo.org/foo.js.map",
  575. sourcesRelativeTo: "http://foo.org/foo.js.map",
  576. map: map.simple,
  577. sourcesResolved: ["http://foo.org/foo.js"],
  578. sourcesContent: ["http://foo.org/foo.js"]
  579. }, "schemeRelative")
  580. isAsync()
  581. })
  582. method(code.absolute, codeUrl, readSimple, function(error, result) {
  583. t.error(error)
  584. t.deepEqual(result, {
  585. sourceMappingURL: "https://foo.org/foo.js.map",
  586. url: "https://foo.org/foo.js.map",
  587. sourcesRelativeTo: "https://foo.org/foo.js.map",
  588. map: map.simple,
  589. sourcesResolved: ["https://foo.org/foo.js"],
  590. sourcesContent: ["https://foo.org/foo.js"]
  591. }, "absolute")
  592. isAsync()
  593. })
  594. method(code.dataUri, codeUrl, wrapMap(Throws, identity), function(error, result) {
  595. t.error(error)
  596. t.deepEqual(result, {
  597. sourceMappingURL: "data:application/json," +
  598. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  599. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  600. url: null,
  601. sourcesRelativeTo: codeUrl,
  602. map: map.simple,
  603. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  604. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  605. }, "dataUri")
  606. isAsync()
  607. })
  608. method(code.base64, codeUrl, wrapMap(Throws, identity), function(error, result) {
  609. t.error(error)
  610. t.deepEqual(result, {
  611. sourceMappingURL: "data:application/json;base64," +
  612. "eyJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W119",
  613. url: null,
  614. sourcesRelativeTo: codeUrl,
  615. map: map.simple,
  616. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  617. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  618. }, "base64")
  619. isAsync()
  620. })
  621. method(code.dataUriText, codeUrl, wrapMap(Throws, identity), function(error, result) {
  622. t.error(error)
  623. t.deepEqual(result, {
  624. sourceMappingURL: "data:text/json," +
  625. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  626. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  627. url: null,
  628. sourcesRelativeTo: codeUrl,
  629. map: map.simple,
  630. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  631. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  632. }, "dataUriText")
  633. isAsync()
  634. })
  635. method(code.dataUriParameter, codeUrl, wrapMap(Throws, identity), function(error, result) {
  636. t.error(error)
  637. t.deepEqual(result, {
  638. sourceMappingURL: "data:application/json;charset=UTF-8;foo=bar," +
  639. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  640. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  641. url: null,
  642. sourcesRelativeTo: codeUrl,
  643. map: map.simple,
  644. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  645. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  646. }, "dataUriParameter")
  647. isAsync()
  648. })
  649. method(code.dataUriNoMime, codeUrl, wrap(Throws), function(error, result) {
  650. t.deepEqual(error.sourceMapData, {
  651. sourceMappingURL: "data:,foo",
  652. url: null,
  653. sourcesRelativeTo: codeUrl,
  654. map: "foo"
  655. }, "dataUriNoMime .sourceMapData")
  656. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriNoMime")
  657. t.notOk(result)
  658. isAsync()
  659. })
  660. method(code.dataUriInvalidMime, codeUrl, wrap(Throws), function(error, result) {
  661. t.deepEqual(error.sourceMapData, {
  662. sourceMappingURL: "data:text/html,foo",
  663. url: null,
  664. sourcesRelativeTo: codeUrl,
  665. map: "foo"
  666. }, "dataUriInvalidMime .sourceMapData")
  667. t.ok(error.message.match(/mime type.+text\/html/), "dataUriInvalidMime")
  668. t.notOk(result)
  669. isAsync()
  670. })
  671. method(code.dataUriInvalidJSON, codeUrl, wrap(Throws), function(error, result) {
  672. t.deepEqual(error.sourceMapData, {
  673. sourceMappingURL: "data:application/json,foo",
  674. url: null,
  675. sourcesRelativeTo: codeUrl,
  676. map: "foo"
  677. }, "dataUriInvalidJSON .sourceMapData")
  678. t.ok(error instanceof SyntaxError && error.message !== "data:application/json,foo",
  679. "dataUriInvalidJSON")
  680. t.notOk(result)
  681. isAsync()
  682. })
  683. method(code.dataUriXSSIsafe, codeUrl, wrapMap(Throws, identity), function(error, result) {
  684. t.error(error)
  685. t.deepEqual(result, {
  686. sourceMappingURL: "data:application/json," + ")%5D%7D%27" +
  687. "%7B%22mappings%22%3A%22AAAA%22%2C%22sources%22%3A%5B%22" +
  688. "foo.js%22%5D%2C%22names%22%3A%5B%5D%7D",
  689. url: null,
  690. sourcesRelativeTo: codeUrl,
  691. map: map.simple,
  692. sourcesResolved: ["http://example.com/a/b/c/foo.js"],
  693. sourcesContent: ["http://example.com/a/b/c/foo.js"]
  694. }, "dataUriXSSIsafe")
  695. isAsync()
  696. })
  697. method(code.dataUriEmpty, codeUrl, wrap(Throws), function(error, result) {
  698. t.deepEqual(error.sourceMapData, {
  699. sourceMappingURL: "data:",
  700. url: null,
  701. sourcesRelativeTo: codeUrl,
  702. map: ""
  703. }, "dataUriEmpty .sourceMapData")
  704. t.ok(error.message.match(/mime type.+text\/plain/), "dataUriEmpty")
  705. t.notOk(result)
  706. isAsync()
  707. })
  708. method(code.noMap, codeUrl, wrap(Throws), function(error, result) {
  709. t.error(error)
  710. t.equal(result, null, "noMap")
  711. isAsync()
  712. })
  713. method(code.absolute, codeUrl, wrap(read([map.simpleString])), function(error, result) {
  714. t.error(error)
  715. t.deepEqual(result, {
  716. sourceMappingURL: "https://foo.org/foo.js.map",
  717. url: "https://foo.org/foo.js.map",
  718. sourcesRelativeTo: "https://foo.org/foo.js.map",
  719. map: map.simple,
  720. sourcesResolved: ["https://foo.org/foo.js"],
  721. sourcesContent: [map.simpleString]
  722. }, "read non-string")
  723. isAsync()
  724. })
  725. method(code.absolute, codeUrl, wrap(read("invalid JSON")), function(error, result) {
  726. t.deepEqual(error.sourceMapData, {
  727. sourceMappingURL: "https://foo.org/foo.js.map",
  728. url: "https://foo.org/foo.js.map",
  729. sourcesRelativeTo: "https://foo.org/foo.js.map",
  730. map: "invalid JSON"
  731. }, "read invalid JSON .sourceMapData")
  732. t.ok(error instanceof SyntaxError, "read invalid JSON")
  733. t.notOk(result)
  734. isAsync()
  735. })
  736. method(code.absolute, codeUrl, wrapMap(read(map.XSSIsafe), identity), function(error, result) {
  737. t.error(error)
  738. t.deepEqual(result, {
  739. sourceMappingURL: "https://foo.org/foo.js.map",
  740. url: "https://foo.org/foo.js.map",
  741. sourcesRelativeTo: "https://foo.org/foo.js.map",
  742. map: map.simple,
  743. sourcesResolved: ["https://foo.org/foo.js"],
  744. sourcesContent: ["https://foo.org/foo.js"]
  745. }, "XSSIsafe map")
  746. isAsync()
  747. })
  748. method(code.absolute, codeUrl, wrap(Throws), function(error, result) {
  749. t.deepEqual(error.sourceMapData, {
  750. sourceMappingURL: "https://foo.org/foo.js.map",
  751. url: "https://foo.org/foo.js.map",
  752. sourcesRelativeTo: "https://foo.org/foo.js.map",
  753. map: null
  754. }, "read throws .sourceMapData")
  755. t.equal(error.message, "https://foo.org/foo.js.map", "read throws")
  756. t.notOk(result)
  757. isAsync()
  758. })
  759. function readMap(what) {
  760. return wrapMap(read(JSON.stringify(what)), identity)
  761. }
  762. var options
  763. method(code.fileRelative, codeUrl, readMap(map.simple), function(error, result) {
  764. t.error(error)
  765. t.deepEqual(result.sourcesResolved, ["http://example.com/a/b/c/foo.js"], "simple")
  766. t.deepEqual(result.sourcesContent, ["http://example.com/a/b/c/foo.js"], "simple")
  767. isAsync()
  768. })
  769. method(code.fileRelative, codeUrl, readMap(map.sourceRoot), function(error, result) {
  770. t.error(error)
  771. t.deepEqual(result.sourcesResolved, [
  772. "http://example.com/static/js/app/foo.js",
  773. "http://example.com/static/js/app/lib/bar.js",
  774. "http://example.com/static/js/vendor/dom.js",
  775. "http://example.com/version.js",
  776. "http://foo.org/baz.js"
  777. ], "sourceRoot")
  778. t.deepEqual(result.sourcesContent, [
  779. "http://example.com/static/js/app/foo.js",
  780. "http://example.com/static/js/app/lib/bar.js",
  781. "http://example.com/static/js/vendor/dom.js",
  782. "http://example.com/version.js",
  783. "http://foo.org/baz.js"
  784. ], "sourceRoot")
  785. isAsync()
  786. })
  787. options = {sourceRoot: false}
  788. method(code.fileRelative, codeUrl, readMap(map.sourceRoot), options, function(error, result) {
  789. t.error(error)
  790. t.deepEqual(result.sourcesResolved, [
  791. "http://example.com/a/b/c/foo.js",
  792. "http://example.com/a/b/c/lib/bar.js",
  793. "http://example.com/a/b/vendor/dom.js",
  794. "http://example.com/version.js",
  795. "http://foo.org/baz.js"
  796. ], "ignore sourceRoot")
  797. t.deepEqual(result.sourcesContent, [
  798. "http://example.com/a/b/c/foo.js",
  799. "http://example.com/a/b/c/lib/bar.js",
  800. "http://example.com/a/b/vendor/dom.js",
  801. "http://example.com/version.js",
  802. "http://foo.org/baz.js"
  803. ], "ignore sourceRoot")
  804. isAsync()
  805. })
  806. options = {sourceRoot: "/static/js/"}
  807. method(code.fileRelative, codeUrl, readMap(map.sourceRoot), options, function(error, result) {
  808. t.error(error)
  809. t.deepEqual(result.sourcesResolved, [
  810. "http://example.com/static/js/foo.js",
  811. "http://example.com/static/js/lib/bar.js",
  812. "http://example.com/static/vendor/dom.js",
  813. "http://example.com/version.js",
  814. "http://foo.org/baz.js"
  815. ], "custom sourceRoot")
  816. t.deepEqual(result.sourcesContent, [
  817. "http://example.com/static/js/foo.js",
  818. "http://example.com/static/js/lib/bar.js",
  819. "http://example.com/static/vendor/dom.js",
  820. "http://example.com/version.js",
  821. "http://foo.org/baz.js"
  822. ], "custom sourceRoot")
  823. isAsync()
  824. })
  825. method(code.fileRelative, codeUrl, readMap(map.sourceRootNoSlash), function(error, result) {
  826. t.error(error)
  827. t.deepEqual(result.sourcesResolved, [
  828. "http://example.com/static/js/app/foo.js",
  829. "http://example.com/static/js/app/lib/bar.js",
  830. "http://example.com/static/js/vendor/dom.js",
  831. "http://example.com/version.js",
  832. "http://foo.org/baz.js"
  833. ], "sourceRootNoSlash")
  834. t.deepEqual(result.sourcesContent, [
  835. "http://example.com/static/js/app/foo.js",
  836. "http://example.com/static/js/app/lib/bar.js",
  837. "http://example.com/static/js/vendor/dom.js",
  838. "http://example.com/version.js",
  839. "http://foo.org/baz.js"
  840. ], "sourceRootNoSlash")
  841. isAsync()
  842. })
  843. method(code.fileRelative, codeUrl, readMap(map.sourceRootEmpty), function(error, result) {
  844. t.error(error)
  845. t.deepEqual(result.sourcesResolved, [
  846. "http://example.com/a/b/c/foo.js",
  847. "http://example.com/a/b/c/lib/bar.js",
  848. "http://example.com/a/b/vendor/dom.js",
  849. "http://example.com/version.js",
  850. "http://foo.org/baz.js"
  851. ], "sourceRootEmpty")
  852. t.deepEqual(result.sourcesContent, [
  853. "http://example.com/a/b/c/foo.js",
  854. "http://example.com/a/b/c/lib/bar.js",
  855. "http://example.com/a/b/vendor/dom.js",
  856. "http://example.com/version.js",
  857. "http://foo.org/baz.js"
  858. ], "sourceRootEmpty")
  859. isAsync()
  860. })
  861. method(code.fileRelative, codeUrl, readMap(map.sourcesContent), function(error, result) {
  862. t.error(error)
  863. t.deepEqual(result.sourcesResolved, [
  864. "http://example.com/static/js/app/foo.js",
  865. "http://example.com/static/js/app/lib/bar.js",
  866. "http://example.com/static/js/vendor/dom.js",
  867. "http://example.com/version.js",
  868. "http://foo.org/baz.js"
  869. ], "sourcesContent")
  870. t.deepEqual(result.sourcesContent, [
  871. "foo.js",
  872. "lib/bar.js",
  873. "../vendor/dom.js",
  874. "/version.js",
  875. "//foo.org/baz.js"
  876. ], "sourcesContent")
  877. isAsync()
  878. })
  879. method(code.fileRelative, codeUrl, readMap(map.mixed), function(error, result) {
  880. t.error(error)
  881. t.deepEqual(result.sourcesResolved, [
  882. "http://example.com/a/b/c/foo.js",
  883. "http://example.com/a/b/c/lib/bar.js",
  884. "http://example.com/a/b/vendor/dom.js",
  885. "http://example.com/version.js",
  886. "http://foo.org/baz.js"
  887. ], "mixed")
  888. t.deepEqual(result.sourcesContent, [
  889. "foo.js",
  890. "http://example.com/a/b/c/lib/bar.js",
  891. "http://example.com/a/b/vendor/dom.js",
  892. "/version.js",
  893. "//foo.org/baz.js"
  894. ], "mixed")
  895. isAsync()
  896. })
  897. method(code.fileRelative, codeUrl, readMap(map.noSources), function(error, result) {
  898. t.error(error)
  899. t.deepEqual(result.sourcesResolved, [], "noSources")
  900. t.deepEqual(result.sourcesContent, [], "noSources")
  901. isAsync()
  902. })
  903. method(code.fileRelative, codeUrl, readMap(map.empty), function(error, result) {
  904. t.error(error)
  905. t.deepEqual(result.sourcesResolved, [], "noSources")
  906. t.deepEqual(result.sourcesContent, [], "noSources")
  907. isAsync()
  908. })
  909. method(code.fileRelative, codeUrl, wrap(read([map.simpleString])), function(error, result) {
  910. t.error(error)
  911. t.deepEqual(result.sourcesResolved, ["http://example.com/a/b/c/foo.js"], "read non-string")
  912. t.deepEqual(result.sourcesContent, [map.simpleString], "read non-string")
  913. isAsync()
  914. })
  915. function ThrowsMap(what) {
  916. return wrapMap(read(JSON.stringify(what)), Throws)
  917. }
  918. method(code.fileRelative, codeUrl, ThrowsMap(map.mixed), function(error, result) {
  919. t.error(error)
  920. t.deepEqual(result.sourcesResolved, [
  921. "http://example.com/a/b/c/foo.js",
  922. "http://example.com/a/b/c/lib/bar.js",
  923. "http://example.com/a/b/vendor/dom.js",
  924. "http://example.com/version.js",
  925. "http://foo.org/baz.js"
  926. ], "read throws .sourcesResolved")
  927. var sourcesContent = result.sourcesContent
  928. for (var index = 0, len = sourcesContent.length; index < len; index++) {
  929. var item = sourcesContent[index]
  930. if (item instanceof Error) {
  931. sourcesContent[index] = null
  932. }
  933. }
  934. t.deepEqual(sourcesContent, [
  935. "foo.js",
  936. null,
  937. null,
  938. "/version.js",
  939. "//foo.org/baz.js"
  940. ], "read throws .sourcesContent")
  941. isAsync()
  942. })
  943. var mapUrl = "https://foo.org/foo.js.map"
  944. method(null, mapUrl, readSimple, function(error, result) {
  945. t.error(error)
  946. t.deepEqual(result, {
  947. sourceMappingURL: null,
  948. url: "https://foo.org/foo.js.map",
  949. sourcesRelativeTo: "https://foo.org/foo.js.map",
  950. map: map.simple,
  951. sourcesResolved: ["https://foo.org/foo.js"],
  952. sourcesContent: ["https://foo.org/foo.js"]
  953. }, "mapUrl simple")
  954. isAsync()
  955. })
  956. method(null, mapUrl, wrap(read([map.simpleString])), function(error, result) {
  957. t.error(error)
  958. t.deepEqual(result, {
  959. sourceMappingURL: null,
  960. url: "https://foo.org/foo.js.map",
  961. sourcesRelativeTo: "https://foo.org/foo.js.map",
  962. map: map.simple,
  963. sourcesResolved: ["https://foo.org/foo.js"],
  964. sourcesContent: [map.simpleString]
  965. }, "mapUrl read non-string")
  966. isAsync()
  967. })
  968. method(null, mapUrl, wrap(read("invalid JSON")), function(error, result) {
  969. t.deepEqual(error.sourceMapData, {
  970. sourceMappingURL: null,
  971. url: "https://foo.org/foo.js.map",
  972. sourcesRelativeTo: "https://foo.org/foo.js.map",
  973. map: "invalid JSON"
  974. }, "mapUrl read invalid JSON .sourceMapData")
  975. t.ok(error instanceof SyntaxError, "mapUrl read invalid JSON")
  976. t.notOk(result)
  977. isAsync()
  978. })
  979. method(null, mapUrl, wrapMap(read(map.XSSIsafe), identity), function(error, result) {
  980. t.error(error)
  981. t.deepEqual(result, {
  982. sourceMappingURL: null,
  983. url: "https://foo.org/foo.js.map",
  984. sourcesRelativeTo: "https://foo.org/foo.js.map",
  985. map: map.simple,
  986. sourcesResolved: ["https://foo.org/foo.js"],
  987. sourcesContent: ["https://foo.org/foo.js"]
  988. }, "mapUrl XSSIsafe map")
  989. isAsync()
  990. })
  991. method(null, mapUrl, wrap(Throws), function(error, result) {
  992. t.deepEqual(error.sourceMapData, {
  993. sourceMappingURL: null,
  994. url: "https://foo.org/foo.js.map",
  995. sourcesRelativeTo: "https://foo.org/foo.js.map",
  996. map: null
  997. }, "mapUrl read throws .sourceMapData")
  998. t.equal(error.message, "https://foo.org/foo.js.map", "mapUrl read throws")
  999. t.notOk(result)
  1000. isAsync()
  1001. })
  1002. mapUrl = "http://example.com/a/b/c/foo.js.map"
  1003. options = {sourceRoot: "/static/js/"}
  1004. method(null, mapUrl, readMap(map.sourceRoot), options, function(error, result) {
  1005. t.error(error)
  1006. t.deepEqual(result.sourcesResolved, [
  1007. "http://example.com/static/js/foo.js",
  1008. "http://example.com/static/js/lib/bar.js",
  1009. "http://example.com/static/vendor/dom.js",
  1010. "http://example.com/version.js",
  1011. "http://foo.org/baz.js"
  1012. ], "mapUrl custom sourceRoot")
  1013. t.deepEqual(result.sourcesContent, [
  1014. "http://example.com/static/js/foo.js",
  1015. "http://example.com/static/js/lib/bar.js",
  1016. "http://example.com/static/vendor/dom.js",
  1017. "http://example.com/version.js",
  1018. "http://foo.org/baz.js"
  1019. ], "mapUrl custom sourceRoot")
  1020. isAsync()
  1021. })
  1022. method(null, mapUrl, readMap(map.mixed), function(error, result) {
  1023. t.error(error)
  1024. t.deepEqual(result.sourcesResolved, [
  1025. "http://example.com/a/b/c/foo.js",
  1026. "http://example.com/a/b/c/lib/bar.js",
  1027. "http://example.com/a/b/vendor/dom.js",
  1028. "http://example.com/version.js",
  1029. "http://foo.org/baz.js"
  1030. ], "mapUrl mixed")
  1031. t.deepEqual(result.sourcesContent, [
  1032. "foo.js",
  1033. "http://example.com/a/b/c/lib/bar.js",
  1034. "http://example.com/a/b/vendor/dom.js",
  1035. "/version.js",
  1036. "//foo.org/baz.js"
  1037. ], "mapUrl mixed")
  1038. isAsync()
  1039. })
  1040. next = true
  1041. }
  1042. }
  1043. test(".resolve", testResolve(sourceMapResolve.resolve, false))
  1044. test(".resolveSync", testResolve(sourceMapResolve.resolveSync, true))
  1045. test(".parseMapToJSON", function(t) {
  1046. t.plan(1)
  1047. t.deepEqual(sourceMapResolve.parseMapToJSON(map.XSSIsafe), map.simple)
  1048. })