diff --git a/package-lock.json b/package-lock.json index 0e5368d9..74dbd8e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@prismicio/mock": "^0.3.1", - "@prismicio/types-internal": "^2.4.0", + "@prismicio/types-internal": "^2.5.0-alpha.4", "@size-limit/preset-small-lib": "^9.0.0", "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.4", @@ -1008,9 +1008,9 @@ } }, "node_modules/@prismicio/types-internal": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@prismicio/types-internal/-/types-internal-2.4.0.tgz", - "integrity": "sha512-39B9KO0sMqIkLcXP0jh1M8dULDwr0uu1FUYPCaAXjKrvnMs3JTNX3j5lAHYDYQQPgFSnX7NvnsRDP8BMqEETuw==", + "version": "2.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/@prismicio/types-internal/-/types-internal-2.5.0-alpha.4.tgz", + "integrity": "sha512-+qjr7gPMlU3di9NtJETMv0Qoe60vLGAJTGiJhjIFEY3c70fQuafD1MAE/HF2EvNy1E7zvRV2tMyI68wERbqAUA==", "dev": true, "dependencies": { "monocle-ts": "^2.3.11", diff --git a/package.json b/package.json index 677f9661..c5d6365a 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ }, "devDependencies": { "@prismicio/mock": "^0.3.1", - "@prismicio/types-internal": "^2.4.0", + "@prismicio/types-internal": "^2.5.0-alpha.4", "@size-limit/preset-small-lib": "^9.0.0", "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.4", diff --git a/src/helpers/isFilled.ts b/src/helpers/isFilled.ts index 4327c217..fc7b933b 100644 --- a/src/helpers/isFilled.ts +++ b/src/helpers/isFilled.ts @@ -3,7 +3,7 @@ import type { ContentRelationshipField } from "../types/value/contentRelationshi import type { DateField } from "../types/value/date"; import type { AnyOEmbed, EmbedField } from "../types/value/embed"; import type { GeoPointField } from "../types/value/geoPoint"; -import type { GroupField } from "../types/value/group"; +import type { GroupField, NestedGroupField } from "../types/value/group"; import type { ImageField, ImageFieldImage } from "../types/value/image"; import type { IntegrationField } from "../types/value/integration"; import type { KeyTextField } from "../types/value/keyText"; @@ -273,7 +273,9 @@ export const integrationFields = integrationField; * * @returns `true` if `group` contains at least one item, `false` otherwise. */ -export const group = >( +export const group = < + Fields extends Record, +>( group: GroupField | null | undefined, ): group is GroupField => { return isNonNullish(group) && isNonEmptyArray(group); diff --git a/src/index.ts b/src/index.ts index 1f1c80bd..49658725 100644 --- a/src/index.ts +++ b/src/index.ts @@ -221,7 +221,7 @@ export type { GeoPointField } from "./types/value/geoPoint"; type IntegrationFields = IntegrationField; export { IntegrationField, IntegrationFields }; -export type { GroupField } from "./types/value/group"; +export type { GroupField, NestedGroupField } from "./types/value/group"; export type { SliceZone } from "./types/value/sliceZone"; export type { Slice } from "./types/value/slice"; @@ -283,7 +283,10 @@ export { CustomTypeModelIntegrationField, CustomTypeModelIntegrationFieldsField, }; -export type { CustomTypeModelGroupField } from "./types/model/group"; +export type { + CustomTypeModelGroupField, + CustomTypeModelNestedGroupField, +} from "./types/model/group"; export type { CustomTypeModelSliceZoneField, CustomTypeModelSliceLabel, @@ -304,6 +307,7 @@ export type { CustomTypeModelSeparatorField } from "./types/model/separator"; export type { CustomTypeModelField, CustomTypeModelFieldForGroup, + CustomTypeModelFieldForNestedGroup, CustomTypeModelFieldForSlicePrimary, } from "./types/model/types"; diff --git a/src/types/model/group.ts b/src/types/model/group.ts index 58849120..0ec898eb 100644 --- a/src/types/model/group.ts +++ b/src/types/model/group.ts @@ -1,5 +1,6 @@ import type { CustomTypeModelFieldForGroup, + CustomTypeModelFieldForNestedGroup, CustomTypeModelFieldType, } from "./types"; @@ -22,3 +23,17 @@ export interface CustomTypeModelGroupField< fields?: Fields; }; } + +/** + * A nested group custom type field. + * + * More details: {@link https://prismic.io/docs/group} + * + * @typeParam Fields - A record of fields that can be repeated. + */ +export type CustomTypeModelNestedGroupField< + Fields extends Record = Record< + string, + CustomTypeModelFieldForNestedGroup + >, +> = CustomTypeModelGroupField; diff --git a/src/types/model/sharedSliceVariation.ts b/src/types/model/sharedSliceVariation.ts index 2bb29be6..4a2d3745 100644 --- a/src/types/model/sharedSliceVariation.ts +++ b/src/types/model/sharedSliceVariation.ts @@ -1,5 +1,5 @@ import type { - CustomTypeModelFieldForGroup, + CustomTypeModelFieldForNestedGroup, CustomTypeModelFieldForSlicePrimary, } from "./types"; @@ -17,10 +17,10 @@ export interface SharedSliceModelVariation< string, CustomTypeModelFieldForSlicePrimary > = Record, - ItemFields extends Record = Record< + ItemFields extends Record< string, - CustomTypeModelFieldForGroup - >, + CustomTypeModelFieldForNestedGroup + > = Record, > { id: ID; name: string; diff --git a/src/types/model/slice.ts b/src/types/model/slice.ts index e5871295..4cc1d3f8 100644 --- a/src/types/model/slice.ts +++ b/src/types/model/slice.ts @@ -1,6 +1,6 @@ -import type { CustomTypeModelFieldForGroup } from "./types"; +import type { CustomTypeModelFieldForNestedGroup } from "./types"; -import type { CustomTypeModelGroupField } from "./group"; +import type { CustomTypeModelNestedGroupField } from "./group"; import type { CustomTypeModelSliceType } from "./sliceZone"; /** @@ -12,14 +12,14 @@ import type { CustomTypeModelSliceType } from "./sliceZone"; * @typeParam RepeatFields - A record of fields that can be repeated. */ export interface CustomTypeModelSlice< - NonRepeatFields extends Record = Record< + NonRepeatFields extends Record< string, - CustomTypeModelFieldForGroup - >, - RepeatFields extends Record = Record< + CustomTypeModelFieldForNestedGroup + > = Record, + RepeatFields extends Record< string, - CustomTypeModelFieldForGroup - >, + CustomTypeModelFieldForNestedGroup + > = Record, > { type: typeof CustomTypeModelSliceType.Slice; fieldset?: string | null; @@ -46,5 +46,5 @@ export const CustomTypeModelSliceDisplay = { * @deprecated - Legacy slice type. Do not use. */ export type CustomTypeModelLegacySlice = - | CustomTypeModelGroupField - | CustomTypeModelFieldForGroup; + | CustomTypeModelNestedGroupField + | CustomTypeModelFieldForNestedGroup; diff --git a/src/types/model/types.ts b/src/types/model/types.ts index 2c77a79b..7c09c76d 100644 --- a/src/types/model/types.ts +++ b/src/types/model/types.ts @@ -4,7 +4,10 @@ import type { CustomTypeModelContentRelationshipField } from "./contentRelations import type { CustomTypeModelDateField } from "./date"; import type { CustomTypeModelEmbedField } from "./embed"; import type { CustomTypeModelGeoPointField } from "./geoPoint"; -import type { CustomTypeModelGroupField } from "./group"; +import type { + CustomTypeModelGroupField, + CustomTypeModelNestedGroupField, +} from "./group"; import type { CustomTypeModelImageField } from "./image"; import type { CustomTypeModelIntegrationField } from "./integration"; import type { CustomTypeModelKeyTextField } from "./keyText"; @@ -65,19 +68,26 @@ export type CustomTypeModelField = | CustomTypeModelUIDField | CustomTypeModelGroupField | CustomTypeModelSliceZoneField - | CustomTypeModelFieldForGroup; + | CustomTypeModelFieldForNestedGroup; /** * Any custom type field that is valid for a slice's primary section. */ export type CustomTypeModelFieldForSlicePrimary = | CustomTypeModelGroupField - | CustomTypeModelFieldForGroup; + | CustomTypeModelFieldForNestedGroup; /** * Any custom type field that is valid for a group field. */ export type CustomTypeModelFieldForGroup = + | CustomTypeModelNestedGroupField + | CustomTypeModelFieldForNestedGroup; + +/** + * Any custom type field that is valid for a nested group field. + */ +export type CustomTypeModelFieldForNestedGroup = | CustomTypeModelBooleanField | CustomTypeModelColorField | CustomTypeModelDateField diff --git a/src/types/value/group.ts b/src/types/value/group.ts index c7298168..4498c2b0 100644 --- a/src/types/value/group.ts +++ b/src/types/value/group.ts @@ -6,9 +6,22 @@ import type { AnyRegularField, FieldState } from "./types"; * More details: {@link https://prismic.io/docs/group} */ export type GroupField< + Fields extends Record = Record< + string, + AnyRegularField | NestedGroupField + >, + State extends FieldState = FieldState, +> = State extends "empty" ? [] : [Fields, ...Fields[]]; + +/** + * A nested group field. + * + * More details: {@link https://prismic.io/docs/group} + */ +export type NestedGroupField< Fields extends Record = Record< string, AnyRegularField >, State extends FieldState = FieldState, -> = State extends "empty" ? [] : [Fields, ...Fields[]]; +> = GroupField; diff --git a/test/types/customType-group.types.ts b/test/types/customType-group.types.ts index 6880fde5..b7974252 100644 --- a/test/types/customType-group.types.ts +++ b/test/types/customType-group.types.ts @@ -77,6 +77,38 @@ expectType< }, }); +/** + * Supports nested groups. + */ +expectType< + prismic.CustomTypeModelGroupField<{ + foo: prismic.CustomTypeModelNestedGroupField<{ + bar: prismic.CustomTypeModelBooleanField; + }>; + }> +>({ + type: prismic.CustomTypeModelFieldType.Group, + config: { + label: "string", + fields: { + foo: { + type: prismic.CustomTypeModelFieldType.Group, + config: { + label: "string", + fields: { + bar: { + type: prismic.CustomTypeModelFieldType.Boolean, + config: { + label: "string", + }, + }, + }, + }, + }, + }, + }, +}); + /** * `@prismicio/types` extends `@prismicio/types-internal` */ diff --git a/test/types/customType.types.ts b/test/types/customType.types.ts index eafa8371..065297f8 100644 --- a/test/types/customType.types.ts +++ b/test/types/customType.types.ts @@ -255,6 +255,12 @@ expectType< prismic.CustomTypeModelLinkToMediaField > >(true); +expectType< + TypeOf< + prismic.CustomTypeModelFieldForGroup, + prismic.CustomTypeModelNestedGroupField + > +>(true); expectType< TypeOf< prismic.CustomTypeModelFieldForGroup, diff --git a/test/types/fields-group.types.ts b/test/types/fields-group.types.ts index b54fa3f8..5796fcdd 100644 --- a/test/types/fields-group.types.ts +++ b/test/types/fields-group.types.ts @@ -58,15 +58,14 @@ expectType>([ }, ]); +/** + * Supports nested groups. + */ +expectType>([]); + /** * Custom fields may only contain group-compatible fields. */ -expectType< - prismic.GroupField ->([]); expectType< prismic.GroupField>(true); expectType>(true); @@ -41,10 +41,11 @@ expectType>(true); expectType>(true); /** - * AnyRegularField excludes any fields not compatible with a Group. + * AnyRegularField excludes any fields not compatible with a nested Group. */ expectType>(false); expectType>(false); +expectType>(false); /** * AnySlicePrimaryField supports any field compatible with a slice's primary diff --git a/test/types/helpers-isFilled.types.ts b/test/types/helpers-isFilled.types.ts index e6c8fa40..f8e9b44f 100644 --- a/test/types/helpers-isFilled.types.ts +++ b/test/types/helpers-isFilled.types.ts @@ -517,7 +517,10 @@ type IntegrationFieldData = { foo: string }; * Group */ -type GroupDefault = Record; +type GroupDefault = Record< + string, + prismic.AnyRegularField | prismic.NestedGroupField +>; // Default (value: prismic.GroupField) => {