@@ -15,38 +15,99 @@ var fs = inquire("fs");
1515 * @returns {undefined }
1616 */
1717
18+ /**
19+ * Options as used by {@link util.fetch}.
20+ * @typedef {Object }
21+ * @property {boolean } [binary=false] Whether expecting a binary response or not
22+ */
23+
1824/**
1925 * Fetches the contents of a file.
2026 * @memberof util
21- * @param {string } path File path or url
22- * @param {FetchCallback } [callback] Callback function
23- * @returns { Promise<string> } A Promise if ` callback` has been omitted, otherwise `undefined`
24- * @property { function(string, FetchCallback=):Promise<string> } xhr XHR/browser fetch with an identical signature
27+ * @param {string } filename File path or url
28+ * @param {FetchOptions } options Fetch options
29+ * @param { FetchCallback } callback Callback function
30+ * @returns { undefined }
2531 */
26- function fetch ( path , callback ) {
32+ function fetch ( filename , options , callback ) {
33+ if ( typeof options === "function" ) {
34+ callback = options ;
35+ options = { } ;
36+ } else if ( ! options )
37+ options = { } ;
38+
2739 if ( ! callback )
28- return asPromise ( fetch , this , path ) ; // eslint-disable-line no-invalid-this
40+ return asPromise ( fetch , this , filename , options ) ; // eslint-disable-line no-invalid-this
41+
42+ // if a node-like filesystem is present, try it first but fall back to XHR if nothing is found.
2943 if ( fs && fs . readFile )
30- return fs . readFile ( path , "utf8" , function fetchReadFileCallback ( err , contents ) {
44+ return fs . readFile ( filename , function fetchReadFileCallback ( err , contents ) {
3145 return err && typeof XMLHttpRequest !== "undefined"
32- ? fetch . xhr ( path , callback )
33- : callback ( err , contents ) ;
46+ ? fetch . xhr ( filename , options , callback )
47+ : err
48+ ? callback ( err )
49+ : callback ( null , options . binary ? contents : contents . toString ( "utf8" ) ) ;
3450 } ) ;
35- return fetch . xhr ( path , callback ) ;
51+
52+ // use the XHR version otherwise.
53+ return fetch . xhr ( filename , options , callback ) ;
3654}
3755
38- fetch . xhr = function fetch_xhr ( path , callback ) {
56+ /**
57+ * Fetches the contents of a file.
58+ * @name util.fetch
59+ * @function
60+ * @param {string } path File path or url
61+ * @param {FetchCallback } callback Callback function
62+ * @returns {undefined }
63+ * @variation 2
64+ */
65+
66+ /**
67+ * Fetches the contents of a file.
68+ * @name util.fetch
69+ * @function
70+ * @param {string } path File path or url
71+ * @param {FetchOptions } [options] Fetch options
72+ * @returns {Promise<string|Uint8Array> } Promise
73+ * @variation 3
74+ */
75+
76+ /**/
77+ fetch . xhr = function fetch_xhr ( filename , options , callback ) {
3978 var xhr = new XMLHttpRequest ( ) ;
4079 xhr . onreadystatechange /* works everywhere */ = function fetchOnReadyStateChange ( ) {
41- return xhr . readyState === 4
42- ? xhr . status === 0 || xhr . status === 200
43- ? callback ( null , xhr . responseText )
44- : callback ( Error ( "status " + xhr . status ) )
45- : undefined ;
80+
81+ if ( xhr . readyState !== 4 )
82+ return undefined ;
83+
4684 // local cors security errors return status 0 / empty string, too. afaik this cannot be
4785 // reliably distinguished from an actually empty file for security reasons. feel free
4886 // to send a pull request if you are aware of a solution.
87+ if ( xhr . status !== 0 && xhr . status !== 200 )
88+ return callback ( Error ( "status " + xhr . status ) ) ;
89+
90+ // if binary data is expected, make sure that some sort of array is returned, even if
91+ // ArrayBuffers are not supported. the binary string fallback, however, is unsafe.
92+ if ( options . binary ) {
93+ var buffer = xhr . response ;
94+ if ( ! buffer ) {
95+ buffer = [ ] ;
96+ for ( var i = 0 ; i < xhr . responseText . length ; ++ i )
97+ buffer . push ( xhr . responseText . charCodeAt ( i ) & 255 ) ;
98+ }
99+ return callback ( null , typeof Uint8Array !== "undefined" ? new Uint8Array ( buffer ) : buffer ) ;
100+ }
101+ return callback ( null , xhr . responseText ) ;
49102 } ;
50- xhr . open ( "GET" , path ) ;
103+
104+ if ( options . binary ) {
105+ // ref: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Receiving_binary_data_in_older_browsers
106+ if ( "overrideMimeType" in xhr )
107+ xhr . overrideMimeType ( "text/plain; charset=x-user-defined" ) ;
108+ xhr . responseType = "arraybuffer" ;
109+ }
110+
111+ xhr . open ( "GET" , filename ) ;
51112 xhr . send ( ) ;
52113} ;
0 commit comments