diff --git a/.changeset/tame-fans-clap.md b/.changeset/tame-fans-clap.md new file mode 100644 index 0000000..de23cf4 --- /dev/null +++ b/.changeset/tame-fans-clap.md @@ -0,0 +1,5 @@ +--- +'@emigrate/cli': minor +--- + +Implement a default "loader" plugin for JavaScript files (supports `.js`, `.cjs` and `.mjs` file extensions) diff --git a/packages/cli/src/plugin-loader-js.ts b/packages/cli/src/plugin-loader-js.ts new file mode 100644 index 0000000..f8f5e62 --- /dev/null +++ b/packages/cli/src/plugin-loader-js.ts @@ -0,0 +1,44 @@ +import { type LoaderPlugin } from '@emigrate/plugin-tools/types'; + +const loaderJs: LoaderPlugin = { + loadableExtensions: ['.js', '.cjs', '.mjs'], + async loadMigration(migration) { + const migrationModule: unknown = await import(migration.filePath); + + if (typeof migrationModule === 'function') { + return async () => { + await migrationModule(); + }; + } + + if ( + migrationModule && + typeof migrationModule === 'object' && + 'default' in migrationModule && + typeof migrationModule.default === 'function' + ) { + const migrationFunction = migrationModule.default; + return async () => { + await migrationFunction(); + }; + } + + if ( + migrationModule && + typeof migrationModule === 'object' && + 'up' in migrationModule && + typeof migrationModule.up === 'function' + ) { + const migrationFunction = migrationModule.up; + return async () => { + await migrationFunction(); + }; + } + + return async () => { + throw new Error(`Migration file does not export a function: ${migration.relativeFilePath}`); + }; + }, +}; + +export default loaderJs; diff --git a/packages/cli/src/up-command.ts b/packages/cli/src/up-command.ts index b007edc..124dcb3 100644 --- a/packages/cli/src/up-command.ts +++ b/packages/cli/src/up-command.ts @@ -4,6 +4,7 @@ import { type LoaderPlugin } from '@emigrate/plugin-tools/types'; import { ShowUsageError } from './show-usage-error.js'; import { type Config } from './types.js'; import { stripLeadingPeriod } from './strip-leading-period.js'; +import pluginLoaderJs from './plugin-loader-js.js'; type ExtraFlags = { dry?: boolean; @@ -40,7 +41,7 @@ export default async function upCommand({ directory, dry, plugins = [] }: Config } const migrationFileExtensions = new Set(migrationFiles.map((file) => stripLeadingPeriod(path.extname(file)))); - const loaderPlugins = await getOrLoadPlugins('loader', plugins); + const loaderPlugins = await getOrLoadPlugins('loader', [...plugins, pluginLoaderJs]); const loaderByExtension = new Map( [...migrationFileExtensions].map( @@ -91,10 +92,12 @@ export default async function upCommand({ directory, dry, plugins = [] }: Config console.log(' -', name, '...'); const extension = stripLeadingPeriod(path.extname(name)); - const filename = path.resolve(process.cwd(), directory, name); + const cwd = process.cwd(); + const filePath = path.resolve(cwd, directory, name); + const relativeFilePath = path.relative(cwd, filePath); const loader = loaderByExtension.get(extension)!; - const migration = await loader.loadMigration({ name, filename, extension }); + const migration = await loader.loadMigration({ name, filePath, relativeFilePath, cwd, directory, extension }); try { await migration();