diff options
Diffstat (limited to 'js/scripting-lang/scripting-harness/core/history.js')
-rw-r--r-- | js/scripting-lang/scripting-harness/core/history.js | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/js/scripting-lang/scripting-harness/core/history.js b/js/scripting-lang/scripting-harness/core/history.js new file mode 100644 index 0000000..94ad1b9 --- /dev/null +++ b/js/scripting-lang/scripting-harness/core/history.js @@ -0,0 +1,169 @@ +/** + * StateHistory - Manages state versioning and metadata + * + * @description Provides automatic versioning, rollback, replay, and diffing capabilities + * for state management in the scripting harness. Each state change creates a new version + * with metadata including timestamp and hash for change detection. + * + * Features: + * - Automatic version tracking + * - Configurable version limits with cleanup + * - State diffing between versions + * - Rollback and replay capabilities + * - Memory-efficient storage with automatic cleanup + */ + +class StateHistory { + constructor(maxVersions = 100) { + this.versions = new Map(); + this.maxVersions = maxVersions; + } + + /** + * Add a new version to the history + * + * @param {number} version - Version number + * @param {Object} inputState - Input state with metadata wrapper + * @param {Object} outputModel - Output model (pure table data) + */ + addVersion(version, inputState, outputModel) { + // Store version data + this.versions.set(version, { + version, + timestamp: Date.now(), + inputState, + outputModel, + hash: this.calculateHash(outputModel) + }); + + // Clean up old versions if needed + this.cleanupOldVersions(); + } + + /** + * Get state at specific version + * + * @param {number} version - Version number to retrieve + * @returns {Object|null} State data or null if version not found + */ + getVersion(version) { + const versionData = this.versions.get(version); + return versionData ? versionData.outputModel : null; + } + + /** + * Get all versions with metadata + * + * @returns {Array} Array of version metadata objects + */ + getAllVersions() { + return Array.from(this.versions.values()).map(v => ({ + version: v.version, + timestamp: v.timestamp, + hash: v.hash + })); + } + + /** + * Get diff between two versions + * + * @param {number} fromVersion - Starting version + * @param {number} toVersion - Ending version + * @returns {Object|null} Diff object or null if versions not found + */ + getDiff(fromVersion, toVersion) { + const fromState = this.getVersion(fromVersion); + const toState = this.getVersion(toVersion); + + if (!fromState || !toState) { + return null; + } + + return { + added: this.findAddedProperties(fromState, toState), + removed: this.findRemovedProperties(fromState, toState), + changed: this.findChangedProperties(fromState, toState) + }; + } + + /** + * Clean up old versions to prevent memory leaks + */ + cleanupOldVersions() { + if (this.versions.size > this.maxVersions) { + const sortedVersions = Array.from(this.versions.keys()).sort(); + const toDelete = sortedVersions.slice(0, this.versions.size - this.maxVersions); + + for (const version of toDelete) { + this.versions.delete(version); + } + } + } + + /** + * Calculate simple hash for change detection + * + * @param {Object} state - State object to hash + * @returns {number} Hash value + */ + calculateHash(state) { + // Simple hash for change detection + if (state === undefined || state === null) { + return 0; + } + return JSON.stringify(state).length; + } + + /** + * Find properties added in the new state + * + * @param {Object} fromState - Original state + * @param {Object} toState - New state + * @returns {Object} Object containing added properties + */ + findAddedProperties(fromState, toState) { + const added = {}; + for (const key in toState) { + if (!(key in fromState)) { + added[key] = toState[key]; + } + } + return added; + } + + /** + * Find properties removed in the new state + * + * @param {Object} fromState - Original state + * @param {Object} toState - New state + * @returns {Object} Object containing removed properties + */ + findRemovedProperties(fromState, toState) { + const removed = {}; + for (const key in fromState) { + if (!(key in toState)) { + removed[key] = fromState[key]; + } + } + return removed; + } + + /** + * Find properties changed in the new state + * + * @param {Object} fromState - Original state + * @param {Object} toState - New state + * @returns {Object} Object containing changed properties with from/to values + */ + findChangedProperties(fromState, toState) { + const changed = {}; + for (const key in toState) { + if (key in fromState && fromState[key] !== toState[key]) { + changed[key] = { from: fromState[key], to: toState[key] }; + } + } + return changed; + } +} + +export { StateHistory }; \ No newline at end of file |