1 line
9.8 KiB
Text
1 line
9.8 KiB
Text
|
|
{"version":3,"file":"io-ts.modern.mjs","sources":["../src/arrayToPath.ts","../src/errorsToRecord.ts","../src/io-ts.ts"],"sourcesContent":["import * as Either from 'fp-ts/Either';\nimport { pipe } from 'fp-ts/function';\n\nconst arrayToPath = (paths: Either.Either<string, number>[]): string =>\n paths.reduce(\n (previous, path, index) =>\n pipe(\n path,\n Either.fold(\n (key) => `${index > 0 ? '.' : ''}${key}`,\n (key) => `[${key}]`,\n ),\n (path) => `${previous}${path}`,\n ),\n '',\n );\n\nexport default arrayToPath;\n","import * as Either from 'fp-ts/Either';\nimport * as Option from 'fp-ts/Option';\nimport * as ReadonlyArray from 'fp-ts/ReadonlyArray';\nimport * as ReadonlyRecord from 'fp-ts/ReadonlyRecord';\nimport * as SemiGroup from 'fp-ts/Semigroup';\nimport { absurd, flow, identity, not, pipe } from 'fp-ts/function';\nimport * as t from 'io-ts';\nimport {\n ExactType,\n IntersectionType,\n RefinementType,\n TaggedUnionType,\n UnionType,\n ValidationError,\n} from 'io-ts';\nimport { FieldError } from 'react-hook-form';\nimport arrayToPath from './arrayToPath';\n\nexport type ErrorObject = Record<string, FieldError>;\nexport type FieldErrorWithPath = FieldError & { path: string };\n\nconst INSTANCE_TYPES_TO_FILTER = [\n TaggedUnionType,\n UnionType,\n IntersectionType,\n ExactType,\n RefinementType,\n];\nconst formatErrorPath = (context: t.Context): string =>\n pipe(\n context,\n ReadonlyArray.filterMapWithIndex((index, contextEntry) => {\n const previousIndex = index - 1;\n const previousContextEntry =\n previousIndex === -1 ? undefined : context[previousIndex];\n const shouldBeFiltered =\n previousContextEntry === undefined ||\n INSTANCE_TYPES_TO_FILTER.some(\n (type) => previousContextEntry.type instanceof type,\n );\n\n return shouldBeFiltered ? Option.none : Option.some(contextEntry);\n }),\n ReadonlyArray.map(({ key }) => key),\n ReadonlyArray.map((key) =>\n pipe(\n key,\n (k) => parseInt(k, 10),\n Either.fromPredicate(not<number>(Number.isNaN), () => key),\n ),\n ),\n ReadonlyArray.toArray,\n arrayToPath,\n );\n\nconst formatError = (e: t.ValidationError): FieldErrorWithPath => {\n const path = formatErrorPath(e.context);\n\n const message = pipe(\n e.message,\n Either.fromNullable(e.context),\n Either.mapLeft(\n flow(\n ReadonlyArray.last,\n Option.map(\n (contextEntry) =>\n `expected ${contextEntry.type.name} but got ${JSON.stringify(\n contextEntry.actual,\n )}`,\n ),\n Option.getOrElseW(() =>\n absurd<string>('Error context is missing name' as never),\n ),\n ),\n ),\n Either.getOrElseW(identity),\n );\n\n const type = pipe(\n e.context,\n ReadonlyArray.last,\n Option.map((contextEntry) => contextEntry.type.name),\n Option.getOrElse(() => 'unknown'),\n );\n\n return { message, type, path };\n};\n\n// this is almost the same function like Semigroup.getObjectSemigroup but reversed\n// in order to get the first error\nconst getObjectSemigroup = <\n A extends Record<string, unknown> = never,\n>(): SemiGroup.Semigroup<A> => ({\n concat: (first, second) => Object.assign({}, second, first),\n});\n\nconst concatToSingleError = (\n errors: ReadonlyArray<FieldErrorWithPath>,\n): ErrorObject =>\n pipe(\n errors,\n ReadonlyArray.map((error) => ({\n [error.path]: {\n type: error.type,\n message: error.message,\n },\n })),\n (errors) => SemiGroup.fold(getObjectSemigroup<ErrorObject>())({}, errors),\n );\n\nconst appendSeveralErrors: SemiGroup.Semigroup<FieldErrorWithPath> = {\n concat: (a, b) => ({\n ...b,\n types: { ...a.types, [a.type]: a.message, [b.type]: b.message },\n }),\n};\n\nconst concatToMultipleErrors = (\n errors: ReadonlyArray<FieldErrorWithPath>,\n): ErrorObject =>\n pipe(\n ReadonlyRecord.fromFoldableMap(appendSeveralErrors, ReadonlyArr
|