diff --git a/deno.jsonc b/deno.jsonc index 7b6b69472b1..a5fbd9f889b 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,9 @@ // auto-generated by package/src/common/create-deno-config.ts // see dev-docs/update-deno_jsonc.md { + "compilerOptions": { + "noErrorTruncation": true + }, "lint": { "include": ["src/"], "exclude": [ diff --git a/package/src/common/create-schema-types.ts b/package/src/common/create-schema-types.ts index 9ec3e1aa0cd..48d7907885a 100644 --- a/package/src/common/create-schema-types.ts +++ b/package/src/common/create-schema-types.ts @@ -14,6 +14,11 @@ import { generateJsonSchemasFromSchemas, } from "../../../src/core/schema/json-schema-from-schema.ts"; +import { + generateZodTypesFromSchemas, +} from "../../../src/core/schema/zod-types-from-schema.ts"; + await generateTypesFromSchemas(Deno.args[0]); await generateSchemaTypes(Deno.args[0]); -await generateJsonSchemasFromSchemas(Deno.args[0]); \ No newline at end of file +await generateJsonSchemasFromSchemas(Deno.args[0]); +await generateZodTypesFromSchemas(Deno.args[0]); \ No newline at end of file diff --git a/src/command/render/pandoc.ts b/src/command/render/pandoc.ts index 4d52ca228f4..76dbf458b1a 100644 --- a/src/command/render/pandoc.ts +++ b/src/command/render/pandoc.ts @@ -197,11 +197,7 @@ import { MarkdownPipelineHandler, } from "../../core/markdown-pipeline.ts"; import { getenv } from "../../core/env.ts"; -import { - BrandFontBunny, - BrandFontFile, - BrandFontGoogle, -} from "../../resources/types/schema-types.ts"; +import { Zod } from "../../resources/types/zod/schema-types.ts"; import { kFieldCategories } from "../../project/types/website/listing/website-listing-shared.ts"; import { isWindows } from "../../deno_ral/platform.ts"; import { appendToCombinedLuaProfile } from "../../core/performance/perfetto-utils.ts"; @@ -1480,19 +1476,19 @@ async function resolveExtras( // deno-lint-ignore no-explicit-any const source: string = (_font as any).source ?? "google"; if (source === "file") { - const font = _font as BrandFontFile; + const font = Zod.BrandFontFile.parse(_font); for (const file of font.files || []) { const path = typeof file === "object" ? file.path : file; fontdirs.add(dirname(join(brand.brandDir, path))); } } else if (source === "bunny") { - const font = _font as BrandFontBunny; + const font = Zod.BrandFontBunny.parse(_font); console.log( "Font bunny is not yet supported for Typst, skipping", font.family, ); } else if (source === "google" /* || font.source === "bunny" */) { - const font = _font as BrandFontGoogle; + const font = Zod.BrandFontGoogle.parse(_font); let { family, style, weight } = font; const parts = [family!]; if (style) { diff --git a/src/command/render/project.ts b/src/command/render/project.ts index 514884ea44c..65e66820058 100644 --- a/src/command/render/project.ts +++ b/src/command/render/project.ts @@ -80,7 +80,7 @@ import { Format } from "../../config/types.ts"; import { fileExecutionEngine } from "../../execute/engine.ts"; import { projectContextForDirectory } from "../../project/project-context.ts"; import { ProjectType } from "../../project/types/types.ts"; -import { ProjectConfig as ProjectConfig_Project } from "../../resources/types/schema-types.ts"; +import { Zod } from "../../resources/types/zod/schema-types.ts"; const noMutationValidations = ( projType: ProjectType, @@ -255,9 +255,11 @@ const mergeExtensionMetadata = async ( context.isSingleFile ? undefined : context.dir, { builtIn: false }, ); - const projectMetadata = extensions.map((extension) => + const projectMetadata = extensions.filter((extension) => extension.contributes.metadata?.project - ).filter((project) => project) as ProjectConfig_Project[]; + ).map((extension) => { + return Zod.ProjectConfig.parse(extension.contributes.metadata!.project); + }); context.config.project = mergeProjectMetadata( context.config.project, ...projectMetadata, diff --git a/src/core/brand/brand.ts b/src/core/brand/brand.ts index 226fb8a42c2..94fc0edd425 100644 --- a/src/core/brand/brand.ts +++ b/src/core/brand/brand.ts @@ -14,7 +14,8 @@ import { BrandTypography, BrandTypographyOptionsBase, BrandTypographyOptionsHeadings, -} from "../../resources/types/schema-types.ts"; + Zod, +} from "../../resources/types/zod/schema-types.ts"; import { InternalError } from "../lib/error.ts"; import { join, relative } from "../../deno_ral/path.ts"; @@ -67,11 +68,15 @@ export class Brand { projectDir: string; processedData: ProcessedBrandData; - constructor(readonly brand: BrandJson, brandDir: string, projectDir: string) { - this.data = brand; + constructor( + readonly brand: unknown, + brandDir: string, + projectDir: string, + ) { + this.data = Zod.Brand.parse(brand); this.brandDir = brandDir; this.projectDir = projectDir; - this.processedData = this.processData(brand); + this.processedData = this.processData(this.data); } processData(data: BrandJson): ProcessedBrandData { @@ -261,8 +266,10 @@ export class Brand { if (typeof entry === "string") { return { path: join(pathPrefix, entry) }; } - entry.path = join(pathPrefix, entry.path); - return entry; + return { + ...entry, + path: join(pathPrefix, entry.path), + }; } getLogo(name: "small" | "medium" | "large"): CanonicalLogoInfo | undefined { diff --git a/src/core/sass/brand.ts b/src/core/sass/brand.ts index 9455023a9b3..69ab57f4599 100644 --- a/src/core/sass/brand.ts +++ b/src/core/sass/brand.ts @@ -16,11 +16,12 @@ import { import { ProjectContext } from "../../project/types.ts"; import { BrandFont, - BrandFontBunny, + // BrandFontBunny, BrandFontCommon, BrandFontGoogle, BrandFontWeight, -} from "../../resources/types/schema-types.ts"; + Zod, +} from "../../resources/types/zod/schema-types.ts"; import { Brand } from "../brand/brand.ts"; import { darkModeDefault } from "../../format/html/format-html-info.ts"; @@ -323,10 +324,11 @@ const brandTypographyLayer = ( ): string | undefined => { let googleFamily = ""; for (const _resolvedFont of font) { - const resolvedFont = _resolvedFont as (BrandFontGoogle | BrandFontBunny); - if (resolvedFont.source !== "google") { + const safeResolvedFont = Zod.BrandFontGoogle.safeParse(_resolvedFont); + if (!safeResolvedFont.success) { return undefined; } + const resolvedFont = safeResolvedFont.data; const thisFamily = resolvedFont.family; if (!thisFamily) { continue; @@ -351,17 +353,15 @@ const brandTypographyLayer = ( ): string | undefined => { let googleFamily = ""; for (const _resolvedFont of font) { - const resolvedFont = - _resolvedFont as (BrandFont | BrandFontGoogle | BrandFontBunny); + const safeResolvedFont = Zod.BrandFontBunny.safeParse(_resolvedFont); + if (!safeResolvedFont.success) { + return undefined; + } + const resolvedFont = safeResolvedFont.data; // Typescript's type checker doesn't understand that it's ok to attempt // to access a property that might not exist on a type when you're // only testing for its existence. - // deno-lint-ignore no-explicit-any - const source = (resolvedFont as any).source; - if (source && source !== "bunny") { - return undefined; - } const thisFamily = resolvedFont.family; if (!thisFamily) { continue; @@ -384,6 +384,7 @@ const brandTypographyLayer = ( type HTMLFontInformation = { [key: string]: unknown }; type FontKind = + | "link" | "base" | "headings" | "monospace" @@ -398,9 +399,14 @@ const brandTypographyLayer = ( } else if (typeof resolvedFontOptions === "string") { resolvedFontOptions = { family: resolvedFontOptions }; } - const family = resolvedFontOptions.family; - const font = getFontFamilies(family); const result: HTMLFontInformation = {}; + // This is an ugly hack: + // resolvedFontOptions doesn't always have 'family', but at this + // point in the code we know resolvedFontOptions is an object + // that we can attempt to extract the family from. + const family = + (resolvedFontOptions as Record).family; + const font = getFontFamilies(family); result.family = resolveGoogleFontFamily(font) ?? resolveBunnyFontFamily(font) ?? // resolveFilesFontFamily(font) ?? @@ -524,11 +530,9 @@ const brandTypographyLayer = ( "monospace", "headings", "base", - ] + ] as const ) { - const fontInformation = resolveHTMLFontInformation( - kind as FontKind, - ); + const fontInformation = resolveHTMLFontInformation(kind); if (!fontInformation) { continue; } diff --git a/src/core/schema/build-schema-file.ts b/src/core/schema/build-schema-file.ts index 5505bcbeb96..852fcc24857 100644 --- a/src/core/schema/build-schema-file.ts +++ b/src/core/schema/build-schema-file.ts @@ -37,6 +37,7 @@ import { kLangCommentChars } from "../lib/partition-cell-options.ts"; import { generateTypesFromSchemas } from "./types-from-schema.ts"; import { generateJsonSchemasFromSchemas } from "./json-schema-from-schema.ts"; import { InternalError } from "../lib/error.ts"; +import { generateZodTypesFromSchemas } from "./zod-types-from-schema.ts"; //////////////////////////////////////////////////////////////////////////////// @@ -90,6 +91,7 @@ export async function buildIntelligenceResources() { await Promise.all([ generateTypesFromSchemas(path), generateJsonSchemasFromSchemas(path), + generateZodTypesFromSchemas(path), ]); } diff --git a/src/core/schema/types-from-schema.ts b/src/core/schema/types-from-schema.ts index da7c69c5e54..15a096447b3 100644 --- a/src/core/schema/types-from-schema.ts +++ b/src/core/schema/types-from-schema.ts @@ -26,16 +26,16 @@ export function typeNameFromSchemaName(schemaName: string) { return capitalize(toCapitalizationCase(schemaName.replaceAll("/", "-"))); } -function fmtSource(source: string) { +export function fmtSource(source: string) { return new Deno.Command(Deno.execPath(), { args: ["fmt", source], }).output(); } export const generatedSrcMessage = - `// This file is automatically generated by \`quarto build-js\`! Do not edit.", + `// This file is automatically generated by \`quarto dev-call build-artifacts\`! Do not edit.", // -// If you find yourself trying to rebuild types and \`quarto build-js\` won't run because +// If you find yourself trying to rebuild types and \`quarto dev-call build-artifacts\` won't run because // of bad type definitions, run the following: // $ cd $QUARTO_ROOT // $ ./package/dist/bin/tools/deno run --importmap=./src/import_map.json --allow-all ./package/src/common/create-schema-types.ts ./src/resources @@ -104,7 +104,7 @@ export async function generateTypesFromSchemas(resourcePath: string) { await fmtSource(join(resourcePath, "/types/schema-types.ts")); } -function yamlToTypeScriptKey(key: string) { +export function yamlToTypeScriptKey(key: string) { // if the key isn't a valid typescript identifier, quote it if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(key)) { return JSON.stringify(key); diff --git a/src/core/schema/zod-types-from-schema.ts b/src/core/schema/zod-types-from-schema.ts new file mode 100644 index 00000000000..b4afc6ab132 --- /dev/null +++ b/src/core/schema/zod-types-from-schema.ts @@ -0,0 +1,462 @@ +/* + * zod-types-from-schema.ts + * + * Tools to convert our schemas to Zod schemas. + * + * Copyright (C) 2025 Posit Software, PBC + */ + +/* + +This file intentionally does not import from a number of quarto libraries +in order to minimize its dependencies. + +We do this because you might need to run this file to regenerate quarto types, +and it's possible that you're doing it from a position where `quarto` doesn't +itself run. + +*/ + +import { ensureDirSync } from "../../deno_ral/fs.ts"; +import { join } from "../../deno_ral/path.ts"; +import { + fmtSource, + generatedSrcMessage, + schemaDefinitions, + typeNameFromSchemaName, + yamlToTypeScriptKey, +} from "./types-from-schema.ts"; + +class ZodDeclarationFileBuilder { + constructor() { + this.declarations = []; + this.inferredTypes = []; + } + + declarations: string[] = []; + inferredTypes: string[] = []; + + // we keep track of the schemas we've seen so we can + // process resolve-ref schemas + // deno-lint-ignore no-explicit-any + schemas: Record = {}; + + // deno-lint-ignore no-explicit-any + addSchema(obj: { name: string; schema: any }, inComments = false) { + this.schemas[obj.name] = obj.schema; + const schemaName = typeNameFromSchemaName(obj.name); + const schema = obj.schema; + const zodType = this.convertToZodJsSource(schema); + const startComment = inComments ? "/* " : ""; + const endComment = inComments ? " */" : ""; + this.declarations.push( + `${startComment}export const Zod${schemaName} = ${zodType};${endComment}\n`, + ); + this.inferredTypes.push( + `${startComment}export type ${schemaName} = z.infer;${endComment}\n`, + ); + } + + fileSource(): string { + const zodDeclarations = this.declarations.join("\n"); + const zodInferredTypes = this.inferredTypes.join("\n"); + const zodObject = (() => { + const lines = [ + "export const Zod = {", + ]; + Object.keys(this.schemas).forEach((name) => { + const typeName = typeNameFromSchemaName(name); + lines.push( + ` ${typeName}: Zod${typeName},`, + ); + }); + lines.push("};"); + return lines.join("\n"); + })(); + return `import { z } from "zod"; + +import { ZodSidebarContents, ZodNavigationItem, ZodNavigationItemObject } from "./handwritten-schema-types.ts"; +export { ZodSidebarContents, ZodNavigationItem, ZodNavigationItemObject } from "./handwritten-schema-types.ts"; + +${generatedSrcMessage} + +${zodDeclarations} +${zodInferredTypes} + +${zodObject} +`; + } + + // deno-lint-ignore no-explicit-any + convertToZodJsSource(schema: any): string { + // we're doing a syntax-directed translation of the schema objects + // as they exist in our JSON format. Follow schema-schema-types.ts + // for the schema types themselves. + // + // To reiterate, we don't import that file directly here to avoid + // bootstrapping problems in the case the build process errors out. + + const result = this.convertSchemaNull(schema) || + this.convertSchemaEnum(schema) || + this.convertExplicitSchema(schema) || + this.convertStringSchema(schema) || + this.convertNumberSchema(schema) || + this.convertBooleanSchema(schema) || + this.convertResolveRefSchema(schema) || + this.convertRefSchema(schema) || + this.convertMaybeArrayOfSchema(schema) || + this.convertArrayOfSchema(schema) || + this.convertAllOfSchema(schema) || + this.convertAnyOfSchema(schema) || + this.convertRecordSchema(schema) || + this.convertObjectSchema(schema); + if (result) { + return result; + } + + throw new Error( + `Unsupported schema: ${JSON.stringify(schema, null, 2)}`, + ); + } + + // deno-lint-ignore no-explicit-any + convertSchemaEnum(schema: any): string | undefined { + // deno-lint-ignore no-explicit-any + const zodEnumDeclaration = (values: any[]) => { + // first filter out strings + const zodEnumStrings = values.filter((value) => { + return typeof value === "string"; + }).map((value) => { + return JSON.stringify(value); + }); + const zodLiterals = values.filter((x) => { + return typeof x !== "string"; + }); + const zodTypes: string[] = []; + + if (zodEnumStrings.length) { + zodTypes.push( + `z.enum([${zodEnumStrings.join(", ")}] as const)`, + ); + } + if (zodLiterals.length) { + zodTypes.push( + ...zodLiterals.map((x) => { + return `z.literal(${JSON.stringify(x)})`; + }), + ); + } + if (zodTypes.length === 0) { + throw new Error( + `Unimplemented: ${JSON.stringify(schema, null, 2)}`, + ); + } else if (zodTypes.length === 1) { + return zodTypes[0]; + } else { + return `z.union([${zodTypes.join(", ")}])`; + } + }; + if (schema.enum) { + if (Array.isArray(schema.enum)) { + return zodEnumDeclaration(schema.enum); + } + return this.convertSchemaEnum(schema.enum); + } + if (schema.values) { + return zodEnumDeclaration(schema.values); + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertSchemaNull(schema: any): string | undefined { + if (schema === "null" || schema === null || schema.null) { + return `z.null()`; + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertExplicitSchema(schema: any): string | undefined { + if (schema.schema) { + return this.convertToZodJsSource(schema.schema); + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertStringSchema(schema: any): string | undefined { + // SchemaExplicitPatternString + // SchemaString + if (schema === "string") { + return `z.string()`; + } + if (schema === "path") { + return `z.string()`; + } + // deno-lint-ignore no-explicit-any + const zodDeclStringWithMaybePattern = (innerSchema: any) => { + if (innerSchema.pattern) { + return `z.string().regex(new RegExp(${ + JSON.stringify( + innerSchema.pattern, + ) + }))`; + } else { + return `z.string()`; + } + }; + if (schema.path) { + return zodDeclStringWithMaybePattern(schema.path); + } + if (schema.string) { + return zodDeclStringWithMaybePattern(schema.string); + } + if (schema.pattern) { + return zodDeclStringWithMaybePattern(schema); + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertNumberSchema(schema: any): string | undefined { + if (schema === "number") { + return `z.number()`; + } + if (schema.number) { + return `z.number()`; + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertBooleanSchema(schema: any): string | undefined { + if (schema === "boolean") { + return `z.boolean()`; + } + if (schema.boolean) { + return `z.boolean()`; + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertResolveRefSchema(schema: any): string | undefined { + if (schema.resolveRef) { + throw new Error("Unimplemented: convertResolveRefSchema"); + } + return undefined; + } + + // TODO: if this is a recursive schema, we need to know about that + // and change the top-level schema to have an explicit type annotation + // cf https://zod.dev/?id=recursive-types + // deno-lint-ignore no-explicit-any + convertRefSchema(schema: any): string | undefined { + if (schema.ref) { + const refName = typeNameFromSchemaName(schema.ref); + return `z.lazy(() => Zod${refName})`; + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertMaybeArrayOfSchema(schema: any): string | undefined { + if (schema.maybeArrayOf) { + const innerSchema = schema.maybeArrayOf; + const innerZodType = this.convertToZodJsSource(innerSchema); + return `z.union([${innerZodType}, z.array(${innerZodType})])`; + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertArrayOfSchema(schema: any): string | undefined { + if (schema.arrayOf) { + const innerSchema = schema.arrayOf; + const innerZodType = this.convertToZodJsSource(innerSchema); + return `z.array(${innerZodType})`; + } + return undefined; + } + + // deno-lint-ignore no-explicit-any + convertAllOfSchema(schema: any): string | undefined { + if (!schema.allOf) { + return undefined; + } + const innerSchemas = schema.allOf; + // deno-lint-ignore no-explicit-any + const innerZodTypes = innerSchemas.map((s: any) => { + return this.convertToZodJsSource(s); + }); + let first = innerZodTypes.shift(); + // z.intersection doesn't take more than 2 arguments + // so we need to chain sese together + while (innerZodTypes.length > 0) { + const innerZodType = innerZodTypes.shift(); + first = `${first}.and(${innerZodType})`; + } + return first; + } + + // deno-lint-ignore no-explicit-any + convertAnyOfSchema(schema: any): string | undefined { + if (!schema.anyOf) { + return undefined; + } + const innerSchemas = schema.anyOf; + // deno-lint-ignore no-explicit-any + const innerZodTypes = innerSchemas.map((s: any) => { + return this.convertToZodJsSource(s); + }); + return `z.union([${innerZodTypes.join(", ")}])`; + } + + // deno-lint-ignore no-explicit-any + convertRecordSchema(schema: any): string | undefined { + if (!schema.record) { + return undefined; + } + const properties = schema.record.properties || schema.record; + return `z.object({ ${ + Object.entries(properties).map(([key, value]) => { + return `${yamlToTypeScriptKey(key)}: ${ + this.convertToZodJsSource(value) + }`; + }) + }}).strict()`; + } + + // deno-lint-ignore no-explicit-any + convertObjectSchema(schema: any): string | undefined { + // deno-lint-ignore no-explicit-any + const getProperties = (s: any) => { + if (s.properties) { + return s.properties; + } + if (s.schema) { + return getProperties(s.schema); + } + if (s.object) { + return getProperties(s.object); + } + return {}; + }; + // deno-lint-ignore no-explicit-any + const resolveSuper = (s: any) => { + if (!s.super) { + return s; + } + // deno-lint-ignore no-explicit-any + let superSchemas: any[]; + if (Array.isArray(s.super)) { + superSchemas = s.super.map(resolveSuper); + } else if (s.super.resolveRef) { + superSchemas = [ + this.schemas[typeNameFromSchemaName(s.super.resolveRef)], + ]; + } else { + throw new Error( + `Unimplemented: ${JSON.stringify(s.super, null, 2)}`, + ); + } + // deno-lint-ignore no-explicit-any + const properties: Record = {}; + for (const superSchema of superSchemas) { + const superProperties = getProperties(superSchema); + for (const key in superProperties) { + properties[key] = superProperties[key]; + } + } + + return { + ...s, + properties: { + ...properties, + ...getProperties(s), + }, + }; + }; + if (schema === "object") { + return `z.object({}).passthrough()`; + } + if (!schema.object) { + return undefined; + } + let obj = schema.object; + if (obj.namingConvention) { + console.warn( + "namingConvention enforcement is not supported. Ignoring.", + ); + console.warn(JSON.stringify(obj, null, 2)); + } + const closed = obj.closed || false; + const required = obj.required; + obj = resolveSuper(obj); + let baseObj = `z.object({${ + Object.entries(obj.properties || {}).map(([key, value]) => { + return `${yamlToTypeScriptKey(key)}: ${ + this.convertToZodJsSource(value) + }`; + }).join(", ") + }})`; + if (closed) { + baseObj = `${baseObj}.strict()`; + } else { + baseObj = `${baseObj}.passthrough()`; + } + if (Array.isArray(required)) { + baseObj = `${baseObj}.partial().required({${ + required.map((key: string) => { + return `${key}: true`; + }).join(", ") + }})`; + } else if (required === undefined) { + baseObj = `${baseObj}.partial()`; + } else if (required === "all") { + baseObj = `${baseObj}.required()`; + } + if (obj.additionalProperties) { + baseObj = `z.record(${ + this.convertToZodJsSource( + obj.additionalProperties, + ) + }).and(${baseObj})`; + } + + return baseObj; + } +} + +export async function generateZodTypesFromSchemas(resourcePath: string) { + const builder = new ZodDeclarationFileBuilder(); + const schemas = schemaDefinitions(resourcePath); + + const schemasToSkip = [ + "SidebarContents", + "NavigationItem", + "NavigationItemObject", + ]; + + for (const schema of schemas) { + builder.addSchema(schema, schemasToSkip.includes(schema.name)); + } + const zodTypes = builder.fileSource(); + const schemaSchemaSourcePath = join( + resourcePath, + "types", + "zod", + "schema-types.ts", + ); + ensureDirSync(join( + resourcePath, + "types", + "zod", + )); + Deno.writeTextFileSync( + schemaSchemaSourcePath, + zodTypes, + ); + await fmtSource(schemaSchemaSourcePath); +} diff --git a/src/import_map.json b/src/import_map.json index c1c370a7409..23c5fb371b2 100644 --- a/src/import_map.json +++ b/src/import_map.json @@ -26,6 +26,8 @@ "log": "jsr:/@std/log@0.224.0", "log/": "jsr:/@std/log@0.224.0/", + "zod": "npm:/zod@3.24.4", + "yaml": "https://cdn.skypack.dev/js-yaml", "events/": "https://deno.land/x/events@v1.0.0/", "cache/": "https://deno.land/x/cache@0.2.12/", diff --git a/src/project/project-shared.ts b/src/project/project-shared.ts index bef495a34dd..0d43d0b90ad 100644 --- a/src/project/project-shared.ts +++ b/src/project/project-shared.ts @@ -47,10 +47,7 @@ import { normalizeNewlines } from "../core/lib/text.ts"; import { DirectiveCell } from "../core/lib/break-quarto-md-types.ts"; import { QuartoJSONSchema, readYamlFromMarkdown } from "../core/yaml.ts"; import { refSchema } from "../core/lib/yaml-schema/common.ts"; -import { - Brand as BrandJson, - BrandPathBoolLightDark, -} from "../resources/types/schema-types.ts"; +import { Zod } from "../resources/types/zod/schema-types.ts"; import { Brand } from "../core/brand/brand.ts"; import { assert } from "testing/asserts"; @@ -524,7 +521,7 @@ export async function projectResolveBrand( brandPath, refSchema("brand", "Format-independent brand configuration."), "Brand validation failed for " + brandPath + ".", - ) as BrandJson; + ); return new Brand(brand, dirname(brandPath), project.dir); } async function loadRelativeBrand( @@ -547,7 +544,7 @@ export async function projectResolveBrand( let fileNames = ["_brand.yml", "_brand.yaml"].map((file) => join(project.dir, file) ); - let brand = project?.config?.brand as Boolean | string | { + const brand = project?.config?.brand as boolean | string | { light?: string; dark?: string; }; @@ -582,11 +579,14 @@ export async function projectResolveBrand( return project.brandCache.brand; } else { const metadata = await project.fileMetadata(fileName); - const brand = metadata.brand as BrandPathBoolLightDark; + if (metadata.brand === undefined) { + return project.resolveBrand(); + } + const brand = Zod.BrandPathBoolLightDark.parse(metadata.brand); if (brand === false) { return undefined; } - if (brand === true || brand === undefined) { + if (brand === true) { return project.resolveBrand(); } const fileInformation = ensureFileInformationCache(project, fileName); @@ -611,7 +611,7 @@ export async function projectResolveBrand( } if (typeof brand.dark === "string") { dark = await loadRelativeBrand(brand.dark); - } else if(brand.dark) { + } else if (brand.dark) { dark = new Brand( brand.dark, dirname(fileName), @@ -622,7 +622,7 @@ export async function projectResolveBrand( } else { fileInformation.brand = { light: new Brand( - brand as BrandJson, + brand, dirname(fileName), project.dir, ), diff --git a/src/project/serve/serve.ts b/src/project/serve/serve.ts index 7d96caca82e..3a5034cc5a0 100644 --- a/src/project/serve/serve.ts +++ b/src/project/serve/serve.ts @@ -109,7 +109,7 @@ import { exitWithCleanup, onCleanup } from "../../core/cleanup.ts"; import { projectExtensionDirs } from "../../extension/extension.ts"; import { findOpenPort } from "../../core/port.ts"; import { kLocalhost } from "../../core/port-consts.ts"; -import { ProjectServe } from "../../resources/types/schema-types.ts"; +import { ProjectServe } from "../../resources/types/zod/schema-types.ts"; import { handleHttpRequests } from "../../core/http-server.ts"; import { touch } from "../../core/file.ts"; import { staticResource } from "../../preview/preview-static.ts"; diff --git a/src/project/types.ts b/src/project/types.ts index 3bc67290dab..8892d59c38f 100644 --- a/src/project/types.ts +++ b/src/project/types.ts @@ -14,7 +14,6 @@ import { ExecutionEngine, ExecutionTarget } from "../execute/types.ts"; import { InspectedMdCell } from "../quarto-core/inspect-types.ts"; import { NotebookContext } from "../render/notebook/notebook-types.ts"; import { - Brand as BrandJson, NavigationItem as NavItem, NavigationItemObject, NavigationItemObject as SidebarTool, @@ -70,8 +69,12 @@ export interface ProjectContext { fileInformationCache: Map; // This is a cache of _brand.yml for a project - brandCache?: { brand?: LightDarkBrand}; - resolveBrand: (fileName?: string) => Promise; + brandCache?: { brand?: LightDarkBrand }; + resolveBrand: ( + fileName?: string, + ) => Promise< + undefined | { light?: Brand | undefined; dark?: Brand | undefined } + >; // expands markdown for a file // input file doesn't have to be markdown; it can be, for example, a knitr spin file diff --git a/src/project/types/book/book-config.ts b/src/project/types/book/book-config.ts index 8e4a4d14c85..7dfed26800f 100644 --- a/src/project/types/book/book-config.ts +++ b/src/project/types/book/book-config.ts @@ -118,10 +118,8 @@ import { RenderFlags } from "../../../command/render/types.ts"; import { formatLanguage } from "../../../core/language.ts"; import { kComments } from "../../../format/html/format-html-shared.ts"; import { resolvePageFooter } from "../website/website-shared.ts"; -import { - NavigationItemObject, - PageFooterRegion, -} from "../../../resources/types/schema-types.ts"; +import { Zod } from "../../../resources/types/zod/schema-types.ts"; +import { PageFooterRegion } from "../../../resources/types/schema-types.ts"; import { projectType } from "../project-types.ts"; import { BookRenderItem, BookRenderItemType } from "./book-types.ts"; import { isAbsoluteRef } from "../../../core/http.ts"; @@ -145,7 +143,7 @@ export async function bookProjectConfig( if (!site[kSiteFavicon]) { const brand = await project.resolveBrand(); if (brand?.light) { - site[kSiteFavicon] = getFavicon(brand.light); // + site[kSiteFavicon] = getFavicon(brand.light); // } } site[kSiteUrl] = book[kSiteUrl]; @@ -259,14 +257,11 @@ export async function bookProjectConfig( const footerFiles: string[] = []; const pageFooter = resolvePageFooter(config); const addFooterItems = (region?: PageFooterRegion) => { - if (region) { - for (const item of region) { - if (typeof item !== "string") { - const navItem = item as NavigationItemObject; - if (navItem.href && !isAbsoluteRef(navItem.href)) { - footerFiles.push(navItem.href); - } - } + if (!region || typeof region === "string") return; + for (const item of region) { + const navItem = Zod.NavigationItemObject.parse(item); + if (navItem.href && !isAbsoluteRef(navItem.href)) { + footerFiles.push(navItem.href); } } }; diff --git a/src/resources/editor/tools/vs-code.mjs b/src/resources/editor/tools/vs-code.mjs index a5156b04bdf..7e18bf4769f 100644 --- a/src/resources/editor/tools/vs-code.mjs +++ b/src/resources/editor/tools/vs-code.mjs @@ -8637,16 +8637,17 @@ var require_yaml_intelligence_resources = __commonJS({ } }, mapping: { - anyOf: [ - { - enum: [ - "pathname", - "url", - "title", - "og:title" - ] - }, - "string" + schema: { + anyOf: [ + "string", + "number" + ] + }, + completions: [ + "pathname", + "url", + "title", + "og:title" ], description: { short: "The mapping between the page and the embedded discussion.", @@ -9699,40 +9700,34 @@ var require_yaml_intelligence_resources = __commonJS({ } }, background: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" - ], - description: "The navbar's background color (named or hex color)." + string: { + description: "The navbar's background color (named or hex color).", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" + ] + } }, foreground: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" - ], - description: "The navbar's foreground color (named or hex color)." + string: { + description: "The navbar's foreground color (named or hex color).", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" + ] + } }, search: { boolean: { @@ -9854,38 +9849,30 @@ var require_yaml_intelligence_resources = __commonJS({ default: "floating" }, background: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" + schema: "string", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" ], description: "The sidebar's background color (named or hex color)." }, foreground: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" + schema: "string", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" ], description: "The sidebar's foreground color (named or hex color)." }, @@ -24345,12 +24332,12 @@ var require_yaml_intelligence_resources = __commonJS({ mermaid: "%%" }, "handlers/mermaid/schema.yml": { - _internalId: 190556, + _internalId: 195562, type: "object", description: "be an object", properties: { "mermaid-format": { - _internalId: 190548, + _internalId: 195554, type: "enum", enum: [ "png", @@ -24366,7 +24353,7 @@ var require_yaml_intelligence_resources = __commonJS({ exhaustiveCompletions: true }, theme: { - _internalId: 190555, + _internalId: 195561, type: "anyOf", anyOf: [ { diff --git a/src/resources/editor/tools/yaml/web-worker.js b/src/resources/editor/tools/yaml/web-worker.js index c88c1730ba0..54c2aede01a 100644 --- a/src/resources/editor/tools/yaml/web-worker.js +++ b/src/resources/editor/tools/yaml/web-worker.js @@ -8638,16 +8638,17 @@ try { } }, mapping: { - anyOf: [ - { - enum: [ - "pathname", - "url", - "title", - "og:title" - ] - }, - "string" + schema: { + anyOf: [ + "string", + "number" + ] + }, + completions: [ + "pathname", + "url", + "title", + "og:title" ], description: { short: "The mapping between the page and the embedded discussion.", @@ -9700,40 +9701,34 @@ try { } }, background: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" - ], - description: "The navbar's background color (named or hex color)." + string: { + description: "The navbar's background color (named or hex color).", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" + ] + } }, foreground: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" - ], - description: "The navbar's foreground color (named or hex color)." + string: { + description: "The navbar's foreground color (named or hex color).", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" + ] + } }, search: { boolean: { @@ -9855,38 +9850,30 @@ try { default: "floating" }, background: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" + schema: "string", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" ], description: "The sidebar's background color (named or hex color)." }, foreground: { - anyOf: [ - { - enum: [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" + schema: "string", + completions: [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" ], description: "The sidebar's foreground color (named or hex color)." }, @@ -24346,12 +24333,12 @@ try { mermaid: "%%" }, "handlers/mermaid/schema.yml": { - _internalId: 190556, + _internalId: 195562, type: "object", description: "be an object", properties: { "mermaid-format": { - _internalId: 190548, + _internalId: 195554, type: "enum", enum: [ "png", @@ -24367,7 +24354,7 @@ try { exhaustiveCompletions: true }, theme: { - _internalId: 190555, + _internalId: 195561, type: "anyOf", anyOf: [ { diff --git a/src/resources/editor/tools/yaml/yaml-intelligence-resources.json b/src/resources/editor/tools/yaml/yaml-intelligence-resources.json index d2caed321e1..0d06a1bd673 100644 --- a/src/resources/editor/tools/yaml/yaml-intelligence-resources.json +++ b/src/resources/editor/tools/yaml/yaml-intelligence-resources.json @@ -1609,16 +1609,17 @@ } }, "mapping": { - "anyOf": [ - { - "enum": [ - "pathname", - "url", - "title", - "og:title" - ] - }, - "string" + "schema": { + "anyOf": [ + "string", + "number" + ] + }, + "completions": [ + "pathname", + "url", + "title", + "og:title" ], "description": { "short": "The mapping between the page and the embedded discussion.", @@ -2671,40 +2672,34 @@ } }, "background": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" - ], - "description": "The navbar's background color (named or hex color)." + "string": { + "description": "The navbar's background color (named or hex color).", + "completions": [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" + ] + } }, "foreground": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" - ], - "description": "The navbar's foreground color (named or hex color)." + "string": { + "description": "The navbar's foreground color (named or hex color).", + "completions": [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" + ] + } }, "search": { "boolean": { @@ -2826,38 +2821,30 @@ "default": "floating" }, "background": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" + "schema": "string", + "completions": [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" ], "description": "The sidebar's background color (named or hex color)." }, "foreground": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - "string" + "schema": "string", + "completions": [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark" ], "description": "The sidebar's foreground color (named or hex color)." }, @@ -17317,12 +17304,12 @@ "mermaid": "%%" }, "handlers/mermaid/schema.yml": { - "_internalId": 190556, + "_internalId": 195562, "type": "object", "description": "be an object", "properties": { "mermaid-format": { - "_internalId": 190548, + "_internalId": 195554, "type": "enum", "enum": [ "png", @@ -17338,7 +17325,7 @@ "exhaustiveCompletions": true }, "theme": { - "_internalId": 190555, + "_internalId": 195561, "type": "anyOf", "anyOf": [ { diff --git a/src/resources/schema/definitions.yml b/src/resources/schema/definitions.yml index b8b8f9f5f1e..93fccfc4d83 100644 --- a/src/resources/schema/definitions.yml +++ b/src/resources/schema/definitions.yml @@ -218,9 +218,15 @@ You can quickly find this by using the configuration tool at [https://giscus.app](https://giscus.app). If this is not provided, Quarto will attempt to discover it at render time. mapping: - anyOf: - - enum: [pathname, url, title, og:title] - - string + schema: + anyOf: + - string + - number + completions: + - pathname + - url + - title + - og:title description: short: The mapping between the page and the embedded discussion. long: | @@ -937,35 +943,29 @@ string: description: "Target href from navbar logo / title. By default, the logo and title link to the root page of the site (/index.html)." background: - anyOf: - - enum: - [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark", - ] - - string - description: "The navbar's background color (named or hex color)." + string: + description: "The navbar's background color (named or hex color)." + completions: + - primary + - secondary + - success + - danger + - warning + - info + - light + - dark foreground: - anyOf: - - enum: - [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark", - ] - - string - description: "The navbar's foreground color (named or hex color)." + string: + description: "The navbar's foreground color (named or hex color)." + completions: + - primary + - secondary + - success + - danger + - warning + - info + - light + - dark search: boolean: description: "Include a search box in the navbar." @@ -1039,34 +1039,28 @@ description: "The style of sidebar (`docked` or `floating`)." default: "floating" background: - anyOf: - - enum: - [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark", - ] - - string + schema: string + completions: + - primary + - secondary + - success + - danger + - warning + - info + - light + - dark description: "The sidebar's background color (named or hex color)." foreground: - anyOf: - - enum: - [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark", - ] - - string + schema: string + completions: + - primary + - secondary + - success + - danger + - warning + - info + - light + - dark description: "The sidebar's foreground color (named or hex color)." border: boolean: diff --git a/src/resources/schema/json-schemas.json b/src/resources/schema/json-schemas.json index bcc3568bb07..9c6094a07d8 100644 --- a/src/resources/schema/json-schemas.json +++ b/src/resources/schema/json-schemas.json @@ -258,15 +258,10 @@ "mapping": { "anyOf": [ { - "enum": [ - "pathname", - "url", - "title", - "og:title" - ] + "type": "string" }, { - "type": "string" + "type": "number" } ] }, @@ -1045,42 +1040,10 @@ "type": "string" }, "background": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - { - "type": "string" - } - ] + "type": "string" }, "foreground": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - { - "type": "string" - } - ] + "type": "string" }, "search": { "type": "boolean" @@ -1179,42 +1142,10 @@ ] }, "background": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - { - "type": "string" - } - ] + "type": "string" }, "foreground": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - { - "type": "string" - } - ] + "type": "string" }, "border": { "type": "boolean" @@ -1306,42 +1237,10 @@ ] }, "background": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - { - "type": "string" - } - ] + "type": "string" }, "foreground": { - "anyOf": [ - { - "enum": [ - "primary", - "secondary", - "success", - "danger", - "warning", - "info", - "light", - "dark" - ] - }, - { - "type": "string" - } - ] + "type": "string" }, "border": { "type": "boolean" diff --git a/src/resources/types/schema-schema-types.ts b/src/resources/types/schema-schema-types.ts index 2e3737f9823..48356107367 100644 --- a/src/resources/types/schema-schema-types.ts +++ b/src/resources/types/schema-schema-types.ts @@ -1,6 +1,6 @@ -// This file is automatically generated by `quarto build-js`! Do not edit.", +// This file is automatically generated by `quarto dev-call build-artifacts`! Do not edit.", // -// If you find yourself trying to rebuild types and `quarto build-js` won't run because +// If you find yourself trying to rebuild types and `quarto dev-call build-artifacts` won't run because // of bad type definitions, run the following: // $ cd $QUARTO_ROOT // $ ./package/dist/bin/tools/deno run --importmap=./src/import_map.json --allow-all ./package/src/common/create-schema-types.ts ./src/resources diff --git a/src/resources/types/schema-types.ts b/src/resources/types/schema-types.ts index 583f7fa7e92..248cf3f2bbc 100644 --- a/src/resources/types/schema-types.ts +++ b/src/resources/types/schema-types.ts @@ -1,6 +1,6 @@ -// This file is automatically generated by `quarto build-js`! Do not edit.", +// This file is automatically generated by `quarto dev-call build-artifacts`! Do not edit.", // -// If you find yourself trying to rebuild types and `quarto build-js` won't run because +// If you find yourself trying to rebuild types and `quarto dev-call build-artifacts` won't run because // of bad type definitions, run the following: // $ cd $QUARTO_ROOT // $ ./package/dist/bin/tools/deno run --importmap=./src/import_map.json --allow-all ./package/src/common/create-schema-types.ts ./src/resources @@ -132,17 +132,7 @@ can only be created by maintainers and giscus. */; loading?: "lazy"; language?: string /* The language that should be used when displaying the commenting interface. */; - mapping?: - | ("pathname" | "url" | "title" | "og:title") - | string /* The mapping between the page and the embedded discussion. - -- `pathname`: The discussion title contains the page path -- `url`: The discussion title contains the page url -- `title`: The discussion title contains the page title -- `og:title`: The discussion title contains the `og:title` metadata value -- any other string or number: Any other strings will be passed through verbatim and a discussion title -containing that value will be used. Numbers will be treated -as a discussion number and automatic discussion creation is not supported. */; + mapping?: string | number; repo: string /* The Github repo that will be used to store comments. In order to work correctly, the repo must be public, with the giscus app installed, and @@ -475,31 +465,11 @@ The user’s cookie preferences will automatically control Google Analytics (if "tools-collapse"?: boolean /* Collapse tools into the navbar menu when the display becomes narrow. */; background?: - | ( - | "primary" - | "secondary" - | "success" - | "danger" - | "warning" - | "info" - | "light" - | "dark" - ) - | string /* The navbar's background color (named or hex color). */; + string /* The navbar's background color (named or hex color). */; collapse?: boolean /* Collapse the navbar into a menu when the display becomes narrow. */; foreground?: - | ( - | "primary" - | "secondary" - | "success" - | "danger" - | "warning" - | "info" - | "light" - | "dark" - ) - | string /* The navbar's foreground color (named or hex color). */; + string /* The navbar's foreground color (named or hex color). */; logo?: string /* Path to a logo image that will be displayed to the left of the title. */; left?: @@ -558,33 +528,11 @@ The user’s cookie preferences will automatically control Google Analytics (if | "left" | "right" | "center" /* Alignment of the items within the sidebar (`left`, `right`, or `center`) */; - background?: - | ( - | "primary" - | "secondary" - | "success" - | "danger" - | "warning" - | "info" - | "light" - | "dark" - ) - | string /* The sidebar's background color (named or hex color). */; + background?: string; border?: boolean /* Whether to show a border on the sidebar (defaults to true for 'docked' sidebars) */; contents?: SidebarContents; - foreground?: - | ( - | "primary" - | "secondary" - | "success" - | "danger" - | "warning" - | "info" - | "light" - | "dark" - ) - | string /* The sidebar's foreground color (named or hex color). */; + foreground?: string; footer?: MaybeArrayOf< string > /* Markdown to place below sidebar content (text or file path) */; diff --git a/src/resources/types/zod/handwritten-schema-types.ts b/src/resources/types/zod/handwritten-schema-types.ts new file mode 100644 index 00000000000..4d7f2834fb6 --- /dev/null +++ b/src/resources/types/zod/handwritten-schema-types.ts @@ -0,0 +1,118 @@ +/* + * handwritten-schema-types.ts + * + * Some Zod schemas that are easier to write by hand than to generate: + * + * - SidebarContents + * - NavigationItem + * + * If you need to change these, the easiest way is to generate the + * schema-types.ts file, and then start from the commented-out, + * slightly incorrect version of the zod schemas to edit. + * + * We're using the strategy illustrated in https://zod.dev/?id=recursive-types + * to solve these recursive types. + * + * Copyright (C) 2025 Posit Software, PBC + */ + +import { z } from "zod"; + +import { ZodContentsAuto } from "./schema-types.ts"; + +import { type ContentsAuto } from "./schema-types.ts"; + +const Base_ZodSidebarContentsObject = z.object({ + section: z.union([z.string(), z.null()]), + /* hide the recursive declaration + + contents: z.lazy(() => ZodSidebarContents), + */ +}).strict().partial(); + +export type SidebarContentsObject = + & z.infer + & { + contents: SidebarContents; + }; + +const ZodSidebarContentsObject: z.ZodType = + Base_ZodSidebarContentsObject.extend({ + contents: z.lazy(() => ZodSidebarContents), + }); + +const Base_ZodSidebarContents = z.union([ + z.string(), + z.lazy(() => ZodContentsAuto), + /* hide the recursive declaration + + z.array(z.union([ + z.lazy(() => ZodNavigationItem), + z.string(), + z.lazy(() => ZodSidebarContentsObject), + z.lazy(() => ZodContentsAuto), + ])), + */ +]); + +export type SidebarContents = + | z.infer + | (NavigationItem | string | SidebarContentsObject | ContentsAuto)[]; + +export const ZodSidebarContents = z.union([ + Base_ZodSidebarContents, + z.array(z.union([ + z.lazy(() => ZodNavigationItem), + z.string(), + z.lazy(() => ZodSidebarContentsObject), + z.lazy(() => ZodContentsAuto), + ])), +]); + +/* export type NavigationItem = z.infer; */ + +/* export type NavigationItemObject = z.infer; */ + +/* export type SidebarContents = z.infer; */ + +export const Base_ZodNavigationItem = z.string(); +/* + hide the recursive declaration +z.union([ + z.string(), + z.lazy(() => ZodNavigationItemObject), +]); +*/ +export type NavigationItem = + | z.infer + | NavigationItemObject; + +export const ZodNavigationItem = z.union([ + Base_ZodNavigationItem, + z.lazy(() => ZodNavigationItemObject), +]); + +export const Base_ZodNavigationItemObject = z.object({ + "aria-label": z.string(), + file: z.string(), + href: z.string(), + icon: z.string(), + id: z.string(), + /* hide the recursive declaration + + menu: z.array(z.lazy(() => ZodNavigationItem)), + */ + text: z.string(), + url: z.string(), + rel: z.string(), + target: z.string(), +}).strict().partial(); + +type NavigationItemObject = z.infer & { + menu?: NavigationItem[]; +}; + +export const ZodNavigationItemObject: z.ZodType = + Base_ZodNavigationItemObject.extend({ + menu: z.array(z.lazy(() => ZodNavigationItem)), + }).strict().partial(); diff --git a/src/resources/types/zod/schema-types.ts b/src/resources/types/zod/schema-types.ts new file mode 100644 index 00000000000..ab506b21214 --- /dev/null +++ b/src/resources/types/zod/schema-types.ts @@ -0,0 +1,1887 @@ +import { z } from "zod"; + +import { + ZodNavigationItem, + ZodNavigationItemObject, + ZodSidebarContents, +} from "./handwritten-schema-types.ts"; +export { + ZodNavigationItem, + ZodNavigationItemObject, + ZodSidebarContents, +} from "./handwritten-schema-types.ts"; + +// This file is automatically generated by `quarto dev-call build-artifacts`! Do not edit.", +// +// If you find yourself trying to rebuild types and `quarto dev-call build-artifacts` won't run because +// of bad type definitions, run the following: +// $ cd $QUARTO_ROOT +// $ ./package/dist/bin/tools/deno run --importmap=./src/import_map.json --allow-all ./package/src/common/create-schema-types.ts ./src/resources + +export type MaybeArrayOf = T | T[]; +export type JsonObject = { [key: string]: unknown }; +// export type SchemaObject = { [key: string]: string }; + +export const ZodDate = z.union([ + z.string(), + z.object({ value: z.string(), format: z.string() }).passthrough().partial() + .required({ value: true }), +]); + +export const ZodMathMethods = z.enum( + ["plain", "webtex", "gladtex", "mathml", "mathjax", "katex"] as const, +); + +export const ZodPandocFormatRequestHeaders = z.array(z.array(z.string())); + +export const ZodPandocFormatOutputFile = z.union([z.string(), z.literal(null)]); + +export const ZodPandocFormatFilters = z.array( + z.union([ + z.string(), + z.object({ type: z.string(), path: z.string() }).passthrough().partial() + .required({ path: true }), + z.object({ + type: z.string(), + path: z.string(), + at: z.enum( + [ + "pre-ast", + "post-ast", + "pre-quarto", + "post-quarto", + "pre-render", + "post-render", + ] as const, + ), + }).passthrough().partial().required({ path: true, at: true }), + z.object({ type: z.enum(["citeproc"] as const) }).strict(), + ]), +); + +export const ZodPandocShortcodes = z.array(z.string()); + +export const ZodPageColumn = z.enum( + [ + "body", + "body-outset", + "body-outset-left", + "body-outset-right", + "page", + "page-left", + "page-right", + "page-inset", + "page-inset-left", + "page-inset-right", + "screen", + "screen-left", + "screen-right", + "screen-inset", + "screen-inset-shaded", + "screen-inset-left", + "screen-inset-right", + "margin", + ] as const, +); + +export const ZodContentsAuto = z.object({ + auto: z.union([z.boolean(), z.union([z.string(), z.array(z.string())])]), +}).passthrough().partial(); + +/* export const ZodNavigationItem = z.union([z.string(), z.lazy(() => ZodNavigationItemObject)]); */ + +/* export const ZodNavigationItemObject = z.object({"aria-label": z.string(), file: z.string(), href: z.string(), icon: z.string(), id: z.string(), menu: z.array(z.lazy(() => ZodNavigationItem)), text: z.string(), url: z.string(), rel: z.string(), target: z.string()}).strict().partial(); */ + +export const ZodGiscusThemes = z.enum( + [ + "light", + "light_high_contrast", + "light_protanopia", + "light_tritanopia", + "dark", + "dark_high_contrast", + "dark_protanopia", + "dark_tritanopia", + "dark_dimmed", + "transparent_dark", + "cobalt", + "purple_dark", + "noborder_light", + "noborder_dark", + "noborder_gray", + "preferred_color_scheme", + ] as const, +); + +export const ZodGiscusConfiguration = z.object({ + repo: z.string(), + "repo-id": z.string(), + category: z.string(), + "category-id": z.string(), + mapping: z.union([z.string(), z.number()]), + "reactions-enabled": z.boolean(), + loading: z.enum(["lazy"] as const), + "input-position": z.enum(["top", "bottom"] as const), + theme: z.union([ + z.string(), + z.lazy(() => ZodGiscusThemes), + z.object({ + light: z.union([z.string(), z.lazy(() => ZodGiscusThemes)]), + dark: z.union([z.string(), z.lazy(() => ZodGiscusThemes)]), + }).strict().partial(), + ]), + language: z.string(), +}).strict().partial().required({ repo: true }); + +export const ZodDocumentCommentsConfiguration = z.union([ + z.literal(false), + z.object({ + utterances: z.object({ + repo: z.string(), + label: z.string(), + theme: z.string(), + "issue-term": z.string(), + }).strict().partial().required({ repo: true }), + giscus: z.lazy(() => ZodGiscusConfiguration), + hypothesis: z.union([ + z.boolean(), + z.object({ + "client-url": z.string(), + openSidebar: z.boolean(), + showHighlights: z.union([ + z.boolean(), + z.enum(["always", "whenSidebarOpen", "never"] as const), + ]), + theme: z.enum(["classic", "clean"] as const), + enableExperimentalNewNoteButton: z.boolean(), + usernameUrl: z.string(), + services: z.array( + z.object({ + apiUrl: z.string(), + authority: z.string(), + grantToken: z.string(), + allowLeavingGroups: z.boolean(), + enableShareLinks: z.boolean(), + groups: z.union([ + z.enum(["$rpc:requestGroups"] as const), + z.array(z.string()), + ]), + icon: z.string(), + }).passthrough().partial().required({ + apiUrl: true, + authority: true, + grantToken: true, + }), + ), + branding: z.object({ + accentColor: z.string(), + appBackgroundColor: z.string(), + ctaBackgroundColor: z.string(), + selectionFontFamily: z.string(), + annotationFontFamily: z.string(), + }).passthrough().partial(), + externalContainerSelector: z.string(), + focus: z.object({ + user: z.object({ + username: z.string(), + userid: z.string(), + displayName: z.string(), + }).passthrough().partial(), + }).passthrough().partial().required({ user: true }), + requestConfigFromFrame: z.object({ + origin: z.string(), + ancestorLevel: z.number(), + }).passthrough().partial(), + assetRoot: z.string(), + sidebarAppUrl: z.string(), + }).strict().partial(), + ]), + }).strict().partial(), +]); + +export const ZodSocialMetadata = z.object({ + title: z.string(), + description: z.string(), + image: z.string(), + "image-alt": z.string(), + "image-width": z.number(), + "image-height": z.number(), +}).strict().partial(); + +export const ZodPageFooterRegion = z.union([ + z.string(), + z.array(z.lazy(() => ZodNavigationItem)), +]); + +/* export const ZodSidebarContents = z.union([z.string(), z.lazy(() => ZodContentsAuto), z.array(z.union([z.lazy(() => ZodNavigationItem), z.string(), z.object({section: z.union([z.string(), z.null()]), contents: z.lazy(() => ZodSidebarContents)}).strict().partial(), z.lazy(() => ZodContentsAuto)]))]); */ + +export const ZodProjectPreview = z.object({ + port: z.number(), + host: z.string(), + serve: z.lazy(() => ZodProjectServe), + browser: z.boolean(), + "watch-inputs": z.boolean(), + navigate: z.boolean(), + timeout: z.number(), +}).strict().partial(); + +export const ZodProjectServe = z.object({ + cmd: z.string(), + args: z.string(), + env: z.object({}).passthrough().partial(), + ready: z.string(), +}).strict().partial().required({ cmd: true, ready: true }); + +export const ZodPublish = z.object({ + netlify: z.array(z.lazy(() => ZodPublishRecord)), +}).strict().partial(); + +export const ZodPublishRecord = z.object({ id: z.string(), url: z.string() }) + .strict().partial(); + +export const ZodTwitterCardConfig = z.object({ + title: z.string(), + description: z.string(), + image: z.string(), + "image-alt": z.string(), + "image-width": z.number(), + "image-height": z.number(), + "card-style": z.enum(["summary", "summary_large_image"] as const), + creator: z.string(), + site: z.string(), +}).strict().partial(); + +export const ZodOpenGraphConfig = z.object({ + title: z.string(), + description: z.string(), + image: z.string(), + "image-alt": z.string(), + "image-width": z.number(), + "image-height": z.number(), + locale: z.string(), + "site-name": z.string(), +}).strict().partial(); + +export const ZodPageFooter = z.object({ + left: z.lazy(() => ZodPageFooterRegion), + right: z.lazy(() => ZodPageFooterRegion), + center: z.lazy(() => ZodPageFooterRegion), + border: z.union([z.boolean(), z.string()]), + background: z.string(), + foreground: z.string(), +}).strict().partial(); + +export const ZodBaseWebsite = z.object({ + title: z.string(), + description: z.string(), + favicon: z.string(), + "site-url": z.string(), + "site-path": z.string(), + "repo-url": z.string(), + "repo-link-target": z.string(), + "repo-link-rel": z.string(), + "repo-subdir": z.string(), + "repo-branch": z.string(), + "issue-url": z.string(), + "repo-actions": z.union([ + z.enum(["none", "edit", "source", "issue"] as const), + z.array(z.enum(["none", "edit", "source", "issue"] as const)), + ]), + "reader-mode": z.boolean(), + "google-analytics": z.union([ + z.string(), + z.object({ + "tracking-id": z.string(), + storage: z.enum(["cookies", "none"] as const), + "anonymize-ip": z.boolean(), + version: z.union([z.literal(3), z.literal(4)]), + }).passthrough().partial(), + ]), + announcement: z.union([ + z.string(), + z.object({ + content: z.string(), + dismissable: z.boolean(), + icon: z.string(), + position: z.enum(["above-navbar", "below-navbar"] as const), + type: z.enum( + [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark", + ] as const, + ), + }).passthrough().partial(), + ]), + "cookie-consent": z.union([ + z.enum(["express", "implied"] as const), + z.boolean(), + z.object({ + type: z.enum(["implied", "express"] as const), + style: z.enum( + ["simple", "headline", "interstitial", "standalone"] as const, + ), + palette: z.enum(["light", "dark"] as const), + "policy-url": z.string(), + language: z.string(), + "prefs-text": z.string(), + }).passthrough().partial(), + ]), + search: z.union([ + z.boolean(), + z.object({ + location: z.enum(["navbar", "sidebar"] as const), + type: z.enum(["overlay", "textbox"] as const), + limit: z.number(), + "collapse-after": z.number(), + "copy-button": z.boolean(), + "merge-navbar-crumbs": z.boolean(), + "keyboard-shortcut": z.union([z.string(), z.array(z.string())]), + "show-item-context": z.union([ + z.enum(["tree", "parent", "root"] as const), + z.boolean(), + ]), + algolia: z.object({ + "index-name": z.string(), + "application-id": z.string(), + "search-only-api-key": z.string(), + "analytics-events": z.boolean(), + "show-logo": z.boolean(), + "index-fields": z.object({ + href: z.string(), + title: z.string(), + text: z.string(), + section: z.string(), + }).strict().partial(), + params: z.object({}).passthrough().partial(), + }).strict().partial(), + }).strict().partial(), + ]), + navbar: z.union([ + z.boolean(), + z.object({ + title: z.union([z.string(), z.boolean()]), + logo: z.string(), + "logo-alt": z.string(), + "logo-href": z.string(), + background: z.string(), + foreground: z.string(), + search: z.boolean(), + pinned: z.boolean(), + collapse: z.boolean(), + "collapse-below": z.enum(["sm", "md", "lg", "xl", "xxl"] as const), + left: z.array(z.lazy(() => ZodNavigationItem)), + right: z.array(z.lazy(() => ZodNavigationItem)), + "toggle-position": z.enum(["left", "right"] as const), + "tools-collapse": z.boolean(), + }).passthrough().partial(), + ]), + sidebar: z.union([ + z.boolean(), + z.union([ + z.object({ + id: z.string(), + title: z.union([z.string(), z.boolean()]), + logo: z.string(), + "logo-alt": z.string(), + "logo-href": z.string(), + search: z.boolean(), + tools: z.array(z.lazy(() => ZodNavigationItemObject)), + contents: z.lazy(() => ZodSidebarContents), + style: z.enum(["docked", "floating"] as const), + background: z.string(), + foreground: z.string(), + border: z.boolean(), + alignment: z.enum(["left", "right", "center"] as const), + "collapse-level": z.number(), + pinned: z.boolean(), + header: z.union([z.string(), z.array(z.string())]), + footer: z.union([z.string(), z.array(z.string())]), + }).passthrough().partial(), + z.array( + z.object({ + id: z.string(), + title: z.union([z.string(), z.boolean()]), + logo: z.string(), + "logo-alt": z.string(), + "logo-href": z.string(), + search: z.boolean(), + tools: z.array(z.lazy(() => ZodNavigationItemObject)), + contents: z.lazy(() => ZodSidebarContents), + style: z.enum(["docked", "floating"] as const), + background: z.string(), + foreground: z.string(), + border: z.boolean(), + alignment: z.enum(["left", "right", "center"] as const), + "collapse-level": z.number(), + pinned: z.boolean(), + header: z.union([z.string(), z.array(z.string())]), + footer: z.union([z.string(), z.array(z.string())]), + }).passthrough().partial(), + ), + ]), + ]), + "body-header": z.string(), + "body-footer": z.string(), + "margin-header": z.union([z.string(), z.array(z.string())]), + "margin-footer": z.union([z.string(), z.array(z.string())]), + "page-navigation": z.boolean(), + "back-to-top-navigation": z.boolean(), + "bread-crumbs": z.boolean(), + "page-footer": z.union([z.string(), z.lazy(() => ZodPageFooter)]), + image: z.string(), + "image-alt": z.string(), + comments: z.lazy(() => ZodDocumentCommentsConfiguration), + "open-graph": z.union([z.boolean(), z.lazy(() => ZodOpenGraphConfig)]), + "twitter-card": z.union([z.boolean(), z.lazy(() => ZodTwitterCardConfig)]), + "other-links": z.lazy(() => ZodOtherLinks), + "code-links": z.union([z.boolean(), z.lazy(() => ZodCodeLinksSchema)]), + drafts: z.union([z.string(), z.array(z.string())]), + "draft-mode": z.enum(["visible", "unlinked", "gone"] as const), +}).strict().partial(); + +export const ZodBookSchema = z.object({ + title: z.string(), + description: z.string(), + favicon: z.string(), + "site-url": z.string(), + "site-path": z.string(), + "repo-url": z.string(), + "repo-link-target": z.string(), + "repo-link-rel": z.string(), + "repo-subdir": z.string(), + "repo-branch": z.string(), + "issue-url": z.string(), + "repo-actions": z.union([ + z.enum(["none", "edit", "source", "issue"] as const), + z.array(z.enum(["none", "edit", "source", "issue"] as const)), + ]), + "reader-mode": z.boolean(), + "google-analytics": z.union([ + z.string(), + z.object({ + "tracking-id": z.string(), + storage: z.enum(["cookies", "none"] as const), + "anonymize-ip": z.boolean(), + version: z.union([z.literal(3), z.literal(4)]), + }).passthrough().partial(), + ]), + announcement: z.union([ + z.string(), + z.object({ + content: z.string(), + dismissable: z.boolean(), + icon: z.string(), + position: z.enum(["above-navbar", "below-navbar"] as const), + type: z.enum( + [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark", + ] as const, + ), + }).passthrough().partial(), + ]), + "cookie-consent": z.union([ + z.enum(["express", "implied"] as const), + z.boolean(), + z.object({ + type: z.enum(["implied", "express"] as const), + style: z.enum( + ["simple", "headline", "interstitial", "standalone"] as const, + ), + palette: z.enum(["light", "dark"] as const), + "policy-url": z.string(), + language: z.string(), + "prefs-text": z.string(), + }).passthrough().partial(), + ]), + search: z.union([ + z.boolean(), + z.object({ + location: z.enum(["navbar", "sidebar"] as const), + type: z.enum(["overlay", "textbox"] as const), + limit: z.number(), + "collapse-after": z.number(), + "copy-button": z.boolean(), + "merge-navbar-crumbs": z.boolean(), + "keyboard-shortcut": z.union([z.string(), z.array(z.string())]), + "show-item-context": z.union([ + z.enum(["tree", "parent", "root"] as const), + z.boolean(), + ]), + algolia: z.object({ + "index-name": z.string(), + "application-id": z.string(), + "search-only-api-key": z.string(), + "analytics-events": z.boolean(), + "show-logo": z.boolean(), + "index-fields": z.object({ + href: z.string(), + title: z.string(), + text: z.string(), + section: z.string(), + }).strict().partial(), + params: z.object({}).passthrough().partial(), + }).strict().partial(), + }).strict().partial(), + ]), + navbar: z.union([ + z.boolean(), + z.object({ + title: z.union([z.string(), z.boolean()]), + logo: z.string(), + "logo-alt": z.string(), + "logo-href": z.string(), + background: z.string(), + foreground: z.string(), + search: z.boolean(), + pinned: z.boolean(), + collapse: z.boolean(), + "collapse-below": z.enum(["sm", "md", "lg", "xl", "xxl"] as const), + left: z.array(z.lazy(() => ZodNavigationItem)), + right: z.array(z.lazy(() => ZodNavigationItem)), + "toggle-position": z.enum(["left", "right"] as const), + "tools-collapse": z.boolean(), + }).passthrough().partial(), + ]), + sidebar: z.union([ + z.boolean(), + z.union([ + z.object({ + id: z.string(), + title: z.union([z.string(), z.boolean()]), + logo: z.string(), + "logo-alt": z.string(), + "logo-href": z.string(), + search: z.boolean(), + tools: z.array(z.lazy(() => ZodNavigationItemObject)), + contents: z.lazy(() => ZodSidebarContents), + style: z.enum(["docked", "floating"] as const), + background: z.string(), + foreground: z.string(), + border: z.boolean(), + alignment: z.enum(["left", "right", "center"] as const), + "collapse-level": z.number(), + pinned: z.boolean(), + header: z.union([z.string(), z.array(z.string())]), + footer: z.union([z.string(), z.array(z.string())]), + }).passthrough().partial(), + z.array( + z.object({ + id: z.string(), + title: z.union([z.string(), z.boolean()]), + logo: z.string(), + "logo-alt": z.string(), + "logo-href": z.string(), + search: z.boolean(), + tools: z.array(z.lazy(() => ZodNavigationItemObject)), + contents: z.lazy(() => ZodSidebarContents), + style: z.enum(["docked", "floating"] as const), + background: z.string(), + foreground: z.string(), + border: z.boolean(), + alignment: z.enum(["left", "right", "center"] as const), + "collapse-level": z.number(), + pinned: z.boolean(), + header: z.union([z.string(), z.array(z.string())]), + footer: z.union([z.string(), z.array(z.string())]), + }).passthrough().partial(), + ), + ]), + ]), + "body-header": z.string(), + "body-footer": z.string(), + "margin-header": z.union([z.string(), z.array(z.string())]), + "margin-footer": z.union([z.string(), z.array(z.string())]), + "page-navigation": z.boolean(), + "back-to-top-navigation": z.boolean(), + "bread-crumbs": z.boolean(), + "page-footer": z.union([z.string(), z.lazy(() => ZodPageFooter)]), + image: z.string(), + "image-alt": z.string(), + comments: z.lazy(() => ZodDocumentCommentsConfiguration), + "open-graph": z.union([z.boolean(), z.lazy(() => ZodOpenGraphConfig)]), + "twitter-card": z.union([z.boolean(), z.lazy(() => ZodTwitterCardConfig)]), + "other-links": z.lazy(() => ZodOtherLinks), + "code-links": z.union([z.boolean(), z.lazy(() => ZodCodeLinksSchema)]), + drafts: z.union([z.string(), z.array(z.string())]), + "draft-mode": z.enum(["visible", "unlinked", "gone"] as const), + subtitle: z.string(), + author: z.union([ + z.union([z.string(), z.object({}).passthrough()]), + z.array(z.union([z.string(), z.object({}).passthrough()])), + ]), + date: z.string(), + "date-format": z.string(), + abstract: z.string(), + chapters: z.lazy(() => ZodChapterList), + appendices: z.lazy(() => ZodChapterList), + references: z.string(), + "output-file": z.string(), + "cover-image": z.string(), + "cover-image-alt": z.string(), + sharing: z.union([ + z.enum(["twitter", "facebook", "linkedin"] as const), + z.array(z.enum(["twitter", "facebook", "linkedin"] as const)), + ]), + downloads: z.union([ + z.enum(["pdf", "epub", "docx"] as const), + z.array(z.enum(["pdf", "epub", "docx"] as const)), + ]), + tools: z.array(z.lazy(() => ZodNavigationItem)), + doi: z.string(), +}).strict().partial(); + +export const ZodChapterItem = z.union([ + z.lazy(() => ZodNavigationItem), + z.object({ + part: z.string(), + chapters: z.array(z.lazy(() => ZodNavigationItem)), + }).passthrough().partial().required({ part: true }), +]); + +export const ZodChapterList = z.array(z.lazy(() => ZodChapterItem)); + +export const ZodOtherLinks = z.array( + z.object({ + text: z.string(), + href: z.string(), + icon: z.string(), + rel: z.string(), + target: z.string(), + }).passthrough().partial().required({ text: true, href: true }), +); + +export const ZodCrossrefLabelsSchema = z.string(); + +export const ZodEpubContributor = z.union([ + z.string(), + z.union([ + z.object({ role: z.string(), "file-as": z.string(), text: z.string() }) + .strict().partial(), + z.array( + z.object({ role: z.string(), "file-as": z.string(), text: z.string() }) + .strict().partial(), + ), + ]), +]); + +export const ZodFormatLanguage = z.object({ + "toc-title-document": z.string(), + "toc-title-website": z.string(), + "related-formats-title": z.string(), + "related-notebooks-title": z.string(), + "callout-tip-title": z.string(), + "callout-note-title": z.string(), + "callout-warning-title": z.string(), + "callout-important-title": z.string(), + "callout-caution-title": z.string(), + "section-title-abstract": z.string(), + "section-title-footnotes": z.string(), + "section-title-appendices": z.string(), + "code-summary": z.string(), + "code-tools-menu-caption": z.string(), + "code-tools-show-all-code": z.string(), + "code-tools-hide-all-code": z.string(), + "code-tools-view-source": z.string(), + "code-tools-source-code": z.string(), + "search-no-results-text": z.string(), + "copy-button-tooltip": z.string(), + "copy-button-tooltip-success": z.string(), + "repo-action-links-edit": z.string(), + "repo-action-links-source": z.string(), + "repo-action-links-issue": z.string(), + "search-matching-documents-text": z.string(), + "search-copy-link-title": z.string(), + "search-hide-matches-text": z.string(), + "search-more-match-text": z.string(), + "search-more-matches-text": z.string(), + "search-clear-button-title": z.string(), + "search-text-placeholder": z.string(), + "search-detached-cancel-button-title": z.string(), + "search-submit-button-title": z.string(), + "crossref-fig-title": z.string(), + "crossref-tbl-title": z.string(), + "crossref-lst-title": z.string(), + "crossref-thm-title": z.string(), + "crossref-lem-title": z.string(), + "crossref-cor-title": z.string(), + "crossref-prp-title": z.string(), + "crossref-cnj-title": z.string(), + "crossref-def-title": z.string(), + "crossref-exm-title": z.string(), + "crossref-exr-title": z.string(), + "crossref-fig-prefix": z.string(), + "crossref-tbl-prefix": z.string(), + "crossref-lst-prefix": z.string(), + "crossref-ch-prefix": z.string(), + "crossref-apx-prefix": z.string(), + "crossref-sec-prefix": z.string(), + "crossref-eq-prefix": z.string(), + "crossref-thm-prefix": z.string(), + "crossref-lem-prefix": z.string(), + "crossref-cor-prefix": z.string(), + "crossref-prp-prefix": z.string(), + "crossref-cnj-prefix": z.string(), + "crossref-def-prefix": z.string(), + "crossref-exm-prefix": z.string(), + "crossref-exr-prefix": z.string(), + "crossref-lof-title": z.string(), + "crossref-lot-title": z.string(), + "crossref-lol-title": z.string(), +}).passthrough().partial(); + +export const ZodWebsiteAbout = z.object({ + id: z.string(), + template: z.union([ + z.enum(["jolla", "trestles", "solana", "marquee", "broadside"] as const), + z.string(), + ]), + image: z.string(), + "image-alt": z.string(), + "image-title": z.string(), + "image-width": z.string(), + "image-shape": z.enum(["rectangle", "round", "rounded"] as const), + links: z.array(z.lazy(() => ZodNavigationItem)), +}).strict().partial().required({ template: true }); + +export const ZodWebsiteListing = z.object({ + id: z.string(), + type: z.enum(["default", "table", "grid", "custom"] as const), + contents: z.union([ + z.union([z.string(), z.lazy(() => ZodWebsiteListingContentsObject)]), + z.array( + z.union([z.string(), z.lazy(() => ZodWebsiteListingContentsObject)]), + ), + ]), + sort: z.union([z.boolean(), z.union([z.string(), z.array(z.string())])]), + "max-items": z.number(), + "page-size": z.number(), + "sort-ui": z.union([z.boolean(), z.array(z.string())]), + "filter-ui": z.union([z.boolean(), z.array(z.string())]), + categories: z.union([ + z.boolean(), + z.enum(["numbered", "unnumbered", "cloud"] as const), + ]), + feed: z.union([ + z.boolean(), + z.object({ + items: z.number(), + type: z.enum(["full", "partial", "metadata"] as const), + title: z.string(), + image: z.string(), + description: z.string(), + language: z.string(), + categories: z.union([z.string(), z.array(z.string())]), + "xml-stylesheet": z.string(), + }).strict().partial(), + ]), + "date-format": z.string(), + "max-description-length": z.number(), + "image-placeholder": z.string(), + "image-lazy-loading": z.boolean(), + "image-align": z.enum(["left", "right"] as const), + "image-height": z.string(), + "grid-columns": z.number(), + "grid-item-border": z.boolean(), + "grid-item-align": z.enum(["left", "right", "center"] as const), + "table-striped": z.boolean(), + "table-hover": z.boolean(), + template: z.string(), + "template-params": z.object({}).passthrough(), + fields: z.array(z.string()), + "field-display-names": z.object({}).passthrough().partial(), + "field-types": z.object({}).passthrough().partial(), + "field-links": z.array(z.string()), + "field-required": z.array(z.string()), + include: z.union([ + z.object({}).passthrough(), + z.array(z.object({}).passthrough()), + ]), + exclude: z.union([ + z.object({}).passthrough(), + z.array(z.object({}).passthrough()), + ]), +}).strict().partial(); + +export const ZodWebsiteListingContentsObject = z.object({ + author: z.union([z.string(), z.array(z.string())]), + date: z.string(), + title: z.string(), + subtitle: z.string(), +}).passthrough().partial(); + +export const ZodCslDate = z.union([ + z.string(), + z.union([z.number(), z.array(z.number())]), + z.object({ year: z.number(), month: z.number(), day: z.number() }) + .passthrough().partial(), +]); + +export const ZodCslPerson = z.union([ + z.union([z.string(), z.array(z.string())]), + z.union([ + z.object({ "family-name": z.string(), "given-name": z.string() }) + .passthrough().partial(), + z.array( + z.object({ "family-name": z.string(), "given-name": z.string() }) + .passthrough().partial(), + ), + ]), +]); + +export const ZodCslNumber = z.union([z.number(), z.string()]); + +export const ZodCslItemShared = z.object({ + "abstract-url": z.string(), + accessed: z.lazy(() => ZodCslDate), + annote: z.string(), + archive: z.string(), + "archive-collection": z.string(), + archive_collection: z.string(), + "archive-location": z.string(), + archive_location: z.string(), + "archive-place": z.string(), + authority: z.string(), + "available-date": z.lazy(() => ZodCslDate), + "call-number": z.string(), + chair: z.lazy(() => ZodCslPerson), + "chapter-number": z.lazy(() => ZodCslNumber), + "citation-key": z.string(), + "citation-label": z.string(), + "citation-number": z.lazy(() => ZodCslNumber), + "collection-editor": z.lazy(() => ZodCslPerson), + "collection-number": z.lazy(() => ZodCslNumber), + "collection-title": z.string(), + compiler: z.lazy(() => ZodCslPerson), + composer: z.lazy(() => ZodCslPerson), + "container-author": z.lazy(() => ZodCslPerson), + "container-title": z.string(), + "container-title-short": z.string(), + contributor: z.lazy(() => ZodCslPerson), + curator: z.lazy(() => ZodCslPerson), + dimensions: z.string(), + director: z.lazy(() => ZodCslPerson), + division: z.string(), + DOI: z.string(), + edition: z.lazy(() => ZodCslNumber), + editor: z.lazy(() => ZodCslPerson), + "editorial-director": z.lazy(() => ZodCslPerson), + "editor-translator": z.lazy(() => ZodCslPerson), + event: z.string(), + "event-date": z.lazy(() => ZodCslDate), + "event-title": z.string(), + "event-place": z.string(), + "executive-producer": z.lazy(() => ZodCslPerson), + "first-reference-note-number": z.lazy(() => ZodCslNumber), + "fulltext-url": z.string(), + genre: z.string(), + guest: z.lazy(() => ZodCslPerson), + host: z.lazy(() => ZodCslPerson), + id: z.union([z.string(), z.number()]), + illustrator: z.lazy(() => ZodCslPerson), + interviewer: z.lazy(() => ZodCslPerson), + isbn: z.string(), + ISBN: z.string(), + issn: z.string(), + ISSN: z.string(), + issue: z.lazy(() => ZodCslNumber), + issued: z.lazy(() => ZodCslDate), + jurisdiction: z.string(), + keyword: z.string(), + language: z.string(), + license: z.string(), + locator: z.lazy(() => ZodCslNumber), + medium: z.string(), + narrator: z.lazy(() => ZodCslPerson), + note: z.string(), + number: z.lazy(() => ZodCslNumber), + "number-of-pages": z.lazy(() => ZodCslNumber), + "number-of-volumes": z.lazy(() => ZodCslNumber), + organizer: z.lazy(() => ZodCslPerson), + "original-author": z.lazy(() => ZodCslPerson), + "original-date": z.lazy(() => ZodCslDate), + "original-publisher": z.string(), + "original-publisher-place": z.string(), + "original-title": z.string(), + page: z.lazy(() => ZodCslNumber), + "page-first": z.lazy(() => ZodCslNumber), + "page-last": z.lazy(() => ZodCslNumber), + "part-number": z.lazy(() => ZodCslNumber), + "part-title": z.string(), + "pdf-url": z.string(), + performer: z.lazy(() => ZodCslPerson), + pmcid: z.string(), + PMCID: z.string(), + pmid: z.string(), + PMID: z.string(), + "printing-number": z.lazy(() => ZodCslNumber), + producer: z.lazy(() => ZodCslPerson), + "public-url": z.string(), + publisher: z.string(), + "publisher-place": z.string(), + recipient: z.lazy(() => ZodCslPerson), + "reviewed-author": z.lazy(() => ZodCslPerson), + "reviewed-genre": z.string(), + "reviewed-title": z.string(), + scale: z.string(), + "script-writer": z.lazy(() => ZodCslPerson), + section: z.lazy(() => ZodCslNumber), + "series-creator": z.lazy(() => ZodCslPerson), + source: z.string(), + status: z.string(), + submitted: z.lazy(() => ZodCslDate), + "supplement-number": z.lazy(() => ZodCslNumber), + "title-short": z.string(), + translator: z.lazy(() => ZodCslPerson), + type: z.enum( + [ + "article", + "article-journal", + "article-magazine", + "article-newspaper", + "bill", + "book", + "broadcast", + "chapter", + "classic", + "collection", + "dataset", + "document", + "entry", + "entry-dictionary", + "entry-encyclopedia", + "event", + "figure", + "graphic", + "hearing", + "interview", + "legal_case", + "legislation", + "manuscript", + "map", + "motion_picture", + "musical_score", + "pamphlet", + "paper-conference", + "patent", + "performance", + "periodical", + "personal_communication", + "post", + "post-weblog", + "regulation", + "report", + "review", + "review-book", + "software", + "song", + "speech", + "standard", + "thesis", + "treaty", + "webpage", + ] as const, + ), + url: z.string(), + URL: z.string(), + version: z.lazy(() => ZodCslNumber), + volume: z.lazy(() => ZodCslNumber), + "volume-title": z.string(), + "year-suffix": z.string(), +}).passthrough().partial(); + +export const ZodCslItem = z.object({ + "abstract-url": z.string(), + accessed: z.lazy(() => ZodCslDate), + annote: z.string(), + archive: z.string(), + "archive-collection": z.string(), + archive_collection: z.string(), + "archive-location": z.string(), + archive_location: z.string(), + "archive-place": z.string(), + authority: z.string(), + "available-date": z.lazy(() => ZodCslDate), + "call-number": z.string(), + chair: z.lazy(() => ZodCslPerson), + "chapter-number": z.lazy(() => ZodCslNumber), + "citation-key": z.string(), + "citation-label": z.string(), + "citation-number": z.lazy(() => ZodCslNumber), + "collection-editor": z.lazy(() => ZodCslPerson), + "collection-number": z.lazy(() => ZodCslNumber), + "collection-title": z.string(), + compiler: z.lazy(() => ZodCslPerson), + composer: z.lazy(() => ZodCslPerson), + "container-author": z.lazy(() => ZodCslPerson), + "container-title": z.string(), + "container-title-short": z.string(), + contributor: z.lazy(() => ZodCslPerson), + curator: z.lazy(() => ZodCslPerson), + dimensions: z.string(), + director: z.lazy(() => ZodCslPerson), + division: z.string(), + DOI: z.string(), + edition: z.lazy(() => ZodCslNumber), + editor: z.lazy(() => ZodCslPerson), + "editorial-director": z.lazy(() => ZodCslPerson), + "editor-translator": z.lazy(() => ZodCslPerson), + event: z.string(), + "event-date": z.lazy(() => ZodCslDate), + "event-title": z.string(), + "event-place": z.string(), + "executive-producer": z.lazy(() => ZodCslPerson), + "first-reference-note-number": z.lazy(() => ZodCslNumber), + "fulltext-url": z.string(), + genre: z.string(), + guest: z.lazy(() => ZodCslPerson), + host: z.lazy(() => ZodCslPerson), + id: z.union([z.string(), z.number()]), + illustrator: z.lazy(() => ZodCslPerson), + interviewer: z.lazy(() => ZodCslPerson), + isbn: z.string(), + ISBN: z.string(), + issn: z.string(), + ISSN: z.string(), + issue: z.lazy(() => ZodCslNumber), + issued: z.lazy(() => ZodCslDate), + jurisdiction: z.string(), + keyword: z.string(), + language: z.string(), + license: z.string(), + locator: z.lazy(() => ZodCslNumber), + medium: z.string(), + narrator: z.lazy(() => ZodCslPerson), + note: z.string(), + number: z.lazy(() => ZodCslNumber), + "number-of-pages": z.lazy(() => ZodCslNumber), + "number-of-volumes": z.lazy(() => ZodCslNumber), + organizer: z.lazy(() => ZodCslPerson), + "original-author": z.lazy(() => ZodCslPerson), + "original-date": z.lazy(() => ZodCslDate), + "original-publisher": z.string(), + "original-publisher-place": z.string(), + "original-title": z.string(), + page: z.lazy(() => ZodCslNumber), + "page-first": z.lazy(() => ZodCslNumber), + "page-last": z.lazy(() => ZodCslNumber), + "part-number": z.lazy(() => ZodCslNumber), + "part-title": z.string(), + "pdf-url": z.string(), + performer: z.lazy(() => ZodCslPerson), + pmcid: z.string(), + PMCID: z.string(), + pmid: z.string(), + PMID: z.string(), + "printing-number": z.lazy(() => ZodCslNumber), + producer: z.lazy(() => ZodCslPerson), + "public-url": z.string(), + publisher: z.string(), + "publisher-place": z.string(), + recipient: z.lazy(() => ZodCslPerson), + "reviewed-author": z.lazy(() => ZodCslPerson), + "reviewed-genre": z.string(), + "reviewed-title": z.string(), + scale: z.string(), + "script-writer": z.lazy(() => ZodCslPerson), + section: z.lazy(() => ZodCslNumber), + "series-creator": z.lazy(() => ZodCslPerson), + source: z.string(), + status: z.string(), + submitted: z.lazy(() => ZodCslDate), + "supplement-number": z.lazy(() => ZodCslNumber), + "title-short": z.string(), + translator: z.lazy(() => ZodCslPerson), + type: z.enum( + [ + "article", + "article-journal", + "article-magazine", + "article-newspaper", + "bill", + "book", + "broadcast", + "chapter", + "classic", + "collection", + "dataset", + "document", + "entry", + "entry-dictionary", + "entry-encyclopedia", + "event", + "figure", + "graphic", + "hearing", + "interview", + "legal_case", + "legislation", + "manuscript", + "map", + "motion_picture", + "musical_score", + "pamphlet", + "paper-conference", + "patent", + "performance", + "periodical", + "personal_communication", + "post", + "post-weblog", + "regulation", + "report", + "review", + "review-book", + "software", + "song", + "speech", + "standard", + "thesis", + "treaty", + "webpage", + ] as const, + ), + url: z.string(), + URL: z.string(), + version: z.lazy(() => ZodCslNumber), + volume: z.lazy(() => ZodCslNumber), + "volume-title": z.string(), + "year-suffix": z.string(), + abstract: z.string(), + author: z.lazy(() => ZodCslPerson), + doi: z.string(), + references: z.string(), + title: z.string(), +}).strict().partial(); + +export const ZodCitationItem = z.object({ + abstract: z.string(), + author: z.lazy(() => ZodCslPerson), + doi: z.string(), + references: z.string(), + title: z.string(), + id: z.union([z.string(), z.number()]), + "article-id": z.union([ + z.union([ + z.string(), + z.object({ type: z.string(), value: z.string() }).passthrough().partial(), + ]), + z.array( + z.union([ + z.string(), + z.object({ type: z.string(), value: z.string() }).passthrough() + .partial(), + ]), + ), + ]), + "elocation-id": z.string(), + eissn: z.string(), + pissn: z.string(), + "art-access-id": z.string(), + "publisher-location": z.string(), + subject: z.string(), + categories: z.union([z.string(), z.array(z.string())]), + "container-id": z.union([ + z.union([ + z.string(), + z.object({ type: z.string(), value: z.string() }).passthrough().partial(), + ]), + z.array( + z.union([ + z.string(), + z.object({ type: z.string(), value: z.string() }).passthrough() + .partial(), + ]), + ), + ]), + "jats-type": z.string(), +}).strict().partial(); + +export const ZodSmartInclude = z.union([ + z.object({ text: z.string() }).strict(), + z.object({ file: z.string() }).strict(), +]); + +export const ZodSemver = z.string().regex( + new RegExp( + "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + ), +); + +export const ZodQuartoDate = z.union([ + z.string(), + z.object({ format: z.string(), value: z.string() }).strict().partial() + .required({ value: true }), +]); + +export const ZodProjectProfile = z.object({ + default: z.union([z.string(), z.array(z.string())]), + group: z.union([z.array(z.string()), z.array(z.array(z.string()))]), +}).strict().partial(); + +export const ZodBadParseSchema = z.object({}).passthrough().partial(); + +export const ZodQuartoDevSchema = z.object({ + _quarto: z.object({ + "trace-filters": z.string(), + tests: z.object({}).passthrough(), + }).passthrough().partial(), +}).passthrough().partial(); + +export const ZodNotebookViewSchema = z.object({ + notebook: z.string(), + title: z.union([z.string(), z.boolean()]), + url: z.string(), + "download-url": z.string(), +}).passthrough().partial().required({ notebook: true }); + +export const ZodCodeLinksSchema = z.union([ + z.boolean(), + z.union([ + z.union([ + z.object({ + icon: z.string(), + text: z.string(), + href: z.string(), + rel: z.string(), + target: z.string(), + }).passthrough().partial(), + z.enum(["repo", "binder", "devcontainer"] as const), + ]), + z.array( + z.union([ + z.object({ + icon: z.string(), + text: z.string(), + href: z.string(), + rel: z.string(), + target: z.string(), + }).passthrough().partial(), + z.enum(["repo", "binder", "devcontainer"] as const), + ]), + ), + ]), +]); + +export const ZodManuscriptSchema = z.object({ + article: z.string(), + "code-links": z.lazy(() => ZodCodeLinksSchema), + "manuscript-url": z.string(), + "meca-bundle": z.union([z.boolean(), z.string()]), + notebooks: z.array( + z.union([z.string(), z.lazy(() => ZodNotebookViewSchema)]), + ), + resources: z.union([z.string(), z.array(z.string())]), + environment: z.union([z.string(), z.array(z.string())]), +}).strict().partial(); + +export const ZodBrandMeta = z.object({ + name: z.union([ + z.string(), + z.object({ full: z.string(), short: z.string() }).passthrough().partial(), + ]), + link: z.union([ + z.string(), + z.object({ + home: z.string(), + mastodon: z.string(), + bluesky: z.string(), + github: z.string(), + linkedin: z.string(), + twitter: z.string(), + facebook: z.string(), + }).passthrough().partial(), + ]), +}).passthrough().partial(); + +export const ZodBrandStringLightDark = z.union([ + z.string(), + z.object({ light: z.string(), dark: z.string() }).strict().partial(), +]); + +export const ZodBrandLogoExplicitResource = z.object({ + path: z.string(), + alt: z.string(), +}).strict().partial().required({ path: true }); + +export const ZodBrandLogoResource = z.union([ + z.string(), + z.lazy(() => ZodBrandLogoExplicitResource), +]); + +export const ZodBrandLogo = z.object({ + images: z.record(z.lazy(() => ZodBrandLogoResource)).and( + z.object({}).passthrough().partial(), + ), + small: z.lazy(() => ZodBrandStringLightDark), + medium: z.lazy(() => ZodBrandStringLightDark), + large: z.lazy(() => ZodBrandStringLightDark), +}).strict().partial(); + +export const ZodBrandNamedLogo = z.enum(["small", "medium", "large"] as const); + +export const ZodBrandColorValue = z.string(); + +export const ZodBrandColor = z.object({ + palette: z.record(z.lazy(() => ZodBrandColorValue)).and( + z.object({}).passthrough().partial(), + ), + foreground: z.lazy(() => ZodBrandColorValue), + background: z.lazy(() => ZodBrandColorValue), + primary: z.lazy(() => ZodBrandColorValue), + secondary: z.lazy(() => ZodBrandColorValue), + tertiary: z.lazy(() => ZodBrandColorValue), + success: z.lazy(() => ZodBrandColorValue), + info: z.lazy(() => ZodBrandColorValue), + warning: z.lazy(() => ZodBrandColorValue), + danger: z.lazy(() => ZodBrandColorValue), + light: z.lazy(() => ZodBrandColorValue), + dark: z.lazy(() => ZodBrandColorValue), + link: z.lazy(() => ZodBrandColorValue), +}).strict().partial(); + +export const ZodBrandMaybeNamedColor = z.union([ + z.lazy(() => ZodBrandNamedThemeColor), + z.string(), +]); + +export const ZodBrandNamedThemeColor = z.enum( + [ + "foreground", + "background", + "primary", + "secondary", + "tertiary", + "success", + "info", + "warning", + "danger", + "light", + "dark", + "link", + ] as const, +); + +export const ZodBrandTypography = z.object({ + fonts: z.array(z.lazy(() => ZodBrandFont)), + base: z.lazy(() => ZodBrandTypographyOptionsBase), + headings: z.lazy(() => ZodBrandTypographyOptionsHeadings), + monospace: z.lazy(() => ZodBrandTypographyOptionsMonospace), + "monospace-inline": z.lazy(() => ZodBrandTypographyOptionsMonospaceInline), + "monospace-block": z.lazy(() => ZodBrandTypographyOptionsMonospaceBlock), + link: z.lazy(() => ZodBrandTypographyOptionsLink), +}).strict().partial(); + +export const ZodBrandTypographyOptionsBase = z.union([ + z.string(), + z.object({ + family: z.string(), + size: z.string(), + weight: z.lazy(() => ZodBrandFontWeight), + "line-height": z.lazy(() => ZodLineHeightNumberString), + }).strict().partial(), +]); + +export const ZodBrandTypographyOptionsHeadings = z.union([ + z.string(), + z.object({ + family: z.string(), + weight: z.lazy(() => ZodBrandFontWeight), + style: z.lazy(() => ZodBrandFontStyle), + color: z.lazy(() => ZodBrandMaybeNamedColor), + "line-height": z.lazy(() => ZodLineHeightNumberString), + }).strict().partial(), +]); + +export const ZodBrandTypographyOptionsMonospace = z.union([ + z.string(), + z.object({ + family: z.string(), + size: z.string(), + weight: z.lazy(() => ZodBrandFontWeight), + color: z.lazy(() => ZodBrandMaybeNamedColor), + "background-color": z.lazy(() => ZodBrandMaybeNamedColor), + }).strict().partial(), +]); + +export const ZodBrandTypographyOptionsMonospaceInline = z.union([ + z.string(), + z.object({ + family: z.string(), + size: z.string(), + weight: z.lazy(() => ZodBrandFontWeight), + color: z.lazy(() => ZodBrandMaybeNamedColor), + "background-color": z.lazy(() => ZodBrandMaybeNamedColor), + }).strict().partial(), +]); + +export const ZodLineHeightNumberString = z.union([z.number(), z.string()]); + +export const ZodBrandTypographyOptionsMonospaceBlock = z.union([ + z.string(), + z.object({ + family: z.string(), + size: z.string(), + weight: z.lazy(() => ZodBrandFontWeight), + color: z.lazy(() => ZodBrandMaybeNamedColor), + "background-color": z.lazy(() => ZodBrandMaybeNamedColor), + "line-height": z.lazy(() => ZodLineHeightNumberString), + }).strict().partial(), +]); + +export const ZodBrandTypographyOptionsLink = z.union([ + z.string(), + z.object({ + weight: z.lazy(() => ZodBrandFontWeight), + color: z.lazy(() => ZodBrandMaybeNamedColor), + "background-color": z.lazy(() => ZodBrandMaybeNamedColor), + decoration: z.string(), + }).strict().partial(), +]); + +export const ZodBrandNamedFont = z.enum( + ["base", "headings", "monospace"] as const, +); + +export const ZodBrandFont = z.union([ + z.lazy(() => ZodBrandFontGoogle), + z.lazy(() => ZodBrandFontBunny), + z.lazy(() => ZodBrandFontFile), + z.lazy(() => ZodBrandFontSystem), + z.lazy(() => ZodBrandFontCommon), +]); + +export const ZodBrandFontWeight = z.union([ + z.enum( + [ + "thin", + "extra-light", + "ultra-light", + "light", + "normal", + "regular", + "medium", + "semi-bold", + "demi-bold", + "bold", + "extra-bold", + "ultra-bold", + "black", + ] as const, + ), + z.literal(100), + z.literal(200), + z.literal(300), + z.literal(400), + z.literal(500), + z.literal(600), + z.literal(700), + z.literal(800), + z.literal(900), +]); + +export const ZodBrandFontStyle = z.enum( + ["normal", "italic", "oblique"] as const, +); + +export const ZodBrandFontCommon = z.object({ + family: z.string(), + weight: z.union([ + z.lazy(() => ZodBrandFontWeight), + z.array(z.lazy(() => ZodBrandFontWeight)), + ]), + style: z.union([ + z.lazy(() => ZodBrandFontStyle), + z.array(z.lazy(() => ZodBrandFontStyle)), + ]), + display: z.enum(["auto", "block", "swap", "fallback", "optional"] as const), +}).strict().partial(); + +export const ZodBrandFontSystem = z.object({ + family: z.string(), + weight: z.union([ + z.lazy(() => ZodBrandFontWeight), + z.array(z.lazy(() => ZodBrandFontWeight)), + ]), + style: z.union([ + z.lazy(() => ZodBrandFontStyle), + z.array(z.lazy(() => ZodBrandFontStyle)), + ]), + display: z.enum(["auto", "block", "swap", "fallback", "optional"] as const), + source: z.enum(["system"] as const), +}).strict().partial(); + +export const ZodBrandFontGoogle = z.object({ + family: z.string(), + weight: z.union([ + z.lazy(() => ZodBrandFontWeight), + z.array(z.lazy(() => ZodBrandFontWeight)), + ]), + style: z.union([ + z.lazy(() => ZodBrandFontStyle), + z.array(z.lazy(() => ZodBrandFontStyle)), + ]), + display: z.enum(["auto", "block", "swap", "fallback", "optional"] as const), + source: z.enum(["google"] as const), +}).strict().partial(); + +export const ZodBrandFontBunny = z.object({ + family: z.string(), + weight: z.union([ + z.lazy(() => ZodBrandFontWeight), + z.array(z.lazy(() => ZodBrandFontWeight)), + ]), + style: z.union([ + z.lazy(() => ZodBrandFontStyle), + z.array(z.lazy(() => ZodBrandFontStyle)), + ]), + display: z.enum(["auto", "block", "swap", "fallback", "optional"] as const), + source: z.enum(["bunny"] as const), +}).strict().partial(); + +export const ZodBrandFontFile = z.object({ + source: z.enum(["file"] as const), + family: z.string(), + files: z.array( + z.union([ + z.string(), + z.object({ + path: z.string(), + weight: z.lazy(() => ZodBrandFontWeight), + style: z.lazy(() => ZodBrandFontStyle), + }).passthrough().partial().required({ path: true }), + ]), + ), +}).strict().partial().required({ files: true, family: true, source: true }); + +export const ZodBrandFontFamily = z.string(); + +export const ZodBrand = z.object({ + meta: z.lazy(() => ZodBrandMeta), + logo: z.lazy(() => ZodBrandLogo), + color: z.lazy(() => ZodBrandColor), + typography: z.lazy(() => ZodBrandTypography), + defaults: z.lazy(() => ZodBrandDefaults), +}).strict().partial(); + +export const ZodBrandPathBoolLightDark = z.union([ + z.string(), + z.boolean(), + z.object({ + light: z.union([z.string(), z.lazy(() => ZodBrand)]), + dark: z.union([z.string(), z.lazy(() => ZodBrand)]), + }).strict().partial(), + z.lazy(() => ZodBrand), +]); + +export const ZodBrandDefaults = z.object({ + bootstrap: z.lazy(() => ZodBrandDefaultsBootstrap), + quarto: z.object({}).passthrough(), +}).passthrough().partial(); + +export const ZodBrandDefaultsBootstrap = z.object({ + defaults: z.record(z.union([z.string(), z.boolean(), z.number()])).and( + z.object({}).passthrough().partial(), + ), +}).passthrough().partial(); + +export const ZodProjectConfig = z.object({ + title: z.string(), + type: z.string(), + render: z.array(z.string()), + "execute-dir": z.enum(["file", "project"] as const), + "output-dir": z.string(), + "lib-dir": z.string(), + resources: z.union([z.string(), z.array(z.string())]), + preview: z.lazy(() => ZodProjectPreview), + "pre-render": z.union([z.string(), z.array(z.string())]), + "post-render": z.union([z.string(), z.array(z.string())]), + detect: z.array(z.array(z.string())), +}).strict().partial(); + +export const ZodBookProject = z.object({}).passthrough().partial(); + +export type Date = z.infer; + +export type MathMethods = z.infer; + +export type PandocFormatRequestHeaders = z.infer< + typeof ZodPandocFormatRequestHeaders +>; + +export type PandocFormatOutputFile = z.infer; + +export type PandocFormatFilters = z.infer; + +export type PandocShortcodes = z.infer; + +export type PageColumn = z.infer; + +export type ContentsAuto = z.infer; + +/* export type NavigationItem = z.infer; */ + +/* export type NavigationItemObject = z.infer; */ + +export type GiscusThemes = z.infer; + +export type GiscusConfiguration = z.infer; + +export type DocumentCommentsConfiguration = z.infer< + typeof ZodDocumentCommentsConfiguration +>; + +export type SocialMetadata = z.infer; + +export type PageFooterRegion = z.infer; + +/* export type SidebarContents = z.infer; */ + +export type ProjectPreview = z.infer; + +export type ProjectServe = z.infer; + +export type Publish = z.infer; + +export type PublishRecord = z.infer; + +export type TwitterCardConfig = z.infer; + +export type OpenGraphConfig = z.infer; + +export type PageFooter = z.infer; + +export type BaseWebsite = z.infer; + +export type BookSchema = z.infer; + +export type ChapterItem = z.infer; + +export type ChapterList = z.infer; + +export type OtherLinks = z.infer; + +export type CrossrefLabelsSchema = z.infer; + +export type EpubContributor = z.infer; + +export type FormatLanguage = z.infer; + +export type WebsiteAbout = z.infer; + +export type WebsiteListing = z.infer; + +export type WebsiteListingContentsObject = z.infer< + typeof ZodWebsiteListingContentsObject +>; + +export type CslDate = z.infer; + +export type CslPerson = z.infer; + +export type CslNumber = z.infer; + +export type CslItemShared = z.infer; + +export type CslItem = z.infer; + +export type CitationItem = z.infer; + +export type SmartInclude = z.infer; + +export type Semver = z.infer; + +export type QuartoDate = z.infer; + +export type ProjectProfile = z.infer; + +export type BadParseSchema = z.infer; + +export type QuartoDevSchema = z.infer; + +export type NotebookViewSchema = z.infer; + +export type CodeLinksSchema = z.infer; + +export type ManuscriptSchema = z.infer; + +export type BrandMeta = z.infer; + +export type BrandStringLightDark = z.infer; + +export type BrandLogoExplicitResource = z.infer< + typeof ZodBrandLogoExplicitResource +>; + +export type BrandLogoResource = z.infer; + +export type BrandLogo = z.infer; + +export type BrandNamedLogo = z.infer; + +export type BrandColorValue = z.infer; + +export type BrandColor = z.infer; + +export type BrandMaybeNamedColor = z.infer; + +export type BrandNamedThemeColor = z.infer; + +export type BrandTypography = z.infer; + +export type BrandTypographyOptionsBase = z.infer< + typeof ZodBrandTypographyOptionsBase +>; + +export type BrandTypographyOptionsHeadings = z.infer< + typeof ZodBrandTypographyOptionsHeadings +>; + +export type BrandTypographyOptionsMonospace = z.infer< + typeof ZodBrandTypographyOptionsMonospace +>; + +export type BrandTypographyOptionsMonospaceInline = z.infer< + typeof ZodBrandTypographyOptionsMonospaceInline +>; + +export type LineHeightNumberString = z.infer; + +export type BrandTypographyOptionsMonospaceBlock = z.infer< + typeof ZodBrandTypographyOptionsMonospaceBlock +>; + +export type BrandTypographyOptionsLink = z.infer< + typeof ZodBrandTypographyOptionsLink +>; + +export type BrandNamedFont = z.infer; + +export type BrandFont = z.infer; + +export type BrandFontWeight = z.infer; + +export type BrandFontStyle = z.infer; + +export type BrandFontCommon = z.infer; + +export type BrandFontSystem = z.infer; + +export type BrandFontGoogle = z.infer; + +export type BrandFontBunny = z.infer; + +export type BrandFontFile = z.infer; + +export type BrandFontFamily = z.infer; + +export type Brand = z.infer; + +export type BrandPathBoolLightDark = z.infer; + +export type BrandDefaults = z.infer; + +export type BrandDefaultsBootstrap = z.infer; + +export type ProjectConfig = z.infer; + +export type BookProject = z.infer; + +export const Zod = { + Date: ZodDate, + MathMethods: ZodMathMethods, + PandocFormatRequestHeaders: ZodPandocFormatRequestHeaders, + PandocFormatOutputFile: ZodPandocFormatOutputFile, + PandocFormatFilters: ZodPandocFormatFilters, + PandocShortcodes: ZodPandocShortcodes, + PageColumn: ZodPageColumn, + ContentsAuto: ZodContentsAuto, + NavigationItem: ZodNavigationItem, + NavigationItemObject: ZodNavigationItemObject, + GiscusThemes: ZodGiscusThemes, + GiscusConfiguration: ZodGiscusConfiguration, + DocumentCommentsConfiguration: ZodDocumentCommentsConfiguration, + SocialMetadata: ZodSocialMetadata, + PageFooterRegion: ZodPageFooterRegion, + SidebarContents: ZodSidebarContents, + ProjectPreview: ZodProjectPreview, + ProjectServe: ZodProjectServe, + Publish: ZodPublish, + PublishRecord: ZodPublishRecord, + TwitterCardConfig: ZodTwitterCardConfig, + OpenGraphConfig: ZodOpenGraphConfig, + PageFooter: ZodPageFooter, + BaseWebsite: ZodBaseWebsite, + BookSchema: ZodBookSchema, + ChapterItem: ZodChapterItem, + ChapterList: ZodChapterList, + OtherLinks: ZodOtherLinks, + CrossrefLabelsSchema: ZodCrossrefLabelsSchema, + EpubContributor: ZodEpubContributor, + FormatLanguage: ZodFormatLanguage, + WebsiteAbout: ZodWebsiteAbout, + WebsiteListing: ZodWebsiteListing, + WebsiteListingContentsObject: ZodWebsiteListingContentsObject, + CslDate: ZodCslDate, + CslPerson: ZodCslPerson, + CslNumber: ZodCslNumber, + CslItemShared: ZodCslItemShared, + CslItem: ZodCslItem, + CitationItem: ZodCitationItem, + SmartInclude: ZodSmartInclude, + Semver: ZodSemver, + QuartoDate: ZodQuartoDate, + ProjectProfile: ZodProjectProfile, + BadParseSchema: ZodBadParseSchema, + QuartoDevSchema: ZodQuartoDevSchema, + NotebookViewSchema: ZodNotebookViewSchema, + CodeLinksSchema: ZodCodeLinksSchema, + ManuscriptSchema: ZodManuscriptSchema, + BrandMeta: ZodBrandMeta, + BrandStringLightDark: ZodBrandStringLightDark, + BrandLogoExplicitResource: ZodBrandLogoExplicitResource, + BrandLogoResource: ZodBrandLogoResource, + BrandLogo: ZodBrandLogo, + BrandNamedLogo: ZodBrandNamedLogo, + BrandColorValue: ZodBrandColorValue, + BrandColor: ZodBrandColor, + BrandMaybeNamedColor: ZodBrandMaybeNamedColor, + BrandNamedThemeColor: ZodBrandNamedThemeColor, + BrandTypography: ZodBrandTypography, + BrandTypographyOptionsBase: ZodBrandTypographyOptionsBase, + BrandTypographyOptionsHeadings: ZodBrandTypographyOptionsHeadings, + BrandTypographyOptionsMonospace: ZodBrandTypographyOptionsMonospace, + BrandTypographyOptionsMonospaceInline: + ZodBrandTypographyOptionsMonospaceInline, + LineHeightNumberString: ZodLineHeightNumberString, + BrandTypographyOptionsMonospaceBlock: ZodBrandTypographyOptionsMonospaceBlock, + BrandTypographyOptionsLink: ZodBrandTypographyOptionsLink, + BrandNamedFont: ZodBrandNamedFont, + BrandFont: ZodBrandFont, + BrandFontWeight: ZodBrandFontWeight, + BrandFontStyle: ZodBrandFontStyle, + BrandFontCommon: ZodBrandFontCommon, + BrandFontSystem: ZodBrandFontSystem, + BrandFontGoogle: ZodBrandFontGoogle, + BrandFontBunny: ZodBrandFontBunny, + BrandFontFile: ZodBrandFontFile, + BrandFontFamily: ZodBrandFontFamily, + Brand: ZodBrand, + BrandPathBoolLightDark: ZodBrandPathBoolLightDark, + BrandDefaults: ZodBrandDefaults, + BrandDefaultsBootstrap: ZodBrandDefaultsBootstrap, + ProjectConfig: ZodProjectConfig, + BookProject: ZodBookProject, +}; diff --git a/tests/unit/schema-validation/zod/simple.test.ts b/tests/unit/schema-validation/zod/simple.test.ts new file mode 100644 index 00000000000..8359516af0a --- /dev/null +++ b/tests/unit/schema-validation/zod/simple.test.ts @@ -0,0 +1,15 @@ +/* +* simple.test.ts +* +* Copyright (C) 2025 Posit Software, PBC +* +*/ + +import { unitTest } from "../../../test.ts"; +import { assertThrows } from "testing/asserts"; +import { Zod } from "../../../../src/resources/types/zod/schema-types.ts"; + +unitTest("zod-schema-basic", async () => { + assertThrows(() => Zod.MathMethods.parse("latex")); + const result = Zod.MathMethods.parse("katex"); +}); \ No newline at end of file