| "use strict"; |
| module.exports = fetch; |
| |
| var asPromise = require("@protobufjs/aspromise"), |
| inquire = require("@protobufjs/inquire"); |
| |
| var fs = inquire("fs"); |
| |
| /** |
| * Node-style callback as used by {@link util.fetch}. |
| * @typedef FetchCallback |
| * @type {function} |
| * @param {?Error} error Error, if any, otherwise `null` |
| * @param {string} [contents] File contents, if there hasn't been an error |
| * @returns {undefined} |
| */ |
| |
| /** |
| * Options as used by {@link util.fetch}. |
| * @interface IFetchOptions |
| * @property {boolean} [binary=false] Whether expecting a binary response |
| * @property {boolean} [xhr=false] If `true`, forces the use of XMLHttpRequest |
| */ |
| |
| /** |
| * Fetches the contents of a file. |
| * @memberof util |
| * @param {string} filename File path or url |
| * @param {IFetchOptions} options Fetch options |
| * @param {FetchCallback} callback Callback function |
| * @returns {undefined} |
| */ |
| function fetch(filename, options, callback) { |
| if (typeof options === "function") { |
| callback = options; |
| options = {}; |
| } else if (!options) |
| options = {}; |
| |
| if (!callback) |
| return asPromise(fetch, this, filename, options); // eslint-disable-line no-invalid-this |
| |
| // if a node-like filesystem is present, try it first but fall back to XHR if nothing is found. |
| if (!options.xhr && fs && fs.readFile) |
| return fs.readFile(filename, function fetchReadFileCallback(err, contents) { |
| return err && typeof XMLHttpRequest !== "undefined" |
| ? fetch.xhr(filename, options, callback) |
| : err |
| ? callback(err) |
| : callback(null, options.binary ? contents : contents.toString("utf8")); |
| }); |
| |
| // use the XHR version otherwise. |
| return fetch.xhr(filename, options, callback); |
| } |
| |
| /** |
| * Fetches the contents of a file. |
| * @name util.fetch |
| * @function |
| * @param {string} path File path or url |
| * @param {FetchCallback} callback Callback function |
| * @returns {undefined} |
| * @variation 2 |
| */ |
| |
| /** |
| * Fetches the contents of a file. |
| * @name util.fetch |
| * @function |
| * @param {string} path File path or url |
| * @param {IFetchOptions} [options] Fetch options |
| * @returns {Promise<string|Uint8Array>} Promise |
| * @variation 3 |
| */ |
| |
| /**/ |
| fetch.xhr = function fetch_xhr(filename, options, callback) { |
| var xhr = new XMLHttpRequest(); |
| xhr.onreadystatechange /* works everywhere */ = function fetchOnReadyStateChange() { |
| |
| if (xhr.readyState !== 4) |
| return undefined; |
| |
| // local cors security errors return status 0 / empty string, too. afaik this cannot be |
| // reliably distinguished from an actually empty file for security reasons. feel free |
| // to send a pull request if you are aware of a solution. |
| if (xhr.status !== 0 && xhr.status !== 200) |
| return callback(Error("status " + xhr.status)); |
| |
| // if binary data is expected, make sure that some sort of array is returned, even if |
| // ArrayBuffers are not supported. the binary string fallback, however, is unsafe. |
| if (options.binary) { |
| var buffer = xhr.response; |
| if (!buffer) { |
| buffer = []; |
| for (var i = 0; i < xhr.responseText.length; ++i) |
| buffer.push(xhr.responseText.charCodeAt(i) & 255); |
| } |
| return callback(null, typeof Uint8Array !== "undefined" ? new Uint8Array(buffer) : buffer); |
| } |
| return callback(null, xhr.responseText); |
| }; |
| |
| if (options.binary) { |
| // ref: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Receiving_binary_data_in_older_browsers |
| if ("overrideMimeType" in xhr) |
| xhr.overrideMimeType("text/plain; charset=x-user-defined"); |
| xhr.responseType = "arraybuffer"; |
| } |
| |
| xhr.open("GET", filename); |
| xhr.send(); |
| }; |