Skip to content

Commit 3d33ccc

Browse files
committed
refactor: add interpret Zod object and value methods to z3 namespace
1 parent 48ed71b commit 3d33ccc

1 file changed

Lines changed: 215 additions & 11 deletions

File tree

apps/web/src/utils/upload2.ts

Lines changed: 215 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-namespace */
2-
import { isObjectLike, isPlainObject, isZodType } from '@douglasneuroinformatics/libjs';
2+
import { isNumberLike, isObjectLike, isPlainObject, isZodType, parseNumber } from '@douglasneuroinformatics/libjs';
33
import type { Language } from '@douglasneuroinformatics/libui/i18n';
44
import type { AnyUnilingualFormInstrument, FormTypes } from '@opendatacapture/runtime-core';
55
import { parse, unparse } from 'papaparse';
@@ -62,6 +62,27 @@ function getTemplateFilename(instrumentInternal: AnyUnilingualFormInstrument['in
6262
return `${instrumentInternal.name}_${instrumentInternal.edition}_template.csv`;
6363
}
6464

65+
//functions to extract set and record array strings into values
66+
export function extractSetEntry(entry: string) {
67+
const result = /SET\(\s*(.*?)\s*\)/.exec(entry);
68+
if (!result?.[1]) {
69+
throw new Error(
70+
`Failed to extract set value from entry: '${entry}' / Échec de l'extraction de la valeur de l'ensemble de l'entrée : '${entry}'`
71+
);
72+
}
73+
return result[1];
74+
}
75+
76+
export function extractRecordArrayEntry(entry: string) {
77+
const result = /RECORD_ARRAY\(\s*(.*?)[\s;]*\)/.exec(entry);
78+
if (!result?.[1]) {
79+
throw new Error(
80+
`Failed to extract record array value from entry: '${entry}' / Échec de l'extraction de la valeur du tableau d'enregistrements de l'entrée : '${entry}'`
81+
);
82+
}
83+
return result[1];
84+
}
85+
6586
namespace Zod3 {
6687
type ZodTypeName = Extract<`${z3.ZodFirstPartyTypeKind}`, (typeof ZOD_TYPE_NAMES)[number]>;
6788

@@ -407,16 +428,16 @@ namespace Zod3 {
407428
} else {
408429
interpreterResult = interpretZodValue(rawValue, typeNameResult.typeName, typeNameResult.isOptional);
409430
}
410-
if (!interpreterResult.success) {
411-
return resolve({
412-
message: {
413-
en: `${interpreterResult.message.en} at column name: '${key}' and row number ${rowNumber}`,
414-
fr: `${interpreterResult.message.fr} au nom de colonne : '${key}' et numéro de ligne ${rowNumber}`
415-
},
416-
success: false
417-
});
418-
}
419-
jsonLine[headers[j]!] = interpreterResult.value;
431+
// if (!interpreterResult.success) {
432+
// return resolve({
433+
// message: {
434+
// en: `${interpreterResult.message.en} at column name: '${key}' and row number ${rowNumber}`,
435+
// fr: `${interpreterResult.message.fr} au nom de colonne : '${key}' et numéro de ligne ${rowNumber}`
436+
// },
437+
// success: false
438+
// });
439+
// }
440+
if (interpreterResult.success) jsonLine[headers[j]!] = interpreterResult!.value;
420441
} catch (error: unknown) {
421442
if (error instanceof UploadError) {
422443
return resolve({
@@ -456,6 +477,189 @@ namespace Zod3 {
456477
reader.readAsText(input);
457478
});
458479
}
480+
481+
//insert zodObjectValue function
482+
export function interpretZodObjectValue(
483+
entry: string,
484+
isOptional: boolean,
485+
zList: ZodTypeNameResult[],
486+
zKeys: string[]
487+
): UploadOperationResult<FormTypes.FieldValue> {
488+
try {
489+
if (entry === '' && isOptional) {
490+
return { success: true, value: undefined };
491+
} else if (!entry.startsWith('RECORD_ARRAY(')) {
492+
return { message: { en: `Invalid ZodType`, fr: `ZodType invalide` }, success: false };
493+
}
494+
495+
const recordArray: { [key: string]: any }[] = [];
496+
const recordArrayDataEntry = extractRecordArrayEntry(entry);
497+
const recordArrayDataList = recordArrayDataEntry.split(';');
498+
499+
if (recordArrayDataList.at(-1) === '') {
500+
recordArrayDataList.pop();
501+
}
502+
503+
for (const listData of recordArrayDataList) {
504+
const recordArrayObject: { [key: string]: any } = {};
505+
506+
const record = listData.split(',');
507+
508+
if (!record) {
509+
return {
510+
message: {
511+
en: `Record in the record array was left undefined`,
512+
fr: `L'enregistrement dans le tableau d'enregistrements n'est pas défini`
513+
},
514+
success: false
515+
};
516+
}
517+
if (record.some((str) => str === '')) {
518+
return {
519+
message: {
520+
en: `One or more of the record array fields was left empty`,
521+
fr: `Un ou plusieurs champs du tableau d'enregistrements ont été laissés vides`
522+
},
523+
success: false
524+
};
525+
}
526+
if (!(zList.length === zKeys.length && zList.length === record.length)) {
527+
return {
528+
message: {
529+
en: `Incorrect number of entries for record array`,
530+
fr: `Nombre incorrect d'entrées pour le tableau d'enregistrements`
531+
},
532+
success: false
533+
};
534+
}
535+
for (let i = 0; i < record.length; i++) {
536+
if (!record[i]) {
537+
return {
538+
message: { en: `Failed to interpret field '${i}'`, fr: `Échec de l'interprétation du champ '${i}'` },
539+
success: false
540+
};
541+
}
542+
543+
const recordValue = record[i]!.split(':')[1]!.trim();
544+
545+
const zListResult = zList[i]!;
546+
if (!(zListResult.success && zListResult.typeName !== 'ZodArray' && zListResult.typeName !== 'ZodObject')) {
547+
return {
548+
message: { en: `Failed to interpret field '${i}'`, fr: `Échec de l'interprétation du champ '${i}'` },
549+
success: false
550+
};
551+
}
552+
const interpretZodValueResult: UploadOperationResult<FormTypes.FieldValue> = interpretZodValue(
553+
recordValue,
554+
zListResult.typeName,
555+
zListResult.isOptional
556+
);
557+
if (!interpretZodValueResult.success) {
558+
return {
559+
message: {
560+
en: `failed to interpret value at entry ${i} in record array row ${listData}`,
561+
fr: `échec de l'interprétation de la valeur à l'entrée ${i} dans la ligne de tableau d'enregistrements ${listData}`
562+
},
563+
success: false
564+
};
565+
}
566+
567+
recordArrayObject[zKeys[i]!] = interpretZodValueResult.value;
568+
}
569+
recordArray.push(recordArrayObject);
570+
}
571+
572+
return { success: true, value: recordArray };
573+
} catch {
574+
return {
575+
message: {
576+
en: `failed to interpret record array entries`,
577+
fr: `échec de l'interprétation des entrées du tableau d'enregistrements`
578+
},
579+
success: false
580+
};
581+
}
582+
}
583+
584+
//insert interpretZodValue Function
585+
export function interpretZodValue(
586+
entry: string,
587+
zType: Exclude<ZodTypeName, 'ZodArray' | 'ZodEffects' | 'ZodObject' | 'ZodOptional'>,
588+
isOptional: boolean
589+
): UploadOperationResult<FormTypes.FieldValue> {
590+
if (entry === '' && isOptional) {
591+
return { success: true, value: undefined };
592+
}
593+
switch (zType) {
594+
case 'ZodBoolean':
595+
if (entry.toLowerCase() === 'true') {
596+
return { success: true, value: true };
597+
} else if (entry.toLowerCase() === 'false') {
598+
return { success: true, value: false };
599+
}
600+
return {
601+
message: { en: `Undecipherable Boolean Type: '${entry}'`, fr: `Type booléen indéchiffrable : '${entry}'` },
602+
success: false
603+
};
604+
case 'ZodDate': {
605+
const date = new Date(entry);
606+
if (Number.isNaN(date.getTime())) {
607+
return {
608+
message: { en: `Failed to parse date: '${entry}'`, fr: `Échec de l'analyse de la date : '${entry}'` },
609+
success: false
610+
};
611+
}
612+
return { success: true, value: date };
613+
}
614+
case 'ZodEnum':
615+
return interpretZodValue(entry, 'ZodString', isOptional);
616+
case 'ZodNumber':
617+
if (isNumberLike(entry)) {
618+
return { success: true, value: parseNumber(entry) };
619+
}
620+
return {
621+
message: { en: `Invalid number type: '${entry}'`, fr: `Type de nombre invalide : '${entry}'` },
622+
success: false
623+
};
624+
case 'ZodSet':
625+
try {
626+
if (entry.startsWith('SET(')) {
627+
const setData = extractSetEntry(entry);
628+
const values = setData
629+
.split(',')
630+
.map((s) => s.trim())
631+
.filter(Boolean);
632+
if (values.length === 0) {
633+
return {
634+
message: { en: 'Empty set is not allowed', fr: "Un ensemble vide n'est pas autorisé" },
635+
success: false
636+
};
637+
}
638+
return { success: true, value: new Set(values) };
639+
}
640+
} catch {
641+
return {
642+
message: {
643+
en: 'Error occurred interpreting set entry',
644+
fr: "Une erreur s'est produite lors de l'interprétation de l'entrée de l'ensemble"
645+
},
646+
success: false
647+
};
648+
}
649+
650+
return { message: { en: `Invalid ZodSet: '${entry}'`, fr: `ZodSet invalide : '${entry}'` }, success: false };
651+
case 'ZodString':
652+
return { success: true, value: entry };
653+
default:
654+
return {
655+
message: {
656+
en: `Invalid ZodType: ${zType satisfies never}`,
657+
fr: `ZodType invalide : ${zType satisfies never}`
658+
},
659+
success: false
660+
};
661+
}
662+
}
459663
}
460664

461665
namespace Zod4 {

0 commit comments

Comments
 (0)