mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 22:46:27 +00:00
feat(schema): Add looseValue
and looseObject
helpers (#20576)
This commit is contained in:
parent
340a913a48
commit
edef60045c
3 changed files with 84 additions and 20 deletions
|
@ -1,6 +1,7 @@
|
||||||
import is from '@sindresorhus/is';
|
import is from '@sindresorhus/is';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { logger } from '../../../logger';
|
import { logger } from '../../../logger';
|
||||||
|
import { looseObject, looseValue } from '../../../util/schema';
|
||||||
import type { Release, ReleaseResult } from '../types';
|
import type { Release, ReleaseResult } from '../types';
|
||||||
|
|
||||||
export const MinifiedArray = z.array(z.record(z.unknown())).transform((xs) => {
|
export const MinifiedArray = z.array(z.record(z.unknown())).transform((xs) => {
|
||||||
|
@ -44,32 +45,20 @@ export const ComposerRelease = z
|
||||||
version: z.string(),
|
version: z.string(),
|
||||||
})
|
})
|
||||||
.merge(
|
.merge(
|
||||||
z
|
looseObject({
|
||||||
.object({
|
homepage: z.string(),
|
||||||
homepage: z.string().nullable().catch(null),
|
source: z.object({ url: z.string() }),
|
||||||
source: z
|
time: z.string(),
|
||||||
.object({
|
require: z.object({ php: z.string() }),
|
||||||
url: z.string(),
|
})
|
||||||
})
|
|
||||||
.nullable()
|
|
||||||
.catch(null),
|
|
||||||
time: z.string().nullable().catch(null),
|
|
||||||
require: z
|
|
||||||
.object({
|
|
||||||
php: z.string(),
|
|
||||||
})
|
|
||||||
.nullable()
|
|
||||||
.catch(null),
|
|
||||||
})
|
|
||||||
.partial()
|
|
||||||
);
|
);
|
||||||
export type ComposerRelease = z.infer<typeof ComposerRelease>;
|
export type ComposerRelease = z.infer<typeof ComposerRelease>;
|
||||||
|
|
||||||
export const ComposerReleases = z
|
export const ComposerReleases = z
|
||||||
.union([
|
.union([
|
||||||
z.array(ComposerRelease.nullable().catch(null)),
|
z.array(looseValue(ComposerRelease)),
|
||||||
z
|
z
|
||||||
.record(ComposerRelease.nullable().catch(null))
|
.record(looseValue(ComposerRelease))
|
||||||
.transform((map) => Object.values(map)),
|
.transform((map) => Object.values(map)),
|
||||||
])
|
])
|
||||||
.catch([])
|
.catch([])
|
||||||
|
|
|
@ -151,4 +151,50 @@ describe('util/schema', () => {
|
||||||
expect(called).toBeTrue();
|
expect(called).toBeTrue();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('looseValue', () => {
|
||||||
|
it('parses value', () => {
|
||||||
|
const s = schema.looseValue(z.string());
|
||||||
|
expect(s.parse('foobar')).toBe('foobar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to null wrong value', () => {
|
||||||
|
const s = schema.looseValue(z.string());
|
||||||
|
expect(s.parse(123)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs callback for wrong elements', () => {
|
||||||
|
let called = false;
|
||||||
|
const s = schema.looseValue(z.string(), () => {
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
expect(s.parse(123)).toBeNull();
|
||||||
|
expect(called).toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('looseObject', () => {
|
||||||
|
it('parses object', () => {
|
||||||
|
const s = schema.looseObject({
|
||||||
|
foo: z.string(),
|
||||||
|
bar: z.number(),
|
||||||
|
});
|
||||||
|
expect(s.parse({ foo: 'foo', bar: 123 })).toEqual({
|
||||||
|
foo: 'foo',
|
||||||
|
bar: 123,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('drops wrong items', () => {
|
||||||
|
const s = schema.looseObject({
|
||||||
|
foo: z.string(),
|
||||||
|
bar: z.number(),
|
||||||
|
baz: z.string(),
|
||||||
|
});
|
||||||
|
expect(s.parse({ foo: 'foo', bar: 'bar' })).toEqual({
|
||||||
|
foo: 'foo',
|
||||||
|
bar: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -143,3 +143,32 @@ export function looseRecord<T extends z.ZodTypeAny>(
|
||||||
|
|
||||||
return filteredRecord;
|
return filteredRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function looseValue<T, U extends z.ZodTypeDef, V>(
|
||||||
|
schema: z.ZodType<T, U, V>,
|
||||||
|
catchCallback?: () => void
|
||||||
|
): z.ZodCatch<z.ZodNullable<z.ZodType<T, U, V>>> {
|
||||||
|
const nullableSchema = schema.nullable();
|
||||||
|
const schemaWithFallback = catchCallback
|
||||||
|
? nullableSchema.catch(() => {
|
||||||
|
catchCallback();
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
: nullableSchema.catch(null);
|
||||||
|
return schemaWithFallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function looseObject<T extends z.ZodRawShape>(
|
||||||
|
shape: T
|
||||||
|
): z.ZodObject<{
|
||||||
|
[k in keyof T]: z.ZodOptional<z.ZodCatch<z.ZodNullable<T[k]>>>;
|
||||||
|
}> {
|
||||||
|
const newShape: Record<keyof T, z.ZodTypeAny> = { ...shape };
|
||||||
|
const keys: (keyof T)[] = Object.keys(shape);
|
||||||
|
for (const k of keys) {
|
||||||
|
const v = looseValue(shape[k]);
|
||||||
|
newShape[k] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return z.object(newShape).partial() as never;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue