@wordpress/core-data
Version:
Access to and manipulation of core WordPress entities.
5 lines • 62 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/selectors.ts"],
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { createSelector, createRegistrySelector } from '@wordpress/data';\nimport { addQueryArgs } from '@wordpress/url';\nimport type { UndoManager } from '@wordpress/undo-manager';\nimport deprecated from '@wordpress/deprecated';\nimport type { ConnectionStatus } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { STORE_NAME } from './name';\nimport {\n\tgetQueriedItems,\n\tgetQueriedTotalItems,\n\tgetQueriedTotalPages,\n} from './queried-data';\nimport { DEFAULT_ENTITY_KEY } from './entities';\nimport { getUndoManager } from './private-selectors';\nimport {\n\tgetNormalizedCommaSeparable,\n\tisRawAttribute,\n\tsetNestedValue,\n\tisNumericID,\n\tgetUserPermissionCacheKey,\n} from './utils';\nimport type * as ET from './entity-types';\nimport logEntityDeprecation from './utils/log-entity-deprecation';\n\n// This is an incomplete, high-level approximation of the State type.\n// It makes the selectors slightly more safe, but is intended to evolve\n// into a more detailed representation over time.\n// See https://github.com/WordPress/gutenberg/pull/40025#discussion_r865410589 for more context.\nexport interface State {\n\tautosaves: Record< string | number, Array< unknown > >;\n\tblockPatterns: Array< unknown >;\n\tblockPatternCategories: Array< unknown >;\n\tcurrentGlobalStylesId: string;\n\tcurrentTheme: string;\n\tcurrentUser: ET.User< 'view' >;\n\tembedPreviews: Record< string, { html: string } >;\n\tentities: EntitiesState;\n\tthemeBaseGlobalStyles: Record< string, Object >;\n\tthemeGlobalStyleVariations: Record< string, string >;\n\tthemeGlobalStyleRevisions: Record< number, Object >;\n\tundoManager: UndoManager;\n\tuserPermissions: Record< string, boolean >;\n\tusers: UserState;\n\tnavigationFallbackId: EntityRecordKey;\n\tuserPatternCategories: Array< UserPatternCategory >;\n\tdefaultTemplates: Record< string, string >;\n\tregisteredPostMeta: Record< string, Object >;\n\teditorSettings: Record< string, any > | null;\n\teditorAssets: Record< string, any > | null;\n\ticons: Icon[];\n\tsyncConnectionStatuses?: Record< string, ConnectionStatus >;\n}\n\ntype EntityRecordKey = string | number;\n\nexport interface Icon {\n\tname: string;\n\tcontent: string;\n\tlabel: string;\n}\n\ninterface EntitiesState {\n\tconfig: EntityConfig[];\n\trecords: Record< string, Record< string, EntityState< ET.EntityRecord > > >;\n}\n\ninterface QueriedData {\n\titems: Record< ET.Context, Record< number, ET.EntityRecord > >;\n\titemIsComplete: Record< ET.Context, Record< number, boolean > >;\n\tqueries: Record< ET.Context, Record< string, Array< number > > >;\n}\n\ntype RevisionRecord =\n\t| Record< ET.Context, Record< number, ET.PostRevision > >\n\t| Record< ET.Context, Record< number, ET.GlobalStylesRevision > >;\n\ninterface RevisionsQueriedData {\n\titems: RevisionRecord;\n\titemIsComplete: Record< ET.Context, Record< number, boolean > >;\n\tqueries: Record< ET.Context, Record< string, Array< number > > >;\n}\n\ninterface EntityState< EntityRecord extends ET.EntityRecord > {\n\tedits: Record< string, Partial< EntityRecord > >;\n\tsaving: Record<\n\t\tstring,\n\t\tPartial< { pending: boolean; isAutosave: boolean; error: Error } >\n\t>;\n\tdeleting: Record< string, Partial< { pending: boolean; error: Error } > >;\n\tqueriedData: QueriedData;\n\trevisions?: RevisionsQueriedData;\n}\n\ninterface EntityConfig {\n\tname: string;\n\tkind: string;\n}\n\ninterface UserState {\n\tqueries: Record< string, EntityRecordKey[] >;\n\tbyId: Record< EntityRecordKey, ET.User< 'edit' > >;\n}\n\ntype TemplateQuery = {\n\tslug?: string;\n\tis_custom?: boolean;\n\tignore_empty?: boolean;\n};\n\nexport interface UserPatternCategory {\n\tid: number;\n\tname: string;\n\tlabel: string;\n\tslug: string;\n\tdescription: string;\n}\n\ntype Optional< T > = T | undefined;\n\n/**\n * HTTP Query parameters sent with the API request to fetch the entity records.\n */\nexport type GetRecordsHttpQuery = Record< string, any >;\n\n/**\n * Arguments for EntityRecord selectors.\n */\ntype EntityRecordArgs =\n\t| [ string, string, EntityRecordKey ]\n\t| [ string, string, EntityRecordKey, GetRecordsHttpQuery ];\n\ntype EntityResource = { kind: string; name: string; id?: EntityRecordKey };\n\n/**\n * Shared reference to an empty object for cases where it is important to avoid\n * returning a new object reference on every invocation, as in a connected or\n * other pure component which performs `shouldComponentUpdate` check on props.\n * This should be used as a last resort, since the normalized data should be\n * maintained by the reducer result in state.\n */\nconst EMPTY_OBJECT = {};\n\n/**\n * Returns true if a request is in progress for embed preview data, or false\n * otherwise.\n *\n * @param state Data state.\n * @param url URL the preview would be for.\n *\n * @return Whether a request is in progress for an embed preview.\n */\nexport const isRequestingEmbedPreview = createRegistrySelector(\n\t( select: any ) =>\n\t\t( state: State, url: string ): boolean => {\n\t\t\treturn select( STORE_NAME ).isResolving( 'getEmbedPreview', [\n\t\t\t\turl,\n\t\t\t] );\n\t\t}\n);\n\n/**\n * Returns all available authors.\n *\n * @deprecated since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead.\n *\n * @param state Data state.\n * @param query Optional object of query parameters to\n * include with request. For valid query parameters see the [Users page](https://developer.wordpress.org/rest-api/reference/users/) in the REST API Handbook and see the arguments for [List Users](https://developer.wordpress.org/rest-api/reference/users/#list-users) and [Retrieve a User](https://developer.wordpress.org/rest-api/reference/users/#retrieve-a-user).\n * @return Authors list.\n */\nexport function getAuthors(\n\tstate: State,\n\tquery?: GetRecordsHttpQuery\n): ET.User[] {\n\tdeprecated( \"select( 'core' ).getAuthors()\", {\n\t\tsince: '5.9',\n\t\talternative: \"select( 'core' ).getUsers({ who: 'authors' })\",\n\t} );\n\n\tconst path = addQueryArgs(\n\t\t'/wp/v2/users/?who=authors&per_page=100',\n\t\tquery\n\t);\n\treturn getUserQueryResults( state, path );\n}\n\n/**\n * Returns the current user.\n *\n * @param state Data state.\n *\n * @return Current user object.\n */\nexport function getCurrentUser( state: State ): ET.User< 'view' > {\n\treturn state.currentUser;\n}\n\n/**\n * Returns all the users returned by a query ID.\n *\n * @param state Data state.\n * @param queryID Query ID.\n *\n * @return Users list.\n */\nexport const getUserQueryResults = createSelector(\n\t( state: State, queryID: string ): ET.User< 'edit' >[] => {\n\t\tconst queryResults = state.users.queries[ queryID ] ?? [];\n\n\t\treturn queryResults.map( ( id ) => state.users.byId[ id ] );\n\t},\n\t( state: State, queryID: string ) => [\n\t\tstate.users.queries[ queryID ],\n\t\tstate.users.byId,\n\t]\n);\n\n/**\n * Returns the loaded entities for the given kind.\n *\n * @deprecated since WordPress 6.0. Use getEntitiesConfig instead\n * @param state Data state.\n * @param kind Entity kind.\n *\n * @return Array of entities with config matching kind.\n */\nexport function getEntitiesByKind( state: State, kind: string ): Array< any > {\n\tdeprecated( \"wp.data.select( 'core' ).getEntitiesByKind()\", {\n\t\tsince: '6.0',\n\t\talternative: \"wp.data.select( 'core' ).getEntitiesConfig()\",\n\t} );\n\treturn getEntitiesConfig( state, kind );\n}\n\n/**\n * Returns the loaded entities for the given kind.\n *\n * @param state Data state.\n * @param kind Entity kind.\n *\n * @return Array of entities with config matching kind.\n */\nexport const getEntitiesConfig = createSelector(\n\t( state: State, kind: string ): Array< any > =>\n\t\tstate.entities.config.filter( ( entity ) => entity.kind === kind ),\n\t/* eslint-disable @typescript-eslint/no-unused-vars */\n\t( state: State, kind: string ) => state.entities.config\n\t/* eslint-enable @typescript-eslint/no-unused-vars */\n);\n/**\n * Returns the entity config given its kind and name.\n *\n * @deprecated since WordPress 6.0. Use getEntityConfig instead\n * @param state Data state.\n * @param kind Entity kind.\n * @param name Entity name.\n *\n * @return Entity config\n */\nexport function getEntity( state: State, kind: string, name: string ): any {\n\tdeprecated( \"wp.data.select( 'core' ).getEntity()\", {\n\t\tsince: '6.0',\n\t\talternative: \"wp.data.select( 'core' ).getEntityConfig()\",\n\t} );\n\treturn getEntityConfig( state, kind, name );\n}\n\n/**\n * Returns the entity config given its kind and name.\n *\n * @param state Data state.\n * @param kind Entity kind.\n * @param name Entity name.\n *\n * @return Entity config\n */\nexport function getEntityConfig(\n\tstate: State,\n\tkind: string,\n\tname: string\n): any {\n\tlogEntityDeprecation( kind, name, 'getEntityConfig' );\n\n\treturn state.entities.config?.find(\n\t\t( config ) => config.kind === kind && config.name === name\n\t);\n}\n\n/**\n * GetEntityRecord is declared as a *callable interface* with\n * two signatures to work around the fact that TypeScript doesn't\n * allow currying generic functions:\n *\n * ```ts\n * \t\ttype CurriedState = F extends ( state: any, ...args: infer P ) => infer R\n * \t\t\t? ( ...args: P ) => R\n * \t\t\t: F;\n * \t\ttype Selector = <K extends string | number>(\n * state: any,\n * kind: K,\n * key: K extends string ? 'string value' : false\n * ) => K;\n * \t\ttype BadlyInferredSignature = CurriedState< Selector >\n * // BadlyInferredSignature evaluates to:\n * // (kind: string number, key: false | \"string value\") => string number\n * ```\n *\n * The signature without the state parameter shipped as CurriedSignature\n * is used in the return value of `select( coreStore )`.\n *\n * See https://github.com/WordPress/gutenberg/pull/41578 for more details.\n */\nexport interface GetEntityRecord {\n\t<\n\t\tEntityRecord extends\n\t\t\t| ET.EntityRecord< any >\n\t\t\t| Partial< ET.EntityRecord< any > >,\n\t>(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\tkey?: EntityRecordKey,\n\t\tquery?: GetRecordsHttpQuery\n\t): EntityRecord | undefined;\n\n\tCurriedSignature: <\n\t\tEntityRecord extends\n\t\t\t| ET.EntityRecord< any >\n\t\t\t| Partial< ET.EntityRecord< any > >,\n\t>(\n\t\tkind: string,\n\t\tname: string,\n\t\tkey?: EntityRecordKey,\n\t\tquery?: GetRecordsHttpQuery\n\t) => EntityRecord | undefined;\n\t__unstableNormalizeArgs?: ( args: EntityRecordArgs ) => EntityRecordArgs;\n}\n\n/**\n * Returns the Entity's record object by key. Returns `null` if the value is not\n * yet received, undefined if the value entity is known to not exist, or the\n * entity object if it exists and is received.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param key Optional record's key. If requesting a global record (e.g. site settings), the key can be omitted. If requesting a specific item, the key must always be included.\n * @param query Optional query. If requesting specific\n * fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available \"Retrieve a [Entity kind]\".\n *\n * @return Record.\n */\nexport const getEntityRecord = createSelector(\n\t( <\n\t\tEntityRecord extends\n\t\t\t| ET.EntityRecord< any >\n\t\t\t| Partial< ET.EntityRecord< any > >,\n\t>(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\tkey?: EntityRecordKey,\n\t\tquery?: GetRecordsHttpQuery\n\t): EntityRecord | undefined => {\n\t\tlogEntityDeprecation( kind, name, 'getEntityRecord' );\n\t\tconst queriedState =\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData;\n\t\tif ( ! queriedState ) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst context = query?.context ?? 'default';\n\n\t\tif ( ! query || ! query._fields ) {\n\t\t\t// If expecting a complete item, validate that completeness.\n\t\t\tif ( ! queriedState.itemIsComplete[ context ]?.[ key ] ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn queriedState.items[ context ][ key ];\n\t\t}\n\n\t\tconst item = queriedState.items[ context ]?.[ key ];\n\t\tif ( ! item ) {\n\t\t\treturn item;\n\t\t}\n\n\t\tconst filteredItem = {};\n\t\tconst fields = getNormalizedCommaSeparable( query._fields ) ?? [];\n\t\tfor ( let f = 0; f < fields.length; f++ ) {\n\t\t\tconst field = fields[ f ].split( '.' );\n\t\t\tlet value = item;\n\t\t\tfield.forEach( ( fieldName ) => {\n\t\t\t\tvalue = value?.[ fieldName ];\n\t\t\t} );\n\t\t\tsetNestedValue( filteredItem, field, value );\n\t\t}\n\t\treturn filteredItem as EntityRecord;\n\t} ) as GetEntityRecord,\n\t( state: State, kind, name, recordId, query ) => {\n\t\tconst context = query?.context ?? 'default';\n\t\tconst queriedState =\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData;\n\t\treturn [\n\t\t\tqueriedState?.items[ context ]?.[ recordId ],\n\t\t\tqueriedState?.itemIsComplete[ context ]?.[ recordId ],\n\t\t];\n\t}\n) as GetEntityRecord;\n\n/**\n * Normalizes `recordKey`s that look like numeric IDs to numbers.\n *\n * @param args EntityRecordArgs the selector arguments.\n * @return EntityRecordArgs the normalized arguments.\n */\ngetEntityRecord.__unstableNormalizeArgs = (\n\targs: EntityRecordArgs\n): EntityRecordArgs => {\n\tconst newArgs = [ ...args ] as EntityRecordArgs;\n\tconst recordKey = newArgs?.[ 2 ];\n\n\t// If recordKey looks to be a numeric ID then coerce to number.\n\tnewArgs[ 2 ] = isNumericID( recordKey ) ? Number( recordKey ) : recordKey;\n\n\treturn newArgs;\n};\n\n/**\n * Returns true if a record has been received for the given set of parameters, or false otherwise.\n *\n * Note: This action does not trigger a request for the entity record from the API\n * if it's not available in the local state.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param key Record's key.\n * @param query Optional query.\n *\n * @return Whether an entity record has been received.\n */\nexport function hasEntityRecord(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\tkey?: EntityRecordKey,\n\tquery?: GetRecordsHttpQuery\n): boolean {\n\tconst queriedState =\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData;\n\tif ( ! queriedState ) {\n\t\treturn false;\n\t}\n\tconst context = query?.context ?? 'default';\n\n\t// If expecting a complete item, validate that completeness.\n\tif ( ! query || ! query._fields ) {\n\t\treturn !! queriedState.itemIsComplete[ context ]?.[ key ];\n\t}\n\n\tconst item = queriedState.items[ context ]?.[ key ];\n\tif ( ! item ) {\n\t\treturn false;\n\t}\n\n\t// When `query._fields` is provided, check that each requested field exists,\n\t// including any nested paths, on the item; return false if any part is missing.\n\tconst fields = getNormalizedCommaSeparable( query._fields ) ?? [];\n\tfor ( let i = 0; i < fields.length; i++ ) {\n\t\tconst path = fields[ i ].split( '.' );\n\t\tlet value = item;\n\t\tfor ( let p = 0; p < path.length; p++ ) {\n\t\t\tconst part = path[ p ];\n\t\t\tif ( ! value || ! Object.hasOwn( value, part ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvalue = value[ part ];\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * Returns the Entity's record object by key. Doesn't trigger a resolver nor requests the entity records from the API if the entity record isn't available in the local state.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param key Record's key\n *\n * @return Record.\n */\nexport function __experimentalGetEntityRecordNoResolver<\n\tEntityRecord extends ET.EntityRecord< any >,\n>( state: State, kind: string, name: string, key: EntityRecordKey ) {\n\treturn getEntityRecord< EntityRecord >( state, kind, name, key );\n}\n\n/**\n * Returns the entity's record object by key,\n * with its attributes mapped to their raw values.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param key Record's key.\n *\n * @return Object with the entity's raw attributes.\n */\nexport const getRawEntityRecord = createSelector(\n\t< EntityRecord extends ET.EntityRecord< any > >(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\tkey: EntityRecordKey\n\t): EntityRecord | undefined => {\n\t\tlogEntityDeprecation( kind, name, 'getRawEntityRecord' );\n\n\t\tconst record = getEntityRecord< EntityRecord >(\n\t\t\tstate,\n\t\t\tkind,\n\t\t\tname,\n\t\t\tkey\n\t\t);\n\t\treturn (\n\t\t\trecord &&\n\t\t\tObject.keys( record ).reduce( ( accumulator, _key ) => {\n\t\t\t\tif (\n\t\t\t\t\tisRawAttribute( getEntityConfig( state, kind, name ), _key )\n\t\t\t\t) {\n\t\t\t\t\t// Because edits are the \"raw\" attribute values,\n\t\t\t\t\t// we return those from record selectors to make rendering,\n\t\t\t\t\t// comparisons, and joins with edits easier.\n\t\t\t\t\taccumulator[ _key ] =\n\t\t\t\t\t\trecord[ _key ]?.raw !== undefined\n\t\t\t\t\t\t\t? record[ _key ]?.raw\n\t\t\t\t\t\t\t: record[ _key ];\n\t\t\t\t} else {\n\t\t\t\t\taccumulator[ _key ] = record[ _key ];\n\t\t\t\t}\n\t\t\t\treturn accumulator;\n\t\t\t}, {} as any )\n\t\t);\n\t},\n\t(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\trecordId: EntityRecordKey,\n\t\tquery?: GetRecordsHttpQuery\n\t) => {\n\t\tconst context = query?.context ?? 'default';\n\t\treturn [\n\t\t\tstate.entities.config,\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData?.items[\n\t\t\t\tcontext\n\t\t\t]?.[ recordId ],\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData\n\t\t\t\t?.itemIsComplete[ context ]?.[ recordId ],\n\t\t];\n\t}\n);\n\n/**\n * Returns true if records have been received for the given set of parameters,\n * or false otherwise.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param query Optional terms query. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for \"List [Entity kind]s\".\n *\n * @return Whether entity records have been received.\n */\nexport function hasEntityRecords(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\tquery?: GetRecordsHttpQuery\n): boolean {\n\tlogEntityDeprecation( kind, name, 'hasEntityRecords' );\n\treturn Array.isArray( getEntityRecords( state, kind, name, query ) );\n}\n\n/**\n * GetEntityRecord is declared as a *callable interface* with\n * two signatures to work around the fact that TypeScript doesn't\n * allow currying generic functions.\n *\n * @see GetEntityRecord\n * @see https://github.com/WordPress/gutenberg/pull/41578\n */\nexport interface GetEntityRecords {\n\t<\n\t\tEntityRecord extends\n\t\t\t| ET.EntityRecord< any >\n\t\t\t| Partial< ET.EntityRecord< any > >,\n\t>(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\tquery?: GetRecordsHttpQuery\n\t): EntityRecord[] | null;\n\n\tCurriedSignature: <\n\t\tEntityRecord extends\n\t\t\t| ET.EntityRecord< any >\n\t\t\t| Partial< ET.EntityRecord< any > >,\n\t>(\n\t\tkind: string,\n\t\tname: string,\n\t\tquery?: GetRecordsHttpQuery\n\t) => EntityRecord[] | null;\n\n\tPromiseCurriedSignature: <\n\t\tEntityRecord extends\n\t\t\t| ET.EntityRecord< any >\n\t\t\t| Partial< ET.EntityRecord< any > >,\n\t>(\n\t\tkind: string,\n\t\tname: string,\n\t\tquery?: GetRecordsHttpQuery\n\t) => Promise< EntityRecord[] | null >;\n}\n\n/**\n * Returns the Entity's records.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param query Optional terms query. If requesting specific\n * fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for \"List [Entity kind]s\".\n *\n * @return Records.\n */\nexport const getEntityRecords = ( <\n\tEntityRecord extends\n\t\t| ET.EntityRecord< any >\n\t\t| Partial< ET.EntityRecord< any > >,\n>(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\tquery: GetRecordsHttpQuery\n): EntityRecord[] | null => {\n\tlogEntityDeprecation( kind, name, 'getEntityRecords' );\n\n\t// Queried data state is prepopulated for all known entities. If this is not\n\t// assigned for the given parameters, then it is known to not exist.\n\tconst queriedState =\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData;\n\tif ( ! queriedState ) {\n\t\treturn null;\n\t}\n\treturn getQueriedItems( queriedState, query );\n} ) as GetEntityRecords;\n\n/**\n * Returns the Entity's total available records for a given query (ignoring pagination).\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param query Optional terms query. If requesting specific\n * fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for \"List [Entity kind]s\".\n *\n * @return number | null.\n */\nexport const getEntityRecordsTotalItems = (\n\tstate: State,\n\tkind: string,\n\tname: string,\n\tquery: GetRecordsHttpQuery\n): number | null => {\n\tlogEntityDeprecation( kind, name, 'getEntityRecordsTotalItems' );\n\n\t// Queried data state is prepopulated for all known entities. If this is not\n\t// assigned for the given parameters, then it is known to not exist.\n\tconst queriedState =\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData;\n\tif ( ! queriedState ) {\n\t\treturn null;\n\t}\n\treturn getQueriedTotalItems( queriedState, query );\n};\n\n/**\n * Returns the number of available pages for the given query.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param query Optional terms query. If requesting specific\n * fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for \"List [Entity kind]s\".\n *\n * @return number | null.\n */\nexport const getEntityRecordsTotalPages = (\n\tstate: State,\n\tkind: string,\n\tname: string,\n\tquery: GetRecordsHttpQuery\n): number | null => {\n\tlogEntityDeprecation( kind, name, 'getEntityRecordsTotalPages' );\n\n\t// Queried data state is prepopulated for all known entities. If this is not\n\t// assigned for the given parameters, then it is known to not exist.\n\tconst queriedState =\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData;\n\tif ( ! queriedState ) {\n\t\treturn null;\n\t}\n\tif ( query?.per_page === -1 ) {\n\t\treturn 1;\n\t}\n\tconst totalItems = getQueriedTotalItems( queriedState, query );\n\tif ( ! totalItems ) {\n\t\treturn totalItems;\n\t}\n\t// If `per_page` is not set and the query relies on the defaults of the\n\t// REST endpoint, get the info from query's meta.\n\tif ( ! query?.per_page ) {\n\t\treturn getQueriedTotalPages( queriedState, query );\n\t}\n\treturn Math.ceil( totalItems / query.per_page );\n};\n\ntype DirtyEntityRecord = {\n\ttitle: string;\n\tkey: EntityRecordKey;\n\tname: string;\n\tkind: string;\n};\n/**\n * Returns the list of dirty entity records.\n *\n * @param state State tree.\n *\n * @return The list of updated records\n */\nexport const __experimentalGetDirtyEntityRecords = createSelector(\n\t( state: State ): Array< DirtyEntityRecord > => {\n\t\tconst {\n\t\t\tentities: { records },\n\t\t} = state;\n\t\tconst dirtyRecords: DirtyEntityRecord[] = [];\n\t\tObject.keys( records ).forEach( ( kind ) => {\n\t\t\tObject.keys( records[ kind ] ).forEach( ( name ) => {\n\t\t\t\tconst primaryKeys = (\n\t\t\t\t\tObject.keys( records[ kind ][ name ].edits ) as string[]\n\t\t\t\t ).filter(\n\t\t\t\t\t( primaryKey ) =>\n\t\t\t\t\t\t// The entity record must exist (not be deleted),\n\t\t\t\t\t\t// and it must have edits.\n\t\t\t\t\t\tgetEntityRecord( state, kind, name, primaryKey ) &&\n\t\t\t\t\t\thasEditsForEntityRecord( state, kind, name, primaryKey )\n\t\t\t\t);\n\n\t\t\t\tif ( primaryKeys.length ) {\n\t\t\t\t\tconst entityConfig = getEntityConfig( state, kind, name );\n\t\t\t\t\tprimaryKeys.forEach( ( primaryKey ) => {\n\t\t\t\t\t\tconst entityRecord = getEditedEntityRecord(\n\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\tkind,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tprimaryKey\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdirtyRecords.push( {\n\t\t\t\t\t\t\t// We avoid using primaryKey because it's transformed into a string\n\t\t\t\t\t\t\t// when it's used as an object key.\n\t\t\t\t\t\t\tkey: entityRecord\n\t\t\t\t\t\t\t\t? entityRecord[\n\t\t\t\t\t\t\t\t\t\tentityConfig.key || DEFAULT_ENTITY_KEY\n\t\t\t\t\t\t\t\t ]\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\ttitle:\n\t\t\t\t\t\t\t\tentityConfig?.getTitle?.( entityRecord ) || '',\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tkind,\n\t\t\t\t\t\t} );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\treturn dirtyRecords;\n\t},\n\t( state ) => [ state.entities.records ]\n);\n\n/**\n * Returns the list of entities currently being saved.\n *\n * @param state State tree.\n *\n * @return The list of records being saved.\n */\nexport const __experimentalGetEntitiesBeingSaved = createSelector(\n\t( state: State ): Array< DirtyEntityRecord > => {\n\t\tconst {\n\t\t\tentities: { records },\n\t\t} = state;\n\t\tconst recordsBeingSaved: DirtyEntityRecord[] = [];\n\t\tObject.keys( records ).forEach( ( kind ) => {\n\t\t\tObject.keys( records[ kind ] ).forEach( ( name ) => {\n\t\t\t\tconst primaryKeys = (\n\t\t\t\t\tObject.keys( records[ kind ][ name ].saving ) as string[]\n\t\t\t\t ).filter( ( primaryKey ) =>\n\t\t\t\t\tisSavingEntityRecord( state, kind, name, primaryKey )\n\t\t\t\t);\n\n\t\t\t\tif ( primaryKeys.length ) {\n\t\t\t\t\tconst entityConfig = getEntityConfig( state, kind, name );\n\t\t\t\t\tprimaryKeys.forEach( ( primaryKey ) => {\n\t\t\t\t\t\tconst entityRecord = getEditedEntityRecord(\n\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\tkind,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tprimaryKey\n\t\t\t\t\t\t);\n\t\t\t\t\t\trecordsBeingSaved.push( {\n\t\t\t\t\t\t\t// We avoid using primaryKey because it's transformed into a string\n\t\t\t\t\t\t\t// when it's used as an object key.\n\t\t\t\t\t\t\tkey: entityRecord\n\t\t\t\t\t\t\t\t? entityRecord[\n\t\t\t\t\t\t\t\t\t\tentityConfig.key || DEFAULT_ENTITY_KEY\n\t\t\t\t\t\t\t\t ]\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\ttitle:\n\t\t\t\t\t\t\t\tentityConfig?.getTitle?.( entityRecord ) || '',\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tkind,\n\t\t\t\t\t\t} );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t\treturn recordsBeingSaved;\n\t},\n\t( state ) => [ state.entities.records ]\n);\n\n/**\n * Returns the specified entity record's edits.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return The entity record's edits.\n */\nexport function getEntityRecordEdits(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): Optional< any > {\n\tlogEntityDeprecation( kind, name, 'getEntityRecordEdits' );\n\treturn state.entities.records?.[ kind ]?.[ name ]?.edits?.[\n\t\trecordId as string | number\n\t];\n}\n\n/**\n * Returns the specified entity record's non transient edits.\n *\n * Transient edits don't create an undo level, and\n * are not considered for change detection.\n * They are defined in the entity's config.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return The entity record's non transient edits.\n */\nexport const getEntityRecordNonTransientEdits = createSelector(\n\t(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\trecordId: EntityRecordKey\n\t): Optional< any > => {\n\t\tlogEntityDeprecation( kind, name, 'getEntityRecordNonTransientEdits' );\n\t\tconst { transientEdits } = getEntityConfig( state, kind, name ) || {};\n\t\tconst edits = getEntityRecordEdits( state, kind, name, recordId ) || {};\n\t\tif ( ! transientEdits ) {\n\t\t\treturn edits;\n\t\t}\n\t\treturn Object.keys( edits ).reduce( ( acc, key ) => {\n\t\t\tif ( ! transientEdits[ key ] ) {\n\t\t\t\tacc[ key ] = edits[ key ];\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, {} );\n\t},\n\t( state: State, kind: string, name: string, recordId: EntityRecordKey ) => [\n\t\tstate.entities.config,\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.edits?.[ recordId ],\n\t]\n);\n\n/**\n * Returns true if the specified entity record has edits,\n * and false otherwise.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return Whether the entity record has edits or not.\n */\nexport function hasEditsForEntityRecord(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): boolean {\n\tlogEntityDeprecation( kind, name, 'hasEditsForEntityRecord' );\n\treturn (\n\t\tisSavingEntityRecord( state, kind, name, recordId ) ||\n\t\tObject.keys(\n\t\t\tgetEntityRecordNonTransientEdits( state, kind, name, recordId )\n\t\t).length > 0\n\t);\n}\n\n/**\n * Returns the specified entity record, merged with its edits.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return The entity record, merged with its edits.\n */\nexport const getEditedEntityRecord = createSelector(\n\t< EntityRecord extends ET.EntityRecord< any > >(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\trecordId: EntityRecordKey\n\t): ET.Updatable< EntityRecord > | false => {\n\t\tlogEntityDeprecation( kind, name, 'getEditedEntityRecord' );\n\t\tconst raw = getRawEntityRecord( state, kind, name, recordId );\n\t\tconst edited = getEntityRecordEdits( state, kind, name, recordId );\n\t\t// Never return a non-falsy empty object. Unfortunately we can't return\n\t\t// undefined or null because we were previously returning an empty\n\t\t// object, so trying to read properties from the result would throw.\n\t\t// Using false here is a workaround to avoid breaking changes.\n\t\tif ( ! raw && ! edited ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn {\n\t\t\t...raw,\n\t\t\t...edited,\n\t\t};\n\t},\n\t(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\trecordId: EntityRecordKey,\n\t\tquery?: GetRecordsHttpQuery\n\t) => {\n\t\tconst context = query?.context ?? 'default';\n\t\treturn [\n\t\t\tstate.entities.config,\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData.items[\n\t\t\t\tcontext\n\t\t\t]?.[ recordId ],\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.queriedData\n\t\t\t\t.itemIsComplete[ context ]?.[ recordId ],\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.edits?.[ recordId ],\n\t\t];\n\t}\n);\n\n/**\n * Returns true if the specified entity record is autosaving, and false otherwise.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return Whether the entity record is autosaving or not.\n */\nexport function isAutosavingEntityRecord(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): boolean {\n\tlogEntityDeprecation( kind, name, 'isAutosavingEntityRecord' );\n\tconst { pending, isAutosave } =\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.saving?.[ recordId ] ?? {};\n\treturn Boolean( pending && isAutosave );\n}\n\n/**\n * Returns true if the specified entity record is saving, and false otherwise.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return Whether the entity record is saving or not.\n */\nexport function isSavingEntityRecord(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): boolean {\n\tlogEntityDeprecation( kind, name, 'isSavingEntityRecord' );\n\treturn (\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.saving?.[\n\t\t\trecordId as EntityRecordKey\n\t\t]?.pending ?? false\n\t);\n}\n\n/**\n * Returns true if the specified entity record is deleting, and false otherwise.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return Whether the entity record is deleting or not.\n */\nexport function isDeletingEntityRecord(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): boolean {\n\tlogEntityDeprecation( kind, name, 'isDeletingEntityRecord' );\n\treturn (\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.deleting?.[\n\t\t\trecordId as EntityRecordKey\n\t\t]?.pending ?? false\n\t);\n}\n\n/**\n * Returns the specified entity record's last save error.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return The entity record's save error.\n */\nexport function getLastEntitySaveError(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): any {\n\tlogEntityDeprecation( kind, name, 'getLastEntitySaveError' );\n\treturn state.entities.records?.[ kind ]?.[ name ]?.saving?.[ recordId ]\n\t\t?.error;\n}\n\n/**\n * Returns the specified entity record's last delete error.\n *\n * @param state State tree.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record ID.\n *\n * @return The entity record's save error.\n */\nexport function getLastEntityDeleteError(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): any {\n\tlogEntityDeprecation( kind, name, 'getLastEntityDeleteError' );\n\treturn state.entities.records?.[ kind ]?.[ name ]?.deleting?.[ recordId ]\n\t\t?.error;\n}\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * Returns the previous edit from the current undo offset\n * for the entity records edits history, if any.\n *\n * @deprecated since 6.3\n *\n * @param state State tree.\n *\n * @return The edit.\n */\nexport function getUndoEdit( state: State ): Optional< any > {\n\tdeprecated( \"select( 'core' ).getUndoEdit()\", {\n\t\tsince: '6.3',\n\t} );\n\treturn undefined;\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * Returns the next edit from the current undo offset\n * for the entity records edits history, if any.\n *\n * @deprecated since 6.3\n *\n * @param state State tree.\n *\n * @return The edit.\n */\nexport function getRedoEdit( state: State ): Optional< any > {\n\tdeprecated( \"select( 'core' ).getRedoEdit()\", {\n\t\tsince: '6.3',\n\t} );\n\treturn undefined;\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n\n/**\n * Returns true if there is a previous edit from the current undo offset\n * for the entity records edits history, and false otherwise.\n *\n * @param state State tree.\n *\n * @return Whether there is a previous edit or not.\n */\nexport function hasUndo( state: State ): boolean {\n\treturn getUndoManager( state ).hasUndo();\n}\n\n/**\n * Returns true if there is a next edit from the current undo offset\n * for the entity records edits history, and false otherwise.\n *\n * @param state State tree.\n *\n * @return Whether there is a next edit or not.\n */\nexport function hasRedo( state: State ): boolean {\n\treturn getUndoManager( state ).hasRedo();\n}\n\n/**\n * Return the current theme.\n *\n * @param state Data state.\n *\n * @return The current theme.\n */\nexport function getCurrentTheme( state: State ): any {\n\tif ( ! state.currentTheme ) {\n\t\treturn null;\n\t}\n\treturn getEntityRecord( state, 'root', 'theme', state.currentTheme );\n}\n\n/**\n * Return the ID of the current global styles object.\n *\n * @param state Data state.\n *\n * @return The current global styles ID.\n */\nexport function __experimentalGetCurrentGlobalStylesId( state: State ): string {\n\treturn state.currentGlobalStylesId;\n}\n\n/**\n * Return theme supports data in the index.\n *\n * @param state Data state.\n *\n * @return Index data.\n */\nexport function getThemeSupports( state: State ): any {\n\treturn getCurrentTheme( state )?.theme_supports ?? EMPTY_OBJECT;\n}\n\n/**\n * Returns the embed preview for the given URL.\n *\n * @param state Data state.\n * @param url Embedded URL.\n *\n * @return Undefined if the preview has not been fetched, otherwise, the preview fetched from the embed preview API.\n */\nexport function getEmbedPreview( state: State, url: string ): any {\n\treturn state.embedPreviews[ url ];\n}\n\n/**\n * Determines if the returned preview is an oEmbed link fallback.\n *\n * WordPress can be configured to return a simple link to a URL if it is not embeddable.\n * We need to be able to determine if a URL is embeddable or not, based on what we\n * get back from the oEmbed preview API.\n *\n * @param state Data state.\n * @param url Embedded URL.\n *\n * @return Is the preview for the URL an oEmbed link fallback.\n */\nexport function isPreviewEmbedFallback( state: State, url: string ): boolean {\n\tconst preview = state.embedPreviews[ url ];\n\tconst oEmbedLinkCheck = '<a href=\"' + url + '\">' + url + '</a>';\n\tif ( ! preview ) {\n\t\treturn false;\n\t}\n\treturn preview.html === oEmbedLinkCheck;\n}\n\n/**\n * Returns whether the current user can perform the given action on the given\n * REST resource.\n *\n * Calling this may trigger an OPTIONS request to the REST API via the\n * `canUser()` resolver.\n *\n * https://developer.wordpress.org/rest-api/reference/\n *\n * @param state Data state.\n * @param action Action to check. One of: 'create', 'read', 'update', 'delete'.\n * @param resource Entity resource to check. Accepts entity object `{ kind: 'postType', name: 'attachment', id: 1 }`\n * or REST base as a string - `media`.\n * @param id Optional ID of the rest resource to check.\n *\n * @return Whether or not the user can perform the action,\n * or `undefined` if the OPTIONS request is still being made.\n */\nexport function canUser(\n\tstate: State,\n\taction: string,\n\tresource: string | EntityResource,\n\tid?: EntityRecordKey\n): boolean | undefined {\n\tconst isEntity = typeof resource === 'object';\n\tif ( isEntity && ( ! resource.kind || ! resource.name ) ) {\n\t\treturn false;\n\t}\n\tif ( isEntity ) {\n\t\tlogEntityDeprecation( resource.kind, resource.name, 'canUser' );\n\t}\n\n\tconst key = getUserPermissionCacheKey( action, resource, id );\n\n\treturn state.userPermissions[ key ];\n}\n\n/**\n * Returns whether the current user can edit the given entity.\n *\n * Calling this may trigger an OPTIONS request to the REST API via the\n * `canUser()` resolver.\n *\n * https://developer.wordpress.org/rest-api/reference/\n *\n * @param state Data state.\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordId Record's id.\n * @return Whether or not the user can edit,\n * or `undefined` if the OPTIONS request is still being made.\n */\nexport function canUserEditEntityRecord(\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordId: EntityRecordKey\n): boolean | undefined {\n\tdeprecated( `wp.data.select( 'core' ).canUserEditEntityRecord()`, {\n\t\tsince: '6.7',\n\t\talternative: `wp.data.select( 'core' ).canUser( 'update', { kind, name, id } )`,\n\t} );\n\n\treturn canUser( state, 'update', { kind, name, id: recordId } );\n}\n\n/**\n * Returns the latest autosaves for the post.\n *\n * May return multiple autosaves since the backend stores one autosave per\n * author for each post.\n *\n * @param state State tree.\n * @param postType The type of the parent post.\n * @param postId The id of the parent post.\n *\n * @return An array of autosaves for the post, or undefined if there is none.\n */\nexport function getAutosaves(\n\tstate: State,\n\tpostType: string,\n\tpostId: EntityRecordKey\n): Array< any > | undefined {\n\treturn state.autosaves[ postId ];\n}\n\n/**\n * Returns the autosave for the post and author.\n *\n * @param state State tree.\n * @param postType The type of the parent post.\n * @param postId The id of the parent post.\n * @param authorId The id of the author.\n *\n * @return The autosave for the post and author.\n */\nexport function getAutosave< EntityRecord extends ET.EntityRecord< any > >(\n\tstate: State,\n\tpostType: string,\n\tpostId: EntityRecordKey,\n\tauthorId: EntityRecordKey\n): EntityRecord | undefined {\n\tif ( authorId === undefined ) {\n\t\treturn;\n\t}\n\n\tconst autosaves = state.autosaves[ postId ];\n\n\treturn autosaves?.find(\n\t\t( autosave: any ) => autosave.author === authorId\n\t) as EntityRecord | undefined;\n}\n\n/**\n * Returns true if the REST request for autosaves has completed.\n *\n * @param state State tree.\n * @param postType The type of the parent post.\n * @param postId The id of the parent post.\n *\n * @return True if the REST request was completed. False otherwise.\n */\nexport const hasFetchedAutosaves = createRegistrySelector(\n\t( select ) =>\n\t\t(\n\t\t\tstate: State,\n\t\t\tpostType: string,\n\t\t\tpostId: EntityRecordKey\n\t\t): boolean => {\n\t\t\treturn select( STORE_NAME ).hasFinishedResolution( 'getAutosaves', [\n\t\t\t\tpostType,\n\t\t\t\tpostId,\n\t\t\t] );\n\t\t}\n);\n\n/**\n * Returns a new reference when edited values have changed. This is useful in\n * inferring where an edit has been made between states by comparison of the\n * return values using strict equality.\n *\n * @example\n *\n * ```\n * const hasEditOccurred = (\n * getReferenceByDistinctEdits( beforeState ) !==\n * getReferenceByDistinctEdits( afterState )\n * );\n * ```\n *\n * @param state Editor state.\n *\n * @return A value whose reference will change only when an edit occurs.\n */\nexport function getReferenceByDistinctEdits( state ) {\n\treturn state.editsReference;\n}\n\n/**\n * Retrieve the current theme's base global styles\n *\n * @param state Editor state.\n *\n * @return The Global Styles object.\n */\nexport function __experimentalGetCurrentThemeBaseGlobalStyles(\n\tstate: State\n): any {\n\tconst currentTheme = getCurrentTheme( state );\n\tif ( ! currentTheme ) {\n\t\treturn null;\n\t}\n\treturn state.themeBaseGlobalStyles[ currentTheme.stylesheet ];\n}\n\n/**\n * Return the ID of the current global styles object.\n *\n * @param state Data state.\n *\n * @return The current global styles ID.\n */\nexport function __experimentalGetCurrentThemeGlobalStylesVariations(\n\tstate: State\n): string | null {\n\tconst currentTheme = getCurrentTheme( state );\n\tif ( ! currentTheme ) {\n\t\treturn null;\n\t}\n\treturn state.themeGlobalStyleVariations[ currentTheme.stylesheet ];\n}\n\n/**\n * Retrieve the list of registered block patterns.\n *\n * @param state Data state.\n *\n * @return Block pattern list.\n */\nexport function getBlockPatterns( state: State ): Array< any > {\n\treturn state.blockPatterns;\n}\n\n/**\n * Retrieve the list of registered block pattern categories.\n *\n * @param state Data state.\n *\n * @return Block pattern category list.\n */\nexport function getBlockPatternCategories( state: State ): Array< any > {\n\treturn state.blockPatternCategories;\n}\n\n/**\n * Retrieve the registered user pattern categories.\n *\n * @param state Data state.\n *\n * @return User patterns category array.\n */\n\nexport function getUserPatternCategories(\n\tstate: State\n): Array< UserPatternCategory > {\n\treturn state.userPatternCategories;\n}\n\n/**\n * Returns the revisions of the current global styles theme.\n *\n * @deprecated since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post.\n *\n * @param state Data state.\n *\n * @return The current global styles.\n */\nexport function getCurrentThemeGlobalStylesRevisions(\n\tstate: State\n): Array< object > | null {\n\tdeprecated( \"select( 'core' ).getCurrentThemeGlobalStylesRevisions()\", {\n\t\tsince: '6.5.0',\n\t\talternative:\n\t\t\t\"select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )\",\n\t} );\n\tconst currentGlobalStylesId =\n\t\t__experimentalGetCurrentGlobalStylesId( state );\n\n\tif ( ! currentGlobalStylesId ) {\n\t\treturn null;\n\t}\n\n\treturn state.themeGlobalStyleRevisions[ currentGlobalStylesId ];\n}\n\n/**\n * Returns the default template use to render a given query.\n *\n * @param state Data state.\n * @param query Query.\n *\n * @return The default template id for the given query.\n */\nexport function getDefaultTemplateId(\n\tstate: State,\n\tquery: TemplateQuery\n): string {\n\treturn state.defaultTemplates[ JSON.stringify( query ) ];\n}\n\n/**\n * Returns an entity's revisions.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordKey The key of the entity record whose revisions you want to fetch.\n * @param query Optional query. If requesting specific\n * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available \"Retrieve a [Entity kind]\".\n *\n * @return Record.\n */\nexport const getRevisions = (\n\tstate: State,\n\tkind: string,\n\tname: string,\n\trecordKey: EntityRecordKey,\n\tquery?: GetRecordsHttpQuery\n): RevisionRecord[] | null => {\n\tlogEntityDeprecation( kind, name, 'getRevisions' );\n\tconst queriedStateRevisions =\n\t\tstate.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ];\n\tif ( ! queriedStateRevisions ) {\n\t\treturn null;\n\t}\n\n\treturn getQueriedItems( queriedStateRevisions, query );\n};\n\n/**\n * Returns a single, specific revision of a parent entity.\n *\n * @param state State tree\n * @param kind Entity kind.\n * @param name Entity name.\n * @param recordKey The key of the entity record whose revisions you want to fetch.\n * @param revisionKey The revision's key.\n * @param query Optional query. If requesting specific\n * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available \"Retrieve a [entity kind]\".\n *\n * @return Record.\n */\nexport const getRevision = createSelector(\n\t(\n\t\tstate: State,\n\t\tkind: string,\n\t\tname: string,\n\t\trecordKey: EntityRecordKey,\n\t\trevisionKey: EntityRecordKey,\n\t\tquery?: GetRecordsHttpQuery\n\t): RevisionRecord | Record< PropertyKey, never > | undefined => {\n\t\tlogEntityDeprecation( kind, name, 'getRevision' );\n\t\tconst queriedState =\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.revisions?.[\n\t\t\t\trecordKey\n\t\t\t];\n\n\t\tif ( ! queriedState ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst context = query?.context ?? 'default';\n\n\t\tif ( ! query || ! query._fields ) {\n\t\t\t// If expecting a complete item, validate that completeness.\n\t\t\tif ( ! queriedState.itemIsComplete[ context ]?.[ revisionKey ] ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn queriedState.items[ context ][ revisionKey ];\n\t\t}\n\n\t\tconst item = queriedState.items[ context ]?.[ revisionKey ];\n\t\tif ( ! item ) {\n\t\t\treturn item;\n\t\t}\n\n\t\tconst filteredItem = {};\n\t\tconst fields = getNormalizedCommaSeparable( query._fields ) ?? [];\n\n\t\tfor ( let f = 0; f < fields.length; f++ ) {\n\t\t\tconst field = fields[ f ].split( '.' );\n\t\t\tlet value = item;\n\t\t\tfield.forEach( ( fieldName ) => {\n\t\t\t\tvalue = value?.[ fieldName ];\n\t\t\t} );\n\t\t\tsetNestedValue( filteredItem, field, value );\n\t\t}\n\n\t\treturn filteredItem;\n\t},\n\t( state: State, kind, name, recordKey, revisionKey, query ) => {\n\t\tconst context = query?.context ?? 'default';\n\t\tconst queriedState =\n\t\t\tstate.entities.records?.[ kind ]?.[ name ]?.revisions?.[\n\t\t\t\trecordKey\n\t\t\t];\n\t\treturn [\n\t\t\tqueriedState?.items?.[ context ]?.[ revisionKey ],\n\t\t\tqueriedState?.itemIsComplete?.[ context ]?.[ revisionKey ],\n\t\t];\n\t}\n);\n\n/**\n * Returns the current sync connection status across all entities. Prioritizes\n * disconnected states, then connecting, then connected.\n *\n * @param state Data state.\n *\n * @return The current sync connection state, prioritized by importance.\n */\nexport function getSyncConnectionStatus(\n\tstate: State\n): ConnectionStatus | undefined {\n\tif ( ! state.syncConnectionStatuses ) {\n\t\treturn undefined;\n\t}\n\n\tconst PRIORITIZED_STATUSES = [ 'disconnected', 'connecting', 'connected' ];\n\n\tlet coalesced: ConnectionStatus | undefined;\n\n\tfor ( const status of Object.values( state.syncConnectionStatuses ) ) {\n\t\tif (\n\t\t\t! coalesced ||\n\t\t\tPRIORITIZED_STATUSES.indexOf( status.status ) <\n\t\t\t\tPRIORITIZED_STATUSES.indexOf( coalesced.status )\n\t\t) {\n\t\t\tcoalesced = status;\n\t\t}\n\t}\n\n\treturn coalesced;\n}\n"],
"mappings": ";AAGA,SAAS,gBAAgB,8BAA8B;AACvD,SAAS,oBAAoB;AAE7B,OAAO,gBAAgB;AAMvB,SAAS,kBAAkB;AAC3B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAEP,OAAO,0BAA0B;AAsHjC,IAAM,eAAe,CAAC;AAWf,IAAM,2BAA2B;AAAA,EACvC,CAAE,WACD,CAAE,OAAc,QAA0B;AACzC,WAAO,OAAQ,UAAW,EAAE,