Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 71x 71x 71x 71x 71x 514x 1x 513x 71x 179x 93x 86x 86x 86x 2x 84x 71x 858x 71x 14x 2x 71x 12x 6x 6x 6x | import { z } from "zod";
const DEFAULT_NULL = process.env.DEFAULT_NULL === "true";
/**
* GitLab REST API default pagination value.
* @see https://docs.gitlab.com/ee/api/rest/index.html#pagination
*/
export const GITLAB_DEFAULT_PER_PAGE = 20;
/**
* Maximum items per page allowed by GitLab API.
*/
export const GITLAB_MAX_PER_PAGE = 100;
/**
* Creates pagination fields for Zod schemas with dynamic descriptions.
* The description automatically includes the default value.
*
* @param defaultPerPage - Default items per page (default: 20)
* @param maxPerPage - Maximum items per page (default: 100)
* @returns Object with page and per_page Zod fields
*
* @example
* // In schema definition:
* const ListSchema = z.object({
* action: z.literal("list"),
* ...paginationFields(), // Uses GitLab defaults (20, max 100)
* });
*
* @example
* // With custom default:
* const ListSchema = z.object({
* action: z.literal("list"),
* ...paginationFields(50), // Default 50, max 100
* });
*/
export function paginationFields(
defaultPerPage: number = GITLAB_DEFAULT_PER_PAGE,
maxPerPage: number = GITLAB_MAX_PER_PAGE
) {
if (defaultPerPage > maxPerPage) {
throw new Error(
`Invalid pagination config: defaultPerPage (${defaultPerPage}) cannot exceed maxPerPage (${maxPerPage})`
);
}
return {
per_page: z
.number()
.int()
.min(1)
.max(maxPerPage)
.optional()
.default(defaultPerPage)
.describe(`Number of items per page (default: ${defaultPerPage}, max: ${maxPerPage})`),
page: z.number().int().min(1).optional().describe("Page number"),
};
}
export const flexibleBoolean = z.preprocess(val => {
if (typeof val === "boolean") {
return val;
}
let result = "false";
try {
result = String(val).toLowerCase();
} catch {
return false;
}
return ["true", "t", "1"].includes(result);
}, z.boolean());
export const flexibleBooleanNullable = DEFAULT_NULL
? flexibleBoolean.nullable().default(null)
: flexibleBoolean.nullable();
/**
* Required ID field that accepts string or number input.
* Unlike z.coerce.string(), this properly rejects undefined/null values
* instead of coercing them to the literal string "undefined"/"null".
*/
export const requiredId = z.preprocess(val => val ?? "", z.coerce.string().min(1));
/**
* Asserts that a value is defined (not undefined).
* Used for fields validated by Zod .refine() where TypeScript cannot
* automatically narrow the type after runtime validation.
*
* Note: This intentionally only checks for undefined, not empty strings.
* Empty string validation is handled by Zod schema .refine() checks which
* run during Schema.parse(args) BEFORE handler code executes. This function
* exists solely for TypeScript type narrowing after validation passes.
*
* @param value - The value to assert
* @param fieldName - Name of the field for error messages
* @throws Error if value is undefined
*/
export function assertDefined<T>(value: T | undefined, fieldName: string): asserts value is T {
if (value === undefined) {
throw new Error(`${fieldName} is required but was not provided`);
}
}
/**
* Validates that the appropriate ID field is provided based on scope.
* Used by webhook schemas to ensure projectId or groupId is present.
*
* @param data - Object containing scope, projectId, and groupId fields
* @returns true if validation passes
*/
export function validateScopeId(data: {
scope: "project" | "group";
projectId?: string;
groupId?: string;
}): boolean {
if (data.scope === "project") {
return !!data.projectId;
}
Eif (data.scope === "group") {
return !!data.groupId;
}
return true;
}
|