mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-12 20:57:12 +01:00
3732c5f71e
ESLint rules have been added to enforce our JSDoc conventions. These rules were introduced by updating `@metamask/eslint-config` to v9. Some of the rules have been disabled because the effort to fix all lint errors was too high. It might be easiest to enable these rules one directory at a time, or one rule at a time. Most of the changes in this PR were a result of running `yarn lint:fix`. There were a handful of manual changes that seemed obvious and simple to make. Anything beyond that and the rule was left disabled.
97 lines
3.0 KiB
JavaScript
97 lines
3.0 KiB
JavaScript
import EventEmitter from 'events';
|
|
|
|
/**
|
|
* @typedef {Object} Migration
|
|
* @property {number} version - The migration version
|
|
* @property {Function} migrate - Returns a promise of the migrated data
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} MigratorOptions
|
|
* @property {Array<Migration>} [migrations] - The list of migrations to apply
|
|
* @property {number} [defaultVersion] - The version to use in the initial state
|
|
*/
|
|
|
|
export default class Migrator extends EventEmitter {
|
|
/**
|
|
* @param {MigratorOptions} opts
|
|
*/
|
|
constructor(opts = {}) {
|
|
super();
|
|
const migrations = opts.migrations || [];
|
|
// sort migrations by version
|
|
this.migrations = migrations.sort((a, b) => a.version - b.version);
|
|
// grab migration with highest version
|
|
const lastMigration = this.migrations.slice(-1)[0];
|
|
// use specified defaultVersion or highest migration version
|
|
this.defaultVersion =
|
|
opts.defaultVersion || (lastMigration && lastMigration.version) || 0;
|
|
}
|
|
|
|
// run all pending migrations on meta in place
|
|
async migrateData(versionedData = this.generateInitialState()) {
|
|
// get all migrations that have not yet been run
|
|
const pendingMigrations = this.migrations.filter(migrationIsPending);
|
|
|
|
// perform each migration
|
|
for (const migration of pendingMigrations) {
|
|
try {
|
|
// attempt migration and validate
|
|
const migratedData = await migration.migrate(versionedData);
|
|
if (!migratedData.data) {
|
|
throw new Error('Migrator - migration returned empty data');
|
|
}
|
|
if (
|
|
migratedData.version !== undefined &&
|
|
migratedData.meta.version !== migration.version
|
|
) {
|
|
throw new Error(
|
|
'Migrator - Migration did not update version number correctly',
|
|
);
|
|
}
|
|
// accept the migration as good
|
|
// eslint-disable-next-line no-param-reassign
|
|
versionedData = migratedData;
|
|
} catch (err) {
|
|
// rewrite error message to add context without clobbering stack
|
|
const originalErrorMessage = err.message;
|
|
err.message = `MetaMask Migration Error #${migration.version}: ${originalErrorMessage}`;
|
|
// emit error instead of throw so as to not break the run (gracefully fail)
|
|
this.emit('error', err);
|
|
// stop migrating and use state as is
|
|
return versionedData;
|
|
}
|
|
}
|
|
|
|
return versionedData;
|
|
|
|
/**
|
|
* Returns whether or not the migration is pending
|
|
*
|
|
* A migration is considered "pending" if it has a higher
|
|
* version number than the current version.
|
|
*
|
|
* @param {Migration} migration
|
|
* @returns {boolean}
|
|
*/
|
|
function migrationIsPending(migration) {
|
|
return migration.version > versionedData.meta.version;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the initial state for the migrator
|
|
*
|
|
* @param {Object} [data] - The data for the initial state
|
|
* @returns {{meta: {version: number}, data: any}}
|
|
*/
|
|
generateInitialState(data) {
|
|
return {
|
|
meta: {
|
|
version: this.defaultVersion,
|
|
},
|
|
data,
|
|
};
|
|
}
|
|
}
|