• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RobinTail / express-zod-api / 14625934837

23 Apr 2025 06:57PM UTC coverage: 99.975%. Remained the same
14625934837

Pull #2573

github

web-flow
Merge 287b126f3 into 83dfadd5f
Pull Request #2573: Improve handling of `ZodError` by `ensureError`

1203 of 1240 branches covered (97.02%)

1 of 1 new or added line in 1 file covered. (100.0%)

4063 of 4064 relevant lines covered (99.98%)

258.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/express-zod-api/src/deep-checks.ts
1
import type {
2
  $ZodArray,
3
  $ZodCatch,
4
  $ZodDefault,
5
  $ZodDiscriminatedUnion,
6
  $ZodIntersection,
7
  $ZodLazy,
8
  $ZodNullable,
9
  $ZodObject,
10
  $ZodOptional,
11
  $ZodPipe,
12
  $ZodReadonly,
13
  $ZodRecord,
14
  $ZodTuple,
15
  $ZodType,
16
  $ZodUnion,
17
} from "@zod/core";
18
import { fail } from "node:assert/strict"; // eslint-disable-line no-restricted-syntax -- acceptable
4✔
19
import { globalRegistry } from "zod";
4✔
20
import { EmptyObject } from "./common-helpers";
21
import { ezDateInBrand } from "./date-in-schema";
4✔
22
import { ezDateOutBrand } from "./date-out-schema";
4✔
23
import { ezFileBrand } from "./file-schema";
4✔
24
import { ezFormBrand } from "./form-schema";
4✔
25
import { IOSchema } from "./io-schema";
26
import { metaSymbol } from "./metadata";
4✔
27
import { ProprietaryBrand } from "./proprietary-schemas";
28
import { ezRawBrand } from "./raw-schema";
4✔
29
import {
30
  FirstPartyKind,
31
  HandlingRules,
32
  NextHandlerInc,
33
  SchemaHandler,
34
} from "./schema-walker";
35
import { ezUploadBrand } from "./upload-schema";
4✔
36

37
/** @desc Check is a schema handling rule returning boolean */
38
type Check = SchemaHandler<boolean>;
39

40
const onSomeUnion: Check = (
4✔
41
  { _zod }: $ZodUnion | $ZodDiscriminatedUnion,
80✔
42
  { next },
80✔
43
) => _zod.def.options.some(next);
80✔
44

45
const onIntersection: Check = ({ _zod }: $ZodIntersection, { next }) =>
4✔
46
  [_zod.def.left, _zod.def.right].some(next);
136✔
47

48
const onWrapped: Check = (
4✔
49
  {
44✔
50
    _zod: { def },
44✔
51
  }: $ZodOptional | $ZodNullable | $ZodReadonly | $ZodDefault | $ZodCatch,
44✔
52
  { next },
44✔
53
) => next(def.innerType);
44✔
54

55
const ioChecks: HandlingRules<boolean, EmptyObject, FirstPartyKind> = {
4✔
56
  object: ({ _zod }: $ZodObject, { next }) =>
4✔
57
    Object.values(_zod.def.shape).some(next),
1,748✔
58
  union: onSomeUnion,
4✔
59
  intersection: onIntersection,
4✔
60
  optional: onWrapped,
4✔
61
  nullable: onWrapped,
4✔
62
  default: onWrapped,
4✔
63
  record: ({ _zod }: $ZodRecord, { next }) => next(_zod.def.valueType),
4✔
64
  array: ({ _zod }: $ZodArray, { next }) => next(_zod.def.element),
4✔
65
};
4✔
66

67
interface NestedSchemaLookupProps {
68
  condition?: (schema: $ZodType) => boolean;
69
  rules?: HandlingRules<
70
    boolean,
71
    EmptyObject,
72
    FirstPartyKind | ProprietaryBrand
73
  >;
74
  maxDepth?: number;
75
  depth?: number;
76
}
77

