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