Skip to content

Commit

Permalink
feat(type): support mixed case enum member in union resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
marcj committed May 4, 2024
1 parent ce0166e commit 96dd2d8
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 12 deletions.
16 changes: 16 additions & 0 deletions packages/type/src/reflection/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2332,6 +2332,22 @@ export function getDeepConstructorProperties(type: TypeClass): TypeParameter[] {
return res;
}

/**
* Returns the index to `type.values` if the given value is part of the enum, exactly or case-insensitive.
* Returns -1 if not found.
*/
export function getEnumValueIndexMatcher(type: TypeEnum): (value: string | number | undefined | null) => number {
const lowerCaseValues = Object.keys(type.enum).map(v => String(v).toLowerCase());
return (value): number => {
const exactMatch = type.values.indexOf(value);
if (exactMatch !== -1) return exactMatch;
const lowerCaseMatch = lowerCaseValues.indexOf(String(value).toLowerCase());
if (lowerCaseMatch !== -1) return lowerCaseMatch;

return -1;
};
}

interface StringifyTypeOptions {
//show type alias names
showNames: boolean;
Expand Down
18 changes: 6 additions & 12 deletions packages/type/src/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
FindType,
getConstructorProperties,
getDeepConstructorProperties,
getEnumValueIndexMatcher,
getTypeJitContainer,
getTypeObjectLiteralFromTypeClass,
groupAnnotation,
Expand Down Expand Up @@ -1977,17 +1978,10 @@ export class Serializer {
this.serializeRegistry.register(ReflectionKind.enum, (type, state) => state.addSetter(state.accessor));
this.deserializeRegistry.register(ReflectionKind.enum, (type, state) => {
const valuesVar = state.setVariable('values', type.values);
const lowercaseNames = state.setVariable('lowercaseNames', Object.keys(type.enum).map(v => v.toLowerCase()));
const allLowercased = Object.keys(type.enum).every(v => v.toLowerCase() === v);
const enumValues = state.setVariable('enumValues', type.values);
const allowLowercase = allLowercased ? '' : `
${state.accessor} = ${enumValues}[${lowercaseNames}.indexOf(String(${state.accessor}).toLowerCase())] ?? ${state.accessor};
`;

const matcher = state.setVariable('enumMatcher', getEnumValueIndexMatcher(type));
state.addCodeForSetter(`
${allowLowercase}
${state.setter} = ${state.accessor};
if (${valuesVar}.indexOf(${state.accessor}) === -1) ${state.throwCode('enum', `'No valid value of ' + ${valuesVar}.join(', ')`)}
${state.setter} = ${valuesVar}[${matcher}(${state.accessor})];
if (${valuesVar}.indexOf(${state.setter}) === -1) ${state.throwCode('enum', `'No valid value of ' + ${valuesVar}.join(', ')`)}
`);
});

Expand Down Expand Up @@ -2219,8 +2213,8 @@ export class Serializer {

this.typeGuards.register(1, ReflectionKind.promise, (type, state) => executeTemplates(state, type.type));
this.typeGuards.register(1, ReflectionKind.enum, (type, state) => {
const values = state.setVariable('values', type.values);
state.addSetterAndReportErrorIfInvalid('type', 'Invalid enum member', `${values}.indexOf(${state.accessor}) >= 0`);
const matcher = state.setVariable('enumMatcher', getEnumValueIndexMatcher(type));
state.addSetterAndReportErrorIfInvalid('type', 'Invalid enum member', `${matcher}(${state.accessor}) >= 0`);
});
this.typeGuards.register(1, ReflectionKind.array, (type, state) => typeGuardArray(type.type, state));
this.typeGuards.register(1, ReflectionKind.tuple, typeGuardTuple);
Expand Down
4 changes: 4 additions & 0 deletions packages/type/tests/serializer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,10 @@ test('enum mixed case', () => {

expect(cast<Units>('gram')).toBe('g');
expect(cast<Units>('gram')).toBe(Units.GRAM);

expect(cast<number | Units>('GRAM')).toBe(Units.GRAM);
expect(cast<number | Units>(23)).toBe(23);
expect(cast<number | Units>('Gram')).toBe(Units.GRAM);
});

test('enum union', () => {
Expand Down

0 comments on commit 96dd2d8

Please sign in to comment.