Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions packages/payload/src/config/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,15 +460,6 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise<SanitizedC
config.csrf!.push(config.serverURL!)
}

const uploadAdapters = new Set<string>()
// interact with all collections
for (const collection of config.collections!) {
// deduped upload adapters
if (collection.upload?.adapter) {
uploadAdapters.add(collection.upload.adapter)
}
}

if (!config.upload) {
config.upload = { adapters: [] }
}
Expand Down
54 changes: 23 additions & 31 deletions packages/plugin-ecommerce/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import type { Config, Endpoint } from 'payload'

import { deepMergeSimple } from 'payload/shared'

import type { PluginDefaultTranslationsObject } from './translations/types.js'
import type { EcommercePluginConfig, SanitizedEcommercePluginConfig } from './types/index.js'

Expand Down Expand Up @@ -311,41 +309,35 @@ export const ecommercePlugin =
incomingConfig.i18n = {}
}

if (!incomingConfig.i18n?.translations) {
if (!incomingConfig.i18n.translations) {
incomingConfig.i18n.translations = {}
}

incomingConfig.i18n.translations = deepMergeSimple(
translations,
incomingConfig.i18n?.translations,
)

/**
* Merge plugin translations
* Merge plugin translations — only for languages the user has enabled.
* Plugins run before sanitize, so `supportedLanguages` may be undefined; sanitize will
* default it to `{ en }`, so we mirror that here. Plugin-ecommerce translations always
* win over user-provided ones for the `plugin-ecommerce` namespace.
*/
if (!incomingConfig.i18n) {
incomingConfig.i18n = {}
}
Object.entries(translations).forEach(([locale, pluginI18nObject]) => {
const typedLocale = locale as AcceptedLanguages
if (!incomingConfig.i18n!.translations) {
incomingConfig.i18n!.translations = {}
const supportedLanguageKeys = incomingConfig.i18n?.supportedLanguages
? Object.keys(incomingConfig.i18n.supportedLanguages)
: ['en']

for (const lang of supportedLanguageKeys) {
const pluginEntry = translations[lang as keyof typeof translations]
if (!pluginEntry) {
continue
}
if (!(typedLocale in incomingConfig.i18n!.translations)) {
incomingConfig.i18n!.translations[typedLocale] = {}
}
if (!('plugin-ecommerce' in incomingConfig.i18n!.translations[typedLocale]!)) {
;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[
'plugin-ecommerce'
] = {} as PluginDefaultTranslationsObject['plugin-ecommerce']
}

;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[
'plugin-ecommerce'
] = {
...pluginI18nObject.translations['plugin-ecommerce'],
}
})
const typedLocale = lang as AcceptedLanguages
const existing = (incomingConfig.i18n.translations[typedLocale] ?? {}) as Record<
string,
unknown
>
incomingConfig.i18n.translations[typedLocale] = {
...existing,
'plugin-ecommerce': pluginEntry.translations['plugin-ecommerce'],
} as PluginDefaultTranslationsObject
}

if (!incomingConfig.typescript) {
incomingConfig.typescript = {}
Expand Down
22 changes: 14 additions & 8 deletions packages/plugin-import-export/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,21 @@ export const importExportPlugin =
}

/**
* Merge plugin translations
* Merge plugin translations — only for languages the user has enabled.
* Plugins run before sanitize, so `supportedLanguages` may be undefined; sanitize will
* default it to `{ en }`, so we mirror that here to avoid merging 30+ unused tables.
*/
const simplifiedTranslations = Object.entries(translations).reduce(
(acc, [key, value]) => {
acc[key] = value.translations
return acc
},
{} as Record<string, PluginDefaultTranslationsObject>,
)
const supportedLanguageKeys = config.i18n?.supportedLanguages
? Object.keys(config.i18n.supportedLanguages)
: ['en']

const simplifiedTranslations: Record<string, PluginDefaultTranslationsObject> = {}
for (const lang of supportedLanguageKeys) {
const entry = translations[lang as keyof typeof translations]
if (entry) {
simplifiedTranslations[lang] = entry.translations
}
}

config.i18n = {
...config.i18n,
Expand Down
18 changes: 11 additions & 7 deletions packages/plugin-search/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ export const searchPlugin =
incomingPluginConfig.localize = shouldLocalize

if (collections) {
const labels = Object.fromEntries(
collections
.filter(({ slug }) => incomingPluginConfig.collections?.includes(slug))
.map((collection) => [collection.slug, collection.labels]),
)
// O(1) slug lookup for enabled-collection checks; replaces an Array.indexOf in the
// hook-attachment pass that was O(M) per collection.
const enabledSlugSet = new Set(incomingPluginConfig.collections ?? [])

const labels: Record<string, (typeof collections)[number]['labels']> = {}
for (const collection of collections) {
if (enabledSlugSet.has(collection.slug)) {
labels[collection.slug] = collection.labels
}
}

const pluginConfig: SanitizedSearchPluginConfig<ConfigTypes> = {
// write any config defaults here
Expand All @@ -42,8 +47,7 @@ export const searchPlugin =
?.map((collection) => {
const { hooks: existingHooks } = collection

const enabledCollections = pluginConfig.collections || []
const isEnabled = enabledCollections.indexOf(collection.slug) > -1
const isEnabled = enabledSlugSet.has(collection.slug)
if (isEnabled) {
return {
...collection,
Expand Down
184 changes: 97 additions & 87 deletions packages/plugin-seo/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,105 +130,115 @@ export const seoPlugin =

return collection
}) || [],
endpoints: [
...(config.endpoints ?? []),
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()
endpoints: (() => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's just gonna be creating the 2 maps, can we move that in the plugin function body instead of creating and calling this inline function?

// Built once per plugin init: avoid an O(N) array scan per request × 4 endpoints.
// Closes over the plugin's input `config` snapshot — same lifetime as the prior
// `.find()` calls below, so behavior is preserved.
const collectionConfigBySlug = new Map<string, NonNullable<Config['collections']>[number]>()
for (const c of config.collections ?? []) {
Comment thread
paulpopus marked this conversation as resolved.
Outdated
collectionConfigBySlug.set(c.slug, c)
}
const globalConfigBySlug = new Map<string, NonNullable<Config['globals']>[number]>()
for (const g of config.globals ?? []) {
globalConfigBySlug.set(g.slug, g)
}
const getCollectionConfig = (slug: string | undefined) =>
slug ? collectionConfigBySlug.get(slug) : undefined
const getGlobalConfig = (slug: string | undefined) =>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary code / function call overhead, Map.get returns undefined if not found already.

slug ? globalConfigBySlug.get(slug) : undefined

const reqData = data ?? req.data
return [
...(config.endpoints ?? []),
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()

const result = pluginConfig.generateTitle
? await pluginConfig.generateTitle({
...data,
collectionConfig: config.collections?.find(
(c) => c.slug === reqData.collectionSlug,
),
globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug),
req,
} satisfies Parameters<GenerateTitle>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
const reqData = data ?? req.data

const result = pluginConfig.generateTitle
? await pluginConfig.generateTitle({
...data,
collectionConfig: getCollectionConfig(reqData.collectionSlug),
globalConfig: getGlobalConfig(reqData.globalSlug),
req,
} satisfies Parameters<GenerateTitle>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
},
method: 'post',
path: '/plugin-seo/generate-title',
},
method: 'post',
path: '/plugin-seo/generate-title',
},
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()

const reqData = data ?? req.data
const reqData = data ?? req.data

const result = pluginConfig.generateDescription
? await pluginConfig.generateDescription({
...data,
collectionConfig: config.collections?.find(
(c) => c.slug === reqData.collectionSlug,
),
globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug),
req,
} satisfies Parameters<GenerateDescription>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
const result = pluginConfig.generateDescription
? await pluginConfig.generateDescription({
...data,
collectionConfig: getCollectionConfig(reqData.collectionSlug),
globalConfig: getGlobalConfig(reqData.globalSlug),
req,
} satisfies Parameters<GenerateDescription>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
},
method: 'post',
path: '/plugin-seo/generate-description',
},
method: 'post',
path: '/plugin-seo/generate-description',
},
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()

const reqData = data ?? req.data
const reqData = data ?? req.data

const result = pluginConfig.generateURL
? await pluginConfig.generateURL({
...data,
collectionConfig: config.collections?.find(
(c) => c.slug === reqData.collectionSlug,
),
globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug),
req,
} satisfies Parameters<GenerateURL>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
const result = pluginConfig.generateURL
? await pluginConfig.generateURL({
...data,
collectionConfig: getCollectionConfig(reqData.collectionSlug),
globalConfig: getGlobalConfig(reqData.globalSlug),
req,
} satisfies Parameters<GenerateURL>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
},
method: 'post',
path: '/plugin-seo/generate-url',
},
method: 'post',
path: '/plugin-seo/generate-url',
},
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()
{
handler: async (req) => {
const data: Omit<
Parameters<GenerateTitle>[0],
'collectionConfig' | 'globalConfig' | 'req'
> = await req.json?.()

const reqData = data ?? req.data
const reqData = data ?? req.data

const result = pluginConfig.generateImage
? await pluginConfig.generateImage({
...data,
collectionConfig: config.collections?.find(
(c) => c.slug === reqData.collectionSlug,
),
globalConfig: config.globals?.find((g) => g.slug === reqData.globalSlug),
req,
} satisfies Parameters<GenerateImage>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
const result = pluginConfig.generateImage
? await pluginConfig.generateImage({
...data,
collectionConfig: getCollectionConfig(reqData.collectionSlug),
globalConfig: getGlobalConfig(reqData.globalSlug),
req,
} satisfies Parameters<GenerateImage>[0])
: ''
return new Response(JSON.stringify({ result }), { status: 200 })
},
method: 'post',
path: '/plugin-seo/generate-image',
},
method: 'post',
path: '/plugin-seo/generate-image',
},
],
]
})(),
globals:
config.globals?.map((global) => {
const { slug } = global
Expand Down
Loading
Loading