1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-23 10:30:04 +01:00
metamask-extension/app/scripts/lib/migrator/index.js
Mark Stacey 14d85b1332
Make JSDoc formatting more consistent (#9796)
A few inconsistencies in JSDoc formatting have been fixed throughout
the project. Many issues remain; these were just the few things that
were easy to fix with a regular expression.

The changes include:

* Using lower-case for primitive types, but capitalizing non-primitive
 types
* Separating the parameter identifier and the description with a dash
* Omitting a dash between the return type and the return description
* Ensuring the parameter type is first and the identifier is second (in
 a few places it was backwards)
* Using square brackets to denote when a parameter is optional, rather
 than putting "(optional)" in the parameter description
* Including a type and identifier with every parameter
* Fixing inconsistent spacing, except where it's used for alignment
* Remove incorrectly formatted `@deprecated` tags that reference non-
 existent properties
* Remove lone comment block without accompanying function

Additionally, one parameter was renamed for clarity.
2020-11-10 14:00:41 -03:30

96 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 {
/**
* @constructor
* @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,
}
}
}