@lcap/nasl
Version:
NetEase Application Specific Language
272 lines • 11.4 kB
JavaScript
;
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