Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
47 changes: 44 additions & 3 deletions src/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/

import { BaseSerializer } from '@adonisjs/core/transformers'
import { BaseSerializer, Collection, Item, Paginator } from '@adonisjs/core/transformers'
import { type AsyncOrSync } from '@adonisjs/core/types/common'
import { type JSONDataTypes } from '@adonisjs/core/types/transformers'

Expand Down Expand Up @@ -315,6 +315,13 @@ export function isOptionalProp<T extends UnPackedPageProps>(
return OPTIONAL_PROP in propValue
}

/**
* Checks if a value is a transformer instance (Item, Collection, or Paginator).
*/
function isTransformerInstance(value: unknown): boolean {
return value instanceof Item || value instanceof Collection || value instanceof Paginator
}

/**
* Helper function to unpack prop values using the transformer serialize function.
*
Expand All @@ -325,8 +332,20 @@ export function isOptionalProp<T extends UnPackedPageProps>(
async function unpackPropValue(
value: UnPackedPageProps<JSONDataTypes>,
containerResolver: ContainerResolver<any>
) {
return inertiaSerializer.serialize(value, containerResolver) as Promise<JSONDataTypes>
): Promise<JSONDataTypes> {
if (isTransformerInstance(value)) {
return inertiaSerializer.serialize(value, containerResolver) as Promise<JSONDataTypes>
}

if (Array.isArray(value)) {
return Promise.all(value.map((item) => unpackPropValue(item, containerResolver)))
}

if (isObject(value)) {
return inertiaSerializer.serialize(value, containerResolver) as Promise<JSONDataTypes>
}

return value
}

/**
Expand Down Expand Up @@ -432,6 +451,15 @@ export async function buildStandardVisitProps(
key,
value: value,
})
} else if (Array.isArray(value)) {
/**
* Arrays may contain nested transformer instances
* that need to be resolved
*/
unpackedValues.push({
key,
value: value,
})
} else {
/**
* Compute lazy value
Expand Down Expand Up @@ -569,6 +597,19 @@ export async function buildPartialRequestProps(
* Unpack all other values
*/
unpackedValues.push({ key, value: value as UnPackedPageProps })
} else if (Array.isArray(value)) {
/**
* Skip key if not part of cherry picking list
*/
if (!cherryPickProps.includes(key)) {
continue
}

/**
* Arrays may contain nested transformer instances
* that need to be resolved
*/
unpackedValues.push({ key, value: value as UnPackedPageProps })
} else {
/**
* Skip key if not part of cherry picking list
Expand Down
89 changes: 89 additions & 0 deletions tests/inertia_page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,95 @@
`)
})

test('build page with nested component props using transformers', async ({ assert }) => {
type Props = {
user: {
id: number
timestamps: boolean
}
groups: [
{
post: { id: number; title: string }
},
]
paginated: {
data: { id: number; title: string }[]
metadata: {
total: number
}
}
}

class PostsTransformer extends BaseTransformer<{ id: number; title: string }> {
toObject() {
return this.resource
}
}

class UserTransformer extends BaseTransformer<{ id: number; timestamps: boolean }> {
toObject() {
return this.resource
}
}

const inertia = new InertiaFactory<{
home: Props
}>().create()

const page = await inertia.page('home', {
user: UserTransformer.transform({
id: 1,
timestamps: true,
}),
groups: [
{
post: PostsTransformer.transform({ id: 1, title: 'Hello world' }),

Check failure on line 1121 in tests/inertia_page.spec.ts

View workflow job for this annotation

GitHub Actions / typecheck / typecheck (latest)

Type 'Item<PostsTransformer, 1, "toObject">' is missing the following properties from type '{ id: number; title: string; }': id, title
},
],
paginated: PostsTransformer.paginate([{ id: 1, title: 'Hello world' }], {
total: 10,
}),
})

assert.snapshot(page).matchInline(`
{
"clearHistory": false,
"component": "home",
"deepMergeProps": [],
"deferredProps": {},
"encryptHistory": false,
"mergeProps": [],
"props": {
"groups": [
{
"post": {
"id": 1,
"title": "Hello world",
},
},
],
"paginated": {
"data": [
{
"id": 1,
"title": "Hello world",
},
],
"metadata": {
"total": 10,
},
},
"user": {
"id": 1,
"timestamps": true,
},
},
"url": "",
"version": "1",
}
`)
})

test('partial reload props using transformers', async ({ assert }) => {
type Props = {
user: {
Expand Down
Loading