UNPKG

create-expo-cljs-app

Version:

Create a react native application with Expo and Shadow-CLJS!

285 lines (240 loc) 8.42 kB
/** * 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 asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function() { var self = this, args = arguments; return new Promise(function(resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } 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; } const _require = require("./traverseDependencies"), initialTraverseDependencies = _require.initialTraverseDependencies, reorderGraph = _require.reorderGraph, traverseDependencies = _require.traverseDependencies; const _require2 = require("events"), EventEmitter = _require2.EventEmitter; /** * This class is in charge of calculating the delta of changed modules that * happen between calls. To do so, it subscribes to file changes, so it can * traverse the files that have been changed between calls and avoid having to * traverse the whole dependency tree for trivial small changes. */ class DeltaCalculator extends EventEmitter { constructor(entryPoints, dependencyGraph, options) { super(); _defineProperty(this, "_deletedFiles", new Set()); _defineProperty(this, "_modifiedFiles", new Set()); _defineProperty(this, "_handleMultipleFileChanges", _ref => { let eventsQueue = _ref.eventsQueue; eventsQueue.forEach(this._handleFileChange); }); _defineProperty(this, "_handleFileChange", _ref2 => { let type = _ref2.type, filePath = _ref2.filePath; if (type === "delete") { this._deletedFiles.add(filePath); this._modifiedFiles.delete(filePath); } else { this._deletedFiles.delete(filePath); this._modifiedFiles.add(filePath); } // Notify users that there is a change in some of the bundle files. This // way the client can choose to refetch the bundle. this.emit("change"); }); this._options = options; this._dependencyGraph = dependencyGraph; this._graph = { dependencies: new Map(), entryPoints, importBundleNames: new Set() }; this._dependencyGraph .getWatcher() .on("change", this._handleMultipleFileChanges); } /** * Stops listening for file changes and clears all the caches. */ end() { this._dependencyGraph .getWatcher() .removeListener("change", this._handleMultipleFileChanges); this.removeAllListeners(); // Clean up all the cache data structures to deallocate memory. this._graph = { dependencies: new Map(), entryPoints: this._graph.entryPoints, importBundleNames: new Set() }; this._modifiedFiles = new Set(); this._deletedFiles = new Set(); } /** * Main method to calculate the delta of modules. It returns a DeltaResult, * which contain the modified/added modules and the removed modules. */ getDelta(_ref3) { var _this = this; let reset = _ref3.reset, shallow = _ref3.shallow; return _asyncToGenerator(function*() { // If there is already a build in progress, wait until it finish to start // processing a new one (delta server doesn't support concurrent builds). if (_this._currentBuildPromise) { yield _this._currentBuildPromise; } // We don't want the modified files Set to be modified while building the // bundle, so we isolate them by using the current instance for the bundling // and creating a new instance for the file watcher. const modifiedFiles = _this._modifiedFiles; _this._modifiedFiles = new Set(); const deletedFiles = _this._deletedFiles; _this._deletedFiles = new Set(); // Concurrent requests should reuse the same bundling process. To do so, // this method stores the promise as an instance variable, and then it's // removed after it gets resolved. _this._currentBuildPromise = _this._getChangedDependencies( modifiedFiles, deletedFiles ); let result; const numDependencies = _this._graph.dependencies.size; try { result = yield _this._currentBuildPromise; } catch (error) { // In case of error, we don't want to mark the modified files as // processed (since we haven't actually created any delta). If we do not // do so, asking for a delta after an error will produce an empty Delta, // which is not correct. modifiedFiles.forEach(file => _this._modifiedFiles.add(file)); deletedFiles.forEach(file => _this._deletedFiles.add(file)); // If after an error the number of modules has changed, we could be in // a weird state. As a safe net we clean the dependency modules to force // a clean traversal of the graph next time. if (_this._graph.dependencies.size !== numDependencies) { _this._graph.dependencies = new Map(); } throw error; } finally { _this._currentBuildPromise = null; } // Return all the modules if the client requested a reset delta. if (reset) { reorderGraph(_this._graph, { shallow }); return { added: _this._graph.dependencies, modified: new Map(), deleted: new Set(), reset: true }; } return result; })(); } /** * Returns the graph with all the dependencies. Each module contains the * needed information to do the traversing (dependencies, inverseDependencies) * plus some metadata. */ getGraph() { return this._graph; } _getChangedDependencies(modifiedFiles, deletedFiles) { var _this2 = this; return _asyncToGenerator(function*() { if (!_this2._graph.dependencies.size) { const _yield$initialTravers = yield initialTraverseDependencies( _this2._graph, _this2._options ), added = _yield$initialTravers.added; return { added, modified: new Map(), deleted: new Set(), reset: true }; } // If a file has been deleted, we want to invalidate any other file that // depends on it, so we can process it and correctly return an error. deletedFiles.forEach(filePath => { const module = _this2._graph.dependencies.get(filePath); if (module) { module.inverseDependencies.forEach(path => { // Only mark the inverse dependency as modified if it's not already // marked as deleted (in that case we can just ignore it). if (!deletedFiles.has(path)) { modifiedFiles.add(path); } }); } }); // We only want to process files that are in the bundle. const modifiedDependencies = Array.from(modifiedFiles).filter(filePath => _this2._graph.dependencies.has(filePath) ); // No changes happened. Return empty delta. if (modifiedDependencies.length === 0) { return { added: new Map(), modified: new Map(), deleted: new Set(), reset: false }; } const _yield$traverseDepend = yield traverseDependencies( modifiedDependencies, _this2._graph, _this2._options ), added = _yield$traverseDepend.added, modified = _yield$traverseDepend.modified, deleted = _yield$traverseDepend.deleted; return { added, modified, deleted, reset: false }; })(); } } module.exports = DeltaCalculator;