From ba2c7333f3b618c3eece5723150936993aee0c7e Mon Sep 17 00:00:00 2001 From: lihbr Date: Fri, 23 Aug 2024 17:29:39 +0200 Subject: [PATCH] test: type test migration types --- src/Migration.ts | 21 ++- src/index.ts | 20 +++ src/types/migration/document.ts | 2 +- test/types/migration-document.types.ts | 234 +++++++++++++++++++++++++ test/types/migration.types.ts | 105 +++++++++++ 5 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 test/types/migration-document.types.ts create mode 100644 test/types/migration.types.ts diff --git a/src/Migration.ts b/src/Migration.ts index d95e574c..4092fdc2 100644 --- a/src/Migration.ts +++ b/src/Migration.ts @@ -8,6 +8,23 @@ import { } from "./types/migration/fields" import type { PrismicDocument } from "./types/value/document" +/** + * Extracts one or more Prismic document types that match a given Prismic + * document type. If no matches are found, no extraction is performed and the + * union of all provided Prismic document types are returned. + * + * @typeParam TMigrationDocuments - Prismic migration document types from which + * to extract. + * @typeParam TType - Type(s) to match `TMigrationDocuments` against. + */ +type ExtractMigrationDocumentType< + TMigrationDocuments extends MigrationPrismicDocument, + TType extends TMigrationDocuments["type"], +> = + Extract extends never + ? TMigrationDocuments + : Extract + type CreateAssetReturnType = MigrationImageField & { image: MigrationImageField linkToMedia: MigrationLinkToMediaField @@ -98,7 +115,9 @@ export class Migration< } } - createDocument(document: TMigrationDocuments): TMigrationDocuments { + createDocument( + document: ExtractMigrationDocumentType, + ): ExtractMigrationDocumentType { this.#documents.push(document) if (!(document.type in this.#documentsByUID)) { diff --git a/src/index.ts b/src/index.ts index 318aebc6..e728600d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -325,6 +325,26 @@ export type { CustomTypeModelFieldForSlicePrimary, } from "./types/model/types" +// Migrations - Types representing Prismic migration API content values. +export { MigrationFieldType } from "./types/migration/fields" + +export type { + MigrationPrismicDocument, + RichTextFieldToMigrationField, +} from "./types/migration/document" + +export type { + MigrationImageField, + MigrationLinkToMediaField, + MigrationContentRelationshipField, + MigrationLinkField, +} from "./types/migration/fields" + +export type { + MigrationRTImageNode, + MigrationRTLinkNode, +} from "./types/migration/richText" + // API - Types representing Prismic Rest API V2 responses. export type { Query } from "./types/api/query" diff --git a/src/types/migration/document.ts b/src/types/migration/document.ts index d98619cf..43af8974 100644 --- a/src/types/migration/document.ts +++ b/src/types/migration/document.ts @@ -94,7 +94,7 @@ type FieldsToMigrationFields< type MakeUIDOptional = TMigrationDocument["uid"] extends string ? TMigrationDocument - : Omit & { uid?: TMigrationDocument["uid"] } + : Omit & Partial> /** * A Prismic document compatible with the migration API. diff --git a/test/types/migration-document.types.ts b/test/types/migration-document.types.ts new file mode 100644 index 00000000..a745ced2 --- /dev/null +++ b/test/types/migration-document.types.ts @@ -0,0 +1,234 @@ +import type { TypeOf } from "ts-expect" +import { expectNever, expectType } from "ts-expect" + +import type * as prismic from "../../src" + +;(value: prismic.MigrationPrismicDocument): true => { + switch (typeof value) { + case "object": { + if (value === null) { + expectNever(value) + } + + return true + } + + default: { + return expectNever(value) + } + } +} + +expectType({ + title: "", + uid: "", + type: "", + lang: "", + data: {}, +}) + +/** + * Supports any field when generic. + */ +expectType({ + title: "", + uid: "", + type: "", + lang: "", + data: { + any: "", + }, +}) + +/** + * `PrismicDocument` is assignable to `MigrationPrismicDocument` with added + * `title`. + */ +expectType< + TypeOf< + prismic.MigrationPrismicDocument, + prismic.PrismicDocument & { title: string } + > +>(true) + +// Migration Documents +type FooDocument = prismic.PrismicDocument, "foo"> +type BarDocument = prismic.PrismicDocument<{ bar: prismic.KeyTextField }, "bar"> +type BazDocument = prismic.PrismicDocument, "baz"> +type Documents = FooDocument | BarDocument | BazDocument + +type MigrationDocuments = prismic.MigrationPrismicDocument + +/** + * Infers data type from document type. + */ +expectType({ + title: "", + uid: "", + type: "foo", + lang: "", + data: {}, +}) + +// @ts-expect-error - `FooDocument` has no `bar` field in `data` +expectType({ + title: "", + uid: "", + type: "foo", + lang: "", + data: { + bar: "", + }, +}) + +expectType({ + title: "", + uid: "", + type: "bar", + lang: "", + data: { + bar: "", + }, +}) + +// @ts-expect-error - `bar` is missing in `data` +expectType({ + title: "", + uid: "", + type: "bar", + lang: "", + data: {}, +}) + +/** + * Accepts migration field types. + */ +type Fields = { + image: prismic.ImageField + migrationImage: prismic.ImageField + link: prismic.LinkField + migrationLink: prismic.LinkField + linkToMedia: prismic.LinkToMediaField + migrationLinkToMedia: prismic.LinkToMediaField + contentRelationship: prismic.ContentRelationshipField + migrationContentRelationship: prismic.ContentRelationshipField +} + +type StaticDocument = prismic.PrismicDocument +type GroupDocument = prismic.PrismicDocument< + { group: prismic.GroupField }, + "group" +> +type SliceDocument = prismic.PrismicDocument< + { + slices: prismic.SliceZone< + prismic.SharedSlice< + "default", + prismic.SharedSliceVariation< + "default", + Fields & { group: prismic.GroupField }, + Fields + > + > + > + }, + "slice" +> +type AdvancedDocuments = StaticDocument | GroupDocument | SliceDocument +type MigrationAdvancedDocuments = + prismic.MigrationPrismicDocument + +// Static +expectType({ + title: "", + uid: "", + type: "static", + lang: "", + data: { + image: {} as prismic.ImageField, + migrationImage: {} as prismic.MigrationImageField, + link: {} as prismic.LinkField, + migrationLink: {} as prismic.MigrationLinkField, + linkToMedia: {} as prismic.LinkToMediaField, + migrationLinkToMedia: {} as prismic.MigrationLinkToMediaField, + contentRelationship: {} as prismic.ContentRelationshipField, + migrationContentRelationship: {} as prismic.ContentRelationshipField, + }, +}) + +// Group +expectType({ + title: "", + uid: "", + type: "group", + lang: "", + data: { + group: [ + { + image: {} as prismic.ImageField, + migrationImage: {} as prismic.MigrationImageField, + link: {} as prismic.LinkField, + migrationLink: {} as prismic.MigrationLinkField, + linkToMedia: {} as prismic.LinkToMediaField, + migrationLinkToMedia: {} as prismic.MigrationLinkToMediaField, + contentRelationship: {} as prismic.ContentRelationshipField, + migrationContentRelationship: {} as prismic.ContentRelationshipField, + }, + ], + }, +}) + +// Slice +expectType({ + title: "", + uid: "", + type: "slice", + lang: "", + data: { + slices: [ + { + slice_type: "default", + slice_label: null, + id: "", + variation: "default", + version: "", + primary: { + image: {} as prismic.ImageField, + migrationImage: {} as prismic.MigrationImageField, + link: {} as prismic.LinkField, + migrationLink: {} as prismic.MigrationLinkField, + linkToMedia: {} as prismic.LinkToMediaField, + migrationLinkToMedia: {} as prismic.MigrationLinkToMediaField, + contentRelationship: {} as prismic.ContentRelationshipField, + migrationContentRelationship: {} as prismic.ContentRelationshipField, + group: [ + { + image: {} as prismic.ImageField, + migrationImage: {} as prismic.MigrationImageField, + link: {} as prismic.LinkField, + migrationLink: {} as prismic.MigrationLinkField, + linkToMedia: {} as prismic.LinkToMediaField, + migrationLinkToMedia: {} as prismic.MigrationLinkToMediaField, + contentRelationship: {} as prismic.ContentRelationshipField, + migrationContentRelationship: + {} as prismic.ContentRelationshipField, + }, + ], + }, + items: [ + { + image: {} as prismic.ImageField, + migrationImage: {} as prismic.MigrationImageField, + link: {} as prismic.LinkField, + migrationLink: {} as prismic.MigrationLinkField, + linkToMedia: {} as prismic.LinkToMediaField, + migrationLinkToMedia: {} as prismic.MigrationLinkToMediaField, + contentRelationship: {} as prismic.ContentRelationshipField, + migrationContentRelationship: + {} as prismic.ContentRelationshipField, + }, + ], + }, + ], + }, +}) diff --git a/test/types/migration.types.ts b/test/types/migration.types.ts new file mode 100644 index 00000000..a6899bd0 --- /dev/null +++ b/test/types/migration.types.ts @@ -0,0 +1,105 @@ +import type { TypeEqual, TypeOf } from "ts-expect" +import { expectType } from "ts-expect" + +import * as prismic from "../../src" + +// Default migration +const defaultMigration = prismic.createMigration() + +// Migration Documents +type FooDocument = prismic.PrismicDocument, "foo"> +type BarDocument = prismic.PrismicDocument, "bar"> +type BazDocument = prismic.PrismicDocument, "baz"> +type Documents = FooDocument | BarDocument | BazDocument + +const documentsMigration = prismic.createMigration() + +/** + * Ensuring no full overlap between test types as we're testing for narrowing. + */ +expectType>(false) +expectType< + TypeEqual, prismic.Query> +>(false) +expectType>(false) + +expectType>(false) +expectType, prismic.Query>>( + false, +) +expectType>(false) + +expectType>(false) +expectType< + TypeEqual, prismic.Query> +>(false) +expectType>(false) + +/** + * createAsset + */ + +// Default +const defaultCreateAsset = defaultMigration.createAsset("url", "name") +expectType>(true) +expectType< + TypeEqual +>(true) +expectType< + TypeEqual< + typeof defaultCreateAsset.linkToMedia, + prismic.MigrationLinkToMediaField + > +>(true) +expectType< + TypeOf +>(true) + +// Documents +const documentsCreateAsset = defaultMigration.createAsset("url", "name") +expectType>( + true, +) +expectType< + TypeEqual +>(true) +expectType< + TypeEqual< + typeof documentsCreateAsset.linkToMedia, + prismic.MigrationLinkToMediaField + > +>(true) +expectType< + TypeOf +>(true) + +/** + * createDocument - basic + */ + +// Default +const defaultCreateDocument = defaultMigration.createDocument({ + title: "", + type: "", + uid: "", + lang: "", + data: {}, +}) +expectType< + TypeEqual +>(true) + +// Documents +const documentsCreateDocument = documentsMigration.createDocument({ + title: "", + type: "foo", + uid: "", + lang: "", + data: {}, +}) +expectType< + TypeEqual< + typeof documentsCreateDocument, + prismic.MigrationPrismicDocument + > +>(true)