-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Matteo Collina <[email protected]>
- Loading branch information
Showing
10 changed files
with
209 additions
and
6 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,87 @@ | ||
import semver from 'semver' | ||
import { join } from 'node:path' | ||
import { pathToFileURL } from 'node:url' | ||
import { readdir } from 'node:fs/promises' | ||
|
||
export type Migration<Input, Output = Input> = { | ||
version: string | ||
toVersion?: string | ||
up: (input: Input) => Promise<Output> | Output | ||
} | ||
|
||
interface SemgratorParams<Input> { | ||
interface BaseSemgratorParams<Input> { | ||
version: string | ||
migrations: Migration<any, any>[] | ||
input: Input | ||
} | ||
|
||
interface SemgratorParamsWithMigrations<Input> | ||
extends BaseSemgratorParams<Input> { | ||
migrations: Migration<Input>[] | ||
} | ||
|
||
interface SemgratorParamsWithPath<Input> | ||
extends BaseSemgratorParams<Input> { | ||
path: string | ||
} | ||
|
||
interface SemgratorResult<Output> { | ||
version: string | ||
result: Output | ||
} | ||
|
||
export async function semgrator<Input = unknown, Output = unknown>( | ||
params: SemgratorParams<Input>, | ||
async function semgratorWithMigrations<Input, Output>( | ||
params: SemgratorParamsWithMigrations<Input>, | ||
): Promise<SemgratorResult<Output>> { | ||
let result = params.input as unknown | ||
let lastVersion = params.version | ||
for (const migration of params.migrations) { | ||
if (semver.gt(migration.version, lastVersion)) { | ||
// @ts-expect-error | ||
result = await migration.up(result) | ||
lastVersion = migration.version | ||
lastVersion = migration.toVersion || migration.version | ||
} | ||
} | ||
|
||
return { version: lastVersion, result: result as Output } | ||
} | ||
|
||
async function loadMigrationsFromPath<Input>( | ||
path: string, | ||
): Promise<Migration<Input>[]> { | ||
const files = (await readdir(path)).filter(file => | ||
file.match(/\.(c|m)?js$/), | ||
) | ||
|
||
const migrations = await Promise.all( | ||
files.map(async file => { | ||
const module = await import( | ||
pathToFileURL(join(path, file)).toString() | ||
) | ||
return module.migration as Migration<Input> | ||
}), | ||
) | ||
|
||
migrations.sort((a, b) => semver.compare(a.version, b.version)) | ||
|
||
return migrations | ||
} | ||
|
||
export async function semgrator<Input = unknown, Output = unknown>( | ||
params: | ||
| SemgratorParamsWithPath<Input> | ||
| SemgratorParamsWithMigrations<Input>, | ||
): Promise<SemgratorResult<Output>> { | ||
if ('path' in params) { | ||
const migrations = await loadMigrationsFromPath<Input>( | ||
params.path, | ||
) | ||
return semgratorWithMigrations<Input, Output>({ | ||
...params, | ||
migrations, | ||
}) | ||
} else if ('migrations' in params) { | ||
return semgratorWithMigrations<Input, Output>(params) | ||
} else { | ||
throw new Error('Specify either path or migrations') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export type Order = { | ||
order: string[] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import type { Migration } from '../../../lib/semgrator.js' | ||
import type { Order } from '../order.js' | ||
|
||
export const migration: Migration<Order> = { | ||
version: '0.16.0', | ||
up: (input: Order) => { | ||
input.order.push('0.16.0') | ||
return input | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import type { Migration } from '../../../lib/semgrator.js' | ||
import type { Order } from '../order.js' | ||
|
||
export const migration: Migration<Order> = { | ||
version: '0.17.0', | ||
up: (input: Order) => { | ||
input.order.push('0.17.0') | ||
return input | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import type { Migration } from '../../../lib/semgrator.js' | ||
import type { Order } from '../order.js' | ||
|
||
export const migration: Migration<Order> = { | ||
version: '1.0.0', | ||
toVersion: '1.42.0', | ||
up: (input: Order) => { | ||
input.order.push('1.0.0') | ||
return input | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import type { Migration } from '../../../lib/semgrator.js' | ||
import type { Order } from '../order.js' | ||
|
||
export const migration: Migration<Order> = { | ||
version: '0.18.0', | ||
up: (input: Order) => { | ||
input.order.push('0.18.0') | ||
return input | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { test } from 'node:test' | ||
import { semgrator } from '../lib/semgrator.js' | ||
import { equal } from 'node:assert/strict' | ||
import { join } from 'desm' | ||
import type { Order } from './fixtures/order.js' | ||
import { deepEqual } from 'node:assert/strict' | ||
|
||
test('apply all migrations in a folder', async t => { | ||
const res = await semgrator<Order>({ | ||
version: '0.15.0', | ||
path: join(import.meta.url, 'fixtures', 'plt'), | ||
input: { | ||
order: [], | ||
}, | ||
}) | ||
|
||
equal(res.version, '1.42.0') | ||
deepEqual(res.result, { | ||
order: ['0.16.0', '0.17.0', '0.18.0', '1.0.0'], | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters