From c7326037edbe26b53e51306e3c93ae6c43776934 Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Wed, 20 Jul 2022 15:04:32 -0500 Subject: [PATCH] Tag values with their types to prevent clobbering Stringifying isn't good enough, because then a string and a number with the same string value would be considered equal. Also, stringifying Dates loses precision, so for those we need to use their internal values. --- src/components/selectMultiple.ts | 19 ++++++++++++++++--- src/components/selectSingle.ts | 20 +++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/components/selectMultiple.ts b/src/components/selectMultiple.ts index e2ee50b..84d2c7f 100644 --- a/src/components/selectMultiple.ts +++ b/src/components/selectMultiple.ts @@ -36,19 +36,30 @@ export default function selectMultiple(logger: Logger) { } } + function getComparisonValue(value: z.infer) { + if (value instanceof Date) { + return `date:${value.valueOf()}` + } + + return `${typeof value}:${value}` + } + const normalizedOptions: z.infer[] = props.options.map( option => normalizeOption(option) ) type Options = typeof props.options const optionMap = new Map( - normalizedOptions.map((o, i) => [o.value.toString(), props.options[i]]) + normalizedOptions.map((o, i) => [ + getComparisonValue(o.value), + props.options[i], + ]) ) let defaultValue = props.defaultValue?.map(d => normalizeOption(d)) if ( defaultValue && - defaultValue.every(val => !optionMap.has(val.value.toString())) + defaultValue.every(val => !optionMap.has(getComparisonValue(val.value))) ) { logger.warn( 'The defaultValue property must be a subset of the provided options, the provided defaultValue will be discarded.' @@ -65,7 +76,9 @@ export default function selectMultiple(logger: Logger) { options: normalizedOptions.map(o => stripper.parse(o)), }, getValue(response: T_IO_RETURNS<'SELECT_MULTIPLE'>): Options { - return response.map(r => optionMap.get(r.value.toString())) as Options + return response.map(r => + optionMap.get(getComparisonValue(r.value)) + ) as Options }, } } diff --git a/src/components/selectSingle.ts b/src/components/selectSingle.ts index ddcc72a..cfbe4c4 100644 --- a/src/components/selectSingle.ts +++ b/src/components/selectSingle.ts @@ -40,13 +40,24 @@ export default function selectSingle(logger: Logger) { } } + function getComparisonValue(value: z.infer) { + if (value instanceof Date) { + return `date:${value.valueOf()}` + } + + return `${typeof value}:${value}` + } + const normalizedOptions = props.options.map(option => normalizeOption(option) ) type Options = typeof props.options const optionMap = new Map( - normalizedOptions.map((o, i) => [o.value.toString(), props.options[i]]) + normalizedOptions.map((o, i) => [ + getComparisonValue(o.value), + props.options[i], + ]) ) const stripper = richSelectOption.strip() @@ -54,7 +65,10 @@ export default function selectSingle(logger: Logger) { ? normalizeOption(props.defaultValue) : undefined - if (defaultValue && !optionMap.has(defaultValue.value.toString())) { + if ( + defaultValue && + !optionMap.has(getComparisonValue(defaultValue.value)) + ) { logger.warn( 'The defaultValue property must be a value in the provided options, the provided defaultValue will be discarded.' ) @@ -68,7 +82,7 @@ export default function selectSingle(logger: Logger) { options: normalizedOptions.map(o => stripper.parse(o)), }, getValue(response: T_IO_RETURNS<'SELECT_SINGLE'>) { - return optionMap.get(response.value.toString()) as Options[0] + return optionMap.get(getComparisonValue(response.value)) as Options[0] }, } }