UNPKG

feeles-ide

Version:

The hackable and serializable IDE to make learning material

453 lines (380 loc) 14 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _includes = _interopRequireDefault(require("lodash/includes")); var _ = require("./"); /** * ファイルの状態を In Memory & IndexedDB で保有するストア * ファイルの探索を手助けする Indexer でもある * Redux は使わず、 FileView インスタンスが setState の * 参照をもち、外から状態を更新する */ var FileView = /*#__PURE__*/ function () { function FileView(files) { (0, _classCallCheck2.default)(this, FileView); this.files = files; this._changed = true; // files 変更フラグ } (0, _createClass2.default)(FileView, [{ key: "install", value: function install(component) { this.component = component; /* 互換性保持のため, つねに最新のステートを参照するAPIをのこす いずれ this.state.fileView を直接 propergate させたい */ component.addFile = this.addFile.bind(this); component.putFile = this.putFile.bind(this); component.deleteFile = this.deleteFile.bind(this); component.findFile = this.findFile.bind(this); } }, { key: "uninstall", value: function uninstall() { this.component = null; } }, { key: "setState", value: function setState(_ref) { var files = _ref.files; this._changed = true; // Index するフラグ if (!files) throw 'Cannot set other than files'; if (!this.component) throw 'Component is not been set'; var fileView = new FileView(files); fileView.install(this.component); return this.component.setStatePromise({ fileView: fileView }); } /** * ファイルパスでファイルを取得 * @param {String} path 取得したいファイルのパス * @return {SourceFile|BinalyFile|null} ファイルまたは null */ }, { key: "getFileByFullPath", value: function getFileByFullPath(path) { this.updateIndex(); return this.pathToFileMap.get(path); } /** * 任意の拡張子をもつすべてのファイルを取得 * @param {String} ext 取得したいファイルのパス * @return {Array<SourceFile|BinalyFile>} ファイルの配列 */ }, { key: "getFilesByExtention", value: function getFilesByExtention(ext) { this.updateIndex(); return this.extToFilesMap.get(ext) || []; } /** * Map を用いてファイル名をインデックス * files が変わったら適宜呼び出す */ }, { key: "updateIndex", value: function updateIndex() { var _this = this; // files が変更されていればあらたにインデックス if (!this._changed) return; this._changed = false; this.pathToFileMap = new Map(); this.extToFilesMap = new Map(); var append = function append(name, file) { // name => File _this.pathToFileMap.set(name, file); // extention => File var _name$split = name.split('.'), _name$split2 = (0, _toArray2.default)(_name$split), extArray = _name$split2.slice(1); if (!extArray.length) return; var ext = extArray.join('.'); if (_this.extToFilesMap.has(ext)) { var files = _this.extToFilesMap.get(ext); _this.extToFilesMap.set(ext, files.concat(file)); } else { _this.extToFilesMap.set(ext, [file]); } }; // i18n 以外 var i18n = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this.files[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var file = _step.value; if (!file.name.startsWith('i18n/')) { append(file.name, file); } else { i18n.push(file); } } // i18n/{ll_CC} を追加 } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var ll_CC = this.component.props.localization.ll_CC; for (var _i = 0; _i < i18n.length; _i++) { var _file = i18n[_i]; var _file$name$split = _file.name.split('/'), _file$name$split2 = (0, _toArray2.default)(_file$name$split), locale = _file$name$split2[1], virtualPath = _file$name$split2.slice(2); if (locale === ll_CC) { append(virtualPath.join('/'), _file); } } } }, { key: "forceUpdate", value: function forceUpdate() { var fileView = new FileView(this.files); fileView.install(this.component); return this.component.setStatePromise({ fileView: fileView }); } /** * ファイルを検索して取得する (後方互換性) * @param {String|Function} name ファイル名 * @param {Boolean} multiple 全件取得フラグ */ }, { key: "findFile", value: function findFile(name) { var multiple = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (typeof name === 'string') { name = name.replace(/^(\.\/|\/)*/, ''); } var i18nName = "i18n/".concat(this.component.props.localization.ll_CC, "/").concat(name); var pred = typeof name === 'function' ? name : function (file) { return !file.options.isTrashed && ( // 言語設定による動的ファイルパス解決 file.name === i18nName || file.moduleName === i18nName || // 通常のファイルパス解決 file.name === name || file.moduleName === name); }; return multiple ? this.files.filter(pred) : this.files.find(pred) || null; } /** * ファイルをひとつ追加する * @param {SourceFile|BinalyFile} file 追加するファイル */ }, { key: "addFile", value: function () { var _addFile = (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee(file) { var remove, files; return _regenerator.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: remove = this.inspection(file); if (!(file === remove)) { _context.next = 3; break; } return _context.abrupt("return", file); case 3: files = this.files.concat(file).filter(function (item) { return item !== remove; }); _context.next = 6; return this.setState({ files: files }); case 6: _context.next = 8; return this.component.resetConfig(file.name); case 8: if (!this.component.state.project) { _context.next = 11; break; } _context.next = 11; return (0, _.putFile)(this.component.state.project.id, file.serialize()); case 11: return _context.abrupt("return", file); case 12: case "end": return _context.stop(); } } }, _callee, this); })); function addFile(_x) { return _addFile.apply(this, arguments); } return addFile; }() /** * ファイルを置き換える * @param {SourceFile|BinalyFile} prevFile 削除するファイル * @param {SourceFile|BinalyFile} nextFile 追加するファイル */ }, { key: "putFile", value: function () { var _putFile2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee2(prevFile, nextFile) { var remove, files; return _regenerator.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!(nextFile === undefined)) { _context2.next = 2; break; } return _context2.abrupt("return", this.addFile(prevFile)); case 2: console.time('putFile 1'); remove = this.inspection(nextFile); console.timeEnd('putFile 1'); if (!(remove === nextFile)) { _context2.next = 7; break; } return _context2.abrupt("return", prevFile); case 7: files = this.files.filter(function (item) { return item !== remove && item.key !== prevFile.key; }).concat(nextFile); console.time('putFile 2'); _context2.next = 11; return this.setState({ files: files }); case 11: console.timeEnd('putFile 2'); console.time('putFile 3'); this.component.resetConfig(prevFile.name); console.timeEnd('putFile 3'); if (!this.component.state.project) { _context2.next = 20; break; } console.time('putFile 4'); _context2.next = 19; return (0, _.putFile)(this.component.state.project.id, nextFile.serialize()); case 19: console.timeEnd('putFile 4'); case 20: return _context2.abrupt("return", nextFile); case 21: case "end": return _context2.stop(); } } }, _callee2, this); })); function putFile(_x2, _x3) { return _putFile2.apply(this, arguments); } return putFile; }() /** * 任意個数のファイルを削除する * @param {Array<SourceFile|BinalyFile>} targets 削除するファイル */ }, { key: "deleteFile", value: function () { var _deleteFile2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee3() { var _len, targets, _key, keys, files, fileNames, _args3 = arguments; return _regenerator.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: for (_len = _args3.length, targets = new Array(_len), _key = 0; _key < _len; _key++) { targets[_key] = _args3[_key]; } keys = targets.map(function (item) { return item.key; }); files = this.files.filter(function (item) { return !(0, _includes.default)(keys, item.key); }); _context3.next = 5; return this.setState({ files: files }); case 5: if (!this.component.state.project) { _context3.next = 9; break; } fileNames = targets.map(function (item) { return item.name; }); _context3.next = 9; return _.deleteFile.apply(void 0, [this.component.state.project.id].concat((0, _toConsumableArray2.default)(fileNames))); case 9: case "end": return _context3.stop(); } } }, _callee3, this); })); function deleteFile() { return _deleteFile2.apply(this, arguments); } return deleteFile; }() /** * ファイル名の衝突をしらべる. TODO: FileDialog で実現すべき * https://trello.com/c/Y4CbIH81/244-conflict-%E3%81%AF%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0%E3%81%AE%E3%81%A8%E3%81%93%E3%82%8D%E3%81%A7%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B-filestore-%E3%81%A7%E3%81%AF%E7%84%A1%E8%A6%96 * @param {Array<SourceFile|BinalyFile>} newFile 追加予定のファイル */ }, { key: "inspection", value: function inspection(newFile) { var conflict = this.files.find(function (file) { return !file.options.isTrashed && file.key !== newFile.key && file.name === newFile.name; }); if (conflict) { // TODO: FileDialog instead of. // 一時的に "強制上書き" にする console.log(newFile); return conflict; // if (confirm(this.component.props.localization.common.conflict)) { // return conflict; // } else { // return newFile; // } } return null; } }]); return FileView; }(); exports.default = FileView;