{"version":3,"file":"useContentTypeSchema.mjs","sources":["../../../admin/src/hooks/useContentTypeSchema.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, useAPIErrorHandler } from '@strapi/admin/strapi-admin';\n\nimport { useGetInitialDataQuery } from '../services/init';\n\nimport type { Component } from '../../../shared/contracts/components';\nimport type { ContentType } from '../../../shared/contracts/content-types';\nimport type { GetInitData } from '../../../shared/contracts/init';\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * useContentTypeSchema\n * -----------------------------------------------------------------------------------------------*/\ntype ComponentsDictionary = Record<string, Component>;\n\nconst EMPTY_COMPONENTS: ComponentsDictionary = {};\n\ntype InitialData = GetInitData.Response['data'];\n\n// Module-level cache preserves schema derivation identities across hook instances;\n// `useMemo` would only stabilize values inside a single component tree.\nconst schemaInfoCache = new WeakMap<\n  InitialData,\n  Map<\n    string | undefined,\n    {\n      components?: ComponentsDictionary;\n      contentType?: ContentType;\n      contentTypes: ContentType[];\n    }\n  >\n>();\n\nconst getSchemaInfo = (data: InitialData | undefined, model?: string) => {\n  if (!data) {\n    return {\n      components: undefined,\n      contentType: undefined,\n      contentTypes: [],\n    };\n  }\n\n  let cachedByModel = schemaInfoCache.get(data);\n\n  if (!cachedByModel) {\n    cachedByModel = new Map();\n    schemaInfoCache.set(data, cachedByModel);\n  }\n\n  const cached = cachedByModel.get(model);\n\n  if (cached) {\n    return cached;\n  }\n\n  const contentType = data.contentTypes.find((ct) => ct.uid === model);\n\n  const componentsByKey = data.components.reduce<ComponentsDictionary>((acc, component) => {\n    acc[component.uid] = component;\n\n    return acc;\n  }, {});\n\n  const components = extractContentTypeComponents(contentType?.attributes, componentsByKey);\n\n  const schemaInfo = {\n    components: Object.keys(components).length === 0 ? undefined : components,\n    contentType,\n    contentTypes: data.contentTypes,\n  };\n\n  cachedByModel.set(model, schemaInfo);\n\n  return schemaInfo;\n};\n\n/**\n * @internal\n * @description Given a model UID, return the schema and the schemas\n * of the associated components within said model's schema. A wrapper\n * implementation around the `useGetInitialDataQuery` with a unique\n * `selectFromResult` function to memoize the calculation.\n *\n * If no model is provided, the hook will return all the schemas.\n */\nconst useContentTypeSchema = (model?: string) => {\n  const { toggleNotification } = useNotification();\n  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n\n  const { data, error, isLoading, isFetching } = useGetInitialDataQuery(undefined);\n\n  const { components, contentType, contentTypes } = React.useMemo(\n    () => getSchemaInfo(data, model),\n    [model, data]\n  );\n\n  React.useEffect(() => {\n    if (error) {\n      toggleNotification({\n        type: 'danger',\n        message: formatAPIError(error),\n      });\n    }\n  }, [toggleNotification, error, formatAPIError]);\n\n  return {\n    components: components ?? EMPTY_COMPONENTS,\n    schema: contentType,\n    schemas: contentTypes,\n    isLoading: isLoading || isFetching,\n  };\n};\n\n/* -------------------------------------------------------------------------------------------------\n * extractContentTypeComponents\n * -----------------------------------------------------------------------------------------------*/\n/**\n * @internal\n * @description Extracts the components used in a content type's attributes recursively.\n */\nconst extractContentTypeComponents = (\n  attributes: ContentType['attributes'] = {},\n  allComponents: ComponentsDictionary = {}\n): ComponentsDictionary => {\n  const getComponents = (attributes: Schema.Attribute.AnyAttribute[]) => {\n    return attributes.reduce<string[]>((acc, attribute) => {\n      /**\n       * If the attribute is a component or dynamiczone, we need to recursively\n       * extract the component UIDs from its attributes.\n       */\n      if (attribute.type === 'component') {\n        const componentAttributes = Object.values(\n          allComponents[attribute.component]?.attributes ?? {}\n        );\n\n        acc.push(attribute.component, ...getComponents(componentAttributes));\n      } else if (attribute.type === 'dynamiczone') {\n        acc.push(\n          ...attribute.components,\n          /**\n           * Dynamic zones have an array of components, so we flatMap over them\n           * performing the same search as above.\n           */\n          ...attribute.components.flatMap((componentUid) => {\n            const componentAttributes = Object.values(\n              allComponents[componentUid]?.attributes ?? {}\n            );\n\n            return getComponents(componentAttributes);\n          })\n        );\n      }\n\n      return acc;\n    }, []);\n  };\n\n  const componentUids = getComponents(Object.values(attributes));\n\n  const uniqueComponentUids = [...new Set(componentUids)];\n\n  const componentsByKey = uniqueComponentUids.reduce<ComponentsDictionary>((acc, uid) => {\n    const component = allComponents[uid];\n    if (component) {\n      acc[uid] = component;\n    }\n\n    return acc;\n  }, {});\n\n  return componentsByKey;\n};\n\nexport { useContentTypeSchema, extractContentTypeComponents };\nexport type { ComponentsDictionary };\n"],"names":["EMPTY_COMPONENTS","schemaInfoCache","WeakMap","getSchemaInfo","data","model","components","undefined","contentType","contentTypes","cachedByModel","get","Map","set","cached","find","ct","uid","componentsByKey","reduce","acc","component","extractContentTypeComponents","attributes","schemaInfo","Object","keys","length","useContentTypeSchema","toggleNotification","useNotification","_unstableFormatAPIError","formatAPIError","useAPIErrorHandler","error","isLoading","isFetching","useGetInitialDataQuery","React","useMemo","useEffect","type","message","schema","schemas","allComponents","getComponents","attribute","componentAttributes","values","push","flatMap","componentUid","componentUids","uniqueComponentUids","Set"],"mappings":"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"}