UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

100 lines (99 loc) 3.17 kB
import { z } from "zod"; const StringSchema = z.object({ type: z.literal("string"), optional: z.boolean().optional(), default: z.string().optional(), max: z.number().optional(), min: z.number().min(0).optional(), length: z.number().optional(), url: z.boolean().optional(), includes: z.string().optional(), startsWith: z.string().optional(), endsWith: z.string().optional() }); const NumberSchema = z.object({ type: z.literal("number"), optional: z.boolean().optional(), default: z.number().optional(), gt: z.number().optional(), min: z.number().optional(), lt: z.number().optional(), max: z.number().optional(), int: z.boolean().optional() }); const BooleanSchema = z.object({ type: z.literal("boolean"), optional: z.boolean().optional(), default: z.boolean().optional() }); const EnumSchema = z.object({ type: z.literal("enum"), values: z.array( // We use "'" for codegen so it can't be passed here z.string().refine((v) => !v.includes("'"), { message: `The "'" character can't be used as an enum value` }) ), optional: z.boolean().optional(), default: z.string().optional() }); const EnvFieldType = z.union([ StringSchema, NumberSchema, BooleanSchema, EnumSchema.superRefine((schema, ctx) => { if (schema.default) { if (!schema.values.includes(schema.default)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `The default value "${schema.default}" must be one of the specified values: ${schema.values.join(", ")}.` }); } } }) ]); const PublicClientEnvFieldMetadata = z.object({ context: z.literal("client"), access: z.literal("public") }); const PublicServerEnvFieldMetadata = z.object({ context: z.literal("server"), access: z.literal("public") }); const SecretServerEnvFieldMetadata = z.object({ context: z.literal("server"), access: z.literal("secret") }); const _EnvFieldMetadata = z.union([ PublicClientEnvFieldMetadata, PublicServerEnvFieldMetadata, SecretServerEnvFieldMetadata ]); const EnvFieldMetadata = z.custom().superRefine((data, ctx) => { const result = _EnvFieldMetadata.safeParse(data); if (result.success) { return; } for (const issue of result.error.issues) { if (issue.code === z.ZodIssueCode.invalid_union) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `**Invalid combination** of "access" and "context" options: Secret client variables are not supported. Please review the configuration of \`env.schema.${ctx.path.at(-1)}\`. Learn more at https://docs.astro.build/en/guides/environment-variables/#variable-types`, path: ["context", "access"] }); } else { ctx.addIssue(issue); } } }); const EnvSchemaKey = z.string().min(1).refine(([firstChar]) => isNaN(Number.parseInt(firstChar)), { message: "A valid variable name cannot start with a number." }).refine((str) => /^[A-Z0-9_]+$/.test(str), { message: "A valid variable name can only contain uppercase letters, numbers and underscores." }); const EnvSchema = z.record(EnvSchemaKey, z.intersection(EnvFieldMetadata, EnvFieldType)); export { EnvSchema };