vega-loader
Advanced tools
Comparing version 3.1.0 to 4.0.0
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-dsv'), require('topojson-client'), require('vega-util'), require('d3-time-format')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'd3-dsv', 'topojson-client', 'vega-util', 'd3-time-format'], factory) : | ||
(factory((global.vega = {}),global.d3,global.topojson,global.vega,global.d3)); | ||
}(this, (function (exports,d3Dsv,topojsonClient,vegaUtil,d3TimeFormat) { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-util'), require('d3-dsv'), require('topojson-client'), require('d3-time-format')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'vega-util', 'd3-dsv', 'topojson-client', 'd3-time-format'], factory) : | ||
(global = global || self, factory(global.vega = {}, global.vega, global.d3, global.topojson, global.d3)); | ||
}(this, function (exports, vegaUtil, d3Dsv, topojsonClient, d3TimeFormat) { 'use strict'; | ||
@@ -15,14 +15,22 @@ // Matches absolute URLs with optional protocol | ||
/** | ||
* Creates a new loader instance that provides methods for requesting files | ||
* from either the network or disk, and for sanitizing request URIs. | ||
* @param {object} [options] - Optional default loading options to use. | ||
* @return {object} - A new loader instance. | ||
* Factory for a loader constructor that provides methods for requesting | ||
* files from either the network or disk, and for sanitizing request URIs. | ||
* @param {function} fetch - The Fetch API for HTTP network requests. | ||
* If null or undefined, HTTP loading will be disabled. | ||
* @param {object} fs - The file system interface for file loading. | ||
* If null or undefined, local file loading will be disabled. | ||
* @return {function} A loader constructor with the following signature: | ||
* param {object} [options] - Optional default loading options to use. | ||
* return {object} - A new loader instance. | ||
*/ | ||
function loader(options) { | ||
return { | ||
options: options || {}, | ||
sanitize: sanitize, | ||
load: load, | ||
file: file, | ||
http: http | ||
function loaderFactory(fetch, fs) { | ||
return function(options) { | ||
return { | ||
options: options || {}, | ||
sanitize: sanitize, | ||
load: load, | ||
fileAccess: !!fs, | ||
file: fileLoader(fs), | ||
http: httpLoader(fetch) | ||
}; | ||
}; | ||
@@ -41,11 +49,9 @@ } | ||
*/ | ||
function load(uri, options) { | ||
var loader = this; | ||
return loader.sanitize(uri, options) | ||
.then(function(opt) { | ||
var url = opt.href; | ||
return opt.localFile | ||
? loader.file(url) | ||
: loader.http(url, options); | ||
}); | ||
async function load(uri, options) { | ||
const opt = await this.sanitize(uri, options), | ||
url = opt.href; | ||
return opt.localFile | ||
? this.file(url) | ||
: this.http(url, options); | ||
} | ||
@@ -63,102 +69,120 @@ | ||
*/ | ||
function sanitize(uri, options) { | ||
async function sanitize(uri, options) { | ||
options = vegaUtil.extend({}, this.options, options); | ||
return new Promise(function(accept, reject) { | ||
var result = {href: null}, | ||
isFile, hasProtocol, loadFile, base; | ||
const fileAccess = this.fileAccess, | ||
result = {href: null}; | ||
if (uri == null || typeof uri !== 'string') { | ||
reject('Sanitize failure, invalid URI: ' + vegaUtil.stringValue(uri)); | ||
return; | ||
} | ||
let isFile, hasProtocol, loadFile, base; | ||
hasProtocol = protocol_re.test(uri); | ||
if (uri == null || typeof uri !== 'string') { | ||
vegaUtil.error('Sanitize failure, invalid URI: ' + vegaUtil.stringValue(uri)); | ||
} | ||
// if relative url (no protocol/host), prepend baseURL | ||
if ((base = options.baseURL) && !hasProtocol) { | ||
// Ensure that there is a slash between the baseURL (e.g. hostname) and url | ||
if (!startsWith(uri, '/') && base[base.length-1] !== '/') { | ||
uri = '/' + uri; | ||
} | ||
uri = base + uri; | ||
hasProtocol = protocol_re.test(uri); | ||
// if relative url (no protocol/host), prepend baseURL | ||
if ((base = options.baseURL) && !hasProtocol) { | ||
// Ensure that there is a slash between the baseURL (e.g. hostname) and url | ||
if (!uri.startsWith('/') && base[base.length-1] !== '/') { | ||
uri = '/' + uri; | ||
} | ||
uri = base + uri; | ||
} | ||
// should we load from file system? | ||
loadFile = (isFile = startsWith(uri, fileProtocol)) | ||
|| options.mode === 'file' | ||
|| options.mode !== 'http' && !hasProtocol && fs(); | ||
// should we load from file system? | ||
loadFile = (isFile = uri.startsWith(fileProtocol)) | ||
|| options.mode === 'file' | ||
|| options.mode !== 'http' && !hasProtocol && fileAccess; | ||
if (isFile) { | ||
// strip file protocol | ||
uri = uri.slice(fileProtocol.length); | ||
} else if (startsWith(uri, '//')) { | ||
if (options.defaultProtocol === 'file') { | ||
// if is file, strip protocol and set loadFile flag | ||
uri = uri.slice(2); | ||
loadFile = true; | ||
} else { | ||
// if relative protocol (starts with '//'), prepend default protocol | ||
uri = (options.defaultProtocol || 'http') + ':' + uri; | ||
} | ||
if (isFile) { | ||
// strip file protocol | ||
uri = uri.slice(fileProtocol.length); | ||
} else if (uri.startsWith('//')) { | ||
if (options.defaultProtocol === 'file') { | ||
// if is file, strip protocol and set loadFile flag | ||
uri = uri.slice(2); | ||
loadFile = true; | ||
} else { | ||
// if relative protocol (starts with '//'), prepend default protocol | ||
uri = (options.defaultProtocol || 'http') + ':' + uri; | ||
} | ||
} | ||
// set non-enumerable mode flag to indicate local file load | ||
Object.defineProperty(result, 'localFile', {value: !!loadFile}); | ||
// set non-enumerable mode flag to indicate local file load | ||
Object.defineProperty(result, 'localFile', {value: !!loadFile}); | ||
// set uri | ||
result.href = uri; | ||
// set uri | ||
result.href = uri; | ||
// set default result target, if specified | ||
if (options.target) { | ||
result.target = options.target + ''; | ||
} | ||
// set default result target, if specified | ||
if (options.target) { | ||
result.target = options.target + ''; | ||
} | ||
// return | ||
accept(result); | ||
}); | ||
// set default result rel, if specified (#1542) | ||
if (options.rel) { | ||
result.rel = options.rel + ''; | ||
} | ||
// return | ||
return result; | ||
} | ||
/** | ||
* HTTP request loader. | ||
* @param {string} url - The url to request. | ||
* @param {object} options - An options hash. | ||
* @return {Promise} - A promise that resolves to the file contents. | ||
* File system loader factory. | ||
* @param {object} fs - The file system interface. | ||
* @return {function} - A file loader with the following signature: | ||
* param {string} filename - The file system path to load. | ||
* param {string} filename - The file system path to load. | ||
* return {Promise} A promise that resolves to the file contents. | ||
*/ | ||
function http(url, options) { | ||
return request(url, vegaUtil.extend({}, this.options.http, options)) | ||
.then(function(response) { | ||
if (!response.ok) throw response.status + '' + response.statusText; | ||
return response.text(); | ||
}); | ||
function fileLoader(fs) { | ||
return fs | ||
? function(filename) { | ||
return new Promise(function(accept, reject) { | ||
fs.readFile(filename, function(error, data) { | ||
if (error) reject(error); | ||
else accept(data); | ||
}); | ||
}); | ||
} | ||
: fileReject; | ||
} | ||
/** | ||
* File system loader. | ||
* @param {string} filename - The file system path to load. | ||
* @return {Promise} - A promise that resolves to the file contents. | ||
* Default file system loader that simply rejects. | ||
*/ | ||
function file(filename) { | ||
return new Promise(function(accept, reject) { | ||
var f = fs(); | ||
f ? f.readFile(filename, function(error, data) { | ||
if (error) reject(error); | ||
else accept(data); | ||
}) | ||
: reject('No file system access for ' + filename); | ||
}); | ||
async function fileReject() { | ||
vegaUtil.error('No file system access.'); | ||
} | ||
function request(url, init) { | ||
var f = typeof fetch === 'function' ? fetch : require('node-fetch'); | ||
return f ? f(url, init) : Promise.reject('No fetch method available.'); | ||
} | ||
/** | ||
* HTTP request handler factory. | ||
* @param {function} fetch - The Fetch API method. | ||
* @return {function} - An http loader with the following signature: | ||
* param {string} url - The url to request. | ||
* param {object} options - An options hash. | ||
* return {Promise} - A promise that resolves to the file contents. | ||
*/ | ||
function httpLoader(fetch) { | ||
return fetch | ||
? async function(url, options) { | ||
const opt = vegaUtil.extend({}, this.options.http, options), | ||
type = options && options.response, | ||
response = await fetch(url, opt); | ||
function fs() { | ||
var fs = typeof require === 'function' && require('fs'); | ||
return fs && vegaUtil.isFunction(fs.readFile) ? fs : null; | ||
return !response.ok | ||
? vegaUtil.error(response.status + '' + response.statusText) | ||
: vegaUtil.isFunction(response[type]) ? response[type]() | ||
: response.text(); | ||
} | ||
: httpReject; | ||
} | ||
function startsWith(string, query) { | ||
return string == null ? false : string.lastIndexOf(query, 0) === 0; | ||
/** | ||
* Default http request handler that simply rejects. | ||
*/ | ||
async function httpReject() { | ||
vegaUtil.error('No HTTP fetch method available.'); | ||
} | ||
@@ -242,6 +266,10 @@ | ||
function delimitedFormat(delimiter) { | ||
return function(data, format) { | ||
var delim = {delimiter: delimiter}; | ||
const parse = function(data, format) { | ||
const delim = {delimiter: delimiter}; | ||
return dsv(data, format ? vegaUtil.extend(format, delim) : delim); | ||
}; | ||
parse.responseType = 'text'; | ||
return parse; | ||
} | ||
@@ -255,5 +283,7 @@ | ||
} | ||
return d3Dsv.dsvFormat(format.delimiter).parse(data+''); | ||
return d3Dsv.dsvFormat(format.delimiter).parse(data + ''); | ||
} | ||
dsv.responseType = 'text'; | ||
function isBuffer(_) { | ||
@@ -265,3 +295,3 @@ return (typeof Buffer === 'function' && vegaUtil.isFunction(Buffer.isBuffer)) | ||
function json(data, format) { | ||
var prop = (format && format.property) ? vegaUtil.field(format.property) : vegaUtil.identity; | ||
const prop = (format && format.property) ? vegaUtil.field(format.property) : vegaUtil.identity; | ||
return vegaUtil.isObject(data) && !isBuffer(data) | ||
@@ -272,2 +302,4 @@ ? parseJSON(prop(data)) | ||
json.responseType = 'json'; | ||
function parseJSON(data, format) { | ||
@@ -294,3 +326,5 @@ return (format && format.copy) | ||
var format = { | ||
topojson.responseType = 'json'; | ||
const format = { | ||
dsv: dsv, | ||
@@ -312,6 +346,11 @@ csv: delimitedFormat(','), | ||
function responseType(type) { | ||
const f = formats(type); | ||
return f && f.responseType || 'text'; | ||
} | ||
function read(data, schema, dateParse) { | ||
schema = schema || {}; | ||
var reader = formats(schema.type || 'json'); | ||
const reader = formats(schema.type || 'json'); | ||
if (!reader) vegaUtil.error('Unknown data format type: ' + schema.type); | ||
@@ -369,2 +408,7 @@ | ||
var loader = loaderFactory( | ||
typeof fetch !== 'undefined' && fetch, // use built-in fetch API | ||
null // no file system access | ||
); | ||
exports.loader = loader; | ||
@@ -377,5 +421,6 @@ exports.read = read; | ||
exports.formats = formats; | ||
exports.responseType = responseType; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
}))); | ||
})); |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-dsv"),require("topojson-client"),require("vega-util"),require("d3-time-format")):"function"==typeof define&&define.amd?define(["exports","d3-dsv","topojson-client","vega-util","d3-time-format"],t):t(e.vega={},e.d3,e.topojson,e.vega,e.d3)}(this,function(e,n,i,s,c){"use strict";var l=/^([A-Za-z]+:)?\/\//,d="file://";function t(e,n){var r=this;return r.sanitize(e,n).then(function(e){var t=e.href;return e.localFile?r.file(t):r.http(t,n)})}function r(f,a){return a=s.extend({},this.options,a),new Promise(function(e,t){var n,r,o,i,u={href:null};null!=f&&"string"==typeof f?(r=l.test(f),(i=a.baseURL)&&!r&&(h(f,"/")||"/"===i[i.length-1]||(f="/"+f),f=i+f),o=(n=h(f,d))||"file"===a.mode||"http"!==a.mode&&!r&&p(),n?f=f.slice(d.length):h(f,"//")&&("file"===a.defaultProtocol?(f=f.slice(2),o=!0):f=(a.defaultProtocol||"http")+":"+f),Object.defineProperty(u,"localFile",{value:!!o}),u.href=f,a.target&&(u.target=a.target+""),e(u)):t("Sanitize failure, invalid URI: "+s.stringValue(f))})}function o(e,t){return(n=e,r=s.extend({},this.options.http,t),o="function"==typeof fetch?fetch:require("node-fetch"),o?o(n,r):Promise.reject("No fetch method available.")).then(function(e){if(!e.ok)throw e.status+""+e.statusText;return e.text()});var n,r,o}function u(t){return new Promise(function(n,r){var e=p();e?e.readFile(t,function(e,t){e?r(e):n(t)}):r("No file system access for "+t)})}function p(){var e="function"==typeof require&&require("fs");return e&&s.isFunction(e.readFile)?e:null}function h(e,t){return null!=e&&0===e.lastIndexOf(t,0)}var m={boolean:s.toBoolean,integer:s.toNumber,number:s.toNumber,date:s.toDate,string:s.toString,unknown:s.identity},g=[function(e){return"true"===e||"false"===e||!0===e||!1===e},function(e){return a(e)&&(e=+e)==~~e},a,function(e){return!isNaN(Date.parse(e))}],v=["boolean","integer","number","date"];function f(e,t){if(!e||!e.length)return"unknown";var n,r,o,i,u=0,f=e.length,a=g.length,s=g.map(function(e,t){return t+1});for(r=0,f=e.length;r<f;++r)for(n=t?e[r][t]:e[r],o=0;o<a;++o)if(s[o]&&(null!=(i=n)&&i==i)&&!g[o](n)&&(s[o]=0,++u===g.length))return"string";return u=s.reduce(function(e,t){return 0===e?t:e},0)-1,v[u]}function y(n,e){return e.reduce(function(e,t){return e[t]=f(n,t),e},{})}function a(e){return!(isNaN(+e)||e instanceof Date)}function b(r){return function(e,t){var n={delimiter:r};return j(e,t?s.extend(t,n):n)}}function j(e,t){return t.header&&(e=t.header.map(s.stringValue).join(t.delimiter)+"\n"+e),n.dsvFormat(t.delimiter).parse(e+"")}function O(e,t){var n,r,o,i=t&&t.property?s.field(t.property):s.identity;return!s.isObject(e)||(o=e,"function"==typeof Buffer&&s.isFunction(Buffer.isBuffer)&&Buffer.isBuffer(o))?i(JSON.parse(e)):(n=i(e),r&&r.copy?JSON.parse(JSON.stringify(n)):n)}var N={dsv:j,csv:b(","),tsv:b("\t"),json:O,topojson:function(e,t){var n,r,o;return e=O(e,t),n=t&&(o=t.feature)?i.feature:t&&(o=t.mesh)?i.mesh:s.error("Missing TopoJSON feature or mesh parameter."),(r=(r=e.objects[o])?n(e,r):s.error("Invalid TopoJSON object: "+o))&&r.features||[r]}};function P(e,t){return 1<arguments.length?(N[e]=t,this):N.hasOwnProperty(e)?N[e]:null}e.loader=function(e){return{options:e||{},sanitize:r,load:t,file:u,http:o}},e.read=function(e,t,n){var r=P((t=t||{}).type||"json");return r||s.error("Unknown data format type: "+t.type),e=r(e,t),t.parse&&function(e,o,i){if(e.length){i=i||c.timeParse;var t,n,r,u,f,a,s,l=e.columns||Object.keys(e[0]);for("auto"===o&&(o=y(e,l)),l=Object.keys(o),t=l.map(function(e){var t,n,r=o[e];if(r&&(0===r.indexOf("date:")||0===r.indexOf("utc:")))return("'"===(n=(t=r.split(/:(.+)?/,2))[1])[0]&&"'"===n[n.length-1]||'"'===n[0]&&'"'===n[n.length-1])&&(n=n.slice(1,-1)),"utc"===t[0]?c.utcParse(n):i(n);if(!m[r])throw Error("Illegal format pattern: "+e+":"+r);return m[r]}),u=0,a=e.length,s=l.length;u<a;++u)for(n=e[u],f=0;f<s;++f)r=l[f],n[r]=t[f](n[r])}}(e,t.parse,n),e.hasOwnProperty("columns")&&delete e.columns,e},e.inferType=f,e.inferTypes=y,e.typeParsers=m,e.format=N,e.formats=P,Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vega-util"),require("d3-dsv"),require("topojson-client"),require("d3-time-format")):"function"==typeof define&&define.amd?define(["exports","vega-util","d3-dsv","topojson-client","d3-time-format"],t):t((e=e||self).vega={},e.vega,e.d3,e.topojson,e.d3)}(this,function(e,t,n,r,o){"use strict";var i=/^([A-Za-z]+:)?\/\//,s="file://";async function u(e,t){const n=await this.sanitize(e,t),r=n.href;return n.localFile?this.file(r):this.http(r,t)}async function f(e,n){n=t.extend({},this.options,n);const r=this.fileAccess,o={href:null};let u,f,a,c;return null!=e&&"string"==typeof e||t.error("Sanitize failure, invalid URI: "+t.stringValue(e)),f=i.test(e),(c=n.baseURL)&&!f&&(e.startsWith("/")||"/"===c[c.length-1]||(e="/"+e),e=c+e),a=(u=e.startsWith(s))||"file"===n.mode||"http"!==n.mode&&!f&&r,u?e=e.slice(s.length):e.startsWith("//")&&("file"===n.defaultProtocol?(e=e.slice(2),a=!0):e=(n.defaultProtocol||"http")+":"+e),Object.defineProperty(o,"localFile",{value:!!a}),o.href=e,n.target&&(o.target=n.target+""),n.rel&&(o.rel=n.rel+""),o}function a(e){return e?function(t){return new Promise(function(n,r){e.readFile(t,function(e,t){e?r(e):n(t)})})}:c}async function c(){t.error("No file system access.")}function l(e){return e?async function(n,r){const o=t.extend({},this.options.http,r),i=r&&r.response,s=await e(n,o);return s.ok?t.isFunction(s[i])?s[i]():s.text():t.error(s.status+""+s.statusText)}:p}async function p(){t.error("No HTTP fetch method available.")}var d={boolean:t.toBoolean,integer:t.toNumber,number:t.toNumber,date:t.toDate,string:t.toString,unknown:t.identity},h=[function(e){return"true"===e||"false"===e||!0===e||!1===e},function(e){return v(e)&&(e=+e)==~~e},v,function(e){return!isNaN(Date.parse(e))}],y=["boolean","integer","number","date"];function m(e,t){if(!e||!e.length)return"unknown";var n,r,o,i,s=0,u=e.length,f=h.length,a=h.map(function(e,t){return t+1});for(r=0,u=e.length;r<u;++r)for(n=t?e[r][t]:e[r],o=0;o<f;++o)if(a[o]&&(null!=(i=n)&&i==i)&&!h[o](n)&&(a[o]=0,++s===h.length))return"string";return s=a.reduce(function(e,t){return 0===e?t:e},0)-1,y[s]}function g(e,t){return t.reduce(function(t,n){return t[n]=m(e,n),t},{})}function v(e){return!(isNaN(+e)||e instanceof Date)}function j(e){const n=function(n,r){const o={delimiter:e};return b(n,r?t.extend(r,o):o)};return n.responseType="text",n}function b(e,r){return r.header&&(e=r.header.map(t.stringValue).join(r.delimiter)+"\n"+e),n.dsvFormat(r.delimiter).parse(e+"")}function O(e,n){const r=n&&n.property?t.field(n.property):t.identity;return!t.isObject(e)||(o=e,"function"==typeof Buffer&&t.isFunction(Buffer.isBuffer)&&Buffer.isBuffer(o))?r(JSON.parse(e)):function(e,t){return t&&t.copy?JSON.parse(JSON.stringify(e)):e}(r(e));var o}function x(e,n){var o,i,s;return e=O(e,n),o=n&&(s=n.feature)?r.feature:n&&(s=n.mesh)?r.mesh:t.error("Missing TopoJSON feature or mesh parameter."),(i=(i=e.objects[s])?o(e,i):t.error("Invalid TopoJSON object: "+s))&&i.features||[i]}b.responseType="text",O.responseType="json",x.responseType="json";const N={dsv:b,csv:j(","),tsv:j("\t"),json:O,topojson:x};function T(e,t){return arguments.length>1?(N[e]=t,this):N.hasOwnProperty(e)?N[e]:null}var P=function(e,t){return function(n){return{options:n||{},sanitize:f,load:u,fileAccess:!!t,file:a(t),http:l(e)}}}("undefined"!=typeof fetch&&fetch,null);e.loader=P,e.read=function(e,n,r){const i=T((n=n||{}).type||"json");return i||t.error("Unknown data format type: "+n.type),e=i(e,n),n.parse&&function(e,t,n){if(e.length){n=n||o.timeParse;var r,i,s,u,f,a,c,l=e.columns||Object.keys(e[0]);for("auto"===t&&(t=g(e,l)),l=Object.keys(t),r=l.map(function(e){var r,i,s=t[e];if(s&&(0===s.indexOf("date:")||0===s.indexOf("utc:")))return("'"===(i=(r=s.split(/:(.+)?/,2))[1])[0]&&"'"===i[i.length-1]||'"'===i[0]&&'"'===i[i.length-1])&&(i=i.slice(1,-1)),"utc"===r[0]?o.utcParse(i):n(i);if(!d[s])throw Error("Illegal format pattern: "+e+":"+s);return d[s]}),u=0,a=e.length,c=l.length;u<a;++u)for(i=e[u],f=0;f<c;++f)s=l[f],i[s]=r[f](i[s])}}(e,n.parse,r),e.hasOwnProperty("columns")&&delete e.columns,e},e.inferType=m,e.inferTypes=g,e.typeParsers=d,e.format=N,e.formats=T,e.responseType=function(e){const t=T(e);return t&&t.responseType||"text"},Object.defineProperty(e,"__esModule",{value:!0})}); |
14
index.js
@@ -1,5 +0,8 @@ | ||
export { | ||
default as loader | ||
} from './src/loader'; | ||
import loaderFactory from './src/loader'; | ||
export var loader = loaderFactory( | ||
require('node-fetch'), | ||
require('fs') | ||
); | ||
export { | ||
@@ -16,4 +19,5 @@ default as read | ||
export { | ||
format as format, | ||
formats as formats | ||
format, | ||
formats, | ||
responseType | ||
} from './src/formats/index'; |
{ | ||
"name": "vega-loader", | ||
"version": "3.1.0", | ||
"version": "4.0.0", | ||
"description": "Network request and file loading utilities.", | ||
@@ -20,38 +20,27 @@ "keywords": [ | ||
"license": "BSD-3-Clause", | ||
"author": { | ||
"name": "Jeffrey Heer", | ||
"url": "http://idl.cs.washington.edu" | ||
}, | ||
"main": "build/vega-loader.js", | ||
"author": "Jeffrey Heer (http://idl.cs.washington.edu)", | ||
"main": "build/vega-loader.node.js", | ||
"module": "index", | ||
"jsnext:main": "index", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/vega/vega-loader.git" | ||
}, | ||
"repository": "vega/vega", | ||
"scripts": { | ||
"build": "npm run test && uglifyjs build/vega-loader.js -c -m -o build/vega-loader.min.js", | ||
"pretest": "rm -rf build && mkdir build&& rollup -f umd -g d3-dsv:d3,d3-time-format:d3,vega-util:vega,topojson-client:topojson -n vega -o build/vega-loader.js -- index.js", | ||
"test": "tape 'test/**/*-test.js' && eslint index.js src test", | ||
"prepublishOnly": "npm run build", | ||
"postpublish": "git push && git push --tags && zip -j build/vega-loader.zip -- LICENSE README.md build/vega-loader.js build/vega-loader.min.js" | ||
"rollup": "rollup -f cjs -g d3-dsv:d3,d3-time-format:d3,vega-util:vega,topojson-client:topojson -n vega -o build/vega-loader.node.js -- index.js && rollup -f umd -g d3-dsv:d3,d3-time-format:d3,vega-util:vega,topojson-client:topojson -n vega -o build/vega-loader.js -- index.browser.js", | ||
"prebuild": "rimraf build && mkdir build", | ||
"build": "yarn rollup", | ||
"postbuild": "terser build/vega-loader.js -c -m -o build/vega-loader.min.js", | ||
"pretest": "yarn prebuild && yarn rollup", | ||
"test": "tape 'test/**/*-test.js' && eslint index.js index.browser.js src test", | ||
"prepublishOnly": "yarn test && yarn build", | ||
"postpublish": "git push && git push --tags" | ||
}, | ||
"dependencies": { | ||
"d3-dsv": "^1.0.10", | ||
"d3-dsv": "^1.1.1", | ||
"d3-time-format": "^2.1.3", | ||
"node-fetch": "^2.3.0", | ||
"topojson-client": "^3.0.0", | ||
"vega-util": "^1.7.0" | ||
"vega-util": "^1.8.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "5", | ||
"rollup": "0.67.4", | ||
"tape": "4", | ||
"uglify-js": "3" | ||
}, | ||
"browser": { | ||
"buffer": false, | ||
"fs": false, | ||
"node-fetch": false | ||
"./build/vega-loader.node.js": "./build/vega-loader.js", | ||
"./index.js": "./index.browser.js" | ||
} | ||
} |
177
README.md
@@ -14,41 +14,25 @@ # vega-loader | ||
vega.<b>loader</b>([<i>options</i>]) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/loader.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/loader.js "Source") | ||
Creates a new loader instance with default *options*. A loader object | ||
provides methods for loading files from the network or disk, and for sanitizing | ||
requested URLs and filenames. If provided, the key-value pairs in the *options* | ||
object will be passed as default options to the various loader methods. | ||
Creates a new loader instance with default *options*. A loader object provides methods for loading files from the network or disk, and for sanitizing requested URLs and filenames. If provided, the key-value pairs in the *options* object will be passed as default options to the various loader methods. | ||
The *options* object can include the following entries: | ||
- *baseURL*: A base URL prefix to append to provided *uri* values. This can | ||
be useful for applications that load multiple data sets from the same domain. | ||
- *mode*: A string explicitly indicating the loading mode. One of `'file'` | ||
(server-side only) or `'http'`. If set to `'file'` mode, later *uri* parameters | ||
may safely omit a `'file://'` prefix. | ||
- *defaultProtocol*: The default protocol to use for protocol-relative *uri* | ||
values (e.g., `'//vega.github.io'`). Defaults to `'http'`. | ||
- *target*: The browser target attribute for hyperlinks. Only applies when | ||
sanitizing *uri* values for use as a hyperlink. | ||
- *http*: HTTP request parameters passed to underlying calls to | ||
[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API); see | ||
[RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed properties. | ||
- *mode*: A string explicitly indicating the loading mode. One of `'file'` (server-side only) or `'http'`. If set to `'file'` mode, later *uri* parameters may safely omit a `'file://'` prefix. | ||
- *defaultProtocol*: The default protocol to use for protocol-relative *uri* values (e.g., `'//vega.github.io'`). Defaults to `'http'`. | ||
- *target*: The browser `target` attribute for hyperlinks. Only applies when sanitizing *uri* values for use as a hyperlink. | ||
- *rel*: The browser `rel` attribute for hyperlinks. Only applies when sanitizing *uri* values for use as a hyperlink. | ||
- *http*: HTTP request parameters passed to underlying calls to [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API); see [RequestInit](https://fetch.spec.whatwg.org/#requestinit) for allowed properties. | ||
<a name="load" href="#load">#</a> | ||
loader.<b>load</b>(<i>uri</i>[, <i>options</i>]) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/loader.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/loader.js "Source") | ||
Loads a file from either the network or disk, and returns a | ||
[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) | ||
for asyncronously accessing the loaded content. This method does not perform | ||
any parsing, it simply returns the loaded data as either a Buffer or String | ||
instance, depending on the execution environment. To subsequently parse loaded | ||
data, use the [read](#read) method. | ||
Loads a file from either the network or disk, and returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) for asyncronously accessing the loaded content. This method does not perform any parsing, it simply returns the loaded data as either a Buffer or String instance, depending on the execution environment. To subsequently parse loaded data, use the [read](#read) method. | ||
The *uri* argument is a value indicating the file to load. This is typically | ||
either an absolute or relative URL string. If running server-side via node.js, | ||
this argument might also be a file path (e.g., `'file:///path/to/file.txt'`). | ||
The *uri* argument is a value indicating the file to load. This is typically either an absolute or relative URL string. If running server-side via node.js, this argument might also be a file path (e.g., `'file:///path/to/file.txt'`). | ||
If provided, the *options* argument will be combined with any default options | ||
passed to the [loader](#loader) constructor. In the case of identical property | ||
names, values from the *options* argument for this method will be used. | ||
If provided, the *options* argument will be combined with any default options passed to the [loader](#loader) constructor. In the case of identical property names, values from the *options* argument for this method will be used. | ||
@@ -66,42 +50,21 @@ ```js | ||
loader.<b>sanitize</b>(<i>uri</i>, <i>options</i>) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/loader.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/loader.js "Source") | ||
URI sanitizer function, which takes a *uri* and *options* object as input, | ||
and returns a Promise that resolves to a return object that includes a | ||
sanitized URL under the *href* property. This method is used internally by | ||
[load](#load) to ensure the URL is valid and to add additional protocol and | ||
hostname information, if needed. This method accepts the same *options* object | ||
accepted by [load](#load) and returns a Promise. If sanitization is successful, | ||
the Promise resolves to a return object containing the URL string as (_href_), | ||
along with a non-enumerable boolean _localFile_ flag, indicating if the file | ||
should be loaded from the local filesystem. The Promise rejects if the *uri* | ||
is invalid or disallowed. This method is over-writable for clients who wish to | ||
implement custom sanitization. | ||
URI sanitizer function, which takes a *uri* and *options* object as input, and returns a Promise that resolves to a return object that includes a sanitized URL under the *href* property. This method is used internally by [load](#load) to ensure the URL is valid and to add additional protocol and hostname information, if needed. This method accepts the same *options* object accepted by [load](#load) and returns a Promise. If sanitization is successful, the Promise resolves to a return object containing the URL string as (_href_), along with a non-enumerable boolean _localFile_ flag, indicating if the file should be loaded from the local filesystem. The Promise rejects if the *uri* is invalid or disallowed. This method is over-writable for clients who wish to implement custom sanitization. | ||
If provided, the *options* argument will be combined with any default options | ||
passed to the [loader](#loader) constructor. In the case of identical property | ||
names, values from the *options* argument for this method will be used. | ||
If provided, the *options* argument will be combined with any default options passed to the [loader](#loader) constructor. In the case of identical property names, values from the *options* argument for this method will be used. | ||
<a name="load_http" href="load_http">#</a> | ||
loader.<b>http</b>(<i>url</i>, <i>options</i>) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/loader.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/loader.js "Source") | ||
Function used internally by [load](#load) for servicing HTTP requests. Uses | ||
[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) by default. | ||
Clients may overwrite this method to perform custom HTTP request handling. | ||
Function used internally by [load](#load) for servicing HTTP requests. Uses [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) by default. Clients may overwrite this method to perform custom HTTP request handling. | ||
If provided, the *options* argument may include any valid fetch | ||
[RequestInit](https://fetch.spec.whatwg.org/#requestinit) properties. The | ||
provided *options* will be combined with any default options passed to the | ||
[loader](#loader) constructor under the *http* property. In the case of | ||
identical property names, values from the *options* argument for this | ||
method will be used. | ||
If provided, the *options* argument may include any valid fetch [RequestInit](https://fetch.spec.whatwg.org/#requestinit) properties. The provided *options* will be combined with any default options passed to the [loader](#loader) constructor under the *http* property. In the case of identical property names, values from the *options* argument for this method will be used. | ||
<a name="load_file" href="load_file">#</a> | ||
loader.<b>file</b>(<i>filename</i>) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/loader.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/loader.js "Source") | ||
Function used internally by [load](#load) for local file system requests. This | ||
method is over-writable for clients who wish to implement custom file loading. | ||
Uses the node.js [fs](https://nodejs.org/api/fs.html) module by default. | ||
Function used internally by [load](#load) for local file system requests. This method is over-writable for clients who wish to implement custom file loading. Uses the node.js [fs](https://nodejs.org/api/fs.html) module by default. | ||
@@ -112,28 +75,13 @@ ### Data Format Parsing | ||
vega.<b>read</b>(<i>data</i>, <i>schema</i>[, <i>dateParse</i>]) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/read.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/read.js "Source") | ||
Parse loaded *data* according to a given format *schema*. The *data* argument | ||
should be either a String or Buffer instance, typically the result of | ||
calling [load](#load). | ||
Parse loaded *data* according to a given format *schema*. The *data* argument should be either a String or Buffer instance, typically the result of calling [load](#load). | ||
The *schema* object contents may depend on the data format (see below). | ||
Common options include: | ||
The *schema* object contents may depend on the data format (see below). Common options include: | ||
- *type*: The data format type, such as `json`, `csv`, `tsv`, or `topojson`. | ||
- *property*: For JSON types, specifies a property of the loaded JSON to | ||
reference. This is useful if a loaded JSON file contains multiple data sets | ||
and one would like to parse data under a specific property. | ||
- *parse*: When set to `'auto'` (the default), the method will perform type | ||
inference (using the [inferTypes](#inferTypes) method) to determine data types | ||
of each field. Alternatively, callers can specify parsing rules by providing | ||
an object mapping field names to data types (for example: `{'timestamp': | ||
'date', 'price': 'number'}`). The valid data type options are `'boolean'`, | ||
`'integer'`, `'number'`, `'date'`, and `'string'`. | ||
- *property*: For JSON types, specifies a property of the loaded JSON to reference. This is useful if a loaded JSON file contains multiple data sets and one would like to parse data under a specific property. | ||
- *parse*: When set to `'auto'` (the default), the method will perform type inference (using the [inferTypes](#inferTypes) method) to determine data types of each field. Alternatively, callers can specify parsing rules by providing an object mapping field names to data types (for example: `{'timestamp': 'date', 'price': 'number'}`). The valid data type options are `'boolean'`, `'integer'`, `'number'`, `'date'`, and `'string'`. | ||
The `'date'` data type also accepts an optional format string | ||
(`'date:format'`). If provided, the optional *dateParse* function is used to | ||
generate date-time parsers for a date format string. If *dateParse* is | ||
unspecified, the [d3-time-format](https://github.com/d3/d3-time-format) | ||
library is used by default. Date-time format strings may be quoted | ||
(`date:'%A'`), but quoting is not required. In addition, parsing of | ||
date-time format strings to UTC time is supported (`'utc:format'`). | ||
The `'date'` data type also accepts an optional format string (`'date:format'`). If provided, the optional *dateParse* function is used to generate date-time parsers for a date format string. If *dateParse* is unspecified, the [d3-time-format](https://github.com/d3/d3-time-format) library is used by default. Date-time format strings may be quoted (`date:'%A'`), but quoting is not required. In addition, parsing of date-time format strings to UTC time is supported (`'utc:format'`). | ||
@@ -169,67 +117,40 @@ ```js | ||
vega.<b>inferType</b>(<i>values</i>[, <i>field</i>]) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/type.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/type.js "Source") | ||
Given an array of *values*, infers their data type as one of `'boolean'`, | ||
`'integer'`, `'number'`, `'date'`, or `'string'`. An optional *field* accessor | ||
can be used to first extract values from the input array, and is equivalent to | ||
first calling `values.map(field)`. | ||
Given an array of *values*, infers their data type as one of `'boolean'`, `'integer'`, `'number'`, `'date'`, or `'string'`. An optional *field* accessor can be used to first extract values from the input array, and is equivalent to first calling `values.map(field)`. | ||
<a name="inferTypes" href="#inferTypes">#</a> | ||
vega.<b>inferTypes</b>(<i>data</i>, <i>fields</i>) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/type.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/type.js "Source") | ||
Given an array of *data* objects and a list of string-typed field names | ||
(*fields*), infers the data type for each field. Returns an object that maps | ||
field names to inferred types, determined using the [inferType](#inferType) | ||
method. | ||
Given an array of *data* objects and a list of string-typed field names (*fields*), infers the data type for each field. Returns an object that maps field names to inferred types, determined using the [inferType](#inferType) method. | ||
<a name="typeParsers" href="#typeParsers">#</a> | ||
vega.<b>typeParsers</b> | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/type.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/type.js "Source") | ||
An object containing a set of parsing functions for converting input values | ||
to a specified data type. All parsing functions return `null` if the input | ||
is `null`, `undefined` or the empty string (`''`). | ||
An object containing a set of parsing functions for converting input values to a specified data type. All parsing functions return `null` if the input is `null`, `undefined` or the empty string (`''`). | ||
The supported functions are: | ||
- typeParsers.<b>boolean</b>(<i>value</i>): Parse the input *value* to a | ||
Boolean. | ||
- typeParsers.<b>integer</b>(<i>value</i>): Parse the input *value* to an | ||
integer Number. | ||
- typeParsers.<b>number</b>(<i>value</i>): Parse the input *value* to a | ||
Number. | ||
- typeParsers.<b>date</b>(<i>value</i>[, <i>parser</i>]): Parse the input | ||
*value* to a Date. If provided, the *parser* function is used to interpret | ||
the *value*; otherwise `Date.parse` is used. | ||
- typeParsers.<b>string</b>(<i>value</i>): Parse the input *value* to a String. | ||
If *value* is not already string-typed, it is coerced to a String. | ||
- typeParsers.<b>boolean</b>(<i>value</i>): Parse the input *value* to a Boolean. | ||
- typeParsers.<b>integer</b>(<i>value</i>): Parse the input *value* to an integer Number. | ||
- typeParsers.<b>number</b>(<i>value</i>): Parse the input *value* to a Number. | ||
- typeParsers.<b>date</b>(<i>value</i>[, <i>parser</i>]): Parse the input *value* to a Date. If provided, the *parser* function is used to interpret the *value*; otherwise `Date.parse` is used. | ||
- typeParsers.<b>string</b>(<i>value</i>): Parse the input *value* to a String. If *value* is not already string-typed, it is coerced to a String. | ||
<a name="formats" href="#formats">#</a> | ||
vega.<b>formats</b>(<i>name</i>[, <i>format</i>]) | ||
[<>](https://github.com/vega/vega-loader/blob/master/src/formats/index.js "Source") | ||
[<>](https://github.com/vega/vega/blob/master/packages/vega-loader/src/formats/index.js "Source") | ||
Registry function for data format parsers. If invoked with two arguments, adds | ||
a new *format* parser with the provided *name*. Otherwise, returns an existing | ||
parser with the given *name*. The method signature of a format parser is: | ||
Registry function for data format parsers. If invoked with two arguments, adds a new *format* parser with the provided *name*. Otherwise, returns an existing parser with the given *name*. The method signature of a format parser is: | ||
- <b>format</b>(<i>data</i>, <i>options</i>) | ||
A format parser that accepts two arguments, the input *data* to parse | ||
(e.g., a block of CSV text) and a set of format-specific *options*. | ||
The following data formats are registered by default: | ||
- *dsv*: Delimiter-separated values format. Each line of text is a record, | ||
with each field separated by a delimiter string. Accepts a *delimiter* option | ||
indicating the delimiter string used to separate field values. | ||
- *csv*: Comma-separated values format. A *dsv* instance with a comma (`,`) | ||
delimiter. | ||
- *tsv*: Tab-separated values format. A *dsv* instance with a tab (`\t`) | ||
delimiter. | ||
- *json*: [JavaScript Object Notation (JSON)](https://en.wikipedia.org/wiki/JSON) | ||
format. Accepts a *property* option, indicating a sub-property of the parsed | ||
JSON to return; useful if a data array is nested within a larger object. | ||
- *topojson*: [TopoJSON](https://github.com/mbostock/topojson/wiki) format for | ||
compressed encoding of geographic data. Requires either a *feature* option | ||
indicating the name of the geographic feature to extract (e.g., extracts | ||
individual paths for all countries), or a *mesh* option indicating a feature | ||
name for which a single mesh should be extracted (e.g., all country | ||
boundaries in a single path). Please see the | ||
[TopoJSON documentation](https://github.com/mbostock/topojson/wiki) for more. | ||
A format parser that accepts two arguments, the input *data* to parse (e.g., a block of CSV text) and a set of format-specific *options*. The following data formats are registered by default: | ||
- *dsv*: Delimiter-separated values format. Each line of text is a record, with each field separated by a delimiter string. Accepts a *delimiter* option indicating the delimiter string used to separate field values. | ||
- *csv*: Comma-separated values format. A *dsv* instance with a comma (`,`) delimiter. | ||
- *tsv*: Tab-separated values format. A *dsv* instance with a tab (`\t`) delimiter. | ||
- *json*: [JavaScript Object Notation (JSON)](https://en.wikipedia.org/wiki/JSON) format. Accepts a *property* option, indicating a sub-property of the parsed JSON to return; useful if a data array is nested within a larger object. | ||
- *topojson*: [TopoJSON](https://github.com/mbostock/topojson/wiki) format for compressed encoding of geographic data. Requires either a *feature* option indicating the name of the geographic feature to extract (e.g., extracts individual paths for all countries), or a *mesh* option indicating a feature name for which a single mesh should be extracted (e.g., all country boundaries in a single path). Please see the [TopoJSON documentation](https://github.com/mbostock/topojson/wiki) for more. |
@@ -5,6 +5,10 @@ import {dsvFormat} from 'd3-dsv'; | ||
export function delimitedFormat(delimiter) { | ||
return function(data, format) { | ||
var delim = {delimiter: delimiter}; | ||
const parse = function(data, format) { | ||
const delim = {delimiter: delimiter}; | ||
return dsv(data, format ? extend(format, delim) : delim); | ||
}; | ||
parse.responseType = 'text'; | ||
return parse; | ||
} | ||
@@ -18,3 +22,5 @@ | ||
} | ||
return dsvFormat(format.delimiter).parse(data+''); | ||
return dsvFormat(format.delimiter).parse(data + ''); | ||
} | ||
dsv.responseType = 'text'; |
@@ -5,3 +5,3 @@ import {default as dsv, delimitedFormat} from './dsv'; | ||
export var format = { | ||
export const format = { | ||
dsv: dsv, | ||
@@ -22,1 +22,6 @@ csv: delimitedFormat(','), | ||
} | ||
export function responseType(type) { | ||
const f = formats(type); | ||
return f && f.responseType || 'text'; | ||
} |
@@ -8,4 +8,4 @@ import {field, identity, isFunction, isObject} from 'vega-util'; | ||
export default function(data, format) { | ||
var prop = (format && format.property) ? field(format.property) : identity; | ||
export default function json(data, format) { | ||
const prop = (format && format.property) ? field(format.property) : identity; | ||
return isObject(data) && !isBuffer(data) | ||
@@ -16,2 +16,4 @@ ? parseJSON(prop(data)) | ||
json.responseType = 'json'; | ||
function parseJSON(data, format) { | ||
@@ -18,0 +20,0 @@ return (format && format.copy) |
@@ -5,3 +5,3 @@ import json from './json'; | ||
export default function(data, format) { | ||
export default function topojson(data, format) { | ||
var method, object, property; | ||
@@ -20,1 +20,3 @@ data = json(data, format); | ||
} | ||
topojson.responseType = 'json'; |
@@ -1,2 +0,2 @@ | ||
import {extend, isFunction, stringValue} from 'vega-util'; | ||
import {extend, error, isFunction, stringValue} from 'vega-util'; | ||
@@ -11,14 +11,22 @@ // Matches absolute URLs with optional protocol | ||
/** | ||
* Creates a new loader instance that provides methods for requesting files | ||
* from either the network or disk, and for sanitizing request URIs. | ||
* @param {object} [options] - Optional default loading options to use. | ||
* @return {object} - A new loader instance. | ||
* Factory for a loader constructor that provides methods for requesting | ||
* files from either the network or disk, and for sanitizing request URIs. | ||
* @param {function} fetch - The Fetch API for HTTP network requests. | ||
* If null or undefined, HTTP loading will be disabled. | ||
* @param {object} fs - The file system interface for file loading. | ||
* If null or undefined, local file loading will be disabled. | ||
* @return {function} A loader constructor with the following signature: | ||
* param {object} [options] - Optional default loading options to use. | ||
* return {object} - A new loader instance. | ||
*/ | ||
export default function(options) { | ||
return { | ||
options: options || {}, | ||
sanitize: sanitize, | ||
load: load, | ||
file: file, | ||
http: http | ||
export default function(fetch, fs) { | ||
return function(options) { | ||
return { | ||
options: options || {}, | ||
sanitize: sanitize, | ||
load: load, | ||
fileAccess: !!fs, | ||
file: fileLoader(fs), | ||
http: httpLoader(fetch) | ||
}; | ||
}; | ||
@@ -37,11 +45,9 @@ } | ||
*/ | ||
function load(uri, options) { | ||
var loader = this; | ||
return loader.sanitize(uri, options) | ||
.then(function(opt) { | ||
var url = opt.href; | ||
return opt.localFile | ||
? loader.file(url) | ||
: loader.http(url, options); | ||
}); | ||
async function load(uri, options) { | ||
const opt = await this.sanitize(uri, options), | ||
url = opt.href; | ||
return opt.localFile | ||
? this.file(url) | ||
: this.http(url, options); | ||
} | ||
@@ -59,102 +65,120 @@ | ||
*/ | ||
function sanitize(uri, options) { | ||
async function sanitize(uri, options) { | ||
options = extend({}, this.options, options); | ||
return new Promise(function(accept, reject) { | ||
var result = {href: null}, | ||
isFile, hasProtocol, loadFile, base; | ||
const fileAccess = this.fileAccess, | ||
result = {href: null}; | ||
if (uri == null || typeof uri !== 'string') { | ||
reject('Sanitize failure, invalid URI: ' + stringValue(uri)); | ||
return; | ||
} | ||
let isFile, hasProtocol, loadFile, base; | ||
hasProtocol = protocol_re.test(uri); | ||
if (uri == null || typeof uri !== 'string') { | ||
error('Sanitize failure, invalid URI: ' + stringValue(uri)); | ||
} | ||
// if relative url (no protocol/host), prepend baseURL | ||
if ((base = options.baseURL) && !hasProtocol) { | ||
// Ensure that there is a slash between the baseURL (e.g. hostname) and url | ||
if (!startsWith(uri, '/') && base[base.length-1] !== '/') { | ||
uri = '/' + uri; | ||
} | ||
uri = base + uri; | ||
hasProtocol = protocol_re.test(uri); | ||
// if relative url (no protocol/host), prepend baseURL | ||
if ((base = options.baseURL) && !hasProtocol) { | ||
// Ensure that there is a slash between the baseURL (e.g. hostname) and url | ||
if (!uri.startsWith('/') && base[base.length-1] !== '/') { | ||
uri = '/' + uri; | ||
} | ||
uri = base + uri; | ||
} | ||
// should we load from file system? | ||
loadFile = (isFile = startsWith(uri, fileProtocol)) | ||
|| options.mode === 'file' | ||
|| options.mode !== 'http' && !hasProtocol && fs(); | ||
// should we load from file system? | ||
loadFile = (isFile = uri.startsWith(fileProtocol)) | ||
|| options.mode === 'file' | ||
|| options.mode !== 'http' && !hasProtocol && fileAccess; | ||
if (isFile) { | ||
// strip file protocol | ||
uri = uri.slice(fileProtocol.length); | ||
} else if (startsWith(uri, '//')) { | ||
if (options.defaultProtocol === 'file') { | ||
// if is file, strip protocol and set loadFile flag | ||
uri = uri.slice(2); | ||
loadFile = true; | ||
} else { | ||
// if relative protocol (starts with '//'), prepend default protocol | ||
uri = (options.defaultProtocol || 'http') + ':' + uri; | ||
} | ||
if (isFile) { | ||
// strip file protocol | ||
uri = uri.slice(fileProtocol.length); | ||
} else if (uri.startsWith('//')) { | ||
if (options.defaultProtocol === 'file') { | ||
// if is file, strip protocol and set loadFile flag | ||
uri = uri.slice(2); | ||
loadFile = true; | ||
} else { | ||
// if relative protocol (starts with '//'), prepend default protocol | ||
uri = (options.defaultProtocol || 'http') + ':' + uri; | ||
} | ||
} | ||
// set non-enumerable mode flag to indicate local file load | ||
Object.defineProperty(result, 'localFile', {value: !!loadFile}); | ||
// set non-enumerable mode flag to indicate local file load | ||
Object.defineProperty(result, 'localFile', {value: !!loadFile}); | ||
// set uri | ||
result.href = uri; | ||
// set uri | ||
result.href = uri; | ||
// set default result target, if specified | ||
if (options.target) { | ||
result.target = options.target + ''; | ||
} | ||
// set default result target, if specified | ||
if (options.target) { | ||
result.target = options.target + ''; | ||
} | ||
// return | ||
accept(result); | ||
}); | ||
// set default result rel, if specified (#1542) | ||
if (options.rel) { | ||
result.rel = options.rel + ''; | ||
} | ||
// return | ||
return result; | ||
} | ||
/** | ||
* HTTP request loader. | ||
* @param {string} url - The url to request. | ||
* @param {object} options - An options hash. | ||
* @return {Promise} - A promise that resolves to the file contents. | ||
* File system loader factory. | ||
* @param {object} fs - The file system interface. | ||
* @return {function} - A file loader with the following signature: | ||
* param {string} filename - The file system path to load. | ||
* param {string} filename - The file system path to load. | ||
* return {Promise} A promise that resolves to the file contents. | ||
*/ | ||
function http(url, options) { | ||
return request(url, extend({}, this.options.http, options)) | ||
.then(function(response) { | ||
if (!response.ok) throw response.status + '' + response.statusText; | ||
return response.text(); | ||
}); | ||
function fileLoader(fs) { | ||
return fs | ||
? function(filename) { | ||
return new Promise(function(accept, reject) { | ||
fs.readFile(filename, function(error, data) { | ||
if (error) reject(error); | ||
else accept(data); | ||
}); | ||
}); | ||
} | ||
: fileReject; | ||
} | ||
/** | ||
* File system loader. | ||
* @param {string} filename - The file system path to load. | ||
* @return {Promise} - A promise that resolves to the file contents. | ||
* Default file system loader that simply rejects. | ||
*/ | ||
function file(filename) { | ||
return new Promise(function(accept, reject) { | ||
var f = fs(); | ||
f ? f.readFile(filename, function(error, data) { | ||
if (error) reject(error); | ||
else accept(data); | ||
}) | ||
: reject('No file system access for ' + filename); | ||
}); | ||
async function fileReject() { | ||
error('No file system access.'); | ||
} | ||
function request(url, init) { | ||
var f = typeof fetch === 'function' ? fetch : require('node-fetch'); | ||
return f ? f(url, init) : Promise.reject('No fetch method available.'); | ||
} | ||
/** | ||
* HTTP request handler factory. | ||
* @param {function} fetch - The Fetch API method. | ||
* @return {function} - An http loader with the following signature: | ||
* param {string} url - The url to request. | ||
* param {object} options - An options hash. | ||
* return {Promise} - A promise that resolves to the file contents. | ||
*/ | ||
function httpLoader(fetch) { | ||
return fetch | ||
? async function(url, options) { | ||
const opt = extend({}, this.options.http, options), | ||
type = options && options.response, | ||
response = await fetch(url, opt); | ||
function fs() { | ||
var fs = typeof require === 'function' && require('fs'); | ||
return fs && isFunction(fs.readFile) ? fs : null; | ||
return !response.ok | ||
? error(response.status + '' + response.statusText) | ||
: isFunction(response[type]) ? response[type]() | ||
: response.text(); | ||
} | ||
: httpReject; | ||
} | ||
function startsWith(string, query) { | ||
return string == null ? false : string.lastIndexOf(query, 0) === 0; | ||
/** | ||
* Default http request handler that simply rejects. | ||
*/ | ||
async function httpReject() { | ||
error('No HTTP fetch method available.'); | ||
} |
@@ -9,3 +9,3 @@ import {inferTypes, typeParsers} from './type'; | ||
var reader = formats(schema.type || 'json'); | ||
const reader = formats(schema.type || 'json'); | ||
if (!reader) error('Unknown data format type: ' + schema.type); | ||
@@ -12,0 +12,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
54257
0
1057
153
15
Updatedd3-dsv@^1.1.1
Updatedvega-util@^1.8.0