UNPKG

@lucidcms/plugin-pages

Version:

The official Pages plugin for Lucid

1,015 lines (987 loc) 38 kB
import { logger, z } from "@lucidcms/core"; import { prefixGeneratedColName } from "@lucidcms/core/helpers"; import { inspect } from "node:util"; //#region src/translations/en-gb.json var cannot_find_collection = "Cannot find the collection of {{collection}}."; var cannot_find_required_field_message = "Cannot find required fields for the pages plugin."; var cannot_have_self_as_parent_page_message = "A page cannot be its own parent, please select a different parent page."; var slug_cannot_be_slash_and_parent_page_set_message = "The slug cannot be / when a parent page is set."; var duplicate_slug_field_found_message = "Please ensure the slug field is unique within the collection."; var duplicate_slug_and_parent_page_field_found_message = "Another document in this collection has the same slug and parent page selected. Please ensure the slug field is unique within the collection."; var an_unknown_error_occurred_checking_for_duplicate_slugs = "An error occurred while checking for duplicate slugs."; var an_unknown_error_occurred_checking_for_circular_parents = "An error occurred while checking for circular parents."; var circular_parents_error_message = "The selected page is either a child/grandchild of this one. Please select a different parent page."; var parent_page_not_found_or_doesnt_have_a_published_version = "The parent page document of the same version (draft/published) was not found, or doesnt have a slug."; var an_unknown_error_occurred_getting_parent_fields = "An error occurred while getting the parent page fields."; var an_unknown_error_occurred_getting_descendant_fields = "An error occurred while getting the descendant page fields."; var an_unknown_error_occurred_updating_fullslug_fields = "An error occurred while updating the fullSlug children fields."; var slug_field_validation_error_message = "The slug field may only contain letters, numbers, underscores, and hyphens."; var an_unknown_error_occurred_getting_document_version_fields = "An error occurred while getting the document version fields."; var full_slug = "Full Slug"; var slug = "Slug"; var parent_page = "Parent Page"; var field_required = "This field is required."; var en_gb_default = { cannot_find_collection, cannot_find_required_field_message, cannot_have_self_as_parent_page_message, slug_cannot_be_slash_and_parent_page_set_message, duplicate_slug_field_found_message, duplicate_slug_and_parent_page_field_found_message, an_unknown_error_occurred_checking_for_duplicate_slugs, an_unknown_error_occurred_checking_for_circular_parents, circular_parents_error_message, parent_page_not_found_or_doesnt_have_a_published_version, an_unknown_error_occurred_getting_parent_fields, an_unknown_error_occurred_getting_descendant_fields, an_unknown_error_occurred_updating_fullslug_fields, slug_field_validation_error_message, an_unknown_error_occurred_getting_document_version_fields, full_slug, slug, parent_page, field_required }; //#endregion //#region src/translations/index.ts const selectedLang = en_gb_default; const T = (key, data) => { const translation = selectedLang[key]; if (!translation) return key; if (!data) return translation; return translation.replace(/\{\{(\w+)\}\}/g, (_, p1) => data[p1]); }; var translations_default = T; //#endregion //#region src/constants.ts const PLUGIN_KEY = "plugin-pages"; const LUCID_VERSION = "0.x.x"; var constants_default = { collectionFieldBrickId: "collection-pseudo-brick", fields: { parentPage: { key: "parentPage" }, slug: { key: "slug" }, fullSlug: { key: "fullSlug" } } }; //#endregion //#region src/services/register-fields.ts const registerFields = (collection, config) => { collection.addText(constants_default.fields.fullSlug.key, { details: { label: translations_default("full_slug") }, config: { useTranslations: config.useTranslations, isHidden: !config.displayFullSlug, isDisabled: true }, displayInListing: config.displayFullSlug }).addText(constants_default.fields.slug.key, { details: { label: translations_default("slug") }, config: { useTranslations: config.useTranslations, isHidden: false, isDisabled: false }, validation: { required: true, zod: z.union([z.literal("/"), z.string().regex(/^[a-zA-Z0-9_-]+$/, translations_default("slug_field_validation_error_message"))]) }, displayInListing: true }).addDocument(constants_default.fields.parentPage.key, { collection: collection.key, details: { label: translations_default("parent_page") }, config: { isHidden: false, isDisabled: false } }); }; var register_fields_default = registerFields; //#endregion //#region src/services/plugin-options.ts const pluginOptions = (given) => { return { collections: given.collections.map((c) => ({ collectionKey: c.collectionKey, useTranslations: c?.useTranslations ?? false, displayFullSlug: c?.displayFullSlug ?? false })) }; }; var plugin_options_default = pluginOptions; //#endregion //#region src/services/get-target-collection.ts /** * Fetches the target collection from the plugin options */ const getTargetCollection = (data) => { const targetCollection = data.options.collections.find((c) => c.collectionKey === data.collectionKey); if (!targetCollection) return { error: { type: "basic", status: 500, message: translations_default("cannot_find_collection", { collection: data.collectionKey }) }, data: void 0 }; return { error: void 0, data: targetCollection }; }; var get_target_collection_default = getTargetCollection; //#endregion //#region src/services/get-parent-fields.ts /** * Get the parent document pages fields */ const getParentFields = async (context, data) => { try { const { version: versionTable, documentFields: fieldsTable } = data.tables; const slugColumn = prefixGeneratedColName(constants_default.fields.slug.key); const parentPageColumn = prefixGeneratedColName(constants_default.fields.parentPage.key); const fullSlugColumn = prefixGeneratedColName(constants_default.fields.fullSlug.key); const parentFields = await context.db.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).select([ `${fieldsTable}.${slugColumn}`, `${fieldsTable}.${fullSlugColumn}`, `${fieldsTable}.${parentPageColumn}`, `${versionTable}.document_id`, `${fieldsTable}.locale` ]).where(`${versionTable}.document_id`, "=", data.fields.parentPage.value).where(`${versionTable}.type`, "=", data.versionType).execute(); if (!parentFields || parentFields.length === 0) return { error: { type: "basic", status: 404, message: translations_default("parent_page_not_found_or_doesnt_have_a_published_version"), errors: { body: { fields: [{ key: constants_default.fields.parentPage.key, localeCode: data.defaultLocale, message: translations_default("parent_page_not_found_or_doesnt_have_a_published_version") }] } } }, data: void 0 }; return { error: void 0, data: parentFields }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_getting_parent_fields") }, data: void 0 }; } }; var get_parent_fields_default = getParentFields; //#endregion //#region src/utils/build-fullslug-from-fullslug.ts const buildFullSlug = (data) => { if (data.slug === null || data.slug === void 0) return null; let result = data.slug; const targetParentFullSlugField = data.parentFields.find((field) => { return field.locale === data.targetLocale; }); if (targetParentFullSlugField?._fullSlug) result = `${targetParentFullSlugField._fullSlug}/${data.slug}`; if (!result.startsWith("/")) result = `/${result}`; result = result.replace(/\/\//g, "/"); return result; }; var build_fullslug_from_fullslug_default = buildFullSlug; //#endregion //#region src/services/construct-parent-fullslug.ts /** * Constructs the fullSlug from the slug and parentPage fields */ const constructParentFullSlug = (data) => { const fullSlug = data.localisation.locales.reduce((acc, locale) => { acc[locale.code] = null; return acc; }, {}); if (data.collection.useTranslations && data.fields.slug.translations) for (let i = 0; i < data.localisation.locales.length; i++) { const locale = data.localisation.locales[i]; if (!locale) continue; fullSlug[locale.code] = build_fullslug_from_fullslug_default({ parentFields: data.parentFields || [], targetLocale: locale.code, slug: data.fields.slug.translations[locale.code] }); } else fullSlug[data.localisation.defaultLocale] = build_fullslug_from_fullslug_default({ parentFields: data.parentFields || [], targetLocale: data.localisation.defaultLocale, slug: data.fields.slug.value }); return { error: void 0, data: fullSlug }; }; var construct_parent_fullslug_default = constructParentFullSlug; //#endregion //#region src/services/set-full-slug.ts /** * Update the fullSlug field with the computed value */ const setFullSlug = (data) => { if (data.collection.useTranslations) data.fields.fullSlug.translations = data.fullSlug; else data.fields.fullSlug.value = data.fullSlug[data.defaultLocale]; return { error: void 0, data: void 0 }; }; var set_full_slug_default = setFullSlug; //#endregion //#region src/services/get-descendant-fields.ts /** * Get the descendant document pages fields */ const getDescendantFields = async (context, data) => { try { const { documentFields: fieldsTable, version: versionTable } = data.tables; const slugColumn = prefixGeneratedColName(constants_default.fields.slug.key); const fullSlugColumn = prefixGeneratedColName(constants_default.fields.fullSlug.key); const parentPageColumn = prefixGeneratedColName(constants_default.fields.parentPage.key); const descendants = await context.db.withRecursive("recursive_cte", (db) => db.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).select([ `${versionTable}.document_id as document_id`, `${fieldsTable}.${parentPageColumn} as parent_id`, `${fieldsTable}.document_version_id` ]).where(({ eb }) => eb(`${fieldsTable}.${parentPageColumn}`, "in", data.ids)).where(`${versionTable}.type`, "=", data.versionType).unionAll(db.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).innerJoin("recursive_cte as rc", "rc.document_id", `${fieldsTable}.${parentPageColumn}`).select([ `${versionTable}.document_id as document_id`, `${fieldsTable}.${parentPageColumn} as parent_id`, `${fieldsTable}.document_version_id` ]).where(`${versionTable}.type`, "=", data.versionType))).selectFrom("recursive_cte").select((eb) => [ "document_id", "document_version_id", context.config.db.jsonArrayFrom(eb.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).select([ `${fieldsTable}.locale`, `${fieldsTable}.${slugColumn} as _slug`, `${fieldsTable}.${fullSlugColumn} as _fullSlug`, `${fieldsTable}.${parentPageColumn} as _parentPage` ]).whereRef(`${versionTable}.document_id`, "=", "recursive_cte.document_id").where(`${versionTable}.type`, "=", data.versionType)).as("rows") ]).where(({ eb }) => eb("document_id", "not in", data.ids)).execute(); return { error: void 0, data: descendants.filter((d, i, self) => { return self.findIndex((e) => e.document_id === d.document_id && e.document_version_id === d.document_version_id) === i; }) }; } catch (error) { console.log(inspect(error, { depth: Number.POSITIVE_INFINITY, colors: true })); return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_getting_descendant_fields") }, data: void 0 }; } }; var get_descendant_fields_default = getDescendantFields; //#endregion //#region src/utils/build-fullslug-from-slugs.ts const buildFullSlugFromSlugs = (data) => { const rowForLocale = data.currentDescendant.rows.find((row) => row.locale === data.targetLocale); if (!rowForLocale || !rowForLocale._slug) return null; const slugFieldValue = rowForLocale._slug; const parentPageValue = rowForLocale._parentPage; if (!parentPageValue) return postSlugFormat(joinSlugs(data.topLevelFullSlug || "", slugFieldValue)); const parentDescendant = data.descendants.find((descendant) => descendant.document_id === parentPageValue); if (!parentDescendant) return postSlugFormat(joinSlugs(data.topLevelFullSlug || "", slugFieldValue)); const parentFullSlug = buildFullSlugFromSlugs({ targetLocale: data.targetLocale, currentDescendant: parentDescendant, descendants: data.descendants, topLevelFullSlug: data.topLevelFullSlug }); return postSlugFormat(joinSlugs(parentFullSlug || data.topLevelFullSlug || "", slugFieldValue)); }; const joinSlugs = (...parts) => { return parts.filter(Boolean).join("/").replace(/\/+/g, "/"); }; const postSlugFormat = (slug$1) => { if (!slug$1) return null; let res = slug$1; if (!res.startsWith("/")) res = `/${res}`; return res.replace(/\/\//g, "/"); }; var build_fullslug_from_slugs_default = buildFullSlugFromSlugs; //#endregion //#region src/services/construct-child-fullslugs.ts /** * Constructs the fullSlug for the child documents */ const constructChildFullSlug = (data) => { const documentFullSlugs = []; for (const descendant of data.descendants) { const fullSlug = {}; if (data.collection.useTranslations) { if (data.parentFullSlugField !== void 0 && !data.parentFullSlugField.translations) break; for (const locale of data.localisation.locales) { const currentFullSlugValue = data.parentFullSlugField?.translations?.[locale.code]; if (data.parentFullSlugField !== void 0 && !currentFullSlugValue) continue; fullSlug[locale.code] = build_fullslug_from_slugs_default({ targetLocale: locale.code, currentDescendant: descendant, descendants: data.descendants, topLevelFullSlug: currentFullSlugValue }); } } else { if (data.parentFullSlugField !== void 0 && !data.parentFullSlugField.value) break; fullSlug[data.localisation.defaultLocale] = build_fullslug_from_slugs_default({ targetLocale: data.localisation.defaultLocale, currentDescendant: descendant, descendants: data.descendants, topLevelFullSlug: data.parentFullSlugField?.value }); } documentFullSlugs.push({ documentId: descendant.document_id, versionId: descendant.document_version_id, fullSlugs: fullSlug }); } return { error: void 0, data: documentFullSlugs }; }; var construct_child_fullslugs_default = constructChildFullSlug; //#endregion //#region src/services/update-fullslug-fields.ts /** * Update the fullSlug fields with the computed value */ const updateFullSlugFields = async (context, data) => { try { const { documentFields: fieldsTable, version: versionTable } = data.tables; const fullSlugColumn = prefixGeneratedColName(constants_default.fields.fullSlug.key); const updateFullSlugsPromises = []; for (const doc of data.docFullSlugs) for (const [locale, fullSlug] of Object.entries(doc.fullSlugs)) updateFullSlugsPromises.push(context.db.updateTable(fieldsTable).set({ [fullSlugColumn]: fullSlug }).where((eb) => eb.exists(eb.selectFrom(versionTable).selectAll().where(`${versionTable}.id`, "=", doc.versionId).where(`${versionTable}.document_id`, "=", doc.documentId).where(`${versionTable}.type`, "=", data.versionType))).where("document_version_id", "=", doc.versionId).where("locale", "=", locale).execute()); await Promise.all(updateFullSlugsPromises); return { error: void 0, data: void 0 }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_updating_fullslug_fields") }, data: void 0 }; } }; var update_fullslug_fields_default = updateFullSlugFields; //#endregion //#region src/services/get-document-version-fields.ts /** * Get the target document versions slug, fullSlug and parentPage fields */ const getDocumentVersionFields = async (context, data) => { try { const { version: versionTable, documentFields: fieldsTable } = data.tables; const slugColumn = prefixGeneratedColName(constants_default.fields.slug.key); const fullSlugColumn = prefixGeneratedColName(constants_default.fields.fullSlug.key); const parentPageColumn = prefixGeneratedColName(constants_default.fields.parentPage.key); const fields = await context.db.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).select([ `${fieldsTable}.locale`, `${versionTable}.document_id`, `${fieldsTable}.${slugColumn}`, `${fieldsTable}.${fullSlugColumn}`, `${fieldsTable}.${parentPageColumn}` ]).where(`${versionTable}.document_id`, "=", data.documentId).where(`${versionTable}.id`, "=", data.versionId).where(`${versionTable}.type`, "=", data.versionType).execute(); if (!fields || fields.length === 0) return { error: void 0, data: null }; return { error: void 0, data: fields }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_getting_document_version_fields") }, data: void 0 }; } }; var get_document_version_fields_default = getDocumentVersionFields; //#endregion //#region src/services/checks/duplicate-slug-parents.ts /** * Query for document fields that have same slug and parentPage for each slug translation (would cause duplicate fullSlug) */ const checkDuplicateSlugParents = async (context, data) => { try { const { document: documentTable, version: versionTable, documentFields: fieldsTable } = data.tables; const slugConditions = Object.entries(data.fields.slug.translations || {}).map(([localeCode, slug$1]) => ({ localeCode, slug: slug$1 })); if (data.fields.slug.value) slugConditions.push({ localeCode: context.config.localisation.defaultLocale, slug: data.fields.slug.value }); const slugColumn = prefixGeneratedColName(constants_default.fields.slug.key); const parentPageColumn = prefixGeneratedColName(constants_default.fields.parentPage.key); const duplicates = await context.db.selectFrom(documentTable).leftJoin(versionTable, `${versionTable}.document_id`, `${documentTable}.id`).leftJoin(fieldsTable, `${fieldsTable}.document_version_id`, `${versionTable}.id`).select([ `${documentTable}.id`, `${documentTable}.collection_key`, `${fieldsTable}.${slugColumn}`, `${fieldsTable}.locale`, `${fieldsTable}.${parentPageColumn}` ]).where(({ eb, and, or }) => and([ or(slugConditions.map(({ localeCode, slug: slug$1 }) => and([eb(`${fieldsTable}.${slugColumn}`, "=", slug$1), localeCode ? eb(`${fieldsTable}.locale`, "=", localeCode) : eb(`${fieldsTable}.locale`, "is", null)]))), data.fields.parentPage.value ? eb(`${fieldsTable}.${parentPageColumn}`, "=", data.fields.parentPage.value) : eb(`${fieldsTable}.${parentPageColumn}`, "is", null), eb(`${versionTable}.type`, "=", data.versionType) ])).where(`${documentTable}.id`, "!=", data.documentId || null).where(`${documentTable}.collection_key`, "=", data.collectionKey).where(`${documentTable}.is_deleted`, "=", context.config.db.getDefault("boolean", "false")).execute(); if (duplicates.length > 0) { const fieldErrors = []; for (const duplicate of duplicates) fieldErrors.push({ key: constants_default.fields.slug.key, localeCode: duplicate.locale || void 0, message: duplicate[parentPageColumn] === null ? translations_default("duplicate_slug_field_found_message") : translations_default("duplicate_slug_and_parent_page_field_found_message") }); return { error: { type: "basic", status: 400, message: translations_default("duplicate_slug_field_found_message"), errors: { body: { fields: fieldErrors } } }, data: void 0 }; } return { error: void 0, data: void 0 }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_checking_for_duplicate_slugs") }, data: void 0 }; } }; var duplicate_slug_parents_default = checkDuplicateSlugParents; //#endregion //#region src/services/checks/root-slug-withparent.ts /** * If slug is / and parentPage is set (would cause fullSlug to be the same as parentPage just with trailing slash) */ const checkRootSlugWithParent = (data) => { if (data.collection.useTranslations && data.fields.slug.translations) { const fieldErrors = []; for (const [key, value] of Object.entries(data.fields.slug.translations)) if (value === "/" && data.fields.parentPage.value) fieldErrors.push({ key: constants_default.fields.slug.key, localeCode: key, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message") }); if (fieldErrors.length > 0) return { error: { type: "basic", status: 400, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message"), errors: { body: { fields: fieldErrors } } }, data: void 0 }; } else if (data.fields.slug.value === "/" && data.fields.parentPage.value) return { error: { type: "basic", status: 400, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message"), errors: { body: { fields: [{ key: constants_default.fields.parentPage.key, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message") }] } } }, data: void 0 }; return { error: void 0, data: void 0 }; }; var root_slug_withparent_default = checkRootSlugWithParent; //#endregion //#region src/services/checks/page-is-parent-of-self.ts /** * Returns an error if the parentPage field is set to the same document as the current document */ const checkParentIsPageOfSelf = (data) => { if (data.fields.parentPage.value && data.fields.parentPage.value === data.documentId) return { error: { type: "basic", status: 400, message: translations_default("cannot_have_self_as_parent_page_message"), errors: { body: { fields: [{ key: constants_default.fields.parentPage.key, localeCode: data.defaultLocale, message: translations_default("cannot_have_self_as_parent_page_message") }] } } }, data: void 0 }; return { error: void 0, data: void 0 }; }; var page_is_parent_of_self_default = checkParentIsPageOfSelf; //#endregion //#region src/services/checks/check-fields-exist.ts /** * Returns an error if the required fields do not exist */ const checkFieldsExist = (data) => { const fieldErrors = []; if (data.fields.slug === void 0) fieldErrors.push({ key: "slug", localeCode: null, message: translations_default("field_required") }); if (data.fields.parentPage === void 0) fieldErrors.push({ key: "parentPage", localeCode: null, message: translations_default("field_required") }); if (data.fields.fullSlug === void 0) fieldErrors.push({ key: "fullSlug", localeCode: null, message: translations_default("field_required") }); if (fieldErrors.length) return { error: { type: "basic", message: translations_default("cannot_find_required_field_message"), status: 400, errors: { body: { fields: fieldErrors } } }, data: void 0 }; return { error: void 0, data: { slug: data.fields.slug, parentPage: data.fields.parentPage, fullSlug: data.fields.fullSlug } }; }; var check_fields_exist_default = checkFieldsExist; //#endregion //#region src/services/checks/circular-parents.ts /** * Recursively checks all parent pages for a circular reference and errors in that case */ const checkCircularParents = async (context, data) => { try { if (!data.documentId || !data.fields.parentPage.value) return { error: void 0, data: void 0 }; const { version: versionTable, documentFields: fieldsTable } = data.tables; const parentPageField = prefixGeneratedColName(constants_default.fields.parentPage.key); const result = await context.db.withRecursive("ancestors", (db) => db.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).select([`${versionTable}.document_id as current_id`, `${fieldsTable}.${parentPageField} as parent_id`]).where(`${fieldsTable}.locale`, "=", data.defaultLocale).where(`${versionTable}.type`, "=", data.versionType).where(`${versionTable}.document_id`, "=", data.fields.parentPage.value).unionAll(db.selectFrom(fieldsTable).innerJoin(versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id`).innerJoin("ancestors", "ancestors.parent_id", `${versionTable}.document_id`).select([`${versionTable}.document_id as current_id`, `${fieldsTable}.${parentPageField} as parent_id`]).where(`${fieldsTable}.locale`, "=", data.defaultLocale).where(`${versionTable}.type`, "=", data.versionType))).selectFrom("ancestors").select("parent_id").where("parent_id", "=", data.documentId).executeTakeFirst(); if (result) return { error: { type: "basic", status: 400, message: translations_default("circular_parents_error_message"), errors: { body: { fields: [{ key: constants_default.fields.parentPage.key, localeCode: data.defaultLocale, message: translations_default("circular_parents_error_message") }] } } }, data: void 0 }; return { error: void 0, data: void 0 }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_checking_for_circular_parents") }, data: void 0 }; } }; var circular_parents_default = checkCircularParents; //#endregion //#region src/services/hooks/before-upsert-handler.ts const beforeUpsertHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) return { error: void 0, data: data.data }; const checkFieldsExistRes = check_fields_exist_default({ fields: { slug: data.data.fields?.find((f) => f.key === constants_default.fields.slug.key && f.type === "text"), parentPage: data.data.fields?.find((f) => f.key === constants_default.fields.parentPage.key && f.type === "document"), fullSlug: data.data.fields?.find((f) => f.key === constants_default.fields.fullSlug.key && f.type === "text") } }); if (checkFieldsExistRes.error) return checkFieldsExistRes; const { slug: slug$1, parentPage, fullSlug } = checkFieldsExistRes.data; const checkParentIsPageOfSelfRes = page_is_parent_of_self_default({ defaultLocale: context.config.localisation.defaultLocale, documentId: data.data.documentId, fields: { parentPage } }); if (checkParentIsPageOfSelfRes.error) return checkParentIsPageOfSelfRes; const checkRootSlugWithParentRes = root_slug_withparent_default({ collection: targetCollectionRes.data, defaultLocale: context.config.localisation.defaultLocale, fields: { slug: slug$1, parentPage } }); if (checkRootSlugWithParentRes.error) return checkRootSlugWithParentRes; const checkDuplicateSlugParentsRes = await duplicate_slug_parents_default(context, { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, collectionKey: targetCollectionRes.data.collectionKey, fields: { slug: slug$1, parentPage }, tables: data.meta.collectionTableNames }); if (checkDuplicateSlugParentsRes.error) return checkDuplicateSlugParentsRes; let parentFieldsData = []; if (parentPage.value) { const circularParentsRes = await circular_parents_default(context, { documentId: data.data.documentId, versionType: data.data.versionType, defaultLocale: context.config.localisation.defaultLocale, fields: { parentPage }, tables: data.meta.collectionTableNames }); if (circularParentsRes.error) return circularParentsRes; const parentFieldsRes = await get_parent_fields_default(context, { defaultLocale: context.config.localisation.defaultLocale, versionType: data.data.versionType, fields: { parentPage }, tables: data.meta.collectionTableNames }); if (parentFieldsRes.error) return parentFieldsRes; parentFieldsData = parentFieldsRes.data; } const fullSlugRes = construct_parent_fullslug_default({ parentFields: parentFieldsData, localisation: context.config.localisation, collection: targetCollectionRes.data, fields: { slug: slug$1 } }); if (fullSlugRes.error) return fullSlugRes; set_full_slug_default({ fullSlug: fullSlugRes.data, defaultLocale: context.config.localisation.defaultLocale, collection: targetCollectionRes.data, fields: { fullSlug } }); return { error: void 0, data: data.data }; }; var before_upsert_handler_default = beforeUpsertHandler; //#endregion //#region src/services/hooks/after-upsert-handler.ts const afterUpsertHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) return { error: void 0, data: void 0 }; const descendantsRes = await get_descendant_fields_default(context, { ids: [data.data.documentId], versionType: data.data.versionType, tables: data.meta.collectionTableNames }); if (descendantsRes.error) return descendantsRes; if (descendantsRes.data.length === 0) return { error: void 0, data: void 0 }; const currentFullSlugField = data.data.fields.find((field) => { return field.key === constants_default.fields.fullSlug.key; }); if (!currentFullSlugField) return { error: void 0, data: void 0 }; const docFullSlugsRes = construct_child_fullslugs_default({ descendants: descendantsRes.data, localisation: context.config.localisation, parentFullSlugField: currentFullSlugField, collection: targetCollectionRes.data }); if (docFullSlugsRes.error) return docFullSlugsRes; await update_fullslug_fields_default(context, { docFullSlugs: docFullSlugsRes.data, versionType: data.data.versionType, tables: data.meta.collectionTableNames }); return { error: void 0, data: void 0 }; }; var after_upsert_handler_default = afterUpsertHandler; //#endregion //#region src/services/hooks/before-delete-handler.ts const beforeDeleteHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) return { error: void 0, data: void 0 }; const versionTypes = ["draft", "published"]; for (const versionType of versionTypes) { const descendantsRes = await get_descendant_fields_default(context, { ids: data.data.ids, versionType, tables: data.meta.collectionTableNames }); if (descendantsRes.error) return descendantsRes; if (descendantsRes.data.length === 0) continue; const docFullSlugsRes = construct_child_fullslugs_default({ descendants: descendantsRes.data, localisation: context.config.localisation, collection: targetCollectionRes.data }); if (docFullSlugsRes.error) return docFullSlugsRes; await update_fullslug_fields_default(context, { docFullSlugs: docFullSlugsRes.data, versionType, tables: data.meta.collectionTableNames }); } return { error: void 0, data: void 0 }; }; var before_delete_handler_default = beforeDeleteHandler; //#endregion //#region src/utils/field-res-to-schema.ts const fieldResToSchema = (key, useTranslations, defaultLocale, items) => { const fieldType = getFieldTypeFromKey(key); if (!fieldType) throw new Error(`Unable to determine field type for key: ${key}`); const result = { key, type: fieldType }; if (useTranslations) { result.translations = {}; for (const item of items) if (fieldType === "text") result.translations[item.locale] = item[`_${key}`]; else if (fieldType === "document") result.translations[item.locale] = item[`_${key}`]; } else { const defaultItem = items.find((item) => item.locale === defaultLocale) || items[0]; if (fieldType === "text") result.value = defaultItem[`_${key}`]; else if (fieldType === "document") result.value = defaultItem[`_${key}`]; } return result; }; function getFieldTypeFromKey(key) { switch (key) { case "slug": case "fullSlug": return "text"; case "parentPage": return "document"; default: return void 0; } } var field_res_to_schema_default = fieldResToSchema; //#endregion //#region src/services/hooks/version-promote.ts const versionPromoteHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) return { error: void 0, data: void 0 }; let createFullSlug = true; const docVersionFieldRes = await get_document_version_fields_default(context, { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, tables: data.meta.collectionTableNames }); if (docVersionFieldRes.error) return docVersionFieldRes; if (docVersionFieldRes.data === null) createFullSlug = false; const checkFieldsExistRes = check_fields_exist_default({ fields: { slug: field_res_to_schema_default(constants_default.fields.slug.key, targetCollectionRes.data.useTranslations, context.config.localisation.defaultLocale, docVersionFieldRes.data || []), parentPage: field_res_to_schema_default(constants_default.fields.parentPage.key, false, context.config.localisation.defaultLocale, docVersionFieldRes.data || []), fullSlug: field_res_to_schema_default(constants_default.fields.fullSlug.key, targetCollectionRes.data.useTranslations, context.config.localisation.defaultLocale, docVersionFieldRes.data || []) } }); if (checkFieldsExistRes.error) return checkFieldsExistRes; const { slug: slug$1, parentPage, fullSlug } = checkFieldsExistRes.data; if (createFullSlug) { const checkDuplicateSlugParentsRes = await duplicate_slug_parents_default(context, { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, collectionKey: targetCollectionRes.data.collectionKey, fields: { slug: slug$1, parentPage }, tables: data.meta.collectionTableNames }); if (checkDuplicateSlugParentsRes.error) return checkDuplicateSlugParentsRes; let parentFieldsData = []; if (parentPage.value) { const circularParentsRes = await circular_parents_default(context, { documentId: data.data.documentId, versionType: data.data.versionType, defaultLocale: context.config.localisation.defaultLocale, fields: { parentPage }, tables: data.meta.collectionTableNames }); if (circularParentsRes.error) return circularParentsRes; const parentFieldsRes = await get_parent_fields_default(context, { defaultLocale: context.config.localisation.defaultLocale, versionType: data.data.versionType, fields: { parentPage }, tables: data.meta.collectionTableNames }); if (parentFieldsRes.error) return parentFieldsRes; parentFieldsData = parentFieldsRes.data; } const fullSlugRes = construct_parent_fullslug_default({ parentFields: parentFieldsData, localisation: context.config.localisation, collection: targetCollectionRes.data, fields: { slug: slug$1 } }); if (fullSlugRes.error) return fullSlugRes; set_full_slug_default({ fullSlug: fullSlugRes.data, defaultLocale: context.config.localisation.defaultLocale, collection: targetCollectionRes.data, fields: { fullSlug } }); const updateFullSlugRes = await update_fullslug_fields_default(context, { docFullSlugs: [{ documentId: data.data.documentId, versionId: data.data.versionId, fullSlugs: fullSlugRes.data }], versionType: data.data.versionType, tables: data.meta.collectionTableNames }); if (updateFullSlugRes.error) return updateFullSlugRes; } await after_upsert_handler_default(options)(context, { meta: { collection: data.meta.collection, collectionKey: data.meta.collectionKey, userId: data.meta.userId, collectionTableNames: data.meta.collectionTableNames }, data: { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, bricks: [], fields: [ slug$1, parentPage, fullSlug ] } }); return { error: void 0, data: void 0 }; }; var version_promote_default = versionPromoteHandler; //#endregion //#region src/plugin.ts const plugin = async (config, plugin$1) => { const options = plugin_options_default(plugin$1); for (const collectionConfig of options.collections) { const collectionInstance = config.collections.find((c) => c.key === collectionConfig.collectionKey); if (!collectionInstance) { logger.warn({ message: translations_default("cannot_find_collection", { collection: collectionConfig.collectionKey }), scope: PLUGIN_KEY }); continue; } register_fields_default(collectionInstance, collectionConfig); if (!collectionInstance.config.hooks) collectionInstance.config.hooks = []; } config.hooks.push({ service: "documents", event: "beforeUpsert", handler: before_upsert_handler_default(options) }); config.hooks.push({ service: "documents", event: "afterUpsert", handler: after_upsert_handler_default(options) }); config.hooks.push({ service: "documents", event: "beforeDelete", handler: before_delete_handler_default(options) }); config.hooks.push({ service: "documents", event: "versionPromote", handler: version_promote_default(options) }); return { key: PLUGIN_KEY, lucid: LUCID_VERSION, config }; }; var plugin_default = plugin; //#endregion //#region src/index.ts const lucidPagesPlugin = (pluginOptions$1) => (config) => plugin_default(config, pluginOptions$1); var src_default = lucidPagesPlugin; //#endregion export { src_default as default }; //# sourceMappingURL=index.js.map