From 87a7fbe19ced30940807017f6dd5fa878791dd30 Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Wed, 23 Feb 2022 00:41:42 +0100 Subject: [PATCH] TypeScript definitions for core-data entity records (#38666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add types for core data entity records * Use string enums instead of numeric ones * Put each type in a separate file * Rond 2 of autogenerating types * Extract enum types * Extract common interfaces * Add type definitions for posts and template parts * Add Raw Data typings * Extract AvatarUrls to common.js * Try context-based entity types * Experimenting with different ways of contextualizing data types * Remove EntityInContext – it isn't really needed * Rename RawDataIsString to RawDataOverride * Use Entity and EntityWithEdits without distinguishing between different contexts * Make all the fields contextual * Refactir WithEdits to EditedRecord * Rename "Edited" to "Updatable" * Flatten Nevers and WithoutNevers to OmitNevers * Remove dedicated updatable fields in favor of an Updateble type wrapper * Remove extra wrappers around types * Add missing definitions to NavMenu type * Use RawField in Page and Post types * Export UpdatableRecord type * Rename RawField to RenderedText * Export updatable types * Rename UpdatableRecord to Updatable * Remove atomic updatable types * Adjust Comment status and User locale modeling * Remove the NestedWidget name, declare the type inline in Sidebar * Make User.password optional * Introduce StringWhenUpdatable type to model WP templates * Document the Updatable type * Document the RenderedText using @dmsnell's proposal * Document types in common.ts * Flatten the content prop of WpTemplate and WpTemplatePart into a string through a condition inside the Updatable type wrapper * Type the remaining optional fields more strictly * Wrap Type with OmitNevers * Wrap the type user with OmitNevers * Use consistent kebab case in type files * Wrap comment with OmitNevers * Add the missing OmitNevers to types with contextual fields * Add README.md * Rename common.ts to helpers.ts * Model WpTemplate.content and WpTemplatePart.content as RenderableText * Link to the REST API docs when explaining contexts * Explain the ContextualFields without meandering on the implementation details of `never` fields * Use the correct capitalization of the word javascript * Rename CommentStatus to CommentingStatus in context of comments container * Use Post as an example illustrating the usage of ContextualField * Focus on the goal of the ContextualField in its documentation * Use a cleaner explanation of the Updatable type wrapper * Explain why the types do not provide full type safety * Remove the TODO comments from the README and a section about extendability * Add extensible type prefix * a -> an * Use export type and import type declarations * Note that Comment.id is still a field even after the Comment type has been extended * Use CommentingStatus and PingStatus in the Attachment type * Use a correct snippet of code to illustrate interface extending in README.md * Use namespaced base types for extenders * Document the BaseTypes namespace * Lint * Lint the docstring in base-types.ts * Rename the BaseTypes namespace to WPBaseTypes * Add more commentary to the Extending section * Add a comma * Clarify the warning about type safety * Restore the first sentence of the warning * Link to the types readme in core-data readme * Do not publish the data types * Rename WPBaseTypes to CoreBaseEntityTypes * Rename CoreBaseEntityTypes to BaseEntityTypes * Fix a typo (extends -> extend) --- packages/core-data/README.md | 2 +- packages/core-data/src/index.js | 1 + packages/core-data/src/types/README.md | 193 +++++++++++++++ packages/core-data/src/types/attachment.ts | 146 ++++++++++++ .../core-data/src/types/base-entity-types.ts | 36 +++ packages/core-data/src/types/comment.ts | 96 ++++++++ packages/core-data/src/types/helpers.ts | 153 ++++++++++++ packages/core-data/src/types/index.ts | 72 ++++++ packages/core-data/src/types/menu-location.ts | 29 +++ packages/core-data/src/types/nav-menu-item.ts | 106 +++++++++ packages/core-data/src/types/nav-menu.ts | 53 +++++ .../core-data/src/types/navigation-area.ts | 29 +++ packages/core-data/src/types/page.ts | 144 ++++++++++++ packages/core-data/src/types/plugin.ts | 74 ++++++ packages/core-data/src/types/post.ts | 153 ++++++++++++ packages/core-data/src/types/settings.ts | 93 ++++++++ packages/core-data/src/types/sidebar.ts | 60 +++++ packages/core-data/src/types/taxonomy.ts | 92 ++++++++ packages/core-data/src/types/theme.ts | 222 ++++++++++++++++++ packages/core-data/src/types/type.ts | 80 +++++++ packages/core-data/src/types/user.ts | 109 +++++++++ packages/core-data/src/types/widget-type.ts | 37 +++ packages/core-data/src/types/widget.ts | 64 +++++ .../core-data/src/types/wp-template-part.ts | 94 ++++++++ packages/core-data/src/types/wp-template.ts | 94 ++++++++ 25 files changed, 2231 insertions(+), 1 deletion(-) create mode 100644 packages/core-data/src/types/README.md create mode 100644 packages/core-data/src/types/attachment.ts create mode 100644 packages/core-data/src/types/base-entity-types.ts create mode 100644 packages/core-data/src/types/comment.ts create mode 100644 packages/core-data/src/types/helpers.ts create mode 100644 packages/core-data/src/types/index.ts create mode 100644 packages/core-data/src/types/menu-location.ts create mode 100644 packages/core-data/src/types/nav-menu-item.ts create mode 100644 packages/core-data/src/types/nav-menu.ts create mode 100644 packages/core-data/src/types/navigation-area.ts create mode 100644 packages/core-data/src/types/page.ts create mode 100644 packages/core-data/src/types/plugin.ts create mode 100644 packages/core-data/src/types/post.ts create mode 100644 packages/core-data/src/types/settings.ts create mode 100644 packages/core-data/src/types/sidebar.ts create mode 100644 packages/core-data/src/types/taxonomy.ts create mode 100644 packages/core-data/src/types/theme.ts create mode 100644 packages/core-data/src/types/type.ts create mode 100644 packages/core-data/src/types/user.ts create mode 100644 packages/core-data/src/types/widget-type.ts create mode 100644 packages/core-data/src/types/widget.ts create mode 100644 packages/core-data/src/types/wp-template-part.ts create mode 100644 packages/core-data/src/types/wp-template.ts diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 09353c16ad4914..fc07ff9df8f6ce 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -1,6 +1,6 @@ # Core Data -Core Data is a [data module](https://github.com/WordPress/gutenberg/tree/HEAD/packages/data/README.md) intended to simplify access to and manipulation of core WordPress entities. It registers its own store and provides a number of selectors which resolve data from the WordPress REST API automatically, along with dispatching action creators to manipulate data. +Core Data is a [data module](https://github.com/WordPress/gutenberg/tree/HEAD/packages/data/README.md) intended to simplify access to and manipulation of core WordPress entities. It registers its own store and provides a number of selectors which resolve data from the WordPress REST API automatically, along with dispatching action creators to manipulate data. Core data is shipped with [`TypeScript definitions for WordPress data types`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/core-data/src/types/README.md). Used in combination with features of the data module such as [`subscribe`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/data/README.md#subscribe-function) or [higher-order components](https://github.com/WordPress/gutenberg/tree/HEAD/packages/data/README.md#higher-order-components), it enables a developer to easily add data into the logic and display of their plugin. diff --git a/packages/core-data/src/index.js b/packages/core-data/src/index.js index 876849704012ee..68ed31a7c55866 100644 --- a/packages/core-data/src/index.js +++ b/packages/core-data/src/index.js @@ -77,3 +77,4 @@ export { default as __experimentalUseEntityRecord } from './hooks/use-entity-rec export { default as __experimentalUseEntityRecords } from './hooks/use-entity-records'; export * from './entity-provider'; export * from './fetch'; +export * from './types'; diff --git a/packages/core-data/src/types/README.md b/packages/core-data/src/types/README.md new file mode 100644 index 00000000000000..10d2a2be75e639 --- /dev/null +++ b/packages/core-data/src/types/README.md @@ -0,0 +1,193 @@ +# Entity Records Types + +## Overview + +The types in this directory are designed to support the following use-cases: + +* Provide type-hinting and documentation for entity records fetched in the various REST API contexts. +* Type-check the values we use to *edit* entity records, the values that are sent back to the server as updates. + +**Warning:** The types model the expected API responses which is **not** the same as having a full type safety for the API-related operations. The API responses are type-cast to these definitions and therefore may not match those expectations; for example, a plugin could modify the response, or the API endpoint could have a nuanced implementation in which strings are sometimes used instead of numbers. + +### Context-aware type checks for entity records + +WordPress REST API returns different responses based on the `context` query parameter, which typically is one of `view`, `edit`, or `embed`. See the [REST API documentation](https://developer.wordpress.org/rest-api/) to learn more. + +For example, requesting `/wp/v2/posts/1?context=view` yields: + +```js +{ + "content": { + "protected": false, + "rendered": "\n

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

\n" + }, + "title": { + "rendered": "Hello world!" + } + // other fields +} +``` + +While requesting `/wp/v2/posts/1?context=edit`, yields: + +```js +{ + "content": { + "block_version": 1, + "protected": false, + "raw": "\n

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

\n", + "rendered": "\n

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

\n" + }, + "title": { + "raw": "Hello world!", + "rendered": "Hello world!" + } + // other fields +} +``` + +And, finally, requesting `/wp/v2/posts/1?context=embed` yields: + +```js +{ + // Note content is missing + "title": { + "rendered": "Hello world!" + } + // other fields +} +``` + +These contexts are supported by the core-data resolvers like `getEntityRecord()` and `getEntityRecords()` to retrieve the appropriate "flavor" of the data. + +The types describing different entity records must thus be aware of the relevant API context. This is implemented using the `Context` type parameter. For example, the implementation of the `Post` type resembles the following snippet: + +```ts +interface Post { + /** + * A named status for the post. + */ + status: ContextualField< PostStatus, 'view' | 'edit', C >; + + // ... other fields ... +} +``` + +The `status` field is a `PostStatus` when the requesting context is `view` or `edit`, but if requested with an `embed` context the field won't appear on the `Post` object at all. + +### Static type checks for *edited* entity records, where certain fields become strings instead of objects. + +When the `post` is retrieved using `getEntityRecord`, its `content` field is an object: + +```js +const post = wp.data.select('core').getEntityRecord( 'postType', 'post', 1, { context: 'view' } ) +// `post.content` is an object with two fields: protected and rendered +``` + +The block markup stored in `content` can only be rendered on the server so the REST API exposes both the raw markup and the rendered version. For example, `content.rendered` could used as a visual preview, and `content.raw` could be used to populate the code editor. + +When updating that field from the JavaScript code, however, all we can set is the raw value that the server will eventually render. The API expects us to send a much simpler `string` form which is the raw form that needs to be stored in the database. + +The types reflect this through the `Updatable` wrapper: + +```ts +interface Post< C extends Context > { + title: { + raw: string; + rendered: string; + } +} + +const post : Post< 'edit' > = ... +// post.title is an object with properties `raw` and `rendered` + +const post : Updatable> = ... +// post.title is a string +``` + +The `getEditedEntityRecord` selector returns the Updatable version of the entity records: + +```js +const post = wp.data.select('core').getEditedEntityRecord( 'postType', 'post', 1 ); +// `post.content` is a string +``` + +## Helpers + +### Context + +The REST API context parameter. + +### ContextualField + +`ContextualField` makes the field available only in the specified given contexts, and ensure the field is absent from the object when in a different context. + +Example: + +```ts +interface Post< C extends Context > { + … + modified: ContextualField< string, 'edit' | 'view', C >; + password: ContextualField< string, 'edit', C >; + … +} + +const post: Post<'edit'> = … +// post.modified exists as a string +// post.password exists as a string + +const post: Post<'view'> = … +// post.modified still exists as a string +// post.password is missing, undefined, because we're not in the `edit` context. +``` + +### OmitNevers + +Removes all the properties of type never, even the deeply nested ones. + +```ts +type MyType = { + foo: string; + bar: never; + nested: { + foo: string; + bar: never; + } +} +const x = {} as OmitNevers; +// x is of type { foo: string; nested: { foo: string; }} +// The `never` properties were removed entirely +``` + +### Updatable + +Updatable is a type describing Edited Entity Records. They are like +regular Entity Records, but they have all the local edits applied on top of the REST API data. + +This turns certain field from an object into a string. + +Entities like Post have fields that only be rendered on the server, like title, excerpt, +and content. The REST API exposes both the raw markup and the rendered version of those fields. +For example, in the block editor, content.rendered could used as a visual preview, and +content.raw could be used to populate the code editor. + +When updating these rendered fields, JavaScript is not be able to properly render arbitrary block +markup. Therefore, it stores only the raw markup without the rendered part. And since that's a string, +the entire field becomes a string. + +```ts +type Post< C extends Context > { + title: RenderedText< C >; +} +const post = {} as Post; +// post.title is an object with raw and rendered properties + +const updatablePost = {} as Updatable< Post >; +// updatablePost.title is a string +``` + +### RenderedText + +A string that the server renders which often involves modifications from the raw source string. + +For example, block HTML with the comment delimiters exists in `post_content` but those comments are stripped out when rendering to a page view. Similarly, plugins might modify content or replace shortcodes. diff --git a/packages/core-data/src/types/attachment.ts b/packages/core-data/src/types/attachment.ts new file mode 100644 index 00000000000000..4ad94226f0a877 --- /dev/null +++ b/packages/core-data/src/types/attachment.ts @@ -0,0 +1,146 @@ +/** + * Internal dependencies + */ +import { + Context, + ContextualField, + MediaType, + PostStatus, + RenderedText, + OmitNevers, + CommentingStatus, + PingStatus, +} from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Attachment< C extends Context > { + /** + * The date the post was published, in the site's timezone. + */ + date: string | null; + /** + * The date the post was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * The globally unique identifier for the post. + */ + guid: ContextualField< RenderedText< C >, 'view' | 'edit', C >; + /** + * Unique identifier for the post. + */ + id: number; + /** + * URL to the post. + */ + link: string; + /** + * The date the post was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the post was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * An alphanumeric identifier for the post unique to its type. + */ + slug: string; + /** + * A named status for the post. + */ + status: ContextualField< PostStatus, 'view' | 'edit', C >; + /** + * Type of post. + */ + type: string; + /** + * Permalink template for the post. + */ + permalink_template: ContextualField< string, 'edit', C >; + /** + * Slug automatically generated from the post title. + */ + generated_slug: ContextualField< string, 'edit', C >; + /** + * The title for the post. + */ + title: RenderedText< C >; + /** + * The ID for the author of the post. + */ + author: number; + /** + * Whether or not comments are open on the post. + */ + comment_status: ContextualField< + CommentingStatus, + 'view' | 'edit', + C + >; + /** + * Whether or not the post can be pinged. + */ + ping_status: ContextualField< PingStatus, 'view' | 'edit', C >; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * The theme file to use to display the post. + */ + template: ContextualField< string, 'view' | 'edit', C >; + /** + * Alternative text to display when attachment is not displayed. + */ + alt_text: string; + /** + * The attachment caption. + */ + caption: ContextualField< string, 'edit', C >; + /** + * The attachment description. + */ + description: ContextualField< + RenderedText< C >, + 'view' | 'edit', + C + >; + /** + * Attachment type. + */ + media_type: MediaType; + /** + * The attachment MIME type. + */ + mime_type: string; + /** + * Details about the media file, specific to its type. + */ + media_details: Record< string, string >; + /** + * The ID for the associated post of the attachment. + */ + post: ContextualField< number, 'view' | 'edit', C >; + /** + * URL to the original attachment file. + */ + source_url: string; + /** + * List of the missing image sizes of the attachment. + */ + missing_image_sizes: ContextualField< string[], 'edit', C >; + } + } +} + +export type Attachment< C extends Context > = OmitNevers< + _BaseEntityTypes.Attachment< C > +>; diff --git a/packages/core-data/src/types/base-entity-types.ts b/packages/core-data/src/types/base-entity-types.ts new file mode 100644 index 00000000000000..790eaa63cfc9d3 --- /dev/null +++ b/packages/core-data/src/types/base-entity-types.ts @@ -0,0 +1,36 @@ +/** + * This module exists solely to make the BaseEntityTypes namespace extensible + * with declaration merging: + * + * ```ts + * declare module './base-entity-types' { + * export namespace BaseEntityTypes { + * export interface Comment< C extends Context > { + * id: number; + * // ... + * } + * } + * } + * ``` + * + * The huge upside is that consumers of @wordpress/core-data may extend the + * exported data types using interface merging as follows: + * + * ```ts + * import type { Context } from '@wordpress/core-data'; + * declare module '@wordpress/core-data' { + * export namespace BaseEntityTypes { + * export interface Comment< C extends Context > { + * numberOfViews: number; + * } + * } + * } + * + * import type { Comment } from '@wordpress/core-data'; + * const c : Comment< 'view' > = ...; + * + * // c.numberOfViews is a number + * // c.id is still present + * ``` + */ +export namespace BaseEntityTypes {} diff --git a/packages/core-data/src/types/comment.ts b/packages/core-data/src/types/comment.ts new file mode 100644 index 00000000000000..56cd559780770a --- /dev/null +++ b/packages/core-data/src/types/comment.ts @@ -0,0 +1,96 @@ +/** + * Internal dependencies + */ +import { + AvatarUrls, + Context, + ContextualField, + OmitNevers, + RenderedText, +} from './helpers'; +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +export type CommentStatus = 'hold' | 'approve' | 'spam' | 'trash' | '1' | '0'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Comment< C extends Context > { + /** + * Unique identifier for the comment. + */ + id: number; + /** + * The ID of the user object, if author was a user. + */ + author: number; + /** + * Email address for the comment author. + */ + author_email: ContextualField< string, 'edit', C >; + /** + * IP address for the comment author. + */ + author_ip: ContextualField< string, 'edit', C >; + /** + * Display name for the comment author. + */ + author_name: string; + /** + * URL for the comment author. + */ + author_url: string; + /** + * User agent for the comment author. + */ + author_user_agent: ContextualField< string, 'edit', C >; + /** + * The content for the comment. + */ + content: RenderedText< C >; + /** + * The date the comment was published, in the site's timezone. + */ + date: string; + /** + * The date the comment was published, as GMT. + */ + date_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * URL to the comment. + */ + link: string; + /** + * The ID for the parent of the comment. + */ + parent: number; + /** + * The ID of the associated post object. + */ + post: ContextualField< number, 'view' | 'edit', C >; + /** + * State of the comment. + */ + status: ContextualField< CommentStatus, 'view' | 'edit', C >; + /** + * Type of the comment. + */ + type: string; + /** + * Avatar URLs for the comment author. + */ + author_avatar_urls: AvatarUrls; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + } + } +} + +export type Comment< C extends Context > = OmitNevers< + _BaseEntityTypes.Comment< C > +>; diff --git a/packages/core-data/src/types/helpers.ts b/packages/core-data/src/types/helpers.ts new file mode 100644 index 00000000000000..e3e60489bdaaf7 --- /dev/null +++ b/packages/core-data/src/types/helpers.ts @@ -0,0 +1,153 @@ +/** + * Internal dependencies + */ +import { EntityRecord } from './index'; + +export interface AvatarUrls { + /** + * Avatar URL with image size of 24 pixels. + */ + '24': string; + /** + * Avatar URL with image size of 48 pixels. + */ + '48': string; + /** + * Avatar URL with image size of 96 pixels. + */ + '96': string; +} + +export type MediaType = 'image' | 'file'; +export type CommentingStatus = 'open' | 'closed'; +export type PingStatus = 'open' | 'closed'; +export type PostStatus = 'publish' | 'future' | 'draft' | 'pending' | 'private'; +export type PostFormat = + | 'standard' + | 'aside' + | 'chat' + | 'gallery' + | 'link' + | 'image' + | 'quote' + | 'status' + | 'video' + | 'audio'; + +/** + * The REST API context parameter. + */ +export type Context = 'view' | 'edit' | 'embed'; + +/** + * ContextualField makes the field available only in the specified given contexts, + * and ensure the field is absent from the object when in a different context. + * + * @example + * ```ts + * interface Post< C extends Context > { + * … + * modified: ContextualField< string, 'edit' | 'view', C >; + * password: ContextualField< string, 'edit', C >; + * … + * } + * + * const post: Post<'edit'> = … + * // post.modified exists as a string + * // post.password exists as a string + * + * const post: Post<'view'> = … + * // post.modified still exists as a string + * // post.password is missing, undefined, because we're not in the `edit` context. + * ``` + */ +export type ContextualField< + FieldType, + AvailableInContexts extends Context, + C extends Context +> = AvailableInContexts extends C ? FieldType : never; + +/** + * Removes all the properties of type never, even the deeply nested ones. + * + * @example + * ```ts + * type MyType = { + * foo: string; + * bar: never; + * nested: { + * foo: string; + * bar: never; + * } + * } + * const x = {} as OmitNevers; + * // x is of type { foo: string; nested: { foo: string; }} + * // The `never` properties were removed entirely + * ``` + */ +export type OmitNevers< + T, + Nevers = { + [ K in keyof T ]: Exclude< T[ K ], undefined > extends never + ? never + : T[ K ] extends Record< string, unknown > + ? OmitNevers< T[ K ] > + : T[ K ]; + } +> = Pick< + Nevers, + { + [ K in keyof Nevers ]: Nevers[ K ] extends never ? never : K; + }[ keyof Nevers ] +>; + +/** + * A string that the server renders which often involves + * modifications from the raw source string. + * + * For example, block HTML with the comment delimiters exists + * in `post_content` but those comments are stripped out when + * rendering to a page view. Similarly, plugins might modify + * content or replace shortcodes. + */ +export interface RenderedText< C extends Context > { + /** + * The source string which will be rendered on page views. + */ + raw: ContextualField< string, 'edit', C >; + /** + * The output of the raw source after processing and filtering on the server. + */ + rendered: string; +} + +/** + * Updatable is a type describing Edited Entity Records. They are like + * regular Entity Records, but they have all the local edits applied on top of the REST API data. + * + * This turns certain field from an object into a string. + * + * Entities like Post have fields that only be rendered on the server, like title, excerpt, + * and content. The REST API exposes both the raw markup and the rendered version of those fields. + * For example, in the block editor, content.rendered could used as a visual preview, and + * content.raw could be used to populate the code editor. + * + * When updating these rendered fields, Javascript is not be able to properly render arbitrary block + * markup. Therefore, it stores only the raw markup without the rendered part. And since that's a string, + * the entire field becomes a string. + * + * @example + * ```ts + * type Post< C extends Context > { + * title: RenderedText< C >; + * } + * const post = {} as Post; + * // post.title is an object with raw and rendered properties + * + * const updatablePost = {} as Updatable< Post >; + * // updatablePost.title is a string + * ``` + */ +export type Updatable< T extends EntityRecord< 'edit' > > = { + [ K in keyof T ]: T[ K ] extends RenderedText< any > ? string : T[ K ]; +}; diff --git a/packages/core-data/src/types/index.ts b/packages/core-data/src/types/index.ts new file mode 100644 index 00000000000000..80a173862b58a5 --- /dev/null +++ b/packages/core-data/src/types/index.ts @@ -0,0 +1,72 @@ +/** + * Internal dependencies + */ +import type { Attachment } from './attachment'; +import type { Comment } from './comment'; +import type { MenuLocation } from './menu-location'; +import type { NavMenu } from './nav-menu'; +import type { NavMenuItem } from './nav-menu-item'; +import type { NavigationArea } from './navigation-area'; +import type { Page } from './page'; +import type { Plugin } from './plugin'; +import type { Post } from './post'; +import type { Settings } from './settings'; +import type { Sidebar } from './sidebar'; +import type { Taxonomy } from './taxonomy'; +import type { Theme } from './theme'; +import type { User } from './user'; +import type { Type } from './type'; +import type { Widget } from './widget'; +import type { WidgetType } from './widget-type'; +import type { WpTemplate } from './wp-template'; +import type { WpTemplatePart } from './wp-template-part'; +import type { Context, Updatable } from './helpers'; + +export type { BaseEntityTypes } from './base-entity-types'; + +export type { + Context, + Updatable, + Attachment, + Comment, + MenuLocation, + NavMenu, + NavMenuItem, + NavigationArea, + Page, + Plugin, + Post, + Settings, + Sidebar, + Taxonomy, + Theme, + User, + Type, + Widget, + WidgetType, + WpTemplate, + WpTemplatePart, +}; + +export type EntityRecord< C extends Context > = + | Attachment< C > + | Comment< C > + | MenuLocation< C > + | NavMenu< C > + | NavMenuItem< C > + | NavigationArea< C > + | Page< C > + | Plugin< C > + | Post< C > + | Settings< C > + | Sidebar< C > + | Taxonomy< C > + | Theme< C > + | Type< C > + | User< C > + | Widget< C > + | WidgetType< C > + | WpTemplate< C > + | WpTemplatePart< C >; + +export type UpdatableEntityRecord = Updatable< EntityRecord< 'edit' > >; diff --git a/packages/core-data/src/types/menu-location.ts b/packages/core-data/src/types/menu-location.ts new file mode 100644 index 00000000000000..71fb5abab87148 --- /dev/null +++ b/packages/core-data/src/types/menu-location.ts @@ -0,0 +1,29 @@ +/** + * Internal dependencies + */ +import { Context, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface MenuLocation< C extends Context > { + /** + * The name of the menu location. + */ + name: string; + /** + * The description of the menu location. + */ + description: string; + /** + * The ID of the assigned menu. + */ + menu: number; + } + } +} + +export type MenuLocation< C extends Context > = OmitNevers< + _BaseEntityTypes.MenuLocation< C > +>; diff --git a/packages/core-data/src/types/nav-menu-item.ts b/packages/core-data/src/types/nav-menu-item.ts new file mode 100644 index 00000000000000..dab6b9ffad2f25 --- /dev/null +++ b/packages/core-data/src/types/nav-menu-item.ts @@ -0,0 +1,106 @@ +/** + * Internal dependencies + */ +import { RenderedText, Context, ContextualField, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +export type NavMenuItemType = + | 'taxonomy' + | 'post_type' + | 'post_type_archive' + | 'custom'; +export type NavMenuItemStatus = + | 'publish' + | 'future' + | 'draft' + | 'pending' + | 'private'; +export type Target = '_blank' | ''; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface NavMenuItem< C extends Context > { + /** + * The title for the object. + */ + title: RenderedText< C >; + /** + * Unique identifier for the object. + */ + id: number; + /** + * The singular label used to describe this type of menu item. + */ + type_label: string; + /** + * The family of objects originally represented, such as "post_type" or "taxonomy". + */ + type: NavMenuItemType; + /** + * A named status for the object. + */ + status: NavMenuItemStatus; + /** + * The ID for the parent of the object. + */ + parent: number; + /** + * Text for the title attribute of the link element for this menu item. + */ + attr_title: string; + /** + * Class names for the link element of this menu item. + */ + classes: string[]; + /** + * The description of this menu item. + */ + description: string; + /** + * The DB ID of the nav_menu_item that is this item's menu parent, if any, otherwise 0. + */ + menu_order: number; + /** + * The type of object originally represented, such as "category", "post", or "attachment". + */ + object: string; + /** + * The database ID of the original object this menu item represents, for example the ID for posts or the term_id for categories. + */ + object_id: number; + /** + * The target attribute of the link element for this menu item. + */ + target: Target; + /** + * The URL to which this menu item points. + */ + url: string; + /** + * The XFN relationship expressed in the link of this menu item. + */ + xfn: string[]; + /** + * Whether the menu item represents an object that no longer exists. + */ + invalid: boolean; + /** + * The terms assigned to the object in the nav_menu taxonomy. + */ + menus: ContextualField< number, 'view' | 'edit', C >; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + } + } +} + +export type NavMenuItem< C extends Context > = OmitNevers< + _BaseEntityTypes.NavMenuItem< C > +>; diff --git a/packages/core-data/src/types/nav-menu.ts b/packages/core-data/src/types/nav-menu.ts new file mode 100644 index 00000000000000..aa3417ddba04b2 --- /dev/null +++ b/packages/core-data/src/types/nav-menu.ts @@ -0,0 +1,53 @@ +/** + * Internal dependencies + */ +import { Context, ContextualField, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface NavMenu< C extends Context > { + /** + * Unique identifier for the term. + */ + id: number; + /** + * HTML description of the term. + */ + description: ContextualField< string, 'view' | 'edit', C >; + /** + * HTML title for the term. + */ + name: string; + /** + * An alphanumeric identifier for the term unique to its type. + */ + slug: string; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * The locations assigned to the menu. + */ + locations: ContextualField< string[], 'view' | 'edit', C >; + /** + * The DB ID of the original object this menu item represents, e . g . ID for posts and term_id for categories. + */ + object_id: number; + /** + * Whether to automatically add top level pages to this menu. + */ + auto_add: ContextualField< boolean, 'view' | 'edit', C >; + } + } +} + +export type NavMenu< C extends Context > = OmitNevers< + _BaseEntityTypes.NavMenu< C > +>; diff --git a/packages/core-data/src/types/navigation-area.ts b/packages/core-data/src/types/navigation-area.ts new file mode 100644 index 00000000000000..ed5ae88769207e --- /dev/null +++ b/packages/core-data/src/types/navigation-area.ts @@ -0,0 +1,29 @@ +/** + * Internal dependencies + */ +import { Context, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface NavigationArea< C extends Context > { + /** + * The name of the navigation area. + */ + name: string; + /** + * The description of the navigation area. + */ + description: string; + /** + * The ID of the assigned navigation. + */ + navigation: number; + } + } +} + +export type NavigationArea< C extends Context > = OmitNevers< + _BaseEntityTypes.NavigationArea< C > +>; diff --git a/packages/core-data/src/types/page.ts b/packages/core-data/src/types/page.ts new file mode 100644 index 00000000000000..eb95206b8424e3 --- /dev/null +++ b/packages/core-data/src/types/page.ts @@ -0,0 +1,144 @@ +/** + * Internal dependencies + */ +import { + CommentingStatus, + Context, + ContextualField, + PingStatus, + PostStatus, + RenderedText, + OmitNevers, +} from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Page< C extends Context > { + /** + * The date the post was published, in the site's timezone. + */ + date: string | null; + /** + * The date the post was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * The globally unique identifier for the post. + */ + guid: ContextualField< RenderedText< C >, 'view' | 'edit', C >; + /** + * Unique identifier for the post. + */ + id: number; + /** + * URL to the post. + */ + link: string; + /** + * The date the post was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the post was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * An alphanumeric identifier for the post unique to its type. + */ + slug: string; + /** + * A named status for the post. + */ + status: ContextualField< PostStatus, 'view' | 'edit', C >; + /** + * Type of post. + */ + type: string; + /** + * A password to protect access to the content and excerpt. + */ + password: ContextualField< string, 'edit', C >; + /** + * Permalink template for the post. + */ + permalink_template: ContextualField< string, 'edit', C >; + /** + * Slug automatically generated from the post title. + */ + generated_slug: ContextualField< string, 'edit', C >; + /** + * The ID for the parent of the post. + */ + parent: ContextualField< number, 'view' | 'edit', C >; + /** + * The title for the post. + */ + title: RenderedText< C >; + /** + * The content for the post. + */ + content: ContextualField< + RenderedText< C > & { + /** + * Whether the content is protected with a password. + */ + is_protected: boolean; + /** + * Version of the content block format used by the page. + */ + block_version: ContextualField< string, 'edit', C >; + }, + 'view' | 'edit', + C + >; + /** + * The ID for the author of the post. + */ + author: number; + /** + * The excerpt for the post. + */ + excerpt: RenderedText< C > & { + protected: boolean; + }; + /** + * The ID of the featured media for the post. + */ + featured_media: number; + /** + * Whether or not comments are open on the post. + */ + comment_status: ContextualField< + CommentingStatus, + 'view' | 'edit', + C + >; + /** + * Whether or not the post can be pinged. + */ + ping_status: ContextualField< PingStatus, 'view' | 'edit', C >; + /** + * The order of the post in relation to other posts. + */ + menu_order: ContextualField< number, 'view' | 'edit', C >; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * The theme file to use to display the post. + */ + template: ContextualField< string, 'view' | 'edit', C >; + } + } +} + +export type Page< C extends Context > = OmitNevers< + _BaseEntityTypes.Page< C > +>; diff --git a/packages/core-data/src/types/plugin.ts b/packages/core-data/src/types/plugin.ts new file mode 100644 index 00000000000000..968f71f7a5bb71 --- /dev/null +++ b/packages/core-data/src/types/plugin.ts @@ -0,0 +1,74 @@ +/** + * Internal dependencies + */ +import { Context, ContextualField, RenderedText, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Plugin< C extends Context > { + /** + * The plugin file. + */ + plugin: string; + /** + * The plugin activation status. + */ + status: PluginStatus; + /** + * The plugin name. + */ + name: string; + /** + * The plugin's website address. + */ + plugin_uri: ContextualField< string, 'view' | 'edit', C >; + /** + * The plugin author. + */ + author: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * Plugin author's website address. + */ + author_uri: ContextualField< string, 'view' | 'edit', C >; + /** + * The plugin description. + */ + description: ContextualField< + RenderedText< 'edit' >, + 'view' | 'edit', + C + >; + /** + * The plugin version number. + */ + version: ContextualField< string, 'view' | 'edit', C >; + /** + * Whether the plugin can only be activated network-wide. + */ + network_only: boolean; + /** + * Minimum required version of WordPress. + */ + requires_wp: string; + /** + * Minimum required version of PHP. + */ + requires_php: string; + /** + * The plugin's text domain. + */ + textdomain: ContextualField< string, 'view' | 'edit', C >; + } + } +} + +export type PluginStatus = 'active' | 'inactive'; +export type Plugin< C extends Context > = OmitNevers< + _BaseEntityTypes.Plugin< C > +>; diff --git a/packages/core-data/src/types/post.ts b/packages/core-data/src/types/post.ts new file mode 100644 index 00000000000000..2c7ed4287f1834 --- /dev/null +++ b/packages/core-data/src/types/post.ts @@ -0,0 +1,153 @@ +/** + * Internal dependencies + */ +import { + CommentingStatus, + Context, + ContextualField, + PingStatus, + PostFormat, + PostStatus, + RenderedText, + OmitNevers, +} from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Post< C extends Context > { + /** + * The date the post was published, in the site's timezone. + */ + date: string | null; + /** + * The date the post was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * The globally unique identifier for the post. + */ + guid: ContextualField< RenderedText< C >, 'view' | 'edit', C >; + /** + * Unique identifier for the post. + */ + id: number; + /** + * URL to the post. + */ + link: string; + /** + * The date the post was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the post was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * An alphanumeric identifier for the post unique to its type. + */ + slug: string; + /** + * A named status for the post. + */ + status: ContextualField< PostStatus, 'view' | 'edit', C >; + /** + * Type of post. + */ + type: string; + /** + * A password to protect access to the content and excerpt. + */ + password: ContextualField< string, 'edit', C >; + /** + * Permalink template for the post. + */ + permalink_template: ContextualField< string, 'edit', C >; + /** + * Slug automatically generated from the post title. + */ + generated_slug: ContextualField< string, 'edit', C >; + /** + * The title for the post. + */ + title: RenderedText< C >; + /** + * The content for the post. + */ + content: ContextualField< + RenderedText< C > & { + /** + * Whether the content is protected with a password. + */ + is_protected: boolean; + /** + * Version of the content block format used by the page. + */ + block_version: ContextualField< string, 'edit', C >; + }, + 'view' | 'edit', + C + >; + /** + * The ID for the author of the post. + */ + author: number; + /** + * The excerpt for the post. + */ + excerpt: RenderedText< C > & { + protected: boolean; + }; + /** + * The ID of the featured media for the post. + */ + featured_media: number; + /** + * Whether or not comments are open on the post. + */ + comment_status: ContextualField< + CommentingStatus, + 'view' | 'edit', + C + >; + /** + * Whether or not the post can be pinged. + */ + ping_status: ContextualField< PingStatus, 'view' | 'edit', C >; + /** + * The format for the post. + */ + format: ContextualField< PostFormat, 'view' | 'edit', C >; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * Whether or not the post should be treated as sticky. + */ + sticky: ContextualField< boolean, 'view' | 'edit', C >; + /** + * The theme file to use to display the post. + */ + template: ContextualField< string, 'view' | 'edit', C >; + /** + * The terms assigned to the post in the category taxonomy. + */ + categories: ContextualField< number[], 'view' | 'edit', C >; + /** + * The terms assigned to the post in the post_tag taxonomy. + */ + tags: ContextualField< number[], 'view' | 'edit', C >; + } + } +} + +export type Post< C extends Context > = OmitNevers< + _BaseEntityTypes.Post< C > +>; diff --git a/packages/core-data/src/types/settings.ts b/packages/core-data/src/types/settings.ts new file mode 100644 index 00000000000000..978ce32e9b4161 --- /dev/null +++ b/packages/core-data/src/types/settings.ts @@ -0,0 +1,93 @@ +/** + * Internal dependencies + */ +import { CommentingStatus, Context, OmitNevers, PingStatus } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Settings< C extends Context > { + /** + * What to show on the front page + */ + show_on_front: string; + /** + * The ID of the page that should be displayed on the front page + */ + page_on_front: number; + /** + * Site title. + */ + title: string; + /** + * Site tagline. + */ + description: string; + /** + * Site URL. + */ + url: string; + /** + * This address is used for admin purposes, like new user notification. + */ + email: string; + /** + * A city in the same timezone as you. + */ + timezone: string; + /** + * A date format for all date strings. + */ + date_format: string; + /** + * A time format for all time strings. + */ + time_format: string; + /** + * A day number of the week that the week should start on. + */ + start_of_week: number; + /** + * WordPress locale code. + */ + language: string; + /** + * Convert emoticons like :-) and :-P to graphics on display. + */ + use_smilies: boolean; + /** + * Default post category. + */ + default_category: number; + /** + * Default post format. + */ + default_post_format: string; + /** + * Blog pages show at most. + */ + posts_per_page: number; + /** + * Allow link notifications from other blogs (pingbacks and trackbacks) on new articles. + */ + default_ping_status: PingStatus; + /** + * Allow people to submit comments on new posts. + */ + default_comment_status: CommentingStatus; + /** + * Site logo. + */ + site_logo: number; + /** + * Site icon. + */ + site_icon: number; + } + } +} + +export type Settings< C extends Context > = OmitNevers< + _BaseEntityTypes.Settings< C > +>; diff --git a/packages/core-data/src/types/sidebar.ts b/packages/core-data/src/types/sidebar.ts new file mode 100644 index 00000000000000..7ff4b209ea3ce4 --- /dev/null +++ b/packages/core-data/src/types/sidebar.ts @@ -0,0 +1,60 @@ +/** + * Internal dependencies + */ +import { Widget } from './widget'; +import { Context, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Sidebar< C extends Context > { + /** + * ID of sidebar. + */ + id: string; + /** + * Unique name identifying the sidebar. + */ + name: string; + /** + * Description of sidebar. + */ + description: string; + /** + * Extra CSS class to assign to the sidebar in the Widgets interface. + */ + class: string; + /** + * HTML content to prepend to each widget's HTML output when assigned to this sidebar. Default is an opening list item element. + */ + before_widget: string; + /** + * HTML content to append to each widget's HTML output when assigned to this sidebar. Default is a closing list item element. + */ + after_widget: string; + /** + * HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element. + */ + before_title: string; + /** + * HTML content to append to the sidebar title when displayed. Default is a closing h2 element. + */ + after_title: string; + /** + * Status of sidebar. + */ + status: SidebarStatus; + /** + * Nested widgets. + */ + widgets: ( Widget< C > | string )[]; + } + } +} + +type SidebarStatus = 'active' | 'inactive'; + +export type Sidebar< C extends Context > = OmitNevers< + _BaseEntityTypes.Sidebar< C > +>; diff --git a/packages/core-data/src/types/taxonomy.ts b/packages/core-data/src/types/taxonomy.ts new file mode 100644 index 00000000000000..120831dbd7acfb --- /dev/null +++ b/packages/core-data/src/types/taxonomy.ts @@ -0,0 +1,92 @@ +/** + * Internal dependencies + */ +import { Context, ContextualField, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Taxonomy< C extends Context > { + /** + * All capabilities used by the taxonomy. + */ + capabilities: ContextualField< + Record< string, string >, + 'edit', + C + >; + /** + * A human-readable description of the taxonomy. + */ + description: ContextualField< string, 'view' | 'edit', C >; + /** + * Whether or not the taxonomy should have children. + */ + hierarchical: ContextualField< boolean, 'view' | 'edit', C >; + /** + * Human-readable labels for the taxonomy for various contexts. + */ + labels: ContextualField< Record< string, string >, 'edit', C >; + /** + * The title for the taxonomy. + */ + name: string; + /** + * An alphanumeric identifier for the taxonomy. + */ + slug: string; + /** + * Whether or not the term cloud should be displayed. + */ + show_cloud: ContextualField< boolean, 'edit', C >; + /** + * Types associated with the taxonomy. + */ + types: ContextualField< string[], 'view' | 'edit', C >; + /** + * REST base route for the taxonomy. + */ + rest_base: string; + /** + * REST namespace route for the taxonomy. + */ + rest_namespace: string; + /** + * The visibility settings for the taxonomy. + */ + visibility: TaxonomyVisibility; + } + + export interface TaxonomyVisibility { + /** + * Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users. + */ + public: boolean; + /** + * Whether the taxonomy is publicly queryable. + */ + publicly_queryable: boolean; + /** + * Whether to generate a default UI for managing this taxonomy. + */ + show_ui: boolean; + /** + * Whether to allow automatic creation of taxonomy columns on associated post-types table. + */ + show_admin_column: boolean; + /** + * Whether to make the taxonomy available for selection in navigation menus. + */ + show_in_nav_menus: boolean; + /** + * Whether to show the taxonomy in the quick/bulk edit panel. + */ + show_in_quick_edit: boolean; + } + } +} + +export type Taxonomy< C extends Context > = OmitNevers< + _BaseEntityTypes.Taxonomy< C > +>; diff --git a/packages/core-data/src/types/theme.ts b/packages/core-data/src/types/theme.ts new file mode 100644 index 00000000000000..d3e58fb994861e --- /dev/null +++ b/packages/core-data/src/types/theme.ts @@ -0,0 +1,222 @@ +/** + * Internal dependencies + */ +import { Context, PostFormat, RenderedText, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Theme< C extends Context > { + /** + * The theme's stylesheet. This uniquely identifies the theme. + */ + stylesheet: string; + /** + * The theme's template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme's stylesheet. + */ + template: string; + /** + * The theme author. + */ + author: RenderedText< 'edit' >; + /** + * The website of the theme author. + */ + author_uri: RenderedText< 'edit' >; + /** + * A description of the theme. + */ + description: RenderedText< 'edit' >; + /** + * The name of the theme. + */ + name: RenderedText< 'edit' >; + /** + * The minimum PHP version required for the theme to work. + */ + requires_php: string; + /** + * The minimum WordPress version required for the theme to work. + */ + requires_wp: string; + /** + * The theme's screenshot URL. + */ + screenshot: string; + /** + * Tags indicating styles and features of the theme. + */ + tags: RenderedText< 'edit' >; + /** + * The theme's text domain. + */ + textdomain: string; + /** + * Features supported by this theme. + */ + theme_supports: ThemeSupports; + /** + * The URI of the theme's webpage. + */ + theme_uri: RenderedText< 'edit' >; + /** + * The theme's current version. + */ + version: string; + /** + * A named status for the theme. + */ + status: ThemeStatus; + } + + export type ThemeStatus = 'active' | 'inactive'; + + export interface ThemeSupports { + /** + * Whether theme opts in to wide alignment CSS class. + */ + 'align-wide': boolean; + /** + * Whether posts and comments RSS feed links are added to head. + */ + 'automatic-feed-links': boolean; + /** + * Custom background if defined by the theme. + */ + 'custom-background': boolean | CustomBackground; + /** + * Custom header if defined by the theme. + */ + 'custom-header': boolean | CustomHeader; + /** + * Custom logo if defined by the theme. + */ + 'custom-logo': boolean | CustomLogo; + /** + * Whether the theme enables Selective Refresh for Widgets being managed with the Customizer. + */ + 'customize-selective-refresh-widgets': boolean; + /** + * Whether theme opts in to the dark editor style UI. + */ + 'dark-editor-style': boolean; + /** + * Whether the theme disables custom colors. + */ + 'disable-custom-colors': boolean; + /** + * Whether the theme disables custom font sizes. + */ + 'disable-custom-font-sizes': boolean; + /** + * Whether the theme disables custom gradients. + */ + 'disable-custom-gradients': boolean; + /** + * Custom color palette if defined by the theme. + */ + 'editor-color-palette': boolean | Color[]; + /** + * Custom font sizes if defined by the theme. + */ + 'editor-font-sizes': boolean | FontSize[]; + /** + * Custom gradient presets if defined by the theme. + */ + 'editor-gradient-presets': boolean | GradientPreset[]; + /** + * Whether theme opts in to the editor styles CSS wrapper. + */ + 'editor-styles': boolean; + /** + * Allows use of HTML5 markup for search forms, comment forms, comment lists, gallery, and caption. + */ + html5: boolean | Html5Option[]; + /** + * Post formats supported. + */ + formats: PostFormat[]; + /** + * The post types that support thumbnails or true if all post types are supported. + */ + 'post-thumbnails': boolean | string[]; + /** + * Whether the theme supports responsive embedded content. + */ + 'responsive-embeds': boolean; + /** + * Whether the theme can manage the document title tag. + */ + 'title-tag': boolean; + /** + * Whether theme opts in to default WordPress block styles for viewing. + */ + 'wp-block-styles': boolean; + } + + export interface CustomBackground { + 'default-image': string; + 'default-preset': 'default' | 'fill' | 'fit' | 'repeat' | 'custom'; + 'default-position-x': 'left' | 'center' | 'right'; + 'default-position-y': 'left' | 'center' | 'right'; + 'default-size': 'auto' | 'contain' | 'cover'; + 'default-repeat': 'repeat-x' | 'repeat-y' | 'repeat' | 'no-repeat'; + 'default-attachment': 'scroll' | 'fixed'; + 'default-color': string; + } + + export interface CustomHeader { + 'default-image': string; + 'random-default': boolean; + width: number; + height: number; + 'flex-height': boolean; + 'flex-width': boolean; + 'default-text-color': string; + 'header-text': boolean; + uploads: boolean; + video: boolean; + } + + export interface CustomLogo { + width: number; + height: number; + 'flex-width': boolean; + 'flex-height': boolean; + 'header-text': string[]; + 'unlink-homepage-logo': boolean; + } + + export interface Color { + name: string; + slug: string; + color: string; + } + + export interface FontSize { + name: string; + size: number; + slug: string; + } + + export interface GradientPreset { + name: string; + gradient: string; + slug: string; + } + + export type Html5Option = + | 'search-form' + | 'comment-form' + | 'comment-list' + | 'gallery' + | 'caption' + | 'script' + | 'style'; + } +} + +export type Theme< C extends Context > = OmitNevers< + _BaseEntityTypes.Theme< C > +>; diff --git a/packages/core-data/src/types/type.ts b/packages/core-data/src/types/type.ts new file mode 100644 index 00000000000000..2841559eb11392 --- /dev/null +++ b/packages/core-data/src/types/type.ts @@ -0,0 +1,80 @@ +/** + * Internal dependencies + */ +import { Context, ContextualField, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Type< C extends Context > { + /** + * All capabilities used by the post type. + */ + capabilities: ContextualField< + Record< string, string >, + 'edit', + C + >; + /** + * A human-readable description of the post type. + */ + description: ContextualField< string, 'view' | 'edit', C >; + /** + * Whether or not the post type should have children. + */ + hierarchical: ContextualField< boolean, 'view' | 'edit', C >; + /** + * Whether or not the post type can be viewed. + */ + viewable: ContextualField< boolean, 'edit', C >; + /** + * Human-readable labels for the post type for various contexts. + */ + labels: ContextualField< Record< string, string >, 'edit', C >; + /** + * The title for the post type. + */ + name: string; + /** + * An alphanumeric identifier for the post type. + */ + slug: string; + /** + * All features, supported by the post type. + */ + supports: ContextualField< Record< string, string >, 'edit', C >; + /** + * Taxonomies associated with post type. + */ + taxonomies: ContextualField< string[], 'view' | 'edit', C >; + /** + * REST base route for the post type. + */ + rest_base: string; + /** + * REST route's namespace for the post type. + */ + rest_namespace: string; + /** + * The visibility settings for the post type. + */ + visibility: ContextualField< TypeVisibility, 'edit', C >; + } + + interface TypeVisibility { + /** + * Whether to generate a default UI for managing this post type. + */ + show_ui: boolean; + /** + * Whether to make the post type is available for selection in navigation menus. + */ + show_in_nav_menus: boolean; + } + } +} + +export type Type< C extends Context > = OmitNevers< + _BaseEntityTypes.Type< C > +>; diff --git a/packages/core-data/src/types/user.ts b/packages/core-data/src/types/user.ts new file mode 100644 index 00000000000000..172d369b44bbb4 --- /dev/null +++ b/packages/core-data/src/types/user.ts @@ -0,0 +1,109 @@ +/** + * Internal dependencies + */ +import { AvatarUrls, Context, ContextualField, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface User< C extends Context > { + /** + * Unique identifier for the user. + */ + id: number; + /** + * Login name for the user. + */ + username: ContextualField< string, 'edit', C >; + /** + * Display name for the user. + */ + name: string; + /** + * First name for the user. + */ + first_name: ContextualField< string, 'edit', C >; + /** + * Last name for the user. + */ + last_name: ContextualField< string, 'edit', C >; + /** + * The email address for the user. + */ + email: ContextualField< string, 'edit', C >; + /** + * URL of the user. + */ + url: string; + /** + * Description of the user. + */ + description: string; + /** + * Author URL of the user. + */ + link: string; + /** + * Locale for the user. + */ + locale: ContextualField< string, 'edit', C >; + /** + * The nickname for the user. + */ + nickname: ContextualField< string, 'edit', C >; + /** + * An alphanumeric identifier for the user. + */ + slug: string; + /** + * Registration date for the user. + */ + registered_date: ContextualField< string, 'edit', C >; + /** + * Roles assigned to the user. + */ + roles: ContextualField< string[], 'edit', C >; + /** + * Password for the user. + * + * This is never sent from the server to the client + * but exists because we might send an update to the + * server with a new password to set. + */ + password?: string; + /** + * All capabilities assigned to the user. + */ + capabilities: ContextualField< + Record< string, string >, + 'edit', + C + >; + /** + * Any extra capabilities assigned to the user. + */ + extra_capabilities: ContextualField< + Record< string, string >, + 'edit', + C + >; + /** + * Avatar URLs for the user. + */ + avatar_urls: AvatarUrls; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + } + } +} + +export type User< C extends Context > = OmitNevers< + _BaseEntityTypes.User< C > +>; diff --git a/packages/core-data/src/types/widget-type.ts b/packages/core-data/src/types/widget-type.ts new file mode 100644 index 00000000000000..82f65ea493141d --- /dev/null +++ b/packages/core-data/src/types/widget-type.ts @@ -0,0 +1,37 @@ +/** + * Internal dependencies + */ +import { Context, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface WidgetType< C extends Context > { + /** + * Unique slug identifying the widget type. + */ + id: string; + /** + * Human-readable name identifying the widget type. + */ + name: string; + /** + * Description of the widget. + */ + description: string; + /** + * Whether the widget supports multiple instances + */ + is_multi: boolean; + /** + * Class name + */ + classname: string; + } + } +} + +export type WidgetType< C extends Context > = OmitNevers< + _BaseEntityTypes.WidgetType< C > +>; diff --git a/packages/core-data/src/types/widget.ts b/packages/core-data/src/types/widget.ts new file mode 100644 index 00000000000000..f1b5a489e92976 --- /dev/null +++ b/packages/core-data/src/types/widget.ts @@ -0,0 +1,64 @@ +/** + * Internal dependencies + */ +import { Context, ContextualField, OmitNevers } from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface Widget< C extends Context > { + /** + * Unique identifier for the widget. + */ + id: string; + /** + * The type of the widget. Corresponds to ID in widget-types endpoint. + */ + id_base: string; + /** + * The sidebar the widget belongs to. + */ + sidebar: string; + /** + * HTML representation of the widget. + */ + rendered: string; + /** + * HTML representation of the widget admin form. + */ + rendered_form: ContextualField< string, 'edit', C >; + /** + * Instance settings of the widget, if supported. + */ + instance: ContextualField< WidgetInstance, 'edit', C >; + /** + * URL-encoded form data from the widget admin form. Used + * to update a widget that does not support instance. + * + * This is never sent from the server to the client but exists + * because we might send an update. + */ + form_data?: string; + } + + interface WidgetInstance { + /** + * Base64 encoded representation of the instance settings. + */ + encoded: string; + /** + * Cryptographic hash of the instance settings. + */ + hash: string; + /** + * Unencoded instance settings, if supported. + */ + raw: Record< string, string >; + } + } +} + +export type Widget< C extends Context > = OmitNevers< + _BaseEntityTypes.Widget< C > +>; diff --git a/packages/core-data/src/types/wp-template-part.ts b/packages/core-data/src/types/wp-template-part.ts new file mode 100644 index 00000000000000..36fc0509003383 --- /dev/null +++ b/packages/core-data/src/types/wp-template-part.ts @@ -0,0 +1,94 @@ +/** + * Internal dependencies + */ +import { + Context, + PostStatus, + RenderedText, + OmitNevers, + ContextualField, +} from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface WpTemplatePart< C extends Context > { + /** + * ID of template. + */ + id: string; + /** + * Unique slug identifying the template. + */ + slug: string; + /** + * Theme identifier for the template. + */ + theme: string; + /** + * Type of template. + */ + type: string; + /** + * Source of template + */ + source: string; + /** + * Source of a customized template + */ + origin: string; + /** + * Content of template. + * + * This field never has a `rendered` property when reading but still uses + * the RenderedText type so it can be set as a string when sending updates to + * the server. + * + * TODO: Figure out how to mesh this with `RenderedText` + */ + content: ContextualField< + RenderedText< C > & { + /** + * Version of the content block format used by the template. + */ + block_version: ContextualField< number, 'edit', C >; + }, + 'view' | 'edit', + C + >; + /** + * Title of template. + */ + title: RenderedText< 'edit' >; + /** + * Description of template. + */ + description: string; + /** + * Status of template. + */ + status: PostStatus; + /** + * Post ID. + */ + wp_id: number; + /** + * Theme file exists. + */ + has_theme_file: Record< string, string >; + /** + * The ID for the author of the template. + */ + author: number; + /** + * Where the template part is intended for use (header, footer, etc.) + */ + area: string; + } + } +} + +export type WpTemplatePart< C extends Context > = OmitNevers< + _BaseEntityTypes.WpTemplatePart< C > +>; diff --git a/packages/core-data/src/types/wp-template.ts b/packages/core-data/src/types/wp-template.ts new file mode 100644 index 00000000000000..33fa31787792a8 --- /dev/null +++ b/packages/core-data/src/types/wp-template.ts @@ -0,0 +1,94 @@ +/** + * Internal dependencies + */ +import { + Context, + PostStatus, + RenderedText, + OmitNevers, + ContextualField, +} from './helpers'; + +import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types'; + +declare module './base-entity-types' { + export namespace BaseEntityTypes { + export interface WpTemplate< C extends Context > { + /** + * ID of template. + */ + id: string; + /** + * Unique slug identifying the template. + */ + slug: string; + /** + * Theme identifier for the template. + */ + theme: string; + /** + * Type of template. + */ + type: string; + /** + * Source of template + */ + source: string; + /** + * Source of a customized template + */ + origin: string; + /** + * Content of template. + * + * This field never has a `rendered` property when reading but still uses + * the RenderedText type so it can be set as a string when sending updates to + * the server. + * + * TODO: Figure out how to mesh this with `RenderedText` + */ + content: ContextualField< + RenderedText< C > & { + /** + * Version of the content block format used by the template. + */ + block_version: ContextualField< number, 'edit', C >; + }, + 'view' | 'edit', + C + >; + /** + * Title of template. + */ + title: RenderedText< 'edit' >; + /** + * Description of template. + */ + description: string; + /** + * Status of template. + */ + status: PostStatus; + /** + * Post ID. + */ + wp_id: number; + /** + * Theme file exists. + */ + has_theme_file: Record< string, string >; + /** + * The ID for the author of the template. + */ + author: number; + /** + * Whether a template is a custom template. + */ + is_custom: Record< string, string >; + } + } +} + +export type WpTemplate< C extends Context > = OmitNevers< + _BaseEntityTypes.WpTemplate< C > +>;