moleculer-zod-validator
Version:
A validator for the Moleculer microservice framework to allow the use of Zod.
147 lines (146 loc) • 5.87 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZodParams = void 0;
const zod_1 = require("zod");
/**
* An adapter for a standard {@link https://github.com/colinhacks/zod#objects ZodObject},
* which can be easier to work with in Moleculer than Zod on its own.
*/
class ZodParams {
/**
* Creates a new ZodParams adapter, which can be used to more easily provide typing
* information to Moleculer services and calls.
* @param {ZodRawShape} schema - The schema used in
* {@link https://github.com/colinhacks/zod#objects z.object()}.
* @param {ZodParamsOptionsType} options - This exposes several methods available
* on the ZodObject type,
* {@link https://github.com/colinhacks/zod#table-of-contents all of which can be referenced under the Objects section in the Zod documentation}.
* @param {any} returnType - The return type of the action in question. This does
* nothing at runtime and is used purely for storing a type on the object that can
* then be referenced later on. This can be done like so:
*
* @example <caption>The return type will be `Promise<string>`</caption>
* new ZodParams({ property: z.string() }, undefined, {} as Promise<string>)
*
* @todo
* **Note**: {@link https://github.com/colinhacks/zod/issues/1949 There's currently a known issue in Zod where catchall type inferences don't work correctly.}
* Until this upstream issue is fixed, catchall type inferences on ZodParams will
* be disabled as not to break existing projects. This will not impact the runtime
* behavior of catchall in the validator, just the type inference.
*
* If you wish to emulate the type inference, you can do so by using a TS union
* when using broker.call or ctx.call.
*
* @example
* broker.call<
* typeof zodParamObject.return,
* typeof zodParamObject.call & {[index: string]: string}
* >({ ... })
*
*/
constructor(schema, options, returnType) {
this._rawSchema = schema;
const opts = ZodParamsOptions.parse(options || {});
// This is an effort to hopefully improve type inference
// As for the @ts-expect-errors ahead, while trying to get this code to work as
// you'd expect, I had to use some of my own types that were supposed to be
// interoperable with the original Zod types. While the interop is supposed to
// be one-way, TypeScript is giving me errors assuming it's supposed to go both
// ways. As much as I'd like to give TS as much power over things as I can,
// here it's just wrong.
// @ts-expect-error
this._validator = zod_1.z.object(this._rawSchema);
if (opts.strip) {
// @ts-expect-error
this._validator = this._validator.strip();
}
else if (opts.strict) {
// @ts-expect-error
this._validator = this._validator.strict();
}
else if (opts.passthrough) {
// @ts-expect-error
this._validator = this._validator.passthrough();
}
if (opts.partial) {
// @ts-expect-error
this._validator = this._validator.partial();
}
else if (opts.deepPartial) {
// @ts-expect-error
this._validator = this._validator.deepPartial();
}
if (opts.catchall) {
this._validator = this._validator.catchall(opts.catchall);
}
// Functions should be considered truthy
if (opts.superRefine) {
// @ts-expect-error
this._validator = this._validator.superRefine(opts.superRefine);
}
if (opts.refine) {
if (typeof opts.refine === "function") {
// @ts-expect-error
this._validator = this._validator.refine(opts.refine);
}
else {
// @ts-expect-error
this._validator = this._validator.refine(opts.refine.validator, opts.refine.params);
}
}
this._rawSchemaWithOptions = Object.assign({}, schema, {
$$$options: opts
});
}
/**
* Returns the raw Zod schema provided in the constructor. This should be passed
* to the `params` object in the action definition.
*
* @example
* broker.createService({
* name: "example",
* actions: {
* exampleAction: {
* params: zodParamObject.schema,
* handler(ctx: Context<typeof zodParamObject.context>) { ... }
* }
* }
* });
*/
get schema() {
return this._rawSchemaWithOptions;
}
/**
* Returns the compiled ZodObject validator.
*/
get validator() {
return this._validator;
}
}
exports.ZodParams = ZodParams;
const ZodParamsOptions = zod_1.z
.object({
partial: zod_1.z.boolean().default(false),
deepPartial: zod_1.z.boolean().default(false),
strict: zod_1.z.boolean().default(false),
catchall: zod_1.z.any(),
passthrough: zod_1.z.boolean(),
strip: zod_1.z.boolean().default(false),
refine: zod_1.z.union([
// Not sure how best to represent the validator function params
zod_1.z.function().args(zod_1.z.any()),
zod_1.z.object({
validator: zod_1.z.function().args(zod_1.z.any()),
params: zod_1.z
.object({
message: zod_1.z.string(),
path: zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number()])),
params: zod_1.z.object({}).passthrough()
})
.partial()
.optional()
})
]),
superRefine: zod_1.z.function().args(zod_1.z.any(), zod_1.z.any())
})
.partial();