Skip to content

Commit

Permalink
Merge branch 'develop' into chore/compiler-utility
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage authored Jan 10, 2025
2 parents 7af3e4c + c1930bd commit 1e1111b
Show file tree
Hide file tree
Showing 15 changed files with 244 additions and 87 deletions.
7 changes: 7 additions & 0 deletions .changeset/thin-games-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@medusajs/medusa": patch
"@medusajs/types": patch
"@medusajs/utils": patch
---

Feat/merge plugin modules
3 changes: 2 additions & 1 deletion packages/core/modules-sdk/src/medusa-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ export async function loadModules(args: {
let declaration: any = {}
let definition: Partial<ModuleDefinition> | undefined = undefined

if (mod === false) {
// TODO: We are keeping mod === false for backward compatibility for now
if (mod === false || (isObject(mod) && "disable" in mod && mod.disable)) {
continue
}

Expand Down
13 changes: 9 additions & 4 deletions packages/core/types/src/common/config-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -944,16 +944,21 @@ type ExternalModuleDeclarationOverride = ExternalModuleDeclaration & {
disable?: boolean
}

/**
* Modules accepted by the defineConfig function
*/
export type InputConfigModules = Partial<
InternalModuleDeclarationOverride | ExternalModuleDeclarationOverride
>[]

/**
* The configuration accepted by the "defineConfig" helper
*/
export type InputConfig = Partial<
Omit<ConfigModule, "admin" | "modules"> & {
admin: Partial<ConfigModule["admin"]>
modules:
| Partial<
InternalModuleDeclarationOverride | ExternalModuleDeclarationOverride
>[]
| InputConfigModules
/**
* @deprecated use the array instead
*/
Expand All @@ -967,5 +972,5 @@ export type PluginDetails = {
id: string
options: Record<string, unknown>
version: string
modules?: InputConfig["modules"]
modules?: InputConfigModules
}
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ describe("defineConfig", function () {
`)
})

it("should not include disabled modules", function () {
it("should include disabled modules", function () {
expect(
defineConfig({
projectConfig: {
Expand Down Expand Up @@ -837,6 +837,9 @@ describe("defineConfig", function () {
"cache": {
"resolve": "@medusajs/medusa/cache-inmemory",
},
"cart": {
"disable": true,
},
"currency": {
"resolve": "@medusajs/medusa/currency",
},
Expand Down
75 changes: 75 additions & 0 deletions packages/core/utils/src/common/__tests__/transform-modules.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { MODULE_PACKAGE_NAMES, Modules } from "../../modules-sdk"
import { transformModules } from "../define-config"

describe("transformModules", () => {
test("convert array of modules to an object", () => {
const modules = transformModules([
{
resolve: require.resolve("../__fixtures__/define-config/github"),
options: {
apiKey: "test",
},
},
])

expect(modules).toEqual({
GithubModuleService: {
options: {
apiKey: "test",
},
resolve: require.resolve("../__fixtures__/define-config/github"),
},
})
})

test("transform default module", () => {
const modules = transformModules([
{
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
},
])

expect(modules).toEqual({
cache: {
resolve: "@medusajs/medusa/cache-inmemory",
},
})
})

test("should manage loading priority of modules when its disabled at a later stage in the array", () => {
const modules = transformModules([
{
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
},
{
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
disable: true,
},
])

expect(modules).toEqual({
cache: {
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
disable: true,
},
})
})

test("should manage loading priority of modules when its not disabled at a later stage in the array", () => {
const modules = transformModules([
{
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
disable: true,
},
{
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
},
])

expect(modules).toEqual({
cache: {
resolve: MODULE_PACKAGE_NAMES[Modules.CACHE],
},
})
})
})
136 changes: 70 additions & 66 deletions packages/core/utils/src/common/define-config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ConfigModule,
InputConfig,
InputConfigModules,
InternalModuleDeclaration,
} from "@medusajs/types"
import {
Expand Down Expand Up @@ -108,14 +109,79 @@ export function defineConfig(config: InputConfig = {}): ConfigModule {
}

/**
* The user API allow to use array of modules configuration. This method manage the loading of the user modules
* along side the default modules and re map them to an object.
* Transforms an array of modules into an object. The last module will
* take precedence in case of duplicate modules
*/
export function transformModules(
modules: InputConfigModules
): Exclude<ConfigModule["modules"], undefined> {
const remappedModules = modules.reduce((acc, moduleConfig) => {
if (moduleConfig.scope === "external" && !moduleConfig.key) {
throw new Error(
"External modules configuration must have a 'key'. Please provide a key for the module."
)
}

if ("disable" in moduleConfig && "key" in moduleConfig) {
acc[moduleConfig.key!] = moduleConfig
}

// TODO: handle external modules later
let serviceName: string =
"key" in moduleConfig && moduleConfig.key ? moduleConfig.key : ""
delete moduleConfig.key

if (!serviceName && "resolve" in moduleConfig) {
if (
isString(moduleConfig.resolve!) &&
REVERSED_MODULE_PACKAGE_NAMES[moduleConfig.resolve!]
) {
serviceName = REVERSED_MODULE_PACKAGE_NAMES[moduleConfig.resolve!]
acc[serviceName] = moduleConfig
return acc
}

let resolution = isString(moduleConfig.resolve!)
? normalizeImportPathWithSource(moduleConfig.resolve as string)
: moduleConfig.resolve

const moduleExport = isString(resolution)
? require(resolution)
: resolution

const defaultExport = resolveExports(moduleExport).default

const joinerConfig =
typeof defaultExport.service.prototype.__joinerConfig === "function"
? defaultExport.service.prototype.__joinerConfig() ?? {}
: defaultExport.service.prototype.__joinerConfig ?? {}

serviceName = joinerConfig.serviceName

if (!serviceName) {
throw new Error(
`Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.`
)
}
}

acc[serviceName] = moduleConfig

return acc
}, {})

return remappedModules as Exclude<ConfigModule["modules"], undefined>
}

/**
* The user API allow to use array of modules configuration. This method manage the loading of the
* user modules along side the default modules and re map them to an object.
*
* @param configModules
*/
function resolveModules(
configModules: InputConfig["modules"]
): ConfigModule["modules"] {
): Exclude<ConfigModule["modules"], undefined> {
/**
* The default set of modules to always use. The end user can swap
* the modules by providing an alternate implementation via their
Expand Down Expand Up @@ -225,67 +291,5 @@ function resolveModules(
}
}

const remappedModules = modules.reduce((acc, moduleConfig) => {
if (moduleConfig.scope === "external" && !moduleConfig.key) {
throw new Error(
"External modules configuration must have a 'key'. Please provide a key for the module."
)
}

if ("disable" in moduleConfig && "key" in moduleConfig) {
acc[moduleConfig.key!] = moduleConfig
}

// TODO: handle external modules later
let serviceName: string =
"key" in moduleConfig && moduleConfig.key ? moduleConfig.key : ""
delete moduleConfig.key

if (!serviceName && "resolve" in moduleConfig) {
if (
isString(moduleConfig.resolve!) &&
REVERSED_MODULE_PACKAGE_NAMES[moduleConfig.resolve!]
) {
serviceName = REVERSED_MODULE_PACKAGE_NAMES[moduleConfig.resolve!]
acc[serviceName] = moduleConfig
return acc
}

let resolution = isString(moduleConfig.resolve!)
? normalizeImportPathWithSource(moduleConfig.resolve as string)
: moduleConfig.resolve

const moduleExport = isString(resolution)
? require(resolution)
: resolution

const defaultExport = resolveExports(moduleExport).default

const joinerConfig =
typeof defaultExport.service.prototype.__joinerConfig === "function"
? defaultExport.service.prototype.__joinerConfig() ?? {}
: defaultExport.service.prototype.__joinerConfig ?? {}

serviceName = joinerConfig.serviceName

if (!serviceName) {
throw new Error(
`Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.`
)
}
}

acc[serviceName] = moduleConfig

return acc
}, {})

// Remove any modules set to false
Object.keys(remappedModules).forEach((key) => {
if (remappedModules[key].disable) {
delete remappedModules[key]
}
})

return remappedModules as ConfigModule["modules"]
return transformModules(modules)
}
1 change: 1 addition & 0 deletions packages/core/utils/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,4 @@ export * from "./trim-zeros"
export * from "./upper-case-first"
export * from "./validate-handle"
export * from "./wrap-handler"
export * from "./merge-plugin-modules"
35 changes: 35 additions & 0 deletions packages/core/utils/src/common/merge-plugin-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type {
PluginDetails,
ConfigModule,
InputConfigModules,
} from "@medusajs/types"
import { transformModules } from "./define-config"

/**
* Mutates the configModules object and merges the plugin modules with
* the modules defined inside the user-config file
*/
export function mergePluginModules(
configModule: ConfigModule,
plugins: PluginDetails[]
) {
/**
* Create a flat array of all the modules exposed by the registered
* plugins
*/
const pluginsModules = plugins.reduce((result, plugin) => {
if (plugin.modules) {
result = result.concat(plugin.modules)
}
return result
}, [] as InputConfigModules)

/**
* Merge plugin modules with the modules defined within the
* config file.
*/
configModule.modules = {
...transformModules(pluginsModules),
...configModule.modules,
}
}
3 changes: 3 additions & 0 deletions packages/medusa/src/commands/db/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { join } from "path"
import {
ContainerRegistrationKeys,
MedusaError,
mergePluginModules,
} from "@medusajs/framework/utils"
import { LinkLoader } from "@medusajs/framework/links"
import { logger } from "@medusajs/framework/logger"
Expand All @@ -27,6 +28,8 @@ const main = async function ({ directory, modules }) {
)

const plugins = await getResolvedPlugins(directory, configModule, true)
mergePluginModules(configModule, plugins)

const linksSourcePaths = plugins.map((plugin) =>
join(plugin.resolve, "links")
)
Expand Down
7 changes: 6 additions & 1 deletion packages/medusa/src/commands/db/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { join } from "path"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
import {
ContainerRegistrationKeys,
mergePluginModules,
} from "@medusajs/framework/utils"
import { LinkLoader } from "@medusajs/framework/links"
import { logger } from "@medusajs/framework/logger"
import { MedusaAppLoader } from "@medusajs/framework"
Expand Down Expand Up @@ -38,6 +41,8 @@ export async function migrate({
)

const plugins = await getResolvedPlugins(directory, configModule, true)
mergePluginModules(configModule, plugins)

const linksSourcePaths = plugins.map((plugin) =>
join(plugin.resolve, "links")
)
Expand Down
3 changes: 3 additions & 0 deletions packages/medusa/src/commands/db/rollback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { join } from "path"
import {
ContainerRegistrationKeys,
MedusaError,
mergePluginModules,
} from "@medusajs/framework/utils"
import { LinkLoader } from "@medusajs/framework/links"
import { logger } from "@medusajs/framework/logger"
Expand All @@ -27,6 +28,8 @@ const main = async function ({ directory, modules }) {
)

const plugins = await getResolvedPlugins(directory, configModule, true)
mergePluginModules(configModule, plugins)

const linksSourcePaths = plugins.map((plugin) =>
join(plugin.resolve, "links")
)
Expand Down
Loading

0 comments on commit 1e1111b

Please sign in to comment.