UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

272 lines 11.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.operationRecordPlayback = exports.operationRecordQuery = exports.deleteExpiredRecords = exports.doOperationRecord = exports.getOperationRecords = exports.operationRecordInfoMap = exports.Operation = void 0; const lodash_1 = require("lodash"); const jsoner = __importStar(require("./jsoner")); class Operation { } exports.Operation = Operation; exports.operationRecordInfoMap = new Map(); const operationRecords = []; const getOperationRecords = () => operationRecords; exports.getOperationRecords = getOperationRecords; // 操作栈记录 function doOperationRecord(operation) { const request = indexedDB.open('naslData', 1); request.onupgradeneeded = (event) => { const db = event.target.result; const objectStore = db.createObjectStore('operationRecord', { autoIncrement: true }); objectStore.createIndex('appId', 'appId'); objectStore.createIndex('timestamp', 'timestamp'); }; request.onsuccess = (event) => { try { const db = event.target.result; const transaction = db.transaction('operationRecord', 'readwrite'); const objectStore = transaction.objectStore('operationRecord'); operation.appId = exports.operationRecordInfoMap.get('appId'); operation.branchId = exports.operationRecordInfoMap.get('branchId'); operation.accountId = exports.operationRecordInfoMap.get('accountId'); operation.userId = exports.operationRecordInfoMap.get('userId'); operation.phone = exports.operationRecordInfoMap.get('phone'); // 将时间戳添加到记录中 operation.timestamp = Date.now(); // 这份数据不存在向上的引用,因此用cloneDeep没有关系 const cloned = (0, lodash_1.cloneDeep)(operation); objectStore.put(cloned); operationRecords.push(cloned); transaction.oncomplete = () => { db.close(); }; } catch (err) { console.log(err); } }; request.onerror = function (event) { console.log('Failed to open database'); }; } exports.doOperationRecord = doOperationRecord; // 删除失效数据 async function deleteExpiredRecords() { return new Promise((resolve, reject) => { const request = indexedDB.open('naslData', 1); request.onupgradeneeded = (event) => { const db = event.target.result; const objectStore = db.createObjectStore('operationRecord', { autoIncrement: true }); objectStore.createIndex('appId', 'appId'); objectStore.createIndex('timestamp', 'timestamp'); }; request.onsuccess = (event) => { const db = event.target.result; const transaction = db.transaction('operationRecord', 'readwrite'); const objectStore = transaction.objectStore('operationRecord'); const index = objectStore.index('timestamp'); // 设置有效期,默认7天 const localStorageExpiresAt = window.localStorage.getItem('expiresAt'); const expiresAt = Date.now() - (localStorageExpiresAt ? +localStorageExpiresAt : 7 * 24 * 60 * 60 * 1000); const range = IDBKeyRange.upperBound(expiresAt); const expiredRecordsRequest = index.openCursor(range); expiredRecordsRequest.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { objectStore.delete(cursor.primaryKey); cursor.continue(); } else { resolve(void 0); } }; transaction.oncomplete = () => { db.close(); }; }; request.onerror = (event) => { reject('Failed to open database'); }; }); } exports.deleteExpiredRecords = deleteExpiredRecords; // 操作栈查询 function operationRecordQuery(app) { return new Promise((resolve, reject) => { const appId = app?.id; const branchId = app?.__branchId; const request = indexedDB.open('naslData', 1); request.onsuccess = (event) => { const db = event.target.result; const transaction = db.transaction('operationRecord', 'readonly'); const objectStore = transaction.objectStore('operationRecord'); const index = objectStore.index('appId'); // 查询 'appId' 索引 const range = IDBKeyRange.only(appId); const result = []; const request = index.openCursor(range); request.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { const record = cursor.value; const branchId = exports.operationRecordInfoMap.get('branchId'); if (record.branchId === branchId) { result.push(record); } cursor.continue(); } else { console.log('操作记录栈:', result); resolve(result); } }; transaction.oncomplete = () => { db.close(); }; }; request.onerror = (event) => { reject('Failed to open database'); }; }); } exports.operationRecordQuery = operationRecordQuery; // 获取父对象 function getParentInfo(appJson, path) { const pathArr = []; (path?.split('.') || []).forEach((pathItem) => { const arrayPropertyKey = pathItem.split('[')[0]; const matchArr = pathItem.match(/\[(.+?)\]/); if (matchArr) { pathArr.push(arrayPropertyKey, matchArr[0]); } else { pathArr.push(pathItem); } }); pathArr.pop(); let parentPath = ''; pathArr.forEach((pathItem, index) => { const matchArr = pathItem.match(/\[(.+?)\]/); if (matchArr || index === 0) { parentPath += pathItem; } else { parentPath += `.${pathItem}`; } }); const parentNode = jsoner.queryNodeByPath(appJson, parentPath); return { parentPath, parentNode, }; } // 操作记录回放 async function operationRecordPlayback(app, operationRecordAction) { const operationRecord = await operationRecordQuery(app); let operationRecordIndex = exports.operationRecordInfoMap.get('operationRecordIndex'); if ([null, undefined].includes(operationRecordIndex)) { operationRecordIndex = operationRecord?.length; } const appJson = app.toJSON(); if (operationRecordAction === 'undo') { if (operationRecordIndex > 0) { const currentRecordItem = operationRecord?.[operationRecordIndex]; const { type, action: recordItemAction } = currentRecordItem || {}; // 多人协作 if (type === 'cooperation' && recordItemAction === 'confirmPull') { console.log(`当前所处栈位置:${operationRecordIndex},已经进行了多人协作“合并”操作,无法继续对操作栈进行回放!`); return; } operationRecordIndex--; } else { console.log(`当前所处栈位置:${operationRecordIndex},无法继续回放`); console.log('当前appJSON:', appJson); return; } } else { if (operationRecordIndex < operationRecord?.length) { operationRecordIndex++; } else { console.log(`当前所处栈位置:${operationRecordIndex},无法继续前进`); console.log('当前appJSON:', appJson); return; } } exports.operationRecordInfoMap.set('operationRecordIndex', operationRecordIndex); const currentIndex = operationRecordIndex; ([...operationRecord].splice(currentIndex, operationRecord?.length) || []).reverse()?.forEach((recordItem) => { const { actionItem } = recordItem || {}; const { list } = actionItem || {}; [...(list || [])].reverse().forEach((actionItem) => { const { path, action, object, oldObject, parentKey, index: oldIndex } = actionItem || {}; const { parentNode } = getParentInfo(appJson, path); let newPath = path; // 如果涉及到改名操作,需要特殊处理 if (operationRecordAction === 'undo' && action === 'update' && object?.name) { const pathArr = path?.split('.') || []; const lastPathItem = pathArr?.pop(); if (lastPathItem) { pathArr.push(lastPathItem.replace(/(name=)[^\]]+/, `$1${object?.name}`)); } newPath = pathArr.join('.'); } const node = jsoner.queryNodeByPath(appJson, newPath); switch (action) { case 'create': if (Array.isArray(parentNode)) { const index = parentNode.indexOf(node); if (index !== -1) { parentNode.splice(index, 1); } } else { parentNode[parentKey] = null; } break; case 'delete': if (Array.isArray(parentNode) && oldIndex !== -1) { parentNode.splice(oldIndex, 0, oldObject); } else { parentNode[parentKey] = oldObject; } break; case 'update': for (const key in oldObject) { if (node) { node[key] = oldObject[key] ?? null; } } break; } }); }); console.log('当前所处栈位置:', currentIndex); console.log('当前appJSON:', appJson); return appJson; } exports.operationRecordPlayback = operationRecordPlayback; //# sourceMappingURL=operation.js.map