Skip to content

Commit

Permalink
Explicitly set additionalProperties for .passthrough() (#405)
Browse files Browse the repository at this point in the history
  • Loading branch information
samchungy authored Jan 23, 2025
1 parent 46e7250 commit 795cae8
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 8 deletions.
29 changes: 29 additions & 0 deletions src/create/schema/parsers/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,35 @@ describe('createObjectSchema', () => {
expect(result).toEqual(expected);
});

it('supports passthrough', () => {
const expected: Schema = {
type: 'schema',
schema: {
type: 'object',
properties: {
a: {
type: 'string',
},
},
required: ['a'],
additionalProperties: true,
},
};
const schema = z
.object({
a: z.string(),
})
.passthrough();

const result = createObjectSchema(
schema,
undefined,
createOutputState(undefined),
);

expect(result).toEqual(expected);
});

it('supports catchall', () => {
const expected: Schema = {
type: 'schema',
Expand Down
36 changes: 29 additions & 7 deletions src/create/schema/parsers/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,25 @@ interface AdditionalPropertyOptions {
catchAll: ZodType;
}

const mapAdditionalProperties = (
{ unknownKeys, catchAll }: AdditionalPropertyOptions,
state: SchemaState,
) => {
if (!isZodType(catchAll, 'ZodNever')) {
return createSchemaObject(catchAll, state, ['additional properties']);
}

if (unknownKeys === 'strict') {
return false;
}

if (unknownKeys === 'passthrough') {
return true;
}

return undefined;
};

export const createObjectSchemaFromShape = (
shape: ZodRawShape,
{ unknownKeys, catchAll }: AdditionalPropertyOptions,
Expand All @@ -245,24 +264,27 @@ export const createObjectSchemaFromShape = (
): Schema => {
const properties = mapProperties(shape, state);
const required = mapRequired(properties, shape, state);
const additionalProperties = !isZodType(catchAll, 'ZodNever')
? createSchemaObject(catchAll, state, ['additional properties'])
: undefined;
const additionalProperties = mapAdditionalProperties(
{ catchAll, unknownKeys },
state,
);

return {
type: 'schema',
schema: {
...(!omitType && { type: 'object' }),
...(properties && { properties: properties.properties }),
...(required?.required.length && { required: required.required }),
...(unknownKeys === 'strict' && { additionalProperties: false }),
...(additionalProperties && {
additionalProperties: additionalProperties.schema,
...(additionalProperties !== undefined && {
additionalProperties:
typeof additionalProperties === 'object'
? additionalProperties.schema
: additionalProperties,
}),
},
effects: flattenEffects([
...(properties?.effects ?? []),
additionalProperties?.effects,
typeof additionalProperties === 'object' && additionalProperties?.effects,
required?.effects,
]),
};
Expand Down
4 changes: 3 additions & 1 deletion src/create/schema/parsers/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ export const verifyEffects = (effects: Effect[], state: SchemaState) => {
}
};

export const flattenEffects = (effects: Array<Effect[] | undefined>) => {
export const flattenEffects = (
effects: Array<Effect[] | undefined | false>,
) => {
const allEffects = effects.reduce<Effect[]>((acc, effect) => {
if (effect) {
return acc.concat(effect);
Expand Down

0 comments on commit 795cae8

Please sign in to comment.