Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support link variants #368

Merged
merged 15 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/Migration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as is from "./lib/isValue"
import { getOptionalLinkProperties } from "./lib/getLinkProperties"
import { validateAssetMetadata } from "./lib/validateAssetMetadata"

import type { Asset } from "./types/api/asset/asset"
Expand Down Expand Up @@ -404,28 +405,32 @@ export class Migration<TDocuments extends PrismicDocument = PrismicDocument> {
*/
#migratePrismicDocumentData(input: unknown): unknown {
if (is.filledContentRelationship(input)) {
const optionalLinkProperties = getOptionalLinkProperties(input)

if (input.isBroken) {
return {
...optionalLinkProperties,
link_type: LinkType.Document,
// ID needs to be 16 characters long to be considered valid by the API
id: "_____broken_____",
isBroken: true,
text: input.text,
}
}

return {
...optionalLinkProperties,
link_type: LinkType.Document,
id: () => this._getByOriginalID(input.id),
text: input.text,
}
}

if (is.filledLinkToMedia(input)) {
const optionalLinkProperties = getOptionalLinkProperties(input)

return {
...optionalLinkProperties,
link_type: LinkType.Media,
id: this.createAsset(input),
text: input.text,
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/lib/getLinkProperties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { FilledContentRelationshipField } from "../types/value/contentRelationship"
import type { OptionalLinkProperties } from "../types/value/link"
import type { FilledLinkToMediaField } from "../types/value/linkToMedia"

/**
* Returns optional properties only available to link fields. Link fields can
* have the same shape as content relationship and link to media fields,
* requiring special treatment to extract link-specific properties.
*
* @param input - The content relationship or link to media field from which the
* link properties are extracted.
*
* @returns Optional link properties that `input` might have.
*/
export const getOptionalLinkProperties = (
input: FilledContentRelationshipField | FilledLinkToMediaField,
): OptionalLinkProperties => {
const res: OptionalLinkProperties = {}

if ("text" in input) {
res.text = input.text
}

return res
}
6 changes: 3 additions & 3 deletions src/lib/resolveMigrationDocumentData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function resolveMigrationContentRelationship(
if (relation instanceof PrismicMigrationDocument) {
return relation.document.id
? { link_type: LinkType.Document, id: relation.document.id }
: { link_type: LinkType.Document }
: { link_type: LinkType.Any }
}

if (relation) {
Expand All @@ -57,7 +57,7 @@ export async function resolveMigrationContentRelationship(
return { link_type: LinkType.Document, id: relation.id }
}

return { link_type: LinkType.Document }
return { link_type: LinkType.Any }
}

/**
Expand Down Expand Up @@ -167,7 +167,7 @@ export const resolveMigrationLinkToMedia = (
}
}

return { link_type: LinkType.Media }
return { link_type: LinkType.Any }
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/types/migration/Asset.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Asset } from "../api/asset/asset"
import type { FilledImageFieldImage } from "../value/image"
import type { EmptyLinkField } from "../value/link"
import type { LinkToMediaField } from "../value/linkToMedia"
import { type RTImageNode } from "../value/richText"

Expand Down Expand Up @@ -89,7 +88,7 @@ export type MigrationLinkToMedia = Pick<
*/
export type MigrationLinkToMediaField =
| Pick<LinkToMediaField<"filled">, "link_type" | "id" | "text">
| EmptyLinkField<"Media">
| LinkToMediaField<"empty">

/**
* A rich text image node in a migration.
Expand Down
19 changes: 10 additions & 9 deletions src/types/migration/ContentRelationship.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { FilledContentRelationshipField } from "../value/contentRelationship"
import type {
ContentRelationshipField,
FilledContentRelationshipField,
} from "../value/contentRelationship"
import type { PrismicDocument } from "../value/document"
import type { EmptyLinkField } from "../value/link"

import type { PrismicMigrationDocument } from "./Document"

Expand All @@ -13,17 +15,16 @@ export type MigrationContentRelationship<
TDocuments extends PrismicDocument = PrismicDocument,
> =
| ValueOrThunk<TDocuments | PrismicMigrationDocument<TDocuments> | undefined>
| (Pick<FilledContentRelationshipField, "link_type"> &
Partial<Pick<FilledContentRelationshipField, "text">> & {
id: ValueOrThunk<
TDocuments | PrismicMigrationDocument<TDocuments> | undefined
>
})
| (Pick<ContentRelationshipField, "link_type"> & {
id: ValueOrThunk<
TDocuments | PrismicMigrationDocument<TDocuments> | undefined
>
})

/**
* The minimum amount of information needed to represent a content relationship
* field with the migration API.
*/
export type MigrationContentRelationshipField =
| Pick<FilledContentRelationshipField, "link_type" | "id">
| EmptyLinkField<"Document">
| ContentRelationshipField<string, string, unknown, "empty">
1 change: 0 additions & 1 deletion src/types/model/contentRelationship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ export interface CustomTypeModelContentRelationshipField<
select: typeof CustomTypeModelLinkSelectType.Document
customtypes?: readonly CustomTypeIDs[]
tags?: readonly Tags[]
allowText?: boolean
}
}
1 change: 1 addition & 0 deletions src/types/model/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface CustomTypeModelLinkField {
allowText?: boolean
allowTargetBlank?: boolean
repeat?: boolean
variants?: string[]
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/types/value/contentRelationship.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { AnyRegularField, FieldState } from "./types"

import type { GroupField } from "./group"
import type { EmptyLinkField, LinkType } from "./link"
import type { SliceZone } from "./sliceZone"

/**
Expand All @@ -21,9 +20,13 @@ export type ContentRelationshipField<
| unknown = unknown,
State extends FieldState = FieldState,
> = State extends "empty"
? EmptyLinkField<typeof LinkType.Document>
? EmptyContentRelationshipField
: FilledContentRelationshipField<TypeEnum, LangEnum, DataInterface>

type EmptyContentRelationshipField = {
link_type: "Any"
}

/**
* Links that refer to documents
*/
Expand All @@ -34,7 +37,7 @@ export interface FilledContentRelationshipField<
| Record<string, AnyRegularField | GroupField | SliceZone>
| unknown = unknown,
> {
link_type: typeof LinkType.Document
link_type: "Document"
id: string
uid?: string
type: TypeEnum
Expand All @@ -44,5 +47,4 @@ export interface FilledContentRelationshipField<
slug?: string
isBroken?: boolean
data?: DataInterface
text?: string
}
77 changes: 46 additions & 31 deletions src/types/value/link.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { AnyRegularField, FieldState } from "./types"

import type { ContentRelationshipField } from "./contentRelationship"
import type { FilledContentRelationshipField } from "./contentRelationship"
import type { GroupField } from "./group"
import type { LinkToMediaField } from "./linkToMedia"
import type { FilledLinkToMediaField } from "./linkToMedia"
import type { SliceZone } from "./sliceZone"

/**
Expand All @@ -15,35 +15,13 @@ export const LinkType = {
Web: "Web",
} as const

/**
* For link fields that haven't been filled
*
* @typeParam Type - The type of link.
*/
export type EmptyLinkField<
Type extends (typeof LinkType)[keyof typeof LinkType] = typeof LinkType.Any,
> = {
link_type: Type | string
text?: string
}

/**
* Link that points to external website
*/
export interface FilledLinkToWebField {
link_type: typeof LinkType.Web
url: string
target?: string
text?: string
}

/**
* A link field.
*
* @typeParam TypeEnum - Type API ID of the document.
* @typeParam LangEnum - Language API ID of the document.
* @typeParam DataInterface - Data fields for the document (filled in via
* GraphQuery of `fetchLinks`).
* @typeParam DataInterface - Data fields for the document (filled via the
* `fetchLinks` or `graphQuery` query parameter).
* @typeParam State - State of the field which determines its shape.
*/
export type LinkField<
Expand All @@ -53,9 +31,46 @@ export type LinkField<
| Record<string, AnyRegularField | GroupField | SliceZone>
| unknown = unknown,
State extends FieldState = FieldState,
> = State extends "empty"
? EmptyLinkField<typeof LinkType.Any>
> = (State extends "empty"
? EmptyLinkField
:
| ContentRelationshipField<TypeEnum, LangEnum, DataInterface, State>
| FilledLinkToWebField
| LinkToMediaField<State>
| FilledContentRelationshipField<TypeEnum, LangEnum, DataInterface>
| FilledLinkToMediaField
| FilledLinkToWebField) &
OptionalLinkProperties

/**
* A link field that is not filled.
*
* @typeParam _Unused - THIS PARAMETER IS NOT USED. If you are passing a type,
* **please remove it**.
*/
// This type needs `OptionalLinkProperties` because this type may be used on its own.
export type EmptyLinkField<
_Unused extends
(typeof LinkType)[keyof typeof LinkType] = typeof LinkType.Any,
> = {
link_type: "Any"
} & OptionalLinkProperties

/**
* A link field pointing to a relative or absolute URL.
*/
// This type needs `OptionalLinkProperties` because this type may be used on its own.
export type FilledLinkToWebField = {
link_type: "Web"
url: string
target?: string
} & OptionalLinkProperties

/**
* Optional properties available to link fields. It is used to augment existing
* link-like fields (like content relationship fields) with field-specific
* properties.
*
* @internal
*/
export type OptionalLinkProperties = {
variant?: string
text?: string
}
13 changes: 7 additions & 6 deletions src/types/value/linkToMedia.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import type { FieldState } from "./types"

import type { EmptyLinkField, LinkType } from "./link"

/**
* A link field that points to media.
*
* @typeParam State - State of the field which determines its shape.
*/
export type LinkToMediaField<State extends FieldState = FieldState> =
State extends "empty"
? EmptyLinkField<typeof LinkType.Media>
: FilledLinkToMediaField
State extends "empty" ? EmptyLinkToMediaField : FilledLinkToMediaField

type EmptyLinkToMediaField = {
link_type: "Any"
text?: string
}

/**
* A link that points to media.
*/
export interface FilledLinkToMediaField {
id: string
link_type: typeof LinkType.Media
link_type: "Media"
name: string
kind: string
url: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ exports[`patches content relationship fields > lazyOtherCreateMissingID > group
"group": [
{
"field": {
"link_type": "Document",
"link_type": "Any",
},
},
],
Expand All @@ -713,18 +713,18 @@ exports[`patches content relationship fields > lazyOtherCreateMissingID > shared
"items": [
{
"field": {
"link_type": "Document",
"link_type": "Any",
},
},
],
"primary": {
"field": {
"link_type": "Document",
"link_type": "Any",
},
"group": [
{
"field": {
"link_type": "Document",
"link_type": "Any",
},
},
],
Expand All @@ -746,13 +746,13 @@ exports[`patches content relationship fields > lazyOtherCreateMissingID > slice
"items": [
{
"field": {
"link_type": "Document",
"link_type": "Any",
},
},
],
"primary": {
"field": {
"link_type": "Document",
"link_type": "Any",
},
},
"slice_label": "Vel",
Expand All @@ -765,7 +765,7 @@ exports[`patches content relationship fields > lazyOtherCreateMissingID > slice
exports[`patches content relationship fields > lazyOtherCreateMissingID > static zone 1`] = `
{
"field": {
"link_type": "Document",
"link_type": "Any",
},
}
`;
Expand Down
Loading
Loading