mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #29593 from overleaf/mfb-from-joi-to-zod-analytics
[Analytics service] Migrate from JOI to ZOD GitOrigin-RevId: 5f6abc23c5359ca8599ef4b7d660d5f08551d247
This commit is contained in:
committed by
Copybot
parent
51639030f0
commit
e861e28296
@@ -2,11 +2,13 @@ const { ParamsError } = require('./Errors')
|
|||||||
const { z } = require('zod')
|
const { z } = require('zod')
|
||||||
const { zz } = require('./zodHelpers')
|
const { zz } = require('./zodHelpers')
|
||||||
const { validateReq } = require('./validateReq')
|
const { validateReq } = require('./validateReq')
|
||||||
|
const { validateSchema } = require('./validateSchema')
|
||||||
const { handleValidationError } = require('./handleValidationError')
|
const { handleValidationError } = require('./handleValidationError')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
z,
|
z,
|
||||||
zz,
|
zz,
|
||||||
|
validateSchema,
|
||||||
validateReq,
|
validateReq,
|
||||||
handleValidationError,
|
handleValidationError,
|
||||||
ParamsError,
|
ParamsError,
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// @ts-check
|
||||||
|
const { isZodErrorLike } = require('zod-validation-error')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('zod').ZodType} ZodType
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @typedef {import('zod').output<T>} output<T>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper function to safely get a nested value from an object
|
||||||
|
* using a path array (e.g., ["query", "resource_type"])
|
||||||
|
*/
|
||||||
|
function getPathValue(data, path) {
|
||||||
|
let current = data
|
||||||
|
for (const key of path) {
|
||||||
|
if (current === null || typeof current !== 'object') {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
current = current[key]
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRequiredError = (issue, value) =>
|
||||||
|
value === undefined &&
|
||||||
|
(issue.code === 'invalid_type' || issue.code === 'invalid_union')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates data against a Zod schema and throws a user-friendly error.
|
||||||
|
*
|
||||||
|
* @template {ZodType} T
|
||||||
|
* @param {T} schema - The Zod schema
|
||||||
|
* @param {unknown} data - The data to validate
|
||||||
|
* @returns {output<T>} The validated (and transformed) data
|
||||||
|
*/
|
||||||
|
function validateSchema(schema, data) {
|
||||||
|
try {
|
||||||
|
return schema.parse(data)
|
||||||
|
} catch (err) {
|
||||||
|
if (isZodErrorLike(err)) {
|
||||||
|
const errorMessages = err.issues.map(issue => {
|
||||||
|
const value = getPathValue(data, issue.path)
|
||||||
|
const fieldName = String(issue.path[issue.path.length - 1])
|
||||||
|
if (isRequiredError(issue, value)) {
|
||||||
|
return `"${fieldName}" is required`
|
||||||
|
}
|
||||||
|
return `"${fieldName}" - ` + issue.message
|
||||||
|
})
|
||||||
|
|
||||||
|
throw new Error(errorMessages.join('; '))
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { validateSchema }
|
||||||
@@ -3,6 +3,13 @@ const mongodb = require('mongodb')
|
|||||||
|
|
||||||
const { ObjectId } = mongodb
|
const { ObjectId } = mongodb
|
||||||
|
|
||||||
|
const dateWithTransform = (schema, allowNull = false) => {
|
||||||
|
return schema.transform(dt => {
|
||||||
|
if (allowNull && !dt) return null
|
||||||
|
return dt instanceof Date ? dt : new Date(dt)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const zz = {
|
const zz = {
|
||||||
objectId: () =>
|
objectId: () =>
|
||||||
z.string().refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' }),
|
z.string().refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' }),
|
||||||
@@ -12,6 +19,14 @@ const zz = {
|
|||||||
.refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' })
|
.refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' })
|
||||||
.transform(val => new ObjectId(val)),
|
.transform(val => new ObjectId(val)),
|
||||||
hex: () => z.string().regex(/^[0-9a-f]*$/),
|
hex: () => z.string().regex(/^[0-9a-f]*$/),
|
||||||
|
datetime: () => dateWithTransform(z.union([z.iso.datetime(), z.date()])),
|
||||||
|
datetimeNullable: () =>
|
||||||
|
dateWithTransform(z.union([z.iso.datetime(), z.date(), z.null()]), true),
|
||||||
|
datetimeNullish: () =>
|
||||||
|
dateWithTransform(
|
||||||
|
z.union([z.iso.datetime(), z.date(), z.null(), z.undefined()]),
|
||||||
|
true
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { zz }
|
module.exports = { zz }
|
||||||
|
|||||||
Generated
+1
-2
@@ -53543,15 +53543,14 @@
|
|||||||
"@overleaf/redis-wrapper": "*",
|
"@overleaf/redis-wrapper": "*",
|
||||||
"@overleaf/settings": "*",
|
"@overleaf/settings": "*",
|
||||||
"@overleaf/stream-utils": "^0.1.0",
|
"@overleaf/stream-utils": "^0.1.0",
|
||||||
|
"@overleaf/validation-tools": "*",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
"bull": "^3.18.0",
|
"bull": "^3.18.0",
|
||||||
"camelcase-keys": "^4.2.0",
|
"camelcase-keys": "^4.2.0",
|
||||||
"celebrate": "^15.0.3",
|
|
||||||
"csv": "^5.4.0",
|
"csv": "^5.4.0",
|
||||||
"east": "^2.0.3",
|
"east": "^2.0.3",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"joi": "^17.12.0",
|
|
||||||
"json2csv": "^4.5.4",
|
"json2csv": "^4.5.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"minimist": "^1.2.7",
|
"minimist": "^1.2.7",
|
||||||
|
|||||||
Reference in New Issue
Block a user