flatfile-csv-importer
Version:
A simple adapter for elegantly importing CSV files via flatfile.io (Typescript, ES6, Browser)
1,622 lines (1,411 loc) • 74.4 kB
JavaScript
var FlatfileImporter = (function () {
'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __awaiter(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function unwrapExports (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var polyfill = createCommonjsModule(function (module, exports) {
(function (global, factory) {
factory();
}(commonjsGlobal, (function () { 'use strict';
// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;
function noop() {}
// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
return function() {
fn.apply(thisArg, arguments);
};
}
function Promise(fn) {
if (!(this instanceof Promise))
throw new TypeError('Promises must be constructed via new');
if (typeof fn !== 'function') throw new TypeError('not a function');
this._state = 0;
this._handled = false;
this._value = undefined;
this._deferreds = [];
doResolve(fn, this);
}
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
Promise._immediateFn(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
}
function resolve(self, newValue) {
try {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self)
throw new TypeError('A promise cannot be resolved with itself.');
if (
newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')
) {
var then = newValue.then;
if (newValue instanceof Promise) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
Promise._immediateFn(function() {
if (!self._handled) {
Promise._unhandledRejectionFn(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, self) {
var done = false;
try {
fn(
function(value) {
if (done) return;
done = true;
resolve(self, value);
},
function(reason) {
if (done) return;
done = true;
reject(self, reason);
}
);
} catch (ex) {
if (done) return;
done = true;
reject(self, ex);
}
}
Promise.prototype['catch'] = function(onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
var prom = new this.constructor(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise.prototype['finally'] = function(callback) {
var constructor = this.constructor;
return this.then(
function(value) {
return constructor.resolve(callback()).then(function() {
return value;
});
},
function(reason) {
return constructor.resolve(callback()).then(function() {
return constructor.reject(reason);
});
}
);
};
Promise.all = function(arr) {
return new Promise(function(resolve, reject) {
if (!arr || typeof arr.length === 'undefined')
throw new TypeError('Promise.all accepts an array');
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.resolve = function(value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.race = function(values) {
return new Promise(function(resolve, reject) {
for (var i = 0, len = values.length; i < len; i++) {
values[i].then(resolve, reject);
}
});
};
// Use polyfill for setImmediate for performance gains
Promise._immediateFn =
(typeof setImmediate === 'function' &&
function(fn) {
setImmediate(fn);
}) ||
function(fn) {
setTimeoutFunc(fn, 0);
};
Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
if (typeof console !== 'undefined' && console) {
console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
}
};
var globalNS = (function() {
// the only reliable means to get the global object is
// `Function('return this')()`
// However, this causes CSP violations in Chrome apps.
if (typeof self !== 'undefined') {
return self;
}
if (typeof window !== 'undefined') {
return window;
}
if (typeof commonjsGlobal !== 'undefined') {
return commonjsGlobal;
}
throw new Error('unable to locate global object');
})();
if (!globalNS.Promise) {
globalNS.Promise = Promise;
}
})));
});
var eventemitter3 = createCommonjsModule(function (module) {
'use strict';
var has = Object.prototype.hasOwnProperty
, prefix = '~';
/**
* Constructor to create a storage for our `EE` objects.
* An `Events` instance is a plain object whose properties are event names.
*
* @constructor
* @private
*/
function Events() {}
//
// We try to not inherit from `Object.prototype`. In some engines creating an
// instance in this way is faster than calling `Object.create(null)` directly.
// If `Object.create(null)` is not supported we prefix the event names with a
// character to make sure that the built-in object properties are not
// overridden or used as an attack vector.
//
if (Object.create) {
Events.prototype = Object.create(null);
//
// This hack is needed because the `__proto__` property is still inherited in
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
//
if (!new Events().__proto__) prefix = false;
}
/**
* Representation of a single event listener.
*
* @param {Function} fn The listener function.
* @param {*} context The context to invoke the listener with.
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
* @constructor
* @private
*/
function EE(fn, context, once) {
this.fn = fn;
this.context = context;
this.once = once || false;
}
/**
* Add a listener for a given event.
*
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} context The context to invoke the listener with.
* @param {Boolean} once Specify if the listener is a one-time listener.
* @returns {EventEmitter}
* @private
*/
function addListener(emitter, event, fn, context, once) {
if (typeof fn !== 'function') {
throw new TypeError('The listener must be a function');
}
var listener = new EE(fn, context || emitter, once)
, evt = prefix ? prefix + event : event;
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
else emitter._events[evt] = [emitter._events[evt], listener];
return emitter;
}
/**
* Clear event by name.
*
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
* @param {(String|Symbol)} evt The Event name.
* @private
*/
function clearEvent(emitter, evt) {
if (--emitter._eventsCount === 0) emitter._events = new Events();
else delete emitter._events[evt];
}
/**
* Minimal `EventEmitter` interface that is molded against the Node.js
* `EventEmitter` interface.
*
* @constructor
* @public
*/
function EventEmitter() {
this._events = new Events();
this._eventsCount = 0;
}
/**
* Return an array listing the events for which the emitter has registered
* listeners.
*
* @returns {Array}
* @public
*/
EventEmitter.prototype.eventNames = function eventNames() {
var names = []
, events
, name;
if (this._eventsCount === 0) return names;
for (name in (events = this._events)) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events));
}
return names;
};
/**
* Return the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Array} The registered listeners.
* @public
*/
EventEmitter.prototype.listeners = function listeners(event) {
var evt = prefix ? prefix + event : event
, handlers = this._events[evt];
if (!handlers) return [];
if (handlers.fn) return [handlers.fn];
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
ee[i] = handlers[i].fn;
}
return ee;
};
/**
* Return the number of listeners listening to a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Number} The number of listeners.
* @public
*/
EventEmitter.prototype.listenerCount = function listenerCount(event) {
var evt = prefix ? prefix + event : event
, listeners = this._events[evt];
if (!listeners) return 0;
if (listeners.fn) return 1;
return listeners.length;
};
/**
* Calls each of the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Boolean} `true` if the event had listeners, else `false`.
* @public
*/
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return false;
var listeners = this._events[evt]
, len = arguments.length
, args
, i;
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
switch (len) {
case 1: return listeners.fn.call(listeners.context), true;
case 2: return listeners.fn.call(listeners.context, a1), true;
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
}
for (i = 1, args = new Array(len -1); i < len; i++) {
args[i - 1] = arguments[i];
}
listeners.fn.apply(listeners.context, args);
} else {
var length = listeners.length
, j;
for (i = 0; i < length; i++) {
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
switch (len) {
case 1: listeners[i].fn.call(listeners[i].context); break;
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
default:
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
args[j - 1] = arguments[j];
}
listeners[i].fn.apply(listeners[i].context, args);
}
}
}
return true;
};
/**
* Add a listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.on = function on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
/**
* Add a one-time listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.once = function once(event, fn, context) {
return addListener(this, event, fn, context, true);
};
/**
* Remove the listeners of a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn Only remove the listeners that match this function.
* @param {*} context Only remove the listeners that have this context.
* @param {Boolean} once Only remove one-time listeners.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return this;
if (!fn) {
clearEvent(this, evt);
return this;
}
var listeners = this._events[evt];
if (listeners.fn) {
if (
listeners.fn === fn &&
(!once || listeners.once) &&
(!context || listeners.context === context)
) {
clearEvent(this, evt);
}
} else {
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
if (
listeners[i].fn !== fn ||
(once && !listeners[i].once) ||
(context && listeners[i].context !== context)
) {
events.push(listeners[i]);
}
}
//
// Reset the array, or remove it completely if we have no more listeners.
//
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
else clearEvent(this, evt);
}
return this;
};
/**
* Remove all listeners, or those of the specified event.
*
* @param {(String|Symbol)} [event] The event name.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
var evt;
if (event) {
evt = prefix ? prefix + event : event;
if (this._events[evt]) clearEvent(this, evt);
} else {
this._events = new Events();
this._eventsCount = 0;
}
return this;
};
//
// Alias methods names because people roll like that.
//
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
//
// Expose the prefix.
//
EventEmitter.prefixed = prefix;
//
// Allow `EventEmitter` to be imported as module namespace.
//
EventEmitter.EventEmitter = EventEmitter;
//
// Expose the module.
//
{
module.exports = EventEmitter;
}
});
var eventemitter3_1 = eventemitter3.EventEmitter;
/* eslint no-void: "off" */
// Loaded ready states
var loadedStates = ['interactive', 'complete'];
// Return Promise
var whenDomReady = function whenDomReady(cb, doc) {
return new Promise(function (resolve) {
// Allow doc to be passed in as the lone first param
if (cb && typeof cb !== 'function') {
doc = cb;
cb = null;
}
// Use global document if we don't have one
doc = doc || window.document;
// Handle DOM load
var done = function done() {
return resolve(void (cb && setTimeout(cb)));
};
// Resolve now if DOM has already loaded
// Otherwise wait for DOMContentLoaded
if (loadedStates.indexOf(doc.readyState) !== -1) {
done();
} else {
doc.addEventListener('DOMContentLoaded', done);
}
});
};
// Promise chain helper
whenDomReady.resume = function (doc) {
return function (val) {
return whenDomReady(doc).then(function () {
return val;
});
};
};
var containers = []; // will store container HTMLElement references
var styleElements = []; // will store {prepend: HTMLElement, append: HTMLElement}
var usage = 'insert-css: You need to provide a CSS string. Usage: insertCss(cssString[, options]).';
function insertCss(css, options) {
options = options || {};
if (css === undefined) {
throw new Error(usage);
}
var position = options.prepend === true ? 'prepend' : 'append';
var container = options.container !== undefined ? options.container : document.querySelector('head');
var containerId = containers.indexOf(container);
// first time we see this container, create the necessary entries
if (containerId === -1) {
containerId = containers.push(container) - 1;
styleElements[containerId] = {};
}
// try to get the correponding container + position styleElement, create it otherwise
var styleElement;
if (styleElements[containerId] !== undefined && styleElements[containerId][position] !== undefined) {
styleElement = styleElements[containerId][position];
} else {
styleElement = styleElements[containerId][position] = createStyleElement();
if (position === 'prepend') {
container.insertBefore(styleElement, container.childNodes[0]);
} else {
container.appendChild(styleElement);
}
}
// strip potential UTF-8 BOM if css was read from a file
if (css.charCodeAt(0) === 0xFEFF) { css = css.substr(1, css.length); }
// actually add the stylesheet
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText += css;
} else {
styleElement.textContent += css;
}
return styleElement;
}
function createStyleElement() {
var styleElement = document.createElement('style');
styleElement.setAttribute('type', 'text/css');
return styleElement;
}
var insertCss_1 = insertCss;
var insertCss_2 = insertCss;
insertCss_1.insertCss = insertCss_2;
var elementClass = function(opts) {
return new ElementClass(opts)
};
function indexOf(arr, prop) {
if (arr.indexOf) return arr.indexOf(prop)
for (var i = 0, len = arr.length; i < len; i++)
if (arr[i] === prop) return i
return -1
}
function ElementClass(opts) {
if (!(this instanceof ElementClass)) return new ElementClass(opts)
var self = this;
if (!opts) opts = {};
// similar doing instanceof HTMLElement but works in IE8
if (opts.nodeType) opts = {el: opts};
this.opts = opts;
this.el = opts.el || document.body;
if (typeof this.el !== 'object') this.el = document.querySelector(this.el);
}
ElementClass.prototype.add = function(className) {
var el = this.el;
if (!el) return
if (el.className === "") return el.className = className
var classes = el.className.split(' ');
if (indexOf(classes, className) > -1) return classes
classes.push(className);
el.className = classes.join(' ');
return classes
};
ElementClass.prototype.remove = function(className) {
var el = this.el;
if (!el) return
if (el.className === "") return
var classes = el.className.split(' ');
var idx = indexOf(classes, className);
if (idx > -1) classes.splice(idx, 1);
el.className = classes.join(' ');
return classes
};
ElementClass.prototype.has = function(className) {
var el = this.el;
if (!el) return
var classes = el.className.split(' ');
return indexOf(classes, className) > -1
};
ElementClass.prototype.toggle = function(className) {
var el = this.el;
if (!el) return
if (this.has(className)) this.remove(className);
else this.add(className);
};
var lib = createCommonjsModule(function (module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.ERR_IFRAME_ALREADY_ATTACHED_TO_DOM = exports.ERR_NOT_IN_IFRAME = exports.ERR_CONNECTION_TIMEOUT = exports.ERR_CONNECTION_DESTROYED = void 0;
var HANDSHAKE = 'handshake';
var HANDSHAKE_REPLY = 'handshake-reply';
var CALL = 'call';
var REPLY = 'reply';
var FULFILLED = 'fulfilled';
var REJECTED = 'rejected';
var MESSAGE = 'message';
var DATA_CLONE_ERROR = 'DataCloneError';
var ERR_CONNECTION_DESTROYED = 'ConnectionDestroyed';
exports.ERR_CONNECTION_DESTROYED = ERR_CONNECTION_DESTROYED;
var ERR_CONNECTION_TIMEOUT = 'ConnectionTimeout';
exports.ERR_CONNECTION_TIMEOUT = ERR_CONNECTION_TIMEOUT;
var ERR_NOT_IN_IFRAME = 'NotInIframe';
exports.ERR_NOT_IN_IFRAME = ERR_NOT_IN_IFRAME;
var ERR_IFRAME_ALREADY_ATTACHED_TO_DOM = 'IframeAlreadyAttachedToDom';
exports.ERR_IFRAME_ALREADY_ATTACHED_TO_DOM = ERR_IFRAME_ALREADY_ATTACHED_TO_DOM;
var CHECK_IFRAME_IN_DOC_INTERVAL = 60000;
var DEFAULT_PORTS = {
'http:': '80',
'https:': '443'
};
var URL_REGEX = /^(https?:|file:)?\/\/([^/:]+)?(:(\d+))?/;
var Penpal = {
ERR_CONNECTION_DESTROYED: ERR_CONNECTION_DESTROYED,
ERR_CONNECTION_TIMEOUT: ERR_CONNECTION_TIMEOUT,
ERR_NOT_IN_IFRAME: ERR_NOT_IN_IFRAME,
ERR_IFRAME_ALREADY_ATTACHED_TO_DOM: ERR_IFRAME_ALREADY_ATTACHED_TO_DOM,
/**
* Promise implementation.
* @type {Constructor}
*/
Promise: function () {
try {
return window ? window.Promise : null;
} catch (e) {
return null;
}
}(),
/**
* Whether debug messages should be logged.
* @type {boolean}
*/
debug: false
};
/**
* @return {number} A unique ID (not universally unique)
*/
var generateId = function () {
var id = 0;
return function () {
return ++id;
};
}();
/**
* Logs a message.
* @param {...*} args One or more items to log
*/
var log = function log() {
if (Penpal.debug) {
var _console;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
(_console = console).log.apply(_console, ['[Penpal]'].concat(args)); // eslint-disable-line no-console
}
};
/**
* Converts a URL into an origin.
* @param {string} url
* @return {string} The URL's origin
*/
var getOriginFromUrl = function getOriginFromUrl(url) {
var location = document.location;
var regexResult = URL_REGEX.exec(url);
var protocol;
var hostname;
var port;
if (regexResult) {
// It's an absolute URL. Use the parsed info.
// regexResult[1] will be undefined if the URL starts with //
protocol = regexResult[1] ? regexResult[1] : location.protocol;
hostname = regexResult[2];
port = regexResult[4];
} else {
// It's a relative path. Use the current location's info.
protocol = location.protocol;
hostname = location.hostname;
port = location.port;
} // If the protocol is file, the origin is "null"
// The origin of a document with file protocol is an opaque origin
// and its serialization "null" [1]
// [1] https://html.spec.whatwg.org/multipage/origin.html#origin
if (protocol === "file:") {
return "null";
} // If the port is the default for the protocol, we don't want to add it to the origin string
// or it won't match the message's event.origin.
var portSuffix = port && port !== DEFAULT_PORTS[protocol] ? ":".concat(port) : '';
return "".concat(protocol, "//").concat(hostname).concat(portSuffix);
};
/**
* A simplified promise class only used internally for when destroy() is called. This is
* used to destroy connections synchronously while promises typically resolve asynchronously.
*
* @param {Function} executor
* @returns {Object}
* @constructor
*/
var DestructionPromise = function DestructionPromise(executor) {
var handlers = [];
executor(function () {
handlers.forEach(function (handler) {
handler();
});
});
return {
then: function then(handler) {
handlers.push(handler);
}
};
};
/**
* Converts an error object into a plain object.
* @param {Error} Error object.
* @returns {Object}
*/
var serializeError = function serializeError(_ref) {
var name = _ref.name,
message = _ref.message,
stack = _ref.stack;
return {
name: name,
message: message,
stack: stack
};
};
/**
* Converts a plain object into an error object.
* @param {Object} Object with error properties.
* @returns {Error}
*/
var deserializeError = function deserializeError(obj) {
var deserializedError = new Error();
Object.keys(obj).forEach(function (key) {
return deserializedError[key] = obj[key];
});
return deserializedError;
};
/**
* Augments an object with methods that match those defined by the remote. When these methods are
* called, a "call" message will be sent to the remote, the remote's corresponding method will be
* executed, and the method's return value will be returned via a message.
* @param {Object} callSender Sender object that should be augmented with methods.
* @param {Object} info Information about the local and remote windows.
* @param {Array} methodNames Names of methods available to be called on the remote.
* @param {Promise} destructionPromise A promise resolved when destroy() is called on the penpal
* connection.
* @returns {Object} The call sender object with methods that may be called.
*/
var connectCallSender = function connectCallSender(callSender, info, methodNames, destroy, destructionPromise) {
var localName = info.localName,
local = info.local,
remote = info.remote,
remoteOrigin = info.remoteOrigin;
var destroyed = false;
log("".concat(localName, ": Connecting call sender"));
var createMethodProxy = function createMethodProxy(methodName) {
return function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
log("".concat(localName, ": Sending ").concat(methodName, "() call")); // This handles the case where the iframe has been removed from the DOM
// (and therefore its window closed), the consumer has not yet
// called destroy(), and the user calls a method exposed by
// the remote. We detect the iframe has been removed and force
// a destroy() immediately so that the consumer sees the error saying
// the connection has been destroyed.
if (remote.closed) {
destroy();
}
if (destroyed) {
var error = new Error("Unable to send ".concat(methodName, "() call due ") + "to destroyed connection");
error.code = ERR_CONNECTION_DESTROYED;
throw error;
}
return new Penpal.Promise(function (resolve, reject) {
var id = generateId();
var handleMessageEvent = function handleMessageEvent(event) {
if (event.source === remote && event.origin === remoteOrigin && event.data.penpal === REPLY && event.data.id === id) {
log("".concat(localName, ": Received ").concat(methodName, "() reply"));
local.removeEventListener(MESSAGE, handleMessageEvent);
var returnValue = event.data.returnValue;
if (event.data.returnValueIsError) {
returnValue = deserializeError(returnValue);
}
(event.data.resolution === FULFILLED ? resolve : reject)(returnValue);
}
};
local.addEventListener(MESSAGE, handleMessageEvent);
remote.postMessage({
penpal: CALL,
id: id,
methodName: methodName,
args: args
}, remoteOrigin);
});
};
};
destructionPromise.then(function () {
destroyed = true;
});
methodNames.reduce(function (api, methodName) {
api[methodName] = createMethodProxy(methodName);
return api;
}, callSender);
};
/**
* Listens for "call" messages coming from the remote, executes the corresponding method, and
* responds with the return value.
* @param {Object} info Information about the local and remote windows.
* @param {Object} methods The keys are the names of the methods that can be called by the remote
* while the values are the method functions.
* @param {Promise} destructionPromise A promise resolved when destroy() is called on the penpal
* connection.
* @returns {Function} A function that may be called to disconnect the receiver.
*/
var connectCallReceiver = function connectCallReceiver(info, methods, destructionPromise) {
var localName = info.localName,
local = info.local,
remote = info.remote,
remoteOrigin = info.remoteOrigin;
var destroyed = false;
log("".concat(localName, ": Connecting call receiver"));
var handleMessageEvent = function handleMessageEvent(event) {
if (event.source === remote && event.origin === remoteOrigin && event.data.penpal === CALL) {
var _event$data = event.data,
methodName = _event$data.methodName,
args = _event$data.args,
id = _event$data.id;
log("".concat(localName, ": Received ").concat(methodName, "() call"));
if (methodName in methods) {
var createPromiseHandler = function createPromiseHandler(resolution) {
return function (returnValue) {
log("".concat(localName, ": Sending ").concat(methodName, "() reply"));
if (destroyed) {
// It's possible to throw an error here, but it would need to be thrown asynchronously
// and would only be catchable using window.onerror. This is because the consumer
// is merely returning a value from their method and not calling any function
// that they could wrap in a try-catch. Even if the consumer were to catch the error,
// the value of doing so is questionable. Instead, we'll just log a message.
log("".concat(localName, ": Unable to send ").concat(methodName, "() reply due to destroyed connection"));
return;
}
var message = {
penpal: REPLY,
id: id,
resolution: resolution,
returnValue: returnValue
};
if (resolution === REJECTED && returnValue instanceof Error) {
message.returnValue = serializeError(returnValue);
message.returnValueIsError = true;
}
try {
remote.postMessage(message, remoteOrigin);
} catch (err) {
// If a consumer attempts to send an object that's not cloneable (e.g., window),
// we want to ensure the receiver's promise gets rejected.
if (err.name === DATA_CLONE_ERROR) {
remote.postMessage({
penpal: REPLY,
id: id,
resolution: REJECTED,
returnValue: serializeError(err),
returnValueIsError: true
}, remoteOrigin);
}
throw err;
}
};
};
new Penpal.Promise(function (resolve) {
return resolve(methods[methodName].apply(methods, args));
}).then(createPromiseHandler(FULFILLED), createPromiseHandler(REJECTED));
}
}
};
local.addEventListener(MESSAGE, handleMessageEvent);
destructionPromise.then(function () {
destroyed = true;
local.removeEventListener(MESSAGE, handleMessageEvent);
});
};
/**
* @typedef {Object} Child
* @property {Promise} promise A promise which will be resolved once a connection has
* been established.
* @property {HTMLIframeElement} iframe The created iframe element.
* @property {Function} destroy A method that, when called, will remove the iframe element from
* the DOM and clean up event listeners.
*/
/**
* Creates an iframe, loads a webpage into the URL, and attempts to establish communication with
* the iframe.
* @param {Object} options
* @param {string} options.url The URL of the webpage that should be loaded into the created iframe.
* @param {HTMLElement} [options.appendTo] The container to which the iframe should be appended.
* @param {Object} [options.methods={}] Methods that may be called by the iframe.
* @param {Number} [options.timeout] The amount of time, in milliseconds, Penpal should wait
* for the child to respond before rejecting the connection promise.
* @return {Child}
*/
Penpal.connectToChild = function (_ref2) {
var url = _ref2.url,
appendTo = _ref2.appendTo,
iframe = _ref2.iframe,
_ref2$methods = _ref2.methods,
methods = _ref2$methods === void 0 ? {} : _ref2$methods,
timeout = _ref2.timeout;
if (iframe && iframe.parentNode) {
var error = new Error('connectToChild() must not be called with an iframe already attached to DOM');
error.code = ERR_IFRAME_ALREADY_ATTACHED_TO_DOM;
throw error;
}
var destroy;
var connectionDestructionPromise = new DestructionPromise(function (resolveConnectionDestructionPromise) {
destroy = resolveConnectionDestructionPromise;
});
var parent = window;
iframe = iframe || document.createElement('iframe');
iframe.src = url;
var childOrigin = getOriginFromUrl(url);
var promise = new Penpal.Promise(function (resolveConnectionPromise, reject) {
var connectionTimeoutId;
if (timeout !== undefined) {
connectionTimeoutId = setTimeout(function () {
var error = new Error("Connection to child timed out after ".concat(timeout, "ms"));
error.code = ERR_CONNECTION_TIMEOUT;
reject(error);
destroy();
}, timeout);
} // We resolve the promise with the call sender. If the child reconnects (for example, after
// refreshing or navigating to another page that uses Penpal, we'll update the call sender
// with methods that match the latest provided by the child.
var callSender = {};
var receiverMethodNames;
var destroyCallReceiver;
var handleMessage = function handleMessage(event) {
var child = iframe.contentWindow;
if (event.source === child && event.origin === childOrigin && event.data.penpal === HANDSHAKE) {
log('Parent: Received handshake, sending reply'); // If event.origin is "null", the remote protocol is file:
// and we must post messages with "*" as targetOrigin [1]
// [1] https://developer.mozilla.org/fr/docs/Web/API/Window/postMessage#Utiliser_window.postMessage_dans_les_extensions
var remoteOrigin = event.origin === "null" ? "*" : event.origin;
event.source.postMessage({
penpal: HANDSHAKE_REPLY,
methodNames: Object.keys(methods)
}, remoteOrigin);
var info = {
localName: 'Parent',
local: parent,
remote: child,
remoteOrigin: remoteOrigin
}; // If the child reconnected, we need to destroy the previous call receiver before setting
// up a new one.
if (destroyCallReceiver) {
destroyCallReceiver();
} // When this promise is resolved, it will destroy the call receiver (stop listening to
// method calls from the child) and delete its methods off the call sender.
var callReceiverDestructionPromise = new DestructionPromise(function (resolveCallReceiverDestructionPromise) {
connectionDestructionPromise.then(resolveCallReceiverDestructionPromise);
destroyCallReceiver = resolveCallReceiverDestructionPromise;
});
connectCallReceiver(info, methods, callReceiverDestructionPromise); // If the child reconnected, we need to remove the methods from the previous call receiver
// off the sender.
if (receiverMethodNames) {
receiverMethodNames.forEach(function (receiverMethodName) {
delete callSender[receiverMethodName];
});
}
receiverMethodNames = event.data.methodNames;
connectCallSender(callSender, info, receiverMethodNames, destroy, connectionDestructionPromise);
clearTimeout(connectionTimeoutId);
resolveConnectionPromise(callSender);
}
};
parent.addEventListener(MESSAGE, handleMessage);
log('Parent: Loading iframe');
(appendTo || document.body).appendChild(iframe); // This is to prevent memory leaks when the iframe is removed
// from the document and the consumer hasn't called destroy().
// Without this, event listeners attached to the window would
// stick around and since the event handlers have a reference
// to the iframe in their closures, the iframe would stick around
// too.
var checkIframeInDocIntervalId = setInterval(function () {
if (!document.contains(iframe)) {
clearInterval(checkIframeInDocIntervalId);
destroy();
}
}, CHECK_IFRAME_IN_DOC_INTERVAL);
connectionDestructionPromise.then(function () {
if (iframe.parentNode) {
iframe.parentNode.removeChild(iframe);
}
parent.removeEventListener(MESSAGE, handleMessage);
clearInterval(checkIframeInDocIntervalId);
var error = new Error('Connection destroyed');
error.code = ERR_CONNECTION_DESTROYED;
reject(error);
});
});
return {
promise: promise,
iframe: iframe,
destroy: destroy
};
};
/**
* @typedef {Object} Parent
* @property {Promise} promise A promise which will be resolved once a connection has
* been established.
*/
/**
* Attempts to establish communication with the parent window.
* @param {Object} options
* @param {string} [options.parentOrigin=*] Valid parent origin used to restrict communication.
* @param {Object} [options.methods={}] Methods that may be called by the parent window.
* @param {Number} [options.timeout] The amount of time, in milliseconds, Penpal should wait
* for the parent to respond before rejecting the connection promise.
* @return {Parent}
*/
Penpal.connectToParent = function () {
var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref3$parentOrigin = _ref3.parentOrigin,
parentOrigin = _ref3$parentOrigin === void 0 ? '*' : _ref3$parentOrigin,
_ref3$methods = _ref3.methods,
methods = _ref3$methods === void 0 ? {} : _ref3$methods,
timeout = _ref3.timeout;
if (window === window.top) {
var error = new Error('connectToParent() must be called within an iframe');
error.code = ERR_NOT_IN_IFRAME;
throw error;
}
var destroy;
var connectionDestructionPromise = new DestructionPromise(function (resolveConnectionDestructionPromise) {
destroy = resolveConnectionDestructionPromise;
});
var child = window;
var parent = child.parent;
var promise = new Penpal.Promise(function (resolveConnectionPromise, reject) {
var connectionTimeoutId;
if (timeout !== undefined) {
connectionTimeoutId = setTimeout(function () {
var error = new Error("Connection to parent timed out after ".concat(timeout, "ms"));
error.code = ERR_CONNECTION_TIMEOUT;
reject(error);
destroy();
}, timeout);
}
var handleMessageEvent = function handleMessageEvent(event) {
if ((parentOrigin === '*' || parentOrigin === event.origin) && event.source === parent && event.data.penpal === HANDSHAKE_REPLY) {
log('Child: Received handshake reply');
child.removeEventListener(MESSAGE, handleMessageEvent);
var info = {
localName: 'Child',
local: child,
remote: parent,
remoteOrigin: event.origin
};
var callSender = {};
connectCallReceiver(info, methods, connectionDestructionPromise);
connectCallSender(callSender, info, event.data.methodNames, destroy, connectionDestructionPromise);
clearTimeout(connectionTimeoutId);
resolveConnectionPromise(callSender);
}
};
child.addEventListener(MESSAGE, handleMessageEvent);
connectionDestructionPromise.then(function () {
child.removeEventListener(MESSAGE, handleMessageEvent);
var error = new Error('Connection destroyed');
error.code = ERR_CONNECTION_DESTROYED;
reject(error);
});
log('Child: Sending handshake');
parent.postMessage({
penpal: HANDSHAKE,
methodNames: Object.keys(methods)
}, parentOrigin);
});
return {
promise: promise,
destroy: destroy
};
};
var _default = Penpal;
exports.default = _default;
});
var Penpal = unwrapExports(lib);
var Stats = /** @class */ (function () {
function Stats(meta) {
this.$meta = meta;
}
Object.defineProperty(Stats.prototype, "originalRows", {
/**
* The number of rows in the parsed data
*/
get: function () {
return this.$meta.count_rows;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Stats.prototype, "acceptedRows", {
/**
* The number of rows that were submitted
*/
get: function () {
return this.$meta.count_rows_accepted || null;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Stats.prototype, "originalColumns", {
/**
* The number of columns in the parsed data
*/
get: function () {
return this.$meta.count_columns || null;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Stats.prototype, "matchedColumns", {
/**
* The number of columns submitted
*/
get: function () {
return this.$meta.count_columns_matched || null;
},
enumerable: true,
configurable: true
});
return Stats;
}());
var EndUser = /** @class */ (function () {
function EndUser(meta) {
this.$user = meta;
}
Object.defineProperty(EndUser.prototype, "id", {
/**
* The UUID referencing the user's record stored in Flatfile
*/
get: function () {
return this.$user.id;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EndUser.prototype, "userId", {
/**
* Your internal ID reference for this user (required)
*/
get: function () {
return this.$user.userId;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EndUser.prototype, "name", {
/**
* The user's full name if you provided it
*/
get: function () {
return this.$user.name;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EndUser.prototype, "email", {
/**
* The user's email if you provided it
*/
get: function () {
return this.$user.name;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EndUser.prototype, "companyName", {
/**
* The company name the user is currently operating under
*/
get: function () {
return this.$user.companyName;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EndUser.prototype, "companyId", {
/**
* The company name the user is currently operating under
*/
get: function () {
return this.$user.companyId;
},
enumerable: true,
configurable: true
});
return EndUser;
}());
var UploadFile = /** @class */ (function () {
function UploadFile(file) {
this.$file = file;
}
Object.defineProperty(UploadFile.prototype, "id", {
/**
* A unique UUID referencing this file in the Flatfile system
*/
get: function () {
return this.$file.id;
},
enumerable: true,
configurable: true
});
Object.defineProperty(UploadFile.prototype, "filename", {
/**
* The original filename on the user's system
*/
get: function () {
return this.$file.filename;
},
enumerable: true,
configurable: true
});
Object.defineProperty(UploadFile.prototype, "filesize", {
/**
* The size of the file in bytes
*/
get: function () {
return this.$file.filesize;
},
enumerable: true,
configurable: true
});
Object.defineProperty(UploadFile.prototype, "filetype", {
/**
* The type of file
*/
get: function () {
return this.$file.filetype;
},
enumerable: true,
configurable: true
});
Object.defineProperty(UploadFile.prototype, "url", {
/**
* A securely signed url giving you temporary access to download the file
*/
get: function () {
return this.$file.url;
},
enumerable: true,
configurable: true
});
return UploadFile;
}());
var StreamedResults = /** @class */ (function () {
function StreamedResults(data, meta) {