78
/** @desc The optimized version of the schema walker for boolean checks */
79
export const hasNestedSchema = (
4✔
80
  subject: $ZodType,
3,944✔
81
  {
3,944✔
82
    condition,
3,944✔
83
    rules = ioChecks,
3,944✔
84
    depth = 1,
3,944✔
85
    maxDepth = Number.POSITIVE_INFINITY,
3,944✔
86
  }: NestedSchemaLookupProps,
3,944✔
87
): boolean => {
3,944✔
88
  if (condition?.(subject)) return true;
3,944✔
89
  if (depth >= maxDepth) return false;
3,944✔
90
  const brand = globalRegistry.get(subject)?.[metaSymbol]?.brand;
3,944✔
91
  const handler =
3,944✔
92
    brand && brand in rules
3,944✔
93
      ? rules[brand as keyof typeof rules]
52✔
94
      : rules[subject._zod.def.type];
3,532✔
95
  if (handler) {
3,944✔
96
    return handler(subject, {
2,156✔
97
      next: (schema) =>
2,156✔
98
        hasNestedSchema(schema, {
2,464✔
99
          condition,
2,464✔
100
          rules,
2,464✔
101
          maxDepth,
2,464✔
102
          depth: depth + 1,
2,464✔
103
        }),
2,464✔
104
    } as EmptyObject & NextHandlerInc<boolean>);
2,156✔
105
  }
2,156✔
106
  return false;
1,428✔
107
};
1,428✔
108

109
export const hasUpload = (subject: IOSchema) =>
4✔
110
  hasNestedSchema(subject, {
344✔
111
    condition: (schema) =>
344✔
112
      globalRegistry.get(schema)?.[metaSymbol]?.brand === ezUploadBrand,
896✔
113
    rules: {
344✔
114
      ...ioChecks,
344✔
115
      [ezFormBrand]: ioChecks.object,
344✔
116
    },
344✔
117
  });
344✔
118

119
export const hasRaw = (subject: IOSchema) =>
4✔
120
  hasNestedSchema(subject, {
348✔
121
    condition: (schema) =>
348✔
122
      globalRegistry.get(schema)?.[metaSymbol]?.brand === ezRawBrand,
848✔
123
    maxDepth: 3,
348✔
124
  });
348✔
125

126
export const hasForm = (subject: IOSchema) =>
4✔
127
  hasNestedSchema(subject, {
300✔
128
    condition: (schema) =>
300✔
129
      globalRegistry.get(schema)?.[metaSymbol]?.brand === ezFormBrand,
756✔
130
    maxDepth: 3,
300✔
131
  });
300✔
132

133
/** @throws AssertionError with incompatible schema constructor */
134
export const assertJsonCompatible = (subject: $ZodType, dir: "in" | "out") => {
4✔
135
  const lazies = new WeakSet<() => $ZodType>();
424✔
136
  return hasNestedSchema(subject, {
424✔
137
    maxDepth: 300,
424✔
138
    rules: {
424✔
139
      ...ioChecks,
424✔
140
      readonly: onWrapped,
424✔
141
      catch: onWrapped,
424✔
142
      pipe: ({ _zod }: $ZodPipe, { next }) => next(_zod.def[dir]),
424✔
143
      lazy: ({ _zod: { def } }: $ZodLazy, { next }) =>
424✔
144
        lazies.has(def.getter)
16✔
145
          ? false
4✔
146
          : lazies.add(def.getter) && next(def.getter()),
12✔
147
      tuple: ({ _zod: { def } }: $ZodTuple, { next }) =>
424✔
148
        [...def.items].concat(def.rest ?? []).some(next),
8✔
149
      nan: () => fail("z.nan()"),
424✔
150
      symbol: () => fail("z.symbol()"),
424✔
151
      map: () => fail("z.map()"),
424✔
152
      set: () => fail("z.set()"),
424✔
153
      bigint: () => fail("z.bigint()"),
424✔
154
      void: () => fail("z.void()"),
424✔
155
      promise: () => fail("z.promise()"),
424✔
156
      never: () => fail("z.never()"),
424✔
157
      date: () => dir === "in" && fail("z.date()"),
424✔
158
      [ezDateOutBrand]: () => dir === "in" && fail("ez.dateOut()"),
424✔
159
      [ezDateInBrand]: () => dir === "out" && fail("ez.dateIn()"),
424✔
160
      [ezRawBrand]: () => dir === "out" && fail("ez.raw()"),
424✔
161
      [ezUploadBrand]: () => dir === "out" && fail("ez.upload()"),
424✔
162
      [ezFileBrand]: () => false,
424✔
163
    },
424✔
164
  });
424✔
165
};
424✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc