create-expo-cljs-app
Version:
Create a react native application with Expo and Shadow-CLJS!
307 lines (248 loc) • 6.77 kB
JavaScript
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
"use strict";
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _slicedToArray(arr, i) {
return (
_arrayWithHoles(arr) ||
_iterableToArrayLimit(arr, i) ||
_unsupportedIterableToArray(arr, i) ||
_nonIterableRest()
);
}
function _nonIterableRest() {
throw new TypeError(
"Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _iterableToArrayLimit(arr, i) {
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr)))
return;
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (
var _i = arr[Symbol.iterator](), _s;
!(_n = (_s = _i.next()).done);
_n = true
) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
const EventEmitter = require("./vendor/eventemitter3");
const inject = _ref => {
let _ref$module = _slicedToArray(_ref.module, 2),
id = _ref$module[0],
code = _ref$module[1],
sourceURL = _ref.sourceURL; // Some engines do not support `sourceURL` as a comment. We expose a
// `globalEvalWithSourceUrl` function to handle updates in that case.
if (global.globalEvalWithSourceUrl) {
global.globalEvalWithSourceUrl(code, sourceURL);
} else {
// eslint-disable-next-line no-eval
eval(code);
}
};
const injectUpdate = update => {
update.added.forEach(inject);
update.modified.forEach(inject);
};
class HMRClient extends EventEmitter {
constructor(url) {
super(); // Access the global WebSocket object only after enabling the client,
// since some polyfills do the initialization lazily.
_defineProperty(this, "_isEnabled", false);
_defineProperty(this, "_pendingUpdate", null);
_defineProperty(this, "_queue", []);
_defineProperty(this, "_state", "opening");
this._ws = new global.WebSocket(url);
this._ws.onopen = () => {
this._state = "open";
this.emit("open");
this._flushQueue();
};
this._ws.onerror = error => {
this.emit("connection-error", error);
};
this._ws.onclose = () => {
this._state = "closed";
this.emit("close");
};
this._ws.onmessage = message => {
const data = JSON.parse(message.data);
switch (data.type) {
case "bundle-registered":
this.emit("bundle-registered");
break;
case "update-start":
this.emit("update-start", data.body);
break;
case "update":
this.emit("update", data.body);
break;
case "update-done":
this.emit("update-done");
break;
case "error":
this.emit("error", data.body);
break;
default:
this.emit("error", {
type: "unknown-message",
message: data
});
}
};
this.on("update", update => {
if (this._isEnabled) {
injectUpdate(update);
} else if (this._pendingUpdate == null) {
this._pendingUpdate = update;
} else {
this._pendingUpdate = mergeUpdates(this._pendingUpdate, update);
}
});
}
close() {
this._ws.close();
}
send(message) {
switch (this._state) {
case "opening":
this._queue.push(message);
break;
case "open":
this._ws.send(message);
break;
case "closed":
// Ignore.
break;
default:
throw new Error("[WebSocketHMRClient] Unknown state: " + this._state);
}
}
_flushQueue() {
this._queue.forEach(message => this.send(message));
this._queue.length = 0;
}
enable() {
this._isEnabled = true;
const update = this._pendingUpdate;
this._pendingUpdate = null;
if (update != null) {
injectUpdate(update);
}
}
disable() {
this._isEnabled = false;
}
isEnabled() {
return this._isEnabled;
}
hasPendingUpdates() {
return this._pendingUpdate != null;
}
}
function mergeUpdates(base, next) {
const addedIDs = new Set();
const deletedIDs = new Set();
const moduleMap = new Map(); // Fill in the temporary maps and sets from both updates in their order.
applyUpdateLocally(base);
applyUpdateLocally(next);
function applyUpdateLocally(update) {
update.deleted.forEach(id => {
if (addedIDs.has(id)) {
addedIDs.delete(id);
} else {
deletedIDs.add(id);
}
moduleMap.delete(id);
});
update.added.forEach(item => {
const id = item.module[0];
if (deletedIDs.has(id)) {
deletedIDs.delete(id);
} else {
addedIDs.add(id);
}
moduleMap.set(id, item);
});
update.modified.forEach(item => {
const id = item.module[0];
moduleMap.set(id, item);
});
} // Now reconstruct a unified update from our in-memory maps and sets.
// Applying it should be equivalent to applying both of them individually.
const result = {
isInitialUpdate: next.isInitialUpdate,
revisionId: next.revisionId,
added: [],
modified: [],
deleted: []
};
deletedIDs.forEach(id => {
result.deleted.push(id);
});
moduleMap.forEach((item, id) => {
if (deletedIDs.has(id)) {
return;
}
if (addedIDs.has(id)) {
result.added.push(item);
} else {
result.modified.push(item);
}
});
return result;
}
module.exports = HMRClient;