Files
Sebastian Poxhofer 15f4bd8eff chore: migrate from zod/v3 to zod/v4 (#43691)
* chore: migrate from zod/v3 to zod/v4

This commit contains the logic changes

* chore: migrate imports from zod/v3 to zod/v4

This contains import updates and adds explicit record keys as zod/v4 requires these now

* ci: enforce usage of zod/v4
2026-05-30 16:01:58 +00:00

67 lines
1.9 KiB
TypeScript

import { isObject, isString } from '@sindresorhus/is';
import { z } from 'zod/v4';
const DockerComposeService = z.object({
image: z.string().optional(),
build: z
.union([
z.string(),
z.object({
context: z.string().optional(),
dockerfile: z.string().optional(),
}),
])
.optional(),
});
const DockerComposeFileV1 = z.record(z.string(), DockerComposeService);
const DockerComposeFileModern = z
.object({
/**
* compose does not use this strictly, so we shouldn't be either
* https://docs.docker.com/compose/compose-file/04-version-and-name/#version-top-level-element
*/
version: z.string().optional(),
services: z.record(z.string(), DockerComposeService),
})
// using catchall to capture fields starting with `x-` and collecting them in `extensions` field
// might need to replace this with something better once zod v4 is stable
.catchall(z.unknown())
.transform(
(
obj,
): {
version?: string;
services: Record<string, z.infer<typeof DockerComposeService>>;
extensions?: Record<string, { image: string }>;
} => {
const { version, services, ...rest } = obj;
let extensions: Record<string, { image: string }> | undefined;
// collect extensions which have image field
// https://docs.docker.com/reference/compose-file/extensions/
for (const key in rest) {
if (key.startsWith('x-')) {
const value = rest[key];
if (isObject(value) && 'image' in value && isString(value.image)) {
extensions ??= {};
extensions[key] = { image: value.image };
}
}
}
return {
version,
services,
...(extensions && { extensions }),
};
},
);
export const DockerComposeFile = z.union([
DockerComposeFileModern,
DockerComposeFileV1,
]);
export type DockerComposeFile = z.infer<typeof DockerComposeFile>;